2015-06-05 2 views
5

У меня возникают проблемы с инкапсулированием необработанных пакетов H264 в контейнер mp4. Вместо того, чтобы записывать их на диск, я хочу сохранить результат в памяти. Я следовал этому подходу Raw H264 frames in mpegts container using libavcodec, но пока не был успешным.Выходной буфер ввода/вывода FFMPEG

Во-первых, это правильный способ записи в память? У меня есть небольшая структура в моем заголовке

struct IOOutput { 
    uint8_t* outBuffer; 
    int bytesSet; 
}; 

, где я инициализирую буфер и байты. Я тогда инициализировать мой AVIOContext переменная

AVIOContext* pIOCtx = avio_alloc_context(pBuffer, iBufSize, 1, outptr, NULL, write_packet, NULL); 

где outptr указатель ничтожным выхода IOOutput и write_packet выглядит следующим образом

int write_packet (void *opaque, uint8_t *buf, int buf_size) { 
    IOOutput* out = reinterpret_cast<IOOutput*>(opaque); 
    memcpy(out->outBuffer+out->bytesSet, buf, buf_size); 
    out->bytesSet+=buf_size; 
    return buf_size; 
} 

Затем я установил

fc->pb = pIOCtx; 
fc->flags = AVFMT_FLAG_CUSTOM_IO; 

на моем AVFormatContext * fc.

Затем, всякий раз, когда я кодировать NAL пакеты у меня есть из кадра, я пишу их к AVFormatContext с помощью av_interleaved_write_frame, а затем получить содержимое mp4 с помощью

void getBufferContent(char* buffer) { 
    memcpy(buffer, output.outBuffer, output.bytesSet); 
    output.bytesSet=0; 
} 

и, таким образом сбросить переменную bytesSet, так что во время следующие байты операции записи будут вставлены в начале буфера. Есть лучший способ сделать это? Действительно ли это правильный способ сделать это? FFMPEG выполняет какую-либо операцию чтения, если я только вызываю av_interleaved_write_frame и avformat_write_header, чтобы добавить пакеты?

спасибо, что заблаговременно!

EDIT

Вот код относительно процесса мультиплексирования - в моем кодирования функции у меня есть что-то вроде

int frame_size = x264_encoder_encode(obj->mEncoder, &obj->nals, &obj->i_nals, obj->pic_in, obj->pic_out); 
int total_size=0; 

for(int i=0; i<obj->i_nals;i++) 
    { 
     if (!obj->fc) { 
      obj->create(obj->nals[i].p_payload, obj->nals[i].i_payload); 
     } 

     if (obj->fc) { 
      obj->write_frame(obj->nals[i].p_payload, obj->nals[i].i_payload); 
     } 
    } 

// Here I get the output values 
int currentBufferSize = obj->output.bytesSet; 
char* mem = new char[currentBufferSize]; 
obj->getBufferContent(mem); 

а также создавать и писать функции выглядеть следующим образом

int create(void *p, int len) { 

    AVOutputFormat *of = av_guess_format("mp4", 0, 0); 

    fc = avformat_alloc_context(); 

    // Add video stream 
    AVStream *pst = av_new_stream(fc, 0); 
    vi = pst->index; 

    void* outptr = (void*) &output; 

// Create Buffer 
    pIOCtx = avio_alloc_context(pBuffer, iBufSize, 1, outptr, NULL, write_packet, NULL); 

    fc->oformat = of; 
    fc->pb = pIOCtx; 
    fc->flags = AVFMT_FLAG_CUSTOM_IO; 

    pcc = pst->codec; 

    AVCodec c= {0}; 
    c.type= AVMEDIA_TYPE_VIDEO; 

    avcodec_get_context_defaults3(pcc, &c); 
    pcc->codec_type = AVMEDIA_TYPE_VIDEO; 

    pcc->codec_id = codec_id; 
    pcc->bit_rate = br; 
    pcc->width = w; 
    pcc->height = h; 
    pcc->time_base.num = 1; 
    pcc->time_base.den = fps; 
} 

void write_frame(const void* p, int len) { 

    AVStream *pst = fc->streams[ vi ]; 

    // Init packet 
    AVPacket pkt; 
    av_init_packet(&pkt); 
    pkt.flags |= (0 >= getVopType(p, len)) ? AV_PKT_FLAG_KEY : 0; 
    pkt.stream_index = pst->index; 
    pkt.data = (uint8_t*)p; 
    pkt.size = len; 

    pkt.dts = AV_NOPTS_VALUE; 
    pkt.pts = AV_NOPTS_VALUE; 

    av_interleaved_write_frame(fc, &pkt); 

} 
+0

Вы могли бы быть заинтересованы в взглянуть на этот FFmpeg патч: https://ffmpeg.org/pipermail/ffmpeg-devel/2014-November/164996.html Хотя я не могу найти фактическое «документ/примеры/avio_writing.c "в GF FFmpeg ... – Gediminas

ответ

3

См. Документацию AVFormatContext.pb. Вы правильно настроили его, но не должны касаться AVFormatContext.flags. Кроме того, убедитесь, что вы установили его перед вызовом avformat_write_header().

Когда вы говорите «это не работает», что именно не работает? Не вызвана ли обратная связь? Являются ли данные в нем не ожидаемого типа/формата? Что-то другое? Если все, что вы хотите сделать, это написать сырые пакеты nal, тогда вы можете просто взять закодированные данные непосредственно из кодировщика (в AVPacket), это исходные данные. Если вы используете api libx264 напрямую, он даже дает вам каждый результат отдельно, поэтому вам не нужно его разбирать.

+0

Большое спасибо за ваш ответ! Поэтому мне не нужно вручную устанавливать AVFMT_FLAG_CUSTOM_IO, правильно?Пока у меня нет успеха в кодировании пакетов nal в контейнер mp4, и я подумал, что, возможно, данные не правильно записаны в буфер, и я не знал, будет ли это путь, или я может использовать некоторый класс FFMPEG, такой как AVStream, для выполнения задачи. Прямо сейчас, я создаю AVPacket, инициализирую его, копирую все nals в память, назначаю его пакету, а затем использую av_interleaved_write_frame. Однако это не работает. – peacer212

+0

Это должно работать, поэтому я задаюсь вопросом о вашем другом коде. Можете ли вы показать код, который обертывает исходные данные в AVPackets и записывает их? Кроме того, можете ли вы показать некоторую диагностику, например, как часто вызывается обратный вызов write_packet(), и каковы типичные значения для buf_size в этих обратных вызовах для заданной длины nal? –

+0

Привет, я отредактировал оригинальное сообщение и добавил мультиплексор - спасибо вам большое за вашу помощь! После небольшого тестирования я обнаружил, что я получаю следующую ошибку: [mp4 @ 0x101076c00] muxer не поддерживает вывод, который нельзя найти! Это означает, что мне нужно реализовать функцию поиска в avio_alloc_context, правильно? Как я могу это сделать, если я постоянно перезаписываю свой буфер? – peacer212