FFMPEG教程1_解码后保存图片(使用2014年新SDK重新整理编译通过)

来源:互联网 发布:python编程培训 编辑:程序博客网 时间:2024/04/30 19:11

    这篇文字仍然是学习FFMPEG最好的入门教程,但是确实太老了,新的FFMpeg下不能编译运行,为此,我专门重新修改了一下。

    http://dranger.com/ffmpeg/tutorial01.html

(VC2012,静态编译,生成一个单exe文件,看起来清爽多了)


#include "stdafx.h"#include <Windows.h>
#pragma warning( disable : 4312 ) #pragma warning( disable : 4244 ) #pragma warning( disable : 4311 ) 
#ifdef  __cplusplus  extern "C" {  #endif  #include <libavcodec/avcodec.h>  #include <libavformat/avformat.h>  #include <libavutil/avutil.h>  #include <libswscale/swscale.h>  #include <SDL/SDL.h>  #include <SDL/SDL_video.h>      // SDL#include <SDL/SDL_thread.h>      // SDL
#ifdef __cplusplus  }  #endif  
#pragma comment( lib, "libgcc.a")  #pragma comment( lib, "libmingwex.a")  #pragma comment( lib, "libcoldname.a")  #pragma comment( lib, "libavcodec.a")  #pragma comment( lib, "libavformat.a")  #pragma comment( lib, "libavutil.a")  #pragma comment( lib, "libswscale.a")  #pragma comment( lib, "libz.a")  #pragma comment( lib, "libfaac.a")  #pragma comment( lib, "libgsm.a")  #pragma comment( lib, "libmp3lame.a")  #pragma comment( lib, "libogg.a")  #pragma comment( lib, "libspeex.a")  #pragma comment( lib, "libtheora.a")  #pragma comment( lib, "libvorbis.a")  #pragma comment( lib, "libvorbisenc.a")  #pragma comment( lib, "libx264.a")  #pragma comment( lib, "xvidcore.a") #pragma comment( lib, "wsock32.lib")  #pragma comment( lib, "vfw32.lib")   
#pragma comment( lib, "sdl2main.lib")  #pragma comment( lib, "sdl2.lib")   #pragma   comment(lib, "winmm.lib ")#pragma   comment(lib,"Version.lib") #pragma   comment(lib,"imm32.lib") 
</pre><pre class="cpp" name="code">
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {  FILE *pFile;  char szFilename[32];  int  y;    // Open file  sprintf(szFilename, "frame%d.ppm", iFrame);  pFile=fopen(szFilename, "wb");  if(pFile==NULL)    return;    // Write header  fprintf(pFile, "P6\n%d %d\n255\n", width, height);    // Write pixel data  for(y=0; y<height; y++)    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);    // Close file  fclose(pFile);}int _tmain(int argc, char *argv[]){//下面这个千万要注意,原来老代码不需要=NULL,//但是新SDK如果不初始化会在avformat_open_input非法退出//因此,将指针初始化为NULL是个好习惯!AVFormatContext *pFormatCtx = NULL;int             i, videoStream;AVCodecContext  *pCodecCtx = NULL;AVCodec         *pCodec = NULL;AVFrame         *pFrame = NULL; AVFrame         *pFrameRGB = NULL;AVPacket        packet;int             frameFinished;int             numBytes;uint8_t         *buffer;struct SwsContext *sws_ctx = NULL;if(argc < 2) {printf("带参数执行,后面跟视频文件\n");return -1;}// 注册所有的解码格式av_register_all();//打开视频printf_s("打开视频文件:%s成功\n",argv[1]);    if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)        return -1; // 打开视频文件失败    printf_s("打开视频文件:%s成功\n",argv[1]);// 检索流信息if(av_find_stream_info(pFormatCtx)<0)return -1; // 不能发现流信息资料//打印标准的转储信息 av_dump_format(pFormatCtx, 0, argv[1], 0);// 找到第一个视频videoStream=-1;for(i=0; i<(int)pFormatCtx->nb_streams; i++)if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {videoStream=i;break;}if(videoStream==-1)return -1; // 没有发现视频流//获得视频编解码器的上下文指针pCodecCtx=pFormatCtx->streams[videoStream]->codec;// 找到视频解码器pCodec=avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec==NULL) {fprintf(stderr, "Unsupported codec!\n");return -1; //视频解码未发现}// 开放的编解码器if(avcodec_open(pCodecCtx, pCodec)<0)return -1; // 视频解码未发现//分配视频帧pFrame=avcodec_alloc_frame();// 分配一个AVFrame结构pFrameRGB=avcodec_alloc_frame();if(pFrameRGB==NULL)return -1;sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);//确定所需的缓冲区大小和分配缓冲区numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));// Assign appropriate parts of buffer to image planes in pFrameRGB // Note that pFrameRGB is an AVFrame, but AVFrame is a superset of AVPicture//分配适当的部分缓冲给在pFrameRGB中的图像平面,请注意,pFrameRGB 是一个AVFrame,但AVFrame却是AVPicture的超集avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);printf_s("打开视频文件:%s成功\n",argv[1]);// 逐帧读取并且将前五帧保存到磁盘i=0;while(av_read_frame(pFormatCtx, &packet)>=0) {// 这是一个视频的包吗?if(packet.stream_index==videoStream) {// 解码视频帧avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet);// 成功获得了视频帧?if(frameFinished) {printf_s("avcodec_decode_video2 success\n");// 将图像从原生格式转换成为RGB格式//Convert the image from its native format to RGB sws_scale(sws_ctx,(uint8_t const * const *)pFrame->data,pFrame->linesize, 0,pCodecCtx->height, pFrameRGB->data,pFrameRGB->linesize);//img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);// 帧保存到磁盘if(++i<=5)SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);}}// 释放av_read_frame分配的包av_free_packet(&packet);}// 释放RGB图像av_free(buffer);av_free(pFrameRGB);// 释放YUV帧av_free(pFrame);// 关闭解码器avcodec_close(pCodecCtx);// 关闭视频文件av_close_input_file(pFormatCtx);return 0;}



0 0