Pregunta

I would like a simple working example of using just libavformat to mux video. There are nice examples (doc/examples/muxing.c) that show encoding with libavcodec, muxing with libavformat and saving the data with libavio. However, there is no example I know of that uses libavformat by itself, feeding in encoded data in a buffer and getting muxed data in a buffer.

The difficulty is two-fold: one, adding a stream with avformat_new_stream(AVFormatContext *s, const AVCodec *c) requires a reference to the codec; and two, the output from muxing is passed to AVFormatContext->pb which is an AVIOContext*. Thus there seems to be no (obvious) way to extricate libavformat from the other libav libraries.

See also: This question mentions a way to not use libavio: Get TS packets into buffer from libavformat

¿Fue útil?

Solución

You can avoid dependencies on libavcodec library, but you need the header files (for example, avcodec.h).

The scheme is as follows:

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);

To get the output, you always have to use the concept of AVIOContext. You can avoid using the built-in protocols. To do this you need to create your own AVIOContext (::avio_alloc_context).

UPD To create your own AVIOContext, you have to do something like this

#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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top