Я пишу пользовательский исходный фильтр нажатия DirectShow, который, как предполагается, получает данные RTP из видеосервера и продвигает их к рендереру. Я записал класс CVideoPushPin, который наследовался классу CSourceStream и CVideoReceiverThread, который является оберткой для потока, которые получают пакеты 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 не может вытащить данные достаточно быстро), и результат увеличивает задержку при проигрывании видео. У кого-либо есть идея, как я должен сделать добавление метки времени при получении данных из живых источников?
Средство визуализации отрисовывает кадры, когда время потока графика достигает отметки времени на образце объекта. Если я правильно прочитал ваш код, вы отметите им время потока по прибытии, поэтому они всегда будут опаздывать при рендеринге. Это несколько сбивает с толку средство рендеринга звука: если средство рендеринга аудио предоставляет часы графика, то оно будет сообщать текущее время потока как любой сэмпл, который он в данный момент воспроизводит, и это вызовет некоторое нежелательное поведение времени.
Вы хотите установить время в будущем, чтобы учесть задержку через график и любую буферизацию в вашем фильтре. Попробуйте установить время на 300 мс в будущее (время потоковой передачи сейчас + 300 мс).
Вы хотите, чтобы кадры были согласованными, поэтому не ставьте для них временные метки на основе времени прибытия каждого кадра. Используйте временную метку RTP для каждого кадра и установите базовый уровень для первого на 300 мс в будущем; последующие кадры тогда (rtp - rtp_at_baseline) + dshow baseline (с соответствующими преобразованиями единиц измерения.
Вам необходимо указать время для аудио- и видеопотоков одинаково, используя одну и ту же базовую линию. Однако, насколько я помню, временные метки RTP имеют разную базовую линию в каждом потоке, поэтому вам нужно использовать пакеты RTCP для преобразования временных меток RTP в (абсолютное) время NTP, а затем преобразовать NTP в директшоу, используя исходную базовую линию (базовая линия NTP = dshow время трансляции сейчас + 300 мс).
G