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

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

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

Java使用FFmpeg处理视频文件指南

Java使用FFmpeg处理视频文件指南 本文主要讲述如何使用Java + FFmpeg实现对视频文件的信息提取.码率压缩.分辨率转换等功能: 之前在网上浏览了一大圈Java使用FFmpeg处理音视频的文章,大多都讲的比较简单,楼主在实操过程中踩了很多坑也填了很多坑,希望这份详细的踩坑&填坑指南能帮助到大家: 1. 什么是FFmpeg 点我了解 2. 开发前准备 在使用Java调用FFmpeg处理音视频之前,需要先安装FFmpeg,安装方法分为两种: 引入封装了FFmpeg的开源框架 在系统中手

opencv打开视频文件出错

使用C#调用mingw的so文件,在C++端使用opencv打开视频.这样的项目完成过了一个,第二次做的时候,发现opencv打开视频文件出错. 首先怀疑是opencv的opencv_ffmpeg2410.dll文件找不到,确认了文件位置仍然不行. 然后怀疑是新换的mingw32编译器问题,换回了老版本仍然不行. 最后确认了视频文件的存在性,传递文件名的正确性,一切正常,视频无法打开. 在试验过程中,出现了很多次segmentation fault的情况,发现是因为两个mingw32编译器和他们

使用ffmpeg截取视频第一帧当做背景图

1.在官网下载ffmpeg,http://ffmpeg.org/download.html 我下载的是Windows 64的,如系统是Windows 32,请下载Windows 32-bit 下载完成后解压,得到如下图文件: 打开bin文件: 把bin文件夹所有.dll和.exe文件复制到项目bin文件夹下. 如果想通过cmd命令截取,需要将ffmpeg.exe的路径配置到环境变量里的Path里,可参考https://www.cnblogs.com/hbtmwangjin/articles/95

三 调用摄像头或打开视频文件

调用摄像头 # -*- coding=GBK -*- import cv2 as cv #打开摄像头获取图片 def video_demo(): capture = cv.VideoCapture(0)#打开摄像头,0代表的是设备id,如果有多个摄像头,可以设置其他数值 while True: ret, frame = capture.read() #读取摄像头,它能返回两个参数,第一个参数是bool型的ret,其值为True或False,代表有没有读到图片:第二个参数是frame,是当前截取一

使用ffmpeg合并视频文件的三种方法

ffmpeg合并视频的方法有三种.国内大多数仅介绍了其中之一.于是觉得有必要翻译一下.其实在ffmpeg的 FAQ文档中有比较详细的说明. 使用concat协议进行视频文件的合并 这种方式的适用场景是:视频容器是MPEG-1, MPEG-2 PS或DV等可以直接进行合并的.换句话说,其实可以直接用cat或者copy之类的命令来对视频直接进行合并.很多文章介绍了这种方法,但适用性却没有提及.这并不是一个通用的方法.典型的命令示例如下: ffmpeg -i concat:"intermediate1

使用FFmpeg处理视频文件:视频转码、剪切、合并、播放速调整

安装 略. 转码 最简单命令如下: ffmpeg -i out.ogv -vcodec h264 out.mp4ffmpeg -i out.ogv -vcodec mpeg4 out.mp4ffmpeg -i out.ogv -vcodec libxvid out.mp4ffmpeg -i out.mp4 -vcodec wmv1 out.wmvffmpeg -i out.mp4 -vcodec wmv2 out.wmv -i 后面是输入文件名.-vcodec 后面是编码格式,h264 最佳,但

使用ffmpeg进行视频文件转换成FLV整理 &lt;第六篇&gt;

1.首先下载ffmpeg 2.将解压得到的ffmpeg.exe和pthreadGC2.dll文件解压到任何目录(当然也可以是WebRoot中的目录) 3.创建bat文件convertVideo.bat并添加以下内容:(参数说明见附录一) [TXT] view plaincopy %1/ffmpeg -i %2 -y -ab 56 -ar 22050 -b 500 -r 15 -s 320*240 %3 exit ****************** %1为ffmpeg存放目录 %2为需要转换的文

通过 ffmpeg 获取视频第一帧(指定时间)图片

最近做一个上传教学视频的方法,上传视频的同时需要上传视频缩略图,为了避免用户上传的缩略图与视频内容不符,经理要求直接从上传的视频中截图视频的某一帧作为缩略图,并给我推荐了FFMPEG.FFMPEG 功能很强大,做视频必备的软件. FFMPEG下载地址:https://ffmpeg.org/download.html 1.VideoThumbTaker.java 获取视频指定播放时间的图片 package video;import java.io.IOException;import java.i

FFMpeg写MP4文件例子分析

#define STREAM_DURATION 5.0 #define STREAM_FRAME_RATE 25 /* 25 images/s */ #define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE)) #define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */ static int sws_flags = SWS_BICUBIC; /*******