我认为让您感到困惑的是,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() 将帧转换为 RGB-24。
要将帧转换为另一种格式,我们将源复制到不同的目标。这既是因为目标帧可能比源帧所能容纳的更大,而且因为某些转换算法需要在未转换源的更大区域上进行操作,因此就地变形源会很尴尬。此外,源框架由库处理,可能无法安全写入。
更新(cmets)
pFrame/pFrameRGB 的data[] 指向什么:最初,什么都没有。它们为 NULL,这就是为什么使用未初始化的 AVframe 会导致核心转储。您使用avpicture_fill(适合空缓冲区,加上图像格式和大小信息)或解码函数之一(执行相同操作)初始化它们(和linesize[] 等)。
为什么 pFrame 不需要内存分配:好问题。答案在使用函数的prototype and layout 中,其中 picture 参数是这样描述的:
将存储解码视频帧的 AVFrame。采用
avcodec_alloc_frame 获取 AVFrame,编解码器将分配内存
对于实际位图。使用默认的 get/release_buffer(),解码器
释放/重用它认为合适的位图。被覆盖
get/release_buffer() (需要 CODEC_CAP_DR1) 用户决定进入什么
缓冲解码器解码,解码器一旦完成就告诉用户
不再需要数据,用户应用程序此时可以
释放/重用/保留它认为合适的内存。