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


    * 音视频入门文章目录 *

    libyuv

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

    准备工作

    一张图片

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

    image-demo-rainbow.png

    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 裁剪

    libyuv-yuv420p-clip.jpg

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

    #include <stdio.h>
    #include <stdint.h>
    #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 缩放

    libyuv-yuv420p-scale.jpg

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

    #include <stdio.h>
    #include <stdint.h>
    #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 旋转

    libyuv-yuv420p-rotation.jpg

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

    #include <stdio.h>
    #include <stdint.h>
    #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 镜像

    libyuv-yuv420p-mirror.jpg

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

    #include <stdio.h>
    #include <stdint.h>
    #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 混合

    libyuv-yuv420p-blend.jpg

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

    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #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

    内容有误?联系作者:

    联系作者


  • 相关阅读:
    C# 文件重命名
    C# 获取图像文件
    我开通了博客
    C# 图像截取
    C# 从txt读取内容
    Linux 下查看用户组信息
    部署Jenkins完整记录
    一篇文章搞定Java注解^_^
    Java基础之接口
    枚举让盗版美国总统wcc给你整明白哈哈
  • 原文地址:https://www.cnblogs.com/binglingziyu/p/audio-video-basic-10-libyuv-usage.html
Copyright © 2020-2023  润新知