У меня возникают проблемы с инкапсулированием необработанных пакетов 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);
}
Вы могли бы быть заинтересованы в взглянуть на этот FFmpeg патч: https://ffmpeg.org/pipermail/ffmpeg-devel/2014-November/164996.html Хотя я не могу найти фактическое «документ/примеры/avio_writing.c "в GF FFmpeg ... – Gediminas