为什么在将AVFrame从一种格式转换为另一种格式时需要缓冲区?

jsp*_*p99 5 c ffmpeg

我指的是这个源代码.这里提供的代码片段来自代码中的行(114-138).这是使用ffmpeg库.任何人都可以解释为什么程序中需要以下代码?

// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
              pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); 
Run Code Online (Sandbox Code Playgroud)

从某种意义上说,我理解以下函数将目标帧与缓冲区相关联.但是必要性是什么?

avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);  
Run Code Online (Sandbox Code Playgroud)

PS:我尝试删除缓冲区并编译程序.它被编译了.但它显示以下运行时错误.

[swscaler @ 0xa06d0a0]坏dst图像指针
分段错误(核心转储)

LSe*_*rni 26

我认为让你困惑的是AVFrame似乎有两个分配.

第一个完成avcodec_alloc_frame(),为通用框架及其元数据分配空间.此时,保持框架所需的存储器仍然是未知的.

然后,填充从另一个来源是框架,它是那么您可以指定需要多少内存通过传递width,height并且色彩深度:

numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
Run Code Online (Sandbox Code Playgroud)

此时,帧及其内容是两个独立的对象(AVFrame及其缓冲区).您将它们与此代码放在一起,这实际上根本不是转换:

avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
Run Code Online (Sandbox Code Playgroud)

上面的代码是"告诉" pFrameRGB:" 你是一个RGB-24帧,这个宽,这么高,你需要的内存是'缓冲' ".

然后,只有这样你才能做任何你想做的事pFrameRGB.否则,你试图在没有画布的框架上绘画,并且油漆向下飞溅 - 你得到一个核心转储.

一旦你有框架(AVFrame)和画布(缓冲区),你可以使用它:

// Read frames and save first five frames to disk
i=0;
while(av_read_frame(pFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) {
      // Decode video frame
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
&packet);
Run Code Online (Sandbox Code Playgroud)

上面的代码提取视频帧并将其解码为pFrame(原始格式).我们可以pFrame在这个阶段保存到磁盘.我们不需要buffer,然后我们就不能使用了pFrameRGB.

相反,我们使用将帧转换为RGB-24 sws_scale().

要将帧转换为另一种格式,我们将源复制到另一个目标.这是因为目标帧可能比源帧可以容纳的更大,并且因为一些转换算法需要在未转换源的更大区域上操作,所以在原位转换源是不方便的.此外,源帧由库处理,并且可能被认为不安全.

更新(评论)

什么是data[]P帧/ pFrameRGB中一点到:首先,没有什么.它们是NULL,这就是使用非初始化的AVframe导致核心转储的原因.linesize[]使用avpicture_fill(适合空缓冲区,图像格式和大小信息)或其中一个解码函数(执行相同操作)初始化它们(等).

为什么pFrame不需要内存分配:好问题.答案在于使用过的函数的原型和布局,其中描述了picture参数:

将存储解码视频帧的AVFrame.使用avcodec_alloc_frame获取AVFrame,编解码器将为实际位图分配内存.使用默认的get/release_buffer(),解码器可以根据需要释放/重用位图.使用重写的get/release_buffer()(需要CODEC_CAP_DR1),用户决定解码器解码的缓冲区,解码器告诉用户一旦不再需要数据,用户应用程序此时可以释放/重用/保留内存为它认为合适.