ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

音视频开发项目-2主函数

音视频开发项目-2主函数 2. 从主函数开始看起上一篇讲了整体设计这篇从入口rv1126_ffmpeg_main.cpp讲起。main 函数只该干 main 函数的事接参数、起轮子、守住进程。一、先把代码全贴出来#includerkmedia_ffmpeg_config.h#includeffmpeg_video_queue.h#includerkmedia_module_function.h#includerkmedia_assignment_manage.hVIDEO_QUEUE*high_video_queueNULL;VIDEO_QUEUE*low_video_queueNULL;intmain(intargc,char*argv[]){if(argc5){printf(Please Input ./rv1126_ffmpeg_main high_stream_type high_url_address low_stream_type low_url_address. Notice URL_TYPE: 0--FLV 1--TS\n);return-1;}inthigh_protocol_typeatoi(argv[1]);char*high_network_addressargv[2];intlow_protocol_typeatoi(argv[3]);char*low_network_addressargv[4];high_video_queuenewVIDEO_QUEUE();//初始化所有VIDEO队列low_video_queuenewVIDEO_QUEUE();init_rkmedia_module_function();//初始化所有rkmedia的模块init_rv1126_first_assignment(high_protocol_type,high_network_address,low_protocol_type,low_network_address);//开启推流任务while(1){sleep(20);}return0;}二、四个参数两路流各配一组./rv1126_ffmpeg_mainhigh_stream_typehigh_urllow_stream_typelow_url# 例如./rv1126_ffmpeg_main0rtmp://192.168.1.100/live/high0rtmp://192.168.1.100/live/low参数是高清 低清两两一组每组协议类型 推流地址协议类型0→ FLV走 RTMP协议类型1→ TS走 SRT/UDP为弱网场景预留的第二条路为什么是两路流这就是直播的标配——观众网速好的看 1080P网速差的看 720P服务端按需分发。推流地址做成命令行参数而不是写死在代码里换服务器、换直播间都不用重编译这是推流程序的基本修养。三、两个全局队列一个经过权衡的决定VIDEO_QUEUE*high_video_queueNULL;VIDEO_QUEUE*low_video_queueNULL;这两个是全局变量后面rkmedia_data_process.cpp里用extern引用externVIDEO_QUEUE*high_video_queue;externVIDEO_QUEUE*low_video_queue;全局变量当然要慎用但这里我权衡过这两个队列是全项目的主动脉5 个工作线程全都要跟它打交道。如果做成参数层层传递init_rv1126_first_assignment的签名要膨胀一倍每创建一个线程都要多打包一个指针——对一个所有线程天然共享同一对队列的场景全局变量反而是最诚实的表达。C/C 里声明定义分离 extern 引用也是跨文件共享的经典写法。队列在这里new出来之后硬件侧线程往里塞数据推流侧线程从里取数据它是整个项目的传送带第 6 篇专门拆。四、三步初始化把生命周期切成三段init_rkmedia_module_function();// 第一步init_rv1126_first_assignment(...);// 第二步while(1)sleep(20);// 第三步步骤函数在哪个文件干的事1init_rkmedia_module_function()rkmedia_module_function.cpp系统初始化 VI/VENC/RGA 全部配好参数2init_rv1126_first_assignment()rkmedia_assignment_manage.cppFFmpeg 初始化 通道绑定 创建所有工作线程3主循环sleep本文件什么都不干纯活着分工设计第一步把硬件摆好第二步把数据流的管道接起来并放水第三步主线程退到一边看着。每一步只做一类事出问题时日志一打就知道卡在哪一段。主线程while(1) sleep(20)为什么不join线程因为所有工作线程创建后都会pthread_detach(pthread_self())——分离线程线程结束资源自动回收不需要别人 join。主线程唯一的职责就是别让进程退出。嵌入式设备上的常驻程序基本都是这个套路。五、为什么叫 “assignment”init_rv1126_first_assignment这个名字是我有意起的。我把一轮推流任务抽象成一个assignment给两路流各建一套 FFmpeg 输出上下文把 VI/VENC/RGA 通道绑起来再创建 5 个工作线程。为什么要有这个抽象给多任务管理留生长点。“first” 的意思是现在的实现是第一个也是默认的assignment将来如果要在同一块板子上跑第二路推流任务换个摄像头、换个目标平台结构上不需要推翻任何东西——再发起一个 assignment 就行。这是我在设计阶段就埋好的扩展位。六、ISP 的分工应用层不管 ISP一个容易被问到的点rv1126_isp_function.cpp里写了init_all_isp_function()为什么主流程不调它intinit_all_isp_function(){rk_aiq_working_mode_t hdr_modeRK_AIQ_WORKING_MODE_NORMAL;SAMPLE_COMM_ISP_Init(hdr_mode,RK_FALSE);SAMPLE_COMM_ISP_Run();SAMPLE_COMM_ISP_SetFrameRate(30);return0;}这是有意的职责分离RV1126 出厂固件里 rkaiq 守护进程负责把 ISP 拉起来、做 3A曝光/白平衡/对焦应用层只管打开视频节点rkispp_scale0拿图。ISP 的调优是独立的一摊专业活和应用推流解耦之后两边可以各自升级互不影响。这个函数留在代码里是给应用自主控 ISP的场景预留的备用入口——哪天要做无 rkaiq 的精简系统它随时可以顶上。七、小结main 函数虽短但它把三件事定了调两路码流的架构参数形式就暴露了全局队列做 RKMedia 和 FFmpeg 的衔接权衡后的选择主线程只负责活着所有活都在分离线程里干下一篇进第一站init_rkmedia_module_function()看 VI、VENC、RGA 这三个模块的参数是怎么定的——1920x1080、25fps、CBR 码率这些数字背后的考量。本篇对应源码rv1126_ffmpeg_main.cpp
返回列表