在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于FFMPEG采集攝像頭圖像編碼MP4視頻+時間水印

嵌入式技術 ? 來源:嵌入式技術 ? 作者:嵌入式技術 ? 2022-09-29 15:46 ? 次閱讀

基于FFMPEG采集攝像頭圖像編碼MP4視頻+時間水印

1.硬件平臺

操作系統:Ubuntu18.04
ffmpeg版本:ffmpeg4.2.5
攝像頭:電腦自帶或USB免驅攝像頭
水印處理:avfilter
圖像渲染:SDL庫

?攝像頭圖像采集+MP4視頻編碼參考示例:https://blog.csdn.net/weixin_44453694/article/details/123885112
水印添加處理參數示例:https://blog.csdn.net/weixin_44453694/article/details/123909568

2.功能實現

本示例采樣三個線程實現:
?子線程1實現ffmpeg編解碼器注冊,設置圖像格式,攝像頭圖像數據采集。
?子線程2實現MP4視頻格式編碼。
?主線程完成子線程創建,SDL庫初始化,窗口創建,圖像數據渲染。
通過ffmpeg自帶avfilter庫實現時間水印添加。

3.核心代碼

3.1 水印處理函數

//添加水印
int waterMark(AVFrame *frame_in,AVFrame *frame_out,int w,int h,const char *str)
{
	int ret;
	/*根據名字獲取ffmegding定義的filter*/
	const AVFilter *buffersrc=avfilter_get_by_name("buffer");//原始數據
	const AVFilter *buffersink=avfilter_get_by_name("buffersink");//處理后的數據
	/*動態分配AVFilterInOut空間*/
	AVFilterInOut *outputs=avfilter_inout_alloc();
	AVFilterInOut *inputs=avfilter_inout_alloc();	
	/*創建AVFilterGraph,分配空間*/
	AVFilterGraph *filter_graph;//對filters系統的整體管理結構體
	filter_graph = avfilter_graph_alloc();
	enum AVPixelFormat pix_fmts[]={AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};//設置格式
	/*過濾器參數:解碼器的解碼幀將被插入這里。*/
	char args[256];
	snprintf(args, sizeof(args),
		"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
		w,h,AV_PIX_FMT_YUV420P,1,25,1,1);//圖像寬高,格式,幀率,畫面橫縱比
	/*創建過濾器上下文,源數據AVFilterContext*/
	AVFilterContext *buffersrc_ctx;
	ret=avfilter_graph_create_filter(&buffersrc_ctx,buffersrc,"in",args,NULL,filter_graph);
	if(ret<0)
	{
		printf("創建src過濾器上下文失敗AVFilterContextn");
		return -1;
	}		
	/*創建過濾器上下文,處理后數據buffersink_params*/
	AVBufferSinkParams *buffersink_params;
	buffersink_params=av_buffersink_params_alloc();
	buffersink_params->pixel_fmts=pix_fmts;//設置格式
	AVFilterContext *buffersink_ctx;
	ret=avfilter_graph_create_filter(&buffersink_ctx,buffersink,"out",NULL,buffersink_params,filter_graph);
	av_free(buffersink_params);
	if(ret<0)
	{
		printf("創建sink過濾器上下文失敗AVFilterContextn");
		return -2;
	}	
	/*過濾器鏈輸入/輸出鏈接列表*/
	outputs->name       =av_strdup("in");
	outputs->filter_ctx =buffersrc_ctx;
	outputs->pad_idx    =0;
	outputs->next		=NULL;

	inputs->name		=av_strdup("out");
	inputs->filter_ctx	=buffersink_ctx;
	inputs->pad_idx    =0;
	inputs->next		=NULL;
	char filter_desrc[200]={0};//要添加的水印數據
	snprintf(filter_desrc,sizeof(filter_desrc),"drawtext=fontfile=msyhbd.ttc:fontcolor=red:fontsize=25:x=50:y=20:text='%snIT_阿水'",str);
	if(avfilter_graph_parse_ptr(filter_graph,filter_desrc,&inputs,&outputs, NULL)<0)//設置過濾器數據內容
	{
		printf("添加字符串信息失敗n");
		return -3;
	}
	/*檢測配置信息是否正常*/
	if(avfilter_graph_config(filter_graph,NULL)<0)
	{
		printf("配置信息有誤n");
		return -4;
	}	
	#if 0
	/*
		查找要在使用的過濾器,將要觸處理的數據添加到過濾器
		注意:時間若從外面傳入(即144行數據已完整),則此處不需要查找,直接添加即可,否則需要添加下面代碼
	*/
	AVFilterContext* filter_ctx;//上下文
	int parsed_drawtext_0_index = -1;
	 for(int i=0;inb_filters;i++)//查找使用的過濾器
	 {
		 AVFilterContext *filter_ctxn=filter_graph->filters[i];
		 printf("[%s %d]:filter_ctxn_name=%sn",__FUNCTION__,__LINE__,filter_ctxn->name);
		 if(!strcmp(filter_ctxn->name,"Parsed_drawtext_0"))
		 {
			parsed_drawtext_0_index=i;
		 }
	 }
	 if(parsed_drawtext_0_index==-1)
	 {
		printf("[%s %d]:no Parsed_drawtext_0n",__FUNCTION__,__LINE__);//沒有找到過濾器
	 }
	 filter_ctx=filter_graph->filters[parsed_drawtext_0_index];//保存找到的過濾器
	 
		/*獲取系統時間,將時間加入到過濾器*/
		char sys_time[64];
		time_t sec,sec2;	 
		sec=time(NULL);
		if(sec!=sec2)
		{
			sec2=sec;
			struct tm* today = localtime(&sec2);	
			strftime(sys_time, sizeof(sys_time), "%Y/%m/%d %H:%M:%S", today);       //24小時制
		}
		av_opt_set(filter_ctx->priv, "text", sys_time, 0 );  //設置text到過濾器
	 #endif

	/*往源濾波器buffer中輸入待處理數據*/
	 if(av_buffersrc_add_frame(buffersrc_ctx,frame_in)<0)
	 {
		return -5;
	 }
	 /*從濾波器中輸出處理數據*/
	 if(av_buffersink_get_frame(buffersink_ctx, frame_out)<0)
	 {
		return -6;
	 }
	avfilter_inout_free(&outputs);
    avfilter_inout_free(&inputs);
    avfilter_graph_free(&filter_graph);
	return 0;
}

3.2 讀取一幀數據

??讀取一幀圖像數據,進行圖像解碼,圖像格式轉換,添加時間水印。

static AVFrame *get_video_frame(OutputStream *ost,IntputDev* input, int *got_pic)
{
	
	int ret,got_picture;
	AVCodecContext *c=ost->enc;
	AVFrame *ret_frame=NULL;
	/*在各自的時基中比較兩個時間戳。*/
	if(av_compare_ts(ost->next_pts,c->time_base,STREAM_DURATION, (AVRational){1,1})>=0)
	{
		return  (void*)-1;
	}
	/*確保幀數據可寫,盡可能避免數據復制。*/
	if(av_frame_make_writable(ost->frame)<0)
	{
		exit(1);
	}
	/*此函數返回文件中存儲的內容,并且不驗證是否存在解碼器的有效幀。*/
	if(av_read_frame(input->v_ifmtCtx,input->in_packet)>=0)
	{
		if(input->in_packet->stream_index == input->videoindex)
		{
			/*解碼一幀視頻數據。輸入一個壓縮編碼的結構體AVPacket,輸出一個解碼后的結構體AVFrame*/
			ret=avcodec_decode_video2(input->pcodecCtx, input->pFrame,&got_picture,input->in_packet);
			*got_pic=got_picture;
			if(ret<0)
			{
				printf("Decode Error.n");
				av_packet_unref(input->in_packet);
				return NULL;
			}
			if(got_picture)
			{
				sws_scale(input->img_convert_ctx, (const unsigned char * const *)input->pFrame->data,input->pFrame->linesize,0,input->pcodecCtx->height,input->pFrameYUV->data,input->pFrameYUV->linesize);
				sws_scale(input->img_convert_ctx, (const unsigned char * const *)input->pFrame->data,input->pFrame->linesize,0,input->pcodecCtx->height,ost->frame->data,ost->frame->linesize);

				pthread_mutex_lock(&fastmutex);//互斥鎖上鎖
				memcpy(rgb_buff,input->pFrameYUV->data[0],size);
				pthread_cond_broadcast(&cond);//廣播喚醒所有線程
				pthread_mutex_unlock(&fastmutex);//互斥鎖解鎖
				//ost->frame->pts=ost->next_pts++;

				//水印添加處理
				//frame->frame->format=AV_PIX_FMT_YUV420P;
				AVFrame *frame_out=av_frame_alloc();
				unsigned char *frame_buffer_out;
				frame_buffer_out=(unsigned char *)av_malloc(size);
				av_image_fill_arrays(frame_out->data,frame_out->linesize,frame_buffer_out,AV_PIX_FMT_YUV420P,width,height,32);
				//添加水印,調用libavfilter庫實現
				time_t sec;
				sec=time(NULL);
				struct tm* today = localtime(&sec);
				char sys_time[64];
				strftime(sys_time, sizeof(sys_time), "%Y/%m/%d %H:%M:%S", today);  
				waterMark(ost->frame,frame_out,width,height,sys_time);
				//yuv420p,y表示亮度,uv表示像素顏色
				ost->frame=frame_out;
				ost->frame->pts=ost->next_pts++;

				ret_frame=frame_out;
			}
		}
		av_packet_unref(input->in_packet);
	}
	return ret_frame;
}

3.3 SDL庫圖像渲染

int main()
{
	/*創建攝像頭采集線程*/
	pthread_t pthid[2];
    pthread_create(&pthid[0],NULL,Video_CollectImage, NULL);
	pthread_detach(pthid[0]);/*設置分離屬性*/
	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);
	/*創建mp4視頻編碼線程*/
	pthread_create(&pthid[1],NULL,Video_savemp4, NULL);
	pthread_detach(pthid[1]);/*設置分離屬性*/
 	/*創建窗口 */
	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;
	int count=0;
	while(quit)
	{
		while(SDL_PollEvent(&event))/*事件監測*/
		{
			if(event.type==SDL_QUIT)/*退出事件*/
			{
				quit=false;
				video_flag=0;
				pthread_cancel(pthid[1]);/*殺死指定線程*/
				pthread_cancel(pthid[0]);/*殺死指定線程*/
				continue;
			}
			else if(event.type == SDL_KEYDOWN)
			{
				 if(event.key.keysym.sym==SDLK_q)//按‘q’保存視頻
				 {
					count++;
					snprintf(file_name,sizeof(file_name),"%d.mp4",count);
					mp4_decode_stat=1;
				 }
			}
		}
		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;
}

4.示例效果

??攝像頭采集圖像實時渲染:

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

5.完整示例

Gitee源碼鏈接:https://gitee.com/it-a-shui/ffmpeg
CSDN源碼鏈接:https://download.csdn.net/download/weixin_44453694/85084851

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 攝像頭
    +關注

    關注

    60

    文章

    4841

    瀏覽量

    95691
  • ffmpeg
    +關注

    關注

    0

    文章

    46

    瀏覽量

    7403
收藏 人收藏

    評論

    相關推薦

    FFMPEG采集攝像頭圖像SDL渲染+MP4格式視頻編碼

    FFmpeg是一套可以用來記錄、轉換數字音頻、視頻,并能將其轉化為流的開源計算機程序。采用LGPL或GPL許可證。它提供了錄制、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻
    的頭像 發表于 09-29 15:36 ?2054次閱讀

    關于攝像頭圖像采集問題

    `我用labview實現電腦攝像頭圖像采集,運行過程中出現問題了,截圖如下,還請高手指教!謝謝啦`
    發表于 05-25 16:59

    現有MP4主控芯片boxchip f16和一u***攝像頭怎么在MP4顯示器成像

    本帖最后由 qwuiop7890123 于 2013-9-13 22:15 編輯 MP4主控芯片boxchipf16和一u***攝像頭怎么在MP4顯示器成像?需要什么開發軟件,怎么編程?
    發表于 09-13 12:38

    攝像頭采集圖像處理

    就可以做到實際中圖像處理并且做到無線傳輸。這樣的圖像采集處理功能在監控系統和在線檢測都有很大的前景。 本作品是基于安芯一號SLH89F5162單片機,驅動并控制帶FIFO的OV7670CMOS
    發表于 11-05 22:35

    【轉載分享】USB攝像頭采集圖像

    `如果你有USB攝像頭,就是隨便的那種。平時QQ視頻的就可以了(筆記本上自帶的攝像頭,也可以),那你就可以用LabVIEW進行圖像采集了。注
    發表于 03-02 11:36

    【NanoPi NEO試用體驗】USB攝像頭

    (如:192.168.1.16:8080),即可看到攝像頭采集的畫面。如下圖:圖7接下來,通過USB攝像頭錄制一段視頻。執行命令:ffmpeg
    發表于 11-20 14:44

    【FPGA DEMO】Lab 4攝像頭HDMI顯示(高速--HDMI&攝像頭)

    `項目名稱:攝像頭HDMI顯示。具體要求:攝像頭采集視頻圖像數據通過HDMI實時顯示。 系統設計:Perf-V開發板可以連接高速口——HD
    發表于 07-30 15:21

    請問CH32V307可以通過攝像頭采集數據并保存為視頻文件嗎?

    CH32V307可以通過攝像頭采集數據并保存為視頻文件嗎DVP攝像頭常見的輸出格式有MJPEG、YUV422、RGB565等。常見的MJPEG格式數據可以按照規則直接填充文件數據,成為
    發表于 05-12 09:08

    【飛凌OKA40i-C開發板試用體驗】玩轉FFmpeg

    對于1080p的視頻壓縮達到45fps,所以對USB攝像頭視頻壓縮應該沒有什么壓力。三、FFmpeg性能測試FFmpeg有個benchma
    發表于 09-15 19:53

    【觸覺智能 Purple Pi開發板試用】視頻采集編碼與推流開發

    的支持,視頻采集方法,視頻編碼與網絡實時視頻傳輸的實現過程。## 一、測試USB攝像頭驅動因為之
    發表于 10-11 01:40

    如何在OKMX6UL-C上利用攝像頭圖像采集

    要求在OKMX6UL-C(emmc版本)上利用攝像頭圖像采集視頻采集,需要在LCD屏幕上將圖像
    發表于 12-02 06:49

    通過OKA40i-C開發板來介紹FFmpeg的命令行工作方式

    。SDP文件并不需要手工編寫,在ffmpeg運行時它會顯示命令行所對應的SDP定義,如下圖所示。5、FFmpeg轉發USB攝像頭視頻流前面演示了將
    發表于 12-29 16:12

    mp4文件偽裝攝像頭畫面

    電子小白,在網上苦苦尋求方案,請各位路過大俠指點: 主管交代,要弄一個Android設備。 能夠用 mp4 視頻文件偽裝成攝像頭畫面,然后循環播放。 不知道能不能實現呢,請大家提供下思路。謝謝
    發表于 05-10 18:37

    【KV260視覺入門套件試用體驗】2.PS端視頻采集FFMPEG編碼開發測試

    通過連接USB攝像頭,順利完成測試PS側的視頻采以及ffmpeg源碼在本開發板上的編譯過程,初步測試了視頻采集
    發表于 09-11 00:52

    基于DirectShow的多攝像頭視頻采集

    1.為什么使用DirectShow 筆者使用的是兩個USB攝像頭,單攝像頭視頻采集使用OpenCV的VideoCapture類沒有問題,但是雙攝像頭
    發表于 02-08 03:24 ?3303次閱讀
    主站蜘蛛池模板: 国产区一区二区三| 欧美黑人性色黄在线视频| 高清配种视频xxxxx| 6080伦理久久亚洲精品| 天天综合天天看夜夜添狠狠玩| 色综合色综合色综合| 大杳蕉伊人狼人久久一本线| 91视频三级| 成人免费看黄网站无遮挡| 天堂网2018| 亚洲欧美精品成人久久91| 色妞色综合久久夜夜| 久久婷婷综合中文字幕| aaaa视频| 国产免费爽爽视频免费可以看| 亚洲视屏一区| 亚洲成人在线网| 免费网站成人亚洲| www.黄网| 国产精品免费看久久久久| 一卡二卡三卡四卡无卡在线| 欧美一区二区三区在线观看 | 日本理论午夜中文字幕第一页| 精品卡一卡二 卡四卡视频| 午夜在线观看网站| 西西人体大胆高清啪啪欧洲| 中文字幕在线视频第一页| 欧美日a| 午夜视频福利| 很黄很污的视频网站| 欧美精品国产第一区二区| 屁屁影院在线| 午夜精品久久久久久久四虎| 国产三级毛片视频| 免费福利片2022潦草影视午夜| 午夜dy888理论在线播放| 日韩精品三级| 午夜影院a| 最近国语剧情视频在线观看| 俺不色| 在线另类|