【问题标题】:How can libavformat be used without using other libav libraries?如何在不使用其他 libav 库的情况下使用 libavformat?
【发布时间】:2012-11-18 01:02:37
【问题描述】:

我想要一个仅使用 libavformat 来复用视频的简单工作示例。有很好的例子 (doc/examples/muxing.c) 展示了使用 libavcodec 进行编码、使用 libavformat 进行复用以及使用 libavio 保存数据。但是,我所知道的没有一个例子是单独使用 libavformat,在缓冲区中输入编码数据并在缓冲区中获取混合数据。

困难在于两方面:一是添加avformat_new_stream(AVFormatContext *s, const AVCodec *c)的流需要引用编解码器;第二,复用的输出传递给AVFormatContext->pb,即AVIOContext*。因此,似乎没有(明显的)方法可以将 libavformat 从其他 libav 库中解脱出来。

另请参阅:这个问题提到了一种不使用 libavio 的方法:Get TS packets into buffer from libavformat

【问题讨论】:

    标签: video ffmpeg libavformat muxer


    【解决方案1】:

    您可以避免对 libavcodec 库的依赖,但您需要头文件(例如,avcodec.h)。

    方案如下:

    AVOutputFormat * oFmt= ::av_guess_format("mp4", NULL, NULL);
    AVFormatContext *oFmtCtx = NULL;
    ::avformat_alloc_output_context2(&oFmtCtx, oFmt, NULL, NULL);
    AVStream * oStrm = ::avformat_new_stream(oFmtCtx, NULL);
    AVCodecContext * strmCodec = oFmtCtx->streams[0]->codec;
    
    // Fill the required properties for codec context.
    // *from the documentation:
    // *The user sets codec information, the muxer writes it to the output.
    // *Mandatory fields as specified in AVCodecContext
    // *documentation must be set even if this AVCodecContext is
    // *not actually used for encoding.
    my_tune_codec(strmCodec); 
    
    if (oFmtCtx->oformat->flags & AVFMT_NOFILE)
    {
      ::avio_open2(&oFmtCtx->pb, fileName, AVIO_FLAG_WRITE, NULL, NULL);
    }
    ::avformat_write_header(oFmtCtx, NULL);
    // .....
    // writing loop
    // .....
    ::av_write_trailer(oFmtCtx);
    ::avio_close(oFmtCtx->pb);
    ::avformat_free_context(oFmtCtx);
    

    要获得输出,您始终必须使用AVIOContext 的概念。您可以避免使用内置协议。为此,您需要创建自己的AVIOContext (::avio_alloc_context)。

    UPD 要创建你自己的AVIOContext,你必须这样做

    #include <stdio.h>
    extern "C" {
    #include <libavformat/avio.h>
    #include <libavformat/avformat.h>
    }
    
    static const int kBufferSize = 32768;
    
    class my_iocontext_private
    {
    public:
        my_iocontext_private(FILE * f) : buffer_size_(kBufferSize),
            buffer_(static_cast<unsigned char*>(::av_malloc(buffer_size_))), f_(f) {
            ctx_ = ::avio_alloc_context(buffer_, buffer_size_, AVIO_FLAG_WRITE, this, 
                &my_iocontext_private::read, &my_iocontext_private::write, &my_iocontext_private::seek);
        }
    
        ~my_iocontext_private()    { av_free(buffer_); }
    
        static int read(void *opaque, unsigned char *buf, int buf_size) {
            my_iocontext_private* h = static_cast<my_iocontext_private*>(opaque);
            return fread(buf, 1, buf_size, h->f_);
        }
    
        static int write(void *opaque, unsigned char *buf, int buf_size) {
            my_iocontext_private* h = static_cast<my_iocontext_private*>(opaque);
            return fwrite(buf, 1, buf_size, h->f_);
        }
    
        static int64_t seek(void *opaque, int64_t offset, int whence) {
            my_iocontext_private* h = static_cast<my_iocontext_private*>(opaque);
    
            // use lseeki64 instead of fseek
            return fseek(h->f_, static_cast<long>(offset), whence);        
        }
        ::AVIOContext *get_avio() { return ctx_; }
    
    private:
        int buffer_size_;
        unsigned char * buffer_;  
        FILE * f_;
        ::AVIOContext * ctx_;
    };
    
    int main(int argc, char* argv[])
    {
        FILE * f = fopen("myfile.dmp", "wb");    
        my_iocontext_private priv_ctx(f); 
    
        AVFormatContext * ctx = ::avformat_alloc_context();
        ctx->pb = priv_ctx.get_avio();
    
        /// using ctx
    
        fclose(f); 
        return 0;
    }
    

    【讨论】:

    • 谢谢,非常有帮助。如何创建自己的 AVIOContext?
    • pogorskiy,您能帮我解答link 的问题吗?或以某种方式提供俄语对话的联系信息。
    • @Tarhan 电子邮件至 pogorskiy@gmail.com
    • 我正在为高通公司的编码器构建一个多路复用器。你能告诉我'my_tune_codec(strmCodec);'是怎么做的吗?有效吗?
    猜你喜欢
    • 1970-01-01
    • 2014-10-12
    • 2012-07-15
    • 1970-01-01
    • 2014-01-23
    • 2013-04-14
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多