使用C语言实现从avi视频中提取图片

 更新时间:2023年10月31日 09:27:59   作者:java 乐山  
这篇文章主要为大家详细介绍了如何使用C语言实现从avi视频中提取图片,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以参考下

avi 视频的视频流编码必须是jpeg,或者mjpg

直接用摄像头录取的视频都是这两种格式,不能用ffmpeg转成avi的视频。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
static int zz=1;
 
int main(void){
	
	struct strf{
		unsigned char id[4];             //块ID,固定为strf
		unsigned int size;               //块大小,等于struct avi_strf_chunk去掉id和size的大小
		unsigned int size1;              //size1含义和值同size一样
		unsigned int width;              //视频主窗口宽度(单位:像素)
		unsigned int height;             //视频主窗口高度(单位:像素)
		unsigned short planes;           //始终为1
		unsigned short bitcount;         //每个像素占的位数,只能是1、4、8、16、24和32中的一个
		unsigned char compression[4];    //视频流编码格式,如JPEG、MJPG等
		unsigned int image_size;         //视频图像大小,等于width * height * bitcount / 8
		unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
		unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
		unsigned int num_colors;         //含义不清楚,设为0即可
		unsigned int imp_colors;         //含义不清楚,设为0即可
	}str;
	FILE *f=fopen("/home/wzpc/Videos/tra_mjpg.avi","rb");            //必须是JPEG,MJPG格式的avi
	if(f==NULL){
		puts("file error");
		exit(-1);
	}
	fseek(f,0,SEEK_END);
	int fsize=ftell(f);
	fseek(f,0,SEEK_SET);
	
	int fd=fileno(f);
	char *m=mmap(NULL,fsize,PROT_READ,MAP_SHARED,fd,0);
	
	
	
	for(int t=0;t<fsize;t++){
		if((m[t]=='s')&&(m[t+1]=='t')&&(m[t+2]=='r')&&(m[t+3]=='f')){
			
			memcpy(&str,&m[t],sizeof(str));
			printf("%d\n",str.bitcount);
			printf("%s\n",str.compression);
			printf("%d*%d\n",str.width,str.height);
			
			char r[]={'M','J','P','G'};                 //avi 编码必须是jpeg,mjpg
			char r1[]={'J','P','E','G'};
			int bj=memcmp(str.compression,r,4);
			int bj1=memcmp(str.compression,r1,4);
            if((bj==0)||(bj1==0))
			{
			   zz=0;
			}
		    
		}
	}
	
	if(zz!=0){
		puts("no zc");
		exit(-1);
	}
	
	for(int t=0;t<fsize;t++){
		if((m[t]=='0')&&(m[t+1]=='0')&&(m[t+2]=='d')&&(m[t+3]=='c')){
		    char file[10]={};
			sprintf(file,"%d",t);
			
			chdir("/home/wzpc/Pictures/pic_avi");    //存储图片的目录
			FILE * fo=fopen(file,"w+b");
			if(fo==NULL){
				puts("fo error");
				exit(-1);
			}
			
			int k;
			memcpy(&k,&m[t+4],4);
			fwrite(&m[t+8],k,1,fo);                //直接从mmap中读数据到文件
			fclose(fo);
		
		}
  }
	
	munmap(m,fsize);
	return 0;
}

知识补充

除了上文的方法,小编还为大家整理了C语言读取视频关键帧并保存成图片的方法,希望对大家有所帮助

#include<opencv2\opencv.hpp>
#include <iostream>
#include <stdio.h>
#include<fstream>
using namespace std;
using namespace cv;
int main()
{
    //打开视频文件:其实就是建立一个VideoCapture结构
    VideoCapture capture("D:/MyData/zhaohz4/Desktop/Nansha_video/2.mp4");
    //检测是否正常打开:成功打开时,isOpened返回ture
    if (!capture.isOpened())
        cout << "fail toopen!" << endl;
    //获取整个帧数
    long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
    cout << "整个视频共" << totalFrameNumber << "帧" << endl;
    //设置开始帧()
    long frameToStart = 1;
    capture.set(CV_CAP_PROP_POS_FRAMES, frameToStart);
    cout << "从第" << frameToStart << "帧开始读" << endl;
    //设置结束帧
    int frameToStop = 4000;
    if (frameToStop < frameToStart)
    {
        cout << "结束帧小于开始帧,程序错误,即将退出!" << endl;
        return -1;
    }
    else
    {
        cout << "结束帧为:第" << frameToStop << "帧" << endl;
    }
    //获取帧率
    double rate = capture.get(CV_CAP_PROP_FPS);
    cout << "帧率为:" << rate << endl;
    //定义一个用来控制读取视频循环结束的变量
    bool stop = false;
    //承载每一帧的图像
    Mat frame;
    //显示每一帧的窗口
    namedWindow("Extractedframe");
    //两帧间的间隔时间:
    //int delay = 1000/rate;
    double delay = 2000 / rate;     //??
    //利用while循环读取帧
    //currentFrame是在循环体中控制读取到指定的帧后循环结束的变量
    long currentFrame = frameToStart;
    //滤波器的核
    int kernel_size = 3;
    Mat kernel = Mat::ones(kernel_size, kernel_size, CV_32F) / (float)(kernel_size*kernel_size);
    while (!stop)
    {
        //读取下一帧
        if (!capture.read(frame))
        {
            cout << "读取视频失败" << endl;
            return -1;
        }
        if (currentFrame % 3 == 0)    //每三帧保存一帧
        {
            cout << "正在读取第" << currentFrame << "帧" << endl;
            imshow("Extractedframe", frame);
            cout << "正在写第" << currentFrame << "帧" << endl;
            stringstream str;
            str << "2-"<<currentFrame << ".jpg";     //保存格式
            cout << str.str() << endl;
            imwrite(str.str(), frame);
        }
        //waitKey(intdelay=0)当delay≤ 0时会永远等待;当delay>0时会等待delay毫秒
        //当时间结束前没有按键按下时,返回值为-1;否则返回按键
        //int c = waitKey(delay);
        int c = waitKey(1000);
        //按下ESC或者到达指定的结束帧后退出读取视频
        if ((char)c == 27 || currentFrame > frameToStop)
        {
            stop = true;
        }
        //按下按键后会停留在当前帧,等待下一次按键
        if (c >= 0)
        {
            waitKey(0);
        }
        currentFrame++;
    }
    //关闭视频文件
    capture.release();
    waitKey(0);
    return 0;
}

到此这篇关于使用C语言实现从avi视频中提取图片的文章就介绍到这了,更多相关C语言视频提取图片内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ socket实现miniFTP

    C++ socket实现miniFTP

    这篇文章主要为大家详细介绍了C++ socket实现miniFTP的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • C语言递归实现扫雷游戏

    C语言递归实现扫雷游戏

    这篇文章主要为大家详细介绍了C语言递归实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 使用C语言绘制统计图中的饼图

    使用C语言绘制统计图中的饼图

    常用的统计图有条形图、柱形图、折线图、曲线图、饼图、环形图、扇形图,本文主要为大家详细介绍了如何使用使用C语言绘制统计图中的饼图,希望对大家有所帮助
    2024-02-02
  • 判断一个无向图是否为连通图的方法

    判断一个无向图是否为连通图的方法

    今天小编就为大家分享一篇关于判断一个无向图是否为连通图的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • C++中对象的动态建立与释放详解及其作用介绍

    C++中对象的动态建立与释放详解及其作用介绍

    这篇文章主要介绍了C++中对象的动态建立与释放详解及其作用介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • C语言中if语句加大括号和不加大括号的区别介绍

    C语言中if语句加大括号和不加大括号的区别介绍

    这篇文章主要给大家介绍了关于C语言中if语句加大括号和不加大括号的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 理解数据结构

    理解数据结构

    本文是对数据结构对编程的重要性,数据结构对数据存储,数据处理,内存工作,从宏观上理解数据结构
    2016-07-07
  • 详解C语言中strcpy函数与memcpy函数的区别与实现

    详解C语言中strcpy函数与memcpy函数的区别与实现

    这篇文章主要介绍了C语言中字符串拷贝函数(strcpy)与内存拷贝函数(memcpy)的不同及内存拷贝函数的模拟实现,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • C语言各种操作符透彻理解下篇

    C语言各种操作符透彻理解下篇

    C 语言提供了丰富的操作符,除了上篇中的算术操作符,移位操作符,位操作符,赋值操作符外,还有单目操作符、关系操作符、逻辑操作符、条件操作符等等,让我们通读本篇来详细了解吧
    2022-02-02
  • 基于QT设计一个春联自动生成器

    基于QT设计一个春联自动生成器

    春节是中国最隆重的传统节日,一到过年家家户户肯定是要贴春联;在春节前夕,会用大红纸张,加上浓墨书写祝福词语。本文将利用Qt框架设计一个春联自动生成器,需要的可以参考一下
    2022-01-01

最新评论