Запись пользовательского DirectShow Исходного фильтра нажатия RTSP/RTP - устанавливающие метку времени данные, прибывающие из живых источников

Я пишу пользовательский исходный фильтр нажатия DirectShow, который, как предполагается, получает данные RTP из видеосервера и продвигает их к рендереру. Я записал класс CVideoPushPin, который наследовался классу CSourceStream и CVideoReceiverThread, который является оберткой для потока, которые получают пакеты 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();
    

Проблемы состоят в том, что я не уверен, как я должен установить метки времени для каждого MediaSample в методе FillBuffer. Я попробовал несколько путей, но воспроизведение или остановки или это являются слишком медленными. В настоящее время метод 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 не может вытащить данные достаточно быстро), и результат увеличивает задержку при проигрывании видео. У кого-либо есть идея, как я должен сделать добавление метки времени при получении данных из живых источников?

5
задан mkurek 10 February 2010 в 20:34
поделиться

1 ответ

Средство визуализации отрисовывает кадры, когда время потока графика достигает отметки времени на образце объекта. Если я правильно прочитал ваш код, вы отметите им время потока по прибытии, поэтому они всегда будут опаздывать при рендеринге. Это несколько сбивает с толку средство рендеринга звука: если средство рендеринга аудио предоставляет часы графика, то оно будет сообщать текущее время потока как любой сэмпл, который он в данный момент воспроизводит, и это вызовет некоторое нежелательное поведение времени.

  1. Вы хотите установить время в будущем, чтобы учесть задержку через график и любую буферизацию в вашем фильтре. Попробуйте установить время на 300 мс в будущее (время потоковой передачи сейчас + 300 мс).

  2. Вы хотите, чтобы кадры были согласованными, поэтому не ставьте для них временные метки на основе времени прибытия каждого кадра. Используйте временную метку RTP для каждого кадра и установите базовый уровень для первого на 300 мс в будущем; последующие кадры тогда (rtp - rtp_at_baseline) + dshow baseline (с соответствующими преобразованиями единиц измерения.

  3. Вам необходимо указать время для аудио- и видеопотоков одинаково, используя одну и ту же базовую линию. Однако, насколько я помню, временные метки RTP имеют разную базовую линию в каждом потоке, поэтому вам нужно использовать пакеты RTCP для преобразования временных меток RTP в (абсолютное) время NTP, а затем преобразовать NTP в директшоу, используя исходную базовую линию (базовая линия NTP = dshow время трансляции сейчас + 300 мс).

G

6
ответ дан 14 December 2019 в 13:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: