【问题标题】:Showing video frames side by side after decoding (Android)解码后并排显示视频帧(Android)
【发布时间】:2018-01-14 04:48:00
【问题描述】:

给定两个编码流,我想并排加入它们。假设我有两个具有相同帧速率的独立 H.264 编码 1024x768 视频。我想将这两者结合起来,使视频 1 和视频 2 并排形成一个宽度为 (1024*2)x768 或 2048x768 的流。我的第一个想法是解码流并组合各个帧,然后重新编码单个流。解码和重新编码很好,这可以工作,但是它非常慢(就像 ffmpeg 一样)。问题似乎在于将帧从 YUV 转换为 RGB 或将它们组合成 YUV 形式的计算时间。 Android 解码器生成 YUV,用于并排组合帧的数学对于这种形式来说是密集的。所以我的问题是;

1) 如果帧是 YUV 形式,是否有更快或更有效的方法来组合帧?

2a) 如果不是,如果它们是 RGB 形式,在计算上组合它们是否会更快?

2b) 如果是这样,我将如何在 Android 中将 H.264 流解码为 RGB 帧?

附:尝试过的 ffmpeg 和 openCV 都需要 YUV 到 RGB 的转换,这使得它非常慢(~5fps)

谢谢!

【问题讨论】:

  • 你是用API还是命令行?
  • API 但在使用 ffmpeg 测试时使用了命令行
  • 最快的方法是为两个帧创建足够大的 YUV 缓冲区,并在将数据传递给编码器之前自己复制数据,而无需来回转换为 RGB。
  • 这是有道理的。但是,我认为由于 YUV 的性质,我无法批量复制和粘贴(即 memcpy)整个帧,我需要以交错方式进行,我认为这在效率/速度方面是一个大问题
  • 您还可以使用内联汇编器来加快从 2 帧复制的速度。很可能比 memcpy 或 C 函数快得多。

标签: android rgb framebuffer android-mediacodec yuv


【解决方案1】:

解码后的帧AVFrame在结构中有uint_t *data[]int linesize[]。一个 YUV 帧具有三个数据指针和三个线大小。线条尺寸通常大于宽度,因此请注意考虑到这一点。

这里有一些可能会有所帮助的伪代码。希望没有太多错别字。

// No proper checks in here, it's just for reference
// You could just as easily pass the data pointers for the outframe as uint8_t *data[]

void mergeFrames(AVFrame *frame1, AVFrame *frame2, AVFrame *outframe)
{
    // do Y frame
    uint32_t *out = outframe->data[0]; // 1 and 2 are for the U and V frames

    uint8_t *in1 = frame1->data[0];
    uint8_t *in2 = frame2->data[0];

    int height = outframe->height;
    int inwidth = frame1->width;
    int stride = frame1->linesize[0];
    int pos = 0;

    while (pos++ < height) {
        // left side

        uint32_t *in = (uint32_t*)(in1 + pos * stride); // <- stride, not width

        int c = frame1->width >> 2; // assume 4 bytes
        while (c--) *out++ = *in++;

        // right side

        in = (uint32_t*)(in2 + pos * stride);

        c = width >> 2;
        while (c--) *out++ = *in++;
    }

    // And the same for the U and V frames
}

编译器应该做好优化工作。

还要注意,在使用 U 和 V 框架时,它们的宽度和高度是 Y 框架的一半。

【讨论】:

  • 会试试这个并报告!
  • 所以这种工作......结果是框架并排但它完全被绿色着色
  • 如果它是绿色的,则 U 或 V 帧之一没有被正确复制。
【解决方案2】:

为了组合这些图像需要什么复杂的数学运算?

您需要做的就是将 frameOfVideo1 的每一行复制到索引 0 到 1023,并将 frameOfVideo2 的每一行复制到索引 1024 到 2047。 (组合图像的线)

(这些是 y 平面的索引。u、v 平面或 uv 平面(例如 nv12)的数字不同。但概念相同)

【讨论】:

  • 我的理解是你所描述的与 RGB 相关,这就是为什么它很容易,但对于 YUV 来说它更复杂,需要更多的数学运算,而不仅仅是简单的批量复制
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多