FFMPEG--图像处理Swscale

SwsContext可用于缩放yuv/rgb图像的大小或者改变其像素点颜色空间格式。

初始化

Libswscale使用起来很方便,最主要的函数只有3个:
(1) sws_getContext():使用参数初始化SwsContext结构体。
(2) sws_scale():转换一帧图像。
(3) sws_freeContext():释放SwsContext结构体。
其中sws_getContext()也可以用另一个接口函数sws_getCachedContext()取代。

像素格式

(1)后缀带P的如yuv420p,则y/u/v分别存放在AVFrame.data[0]/data[1]/data[2]。
(2)后缀不带P的如rgb24,则rgb数据都存放在AVFrame.data[0]中。

AVFrame

本文实例是通过将图像读取到AVFrame中,然后在进行swscale处理的,所以这里介绍下AVFrame的初始化及处理

注意,我们操作yuv数据时,要根据像素格式,响应的访问avFrame.data[0/1/2],以获取正确的yuv数据。

//初始化源图AVFrame结构
    AVFrame* ptFrameSrc= av_frame_alloc();
    int dwSrcPictureSize = avpicture_get_size(em_Src_Pix_fmt, dwSrc_Width, dwSrc_Height);
    //上边的只是alloc了一个AVFrame的结构体,真正数据存放在pbySrcBuf中
    uint8_t* pbySrcBuf = (uint8_t*)av_malloc(dwSrcPictureSize);
    avpicture_fill((AVPicture *)ptFrameSrc, pbySrcBuf, em_Src_Pix_fmt, dwSrc_Width, dwSrc_Height);

示例



#include <stdio.h>

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


#define _SRC_WIDTH 1920
#define _SRC_HEIGHT 1080
#define _DST_WIDTH 1280
#define _DST_HEIGHT 720

#define _SRC_FILE_NAME "1080P.420pyuv"
#define _DST_FILE_NAME "720P.422pyuv"

#define ASSERT(X) if(!(X)){printf("####[%s:%d]assert failed:%s\n", __FUNCTION__, __LINE__, #X);}

int main()
{
    //源图像信息
    const int dwSrc_Width = _SRC_WIDTH;
    const int dwSrc_Height =_SRC_HEIGHT;
    enum AVPixelFormat em_Src_Pix_fmt = AV_PIX_FMT_YUV420P;
    int dwSrc_YSize = dwSrc_Width * dwSrc_Height;
    int dwSrc_UVSize = dwSrc_YSize/4;

    //初始化源图AVFrame结构
    AVFrame* ptFrameSrc= av_frame_alloc();
    int dwSrcPictureSize = avpicture_get_size(em_Src_Pix_fmt, dwSrc_Width, dwSrc_Height);
    //上边的只是alloc了一个AVFrame的结构体,真正数据存放在pbySrcBuf中
    uint8_t* pbySrcBuf = (uint8_t*)av_malloc(dwSrcPictureSize);
    avpicture_fill((AVPicture *)ptFrameSrc, pbySrcBuf, em_Src_Pix_fmt, dwSrc_Width, dwSrc_Height);


    FILE* pf_Src = fopen(_SRC_FILE_NAME, "rb");
    ASSERT(pf_Src != NULL);

    //目的图像信息
    const int dwDst_Width = _DST_WIDTH;
    const int dwDst_Height = _DST_HEIGHT;
    enum AVPixelFormat em_Dst_Pix_fmt = AV_PIX_FMT_RGB24;
    int dwDst_YSize = dwDst_Width * dwDst_Height;
    int dwDst_UVSize = dwDst_YSize;

    //初始化目的图像AVFrame结构
    AVFrame* ptFrameDst= av_frame_alloc();
    int dwDstPictureSize = avpicture_get_size(em_Dst_Pix_fmt, dwDst_Width, dwDst_Height);
    printf("dwDstPictureSize:%d\n", dwDstPictureSize);
    uint8_t* pbyDstBuf = (uint8_t*)av_malloc(dwDstPictureSize);
    avpicture_fill((AVPicture *)ptFrameDst, pbyDstBuf, em_Dst_Pix_fmt, dwDst_Width, dwDst_Height);

    printf("Dst:(w:%d, h:%d), line0:%d, lin1:%d, line2:%d\n", 
        ptFrameDst->width, ptFrameDst->height, 
        ptFrameDst->linesize[0], ptFrameDst->linesize[1], ptFrameDst->linesize[2]);

    printf("Dst: data0-%p,%p, data1-%p,%p, data2-%p\n",
        ptFrameDst->data[0], ptFrameDst->data[0] + dwDst_YSize, ptFrameDst->data[1], ptFrameDst->data[1] + dwDst_YSize/2, ptFrameDst->data[2]);

    FILE* pf_Dst = fopen(_DST_FILE_NAME, "wb");
    ASSERT(pf_Dst != NULL);

    //获取SwsContext
    struct SwsContext* ptImgConvertCtx = sws_getContext(dwSrc_Width, dwSrc_Height, em_Src_Pix_fmt, \
        dwDst_Width, dwDst_Height, em_Dst_Pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
    ASSERT(ptImgConvertCtx != NULL);

    int dwCnt = 0;
    for(;;)
    {

        //一帧AV_PIX_FMT_YUV420P图像的大小dwSrc_YSize*3/2, 而且这里的data[0] data[1] data[2]必定是连续的
        ASSERT((ptFrameSrc->data[1]) == (ptFrameSrc->data[0] + dwSrc_YSize));
        ASSERT((ptFrameSrc->data[2]) == (ptFrameSrc->data[1] + dwSrc_YSize/4));
        int dwRWSize = fread(ptFrameSrc->data[0], 1, dwSrc_YSize, pf_Src);
        dwRWSize += fread(ptFrameSrc->data[1], 1, dwSrc_UVSize, pf_Src);
        dwRWSize += fread(ptFrameSrc->data[2], 1, dwSrc_UVSize, pf_Src);
        if (dwRWSize <=0)
        {
            if (feof(pf_Src))
            {
                fclose(pf_Src);
                fclose(pf_Dst);
                pf_Src = NULL;
                pf_Dst = NULL;

                av_log(NULL, AV_LOG_INFO, "end of src file\n");
                break;
            }
        }
        dwCnt++;
        if (!ptFrameSrc->height)
        {
            //很奇怪的是avpicture_fill仅设置了ptFraemSrc的data和linesize, 并没有设置ptFrameSrc的宽高值,
            ptFrameSrc->height = dwSrc_Height;
        }

        //sws处理
        sws_scale(ptImgConvertCtx, (const uint8_t* const*)ptFrameSrc->data, ptFrameSrc->linesize, 0, ptFrameSrc->height, 
            ptFrameDst->data, ptFrameDst->linesize);

        dwRWSize = fwrite(ptFrameDst->data[0], 1, dwDst_YSize*3, pf_Dst);
        //dwRWSize = fwrite(ptFrameDst->data[1], 1, dwDst_UVSize, pf_Dst);
        //dwRWSize = fwrite(ptFrameDst->data[2], 1, dwDst_UVSize, pf_Dst);
        fflush(pf_Dst);
    }

    av_frame_free(&ptFrameSrc); //记得释放
    av_frame_free(&ptFrameDst);
    sws_freeContext(ptImgConvertCtx);
}

雷神的一个相关文章给了另外的操作swscale的方式,我这里复制下来,想看原文的可以通过最后的连接看:

 #include <stdio.h>
 extern "C"
 {
 #include "libswscale/swscale.h"
 #include "libavutil/opt.h"
 #include "libavutil/imgutils.h"
 }
int main(int argc, char* argv[])  
{  
    //Parameters      
    FILE *src_file =fopen("sintel_480x272_yuv420p.yuv", "rb");  
    const int src_w=480,src_h=272;  
    AVPixelFormat src_pixfmt=AV_PIX_FMT_YUV420P;  

    int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt));  

    FILE *dst_file = fopen("sintel_1280x720_rgb24.rgb", "wb");  
    const int dst_w=1280,dst_h=720;  
    AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGB24;  
    int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));  

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

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

    int rescale_method=SWS_BICUBIC;  
    struct SwsContext *img_convert_ctx;  
    uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/8);  

    int frame_idx=0;  
    int ret=0;  
    ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1);  
    if (ret< 0) {  
        printf( "Could not allocate source image\n");  
        return -1;  
    }  
    ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1);  
    if (ret< 0) {  
        printf( "Could not allocate destination image\n");  
        return -1;  
    }  
    //-----------------------------   
    //Init Method 1  
    img_convert_ctx =sws_alloc_context();  
    //Show AVOption  
    av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,0);  
    //Set Value  
    av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,0);  
    av_opt_set_int(img_convert_ctx,"srcw",src_w,0);  
    av_opt_set_int(img_convert_ctx,"srch",src_h,0);  
    av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,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",dst_w,0);  
    av_opt_set_int(img_convert_ctx,"dsth",dst_h,0);  
    av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,0);  
    av_opt_set_int(img_convert_ctx,"dst_range",1,0);  
    sws_init_context(img_convert_ctx,NULL,NULL);  

    //Init Method 2  
    //img_convert_ctx = sws_getContext(src_w, src_h,src_pixfmt, dst_w, dst_h, dst_pixfmt,   
    //  rescale_method, NULL, NULL, NULL);   
    //-----------------------------  
    /* 
    //Colorspace 
    ret=sws_setColorspaceDetails(img_convert_ctx,sws_getCoefficients(SWS_CS_ITU601),0, 
        sws_getCoefficients(SWS_CS_ITU709),0, 
         0, 1 << 16, 1 << 16); 
    if (ret==-1) { 
        printf( "Colorspace not support.\n"); 
        return -1; 
    } 
    */  
    while(1)  
    {  
        if (fread(temp_buffer, 1, src_w*src_h*src_bpp/8, src_file) != src_w*src_h*src_bpp/8){  
            break;  
        }  

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

        sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);  
        printf("Finish process frame %5d\n",frame_idx);  
        frame_idx++;  

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

    sws_freeContext(img_convert_ctx);  

    free(temp_buffer);  
    fclose(dst_file);  
    av_freep(&src_data[0]);  
    av_freep(&dst_data[0]);  

    return 0;  
}  

本文主要参考雷神的三篇文档:
最简单的基于FFmpeg的libswscale的示例(YUV转RGB)

FFmpeg源代码简单分析:libswscale的sws_scale()

FFmpeg源代码简单分析:libswscale的sws_getContext()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ffmpeg是一个广泛使用的开源多媒体处理库,支持多种音视频编解码格式。在使用ffmpeg进行JPG解码时,它会将JPG图像转换为YUV格式。YUV是一种用于存储和传输彩色图像的格式,它将亮度(Y)和色度(U和V)分离开来。 首先,ffmpeg会读取JPG图像文件,并将其解析为像素数据。然后,它会根据JPG中的颜色信息,将像素数据转换为YUV格式。Y分量表示图像的亮度信息,U和V分量表示图像的色度信息。 在进行YUV转换时,ffmpeg会根据JPG图像的色彩空间信息进行自适应处理。常见的色彩空间包括RGB和YCbCr,其中YCbCr就是一种YUV的变体。通过将RGB图像转换为YCbCr,可以更有效地压缩图像数据,并减少存储或传输所需的空间和带宽。 因此,当使用ffmpeg解码JPG图像时,它会将输入的JPG转换为YUV格式,并提供Y,U和V三个分量的像素数据。这些像素数据可以根据需要进行进一步的处理或者用于其他操作,如视频编码、图像处理等。 总之,使用ffmpeg解码JPG图像时,它会将图像转换为YUV格式,将亮度和色度信息分离开来,以便于后续的处理和应用。 ### 回答2: FFmpeg是一个开源的多媒体处理工具集,可以实现音视频的编解码、转码、处理等功能。在FFmpeg中,可以通过使用libjpeg库来实现JPG格式的解码。 JPG是一种常见的图片压缩格式,其编码方式使用了基于离散余弦变换(DCT)的算法。要解码JPG图片到YUV格式,需要以下几个步骤: 1. 打开JPG文件:通过FFmpeg提供的接口,可以打开并读取JPG文件。 2. 解码JPG图像:使用libjpeg库提供的函数,可以将JPG图像解码为RGB(红绿蓝)格式。 3. 转换为YUV格式:在FFmpeg中,可以使用swscale库提供的函数将RGB图像转换为YUV格式。YUV是一种常用的视频颜色空间,其中包括亮度(Y)和色度(U、V)分量。 4. 保存YUV图像:将转换后的YUV图像保存到文件中,或者用于后续的视频处理。 需要注意的是,解码JPG到YUV格式是一个比较复杂的过程,需要对图像编码和颜色空间转换等进行处理。在使用FFmpeg进行解码时,可以针对具体的需求选择不同的设置和参数,以获得所需的解码效果。 总之,使用FFmpeg可以方便地实现JPG图像解码为YUV格式的功能,通过调用FFmpeg提供的接口和库函数,可以完成文件的打开、图像的解码和颜色空间的转换等操作。这为后续的视频处理提供了基础。 ### 回答3: ffmpeg是一个开源的多媒体处理工具,可以在命令行中使用。jpg是一种常见的图片格式,而yuv则是一种常见的视频像素格式。 使用ffmpeg解码jpg图片到yuv像素格式的过程可以分为以下几步: 1. 安装ffmpeg:在电脑上安装ffmpeg软件,可以从官方网站或其他途径下载并安装。 2. 打开命令行界面:在电脑上打开命令行界面,可以通过搜索或者运行cmd命令打开。 3. 编写解码命令:在命令行中输入ffmpeg的解码命令。命令的基本格式如下所示: `ffmpeg -i input.jpg -pix_fmt yuv420p output.yuv` 这条命令中,`-i input.jpg`表示输入的jpg图片文件,`-pix_fmt yuv420p`表示输出的像素格式为yuv420p,`output.yuv`表示输出的yuv文件名。 4. 执行命令:在命令行中按下回车键执行解码命令。此时,ffmpeg会加载输入的jpg文件,将其解码成yuv420p格式,并输出到指定的文件中。 通过以上步骤,我们可以使用ffmpeg将jpg图片解码为yuv像素格式。这样的操作对于一些视频处理任务或者需要将图片转换为视频的应用场景非常有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值