/* 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;
}

通过FFmpeg将多媒体文件解码后保存成Bmp图像(YUV420 RGB32)的更多相关文章

  1. C# 图片缩放,拖拽后保存成图片的功能

    窗体界面部分如下: 鼠标的缩放功能需要手动在 OpertaionImg.Designer.cs 文件里面添加一句代码,具体代码如下: //picturePhoto显示图片的控件 this.pictur ...

  2. 1.1.0-学习Opencv与MFC混合编程之---全屏截图,保存为BMP图像(并增加快捷键)

    源代码:http://download.csdn.net/detail/nuptboyzhb/3961677 Ø  添加全屏截图菜单项,菜单项的属性如下; Ø  为该菜单项建立类向导. 编辑消息处理函 ...

  3. [原]将BITMAPINFO保存成bmp文件,以及渲染到设备

    /* class Image { public: Image() = delete; Image(const uint32_t& _w, const uint32_t& _h) :w( ...

  4. linux之x86裁剪移植---ffmpeg的H264解码显示(420、422)

    在虚拟机上yuv420可以正常显示 ,而945(D525)模块上却无法显示 ,后来验证了directdraw的yuv420也无法显示 ,由此怀疑显卡不支持 ,后把420转换为422显示. 420显示如 ...

  5. 音视频入门-03-RGB转成BMP图片

    * 音视频入门文章目录 * BMP 文件格式解析 BMP 文件由文件头.位图信息头.颜色信息和图形数据四部分组成. 位图文件头(14个字节) 位图信息头(40个字节) 颜色信息 图形数据 文件头与信息 ...

  6. 在linux下实现用ffmpeg把YUV420帧保存成图片

    在网上搜了很久相关的问题,但是好像没有一个在linux下跑得比较完整的例子,不过经过自己一番搜索和总结,终于做出来了,哈哈,看下面的代码吧. 这个例子可以保存成bmp或者jpeg格式的图片. 下面的结 ...

  7. 使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码

    ffmpeg开源库,实现将bmp格式的图片编码成x264文件,并将编码好的H264文件解码保存为BMP文件. 实现将视频文件yuv格式保存的图片格式的測试,图像格式png,jpg, gif等等測试均O ...

  8. js中保存成图片并下载

    1.保存canvas中绘制的内容为图片 HTML代码: <canvas id="canvas" width="400" height="400& ...

  9. js将canvas保存成图片并下载

    <canvas id="canvas" width="400" height="400"></canvas> < ...

随机推荐

  1. 怎样看K线图(实图详解)

    K线图由开盘价.收盘价.最高价和最低价组成.       上面两种图叫作实体红K线和实体黑K线,实体红K线意味买力强劲,市场有强烈的做多欲望,此时可持股待涨.实体黑K线则代表市场完全进入恐惧状态,如果 ...

  2. 网易研发project师(移动端游戏)—暑期实习生电面题目 2014年5月14日

    2014年5月14日 暑期实习生电话面试: 首先自我介绍. 一.C++ 1.extern的使用方法 2.虚函数 3.强制转换 4.malloc和new的差别 二.计算机网络 1.TCP和UDP有什么差 ...

  3. 三角矩阵怎么用MathType输入

    虽然现在已经是暑假,但还是有很多学霸们在炎炎夏日中努力奋战,连暑假都不放过.也许正在实验室里面做得昏天暗地,也许是正在跟数据努力奋战,也许还在办公室里面一点一点地码着论文.码论文的时候,不时地要敲着复 ...

  4. java中的类、成员变量、方法的修饰符。

    http://blog.sina.com.cn/s/blog_7ffb8dd501011alw.html http://www.cnblogs.com/lixiaolun/p/4311727.html

  5. 下载VMware

    1.进入VMware官网:http://www.vmware.com/cn 2.找到下载,点击Workstation Pro,此时需要账号登录. 3.选择需要下载的版本.对应的操作系统,点击转至下载

  6. 如何使用C#操作WinAPI

    Windows API是对Windows操作系统的API函数,在C#中调用Windows API的实质是托管代码对非托管代码的调用. 主要使用的格式就是: using System.Runtime.I ...

  7. resin配置

    第一种方式:      在本机调试Resin服务,一般是在Eclipse IDE中进行,这样即可以快速的在开发环境中启动/终止Resin,又可以很方便的Debug程序.跟踪异常栈.    在任何版本的 ...

  8. 160727、自定义hibernate主键生成策略生成字符串+数字自增长

    需求:需要自增长注解如MyId0001.MyId0002.MyId0003 实现:实现这个接口org.hibernate.id.IdentifierGenerator 一.MyIdGenerator. ...

  9. 【JDF】学习和理解

    一.资源地址 官方GitBub地址: putaoshu/jdf: Jingdong front-end integrated solution https://github.com/putaoshu/ ...

  10. 云计算之路:2009年Xen一个补丁背后那不为人知的故事

    仔细阅读了http://www.cnblogs.com/cmt/p/3729386.html这篇关于xen的博文,这篇博文写的挺赞的,分析的也很细致,涉及到4年前的一个patch的故事.在讲这个故事之 ...