Как можно использовать libavformat без использования других библиотек libav?

Мне нужен простой рабочий пример использования только libavformat для мультиплексирования видео. Есть хорошие примеры (doc/examples/muxing.c), которые показывают кодировку с помощью libavcodec, мультиплексирование с помощью libavformat и сохранение данных с помощью libavio. Тем не менее, я не знаю ни одного примера, который использует libavformat сам по себе, загружая закодированные данные в буфер и получая мультиплексированные данные в буфер.

Сложность двоякая: во-первых, для добавления потока с avformat_new_stream(AVFormatContext *s, const AVCodec *c) требуется ссылка на кодек; и, во-вторых, выходные данные мультиплексирования передаются в AVFormatContext->pb, который является AVIOContext*. Таким образом, кажется, нет (очевидного) способа отделить libavformat от других библиотек libav.

См. Также: В этом вопросе упоминается способ не использовать libavio: Получить пакеты TS в буфер из libavformat


person Alex I    schedule 29.11.2012    source источник


Ответы (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;
}
person pogorskiy    schedule 30.11.2012
comment
Спасибо, очень полезно. Как мне создать свой собственный AVIOContext? - person Alex I; 30.11.2012
comment
Погорский, не могли бы вы помочь мне с моим вопросом в ссылка? или как-то предоставить контактную информацию для разговора на русском языке. - person Tarhan; 30.04.2013
comment
@Tarhan пишите на [email protected] - person pogorskiy; 02.05.2013
comment
Я создаю мультиплексор для кодировщика QUALCOMM. Не могли бы вы рассказать мне, как работает my_tune_codec(strmCodec); работает? - person Brendon Tsai; 05.06.2014