ARTICLE DETAIL

资讯详情

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

Linux Gstreamer深度解析之gst_audio_decoder_set_estimate_rate调用流程与实战(四十五)

Linux Gstreamer深度解析之gst_audio_decoder_set_estimate_rate调用流程与实战(四十五) 简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮文章目录1.前言2.应用场景和用法2.1字节与时间估算场景2.2函数原型与返回语义3.调用流程剖析3.1设置开关到基类辅助路径3.2累计统计与估算公式4.实战案例4.1准备内置音频解码器4.2切换开关并读取状态4.3完整代码与关键输出5.总结1.前言本篇目的理解gst_audio_decoder_set_estimate_rate()如何控制GstAudioDecoder的字节与时间估算能力并通过最小程序验证开关状态变化。压缩音频解码器接收的是编码字节输出的是带采样率和Frame数的原始音频。上游可能使用GST_FORMAT_BYTES发起Segment、Duration或Seek请求而解码器下游通常使用GST_FORMAT_TIME。这两种单位之间没有固定换算关系。GstAudioDecoder只能根据已经收到的编码字节数、已经输出的样本数和输出采样率计算一个平均估算值。gst_audio_decoder_set_estimate_rate()就是这个能力的开关。它只修改解码器上下文中的布尔字段不统计码流不执行字节到时间的换算也不会直接发送Seek事件。GstAudioDecoder对象子类启动阶段设置估算开关累计编码字节和输出Frame达到基类估算条件辅助字节与时间换算2.应用场景和用法2.1字节与时间估算场景gst_audio_decoder_set_estimate_rate()主要用于编码音频解码器需要兼容字节单位上游的场景。场景调用目的实际作用字节流上游发起时间Seek允许基类把时间位置估算成字节偏移向上游发送字节Seek上游发送非TIME格式Segment允许基类把字节Segment起点估算成时间把后续解码流程切换到TIME Segment上游只能提供字节Duration允许基类根据平均码率估算时间Duration回答下游的时间长度查询传统编码解码器兼容让解码器继续支持旧式BYTE定位方式改善Seek和Duration能力这种换算只适合估算不能当作精确码率。对于可变码率格式估算值会随着累计数据变化。这个函数不负责以下工作不修改输入Buffer。不更新bytes_in和samples_out。不建立输出音频格式。不生成时间戳。不直接调用上游Pad发送Seek。不保证所有GST_QUERY_CONVERT请求都成功。输出Buffer的PTS和Duration仍由gst_audio_decoder_finish_frame()等输出接口结合GstAudioInfo完成。2.2函数原型与返回语义函数原型如下voidgst_audio_decoder_set_estimate_rate(GstAudioDecoder*dec,gboolean enabled);参数含义dec有效的GstAudioDecoder对象enabledTRUE允许基类执行字节与时间的估算辅助FALSE关闭该能力返回值void函数实现的核心动作如下g_return_if_fail(GST_IS_AUDIO_DECODER(dec));dec-priv-ctx.do_estimate_rateenabled;最小调用方式通常放在音频解码器子类的start()回调中staticgbooleanmy_decoder_start(GstAudioDecoder*dec){gst_audio_decoder_set_estimate_rate(dec,TRUE);returnTRUE;}部分GStreamer解码器例如alawdec、mulawdec、a52dec和faad会在启动阶段打开这个开关。基类完整复位时会清空GstAudioDecoderContext因此应用或子类不应只在对象创建后设置一次。需要持续生效时应在子类start()中重新设置。相邻接口的职责不同接口作用gst_audio_decoder_set_estimate_rate()修改估算开关gst_audio_decoder_get_estimate_rate()读取当前开关状态gst_audio_decoder_handle_frame()累计输入编码字节数gst_audio_decoder_finish_frame()累计已输出样本数gst_pad_query_convert()触发Pad之间的格式换算请求gst_audio_decoder_do_byte()基类内部判断当前是否允许自动字节换算gst_audio_decoder_set_estimate_rate()只改变策略不会立即触发后续换算路径。3.调用流程剖析3.1设置开关到基类辅助路径解码器子类通常在启动阶段调用目标函数。目标函数先检查对象类型再把enabled写入dec-priv-ctx.do_estimate_rate。之后基类在处理Segment、Seek和Duration时会调用内部的gst_audio_decoder_do_byte()判断条件retdec-priv-ctx.do_estimate_ratedec-priv-ctx.info.bpfdec-priv-ctx.info.ratedec-priv-samples_out;只有三个条件同时满足基类才会启用自动字节估算子类打开了估算开关。输出音频格式已经提供有效BPF。已经输出至少接近一秒的音频样本。条件满足后基类可以把估算结果用于三类路径把上游字节Segment起点转换成TIME。把时间Seek转换成字节Seek发送给上游。把上游提供的字节Duration转换成时间Duration。解码器子类启动阶段设置估算开关基类累计输入和输出统计检查字节估算条件执行BYTE到TIME估算辅助Segment和Seek及Duration如果开关关闭、输出格式尚未协商或输出样本不足gst_audio_decoder_do_byte()返回FALSE。此时设置函数本身不会报错后续查询或Seek路径是否成功由其他Pad和上游组件决定。3.2累计统计与估算公式输入编码字节数和输出样本数来自两个不同阶段。gst_audio_decoder_handle_frame()收到输入Buffer后会把Buffer大小累加到priv-bytes_indec-priv-bytes_insize;子类调用gst_audio_decoder_finish_frame()或相关输出接口后基类会把已输出样本数累加到priv-samples_outpriv-samples_outsamples;随后内部辅助函数使用输出采样率和累计统计值估算平均字节速率。字节到时间的核心计算可以表示为estimated_time byte_position × GST_SECOND × samples_out ÷ (bytes_in × sample_rate)时间到字节的反向计算可以表示为estimated_bytes time_position × bytes_in × sample_rate ÷ (samples_out × GST_SECOND)这里的bytes_in是累计编码字节数sample_rate来自已经协商的输出GstAudioInfosamples_out是已经解码并交给基类的输出样本数。输入编码字节累计bytes_in解码输出Frame累计samples_out检查估算条件计算BYTE和TIME的估算值因此刚打开开关时不一定马上可以完成换算。没有有效采样率、BPF为0或输出样本数少于一个采样率周期时基类会认为统计信息不足。4.实战案例4.1准备内置音频解码器使用GStreamer自带的alawdec作为测试对象。alawdec属于GstAudioDecoder子类正常启动时会在start()回调中调用gst_audio_decoder_set_estimate_rate(dec,TRUE);测试程序直接创建该解码器对象并通过Getter和Setter观察上下文开关。4.2切换开关并读取状态程序按以下顺序运行创建alawdec对象读取初始估算状态。调用gst_audio_decoder_set_estimate_rate()传入TRUE再次读取状态。传入FALSE确认开关能够关闭。这个实验验证的是Setter的直接职责。它不会产生字节换算结果因为程序没有建立完整解码链也没有累计输入字节、输出样本和协商后的音频格式。4.3完整代码与关键输出#includegst/gst.h#includegst/audio/gstaudiodecoder.hintmain(intargc,char*argv[]){GstElement*element;GstAudioDecoder*decoder;gst_init(argc,argv);elementgst_element_factory_make(alawdec,decoder);if(elementNULL){g_printerr(Failed to create alawdec\n);return1;}decoderGST_AUDIO_DECODER(element);g_print(Initial estimate rate: %d\n,gst_audio_decoder_get_estimate_rate(decoder));gst_audio_decoder_set_estimate_rate(decoder,TRUE);g_print(After enabling: %d\n,gst_audio_decoder_get_estimate_rate(decoder));gst_audio_decoder_set_estimate_rate(decoder,FALSE);g_print(After disabling: %d\n,gst_audio_decoder_get_estimate_rate(decoder));gst_object_unref(element);return0;}编译运行gcc test_estimate_rate.c-otest_estimate_rate\$(pkg-config--cflags--libsgstreamer-1.0 gstreamer-audio-1.0)./test_estimate_rate运行环境需要安装包含alawdec的GStreamer插件。关键输出Initial estimate rate: 0 After enabling: 1 After disabling: 0输出证明gst_audio_decoder_set_estimate_rate()只修改GstAudioDecoderContext中的估算开关。真正的字节与时间换算还需要解码器完成格式协商并累计足够的输入字节和输出样本。5.总结gst_audio_decoder_set_estimate_rate()就是为GstAudioDecoder打开或关闭基类的字节与时间估算能力本身不统计码流、不执行换算也不直接发起Seek。
返回列表