您的位置:首页 > 其它

在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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: