音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合

音视频入门文章目录

libyuv

libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换、旋转、缩放等的库。它是跨平台的,可在 Windows、Linux、Mac、Android 等操作系统,x86、x64、arm 架构上进行编译运行,支持 SSE、AVX、NEON 等 SIMD 指令加速。

准备工作

一张图片

下载 rainbow-700x700.bmp BMP 图片 或者 自己准备一张图片(知道分辨率,如:700x700)

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第1张图片

FFmpeg 工具包

FFmpeg 工具下载

根据自己的系统,下载 FFmpeg Static 工具包。

得到所需的 yuv420p 文件

将上面准备的图片转换成 YUV420P 格式:

ffmpeg -i rainbow.bmp -video_size 700x700 -pix_fmt yuv420p rainbow-yuv420p.yuv

查看 YUV 文件

ffplay -f rawvideo -pixel_format yuv420p -video_size 700x700 rainbow-yuv420p.yuv

libyuv 操作 YUV

YUV 裁剪

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第2张图片

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-clip-x-y.yuv]

#include 
#include 
#include "libyuv.h"

void clip(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int cropX, int cropY, int cropWidth, int cropHeight) {
    ConvertToI420(
            srcYuvData,
            width*height*3/2,
            dstYuvData,
            cropWidth,
            dstYuvData cropWidth*cropHeight,
            (cropWidth 1)/2,
            dstYuvData cropWidth*cropHeight ((cropWidth 1)/2)*((cropHeight 1)/2),
            (cropWidth 1)/2,
            cropX,
            cropY,
            width,
            height,
            cropWidth,
            cropHeight,
            kRotate0,
            FOURCC_YU12);
}

int main() {
    uint32_t width = 700, height = 700;
    uint32_t clipWidth = 200, clipHeight = 200;
    uint8_t YUV[width*height*3/2];
    uint8_t YUV_CLIP[clipWidth*clipHeight*3/2];

    FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
    fread(YUV, sizeof(YUV), 1, yuv420pFile);

    clip(YUV, YUV_CLIP, width, height, 0, 0, clipWidth, clipHeight);

    FILE *yuvClipFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-clip-0-0.yuv", "wb");
    fwrite(YUV_CLIP, sizeof(YUV_CLIP), 1, yuvClipFile);

    fclose(yuvClipFile);
    fclose(yuv420pFile);
    return 0;
}

YUV 缩放

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第3张图片

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-scale-X.yuv]

#include 
#include 
#include "libyuv.h"

void scale(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int dstWidth, int dstHeight) {
    I420Scale(
            srcYuvData,
            width,
            srcYuvData width*height,
            (width 1)/2,
            srcYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            width,
            height,
            dstYuvData,
            dstWidth,
            dstYuvData dstWidth*dstWidth,
            (dstWidth 1)/2,
            dstYuvData dstWidth*dstHeight ((dstWidth 1)/2)*((dstHeight 1)/2),
            (dstWidth 1)/2,
            dstWidth,
            dstHeight,
            kFilterNone
            );
}

int main() {
    uint32_t width = 700, height = 700;
    uint32_t dstWidth = 100, dstHeight = 100;
    uint8_t YUV[width*height*3/2];
    uint8_t YUV_SCALE[dstWidth*dstHeight*3/2];

    FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
    fread(YUV, sizeof(YUV), 1, yuv420pFile);

    scale(YUV, YUV_SCALE, width, height, dstWidth, dstHeight);

    FILE *yuvScaleFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-scale-6.yuv", "wb");
    fwrite(YUV_SCALE, sizeof(YUV_SCALE), 1, yuvScaleFile);

    fclose(yuvScaleFile);
    fclose(yuv420pFile);
    return 0;
}

YUV 旋转

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第4张图片

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-rotation-90.yuv]

#include 
#include 
#include "libyuv.h"

void rotation(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
    I420Rotate(
            srcYuvData,
            width,
            srcYuvData width*height,
            (width 1)/2,
            srcYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            dstYuvData,
            width,
            dstYuvData width*height,
            (width 1)/2,
            dstYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            width,
            height,
            kRotate90
            );
}

int main() {
    uint32_t width = 700, height = 700;
    uint8_t YUV[width*height*3/2];
    uint8_t YUV_ROTATION[width*height*3/2];

    FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
    fread(YUV, sizeof(YUV), 1, yuv420pFile);

    rotation(YUV, YUV_ROTATION, width, height);

    FILE *yuvRotationFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "wb");
    fwrite(YUV_ROTATION, sizeof(YUV_ROTATION), 1, yuvRotationFile);

    fclose(yuvRotationFile);
    fclose(yuv420pFile);
    return 0;
}

YUV 镜像

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第5张图片

[rainbow-yuv420p-rotation-90.yuv] -> [rainbow-yuv420p-rotation-90-mirror.yuv]

#include 
#include 
#include "libyuv.h"

void mirror(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
    I420Mirror(
            srcYuvData,
            width,
            srcYuvData width*height,
            (width 1)/2,
            srcYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            dstYuvData,
            width,
            dstYuvData width*height,
            (width 1)/2,
            dstYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            width,
            height
            );
}

int main() {
    uint32_t width = 700, height = 700;
    uint8_t YUV[width*height*3/2];
    uint8_t YUV_MIRROR[width*height*3/2];

    FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "rb");
    fread(YUV, sizeof(YUV), 1, yuv420pFile);

    mirror(YUV, YUV_MIRROR, width, height);

    FILE *yuvMirrorFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90-mirror.yuv", "wb");
    fwrite(YUV_MIRROR, sizeof(YUV_MIRROR), 1, yuvMirrorFile);

    fclose(yuvMirrorFile);
    fclose(yuv420pFile);
    return 0;
}

YUV 混合

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第6张图片

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-blend.yuv]

#include 
#include 
#include 
#include "libyuv.h"

void blend(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
    uint8_t YUV_ROTATION[width*height*3/2];
    I420Rotate(
            srcYuvData,
            width,
            srcYuvData width*height,
            (width 1)/2,
            srcYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            YUV_ROTATION,
            width,
            YUV_ROTATION width*height,
            (width 1)/2,
            YUV_ROTATION width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            width,
            height,
            kRotate90
    );

    // 透明度
    uint8_t alpha[width*height];
    memset(alpha, 0X88, width*height);

    I420Blend(
            srcYuvData,
            width,
            srcYuvData width*height,
            (width 1)/2,
            srcYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            YUV_ROTATION,
            width,
            YUV_ROTATION width*height,
            (width 1)/2,
            YUV_ROTATION width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            alpha,
            width,
            dstYuvData,
            width,
            dstYuvData width*height,
            (width 1)/2,
            dstYuvData width*height ((width 1)/2)*((height 1)/2),
            (width 1)/2,
            width,
            height
            );
}

int main() {
    uint32_t width = 700, height = 700;
    uint8_t YUV[width*height*3/2];
    uint8_t YUV_BLEND[width*height*3/2];

    FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
    fread(YUV, sizeof(YUV), 1, yuv420pFile);

    blend(YUV, YUV_BLEND, width, height);

    FILE *yuvBlendFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-blend.yuv", "wb");
    fwrite(YUV_BLEND, sizeof(YUV_BLEND), 1, yuvBlendFile);

    fclose(yuvBlendFile);
    fclose(yuv420pFile);
    return 0;
}

代码:10-yuv-conversion-libyuv

参考资料:

libyuv/libyuv

内容有误?联系作者:

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合_第7张图片

你可能感兴趣的:(音视频基础)