http://www.tuicool.com/articles/jiUzua
http://blog.csdn.net/code_future/article/details/8646717
主题 FFmpeg
任务:需要把一个视频文件的每一帧提取出来,每帧存储成单独的文件。
以前用Matlab处理过这个问题,可是感觉比较慢,而且最近正在逐步转向使用开源的东西。因此搜到ffmpeg这个好东西。
ffmpeg可用来处理视频文件的提取和各种转换,跨平台,官网上有Linux,WINDOWS和MAC版本。
以下是windows 命令行下使用ffmpeg提取视频帧的方法:
SET PATH=%PATH%;[path_to_ffmpeg]
SET VIDEOFILE=demo.mp4
SET DESTDIR=video_frameffmpeg -i %VIDEOFILE% -q:v 2 -f image2 %DESTDIR%%07d.jpeg
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
其中-i 后面是输入文件,-q:v 2 q代表质量quality, v代表视频流,2是控制质量的参数。-f指定输出的格式是image2. %07d是图片命名的pattern
//--------------------------------------------------------------------------------------------
第一次接触ffmpeg,可以算是hello world程序。
下面的代码全部都是直接可以使用的,借鉴了官方学习样例,也算是翻译吧。
但是解决了,保存bmp图像时,图像颠倒和色彩异常问题。
// x_ffmpeg.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <iostream> #include <iosfwd> #include <fstream> using namespace std; #define FILE_OUT #ifdef FILE_OUT std::ofstream file_debugout("frameandpacketinfo.txt"); #endif static int av_create_bmp(char* filename,uint8_t *pRGBBuffer,int width,int height,int bpp) { BITMAPFILEHEADER bmpheader; BITMAPINFO bmpinfo; FILE *fp; fp = fopen(filename,"wb"); if(!fp)return -1; 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.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.bmiHeader.biWidth = width; /*----注意,这里的bmpinfo.bmiHeader.biHeight变量的正负决定bmp文件的存储方式,如果 为负值,表示像素是倒过来的*/ bmpinfo.bmiHeader.biHeight = -height; bmpinfo.bmiHeader.biPlanes = 1; bmpinfo.bmiHeader.biBitCount = bpp; bmpinfo.bmiHeader.biCompression = BI_RGB; bmpinfo.bmiHeader.biSizeImage = 0; bmpinfo.bmiHeader.biXPelsPerMeter = 100; bmpinfo.bmiHeader.biYPelsPerMeter = 100; bmpinfo.bmiHeader.biClrUsed = 0; bmpinfo.bmiHeader.biClrImportant = 0; fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp); fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); fwrite(pRGBBuffer,width*height*bpp/8,1,fp); fclose(fp); return 0; } static int av_create_bmp(char* filename, AVFrame *pRGBBuffer,int width,int height,int bpp) { BITMAPFILEHEADER bmpheader; BITMAPINFO bmpinfo; FILE *fp; fp = fopen(filename, "wb"); if(!fp)return -1; 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.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.bmiHeader.biWidth = width; bmpinfo.bmiHeader.biHeight = -height; bmpinfo.bmiHeader.biPlanes = 1; bmpinfo.bmiHeader.biBitCount = 24; bmpinfo.bmiHeader.biCompression = BI_RGB; bmpinfo.bmiHeader.biSizeImage = 0; bmpinfo.bmiHeader.biXPelsPerMeter = 100; bmpinfo.bmiHeader.biYPelsPerMeter = 100; bmpinfo.bmiHeader.biClrUsed = 0; bmpinfo.bmiHeader.biClrImportant = 0; fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp); fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); //fwrite(pRGBBuffer,width*height*bpp/8,1,fp); for(int y=0; y<height; y++) fwrite(pRGBBuffer->data[0] + y*pRGBBuffer->linesize[0], 1, width*3, fp); fclose(fp); return 0; } static void print_packet_info(AVPacket info) { #ifdef FILE_OUT file_debugout << "print_packet_info" << " convergence_duration:" << info.convergence_duration << " dts:" << info.dts << " duration:" << info.duration << " flags:" << info.flags << " pos:" << info.pos << " pts:" << info.pts << " size:" << info.size << " stream_index:" << info.stream_index << endl; #else cout << "print_packet_info" << " convergence_duration:" << info.convergence_duration << " dts:" << info.dts << " duration:" << info.duration << " flags:" << info.flags << " pos:" << info.pos << " pts:" << info.pts << " size:" << info.size << " stream_index:" << info.stream_index << endl; #endif } static void print_frame_info(AVFrame* pinfo) { #ifdef FILE_OUT file_debugout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number << " display_picture_number:" << pinfo->display_picture_number << " type:" << pinfo->type << endl; #else cout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number << " display_picture_number:" << pinfo->display_picture_number << " type:" << pinfo->type << endl; #endif } int decode_video_packet(AVFormatContext * fmt_ctx_for_decode, AVCodecContext* dec_ctx, int video_stream_index) { int ret = 0; AVFrame* pFrame=avcodec_alloc_frame(); AVFrame* pFrameRGB = avcodec_alloc_frame(); int numBytes=avpicture_get_size(PIX_FMT_BGR24, dec_ctx->width,dec_ctx->height); uint8_t* buffer = new(std::nothrow) uint8_t[numBytes]; avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24, dec_ctx->width, dec_ctx->height); SwsContext *pSWSCtx = sws_getContext(dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, dec_ctx->width, dec_ctx->height, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); if (NULL == pFrame || NULL == pFrameRGB || NULL == buffer || NULL == pSWSCtx) { ret = -1; goto exit; } AVPacket packet; int key_frame_picture_count = 0; while (av_read_frame(fmt_ctx_for_decode, &packet) >= 0) { if (packet.stream_index == video_stream_index) { int got_frame = 0; avcodec_decode_video2(dec_ctx, pFrame,&got_frame, &packet); if (got_frame) //一个完整的帧 { if (pFrame->key_frame) { sws_scale(pSWSCtx, pFrame->data, pFrame->linesize,0, dec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); // 保存到磁盘 char pic[200]; sprintf(pic,"keyframe%d.bmp", ++key_frame_picture_count); av_create_bmp(pic,pFrameRGB->data[0],dec_ctx->width,dec_ctx->height,24); //av_create_bmp(pic, pFrameRGB, dec_ctx->width,dec_ctx->height,24); } print_frame_info(pFrame); } print_packet_info(packet); } } exit: avcodec_free_frame(&pFrame); avcodec_free_frame(&pFrameRGB); delete [] buffer; sws_freeContext(pSWSCtx); return ret; } static int open_input_file(const char *filename) { int ret; bool video_codec_init = false; int video_stream_index = -1; AVCodecContext* suitable_dec_ctx = NULL; AVFormatContext *video_fmt_ctx = NULL; if ((ret = avformat_open_input(&video_fmt_ctx, filename, NULL, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n"); return ret; } if ((ret = avformat_find_stream_info(video_fmt_ctx, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); avformat_close_input(&video_fmt_ctx); return ret; } for (int i = 0; i < video_fmt_ctx->nb_streams; i++) { // 找到视频码流 if (video_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; // 初始化解码器信息 if (!video_codec_init) { suitable_dec_ctx = video_fmt_ctx->streams[i]->codec; AVCodec* pcodec = avcodec_find_decoder(suitable_dec_ctx->codec_id); if (NULL == pcodec) { printf("cannot find decoder"); avformat_close_input(&video_fmt_ctx); return 1; } if(0 != avcodec_open2(suitable_dec_ctx, pcodec, NULL)) { printf("open codecer failed"); avformat_close_input(&video_fmt_ctx); return 1; } video_codec_init = true; } } } // 解码视频 if (video_codec_init && suitable_dec_ctx) { decode_video_packet(video_fmt_ctx, suitable_dec_ctx, video_stream_index); } // 关闭文件 avformat_close_input(&video_fmt_ctx); return 0; } int _tmain(int argc, _TCHAR* argv[]) { // 注册库中所有可能有用的文件格式和编码器 av_register_all(); open_input_file("C:\\Users\\xukaijun.HIK\\Desktop\\hikvison.mp4"); #ifdef FILE_OUT file_debugout.close(); #endif return 0; }
时间: 2024-10-13 20:44:00