在window下使用ffmpeg进行解码
2011-09-11 00:09
633 查看
在window下使用ffmpeg进行解码
分类: ffmpeg2011-07-28 12:02 18人阅读 评论(0) 收藏 举报ffmpeg的库可下载:搜索ffmpeg sdk 3.2即可得到。
一、解码显示过程
我使用的环境是vs2008
头文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif
1、注册所用编码器或者解码器
av_register_all();
2、打开视频文件
AVFormatContext *pFormatCtx;//AVFormatContext 即format I/O context,比较重要,里面记录了流文件相关信息,基本贯穿整个处理流程
// Open video file
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
return -1; // Couldn't open file
dump_format(pFormatCtx, 0,argv[1], 0);//用于调试,可以输出一些相关信息的
3、获取流的一些信息,比如说解码时需要的height及width
if(av_find_stream_info(pFormatCtx)<0)
return -1; // Couldn't find stream information
4、找到视频流
AVCodecContext *pCodecCtx;//AVCodecContext即Codec的相关信息
// Find the first video stream
int videoStream=-1;
for(int i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
videoStream=i;
break;
}
}
if(videoStream==-1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
5、为对应的视频流找到编解码器
// Find the decoder for the video stream
AVCodec *pCodec;//编解码器信息
pCodec = NULL;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
6、为对应的流打开所需要的编码器
// Open codec
if(avcodec_open(pCodecCtx, pCodec)<0)
return -1; // Could not open code
7、解码
-----分配一个AVFrame的结构,用于记录原始图像信息
AVFrame *pFrame;
pFrame = NULL;
pFrame = avcodec_alloc_frame();
if(pFrame==NULL)
return -1;
-----根据图像大小创建一个缓冲区
uint8_t *buffer;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width,
pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrame, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);//填充AVPicture对应域
-------解码
int frameFinished;
AVPacket packet;
i=0;
while(av_read_frame(pFormatCtx, &packet)>=0) {
// Is this a packet from the video stream?
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
packet.data, packet.size);
// Did we get a video frame?
if(frameFinished) {
显示视频。。。。。。
}
}
// Free the packet that was allocated by av_read_frame
}
-------释放资源
av_free_packet(&packet);
av_free(buffer);
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
av_close_input_file(pFormatCtx);
-------显示视频
1)加入SDL动态库
1)下载SDL开发包SDL-devel-1.2.14-VC6.zip,并解压主要生成include、lib文件,下载地址:http://www.libsdl.org/download-1.2.php;
2)在vc的安装目录Microsoft Visual Studio\VC98\Include下创建一个新文件夹SDL,将1)中解压后的include文件夹中所有文件拷贝到所创建SDL文件夹中
3)将1)中解压后的lib文件夹中.lib文件以及.dll文件拷贝到所创建的工程目录下
4)在工程的选项配置为多线程已解决库冲突问题
5)编译后会发现数据定义有冲突,我解决的办法是把SDL中对应的项注释掉
2)初始化SDL库
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
{//SDL init
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
3)设置视频模式
SDL_Surface *screen;
screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
if(!screen) //create a screen
{
fprintf(stderr, "SDL: could not set video mode - exiting\n");
return -2;
}
4)创建贴图
SDL_Overlay *bmp;
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
SDL_YV12_OVERLAY, screen);
SDL_LockYUVOverlay(bmp);
AVPicture pict;
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
SwsContext *ctx;
ctx = sws_getContext(
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
PIX_FMT_YUV420P,
SWS_BICUBIC, NULL, NULL, NULL);
if(ctx == NULL)
{
fprintf(stderr, "Cannot get resampling context\n");
return -3;
}
//sws_scale( ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrame->data,pFrame->linesize);//原文中这句话没有注释,我在测试时发现需要注释掉才能成功
sws_scale( ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pict.data,pict.linesize);
SDL_UnlockYUVOverlay(bmp);
//draw
5)显示图像
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
SDL_DisplayYUVOverlay(bmp, &rect);
二、注意
1、此实例只解码视频
2、显示图像的时候没有帧率方面的处理,所以播放速度过快,cpu占用率过高,有待完善
原文地址:http://tianyou8.blog.hexun.com/46861549_d.html
分享到:
ffmpeg解码视频存为BMP文件
分类: ffmpeg2011-07-28 12:13 5人阅读 评论(0) 收藏 举报view plain
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif
//定义BMP文件头
#ifndef _WINGDI_
#define _WINGDI_
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
#endif
//保存BMP文件的函数
void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int bpp)
{
char buf[5] = {0};
BITMAPFILEHEADER bmpheader;
BITMAPINFOHEADER bmpinfo;
FILE *fp;
char *filename = new char[255];
//文件存放路径,根据自己的修改
sprintf_s(filename,255,"%s%d.bmp","D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/test",index);
if ( (fp=fopen(filename,"wb+")) == NULL )
{
printf ("open file failed!\n");
return;
}
bmpheader.bfType = 0x4d42;
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 = height;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = bpp;
bmpinfo.biCompression = BI_RGB;
bmpinfo.biSizeImage = (width*bpp+31)/32*4*height;
bmpinfo.biXPelsPerMeter = 100;
bmpinfo.biYPelsPerMeter = 100;
bmpinfo.biClrUsed = 0;
bmpinfo.biClrImportant = 0;
fwrite (&bmpheader, sizeof(bmpheader), 1, fp);
fwrite (&bmpinfo, sizeof(bmpinfo), 1, fp);
fwrite (pFrameRGB->data[0], width*height*bpp/8, 1, fp);
fclose(fp);
}
//主函数
int main (void)
{
unsigned int i = 0, videoStream = -1;
AVCodecContext *pCodecCtx;
AVFormatContext *pFormatCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameRGB;
struct SwsContext *pSwsCtx;
const char *filename = "D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/DELTA.MPG";
AVPacket packet;
int frameFinished;
int PictureSize;
uint8_t *buf;
//注册编解码器
av_register_all();
//打开视频文件
if ( av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL) != 0 )
{
printf ("av open input file failed!\n");
exit (1);
}
//获取流信息
if ( av_find_stream_info(pFormatCtx) < 0 )
{
printf ("av find stream info failed!\n");
exit (1);
}
//获取视频流
for ( i=0; i<pFormatCtx->nb_streams; i++ )
if ( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
{
videoStream = i;
break;
}
if (videoStream == -1)
{
printf ("find video stream failed!\n");
exit (1);
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder (pCodecCtx->codec_id);
if (pCodec == NULL)
{
printf ("avcode find decoder failed!\n");
exit (1);
}
//打开解码器
if ( avcodec_open(pCodecCtx, pCodec)<0 )
{
printf ("avcode open failed!\n");
exit (1);
}
//为每帧图像分配内存
pFrame = avcodec_alloc_frame();
pFrameRGB = avcodec_alloc_frame();
if ( (pFrame==NULL)||(pFrameRGB==NULL) )
{
printf("avcodec alloc frame failed!\n");
exit (1);
}
PictureSize = avpicture_get_size (PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
buf = (uint8_t*)av_malloc(PictureSize);
if ( buf == NULL )
{
printf( "av malloc failed!\n");
exit(1);
}
avpicture_fill ( (AVPicture *)pFrameRGB, buf, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
//设置图像转换上下文
pSwsCtx = sws_getContext (pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
PIX_FMT_BGR24,
SWS_BICUBIC,
NULL, NULL, NULL);
i = 0;
while(av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
packet.data, packet.size);
if(frameFinished)
{
//反转图像 ,否则生成的图像是上下调到的
pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1);
pFrame->linesize[0] *= -1;
pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1);
pFrame->linesize[1] *= -1;
pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1);
pFrame->linesize[2] *= -1;
//转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像
sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);
}
}
av_free_packet(&packet);
}
sws_freeContext (pSwsCtx);
av_free (pFrame);
av_free (pFrameRGB);
avcodec_close (pCodecCtx);
av_close_input_file (pFormatCtx);
return 0;
}
@import url(http://www.cnblogs.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
相关文章推荐
- 在window下使用ffmpeg进行解码
- 使用ffmpeg进行视频解码以及图像转换
- 使用ffmpeg进行视频解码以及图像转换
- android jni中将大数据回调到java层的时候用法,比如视频流,音频流等,图片流等 比如我用ffmpeg解码好视频流,想送到java层使用opengGL进行显示,opencv进行人脸识别等等
- 使用 ffmpeg 进行网络推流:拉流->解封装->解码->处理原始数据(音频、视频)->编码->编码->推流
- 使用ffmpeg进行视频解码以及图像转换
- 使用ffmpeg进行视频解码以及图像转换
- Android音视频学习第1章:使用ffmpeg进行视频解码
- 使用FFMPEG对流数据进行解码
- 使用FFMPEG3.4.2版本进行视频的解码为YUV格式
- 再谈使用ffmpeg进行单纯音频编解码
- 通过C++/CLI使用FFMPEG库进行视频解码[初步]
- 使用FFmpeg对视频进行编解码的一般流程
- 使用ffmpeg进行音视频编解码时用到的函数介绍
- 通过C++/CLI使用FFMPEG库进行视频解码[初步]
- 使用window.btoa和window.atob来进行Base64编码和解码
- 使用ffmpeg进行解码的基本流程 和几个重要函数
- Android音视频学习第2章:使用ffmpeg进行音频解码
- 使用FastJson进行JSON编解码
- 在iOS平台使用ffmpeg解码h264视频流