FFMPEG中的swscale提供了视频原始数据(YUV420,YUV422,YUV444,RGB24...)之间的转换,分辨率变换等操作,使用起来十分方便,在这里记录一下它的用法。
swscale主要用于在2个AVFrame之间进行转换。
下面来看一个视频解码的简单例子,这个程序完成了对"北京移动开发者大会茶歇视频2.flv"(其实就是优酷上的一个普通视频)的解码工作,并将解码后的数据保存为原始数据文件(例如YUV420,YUV422,RGB24等等)。其中略去了很多的代码。
- #include "stdafx.h"
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- AVFormatContext *pFormatCtx;
- int i, videoindex;
- AVCodecContext *pCodecCtx;
- AVCodec *pCodec;
- char filepath[]="北京移动开发者大会茶歇视频2.flv";
- av_register_all();
- avformat_network_init();
- pFormatCtx = avformat_alloc_context();
- if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
- printf("无法打开文件\n");
- return -1;
- }
-
- ......
-
- AVFrame *pFrame,*pFrameYUV;
- pFrame=avcodec_alloc_frame();
- pFrameYUV=avcodec_alloc_frame();
- uint8_t *out_buffer;
-
- out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height)];
- avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
-
-
- ......
-
- FILE *output=fopen("out.rgb","wb+");
-
- while(av_read_frame(pFormatCtx, packet)>=0)
- {
- if(packet->stream_index==videoindex)
- {
- ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
-
- if(ret < 0)
- {
- printf("解码错误\n");
- return -1;
- }
- if(got_picture)
- {
-
-
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
-
-
-
- fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height)*3,1,output);
-
- ......
-
- }
- }
- av_free_packet(packet);
- }
-
- fclose(output);
-
- ......
-
- return 0;
- }
从代码中可以看出,解码后的视频帧数据保存在pFrame变量中,然后经过swscale函数转换后,将视频帧数据保存在pFrameYUV变量中。最后将pFrameYUV中的数据写入成文件。
在本代码中,将数据保存成了RGB24的格式。如果想保存成其他格式,比如YUV420,YUV422等,需要做2个步骤:
1.初始化pFrameYUV的时候,设定想要转换的格式:
- AVFrame *pFrame,*pFrameYUV;
- pFrame=avcodec_alloc_frame();
- pFrameYUV=avcodec_alloc_frame();
- uint8_t *out_buffer;
-
- out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height)];
- avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
只需要把PIX_FMT_***改了就可以了
2.在sws_getContext()中更改想要转换的格式:
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
也是把PIX_FMT_***改了就可以了
最后,如果想将转换后的原始数据存成文件,只需要将pFrameYUV的data指针指向的数据写入文件就可以了。
例如,保存YUV420P格式的数据,用以下代码:
- fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),1,output);
- fwrite(pFrameYUV->data[1],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);
- fwrite(pFrameYUV->data[2],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);
保存RGB24格式的数据,用以下代码:
- fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height)*3,1,output);
保存UYVY格式的数据,用以下代码:
- fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),2,output);
在这里又有一个问题,YUV420P格式需要写入data[0],data[1],data[2];而RGB24,UYVY格式却仅仅是写入data[0],他们的区别到底是什么呢?经过研究发现,在FFMPEG中,图像原始数据包括两种:planar和packed。planar就是将几个分量分开存,比如YUV420中,data[0]专门存Y,data[1]专门存U,data[2]专门存V。而packed则是打包存,所有数据都存在data[0]中。
具体哪个格式是planar,哪个格式是packed,可以查看pixfmt.h文件。注:有些格式名称后面是LE或BE,分别对应little-endian或big-endian。另外名字后面有P的是planar格式。
-
-
-
- #ifndef AVUTIL_PIXFMT_H
- #define AVUTIL_PIXFMT_H
-
-
- #include "libavutil/avconfig.h"
-
- enum PixelFormat {
- PIX_FMT_NONE= -1,
- PIX_FMT_YUV420P,
- PIX_FMT_YUYV422,
- PIX_FMT_RGB24,
- PIX_FMT_BGR24,
- PIX_FMT_YUV422P,
- PIX_FMT_YUV444P,
- PIX_FMT_YUV410P,
- PIX_FMT_YUV411P,
- PIX_FMT_GRAY8,
- PIX_FMT_MONOWHITE,
- PIX_FMT_MONOBLACK,
- PIX_FMT_PAL8,
- PIX_FMT_YUVJ420P,
- PIX_FMT_YUVJ422P,
- PIX_FMT_YUVJ444P,
- PIX_FMT_XVMC_MPEG2_MC,
- PIX_FMT_XVMC_MPEG2_IDCT,
- PIX_FMT_UYVY422,
- PIX_FMT_UYYVYY411,
- PIX_FMT_BGR8,
- PIX_FMT_BGR4,
- PIX_FMT_BGR4_BYTE,
- PIX_FMT_RGB8,
- PIX_FMT_RGB4,
- PIX_FMT_RGB4_BYTE,
- PIX_FMT_NV12,
- PIX_FMT_NV21,
-
- PIX_FMT_ARGB,
- PIX_FMT_RGBA,
- PIX_FMT_ABGR,
- PIX_FMT_BGRA,
-
- PIX_FMT_GRAY16BE,
- PIX_FMT_GRAY16LE,
- PIX_FMT_YUV440P,
- PIX_FMT_YUVJ440P,
- PIX_FMT_YUVA420P,
- PIX_FMT_VDPAU_H264,
- PIX_FMT_VDPAU_MPEG1,
- PIX_FMT_VDPAU_MPEG2,
- PIX_FMT_VDPAU_WMV3,
- PIX_FMT_VDPAU_VC1,
- PIX_FMT_RGB48BE,
- PIX_FMT_RGB48LE,
-
- PIX_FMT_RGB565BE,
- PIX_FMT_RGB565LE,
- PIX_FMT_RGB555BE,
- PIX_FMT_RGB555LE,
-
- PIX_FMT_BGR565BE,
- PIX_FMT_BGR565LE,
- PIX_FMT_BGR555BE,
- PIX_FMT_BGR555LE,
-
- PIX_FMT_VAAPI_MOCO,
- PIX_FMT_VAAPI_IDCT,
- PIX_FMT_VAAPI_VLD,
-
- PIX_FMT_YUV420P16LE,
- PIX_FMT_YUV420P16BE,
- PIX_FMT_YUV422P16LE,
- PIX_FMT_YUV422P16BE,
- PIX_FMT_YUV444P16LE,
- PIX_FMT_YUV444P16BE,
- PIX_FMT_VDPAU_MPEG4,
- PIX_FMT_DXVA2_VLD,
-
- PIX_FMT_RGB444LE,
- PIX_FMT_RGB444BE,
- PIX_FMT_BGR444LE,
- PIX_FMT_BGR444BE,
- PIX_FMT_GRAY8A,
- PIX_FMT_BGR48BE,
- PIX_FMT_BGR48LE,
-
-
-
-
- PIX_FMT_YUV420P9BE,
- PIX_FMT_YUV420P9LE,
- PIX_FMT_YUV420P10BE,
- PIX_FMT_YUV420P10LE,
- PIX_FMT_YUV422P10BE,
- PIX_FMT_YUV422P10LE,
- PIX_FMT_YUV444P9BE,
- PIX_FMT_YUV444P9LE,
- PIX_FMT_YUV444P10BE,
- PIX_FMT_YUV444P10LE,
- PIX_FMT_YUV422P9BE,
- PIX_FMT_YUV422P9LE,
- PIX_FMT_VDA_VLD,
-
- #ifdef AV_PIX_FMT_ABI_GIT_MASTER
- PIX_FMT_RGBA64BE,
- PIX_FMT_RGBA64LE,
- PIX_FMT_BGRA64BE,
- PIX_FMT_BGRA64LE,
- #endif
- PIX_FMT_GBRP,
- PIX_FMT_GBRP9BE,
- PIX_FMT_GBRP9LE,
- PIX_FMT_GBRP10BE,
- PIX_FMT_GBRP10LE,
- PIX_FMT_GBRP16BE,
- PIX_FMT_GBRP16LE,
-
- #ifndef AV_PIX_FMT_ABI_GIT_MASTER
- PIX_FMT_RGBA64BE=0x123,
- PIX_FMT_RGBA64LE,
- PIX_FMT_BGRA64BE,
- PIX_FMT_BGRA64LE,
- #endif
- PIX_FMT_0RGB=0x123+4,
- PIX_FMT_RGB0,
- PIX_FMT_0BGR,
- PIX_FMT_BGR0,
- PIX_FMT_YUVA444P,
-
- PIX_FMT_NB,
- };
-
- #define PIX_FMT_Y400A PIX_FMT_GRAY8A
- #define PIX_FMT_GBR24P PIX_FMT_GBRP
-
- #if AV_HAVE_BIGENDIAN
- # define PIX_FMT_NE(be, le) PIX_FMT_##be
- #else
- # define PIX_FMT_NE(be, le) PIX_FMT_##le
- #endif
-
- #define PIX_FMT_RGB32 PIX_FMT_NE(ARGB, BGRA)
- #define PIX_FMT_RGB32_1 PIX_FMT_NE(RGBA, ABGR)
- #define PIX_FMT_BGR32 PIX_FMT_NE(ABGR, RGBA)
- #define PIX_FMT_BGR32_1 PIX_FMT_NE(BGRA, ARGB)
- #define PIX_FMT_0RGB32 PIX_FMT_NE(0RGB, BGR0)
- #define PIX_FMT_0BGR32 PIX_FMT_NE(0BGR, RGB0)
-
- #define PIX_FMT_GRAY16 PIX_FMT_NE(GRAY16BE, GRAY16LE)
- #define PIX_FMT_RGB48 PIX_FMT_NE(RGB48BE, RGB48LE)
- #define PIX_FMT_RGB565 PIX_FMT_NE(RGB565BE, RGB565LE)
- #define PIX_FMT_RGB555 PIX_FMT_NE(RGB555BE, RGB555LE)
- #define PIX_FMT_RGB444 PIX_FMT_NE(RGB444BE, RGB444LE)
- #define PIX_FMT_BGR48 PIX_FMT_NE(BGR48BE, BGR48LE)
- #define PIX_FMT_BGR565 PIX_FMT_NE(BGR565BE, BGR565LE)
- #define PIX_FMT_BGR555 PIX_FMT_NE(BGR555BE, BGR555LE)
- #define PIX_FMT_BGR444 PIX_FMT_NE(BGR444BE, BGR444LE)
-
- #define PIX_FMT_YUV420P9 PIX_FMT_NE(YUV420P9BE , YUV420P9LE)
- #define PIX_FMT_YUV422P9 PIX_FMT_NE(YUV422P9BE , YUV422P9LE)
- #define PIX_FMT_YUV444P9 PIX_FMT_NE(YUV444P9BE , YUV444P9LE)
- #define PIX_FMT_YUV420P10 PIX_FMT_NE(YUV420P10BE, YUV420P10LE)
- #define PIX_FMT_YUV422P10 PIX_FMT_NE(YUV422P10BE, YUV422P10LE)
- #define PIX_FMT_YUV444P10 PIX_FMT_NE(YUV444P10BE, YUV444P10LE)
- #define PIX_FMT_YUV420P16 PIX_FMT_NE(YUV420P16BE, YUV420P16LE)
- #define PIX_FMT_YUV422P16 PIX_FMT_NE(YUV422P16BE, YUV422P16LE)
- #define PIX_FMT_YUV444P16 PIX_FMT_NE(YUV444P16BE, YUV444P16LE)
-
- #define PIX_FMT_RGBA64 PIX_FMT_NE(RGBA64BE, RGBA64LE)
- #define PIX_FMT_BGRA64 PIX_FMT_NE(BGRA64BE, BGRA64LE)
- #define PIX_FMT_GBRP9 PIX_FMT_NE(GBRP9BE , GBRP9LE)
- #define PIX_FMT_GBRP10 PIX_FMT_NE(GBRP10BE, GBRP10LE)
- #define PIX_FMT_GBRP16 PIX_FMT_NE(GBRP16BE, GBRP16LE)
-
- #endif /* AVUTIL_PIXFMT_H */
from:http://blog.csdn.net/leixiaohua1020/article/details/14215391