Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.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
Filter 编写自定义DirectShow RTSP/RTP源推送筛选器-来自实时源的时间戳数据_Filter_Directshow_Rtp_Rtsp - Fatal编程技术网

Filter 编写自定义DirectShow RTSP/RTP源推送筛选器-来自实时源的时间戳数据

Filter 编写自定义DirectShow RTSP/RTP源推送筛选器-来自实时源的时间戳数据,filter,directshow,rtp,rtsp,Filter,Directshow,Rtp,Rtsp,我正在编写定制的DirectShow源推送过滤器,它应该从视频服务器接收RTP数据并将它们推送到渲染器。我编写了一个CVideoPushPin类,它继承了CSourceStream和CVideoReceiveThread类,后者是从视频服务器接收RTP数据包的线程的包装器。接收器线程基本上做三件事: 接收原始RTP数据包并收集接收器报告所需的一些数据 组装帧,将其复制到缓冲区,并将有关帧的信息存储到256 元素队列,定义如下: struct queue_elem { char *star

我正在编写定制的DirectShow源推送过滤器,它应该从视频服务器接收RTP数据并将它们推送到渲染器。我编写了一个CVideoPushPin类,它继承了CSourceStream和CVideoReceiveThread类,后者是从视频服务器接收RTP数据包的线程的包装器。接收器线程基本上做三件事:

  • 接收原始RTP数据包并收集接收器报告所需的一些数据
  • 组装帧,将其复制到缓冲区,并将有关帧的信息存储到256 元素队列,定义如下:

    struct queue_elem {
       char *start; // Pointer to a frame in a buffer
       int length; // Lenght of data
       REFERENCE_TIME recvTime; // Timestamp when the frame was received (stream time)
    };
    
    struct data {
       struct queue_elem queue[QUEUE_LENGTH];
       int qWrIdx;
       int qRdIdx;
    HANDLE mutex;
    };
    
  • 每个接收到的帧都带有当前流时间的时间戳

    p->StreamTime(refTime);
    REFERENCE_TIME rt = refTime.GetUnits();
    
问题在于,我不确定如何为FillBuffer方法中的每个MediaSample设置时间戳。我尝试了几种方法,但播放要么停止,要么太慢。 当前FillBuffer方法如下所示:

   REFERENCE_TIME thisFrameStartTime, thisFrameEndTime;
// Make sure if there are at least 4 frames in the buffer
    if(noOfFrames >= 4)
    {   
        currentQe = m_myData.queue[m_myData.qRdIdx++]; //Take current frame description     
        if(m_myData.qRdIdx >= QUEUE_LENGTH)
        {
            m_myData.qRdIdx = 0;
        }           
        nextQe = m_myData.queue[m_myData.qRdIdx]; //Take next frame description
        if(currentQe.length > 0)
        {
            memcpy(pData, currentQe.start, currentQe.length);               

             pSample->SetActualDataLength(currentQe.length);                
            CRefTime refTime;
            m_pFilter->StreamTime(refTime);
            REFERENCE_TIME rt;
            rt = refTime.GetUnits();
            pSample->GetTime(&thisFrameStartTime, &thisFrameEndTime);
            thisFrameEndTime = thisFrameStartTime + (nextQe.recvTime - currentQe.recvTime);
            pSample->SetTime(&thisFrameStartTime, &thisFrameEndTime);   
        }
    }
    else 
    {
        pSample->SetActualDataLength(0);
    }

在本例中,我注意到队列中的项目数量增长非常快(由于某些原因,FillBuffer方法无法足够快地提取数据),结果是播放视频时增加了延迟。有人知道当从实时源接收数据时应该如何进行时间戳吗?

当图形的流时间达到样本对象上的时间戳时,渲染器将绘制帧。如果我正确阅读了您的代码,您将使用到达时的流时间为它们添加时间戳,因此它们在渲染时总是会迟到。这在某种程度上被音频渲染器弄糊涂了:如果音频渲染器提供图形的时钟,那么它将报告当前流时间为它当前正在播放的任何样本,这将导致一些不希望的时间行为

  • 您希望在将来设置一个时间,以允许通过图形的延迟和过滤器中的任何缓冲。尝试将时间设置为300毫秒(现在的流时间+300毫秒)

  • 您希望帧之间保持一致,因此不要基于每个帧的到达时间为帧添加时间戳。对每一帧使用RTP时间戳,并将第一帧的基线设置为未来的300ms;随后的帧是(rtp-rtp_at_基线)+dshow基线(具有适当的单位转换)

  • 您需要使用相同的基线以相同的方式为音频和视频流添加时间戳。但是,如果我记得,RTP时间戳在每个流中都有不同的基线,因此您需要使用RTCP数据包将RTP时间戳转换为(绝对)NTP时间,然后使用初始基线将NTP转换为directshow(基准NTP=现在显示的数据流时间+300ms)


  • G

    Geraint,感谢您的输入。我对代码做了一些更改,但是,视频在运行后立即冻结。在日志文件中,我注意到FillBuffer方法只调用了两次。第一次调用时,流时间为3633950000,frameStartTime为3635700000,frameEndTime为3635703600。第二次调用时,stream时间是3634370000,frameStartTime是3635703600,frameEndTime是3635707200。因此,如果我理解正确,渲染器应该等待流时间到达第一帧的时间戳,然后平稳运行,但不幸的是,它没有发生。