FFmpeg之yuv裁剪(二十一)

1. 裁剪NV21NV12

需要注意YUV三者的共用关系,Y的裁剪比较直接;但是对于UV而言,UV的大小各只有Y的大小的1/4(U的宽高和V的宽高都是Y的宽高的一半),因此在横纵向都要进行跳行,在横向由于UV是交叉排序,width / 2 的V和 width / 2 的U加起来刚好就是Y的大小,可以直接按偏移量裁剪。

void cropYuv420sp(char *yuv420sp, char *cropYuv420sp, int width, int height, int left, int top,
                  int right, int bottom) {
    int halfWidth = width / 2;
    int cropImageWidth = right - left;
    int cropImageHeight = bottom - top;

    //复制Y
    int originalYLineStart = top * width;
    int targetYIndex = 0;

    //复制UV
    int originalUVLineStart = width * height + top * halfWidth;
    int targetUVIndex = cropImageWidth * cropImageHeight;
    for (int i = top; i < bottom; i++) {
        memcpy(cropYuv420sp + targetYIndex, yuv420sp + originalYLineStart + left, cropImageWidth);
        originalYLineStart += width;
        targetYIndex += cropImageWidth;
        if ((i & 1) == 0) {
            memcpy(cropYuv420sp + targetUVIndex, yuv420sp + originalUVLineStart + left,
                   cropImageWidth);
            originalUVLineStart += width;
            targetUVIndex += cropImageWidth;
        }
    }
}

2. 裁剪YV12I420

和裁剪NV21类似,Y的裁剪比较直接;但是对于UV而言,UV的大小各只有Y的大小的1/4,且是各自连续排序(U的宽高和V的宽高都是Y的宽高的一半),因此在横纵向都要进行跳行。

void cropYuv420p(char *yuv420p, char *cropYuv420p, int width, int height, int left, int top,
                 int right, int bottom) {
    int halfWidth = width / 2;
    int cropImageWidth = right - left;
    int cropImageHeight = bottom - top;

    //复制Y
    int originalYLineStart = top * width;
    int targetYIndex = 0;

    //复制UV
    int originalULineStart = width * height + top * halfWidth / 2;
    int originalVLineStart = width * height + width * height / 4 + top * halfWidth / 2;
    int targetUIndex = cropImageWidth * cropImageHeight;
    int targetVIndex = cropImageWidth * cropImageHeight * 5 / 4;
    int halfImageWidth = halfWidth;
    int halfLeft = left / 2;
    int halfCropImageWidth = cropImageWidth / 2;
    for (int i = top; i < bottom; i++) {
        memcpy(cropYuv420p + targetYIndex, yuv420p + originalYLineStart + left, cropImageWidth);
        originalYLineStart += width;
        targetYIndex += cropImageWidth;
        if ((i & 1) == 0) {
            memcpy(cropYuv420p + targetUIndex, yuv420p + originalULineStart + halfLeft,
                   halfCropImageWidth);
            memcpy(cropYuv420p + targetVIndex, yuv420p + originalVLineStart + halfLeft,
                   halfCropImageWidth);
            originalULineStart += halfImageWidth;
            originalVLineStart += halfImageWidth;
            targetUIndex += halfCropImageWidth;
            targetVIndex += halfCropImageWidth;
        }
    }
}

3. 裁剪YUYV

NV21I420之类的数据不同,YUYV的排列方式是YUYV YUYV....,每行的连续4个byte会有共用关系,这4个byte相当于2个像素),每行的数据宽度是 width * 2。
注意:该函数对入参有限制,需要裁剪的边界都需要是偶数。

void cropYuyv(char *yuyv, char *cropYuyv, int width, int height, int left, int top, int right,
              int bottom) {

    int cropImageWidth = right - left;
    int cropImageHeight = bottom - top;

    int lineDataSize = width * 2;
    int cropLineDataSize = cropImageWidth * 2;

    int originalLineStart = top * width * 2;
    int targetIndex = 0;
    int lineOffsetDataSize = left * 2;
    for (int i = top; i < bottom; i++) {
        memcpy(cropYuyv + targetIndex, yuyv + originalLineStart + lineOffsetDataSize, cropLineDataSize);
        originalLineStart += lineDataSize;
        targetIndex += cropLineDataSize;
    }
}

4. 裁剪BGR24

无论是BGR24RGB24,在裁剪时,都是以3个byte为一个整体进行裁剪,因此以下代码兼容24bpp的RGB数据的裁剪。

void cropRgb24(char *rgb24, char *cropRgb24, int width, int height, int left, int top, int right,
               int bottom) {

    int cropImageWidth = right - left;
    int cropImageHeight = bottom - top;

    int lineDataSize = width * 3;
    int cropLineDataSize = cropImageWidth * 3;

    int originalLineStart = top * lineDataSize;
    int targetIndex = 0;

    int lineOffsetDataSize = left * 3;

    for (int i = top; i < bottom; i++) {
        memcpy(cropRgb24 + targetIndex, rgb24 + originalLineStart + lineOffsetDataSize, cropLineDataSize);
        originalLineStart += lineDataSize;
        targetIndex += cropLineDataSize;
    }
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付 59.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值