【问题标题】:Why do we need a buffer while converting AVFrame from one format to another?为什么在将 AVFrame 从一种格式转换为另一种格式时需要缓冲区?
【发布时间】:2012-12-17 19:20:38
【问题描述】:

我指的是this源代码。此处提供的代码 sn-ps 来自代码中的第 (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)); 

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

avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);  

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

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

【问题讨论】:

    标签: c ffmpeg


    【解决方案1】:

    ffmpeg 或类似的库不会进行就地缓冲区转换。首先是关于不丢失原始数据和使用不同缓冲区的速度。其次,如果你做了很多转换,你可以预先分配需要的缓冲区。

    【讨论】:

    • 你能不能通俗点解释一下!我没那么明白。另外,如果可能的话,请将它与具有隐式缓冲区的“SOMETHING”进行比较:) 谢谢。
    【解决方案2】:

    我认为让您感到困惑的是,AVFrame 似乎有两个分配。

    第一个使用avcodec_alloc_frame() 完成,为通用框架及其元数据分配空间。此时保持帧正确所需的内存仍然未知。

    然后您从另一个来源填充该帧,然后您通过传递 widthheight 和颜色深度来指定需要多少内存:

    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) 用户决定进入什么 缓冲解码器解码,解码器一旦完成就告诉用户 不再需要数据,用户应用程序此时可以 释放/重用/保留它认为合适的内存。

    【讨论】:

    • 我很困惑 :D .. This 非常著名的教程说我们正在将帧从原生格式转换为 RGB。
    • 是的,但这是另一个更进一步的操作。我正在更新答案,希望更清楚......
    • 为什么我们不需要 pFrame 的“画布”? pFrame 的 AVFrame 有 data[] 和 linesize[] 数组。那他们指的是什么?
    • @Iserni ...您的解释非常清楚。非常感谢:)
    • 很好的答案。 @lserni 是否有任何网络资源,除了文档之外,我可以在其中阅读 ffmpeg。我正在尝试在 iOS 中流式传输 RTSP 并进行一些优化。如果可以的话,在这里需要一些帮助。
    【解决方案3】:

    ffmpeg 在帧缓冲区中以特定顺序存储帧的像素数据。存储取决于图片格式(YUV,RGB,)。

    avpicture_fill() => 该函数获取原始缓冲区并设置 AVPicture 结构的各种指针。

    【讨论】:

    • 我所指的这些术语来自源代码: 'pFrame' 指向的 AVFrame 有 data[] 和 linesize[] 数组。但是在解码“数据包”之前我们没有为 pFrame 分配任何缓冲区,因此将接收到的帧放置在 pFrame 指向的 AVFrame 中。这些数组指向什么?
    猜你喜欢
    • 2018-01-20
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多