FFMPEG I/O输出缓冲区

pea*_*212 6 c c++ ffmpeg

我目前在尝试将原始H264 nal数据包封装到mp4容器中时遇到问题.但是,我想将结果存储在内存中,而不是将它们写入磁盘.我使用libavcodec在mpegts容器中遵循这种方法原始H264帧但到目前为止还没有成功.

首先,这是写入内存的正确方法吗?我的标题中有一个小结构

struct IOOutput {
    uint8_t* outBuffer;
    int bytesSet;
};
Run Code Online (Sandbox Code Playgroud)

我初始化缓冲区和bytesset.然后我初始化我的AVIOContext变量

AVIOContext* pIOCtx = avio_alloc_context(pBuffer, iBufSize, 1, outptr, NULL, write_packet, NULL);
Run Code Online (Sandbox Code Playgroud)

其中outptr是指向IOOutput输出的void指针,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;
}
Run Code Online (Sandbox Code Playgroud)

我接着说

fc->pb = pIOCtx;
fc->flags = AVFMT_FLAG_CUSTOM_IO;
Run Code Online (Sandbox Code Playgroud)

在我的AVFormatContext*fc变量上.

然后,每当我从帧中编码nal数据包时,我通过av_interleaved_write_frame将它们写入AVFormatContext,然后通过以下方式获取mp4内容

void getBufferContent(char* buffer) {
    memcpy(buffer, output.outBuffer, output.bytesSet);
    output.bytesSet=0;
}
Run Code Online (Sandbox Code Playgroud)

因此重置变量bytesSet,因此在下一次写操作期间,将在缓冲区的开头插入字节.有一个更好的方法吗?这实际上是一种有效的方法吗?如果我只调用av_interleaved_write_frame和avformat_write_header来添加数据包,FFMPEG是否会执行任何读取操作?

非常感谢你提前!

编辑

这是关于多路复用过程的代码 - 在我的编码功能中我有类似的东西

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);
Run Code Online (Sandbox Code Playgroud)

而create和write函数看起来像这样

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

}
Run Code Online (Sandbox Code Playgroud)

Ron*_*tje 5

请参阅AVFormatContext.pb文档。您设置正确,但不应该触摸 AVFormatContext.flags。另外,请确保在调用 avformat_write_header() 之前设置它。

当你说“它不起作用”时,到底什么不起作用?回调没有被调用吗?其中的数据是否不是预期的类型/格式?还有别的事吗?如果您只想写入原始 nal 数据包,那么您可以直接从编码器(在 AVPacket 中)获取编码数据,这就是原始 nal 数据。如果您直接使用 libx264 的 api,它甚至会单独为您提供每个 nal,因此您无需解析它。