第一次接觸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;
- }