0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux下ffmpeg库开发之读取摄像头数据

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-09-29 15:08 次阅读

Linux下ffmpeg库开发之读取摄像头数据

 FFmpeg是一套可以用来记录、转换数字音频视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

1.ffmpeg源码安装

  安装ffmpeg库之前需要先安装yasm库和x264库。

 1.1 Yasm安装

  下载地址:http://yasm.tortall.net/

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

  安装yasm

#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/yasm-1.3.0.tar.gz  
#配置信息,生成Makefile
./configure 
#编译安装
make && make install 

 1.2 x264安装

  下载地址:https://www.videolan.org/developers/x264.html

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

  安装x264

#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/x264-master.tar.bz2
#配置信息,生成Makefile
./configure --prefix=$PWD/_install --enable-shared --enable-static
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

  若配置时提示找不到nasm则下载nasm
  安装nasm
  nasm下载地址:https://www.nasm.us/pub/nasm/releasebuilds/2.15.03/

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

 Netwide Assembler (简称 NASM)是一款基于x86架构的汇编与反汇编软件。它可以用来编写16位(8086、80286等)、32位(IA-32)和64位(x86_64)的程序。 NASM被认为是Linux平台上最受欢迎的汇编工具之一。
NASM可以输出包括通用对象文件格式(COFF)、OMF(Relocatable Object Module Format,用于80x86系列处理器上)、a.out、可执行与可链接格式(ELF)、Mach-O、二进制文件(.bin,二进制磁盘映像,用于编译操作系统)等多种二进制格式,而地址无关代码仅支持ELF对象文件。 NASM也有自己的称为RDOFF(Relocatable Dynamic Object File Format)的二进制格式。

tar xvf /mnt/hgfs/ubuntu/software_pack/nasm-2.15.03.tar.gz
./autogen.sh 
./configure
make && make install

 再重新编译x264,按照1.2小结操作:

#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/x264-master.tar.bz2
#配置信息,生成Makefile
./configure --prefix=$PWD/_install --enable-shared --enable-static
make && make install

  拷贝相关库到系统目录下

[wbyq@wbyq _install]$ sudo cp ./lib/*.so* /usr/lib -fdv

 1.3 ffmpeg安装

  为了保证后续音视频录制正常,需要先安装声卡驱动。

sudo apt-get install libasound2-dev

  下载地址:http://www.ffmpeg.org/download.html

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

编译安装ffmpeg

#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/ffmpeg-4.2.5.tar.bz2
#配置信息,生成Makefile
./configure --enable-static --enable-shared --prefix=$PWD/_install --extra-cflags=-I/home/wbyq/src_pack/x264-master/_install/include --extra-ldflags=-L/home/wbyq/src_pack/x264-master/_install/lib --enable-ffmpeg --enable-libx264 --enable-gpl
#编译安装
make && make install

拷贝相关库到系统目录下

[wbyq@wbyq _install]$ sudo  cp ./bin/ffmpeg /usr/bin/
[wbyq@wbyq _install]$ sudo cp lib/*.so* /usr/lib -rfdv

2. 查看ffmpeg版本信息

[wbyq@wbyq ~]$ ffmpeg -version
ffmpeg version 4.2.5 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --enable-static --enable-shared --prefix=/home/wbyq/src_pack/ffmpeg-4.2.5/_install --extra-cflags=-I/home/wbyq/src_pack/x264-master/_install/include --extra-ldflags=-L/home/wbyq/src_pack/x264-master/_install/lib --enable-ffmpeg --enable-libx264 --enable-gpl
libavutil      56. 31.100 / 56. 31.100
libavcodec     58. 54.100 / 58. 54.100
libavformat    58. 29.100 / 58. 29.100
libavdevice    58.  8.100 / 58.  8.100
libavfilter     7. 57.100 /  7. 57.100
libswscale      5.  5.100 /  5.  5.100
libswresample   3.  5.100 /  3.  5.100
libpostproc    55.  5.100 / 55.  5.100

3.ffmpeg代码开发读取摄像头数据通过SDL显示

 3.1 参考代码

#include 
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define VIDEO_DEV "/dev/video2"
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件变量
typedef enum
{
	false=0,
	true,
}bool;
int width;
int height;
int size;
unsigned char *rgb_buff=NULL;
unsigned char video_flag=1;
void *Video_CollectImage(void *arg);
int main()
{
	/*创建摄像头采集线程*/
	pthread_t pthid;
    pthread_create(&pthid,NULL,Video_CollectImage, NULL);
	pthread_detach(pthid);/*设置分离属性*/
	sleep(1);
	while(1)
	{
		if(width!=0 && height!=0 && size!=0)break;
		if(video_flag==0)return 0;
	}
	printf("image:%d * %d,%dn",width,height,size);
	unsigned char *rgb_data=malloc(size);
 	/*创建窗口 */
	SDL_Window *window=SDL_CreateWindow("SDL_VIDEO", SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE);
    /*创建渲染器*/
	SDL_Renderer *render=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
	/*清空渲染器*/
	SDL_RenderClear(render);
   /*创建纹理*/
	SDL_Texture*sdltext=SDL_CreateTexture(render,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,width,height);
	bool quit=true;
	SDL_Event event;
	SDL_Rect rect;
	while(quit)
	{
		while(SDL_PollEvent(&event))/*事件监测*/
		{
			if(event.type==SDL_QUIT)/*退出事件*/
			{
				quit=false;
				video_flag=0;
				pthread_cancel(pthid);/*杀死指定线程*/
				continue;
			}
		}
		if(!video_flag)
		{
			quit=false;
			continue;
		}
		pthread_mutex_lock(&fastmutex);//互斥锁上锁
		pthread_cond_wait(&cond,&fastmutex);
		memcpy(rgb_data,rgb_buff,size);
		pthread_mutex_unlock(&fastmutex);//互斥锁解锁
		SDL_UpdateTexture(sdltext,NULL,rgb_data,width);
		//SDL_RenderCopy(render, sdltext, NULL,NULL); // 拷贝纹理到渲染器
		SDL_RenderCopyEx(render, sdltext,NULL,NULL,0,NULL,SDL_FLIP_NONE);
		SDL_RenderPresent(render); // 渲染
	}
	SDL_DestroyTexture(sdltext);/*销毁纹理*/
    SDL_DestroyRenderer(render);/*销毁渲染器*/
    SDL_DestroyWindow(window);/*销毁窗口 */
    SDL_Quit();/*关闭SDL*/
    pthread_mutex_destroy(&fastmutex);/*销毁互斥锁*/
    pthread_cond_destroy(&cond);/*销毁条件变量*/
	free(rgb_buff);
	free(rgb_data);
	return 0;
}
void *Video_CollectImage(void *arg)
{
	int res=0;
	AVFrame *Input_pFrame=NULL;
	AVFrame *Output_pFrame=NULL;
	printf("pth:%sn",avcodec_configuration());
	/*注册设备*/
	avdevice_register_all();
	/*查找输入格式*/
	AVInputFormat *ifmt=av_find_input_format("video4linux2");
	if(ifmt==NULL)
	{
		printf("av_find_input_format failedn");
		video_flag=0;
		return 0;
	}
	/*打开输入流并读取头部信息*/
	AVFormatContext *ps=NULL;
	res=avformat_open_input(&ps,VIDEO_DEV,ifmt,NULL);
	if(res)
	{
		printf("open input failedn");
		video_flag=0;
		return 0;
	}
	/*查找流信息*/
	res=avformat_find_stream_info(ps,NULL);
	if(res)
	{
		printf("find stream failedn");
		video_flag=0;
		return 0;
	}
	/*打印有关输入或输出格式信息*/
	av_dump_format(ps, 0, "video4linux2", 0);
	/*寻找视频流*/
	int videostream=-1;
	videostream=av_find_best_stream(ps,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
	printf("videostram=%dn",videostream);
	/*寻找编解码器*/
	AVCodec *video_avcodec=NULL;/*保存解码器信息*/
	AVStream *stream = ps->streams[videostream];
	AVCodecContext *context=stream->codec;
	video_avcodec=avcodec_find_decoder(context->codec_id);
	if(video_avcodec==NULL)
	{
		printf("find video decodec failedn");
		video_flag=0;
		return 0;
	}	
	/*初始化音视频解码器*/
	res=avcodec_open2(context,video_avcodec,NULL);
	if(res)
	{
		printf("avcodec_open2 failedn");
		video_flag=0;
		return 0;
	}	
	AVPacket *packet=av_malloc(sizeof(AVPacket));/*分配包*/
	AVFrame *frame=av_frame_alloc();/*分配视频帧*/
	AVFrame *frameyuv=av_frame_alloc();/*申请YUV空间*/
	/*分配空间,进行图像转换*/
	width=context->width;
	height=context->height;
	int fmt=context->pix_fmt;/*流格式*/
	size=av_image_get_buffer_size(AV_PIX_FMT_YUV420P,width,height,16);
	unsigned char *buff=NULL;
	printf("w=%d,h=%d,size=%dn",width,height,size);	
	buff=av_malloc(size);
	rgb_buff=malloc(size);//保存RGB颜色数据
	/*存储一帧图像数据*/
	av_image_fill_arrays(frameyuv->data,frameyuv->linesize,buff,AV_PIX_FMT_YUV420P,width,height, 16);
	/*转换上下文,使用sws_scale()执行缩放/转换操作。*/
	struct SwsContext *swsctx=sws_getContext(width,height, fmt,width,height, AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
	/*读帧*/
	int go=0;
	int Framecount=0;
	printf("read fream buffn");
	while(av_read_frame(ps,packet)>=0 && video_flag)
	{
		Framecount++;
		if(packet->stream_index == AVMEDIA_TYPE_VIDEO)/*判断是否为视频*/
		{
			/*解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame*/
			res=avcodec_decode_video2(ps->streams[videostream]->codec,frame,&go,packet);
			if(res<0)
			{
				printf("avcodec_decode_video2 failedn");
				break;
			}
			if(go)
			{
				/*转换像素的函数*/
				sws_scale(swsctx,(const uint8_t * const*)frame->data,frame->linesize,0,height,frameyuv->data,frameyuv->linesize);
				pthread_mutex_lock(&fastmutex);//互斥锁上锁
				memcpy(rgb_buff,buff,size);
		        pthread_cond_broadcast(&cond);//广播唤醒所有线程
		        pthread_mutex_unlock(&fastmutex);//互斥锁解锁
			}
		}		
	}
	sws_freeContext(swsctx);/*释放上下文*/
	av_frame_free(&frameyuv);/*释放YUV空间*/
	av_packet_unref(packet);/*释放包*/
	av_frame_free(&frame);/*释放视频帧*/
	avformat_close_input(&ps);/*关闭流*/
	video_flag=0;
	pthread_exit(NULL);	
}

 3.2 Makefile文件

OBJ=get_cameraimage.c
CFLAGS =-I/home/wbyq/src_pack/SDL2-2.0.14/_install/include -I/home/wbyq/src_pack/SDL2-2.0.14/_install/include/SDL2 -L/home/wbyq/src_pack/SDL2-2.0.14/_install/lib
CFLAGS +=-L/home/wbyq/src_pack/SDL2_image-2.0.5/_install/lib -I/home/wbyq/src_pack/SDL2_image-2.0.5/_install/include -I/home/wbyq/src_pack/SDL2_image-2.0.5/_install/include/SDL2
CFLAGS+=-lSDL2 -lpthread -lm -ldl -lSDL2_image -lavcodec -lavfilter -lavutil -lswresample -lavdevice -lavformat -lpostproc -lswscale -lpthread -lstdc++ -lm -lasound
CFLAGS+=-I/home/wbyq/src_pack/ffmpeg-4.2.5/_install/include -L/home/wbyq/src_pack/ffmpeg-4.2.5/_install/lib -I/home/wbyq/src_pack/SDL2-2.0.14/_install/include -I/home/wbyq/src_pack/SDL2-2.0.14/_install/include/SDL2 
app:
	gcc $(OBJ) $(CFLAGS)

 3.3 运行效果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208896
  • 摄像头
    +关注

    关注

    59

    文章

    4807

    浏览量

    95408
  • ffmpeg
    +关注

    关注

    0

    文章

    46

    浏览量

    7378
收藏 人收藏

    评论

    相关推荐

    Linux摄像头应用编程

    V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/vid
    的头像 发表于 08-26 21:39 2781次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>下</b><b class='flag-5'>摄像头</b>应用编程

    《深入理解FFmpeg阅读体验》FFmpeg摄像头测试

    零、前期工作 上文FFmpeg移植完成后,需要将x264/lib文件夹下的文件拷贝到开发板的/lib/目录下,将ffmpeg_install/lib文件夹下的
    发表于 04-17 19:06

    如何将连接到FPGA的摄像头数据发送到主机PC?

    我正在寻找一种方法,将连接到 FPGA 的摄像头数据发送到主机 PC。 摄像头 ---> FPGA ---> FX3 ---> USB 主机 (PC) 我
    发表于 07-05 07:31

    求教大神 串口发送摄像头数据问题

    我想做一个摄像头数据帧的帧头。就是我将采集的图像(很小而且是灰度图)数据通过串口发送给LabVIEW, 在图像数据前发送一个字节,值为0xff,图像数据一个字节一个字节传送。请问该怎么
    发表于 11-28 21:47

    【DragonBoard 410c试用体验】初试摄像头

    龙板上使用摄像头,归根到底还是Linux系统使用摄像头,无非就是打开设备文件,然后读取摄像头数据读取
    发表于 09-19 15:35

    请问摄像头数据做PID控制是控制四轴的什么量?

    你们说那摄像头数据做PID控制 是控制四轴的什么量的啊 ,控制油门原来的前后左右值还是什么?还有四轴调好后可以垂直起飞,之后很飘正常吗?这样还可以摄像头控制吗? 求大神解答
    发表于 05-26 21:50

    stm32如何通过串口将摄像头数据以bmp格式输出?

    stm32通过串口将摄像头数据以bmp格式输出大侠们 给个思路
    发表于 04-28 04:35

    TM4C对ov7620摄像头数据的直接读取

    大家好!刚刚接触到摄像头这一块,当我用ccs5.4定义一个640*480的uchar型大数组时,编译一定不会通过。不过我不能把数组定义为常量,因为摄像头数据需要实时读取,更新与分析,需要在内存里。这种情况应该如何解决?谢谢大家!
    发表于 08-26 11:46

    单片机摄像头数据采集驱动

    一、摄像头数据采集驱动1.时序2.代码二、图像数据的简单处理参考:
    发表于 11-22 07:13

    RK3399pro使用python3读取USB摄像头数据出现错误怎么解决?

    RK3399pro使用python3读取USB摄像头数据出现错误怎么解决?SSD模型输出之后,后处理时间太长怎么解决?
    发表于 03-07 07:26

    如何在Android平台实现对摄像头数据采集并发送H.264格式的视频数据

    本帖子主要展示如何在Android平台实现对摄像头数据采集,再通过JNI调用ffmpeg压制成H.264格式的视频数据,再通过简单UDP协议外发到WIN平台的简易例程,没有实现RTS
    发表于 07-01 16:56

    【米尔MYD-YT507开发板试用体验】ubuntuFFmpeg摄像头流体验

    体验了。之后我们需要完成我们的摄像头数据推流实验,需要一个摄像头。这里可以选择某宝的USB免驱摄像头,看挂载与否可以参考命令。ls /dev 查看下面,插入是否有video0这样的设备。由于其没有插入
    发表于 07-21 20:11

    如何将采集到摄像头数据完全传输到PC?

    如何将采集到摄像头数据完全传输到PC有什么好的方法?
    发表于 10-18 08:31

    OV7620摄像头数据手册

    OV7620摄像头数据手册
    发表于 10-24 13:48 44次下载
    OV7620<b class='flag-5'>摄像头数据</b>手册

    Linux开发_摄像头编程(实现拍照功能)

    这篇文章主要介绍LinuxUVC免驱摄像头操作流程,介绍V4L2框架、完成摄像头拍照保存为BMP图像到本地,最后贴出了利用CJSON解析
    的头像 发表于 09-17 15:34 1778次阅读