ARTICLE DETAIL

资讯详情

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

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

Linux Gstreamer深度解析之gst_audio_decoder_set_drainable调用流程与实战(四十四) 简介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准备最小GstAudioDecoder子类4.2设置状态并读取结果4.3完整代码与关键输出5.总结1.前言本篇目的理解gst_audio_decoder_set_drainable()如何配置GstAudioDecoder的排空能力分析它与handle_frame()、EOS和Flush处理的关系并通过最小C程序验证配置状态。音频解码器可能在输入数据结束后仍然保留部分编码器缓存。例如帧重排、子帧合并或编解码器内部延迟都可能导致最后一批PCM还没有输出。GstAudioDecoder基类在处理EOS或Flush时会尝试排空这些残留数据。gst_audio_decoder_set_drainable()用于告诉基类当前解码器子类是否能够接受一个NULL输入Buffer并在这个阶段输出剩余解码数据。这个函数只修改drainable状态不会主动触发排空不会调用handle_frame()也不会创建或释放Buffer。GstAudioDecoder子类gst_audio_decoder_set_drainable保存drainable状态EOS或Flush触发排空允许或跳过NULL输入处理2.应用场景和用法2.1解码器排空状态的使用场景gst_audio_decoder_set_drainable()主要用于配置解码器子类与基类之间的结束处理边界。场景配置方式结果编解码器存在内部延迟设置为TRUEEOS或Flush排空时子类可以收到NULL输入解码器只接受真实编码数据设置为FALSE基类不会通过NULL输入调用子类帧重排或子帧合并通常保持TRUE子类可以在无新输入时输出缓存数据只需要处理完整输入帧可以设置为FALSE排空阶段直接结束不额外请求残留数据默认值是TRUE。这意味着一个新的GstAudioDecoder默认允许基类在排空阶段调用子类的handle_frame()并传入NULL。TRUE只表示子类具备接收NULL输入的能力不代表子类一定会产生输出。是否能够输出剩余PCM仍然由具体解码器的handle_frame()实现决定。FALSE也不会阻止正常输入处理。它只影响基类进入强制排空模式、且适配器中没有剩余输入数据时的行为。2.2函数原型与返回语义函数原型如下voidgst_audio_decoder_set_drainable(GstAudioDecoder*dec,gboolean enabled);参数含义dec有效的GstAudioDecoder对象enabled是否允许排空阶段把NULL输入交给子类函数返回值为void。调用前dec必须是有效的GstAudioDecoder实例。最小调用方式如下gst_audio_decoder_set_drainable(dec,TRUE);函数内部会执行对象类型检查然后在GST_OBJECT_LOCK保护下写入GST_OBJECT_LOCK(dec);dec-priv-drainableenabled;GST_OBJECT_UNLOCK(dec);因此该接口是线程安全的状态配置接口。它不会调用子类的handle_frame()。触发EOS、Flush或Drain。修改输入适配器中的编码数据。修改输出Caps和音频格式。创建或释放解码Buffer。改变解码器的引用计数。对应的读取接口是gst_audio_decoder_get_drainable()gboolean drainable;drainablegst_audio_decoder_get_drainable(dec);gst_audio_decoder_set_drainable()负责写入状态gst_audio_decoder_get_drainable()负责读取状态handle_frame()负责真正处理输入或排空请求。3.调用流程剖析3.1基类排空路径中的状态分派gst_audio_decoder_set_drainable()只修改私有字段。真正使用这个字段的是基类内部的排空流程。当EOS或非硬Flush到达时基类会进入gst_audio_decoder_drain()随后调用gst_audio_decoder_push_buffers()并启用强制模式。如果适配器中仍然有编码数据基类继续把真实Buffer交给子类。只有在强制模式下且适配器已经没有可用数据时基类才检查drainable。否是EOS或Flush事件基类进入排空流程push_buffers进入强制模式drainable是否启用标记已排空并结束handle_frame收到NULL当drainable为FALSE时基类直接把解码器标记为已排空不调用子类的handle_frame()。当drainable为TRUE时基类构造一个NULL输入并调用子类的handle_frame()。子类可以在这个调用中刷新内部缓存再通过gst_audio_decoder_finish_frame()提交剩余解码数据。因此gst_audio_decoder_set_drainable()位于配置阶段handle_frame(NULL)位于结束阶段两者之间由EOS、Flush或其他基类排空动作连接。3.2状态字段与相邻接口边界GstAudioDecoder初始化时会把私有字段drainable设置为TRUE。之后只有初始化逻辑和gst_audio_decoder_set_drainable()会修改这个字段。基类的普通输入处理不受该字段影响。适配器中存在真实编码数据时子类仍然收到真实Buffer。drainable只参与强制排空分支。几个相邻接口的职责不同接口或回调职责gst_audio_decoder_set_drainable()写入是否允许NULL排空输入gst_audio_decoder_get_drainable()读取当前排空配置GstAudioDecoderClass.handle_frame处理真实编码Buffer或排空阶段的NULL输入gst_audio_decoder_finish_frame()提交解码输出或标记输入帧已处理GstAudioDecoderClass.flush通知子类清理编解码器缓存gst_audio_decoder_drain()基类内部执行排空流程gst_audio_decoder_set_drainable()不会替代子类的flush()。Flush场景中基类可以先排空再调用子类的Flush处理逻辑。子类是否清理内部缓存、是否输出剩余数据仍然由对应回调负责。4.实战案例4.1准备最小GstAudioDecoder子类为了调用gst_audio_decoder_set_drainable()需要先创建一个GstAudioDecoder子类对象。示例子类只提供必要的Sink和SrcPad模板不进入真实解码流程。这样可以直接观察默认值、关闭状态和重新开启状态。4.2设置状态并读取结果程序按以下顺序运行创建一个最小GstAudioDecoder子类对象。使用gst_audio_decoder_get_drainable()读取默认值。调用gst_audio_decoder_set_drainable()关闭排空能力再读取状态。再次开启排空能力确认状态恢复。这个实验验证的是目标函数直接修改的私有状态。真正的NULL输入分派需要把该对象放入运行中的解码Pipeline并通过EOS或Flush触发基类排空。4.3完整代码与关键输出#includegst/gst.h#includegst/audio/audio.htypedefstruct_DemoAudioDecoder{GstAudioDecoder parent;}DemoAudioDecoder;typedefstruct_DemoAudioDecoderClass{GstAudioDecoderClass parent_class;}DemoAudioDecoderClass;G_DEFINE_TYPE(DemoAudioDecoder,demo_audio_decoder,GST_TYPE_AUDIO_DECODER);staticGstStaticPadTemplate sink_templateGST_STATIC_PAD_TEMPLATE(sink,GST_PAD_SINK,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-demo));staticGstStaticPadTemplate src_templateGST_STATIC_PAD_TEMPLATE(src,GST_PAD_SRC,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-raw, format(string)S16LE, layout(string)interleaved, rate(int)8000, channels(int)1));staticvoiddemo_audio_decoder_class_init(DemoAudioDecoderClass*klass){GstElementClass*element_classGST_ELEMENT_CLASS(klass);gst_element_class_add_static_pad_template(element_class,sink_template);gst_element_class_add_static_pad_template(element_class,src_template);gst_element_class_set_static_metadata(element_class,Drainable demo decoder,Codec/Decoder/Audio,Minimal GstAudioDecoder state test,Example);}staticvoiddemo_audio_decoder_init(DemoAudioDecoder*self){}intmain(intargc,char*argv[]){GstAudioDecoder*decoder;gboolean default_value;gboolean disabled_value;gboolean enabled_value;gst_init(argc,argv);decoderGST_AUDIO_DECODER(g_object_new(demo_audio_decoder_get_type(),NULL));if(decoderNULL){g_printerr(Failed to create decoder\n);return1;}default_valuegst_audio_decoder_get_drainable(decoder);gst_audio_decoder_set_drainable(decoder,FALSE);disabled_valuegst_audio_decoder_get_drainable(decoder);gst_audio_decoder_set_drainable(decoder,TRUE);enabled_valuegst_audio_decoder_get_drainable(decoder);g_print(Default drainable: %s\n,default_value?TRUE:FALSE);g_print(After disable: %s\n,disabled_value?TRUE:FALSE);g_print(After enable: %s\n,enabled_value?TRUE:FALSE);gst_object_unref(decoder);return0;}编译运行gcc test_audio_decoder_drainable.c\-otest_audio_decoder_drainable\$(pkg-config--cflags--libsgstreamer-1.0 gstreamer-audio-1.0)./test_audio_decoder_drainable关键输出Default drainable: TRUE After disable: FALSE After enable: TRUE5.总结gst_audio_decoder_set_drainable()就是为GstAudioDecoder写入是否允许排空阶段接收NULL输入的状态它本身不触发Drain真正的缓存处理仍由基类排空流程和子类handle_frame()负责。
返回列表