利用ffmpeg进行图像数据格式的转换以及图片的缩放应用中,主要用到了swscale.h文件中的三个函数,分别是:

  struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
int dstW, int dstH, enum AVPixelFormat dstFormat,
int flags, SwsFilter *srcFilter,
SwsFilter *dstFilter, const double *param);
  int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[]);
  void sws_freeContext(struct SwsContext *swsContext);

sws_getContext函数可以看做是初始化函数,它的参数定义分别为:

int srcW,int srcH 为原始图像数据的高和宽;

 int dstW,int dstH 为输出图像数据的高和宽;

enum AVPixelFormat srcFormat 为输入和输出图片数据的类型;eg:AV_PIX_FMT_YUV420、PAV_PIX_FMT_RGB24;

int flags 为scale算法种类;eg:SWS_BICUBIC、SWS_BICUBLIN、SWS_POINT、SWS_SINC;

SwsFilter *srcFilter ,SwsFilter *dstFilter,const double *param 可以不用管,全为NULL即可;

sws_scale函数则为执行函数,它的参数定义分别为:

struct SwsContext *c 为sws_getContext函数返回的值;

const uint8_t *const srcSlice[],uint8_t *const dst[] 为输入输出图像数据各颜色通道的buffer指针数组;

const int srcStride[],const int dstStride[] 为输入输出图像数据各颜色通道每行存储的字节数数组;

int srcSliceY 为从输入图像数据的第多少列开始逐行扫描,通常设为0;

     int srcSliceH 为需要扫描多少行,通常为输入图像数据的高度;

 sws_freeContext函数为结束函数,它的参数即为sws_getContext函数返回的值;

做一个实际缩放YUV420函数打包实例如下:

int ScaleImg(AVCodecContext *pCodecCtx,AVFrame *src_picture,AVFrame *dst_picture,int nDstH ,int nDstW )
{
  int i ;
  int nSrcStride[3];
  int nDstStride[3];
  int nSrcH = pCodecCtx->height;
  int nSrcW = pCodecCtx->width;
  struct SwsContext* m_pSwsContext;   uint8_t *pSrcBuff[3] = {src_picture->data[0],src_picture->data[1], src_picture->data[2]};   nSrcStride[0] = nSrcW ;
  nSrcStride[1] = nSrcW/2 ;
  nSrcStride[2] = nSrcW/2 ;   dst_picture->linesize[0] = nDstW;
  dst_picture->linesize[1] = nDstW / 2;
  dst_picture->linesize[2] = nDstW / 2;   printf("nSrcW%d\n",nSrcW);   m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
                   nDstW, nDstH, PIX_FMT_YUV420P,
                     SWS_BICUBIC,
                     NULL, NULL, NULL);   if (NULL == m_pSwsContext)
  {
    printf("ffmpeg get context error!\n");
    exit (-1);
  }
  sws_scale(m_pSwsContext, src_picture->data,src_picture->linesize, 0, pCodecCtx->height,dst_picture->data,dst_picture->linesize);   printf("line0:%d line1:%d line2:%d\n",dst_picture->linesize[0] ,dst_picture->linesize[1] ,dst_picture->linesize[2]);
  sws_freeContext(m_pSwsContext);   return 1 ;
}

函数很简单,申请环境初始指针,后缩放即可。读到此文的朋友,这个函数可以直接拷贝使用哟。如果有疑问可以留言或者邮件:leoluopy@gmail.com

RGB的缩放可以参考下面:

int ScaleYUVImgToRGB(int nSrcW,int nSrcH ,uint8_t* src_data,int *linesize,int nDstW ,int nDstH )
{
int i ; int ret ; FILE *nRGB_file ; AVFrame *nDst_picture ;
struct SwsContext* m_pSwsContext; nDst_picture = avcodec_alloc_frame();
if (!nDst_picture){
printf("nDst_picture avcodec_alloc_frame failed\n");
exit(1);
}
if(avpicture_alloc((AVPicture *)nDst_picture,PIX_FMT_RGB24,nDstW, nDstH)<0){
printf("dst_picture avpicture_alloc failed\n");
exit(1);
}
m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
nDstW, nDstH, PIX_FMT_RGB24,
SWS_BICUBIC,
NULL, NULL, NULL); if (NULL == m_pSwsContext)
{
printf("ffmpeg get context error!\n");
exit (-1);
} ret = sws_scale(m_pSwsContext, src_data,linesize, 0,nSrcH,nDst_picture->data,nDst_picture->linesize); nRGB_file = fopen("..\\YUV_STREAM\\RGBFile.rgb","ab+");
fwrite(nDst_picture->data[0],nDstW*nDstH*3,1,nRGB_file);
fclose(nRGB_file); sws_freeContext(m_pSwsContext);
avpicture_free((AVPicture *)nDst_picture); return 0;
}

参数data  和 linesize 参考yuv平面指针即可。

同时如果不想使用AVPicture结构的话,可以参考下面的:(注意不同图像类型,linesize一定要写对)

char* H264Decoder_c::ScaleYUVImgToRGB(int nSrcW,int nSrcH ,uint8_t** src_data,int *linesize,int nDstW ,int nDstH )
{
int i ; int ret ; FILE *nRGB_file ; struct SwsContext* m_pSwsContext;
char* out_Img[3];
int out_linesize[3];
out_linesize[0] = 2*nDstW ; //out_linesize[1] = nDstW ;out_linesize[2] = nDstW ;
out_Img[0] = g_RGBImg ; m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
nDstW, nDstH, PIX_FMT_RGB565,
SWS_BICUBIC,
NULL, NULL, NULL); if (NULL == m_pSwsContext)
{
printf("ffmpeg get context error!\n");
exit (-1);
} ret = sws_scale(m_pSwsContext, src_data,linesize, 0,nSrcH,(uint8_t**)out_Img,out_linesize);
#if 0
nRGB_file = fopen("./RGBFile.rgb","ab+");
fwrite(out_Img[0],nDstW*nDstH*2,1,nRGB_file);
fclose(nRGB_file); #endif sws_freeContext(m_pSwsContext); return out_Img[0];
}

目的位图的空间申请:

注意:上面的缩放函数如果直接使用而在没有解码成功或者没有申请目的位图空间时,将报段错误。

原因:没有解码成功,位图源地址将是指向空的地址,目的位图地址同样。

申请目的位图的方式:

dst_picture = avcodec_alloc_frame();
if (!dst_picture){
  return ;
}
if(avpicture_alloc((AVPicture *)dst_picture, c->pix_fmt,c->width*2, c->height*2)<0){
  printf("dst_picture allocate failed\n");
  exit(1);
}

初始化后即可以用于缩放了。

图像的内存Dump方法:

上文已经比较详细的阐述了ffmpeg的解码以及缩放原理及流程,然而在实际运用环境中,无论是从实时播放或者是从历史回放来看,我们需要的是像素位图,而不是ffmpeg的结构体。那么怎么转换呢?下文介绍了相关的内容。

作为实际运用环境中,像素位图格式,笔者使用的是比较常用的YUV格式。

编解码图像格式

          承接上文继续,在大部分现场环境下,为了节省传送带宽以及提高系统工作效率,视频原始位图格式以及解码后展示格式一般使用YUV420。
          其中YV12以及IYUV是最常见的格式。
          简单的说,YUV格式又分为平面格式以及打包格式。他们各有利弊。本文使用的是YUV平面格式即三通道分别使用不同入口地址存储,这样的好处是,与ffmpeg解码接口方面,AVFrame中数据结构可以便捷拷贝图像信息。

YV12:

IYUV

 
这里做简单的叙述:详细可以参考:

http://blog.csdn.net/searchsun/article/details/2443867

如何Dump

  好了,对YUV格式又初步了解后,下面介绍如果导出这像素位图数据。ffmpeg将图像的亮度以及色差信息保存在AVFrame中的data[0]、data[1]、data[2]中。

  详细参考:

AVFrame和AVPicture对比:

http://yul100887.blog.163.com/blog/static/200336135201211143525930/

所有操作均是针对这三个指针展开的,如下:

pgm_save(picture->data[0], picture->linesize[0], //Y
c->width, c->height, outfilename);
pgm_save(picture->data[1], picture->linesize[1],
c->width/2, c->height/2, outfilename); //U
pgm_save(picture->data[2], picture->linesize[2],
c->width/2, c->height/2, outfilename); //V
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
FILE *f;
int i;   f=fopen(filename,"ab+");
  for(i=0;i<ysize;i++)
  {
    fwrite(buf + i * wrap, 1, xsize, f );
  }
  fclose(f);
}

代码对YUV三个像素通道分开dump,读者可以根据自己的需要对函数进行包装。data[0] 是亮度信息入口指针,同时传入图像长宽,以及存储内存区域行宽。 data[1]  data[2] 类似。

最后需要注意的是:linesize总是容易被遗忘,livesize[0]=height ,livesize[1]=height/2 ,livesize[2]=height /2,

==================================================================================

原帖地址:http://blog.csdn.net/gubenpeiyuan/article/details/19548019?utm_source=tuicool

其参考地址:

参考文章:

使用ffmpeg进行图像格式转换及缩放

http://blog.csdn.net/skys_broyal/article/details/10337147

AVFrame和AVPicture对比:

http://yul100887.blog.163.com/blog/static/200336135201211143525930/

FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)

http://blog.csdn.net/leixiaohua1020/article/details/14215391

ffmpeg编解码H264

http://blog.csdn.net/chinabinlang/article/details/7088590

h264检测是I帧还是P帧

http://blog.csdn.net/zgyulongfei/article/details/7558031

最简单的基于FFmpeg的Swscale示例(YUV转RGB)

/**
* 最简单的基于FFmpeg的Swscale示例
* Simplest FFmpeg Swscale
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序使用libswscale对像素数据进行缩放转换等处理。
* 是最简单的libswscale的教程。
*
* This software uses libswscale to scale / convert pixels.
* It the simplest tutorial about libswscale.
*/ #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=,src_h=;
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=,dst_h=;
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[];
int src_linesize[]; uint8_t *dst_data[];
int dst_linesize[]; int rescale_method=SWS_BICUBIC;
struct SwsContext *img_convert_ctx;
uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/); int frame_idx=;
int ret=;
ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, );
if (ret< ) {
printf( "Could not allocate source image\n");
return -;
}
ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, );
if (ret< ) {
printf( "Could not allocate destination image\n");
return -;
}
//-----------------------------
//Init Method 1
img_convert_ctx =sws_alloc_context();
//Show AVOption
av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,NULL);
//Set Value
av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,NULL);
av_opt_set_int(img_convert_ctx,"srcw",src_w,NULL);
av_opt_set_int(img_convert_ctx,"srch",src_h,NULL);
av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,NULL);
//'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)
av_opt_set_int(img_convert_ctx,"src_range",,NULL);
av_opt_set_int(img_convert_ctx,"dstw",dst_w,NULL);
av_opt_set_int(img_convert_ctx,"dsth",dst_h,NULL);
av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,NULL);
av_opt_set_int(img_convert_ctx,"dst_range",,NULL);
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()
{
if (fread(temp_buffer, , src_w*src_h*src_bpp/, src_file) != src_w*src_h*src_bpp/){
break;
} switch(src_pixfmt){
case AV_PIX_FMT_GRAY8:{
memcpy(src_data[],temp_buffer,src_w*src_h);
break;
}
case AV_PIX_FMT_YUV420P:{
memcpy(src_data[],temp_buffer,src_w*src_h); //Y
memcpy(src_data[],temp_buffer+src_w*src_h,src_w*src_h/); //U
memcpy(src_data[],temp_buffer+src_w*src_h*/,src_w*src_h/); //V
break;
}
case AV_PIX_FMT_YUV422P:{
memcpy(src_data[],temp_buffer,src_w*src_h); //Y
memcpy(src_data[],temp_buffer+src_w*src_h,src_w*src_h/); //U
memcpy(src_data[],temp_buffer+src_w*src_h*/,src_w*src_h/); //V
break;
}
case AV_PIX_FMT_YUV444P:{
memcpy(src_data[],temp_buffer,src_w*src_h); //Y
memcpy(src_data[],temp_buffer+src_w*src_h,src_w*src_h); //U
memcpy(src_data[],temp_buffer+src_w*src_h*,src_w*src_h); //V
break;
}
case AV_PIX_FMT_YUYV422:{
memcpy(src_data[],temp_buffer,src_w*src_h*); //Packed
break;
}
case AV_PIX_FMT_RGB24:{
memcpy(src_data[],temp_buffer,src_w*src_h*); //Packed
break;
}
default:{
printf("Not Support Input Pixel Format.\n");
break;
}
} sws_scale(img_convert_ctx, src_data, src_linesize, , 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[],,dst_w*dst_h,dst_file);
break;
}
case AV_PIX_FMT_YUV420P:{
fwrite(dst_data[],,dst_w*dst_h,dst_file); //Y
fwrite(dst_data[],,dst_w*dst_h/,dst_file); //U
fwrite(dst_data[],,dst_w*dst_h/,dst_file); //V
break;
}
case AV_PIX_FMT_YUV422P:{
fwrite(dst_data[],,dst_w*dst_h,dst_file); //Y
fwrite(dst_data[],,dst_w*dst_h/,dst_file); //U
fwrite(dst_data[],,dst_w*dst_h/,dst_file); //V
break;
}
case AV_PIX_FMT_YUV444P:{
fwrite(dst_data[],,dst_w*dst_h,dst_file); //Y
fwrite(dst_data[],,dst_w*dst_h,dst_file); //U
fwrite(dst_data[],,dst_w*dst_h,dst_file); //V
break;
}
case AV_PIX_FMT_YUYV422:{
fwrite(dst_data[],,dst_w*dst_h*,dst_file); //Packed
break;
}
case AV_PIX_FMT_RGB24:{
fwrite(dst_data[],,dst_w*dst_h*,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[]);
av_freep(&dst_data[]); return ;
}

FFmpeg缩放swscale详解 <转>的更多相关文章

  1. ffmpeg命令参数详解

    ffmpeg命令参数详解 http://linux.51yip.com/search/ffmpeg ffmpeg图片加滤镜效果 参考:https://cloud.tencent.com/develop ...

  2. OpenGL的glScalef缩放变换函数详解

    glScalef是openGL中的模型缩放函数,就是把当前矩阵与一个表示延各个轴对物体进行拉伸.压缩.反射的矩阵相乘.这个物体的每个点的x,y,z坐标与对应的xyz参数相乘. 先看函数定义void g ...

  3. android的ScaleGestureDetector缩放类详解

    文章由多出组合,它们来自: http://elvajxw.iteye.com/blog/1308452 http://www.cnblogs.com/lknlfy/archive/2012/03/11 ...

  4. FFmpeg av_seek_frame规律详解

    本帖最后由 TangMonk 于 2016-7-27 10:26 编辑 1 av_seek_frame对视频进行跳转规律 1.1 flags参数 #define AVSEEK_FLAG_BACKWAR ...

  5. Echarts dataZoom缩放功能参数详解:

    dataZoom=[ //区域缩放 { id: 'dataZoomX', show:true, //是否显示 组件.如果设置为 false,不会显示,但是数据过滤的功能还存在. backgroundC ...

  6. ffmpeg 详解

    来源:http://blog.itpub.net/9399028/viewspace-1242300/ FFMPEG详解   认识FFMPEG FFMPEG堪称自由软件中最完备的一套多媒体支持库,它几 ...

  7. ffmpeg播放器实现详解 - 视频显示

    ffplay是ffmpeg源码中一个自带的开源播放器实例,同时支持本地视频文件的播放以及在线流媒体播放,功能非常强大. FFplay: FFplay is a very simple and port ...

  8. FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  9. CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)

    CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)   在CSS3中,可以利用transform功能来实现文字或图像的旋转.缩放.倾 ...

随机推荐

  1. 第26讲 对话框AlertDialog的自定义实现

    第26讲对话框AlertDialog的自定义实现 比如我们在开发过长当中,要通过介绍系统发送的一个广播弹出一个dialog.但是dialog必需是基于activity才能呈现出来,如果没有activi ...

  2. JavaScript运算符有哪些

    JavaScript中的运算符有很多,主要分为算术运算符,等同全同运算符,比较运算符,字符串运算符,逻辑运算符,赋值运算符等.这些运算符都有一些属于自己的运算规则,下面就为大家介绍一下JavaScri ...

  3. android布局属性具体解释

    RelativeLayout用到的一些重要的属性: 1:LinearLayout ( 线性布局 ) (里面仅仅能够有一个控件,而且不能设计这个控件的位置,控件会放到左上角) 线性布局分为水平线性和垂直 ...

  4. 使用Gradle构建Android应用内测版本

    在开发应用的过程中,有时候需要比较当前线上版本和正在开发中的版本差异,目前的做法只能是在两个不同的设备上面安装线上版本和开发中的版本,因为当前版本在调试过程中会覆盖旧版本.本文通过使用gradle来构 ...

  5. Hacker(23)----破解常见文件密码

    Win7中,office文档.压缩文件等都是常见的文件,这些文档含有重要的信息,即使用户为这些文件设置了密码,黑客也会有办法破解. 一.破解office文档密码 破解office文档密码常用工具是Ad ...

  6. asp Eval()函数的一些使用总结

    一.函数的原型: Eval(string s); s可以是变量,表达式,语句: 二.使用: 1.s为变量时,返回该变量的值,如:string s = "sss";Eval(s);/ ...

  7. .NET程序猿 - 提升幸福感的组件一览

    1.Newtonsoft.Json.net 操作JSON最简便的方式.  .Net 3.5开始,Framework集成Json序列化器:JavaScriptSerializer,然而Json.net给 ...

  8. 使用QTP打开应用程序的三种方法

    1. systemUtil.Run ‘SystemUtil对象的Run方法 SystemUtil.Run “http://192.168.11.82/XXX” 参数实例: File:“http://1 ...

  9. UISearchDisplayController简单使用

    最近在做一个简单的app入门,中间有一个页面用到了搜索框,本来以为很简单的控件,没想到用到的时候才发现很麻烦. 搜索框使用过程大约有以下几个状态:不活跃-活跃-输入关键词-根据关键词动态列出相关结果- ...

  10. poj2378 树形DP

    C - 树形dp Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bit ...