FFmpeg获取网络摄像头数据解码
对USB摄像头实时编码,在前面已经探讨过了。这次改变下思路,尝试去截取网络摄像头的H264码流,将其解码播放。
这里的测试代码,是在海康摄像头的基础上进行的。
解码的大致流程和以前的保持一致,只不过增加了部分函数。
FFmpeg打开媒体文件并查看媒体文件的信息,有三个步骤:
avformat_open_input;
avformat_find_stream_info;
av_dump_format;
依次调用三个函数后,我们可以很清楚的知道码流的各种信息。
完整的代码:
#include#include #include #include #include #include"queue.h" extern"C" { #include #include #include } #pragmacomment(lib,"avcodec.lib") #pragmacomment(lib,"avformat.lib") #pragmacomment(lib,"avutil.lib") #pragmacomment(lib,"swscale.lib") usingnamespacestd; usingnamespacecv; DWORDWINAPIopencv_imshow(LPVOIDlparam) { result_link_type*result_link=(result_link_type*)lparam; structresult_node_datatype*result_node2=NULL; while(1) { result_node2=result_pop(result_link); if(result_node2==NULL) { Sleep(1); continue; } imshow("frame",result_node2->result); waitKey(1); } } intmain(intargc,constchar*argv[]) { HANDLEthread1; result_link_type*result_link=newresult_link_type; result_link->head=result_link->end=NULL; result_link->result_num=0; thread1=CreateThread(NULL,0,opencv_imshow,(LPVOID)result_link,0,NULL); inti; intvideoStream; intframeFinished; intnumBytes; intret; intgot_picture; longprepts=0; boolfirst_time=true; AVCodec*pCodec; AVFrame*pFrame; AVFrame*pFrameRGB; AVPacketpacket; AVCodecContext*pCodecCtx; AVFormatContext*pFormatCtx=NULL;//结构体AVFormatContext:包含码流参数较多 staticstructSwsContext*img_convert_ctx; uint8_t*buffer; MatpCvMat; charfilepath[]="rtsp://admin:jdh123456@10.170.6.187/axis-media/media.amp?camera=2";//码流的获取路径 av_register_all();//注册编解码器 avformat_network_init();//加载socket库以及网络加密协议相关的库 if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0)//打开多媒体数据并且获得信息 { return-1; } if(avformat_find_stream_info(pFormatCtx,NULL)<0)//读取视音频数据并且获得信息 { return-1; } av_dump_format(pFormatCtx,0,argv[1],false);//手工调试函数,看到pFormatCtx->streams的内容 videoStream=-1; for(i=0;i nb_streams;i++) { if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) { videoStream=i; break; } } if(videoStream==-1) { return-1; } pCodecCtx=pFormatCtx->streams[videoStream]->codec; pCodec=avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器 if(pCodec==NULL) { return-1; } if(avcodec_open2(pCodecCtx,pCodec,0)<0)//初始化AVCodecContext { return-1; } if(pCodecCtx->time_base.num>1000&&pCodecCtx->time_base.den==1) { pCodecCtx->time_base.den=1000; } pFrame=av_frame_alloc();//分配内存 pFrameRGB=av_frame_alloc(); i=0; while(1) { if(av_read_frame(pFormatCtx,&packet)>=0)//读取码流中的音频若干帧或者视频一帧 { if(packet.stream_index==videoStream) { ret=avcodec_decode_video2(pCodecCtx,pFrame,&got_picture,&packet);//开始解码 if(ret<0) { printf("DecodeError.(解码错误)\n"); returnret; } if(got_picture)//解码成功,got_picture返回任意非零值 { if(first_time) { //初始化SwsContext img_convert_ctx=sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_BGR24,SWS_BICUBIC,NULL,NULL,NULL); if(img_convert_ctx==NULL) { fprintf(stderr,"Cannotinitializetheconversioncontext!\n"); exit(1); } numBytes=avpicture_get_size(AV_PIX_FMT_BGR24,pCodecCtx->width,pCodecCtx->height); buffer=(uint8_t*)av_malloc(numBytes); avpicture_fill((AVPicture*)pFrameRGB,buffer,AV_PIX_FMT_BGR24,pCodecCtx->width,pCodecCtx->height);//allocatormemoryforBGRbuffer pCvMat.create(cv::Size(pCodecCtx->width,pCodecCtx->height),CV_8UC3); first_time=false; } //处理图像数据 sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize); memcpy(pCvMat.data,buffer,numBytes); structresult_node_datatype*result_node=newstructresult_node_datatype; result_node->result=pCvMat; result_push(result_link,result_node); } } av_free_packet(&packet); } } //free(buffer); av_free(buffer); av_free(pFrameRGB); av_free(pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); system("Pause"); return0; }
队列函数:
#include"queue.h" #includeusingnamespacestd; voidresult_push(result_link_type*result_link,result_node_datatype*result_node)//入队操作 { if(result_link->head==NULL) { result_link->head=result_node; result_link->end=result_link->head; result_link->result_num++; } else { result_link->end->next=result_node; result_link->end=result_node; result_link->result_num++; } } structresult_node_datatype*result_pop(result_link_type*result_link)//出队操作 { structresult_node_datatype*tmp_node; if(result_link->head==NULL) returnNULL; elseif(result_link->head==result_link->end) { returnNULL; } else { tmp_node=result_link->head; result_link->head=result_link->head->next; result_link->result_num--; returntmp_node; } }
队列函数的头文件:
#ifndefQUEUE_H #defineQUEUE_H #include#include #include #include usingnamespacecv; typedefstructresult_link_datatype { structresult_node_datatype*head; structresult_node_datatype*end; intresult_num; }result_link_type; structresult_node_datatype { Matresult; structresult_node_datatype*next; }; voidresult_push(result_link_type*result_link,result_node_datatype*result_node);//入队操作 structresult_node_datatype*result_pop(result_link_type*result_link);//出队操作 #endif
解码后的数据进入队列,再从队列中取出,利用opencv将其显示(opencv显示是另外开的一个线程函数)。
admin:jdh123456@10.170.6.187,这里是摄像头的名称和IP地址。
测试代码下载:点击打开链接
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。