我认为让您感到困惑的是,AVFrame 似乎有两个分配。
第一个,用 完成avcodec_alloc_frame()
,为通用框架及其元数据分配空间。此时,保持帧正确所需的内存仍然未知。
width
然后从另一个源填充该帧,然后通过传递和height
颜色深度来指定需要多少内存:
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
此时帧和它的内容是两个独立的对象(一个 AVFrame 和它的缓冲区)。您将它们与这段代码放在一起,这实际上根本不是转换:
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
上面的代码所做的是“告诉” 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);
上面的代码提取视频帧并将其解码为pFrame
(原生格式)。我们可以在这个阶段保存pFrame
到磁盘。我们不需要buffer
,然后我们就不能使用pFrameRGB
.
相反,我们使用sws_scale()
.
要将帧转换为另一种格式,我们将源复制到不同的目标。这既是因为目标帧可能比源帧所能容纳的更大,而且因为某些转换算法需要在未转换的源的更大区域上进行操作,因此就地变形源会很尴尬。此外,源框架由库处理,并且可能无法安全写入。
更新(评论)
data[]
pFrame/pFrameRGB 指向什么:最初,什么都没有。它们为 NULL,这就是为什么使用未初始化的 AVframe 会导致核心转储。linesize[]
您使用avpicture_fill
(适合空缓冲区,加上图像格式和大小信息)或解码函数之一(执行相同操作)初始化它们(等)。
为什么 pFrame 不需要内存分配:好问题。答案在 used 函数的原型和布局中,其中图片参数是这样描述的:
将存储解码视频帧的 AVFrame。使用 avcodec_alloc_frame 获取 AVFrame,编解码器将为实际的位图分配内存。使用默认的 get/release_buffer(),解码器会释放/重用它认为合适的位图。使用覆盖的 get/release_buffer()(需要 CODEC_CAP_DR1),用户决定解码器解码到哪个缓冲区,一旦不再需要数据,解码器就会告诉用户,用户应用程序此时可以释放/重用/保留内存它认为合适。