如何将 uint8 I420 视频数据的原始缓冲区拆分为 YUV 指针?
How can I split a raw buffer of uint8 I420 video data into YUV pointers?
我有一个原始 uint8 指针,指向包含 I420 格式视频数据的缓冲区和缓冲区大小。我也知道框架的宽度/高度。我想将数据输入到一个库中,该库可以通过此函数签名创建视频帧:
Copy(int width, int height,
const uint8_t* data_y, int stride_y,
const uint8_t* data_u, int stride_u,
const uint8_t* data_v, int stride_v)
是否有一些简单的指针算法可以解决这个问题?
据我所知,描述各种 YUV 和 RGB 视频格式的最佳网站是 FOURCC - YUV 描述是 here。
您所指的 I420 格式已被描述 here。这意味着您的原始数据将像这样组织:
- Y 平面,H x W 字节,线步幅为 W 字节
- U 平面,H/2 x W/2 字节,行步幅为 W/2 字节
- V 平面,H/2 x W/2 字节,行跨度为 W/2 字节
我发现 ffmpeg
是生成 YUV 数据以在您自己的软件中编码和解码的最佳工具。以下是使用 ffmpeg
和原始 YUV 的一些技巧。
您可以获得它支持的像素格式列表:
ffmpeg -pix_fmts
所以,为了找到你的,我找了一些里面有 420 的东西:
ffmpeg -pix_fmts | grep 420p
IO... yuv420p 3 12 8-8-8
所以我知道我需要 -pix_fmt yuv420p
来编码或解码您的数据。我还可以通过查看 ffmpeg
来源 here 获得有关布局方式的体面描述。上面的12表示每像素12位
然后我想:
- 使用
ffmpeg
生成示例 I420 帧
- 用
dd
将其分开并用IMageMagick 提取Y、U和V通道
- 用 ImageMagick
重新组合 Y、U 和 V 通道
- 重新组合 Y、U 和 V 通道
ffmpeg
所以我制作了以下 bash
脚本:
#!/bin/bash
################################################################################
# User-editable values
################################################################################
# Define WIDTH and HEIGHT of the frame we want to generate...
# ... so we are consistent all the way through
W=640
H=480
PIX_FMT="yuv420p"
################################################################################
# Derived values - do not edit
################################################################################
BASENAME="${PIX_FMT}-${W}x${H}"
FILENAME="${BASENAME}.raw"
PNGNAME="${BASENAME}.png"
UVW=$((W/2)) # width of U plane, same as V plane
UVH=$((H/2)) # height of U plane, same as V plane
YBYTES=$((H*W)) # bytes in Y plane
UBYTES=$((UVW*UVH)) # bytes in U plane, same as in V plane
# Generate a sample frame
echo "Generating sample: ${FILENAME}, and viewable PNG equivalent: ${PNGNAME}"
ffmpeg -y -f lavfi -i testsrc=size=${W}x${H}:rate=1:duration=1 -vcodec rawvideo -pix_fmt "$PIX_FMT" -f image2pipe - > "$FILENAME"
ffmpeg -y -f lavfi -i testsrc=size=${W}x${H}:rate=1:duration=1 "$PNGNAME"
# Check its size in bytes
ls -l "$FILENAME"
# Extract Y plane from sample into "Y.png" using ImageMagick
echo "Extracting Y plane into Y.png"
dd if="$FILENAME" bs=$YBYTES count=1 | magick -depth 8 -size ${W}x${H} gray:- Y.png
# Extract U plane from sample into "U.png" using ImageMagick
echo "Extracting U plane into U.png"
dd if="$FILENAME" bs=1 skip=$YBYTES count=$UBYTES | magick -depth 8 -size ${UVW}x${UVH} gray:- U.png
# Extract V plane from sample into "V.png" using ImageMagick
echo "Extracting V plane into V.png"
dd if="$FILENAME" bs=1 skip=$((YBYTES+UBYTES)) count=$UBYTES | magick -depth 8 -size ${UVW}x${UVH} gray:- V.png
# Recombine with ImageMagick
echo "Combining Y.png, U.png, V.png into result.png"
magick Y.png \( U.png v.png -resize 200% \) -set colorspace YUV -combine result.png
# Create a PNG from the YUV420p raw data just the same with 'ffmpeg'
echo "Create PNG from the YUV420p raw data as 'extracted.png'"
ffmpeg -y -f rawvideo -video_size 640x480 -pixel_format yuv420p -i - extracted.png < "$FILENAME"
将此图像创建为 PNG 和 I420 数据供您测试:
以及这些 Y、U 和 V 平面:
我有一个原始 uint8 指针,指向包含 I420 格式视频数据的缓冲区和缓冲区大小。我也知道框架的宽度/高度。我想将数据输入到一个库中,该库可以通过此函数签名创建视频帧:
Copy(int width, int height,
const uint8_t* data_y, int stride_y,
const uint8_t* data_u, int stride_u,
const uint8_t* data_v, int stride_v)
是否有一些简单的指针算法可以解决这个问题?
据我所知,描述各种 YUV 和 RGB 视频格式的最佳网站是 FOURCC - YUV 描述是 here。
您所指的 I420 格式已被描述 here。这意味着您的原始数据将像这样组织:
- Y 平面,H x W 字节,线步幅为 W 字节
- U 平面,H/2 x W/2 字节,行步幅为 W/2 字节
- V 平面,H/2 x W/2 字节,行跨度为 W/2 字节
我发现 ffmpeg
是生成 YUV 数据以在您自己的软件中编码和解码的最佳工具。以下是使用 ffmpeg
和原始 YUV 的一些技巧。
您可以获得它支持的像素格式列表:
ffmpeg -pix_fmts
所以,为了找到你的,我找了一些里面有 420 的东西:
ffmpeg -pix_fmts | grep 420p
IO... yuv420p 3 12 8-8-8
所以我知道我需要 -pix_fmt yuv420p
来编码或解码您的数据。我还可以通过查看 ffmpeg
来源 here 获得有关布局方式的体面描述。上面的12表示每像素12位
然后我想:
- 使用
ffmpeg
生成示例 I420 帧
- 用
dd
将其分开并用IMageMagick 提取Y、U和V通道
- 用 ImageMagick 重新组合 Y、U 和 V 通道
- 重新组合 Y、U 和 V 通道
ffmpeg
所以我制作了以下 bash
脚本:
#!/bin/bash
################################################################################
# User-editable values
################################################################################
# Define WIDTH and HEIGHT of the frame we want to generate...
# ... so we are consistent all the way through
W=640
H=480
PIX_FMT="yuv420p"
################################################################################
# Derived values - do not edit
################################################################################
BASENAME="${PIX_FMT}-${W}x${H}"
FILENAME="${BASENAME}.raw"
PNGNAME="${BASENAME}.png"
UVW=$((W/2)) # width of U plane, same as V plane
UVH=$((H/2)) # height of U plane, same as V plane
YBYTES=$((H*W)) # bytes in Y plane
UBYTES=$((UVW*UVH)) # bytes in U plane, same as in V plane
# Generate a sample frame
echo "Generating sample: ${FILENAME}, and viewable PNG equivalent: ${PNGNAME}"
ffmpeg -y -f lavfi -i testsrc=size=${W}x${H}:rate=1:duration=1 -vcodec rawvideo -pix_fmt "$PIX_FMT" -f image2pipe - > "$FILENAME"
ffmpeg -y -f lavfi -i testsrc=size=${W}x${H}:rate=1:duration=1 "$PNGNAME"
# Check its size in bytes
ls -l "$FILENAME"
# Extract Y plane from sample into "Y.png" using ImageMagick
echo "Extracting Y plane into Y.png"
dd if="$FILENAME" bs=$YBYTES count=1 | magick -depth 8 -size ${W}x${H} gray:- Y.png
# Extract U plane from sample into "U.png" using ImageMagick
echo "Extracting U plane into U.png"
dd if="$FILENAME" bs=1 skip=$YBYTES count=$UBYTES | magick -depth 8 -size ${UVW}x${UVH} gray:- U.png
# Extract V plane from sample into "V.png" using ImageMagick
echo "Extracting V plane into V.png"
dd if="$FILENAME" bs=1 skip=$((YBYTES+UBYTES)) count=$UBYTES | magick -depth 8 -size ${UVW}x${UVH} gray:- V.png
# Recombine with ImageMagick
echo "Combining Y.png, U.png, V.png into result.png"
magick Y.png \( U.png v.png -resize 200% \) -set colorspace YUV -combine result.png
# Create a PNG from the YUV420p raw data just the same with 'ffmpeg'
echo "Create PNG from the YUV420p raw data as 'extracted.png'"
ffmpeg -y -f rawvideo -video_size 640x480 -pixel_format yuv420p -i - extracted.png < "$FILENAME"
将此图像创建为 PNG 和 I420 数据供您测试:
以及这些 Y、U 和 V 平面: