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

FFMPEG中的swscale提供了视频原始数据(YUV420,YUV422,YUV444,RGB24…)之间的转换,分辨率变换等操作,使用起来十分方便,在这里记录一下它的用法。

swscale主要用于在2个AVFrame之间进行转换。

下面来看一个视频解码的简单例子,这个程序完成了对"北京移动开发者大会茶歇视频2.flv"(其实就是优酷上的一个普通视频)的解码工作,并将解码后的数据保存为原始数据文件(例如YUV420,YUV422,RGB24等等)。其中略去了很多的代码。

注:完整代码在文章:100行代码实现最简单的基于FFMPEG+SDL的视频播放器

//ffmpeg simple player////媒资检索系统子系统////2013 雷霄骅 leixiaohua1020@126.com//中国传媒大学/数字电视技术//#include "stdafx.h"int _tmain(int argc, _TCHAR* argv[]){AVFormatContext*pFormatCtx;inti, 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);/*out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);*//*out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_UYVY422, pCodecCtx->width, pCodecCtx->height)];avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_UYVY422, pCodecCtx->width, pCodecCtx->height);out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV422P, pCodecCtx->width, pCodecCtx->height)];avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV422P, 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_UYVY422, 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);img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV422P, 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);*///转换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);//RGBfwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height)*3,1,output);/*//UYVYfwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),2,output);//YUV420Pfwrite(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);*/……}}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指针指向的数据写入文件就可以了。

与其临渊羡鱼,不如退而结网。

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

相关文章:

你感兴趣的文章:

标签云: