• 音视频入门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 格式:

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

    查看 YUV 文件

    1
    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]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #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]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #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]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    #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]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #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]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    #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

    内容有误?联系作者:

  • 相关阅读:
    2016/05/16 thinkphp3.2.2 验证码使用
    2016/05/16 UEditor 文本编辑器 使用教程与使用方法
    2016/05/15 ThinkPHP3.2.2 表单自动验证实例 验证规则的数组 直接写在相应的控制器里
    DropzoneJS 使用指南
    MVC设计模式
    Smarty 配置文件的读取
    会话控制
    JS中的call和apply
    CSS选择器
    XML
  • 原文地址:https://www.cnblogs.com/eastgeneral/p/16590622.html
Copyright © 2020-2023  润新知