首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

【学习ffmpeg】打开视频文件,帧分析,并bmp保留关键帧

2013-03-10 
【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧第一次接触ffmpeg,可以算是hello world程序。下面的代码

【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧

第一次接触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_OUTstd::ofstream file_debugout("frameandpacketinfo.txt");#endifstatic 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;}


 

热点排行