解码后并排显示视频帧 (Android)
Showing video frames side by side after decoding (Android)
给定两个编码流,我想并排加入它们。假设我有两个具有相同帧速率的独立 H.264 编码的 1024x768 视频。我想将这两个组合起来,使视频 1 和视频 2 并排形成一个双倍宽度 (1024*2)x768 或 2048x768 的流。我的第一个想法是解码流并组合各个帧,然后重新编码单个流。解码和重新编码都很好,但它工作得非常慢(就像 ffmpeg 一样)。问题似乎在于将帧从 YUV 转换为 RGB 或将它们组合成 YUV 形式的计算时间。 Android 解码器产生 YUV,并且用于并排组合帧的数学对于该形式来说是密集的。所以我的问题是;
1) 如果帧是 YUV 格式,有没有更快或更有效的方法来合并帧?
2a) 如果不是,如果它们是 RGB 形式,那么合并它们在计算上是否更快?
2b) 如果是这样,我如何将 H.264 流解码为 Android 中的 RGB 帧?
P.S。尝试过的 ffmpeg 和 openCV 都需要 YUV 到 RGB 的转换,这使得它非常慢(~5fps)
谢谢!
组合这些图像需要什么复杂的数学运算?
您需要做的就是将 frameOfVideo1 中的每一行复制到索引 0 到 1023,并将 frameOfVideo2 中的每一行复制到索引 1024 到 2047。
(组合图像的线)
(这些是y平面的索引。u,v平面或uv平面(例如nv12)数字不同。但概念相同)
解码帧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 框架宽度和高度的一半。
给定两个编码流,我想并排加入它们。假设我有两个具有相同帧速率的独立 H.264 编码的 1024x768 视频。我想将这两个组合起来,使视频 1 和视频 2 并排形成一个双倍宽度 (1024*2)x768 或 2048x768 的流。我的第一个想法是解码流并组合各个帧,然后重新编码单个流。解码和重新编码都很好,但它工作得非常慢(就像 ffmpeg 一样)。问题似乎在于将帧从 YUV 转换为 RGB 或将它们组合成 YUV 形式的计算时间。 Android 解码器产生 YUV,并且用于并排组合帧的数学对于该形式来说是密集的。所以我的问题是;
1) 如果帧是 YUV 格式,有没有更快或更有效的方法来合并帧?
2a) 如果不是,如果它们是 RGB 形式,那么合并它们在计算上是否更快?
2b) 如果是这样,我如何将 H.264 流解码为 Android 中的 RGB 帧?
P.S。尝试过的 ffmpeg 和 openCV 都需要 YUV 到 RGB 的转换,这使得它非常慢(~5fps)
谢谢!
组合这些图像需要什么复杂的数学运算?
您需要做的就是将 frameOfVideo1 中的每一行复制到索引 0 到 1023,并将 frameOfVideo2 中的每一行复制到索引 1024 到 2047。 (组合图像的线)
(这些是y平面的索引。u,v平面或uv平面(例如nv12)数字不同。但概念相同)
解码帧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 框架宽度和高度的一半。