参考http://hi.baidu.com/mingxin505/item/52d6d1cda805d925a0b50a57,将其改为linux下可编译运行。可实现YUV420P与RGB32的互转。
/* g++ -o test test.cpp -lavformat -lavcodec -lavutil -lz -lm -lpthread -lswscale */ #include <string> #include <cassert> #include <iostream> #include <sstream> //#include <tchar.h> extern "C" { #ifndef INT64_C #define INT64_C(c) (c ## LL) #define UINT64_C(c) (c ## ULL) #endif #include <libavutil/avutil.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <libavcodec/avcodec.h> #include <stdlib.h> #include <unistd.h> }; //#pragma comment(lib, "avformat.lib") //#pragma comment(lib, "avutil.lib") //#pragma comment(lib, "avcodec.lib") //#pragma comment(lib, "swscale.lib") #pragma pack(1) #define BOOL int #define TRUE 1 #define FALSE 0 #define BI_RGB 0x0 char *itoa(int num,char *str,int radix) { /* 索引表 */ char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; unsigned unum; /* 中间变量 */ int i=0,j,k; /* 确定unum的值 */ if(radix==10&&num<0) /* 十进制负数 */ { unum=(unsigned)-num; str[i++]='-'; } else unum=(unsigned)num; /* 其他情况 */ /* 逆序 */ do { str[i++]=index[unum%(unsigned)radix]; unum/=radix; }while(unum); str[i]='\0'; /* 转换 */ if(str[0]=='-') k=1; /* 十进制负数 */ else k=0; char temp; for(j=k;j<=(i-k-1)/2;j++) { temp=str[j]; str[j]=str[i-j-1]; str[i-j-1]=temp; } return str; } static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height); BOOL CreateBmp(const char *filename, uint8_t *pRGBBuffer, int width, int height, int bpp) ; int main(int argc, char* argv[]) { int iResult = 0; //* 注册 av_register_all(); //* 文件名. //std::string strFile = "e:\\高码\\13587戈壁母亲片花__016.mpg"; const char *strFile = "input.MP4"; //* 打开文件 AVFormatContext* pavFmtCxt = NULL; //iResult = av_open_input_file(&pavFmtCxt, strFile.c_str(), NULL, 0, NULL); iResult = avformat_open_input(&pavFmtCxt, strFile, NULL, NULL); assert(iResult == 0); iResult = avformat_find_stream_info(pavFmtCxt, NULL); assert(iResult >= 0); int iVidStrmID = -1; for (int i = 0; i < pavFmtCxt->nb_streams; ++i) { if (AVMEDIA_TYPE_VIDEO == pavFmtCxt->streams[i]->codec->codec_type) { iVidStrmID = i; } } assert(iVidStrmID != -1); //* 查找,打开解码器. AVCodec* pDecodec = avcodec_find_decoder( pavFmtCxt->streams[iVidStrmID]->codec->codec_id); iResult = avcodec_open2(pavFmtCxt ->streams[iVidStrmID]->codec, pDecodec, NULL); assert(iResult >= 0); av_dump_format(pavFmtCxt, iVidStrmID, strFile, 0); //* 读取文件,解码. AVFrame* pFrame = avcodec_alloc_frame(); AVPacket pkt; av_init_packet(&pkt); //* Seek //av_seek_frame(pavFmtCxt, 0, 493, AVSEEK_FLAG_FRAME); while (av_read_frame(pavFmtCxt, &pkt)>= 0) { if (pkt.stream_index == iVidStrmID) { int iFinished = 0; AVCodecContext* pavCCxt = NULL; pavCCxt = pavFmtCxt->streams[iVidStrmID]->codec; int iDecoded = avcodec_decode_video2(pavCCxt, pFrame, &iFinished, &pkt); if (iDecoded > 0 && iFinished) { std::ostringstream ostrm; //* 解码成功.输出PTS, ostrm<<"pts_" <<pkt.pts//<<pavFmtCxt->streams[iVidStrmID]->pts_buffer[0] <<"\n"; //OutputDebugStringA(ostrm.str().c_str()); int width, height; width = pavFmtCxt->streams[iVidStrmID]->codec->width; height = pavFmtCxt->streams[iVidStrmID]->codec->height; //* 将YUV420P转换成RGB32. SwsContext* pSwsCxt = sws_getContext(width, height, PIX_FMT_YUV420P, width, height, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL); uint8_t *rgb_data = static_cast<uint8_t*>(av_malloc(width*height*4)); uint8_t *rgb_src[3]= {rgb_data, NULL, NULL}; int rgb_stride[3]={4*width, 0, 0}; assert(pSwsCxt); iResult = sws_scale(pSwsCxt, pFrame->data, pFrame->linesize, 0, height, rgb_src, rgb_stride); assert(iResult == height); /* {{ 测试代码,RGB32,YUV420之间的转换. //* 将RGB32转换为YUV420P AVFrame* pYUVFrm = alloc_picture(PIX_FMT_YUV420P, width, height); SwsContext* pSwsCxtYUV = sws_getContext(width, height, PIX_FMT_RGB32, width, height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//* 注意Flag的值. iResult = sws_scale(pSwsCxtYUV, rgb_src, rgb_stride, 0, height, pYUVFrm->data, pYUVFrm->linesize); assert(iResult == height); //* 再转换成RGB32 ::memset(rgb_data, 0, width*height*4); iResult = sws_scale(pSwsCxt, pYUVFrm->data, pYUVFrm->linesize, 0, height, rgb_src, rgb_stride); assert(iResult == height); //* }} */ char sz[100]; itoa(pkt.pts, sz, 10); CreateBmp(sz, rgb_data, width, height, 32); ::memset(rgb_data, 0, width*height*4); av_freep(&rgb_data); //* 注意SwsContext必须用这个函数释放. sws_freeContext(pSwsCxt); /* {{ 测试代码, 打开上面必须打开这里.否则会内存泄漏. sws_freeContext(pSwsCxtYUV); av_free(pYUVFrm->data[0]); av_free(pYUVFrm); pYUVFrm = NULL; //* }} */ } else { //::OutputDebugStringA("解码失败"); printf("解码失败"); } } } return 0; } typedef struct tagBITMAPFILEHEADER { unsigned short bfType; //2 位图文件的类型,必须为“BM” unsigned long bfSize; //4 位图文件的大小,以字节为单位 unsigned short bfReserved1; //2 位图文件保留字,必须为0 unsigned short bfReserved2; //2 位图文件保留字,必须为0 unsigned long bfOffBits; //4 位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位 } BITMAPFILEHEADER;//该结构占据14个字节。 // printf("%d\n",sizeof(BITMAPFILEHEADER)); typedef struct tagBITMAPINFOHEADER{ unsigned long biSize; //4 本结构所占用字节数 long biWidth; //4 位图的宽度,以像素为单位 long biHeight; //4 位图的高度,以像素为单位 unsigned short biPlanes; //2 目标设备的平面数不清,必须为1 unsigned short biBitCount;//2 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一 unsigned long biCompression; //4 位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 unsigned long biSizeImage; //4 位图的大小,以字节为单位 long biXPelsPerMeter; //4 位图水平分辨率,每米像素数 long biYPelsPerMeter; //4 位图垂直分辨率,每米像素数 unsigned long biClrUsed;//4 位图实际使用的颜色表中的颜色数 unsigned long biClrImportant;//4 位图显示过程中重要的颜色数 } BITMAPINFOHEADER;//该结构占据40个字节。 BOOL CreateBmp(const char *filename, uint8_t *pRGBBuffer, int width, int height, int bpp) { BITMAPFILEHEADER bmpheader; BITMAPINFOHEADER bmpinfo; FILE *fp = NULL; fp = fopen(filename,"wb"); if( fp == NULL ) { return FALSE; } bmpheader.bfType = ('M' <<8)|'B'; bmpheader.bfReserved1 = 0; bmpheader.bfReserved2 = 0; bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8; bmpinfo.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.biWidth = width; bmpinfo.biHeight = 0 - height; bmpinfo.biPlanes = 1; bmpinfo.biBitCount = bpp; bmpinfo.biCompression = BI_RGB; bmpinfo.biSizeImage = 0; bmpinfo.biXPelsPerMeter = 100; bmpinfo.biYPelsPerMeter = 100; bmpinfo.biClrUsed = 0; bmpinfo.biClrImportant = 0; fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp); fwrite(&bmpinfo,sizeof(BITMAPINFOHEADER),1,fp); fwrite(pRGBBuffer,width*height*bpp/8,1,fp); fclose(fp); fp = NULL; return TRUE; } static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height) { AVFrame *picture; uint8_t *picture_buf; int size; picture = avcodec_alloc_frame(); if (!picture) return NULL; size = avpicture_get_size(pix_fmt, width, height); picture_buf = (uint8_t*)av_malloc(size); if (!picture_buf) { av_free(picture); return NULL; } avpicture_fill((AVPicture *)picture, picture_buf, pix_fmt, width, height); return picture; }