欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

FFmpeg中AVIOContext的使用方法詳解

 更新時(shí)間:2023年08月07日 11:17:40   作者:fengbingchun  
AVIOContext是FFMPEG管理輸入輸出數(shù)據(jù)的結(jié)構(gòu)體,這篇文章主要為大家詳細(xì)介紹了這個結(jié)構(gòu)體的具體使用,文中的示例代碼講解詳細(xì),需要的可以參考一下

通過FFmpeg對視頻進(jìn)行編解碼時(shí),如果輸入文件存在本機(jī)或通過USB攝像頭、筆記本內(nèi)置攝像頭獲取數(shù)據(jù)時(shí),可通過avformat_open_input接口中的第二個參數(shù)直接指定即可。但如果待處理的視頻數(shù)據(jù)存在于內(nèi)存塊中時(shí),該如何指定,可通過FFmpeg中的結(jié)構(gòu)體AVIOContext實(shí)現(xiàn),此時(shí)avformat_open_input中的第二個參數(shù)傳nullptr。

涉及到FFmpeg中的主要函數(shù)是avio_alloc_context,聲明如下:

AVIOContext *avio_alloc_context(
                unsigned char *buffer,
                int buffer_size,
                int write_flag,
                void *opaque,
                int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                int64_t (*seek)(void *opaque, int64_t offset, int whence))

(1).buffer:通過AVIOContext進(jìn)行輸入/輸出操作的內(nèi)存塊,由av_malloc分配,av_free釋放。av_read_frame會持續(xù)從此處取數(shù)據(jù)。

(2).buffer_size: 內(nèi)存塊大小。

(3).write_flag: 如果buffer作為輸出即寫入則為1(FFmpeg將處理后的數(shù)據(jù)寫入buffer),如果buffer作為輸入則設(shè)置為0(FFmpeg從buffer獲取數(shù)據(jù)).

(4).opaque: 指向用戶特定數(shù)據(jù)的不透明指針。

(5).read_packet: 回調(diào)函數(shù),當(dāng)buffer作為輸入時(shí)必須指定,否則可為nullptr。此回調(diào)函數(shù)的參數(shù)依次為avio_alloc_context中的opaque、buffer、buffer_size。

(6).write_packet:回調(diào)函數(shù),當(dāng)buffer作為輸出時(shí)必須指定,否則可為nullptr。此回調(diào)函數(shù)的參數(shù)依次為avio_alloc_context中的opaque、buffer、buffer_size。

(7).seek:回調(diào)函數(shù),用于查找指定字節(jié)位置的函數(shù),可為nullptr。

調(diào)用完此接口后,需要將此接口返回的指針賦值給AVFormatContext的pb即I/O context。

以下為測試代碼段:

(1).主線程用于實(shí)時(shí)顯示內(nèi)存塊內(nèi)容。另有一個單獨(dú)線程用于創(chuàng)建數(shù)據(jù)。這里使用隊(duì)列:線程set_packet持續(xù)向隊(duì)列中push數(shù)據(jù);回調(diào)函數(shù)read_packet持續(xù)從隊(duì)列中pop數(shù)據(jù)

typedef struct Buffer {
    unsigned char* data;
    unsigned int length;
} Buffer;
class BufferQueue {
public:
    BufferQueue() = default;
    ~BufferQueue() {}
    void push(Buffer& buffer) {
        std::unique_lock<std::mutex> lck(mtx);
        queue.push(buffer);
        cv.notify_all();
    }
    void pop(Buffer& buffer) {
        std::unique_lock<std::mutex> lck(mtx);
        while (queue.empty()) {
            cv.wait(lck);
        }
        buffer = queue.front();
        queue.pop();
    }
    unsigned int size() {
        return queue.size();
    }
private:
    std::queue<Buffer> queue;
    std::mutex mtx;
    std::condition_variable cv;
};
class PacketScaleQueue {
public:
    PacketScaleQueue() = default;
    ~PacketScaleQueue() {
        Buffer buffer;
        while (getPacketSize() > 0) {
            popPacket(buffer);
            delete[] buffer.data;
        }
        while (getScaleSize() > 0) {
            popScale(buffer);
            delete[] buffer.data;
        }
    }
    void init(unsigned int buffer_num = 16, unsigned int buffer_size = 1024 * 1024 * 4) {
        for (unsigned int i = 0; i < buffer_num; ++i) {
            Buffer buffer = { new unsigned char[buffer_size], buffer_num};
            pushPacket(buffer);
        }
    }
    void pushPacket(Buffer& buffer) { packet_queue.push(buffer); }
    void popPacket(Buffer& buffer) { packet_queue.pop(buffer); }
    unsigned int getPacketSize() { return packet_queue.size(); }
    void pushScale(Buffer& buffer) { scale_queue.push(buffer); }
    void popScale(Buffer& buffer) { scale_queue.pop(buffer); }
    unsigned int getScaleSize() { return scale_queue.size(); }
private:
    BufferQueue packet_queue, scale_queue;
};

(2).線程函數(shù)set_packet內(nèi)容如下:類PacketScaleQueue中有兩個BufferQueue: packet_queue:未被使用的;scale_queue:已被使用的

void set_packet(PacketScaleQueue& packet_encode)
{
    while (packet_encode_flag) {
        static unsigned char v1 = 0, v2 = 0, v3 = 255;
        static const size_t size = height * width;
        Buffer buffer;
        packet_encode.popPacket(buffer);
        memset(buffer.data, v1, size);
        memset(buffer.data + size, v2, size);
        memset(buffer.data + size * 2, v3, size);
        packet_encode.pushScale(buffer);
        ++v1;
        ++v2;
        --v3;
        if (v1 == 255) v1 = 0;
        if (v2 == 255) v2 = 0;
        if (v3 == 0) v3 = 255;
        std::this_thread::sleep_for(std::chrono::milliseconds(40));
    }
}

(3).回調(diào)函數(shù)read_packet內(nèi)容如下:

int read_packet(void* opaque, uint8_t* buf, int buf_size)
{
    PacketScaleQueue* packet_encode = static_cast<PacketScaleQueue*>(opaque);
    Buffer buffer;
    packet_encode->popScale(buffer);
    memcpy(buf, buffer.data, buf_size);
    packet_encode->pushPacket(buffer);
    return buf_size;
}

(4).主函數(shù)test_ffmpeg_avio_show內(nèi)容如下:

int test_ffmpeg_avio_show()
{
    PacketScaleQueue packet_encode;
    packet_encode.init(30, block_size);
    std::thread thread_packet(set_packet, std::ref(packet_encode));
    uint8_t* avio_ctx_buffer = static_cast<uint8_t*>(av_malloc(block_size));
    if (!avio_ctx_buffer) {
        print_error_string(AVERROR(ENOMEM));
        return -1;
    }
    AVIOContext* avio_ctx = avio_alloc_context(avio_ctx_buffer, block_size, 0, &packet_encode, &read_packet, nullptr, nullptr);
    if (!avio_ctx) {
        print_error_string(AVERROR(ENOMEM));
        return -1;
    }
    AVFormatContext* ifmt_ctx = avformat_alloc_context();
    if (!ifmt_ctx) {
        print_error_string(AVERROR(ENOMEM));
        return -1;
    }
    ifmt_ctx->pb = avio_ctx;
    AVDictionary* dict = nullptr;
    av_dict_set(&dict, "video_size", "640x480", 0);
    av_dict_set(&dict, "pixel_format", "bgr24", 0);
    auto ret = avformat_open_input(&ifmt_ctx, nullptr, av_find_input_format("rawvideo"), &dict);
    if (ret < 0) {
        fprintf(stderr, "Could not open input\n");
        print_error_string(ret);
        return ret;
    }
    ret = avformat_find_stream_info(ifmt_ctx, nullptr);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        print_error_string(ret);
        return ret;
    }
    av_dump_format(ifmt_ctx, 0, "nothing", 0);
    int video_stream_index = -1;
    for (unsigned int i = 0; i < ifmt_ctx->nb_streams; ++i) {
        const AVStream* stream = ifmt_ctx->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            fprintf(stdout, "type of the encoded data: %d, dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n",
                stream->codecpar->codec_id, stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
        }
    }
    if (video_stream_index == -1) {
        fprintf(stderr, "error: no video stream\n");
        return -1;
    }
    AVCodecParameters* codecpar = ifmt_ctx->streams[video_stream_index]->codecpar;
    if (codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
        fprintf(stderr, "error: this test code only support rawvideo encode: %d\n", codecpar->codec_id);
        return -1;
    }
    AVPacket* packet = static_cast<AVPacket*>(av_malloc(sizeof(AVPacket)));
    if (!packet) {
        fprintf(stderr, "fail to av_malloc\n");
        return -1;
    }
    cv::Mat mat(height, width, CV_8UC3);
    const char* winname = "show video";
    cv::namedWindow(winname);
    while (1) {
        ret = av_read_frame(ifmt_ctx, packet);
        if (ret >= 0 && packet->stream_index == video_stream_index && packet->size > 0) {
            mat.data = packet->data;
            cv::imshow(winname, mat);
            av_packet_unref(packet);
            int key = cv::waitKey(30);
            if (key == 27) {
                packet_encode_flag = false;
                break;
            }
        }
    }
    av_freep(packet);
    cv::destroyWindow(winname);
    avformat_close_input(&ifmt_ctx);
    // note: the internal buffer could have changed, and be != avio_ctx_buffer
    if (avio_ctx) {
        av_freep(&avio_ctx->buffer);
        av_freep(&avio_ctx);
    }
    //avio_context_free(&avio_ctx); ==> av_freep(&avio_ctx);
    av_dict_free(&dict);
    thread_packet.join();
    fprintf(stdout, "test finish\n");
    return 0;
}

執(zhí)行結(jié)果如下圖所示:

GitHubhttps://github.com/fengbingchun/OpenCV_Test

到此這篇關(guān)于FFmpeg中AVIOContext的使用方法詳解的文章就介紹到這了,更多相關(guān)FFmpeg AVIOContext內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python摸魚神器之利用樹莓派opencv人臉識別自動控制電腦顯示桌面

    Python摸魚神器之利用樹莓派opencv人臉識別自動控制電腦顯示桌面

    這篇文章主要介紹了Python摸魚神器樹莓派opencv人臉識別自動控制電腦顯示桌面,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • numpy使用fromstring創(chuàng)建矩陣的實(shí)例

    numpy使用fromstring創(chuàng)建矩陣的實(shí)例

    今天小編就為大家分享一篇numpy使用fromstring創(chuàng)建矩陣的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • 簡單介紹Python的第三方庫yaml

    簡單介紹Python的第三方庫yaml

    今天給大家?guī)淼氖顷P(guān)于Python的相關(guān)知識,文章圍繞著Python的第三方庫yaml展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • python實(shí)現(xiàn)聊天小程序

    python實(shí)現(xiàn)聊天小程序

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)聊天小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 使用python實(shí)現(xiàn)多維數(shù)據(jù)降維操作

    使用python實(shí)現(xiàn)多維數(shù)據(jù)降維操作

    今天小編就為大家分享一篇使用python實(shí)現(xiàn)多維數(shù)據(jù)降維操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • 使用python 獲取進(jìn)程pid號的方法

    使用python 獲取進(jìn)程pid號的方法

    這篇文章主要介紹了使用python 獲取進(jìn)程pid號的方法,需要的朋友可以參考下
    2014-03-03
  • Python wxPython庫消息對話框MessageDialog用法示例

    Python wxPython庫消息對話框MessageDialog用法示例

    這篇文章主要介紹了Python wxPython庫消息對話框MessageDialog用法,結(jié)合實(shí)例形式簡單分析了wxPython庫的基本事件與相關(guān)使用技巧,需要的朋友可以參考下
    2018-09-09
  • Python?PyQt5中窗口數(shù)據(jù)傳遞的示例詳解

    Python?PyQt5中窗口數(shù)據(jù)傳遞的示例詳解

    開發(fā)應(yīng)用程序時(shí),若只有一個窗口則只需關(guān)心這個窗口里面的各控件之間如何傳遞數(shù)據(jù)。如果程序有多個窗口,就要關(guān)心不同的窗口之間是如何傳遞數(shù)據(jù)。本文介紹了PyQt5中三種窗口數(shù)據(jù)傳遞,需要的可以了解一下
    2022-12-12
  • 在Python的setuptools框架下生成egg的教程

    在Python的setuptools框架下生成egg的教程

    這篇文章主要介紹了在Python的setuptools框架下生成egg的教程,本文來自于IBM官方開發(fā)者技術(shù)文檔,需要的朋友可以參考下
    2015-04-04
  • Pyhton中單行和多行注釋的使用方法及規(guī)范

    Pyhton中單行和多行注釋的使用方法及規(guī)范

    大家都知道python中的注釋有多種,有單行注釋,多行注釋,批量注釋,中文注釋也是常用的。python注釋也有自己的規(guī)范,這篇文章文章中會給大家詳細(xì)介紹Pyhton中單行和多行注釋的使用方法及規(guī)范,有需要朋友們可以參考借鑒。
    2016-10-10

最新評論