将 RGB 转换为 YUV,+ ffmpeg
Posted
技术标签:
【中文标题】将 RGB 转换为 YUV,+ ffmpeg【英文标题】:Converting RGB to YUV, + ffmpeg 【发布时间】:2012-02-27 10:13:49 【问题描述】:我正在尝试以下方法从我的 Flash/AIR 应用程序中录制实时视频:
-
我每帧拍摄一个“屏幕截图”(舞台上的 BitmapData)。
我将每个像素转换为像这样 (V2) 的 yuv 格式:
var file :File = new File(_appUrl + "/creation/output.raw");
var fs :FileStream = new FileStream();
fs.open(file, FileMode.WRITE);
var finalY :ByteArray = new ByteArray();
var finalU :ByteArray = new ByteArray();
var finalV :ByteArray = new ByteArray();
var rect :Rectangle = new Rectangle(0, 0, 600, 700);
var pixels :ByteArray;
var pixel :uint;
var r :uint;
var g :uint;
var b :uint;
_screenBuffer = _screenBuffer.reverse();
while (_screenBuffer.length > 0)
pixels = BitmapData(_screenBuffer.pop()).getPixels(rect);
pixels.position = 0;
// Convert and save each pixel
for (var x:int = 0; x < 600; x++)
for (var y:int = 0; y < 700; y++)
// Convert to yuv
pixel = pixels.readUnsignedInt();
r = pixel >> 16 & 0xff;
g = pixel >> 8 & 0xff;
b = pixel & 0xff;
// Y' is written for each pixel
finalY.writeByte(0.257 * r + 0.504 * g + 0.098 * b + 128);
// U and V are written once per 2x2 pixel block
if (x % 2 == 0 && y % 2 == 0)
finalU.writeByte(-0.148 * r - 0.291 * g + 0.439 * b + 128);
finalV.writeByte(0.439 * r - 0.368 * g - 0.071 * b + 128);
// Write the converted bytes to the file
finalY.position = 0;
finalU.position = 0;
finalV.position = 0;
fs.writeBytes(finalY, 0, finalY.length);
fs.writeBytes(finalU, 0, finalU.length);
fs.writeBytes(finalV, 0, finalV.length);
fs.close();
我使用以下 ffmpeg 行将原始文件转换为视频:
ffmpeg -r 30 -pix_fmt yuv420p -s 600x700 -vcodec rawvideo -f rawvideo -i output.raw -y test.mp4
创建了一个视频,但它只是一团糟,几乎不像录制的内容。我知道捕获过程有效,因为我尝试了与SimpleFlvWriter 相同的 BitmapData“截图”。
所以,要么是我的转换有问题,要么是 ffmpeg 行有问题,但我不知道。
这是创建视频时 ffmpeg 输出的内容,也许它可以帮助某人:
libavutil 51. 39.100 / 51. 39.100
libavcodec 54. 3.101 / 54. 3.101
libavformat 54. 1.100 / 54. 1.100
libavdevice 53. 4.100 / 53. 4.100
libavfilter 2. 62.101 / 2. 62.101
libswscale 2. 1.100 / 2. 1.100
libswresample 0. 7.100 / 0. 7.100
libpostproc 52. 0.100 / 52. 0.100
[rawvideo @ 01D39FC0] Estimating duration from bitrate, this may be inaccurate
Input #0, rawvideo, from 'output.raw':
Duration: N/A, start: 0.000000, bitrate: N/A
Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p, 600x700, 30 tbr,
30 tbn, 30 tbc
[buffer @ 01D3FEC0] w:600 h:700 pixfmt:yuv420p tb:1/1000000 sar:0/1 sws_param:
[libx264 @ 0375DB80] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE 4.2 AVX
[libx264 @ 0375DB80] profile High, level 3.1
[libx264 @ 0375DB80] 264 - core 120 r2146 bcd41db - H.264/MPEG-4 AVC codec - Copyleft 2003-2011 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'test.mp4':
Metadata:
encoder : Lavf54.1.100
Stream #0:0: Video: h264 (![0][0][0] / 0x0021), yuv420p, 600x700, q=-1--1, 30 tbn, 30 tbc
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo -> libx264)
Press [q] to stop, [?] for help
Truncating packet of size 630000 to 1
frame= 48 fps= 0 q=-1.0 Lsize= 157kB time=00:00:01.53 bitrate= 837.3kbits/s
video:156kB audio:0kB global headers:0kB muxing overhead 0.687626%
[libx264 @ 0375DB80] frame I:3 Avg QP:23.15 size: 23480
[libx264 @ 0375DB80] frame P:38 Avg QP:28.80 size: 2169
[libx264 @ 0375DB80] frame B:7 Avg QP:29.61 size: 833
[libx264 @ 0375DB80] consecutive B-frames: 79.2% 4.2% 0.0% 16.7%
[libx264 @ 0375DB80] mb I I16..4: 41.4% 6.2% 52.4%
[libx264 @ 0375DB80] mb P I16..4: 10.6% 3.3% 0.9% P16..4: 68.4% 1.3% 1.2% 0.0% 0.0% skip:14.2%
[libx264 @ 0375DB80] mb B I16..4: 0.0% 0.0% 0.0% B16..8: 13.3% 2.2% 0.7% direct: 1.9% skip:81.9% L0:51.6% L1:47.4% BI: 1.0%
[libx264 @ 0375DB80] 8x8 transform intra:16.7% inter:31.2%
[libx264 @ 0375DB80] coded y,uvDC,uvAC intra: 14.7% 25.5% 22.3% inter: 1.0% 4.1% 3.4%
[libx264 @ 0375DB80] i16 v,h,dc,p: 87% 11% 2% 0%
[libx264 @ 0375DB80] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 3% 18% 75% 1% 0% 1% 1% 0% 0%
[libx264 @ 0375DB80] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 6% 74% 12% 1% 1% 1% 2% 1% 2%
[libx264 @ 0375DB80] i8c dc,h,v,p: 51% 45% 4% 1%
[libx264 @ 0375DB80] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0375DB80] ref P L0: 4.6% 0.4% 94.6% 0.3%
[libx264 @ 0375DB80] ref B L0: 96.0% 4.0%
[libx264 @ 0375DB80] ref B L1: 96.5% 3.5%
[libx264 @ 0375DB80] kb/s:793.39
我并不是真正的编解码器专家(刚刚开始;)),所以我不知道该怎么做。
Here is a zip 包含其中一帧和视频输出。 应该可见的是一个绿色的微笑梨,没有任何人工制品。请记住,大小为 600x700,格式为 yuv420。最好使用 irfanview、IMO 查看此类原始图像文件。不要介意噪音,它来自我的麦克风;)
【问题讨论】:
【参考方案1】:你使用像素格式
-pix_fmt yuv420p
在内存中是
Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 U1234 U5678 V1234 V5678
即每个 4 像素的正方形有一个 U 和一个 V。此外,您首先拥有所有 Y,然后是所有 U,然后是所有 V。
看来你在写
Y1 U1 V1 Y2 U2 V2 ...
有多种像素格式。如果要使用yuv420p
,则需要坚持内存布局。检查Wikipedia entry on yuv420p
【讨论】:
是的,谢谢,我确定就是这样。转换为 yuv 比我想象的要复杂得多。而且大多数来源仅涵盖直接颜色版本。 请注意写入数据的位置 嗯,不幸的是,它仍然不起作用。我已更改函数以正确保存 YUV 字节。我还保存了每个转换帧的原始 *.yuv 图像以进行调试。当用 irfanview 打开时,那些看起来好多了,但视频仍然搞砸了。我将更新我的原始帖子以显示新功能。 我相信图像会太亮。问题是finalY.writeByte(0.257 * r + 0.504 * g + 0.098 * b + 128);
。删除 128
不,问题不在于颜色太亮。这很难解释,所以我上传了一个 zip,其中包含一个保存的帧和输出视频。一个微笑的绿色梨应该可见。 Download here 别介意噪音,它来自我的麦克风;)我也会把它添加到我的主帖中。以上是关于将 RGB 转换为 YUV,+ ffmpeg的主要内容,如果未能解决你的问题,请参考以下文章
将 Android camera2 api YUV_420_888 转换为 RGB
将 Yuv420 转换为 rgb 并在 qt pixmap 上显示
iOS 使用 vImage - 加速将 QCAR YUV 转换为 RGB
OpenCV for Android:使用 Imgproc.cvtColor 将相机预览从 YUV 转换为 RGB
使用 OpenCV 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度