ffmpeg libswscale实现YUV转RGB

2018-06-22  本文已影响0人  曾大稳丶

libswscale里面实现了各种图像像素格式的转换。

主要函数如下:

//使用参数初始化SwsContext结构体
sws_getContext()
//转换一帧图像
sws_scale()
//释放SwsContext结构体
sws_freeContext()

初始化函数:

//为SwsContext结构体分配内存
sws_alloc_context()
//设置SwsContext结构体的值
av_opt_set()/av_opt_set_XXX()
//初始化SwsContext结构体。
sws_init_context()

这种复杂的方法可以配置一些sws_getContext()配置不了的参数。比如说设置图像的YUV像素的取值范围是JPEG标准(Y、U、V取值范围都是0-255)还是MPEG标准(Y取值范围是16-235,U、V的取值范围是16-240)

获取像素格式信息:

//可以获得指定像素格式的AVPixFmtDescriptor结构体
av_pix_fmt_desc_get()
//通过AVPixFmtDescriptor获取值
av_get_bits_per_pixel() //获取比特数(bpp)

图像拉伸:

SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。

示例将通过yuv文件生成rgb文件,代码如下:

#include "stdafx.h"


extern "C" {
    #include <libswscale/swscale.h>
    #include <libavutil/opt.h>
    #include <libavutil/imgutils.h>
}


void p(const char * msg, int d = -1123) {
    if (d == -1123) {
        printf_s("%s\n", msg);
    }
    else {
        printf_s("%s  %d \n", msg, d);
    }
}


int yuv2Rgb(FILE *yuvFile,FILE * rgbFile) {

    SwsContext *img_convert_ctx = NULL;

    const AVPixelFormat srcPixelFormat = AV_PIX_FMT_YUV420P;
    const AVPixelFormat dstPixelFormat = AV_PIX_FMT_RGB24;

    const int srcW = 1080;
    const int srcH= 720;

    const int dstW = 540;
    const int dstH = 360;

    uint8_t *src_data[4];
    int src_linesize[4];

    uint8_t *dst_data[4];
    int dst_linesize[4];


    //1. 获得指定像素格式的AVPixFmtDescriptor结构体
    const AVPixFmtDescriptor * pSrcPixFmtDes = av_pix_fmt_desc_get(srcPixelFormat);
    //2. 获得指定像素格式每个像素占用的比特数bpp(Bit Per Pixel) 
    int srcBpp=  av_get_bits_per_pixel(pSrcPixFmtDes);

    const AVPixFmtDescriptor * pDstPixFmtDes = av_pix_fmt_desc_get(dstPixelFormat);
    int dstBpp = av_get_bits_per_pixel(pDstPixFmtDes);


    

    //3. 根据宽高,像素格式分配buffer大小
    if (av_image_alloc(src_data, src_linesize, srcW, srcH, srcPixelFormat, 1) < 0) {
        p("Could not allocate source image");
        return -1;
    }

    if (av_image_alloc(dst_data, dst_linesize, dstW, dstH, dstPixelFormat, 1) < 0) {
        p("Could not allocate source image");
        return -1;
    }

    //4. 为SwsContext结构体分配内存。
    img_convert_ctx = sws_alloc_context();
    //Show AVOption
    av_opt_show2(img_convert_ctx, stdout, AV_OPT_FLAG_VIDEO_PARAM, 0);




    //图像拉伸   SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。
    //const int rescale_method = SWS_BICUBIC;
    //5. 设置值
    av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC | SWS_PRINT_INFO, 0);
    av_opt_set_int(img_convert_ctx, "srcw", srcW, 0);
    av_opt_set_int(img_convert_ctx, "srch", srcH, 0);
    av_opt_set_int(img_convert_ctx, "src_format", srcPixelFormat, 0);
    //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)
    av_opt_set_int(img_convert_ctx, "src_range", 1, 0);
    av_opt_set_int(img_convert_ctx, "dstw", dstW, 0);
    av_opt_set_int(img_convert_ctx, "dsth", dstH, 0);
    av_opt_set_int(img_convert_ctx, "dst_format", dstPixelFormat, 0);
    av_opt_set_int(img_convert_ctx, "dst_range", 1, 0);
    sws_init_context(img_convert_ctx, NULL, NULL);//对SwsContext中的各种变量进行赋值

    
    uint8_t *temp_buffer = (uint8_t *)malloc(srcW *srcH *srcBpp / 8);

    int frame_idx = 0;
    while (1){
        if (fread(temp_buffer, 1, srcW*srcH*srcBpp / 8, yuvFile) != srcW * srcH*srcBpp / 8) {
            break;
        }

        switch (srcPixelFormat) {
            case AV_PIX_FMT_GRAY8: {
                memcpy(src_data[0], temp_buffer, srcW*srcH);
                break;
            }
            case AV_PIX_FMT_YUV420P: {
                memcpy(src_data[0], temp_buffer, srcW*srcH);                    //Y
                memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH / 4);      //U
                memcpy(src_data[2], temp_buffer + srcW * srcH * 5 / 4, srcW*srcH / 4);  //V
                break;
            }
            case AV_PIX_FMT_YUV422P: {
                memcpy(src_data[0], temp_buffer, srcW*srcH);                    //Y
                memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH / 2);      //U
                memcpy(src_data[2], temp_buffer + srcW * srcH * 3 / 2, srcW*srcH / 2);  //V
                break;
            }
            case AV_PIX_FMT_YUV444P: {
                memcpy(src_data[0], temp_buffer, srcW*srcH);                    //Y
                memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH);        //U
                memcpy(src_data[2], temp_buffer + srcW * srcH * 2, srcW*srcH);      //V
                break;
            }
            case AV_PIX_FMT_YUYV422: {
                memcpy(src_data[0], temp_buffer, srcW*srcH * 2);                  //Packed
                break;
            }
            case AV_PIX_FMT_RGB24: {
                memcpy(src_data[0], temp_buffer, srcW*srcH * 3);                  //Packed
                break;
            }
            default: {
                printf("Not Support Input Pixel Format.\n");
                break;
            }
        }

        sws_scale(img_convert_ctx, src_data, src_linesize, 0, srcH, dst_data, dst_linesize);//转换像素
        printf("Finish process frame %5d\n", frame_idx);
        frame_idx++;

        switch (dstPixelFormat) {
            case AV_PIX_FMT_GRAY8: {
                fwrite(dst_data[0], 1, dstW*dstH, rgbFile);
                break;
            }
            case AV_PIX_FMT_YUV420P: {
                fwrite(dst_data[0], 1, dstW*dstH, rgbFile);                 //Y
                fwrite(dst_data[1], 1, dstW*dstH / 4, rgbFile);               //U
                fwrite(dst_data[2], 1, dstW*dstH / 4, rgbFile);               //V
                break;
            }
            case AV_PIX_FMT_YUV422P: {
                fwrite(dst_data[0], 1, dstW*dstH, rgbFile);                 //Y
                fwrite(dst_data[1], 1, dstW*dstH / 2, rgbFile);               //U
                fwrite(dst_data[2], 1, dstW*dstH / 2, rgbFile);               //V
                break;
            }
            case AV_PIX_FMT_YUV444P: {
                fwrite(dst_data[0], 1, dstW*dstH, rgbFile);                 //Y
                fwrite(dst_data[1], 1, dstW*dstH, rgbFile);                 //U
                fwrite(dst_data[2], 1, dstW*dstH, rgbFile);                 //V
                break;
            }
            case AV_PIX_FMT_YUYV422: {
                fwrite(dst_data[0], 1, dstW*dstH * 2, rgbFile);               //Packed
                break;
            }
            case AV_PIX_FMT_RGB24: {
                fwrite(dst_data[0], 1, dstW*dstH * 3, rgbFile);               //Packed
                break;
            }
            default: {
                p("Not Support Output Pixel Format.\n");
                break;
            }
        }
    }

    sws_freeContext(img_convert_ctx);
    free(temp_buffer);
    av_freep(&src_data[0]);
    av_freep(&dst_data[0]);

    return 0;


}


int main() {
    FILE* inFile;
    FILE* outFile;
    fopen_s(&inFile,"F:/视频资源/gxsp.yuv", "rb");
    fopen_s(&outFile, "F:/视频资源/gxsp.rgb", "wb");
    yuv2Rgb(inFile,outFile);

    fclose(inFile);
    fclose(outFile);

    getchar();

    return 0;
}

参考链接:
libswscale实现YUV转RGB

相关格式转换:
视音频数据处理入门:RGB、YUV像素数据处理

上一篇下一篇

猜你喜欢

热点阅读