FFMPEG--图像处理Swscale

来源:互联网 发布:joel说软件 pdf 编辑:程序博客网 时间:2024/06/10 23:41

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 0
原创粉丝点击