Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 长时间保存在图形中的介质样本(累积效应)_C#_C++ Cli_Directshow - Fatal编程技术网

C# 长时间保存在图形中的介质样本(累积效应)

C# 长时间保存在图形中的介质样本(累积效应),c#,c++-cli,directshow,C#,C++ Cli,Directshow,几个月前,我在DirectShow图形上写了一篇关于缓冲区不足的文章 饥饿问题通过实现一个自定义分配器来解决,该分配器在饥饿时会扩展大小。然而,这仅仅缓解了真正的问题如果有足够的时间,图表中保存的样本数量会过多,并且不断扩展的池会造成内存不足的情况。 以下是我收集到的一些事实: 该图基本上是将MPEG2-TS流转码为MP4文件,以及提取音频和视频数据以进行实时DSP处理 该流以UDP多播流的形式出现。这条溪流有14个不同的SD节目 我正在使用从DsNetwork示例派生的自定义筛选器读取UDP流

几个月前,我在DirectShow图形上写了一篇关于缓冲区不足的文章

饥饿问题通过实现一个自定义分配器来解决,该分配器在饥饿时会扩展大小。然而,这仅仅缓解了真正的问题如果有足够的时间,图表中保存的样本数量会过多,并且不断扩展的池会造成内存不足的情况。

以下是我收集到的一些事实:

  • 该图基本上是将MPEG2-TS流转码为MP4文件,以及提取音频和视频数据以进行实时DSP处理

  • 该流以UDP多播流的形式出现。这条溪流有14个不同的SD节目

  • 我正在使用从DsNetwork示例派生的自定义筛选器读取UDP流。按照上述示例,围绕UDP接收数据块(8KiB块)创建媒体样本(无时间戳),并将其传递给Microsoft的MPEG2解复用器过滤器,该过滤器配置为过滤感兴趣的程序(我应该给样本加时间戳吗?

  • 需要可扩展分配器的过滤器是MPEG2解复用器,尤其是由输出视频引脚交付的样本需要它。输出音频引脚与默认分配器配合良好,音频解码器或解复用器不会保留任何样本

  • 视频样本由LAV视频解码器解码。将LAV过滤器替换为ffdshow过滤器没有任何积极影响-累积仍然存在。我在LAV或ffdshow(包括示例队列设置)中都没有找到可以缓解累积问题的设置

  • 问题完全与接收流的质量有关。流上检测到的不连续性越多(由MPEG解复用器输出样本标记),累积的样本就越多。顺便说一句,并行运行的VLC播放器使用相同的流记录相同的不连续性,因此它们似乎不是由我这方面的错误网络代码引起的

  • 延迟的样本不会丢失,它们最终由图形处理。我编写了一些看门狗逻辑来检测丢失样本的可能性,每个样本最终都被正确释放并返回到池中

  • 延迟与CPU不足无关。如果我停止向解复用器发送样本,则解复用器将停止向输出引脚发送样本我需要将新样本推入解复用器,以便正确释放滞留样本并将其返回池。

  • 我尝试从捕获图和muxer图(通过GDCL桥接过滤器桥接)中删除时钟。这并不能解决问题,实际上会阻塞数据流

  • 我不知道样本是由解复用器还是视频解码器保存的。事实上,我完全不知道如何调试并希望修复这种情况,任何指点或建议都是非常受欢迎的。

    附录:

    我还有一些补充资料:

  • 转码视频相对于音频滞后
  • 延迟时间与延迟样本的数量成正比
  • 因此,我认为在图形处理的某个时刻,解码的音频和视频样本时间戳不同步,图形的muxer端点可能正在阻塞视频解码线程,等待相应的音频到达

    关于如何检测有问题的筛选器,或者如何“重新设置”同步的提示?

    附录2:

    正如你在Roman回答的评论中所看到的,我实际上发现了一个错误,它在流中导致了错误的不连续性。通过修复这个bug,我减少了问题的发生率,但我没有修复根本原因

    原来问题的根源是Monogram AAC编码器过滤器(至少是我设法得到的版本,因为该项目似乎不再受支持)

    编码器通过将接收的样本量乘以输入的采样频率,以增量方式计算输出时间戳过滤器假设数据流始终是连续的,甚至不检查传入样本的不连续性。一旦我发现问题,修复它就很容易了,但这确实是我作为开发人员一生中调试的最难的问题,因为所有问题都指向MPEG2解复用器(时间戳在编码的输出音频和视频引脚之间漂移,正是这个过滤器首先耗尽了汇集的样本)然而,这是由于视频输出引脚的工作线程在图形末尾被MPEG4多路复用器阻塞而间接造成的,该多路复用器接收音频和视频之间的不同步采样,并限制视频输入以保持同步


    过滤器确实是“黑匣子”的幻觉需要小心,因为线程沿着图流动,下游过滤器上的问题可能会在上游过滤器中显示为错误问题。

    首先,所描述的行为听起来像一个bug。也就是说,意外行为会造成不必要的影响。但是,我同意尝试解决问题的做法是要求对罪犯进行鉴定,并对登记的问题进行详细调查

    由于视频在与延迟样本相关的数量上相对滞后于音频,并且没有其他副作用(例如,像丢失的帧),我同意挑战在于找到谁准确地持有媒体样本

    我可以提出两种方法
    void MulticastMediaSample::Initialize(MulticastSourceFilter* pFilter, MulticastSourceFilter::UDPBuffer* pBuffer) {
       _props.pbBuffer = pBuffer->Data;
       _props.lActual = pBuffer->payloadSizeInBytes;
       _pBuffer = pBuffer;
    
       // Network packet should be a multiple of a TS packet length (188 bytes)
       int tsPacketCount = pBuffer->payloadSizeInBytes / 188;
       if( pBuffer->payloadSizeInBytes % 188 != 0 ) {
          printf("Invalid TCP packet, length is not multiple of 188\r\n");
          exit(-8828);
       }
       BYTE* pPacket = pBuffer->Data;
       UINT header;
       for( int i = 0; i < tsPacketCount; i++ ) {
          if( pPacket[0] != 0x47 ) {
             printf("Lost Sync!\r\n");
             exit(-12423);
          }
          UINT pId = (pPacket[1] & 0x1f) << 8 | pPacket[2];
          if( pId != 0x1fff ) {  // ignore "filler" packets
             UINT afc = (pPacket[3] & 0x30) >> 4;
             BYTE cc = pPacket[3] & 0xf;
             auto it = pFilter->_ccMap.lower_bound(pId);
             if( it != pFilter->_ccMap.end() && !(pFilter->_ccMap.key_comp()(pId, it->first)) ) {
                // PID key exists in map, check continuity
                if( afc != 2 ) {  // don't check for packets carrying no payload
                   BYTE expected = (it->second + 1) & 0xf;
                   if( cc != expected ) {
                      printf("Continuity check error for pId %d: expected %d, got %d\r\n", pId, expected, cc);
                      SetDiscontinuity(TRUE);
                   }
                }
                // update key
                it->second = cc;
             } else {
                // key does not exist, insert first time 
                pFilter->_ccMap.insert(it, std::map<UINT16, BYTE>::value_type(pId, cc));
             }
          }
          pPacket += 188;
       }
    #ifdef DEBUG
       ASSERT(pBuffer->payloadSizeInBytes <= sizeof pBuffer->DataCopy);
       memcpy(pBuffer->DataCopy, pBuffer->Data, pBuffer->payloadSizeInBytes);
    #endif
       _pBuffer->AddRef();
       ASSERT(_refCnt == 1);
    }