打開視頻文件,幀分析,並bmp保存關鍵幀

第一次接觸ffmpeg,可以算是hello world程序。

下面的代碼全部都是直接可以使用的,借鑑了官方學習樣例,也算是翻譯吧。

但是解決了,保存bmp圖像時,圖像顛倒和色彩異常問題。

 

  1. // x_ffmpeg.cpp : Defines the entry point for the console application.   
  2. //   
  3.   
  4. #include "stdafx.h"   
  5. #include <windows.h>   
  6. #include <iostream>   
  7. #include <iosfwd>   
  8. #include <fstream>   
  9. using namespace std;  
  10.   
  11. #define FILE_OUT   
  12. #ifdef FILE_OUT   
  13. std::ofstream file_debugout("frameandpacketinfo.txt");  
  14. #endif   
  15.   
  16. static int av_create_bmp(char* filename,uint8_t *pRGBBuffer,int width,int height,int bpp)  
  17. {  
  18.     BITMAPFILEHEADER bmpheader;  
  19.     BITMAPINFO bmpinfo;  
  20.     FILE *fp;  
  21.   
  22.     fp = fopen(filename,"wb");  
  23.     if(!fp)return -1;  
  24.   
  25.     bmpheader.bfType = ('M'<<8)|'B';  
  26.     bmpheader.bfReserved1 = 0;  
  27.     bmpheader.bfReserved2 = 0;  
  28.     bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
  29.     bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;  
  30.     bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  31.     bmpinfo.bmiHeader.biWidth = width;  
  32.     /*----注意,這裏的bmpinfo.bmiHeader.biHeight變量的正負決定bmp文件的存儲方式,如果 
  33.     爲負值,表示像素是倒過來的*/  
  34.     bmpinfo.bmiHeader.biHeight = -height;  
  35.     bmpinfo.bmiHeader.biPlanes = 1;  
  36.     bmpinfo.bmiHeader.biBitCount = bpp;  
  37.     bmpinfo.bmiHeader.biCompression = BI_RGB;  
  38.     bmpinfo.bmiHeader.biSizeImage = 0;  
  39.     bmpinfo.bmiHeader.biXPelsPerMeter = 100;  
  40.     bmpinfo.bmiHeader.biYPelsPerMeter = 100;  
  41.     bmpinfo.bmiHeader.biClrUsed = 0;  
  42.     bmpinfo.bmiHeader.biClrImportant = 0;  
  43.   
  44.     fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);  
  45.     fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);  
  46.     fwrite(pRGBBuffer,width*height*bpp/8,1,fp);  
  47.     fclose(fp);  
  48.   
  49.     return 0;  
  50. }  
  51.   
  52. static int av_create_bmp(char* filename, AVFrame *pRGBBuffer,int width,int height,int bpp)  
  53. {  
  54.     BITMAPFILEHEADER bmpheader;  
  55.     BITMAPINFO bmpinfo;  
  56.     FILE *fp;  
  57.   
  58.     fp = fopen(filename, "wb");  
  59.     if(!fp)return -1;  
  60.   
  61.     bmpheader.bfType = ('M'<<8)|'B';  
  62.     bmpheader.bfReserved1 = 0;  
  63.     bmpheader.bfReserved2 = 0;  
  64.     bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
  65.     bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;  
  66.     bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  67.     bmpinfo.bmiHeader.biWidth = width;  
  68.     bmpinfo.bmiHeader.biHeight = -height;  
  69.     bmpinfo.bmiHeader.biPlanes = 1;  
  70.     bmpinfo.bmiHeader.biBitCount = 24;  
  71.     bmpinfo.bmiHeader.biCompression = BI_RGB;  
  72.     bmpinfo.bmiHeader.biSizeImage = 0;  
  73.     bmpinfo.bmiHeader.biXPelsPerMeter = 100;  
  74.     bmpinfo.bmiHeader.biYPelsPerMeter = 100;  
  75.     bmpinfo.bmiHeader.biClrUsed = 0;  
  76.     bmpinfo.bmiHeader.biClrImportant = 0;  
  77.     fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);  
  78.     fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);  
  79.     //fwrite(pRGBBuffer,width*height*bpp/8,1,fp);   
  80.     for(int y=0; y<height; y++)  
  81.         fwrite(pRGBBuffer->data[0] + y*pRGBBuffer->linesize[0], 1, width*3, fp);  
  82.     fclose(fp);  
  83.     return 0;  
  84. }  
  85.   
  86. static void print_packet_info(AVPacket info)  
  87. {  
  88. #ifdef FILE_OUT   
  89.     file_debugout << "print_packet_info" << " convergence_duration:" << info.convergence_duration  
  90.         << " dts:" << info.dts   
  91.         << " duration:" << info.duration  
  92.         << " flags:" << info.flags   
  93.         << " pos:" << info.pos  
  94.         << " pts:" << info.pts  
  95.         << " size:" << info.size  
  96.         << " stream_index:" << info.stream_index << endl;  
  97. #else   
  98.     cout << "print_packet_info" << " convergence_duration:" << info.convergence_duration  
  99.         << " dts:" << info.dts   
  100.         << " duration:" << info.duration  
  101.         << " flags:" << info.flags   
  102.         << " pos:" << info.pos  
  103.         << " pts:" << info.pts  
  104.         << " size:" << info.size  
  105.         << " stream_index:" << info.stream_index << endl;  
  106. #endif   
  107. }  
  108.   
  109. static void print_frame_info(AVFrame* pinfo)  
  110. {  
  111. #ifdef FILE_OUT   
  112.     file_debugout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number  
  113.         << " display_picture_number:" << pinfo->display_picture_number   
  114.         << " type:" << pinfo->type << endl;  
  115. #else   
  116.     cout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number  
  117.         << " display_picture_number:" << pinfo->display_picture_number   
  118.         << " type:" << pinfo->type << endl;  
  119. #endif   
  120.   
  121. }  
  122.   
  123. int decode_video_packet(AVFormatContext * fmt_ctx_for_decode, \  
  124.                          AVCodecContext* dec_ctx, int video_stream_index)  
  125. {  
  126.     int ret = 0;  
  127.   
  128.     AVFrame* pFrame=avcodec_alloc_frame();  
  129.     AVFrame* pFrameRGB = avcodec_alloc_frame();  
  130.   
  131.     int numBytes=avpicture_get_size(PIX_FMT_BGR24, dec_ctx->width,dec_ctx->height);   
  132.     uint8_t* buffer = new(std::nothrow) uint8_t[numBytes];  
  133.   
  134.     avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,\  
  135.         dec_ctx->width, dec_ctx->height);  
  136.   
  137.     SwsContext *pSWSCtx = sws_getContext(dec_ctx->width, dec_ctx->height, \  
  138.         dec_ctx->pix_fmt, dec_ctx->width, dec_ctx->height, PIX_FMT_BGR24,\  
  139.         SWS_BICUBIC, NULL, NULL, NULL);  
  140.   
  141.     if (NULL == pFrame || NULL == pFrameRGB || NULL == buffer || NULL == pSWSCtx)  
  142.     {  
  143.         ret = -1;  
  144.         goto exit;  
  145.     }  
  146.   
  147.     AVPacket packet;  
  148.     int key_frame_picture_count = 0;  
  149.   
  150.     while (av_read_frame(fmt_ctx_for_decode, &packet) >= 0)  
  151.     {  
  152.         if (packet.stream_index == video_stream_index)  
  153.         {  
  154.             int got_frame = 0;  
  155.             avcodec_decode_video2(dec_ctx, pFrame,&got_frame, &packet);  
  156.   
  157.             if (got_frame) //一個完整的幀   
  158.             {  
  159.                 if (pFrame->key_frame)  
  160.                 {  
  161.                     sws_scale(pSWSCtx, pFrame->data, pFrame->linesize,0, \  
  162.                         dec_ctx->height, pFrameRGB->data, pFrameRGB->linesize);  
  163.   
  164.                     // 保存到磁盤    
  165.                     char pic[200];   
  166.                     sprintf(pic,"keyframe%d.bmp", ++key_frame_picture_count);  
  167.                     av_create_bmp(pic,pFrameRGB->data[0],dec_ctx->width,dec_ctx->height,24);  
  168.                     //av_create_bmp(pic, pFrameRGB, dec_ctx->width,dec_ctx->height,24);   
  169.                 }  
  170.                 print_frame_info(pFrame);  
  171.   
  172.             }  
  173.   
  174.             print_packet_info(packet);  
  175.         }  
  176.   
  177.     }  
  178.   
  179. exit:  
  180.     avcodec_free_frame(&pFrame);  
  181.     avcodec_free_frame(&pFrameRGB);  
  182.     delete [] buffer;  
  183.     sws_freeContext(pSWSCtx);  
  184.     return ret;  
  185. }  
  186.   
  187. static int open_input_file(const char *filename)  
  188. {  
  189.     int ret;  
  190.     bool video_codec_init = false;  
  191.     int video_stream_index = -1;  
  192.     AVCodecContext* suitable_dec_ctx = NULL;  
  193.     AVFormatContext *video_fmt_ctx = NULL;  
  194.   
  195.     if ((ret = avformat_open_input(&video_fmt_ctx, filename, NULL, NULL)) < 0) {  
  196.         av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");  
  197.         return ret;  
  198.     }  
  199.   
  200.     if ((ret = avformat_find_stream_info(video_fmt_ctx, NULL)) < 0) {  
  201.         av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");  
  202.         avformat_close_input(&video_fmt_ctx);  
  203.         return ret;  
  204.     }  
  205.   
  206.     for (int i = 0; i < video_fmt_ctx->nb_streams; i++)  
  207.     {  
  208.         // 找到視頻碼流   
  209.         if (video_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
  210.         {  
  211.             video_stream_index = i;  
  212.             // 初始化解碼器信息   
  213.             if (!video_codec_init)  
  214.             {  
  215.                 suitable_dec_ctx = video_fmt_ctx->streams[i]->codec;  
  216.   
  217.                  AVCodec* pcodec = avcodec_find_decoder(suitable_dec_ctx->codec_id);  
  218.   
  219.                 if (NULL == pcodec)  
  220.                 {  
  221.                     printf("cannot find decoder");  
  222.                     avformat_close_input(&video_fmt_ctx);  
  223.                     return 1;  
  224.                 }  
  225.   
  226.                 if(0 != avcodec_open2(suitable_dec_ctx, pcodec, NULL))  
  227.                 {  
  228.                     printf("open codecer failed");  
  229.                     avformat_close_input(&video_fmt_ctx);  
  230.                     return 1;  
  231.                 }  
  232.   
  233.                 video_codec_init = true;  
  234.             }  
  235.   
  236.         }  
  237.     }  
  238.   
  239.     // 解碼視頻   
  240.     if (video_codec_init && suitable_dec_ctx)  
  241.     {  
  242.         decode_video_packet(video_fmt_ctx, suitable_dec_ctx, video_stream_index);  
  243.     }  
  244.   
  245.     // 關閉文件   
  246.     avformat_close_input(&video_fmt_ctx);  
  247.   
  248.     return 0;  
  249. }  
  250.   
  251.   
  252. int _tmain(int argc, _TCHAR* argv[])  
  253. {  
  254.     // 註冊庫中所有可能有用的文件格式和編碼器   
  255.     av_register_all();  
  256.     open_input_file("C:\\Users\\xukaijun.HIK\\Desktop\\hikvison.mp4");  
  257.   
  258. #ifdef FILE_OUT   
  259.     file_debugout.close();  
  260. #endif   
  261.   
  262.     return 0;  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章