ARTICLE DETAIL

资讯详情

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

TEN Framework 中的 FFmpeg Demuxer 扩展:媒体流解复用与音视频帧输出全解析

TEN Framework 中的 FFmpeg Demuxer 扩展:媒体流解复用与音视频帧输出全解析 人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载导读ffmpeg_demuxer是 TEN Framework 提供的一个基于 FFmpeg 的扩展extension示例用于将媒体文件或网络流中的视频流、音频流分离并解码再以统一的video_frame/audio_frame消息格式送入 TEN 图graph中的下游节点。本文以该扩展的 英文文档 为骨架结合其 manifest.json 与 C 源码讲解如何把该扩展接入 TEN 应用、如何通过prepare_demuxer/start_demuxer命令驱动它工作以及它在多线程架构、FFmpeg 解码链路和输出帧格式上的底层实现细节。读完本文你将掌握在 TEN 应用中搭建一个可用的媒体解复用节点并理解其音视频输出约定。扩展定位媒体流分离ffmpeg_demuxer在 TEN Framework 中扮演“解复用器”角色它读取一个媒体输入源本地文件或网络流从中找出视频流与音频流分别解码并把解码后的每一帧转换成 TEN 的video_frame与audio_frame消息交给图中下游扩展消费。其官方定位是 “media stream separation”媒体流分离详见 英文文档。与之配套仓库中还提供了 ffmpeg_muxer负责把音视频帧重新组合封装与 ffmpeg_client负责编排整个流程三者可以组成一条完整的“解复用 → 处理 → 复用”链路。例如集成测试 tests/ten_runtime/integration/cpp/ffmpeg_basic/test_case.py 就是先让ffmpeg_client发送命令驱动ffmpeg_demuxer解码res/test.mp4把帧交给ffmpeg_muxer重新封装最后用视频对比工具验证输出与原始文件一致。前置条件与依赖根据 manifest.json该扩展声明的依赖如下字段值说明typeextension包类型为扩展nameffmpeg_demuxer扩展名version0.11.73当前仓库中的版本号tags[cpp]使用 C 实现dependencies[0]system/ffmpeg版本7.1.0运行时依赖 FFmpeg 系统包也就是说安装该扩展前需要保证环境中存在版本匹配的 FFmpeg7.1.0系统依赖。构建层面BUILD.gn 中的deps指向//third_party/ffmpeg:ffmpeg_for_ten_packages说明其构建依赖仓库内的 third_party/ffmpeg 目标同时它会打包LICENSE、manifest.json、property.json以及测试用的res/test.mp4资源文件。安装该扩展遵循 TEN Framework 的包安装方式可参考 docs/development/how_to_develop_with_ext.md 中关于扩展包集成到应用的一般流程。集成测试中的应用 manifest.json 展示了典型声明方式应用依赖列表中加入extension/ffmpeg_demuxer版本0.11.73并声明scripts.start为bin/ffmpeg_basic_app。在 TEN 图中接入 demuxer 节点接入方式与 TEN Framework 其他扩展一致在应用的property.json的predefined_graphs中声明节点与连接。参考 ffmpeg_basic 测试应用的 property.json一个典型配置片段如下{ nodes: [ { type: extension, addon: ffmpeg_client, name: ffmpeg_client, extension_group: default_extension_group }, { type: extension, name: ffmpeg_demuxer, addon: ffmpeg_demuxer, extension_group: demuxer_group } ], connections: [ { extension: ffmpeg_client, cmd: [ { name: prepare_demuxer, dest: [ { extension: ffmpeg_demuxer } ] }, { name: start_demuxer, dest: [ { extension: ffmpeg_demuxer } ] } ] }, { extension: ffmpeg_demuxer, cmd: [ { name: complete, dest: [ { extension: ffmpeg_client, msg_conversion: { type: per_property, rules: [ { path: ten.name, conversion_mode: fixed_value, value: demuxer_complete } ] } } ] } ], video_frame: [ { name: video_frame, dest: [ { extension: ffmpeg_muxer } ] } ], audio_frame: [ { name: audio_frame, dest: [ { extension: ffmpeg_muxer } ] } ] } ] }要点说明prepare_demuxer、start_demuxer是 demuxer 扩展对外提供的两个命令必须从上游节点路由到本扩展video_frame与audio_frame是 demuxer 输出给下游的帧消息图中的连接决定了解码后的帧流向此处流向 muxer当输入流读完时demuxer 会发出名为complete的命令可通过msg_conversion将其改名如demuxer_complete后回送给编排方用于通知“解复用结束”。对外命令协议prepare_demuxer 与 start_demuxerdemuxer 的命令入口位于 src/main.cc 的on_cmd()它只处理两个命令prepare_demuxer根据命令属性input_stream指定输入源文件路径或流地址。若未携带该属性则回退到默认值ten_packages/extension/ffmpeg_demuxer/res/test.mp4即打包进扩展资源的测试视频。随后创建一个ten_env_proxy并启动独立的 demuxer 线程命令的成功/失败结果将在该线程中返回。start_demuxer向 demuxer 线程发送“开始解复用”信号。若尚未prepare过则直接返回TEN_STATUS_CODE_ERRORdetail为You should prepare first.否则置信号并返回TEN_STATUS_CODE_OK。命令的发起方可以参考 ffmpeg_client 的 main.cc在on_start()中依次send_cmd(prepare_demuxer)在回调里校验TEN_STATUS_CODE_OK后把返回的 JSON 属性透传给start_muxer命令再send_cmd(start_demuxer)。可见prepare_demuxer的返回结果媒体参数被设计为可继续传递给 muxer 使用。prepare_demuxer 返回的媒体参数demuxer 线程在成功打开输入流后会把媒体信息作为命令结果属性返回见 demuxer_thread.cc 的return_success_result_to_prepare_cmd()属性含义frame_rate_num/frame_rate_den/frame_rate_d视频平均帧率有理数分子分母 浮点值video_time_base_num/video_time_base_den/video_time_base_d视频流 time_basewidth/height视频宽高已考虑旋转bit_rate视频码率num_of_frames视频总帧数audio_sample_rate音频采样率audio_channel_layout_mask音频声道布局掩码audio_num_of_channels音频声道数audio_time_base_num/audio_time_base_den/audio_time_base_d音频流 time_base多线程架构demuxer 独立线程 ten_env_proxy解复用与解码是 CPU 密集型操作因此实现上把它放到独立线程执行避免阻塞 TEN 的扩展线程。整体线程模型可结合 main.cc、demuxer_thread.h 与 demuxer.h 理解prepare_demuxer到达后扩展创建ten_env_proxy_t并new一个demuxer_thread_t启动独立线程ten_thread_create见 demuxer_thread.cc 的start()。线程入口demuxer_thread_main先create_demuxer()打开输入流失败则通过 proxy 返回fail to prepare demuxer.错误成功则返回携带媒体参数的 OK 结果。线程随后阻塞在event_for_start_demuxing事件上wait_to_start_demuxing()直到收到start_demuxer命令触发start_demuxing()置位事件才进入解码循环。解码循环中每得到一帧都通过ten_env_proxy-notify(...)切回 TEN 主线程调用ten_env.send_video_frame(...)/ten_env.send_audio_frame(...)发送帧消息。on_stop()时依次stop()、wait_for_stop_completed()即ten_thread_join并销毁线程对象确保线程安全退出。该设计与 core/include/ten_runtime/ten_env_proxy 提供的跨线程机制一致非扩展线程持有ten_env_proxy即可安全地向 TEN 主线程投递回调。FFmpeg 解码链路源码剖析解码核心类demuxer_t见 demuxer.h 与 demuxer.cc封装了完整的 FFmpeg 流程可按阶段拆解1. 打开输入流与中断保护open_input()demuxer.cc 约 L227 起执行avformat_alloc_context()分配格式上下文注册interrupt_cb中断回调约 L84 起若单次 FFmpeg 操作超过 20 秒time(nullptr) - last_time 20返回非零值立即中断防止网络流等阻塞 I/O 导致无限挂起通过av_dict_set设置analyzeduration1000000约 1000 毫秒以降低探测时延调用avformat_open_input()打开输入失败时打印 FFmpeg 错误消息并关闭上下文交由上层重试。open_input_with_retry()约 L277 起会循环重试打开直到成功或 demuxer 线程被要求停止——这种设计使扩展可以等待“稍后才出现的输入流”。2. 流信息分析与解码器初始化analyze_input()调用avformat_find_stream_info()分析流信息并注释提醒分析时长受analyzeduration影响若追求极低时延可考虑自定义解析器。open_video_stream()/open_audio_stream()使用av_find_best_stream()找到最佳视频/音频流经avcodec_alloc_context3、avcodec_parameters_to_context、avcodec_open2完成解码器绑定。视频流元数据中若有rotate标签会解析为rotate_degree供video_width()/video_height()按 0/180 度与 90/270 度交换宽高保证输出尺寸符合旋转后的画面见 demuxer.cc 中相关实现。音频侧从流参数读取sample_rate、声道数与ch_layout对没有原生声道布局的编码如pcm_mulaw用av_channel_layout_default生成默认布局掩码。3. 解码主循环decode_next_packet()约 L688 起流程如下av_packet_unref(packet) // 丢弃上一包 av_read_frame(ctx, packet) // 读取一个 packet ├─ AVERROR_EOF → flush 剩余音视频帧返回 DECODE_STATUS_EOF └─ 其他错误 → 返回 DECODE_STATUS_ERROR 按 packet-stream_index 分流 ├─ 视频流 → decode_next_video_packet() └─ 音频流 → decode_next_audio_packet()视频avcodec_send_packetavcodec_receive_frameAVERROR(EAGAIN)表示需要更多数据返回true继续读包成功解码后转换为ten::video_frame_t发送。音频同样的 send/receive 模型但用while循环处理“一个 packet 包含多个帧”的情况对 MP3 的AVERROR_INVALIDDATA缺头做跳过处理。到达 EOF 时flush_remaining_video_frames()/flush_remaining_audio_frames()向解码器发送nullptrpacket 冲刷解码器内部缓冲确保末尾帧不丢失。4. 输出帧格式约定源码中定义了两个输出格式宏见 demuxer.cc L58-L59#define DEMUXER_OUTPUT_AUDIO_FRAME_SAMPLE_FMT AV_SAMPLE_FMT_S16 #define DEMUXER_OUTPUT_VIDEO_FRAME_PIXEL_FMT AV_PIX_FMT_RGB24视频帧优先保持AV_PIX_FMT_YUV420P/AV_PIX_FMT_YUVJ420P并映射为 TEN 的TEN_PIXEL_FMT_I420Y/U/V三平面通过av_image_copy_plane拷贝若解码输出恰为AV_PIX_FMT_RGB24则映射为TEN_PIXEL_FMT_RGB24其他像素格式会打日志并跳过。同时通过av_rescale将帧时间戳归一化减去流的start_time并换算为毫秒。音频帧经swr_allocav_opt_set_*配置重采样器统一输出为S16交错格式TEN_AUDIO_FRAME_DATA_FMT_INTERLEAVE并设置bytes_per_sample、sample_rate、channel_layout、声道数与samples_per_channel。线程结束或 EOF 时还会发送set_eof(true)的空video_frame/audio_frame帧demuxer_thread.cc 的send_video_eof/send_audio_eof告知下游流已结束。5. 资源释放析构函数约 L186 起逐一释放AVPacket、AVFrame、视频/音频解码器上下文、sws/swr转换上下文并特别强调必须用avformat_close_input()关闭输入上下文否则对某些封装格式如 HLS会产生内存泄漏。集成验证ffmpeg_basic 与 ffmpeg_bypass仓库中的集成测试可直接验证 demuxer 的功能tests/ten_runtime/integration/cpp/ffmpeg_basic/test_case.py构建ffmpeg_basic_appC 应用运行后由ffmpeg_client驱动 demuxer 解码ten_packages/extension/ffmpeg_demuxer/res/test.mp4帧经 muxer 重新封装为输出 mp4最后调用video_cmp.compareVideo对比输入与输出的视频内容断言一致cmp_rc为真才算通过。测试还处理了 Linux 下LD_LIBRARY_PATH、LD_PRELOADsanitizer 构建时等运行环境细节。tests/ten_runtime/integration/cpp/ffmpeg_bypass/test_case.py另一条“旁路”链路demuxer → muxer 直通同样以对比视频结果来验证帧传输的正确性。这些测试证明demuxer 输出的video_frame/audio_frame能被下游节点消费并重新封装且内容与源文件一致可用于验证二次开发的正确性。小结ffmpeg_demuxer是理解 TEN Framework 媒体扩展的一个高质量样例它以两个命令prepare_demuxer/start_demuxer驱动通过独立线程 ten_env_proxy完成 CPU 密集的解复用解码把 FFmpeg 的AVPacket/AVFrame统一转换为 TEN 的video_frame/audio_frame消息并携带完整的媒体参数供下游使用。无论你是要在 TEN 中搭建视频转码、音视频分析还是媒体流处理的图都可以以此为模板声明依赖、在图中接线、用ffmpeg_client编排命令时序再用仓库中的集成测试验证整条链路。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐TEN Framework 中的 FFmpeg Muxer 扩展音视频媒体流复用Muxing实战解析TEN Framework 中的 FFmpeg Muxer 扩展音视频媒体流复用Muxing实战解析 导读 ffmpeg_muxer 是 TEN Fram人工智能AI Agent多模态语音AI 应用TEN Framework 中的 FFmpeg Muxer 扩展媒体流合并与音视频封装实战解析TEN Framework 中的 FFmpeg Muxer 扩展媒体流合并与音视频封装实战解析 本文围绕 TEN Framework 开源仓库中的 ffmpe人工智能AI Agent多模态语音AI 应用TEN Framework 中的 FFmpeg 解复用扩展基于 ffmpeg_demuxer 的媒体流分离实战指南TEN Framework 中的 FFmpeg 解复用扩展基于 ffmpeg_demuxer 的媒体流分离实战指南 本文围绕 TEN Framework 开源人工智能AI Agent多模态语音AI 应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表