C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C语言视频提取图片

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

作者: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语言视频提取图片内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文