Отрицательное время презентации в DirectShow

Это действительно заставляет меня рвать на себе волосы. Я написал фильтр преобразования DirectShow, производный от CTransformFilter. Я получил входной контакт от CTransformInputPin. Когда вызывается метод Receive моего входного вывода, он записывает время презентации IMediaSample в файл. Все это работает нормально, пока я не остановлю график и не запущу его снова (я использую MS graphedt). В большинстве случаев при повторном запуске проблем не возникает. Но примерно в одном из каждых дюжин или около того раз, когда я останавливаюсь, а затем снова запускаю график, начальное время презентации отрицательное. В конечном итоге оно увеличивается до нуля и поднимается выше нуля по мере выполнения графика, но никогда не догоняет время потока, в результате чего время потока остается значительно опережающим время начала представления для каждого образца.

Я наблюдал это с Logitech Webcam Pro 9000 и камерой Logitech C600, но не с камерой Winbook, поэтому мне интересно, является ли это проблемой Logitech. Кто-нибудь еще видел отрицательное время презентации на видео IMediaSamples после остановки и повторного запуска? (Я посмотрел на флаг preroll в IMediaSample: он всегда S_FALSE.)

ОБНОВЛЕНИЕ:

Я переопределил метод Run CTransformFilter (на самом деле, CBaseFilter) следующим образом:

STDMETHODIMP MyTransformFilter::Run(REFERENCE_TIME tStart)
{
    char buff[1000];
    REFERENCE_TIME rTime;

    m_pClock->GetTime(&rTime);
    sprintf(buff, "Run tstart = %lld, rTime = %lld", tStart, rTime);
    Trace(buff); // open my log file, add buff, close my log file
    return CTransformFilter::Run(tStart);
}

Я использовал graphedt, чтобы запустить график, запустить его на 10 секунд, сделать паузу на 5 секунд, а затем запустить снова. Вот результат:

Run tstart = 7855978550000, rTime = 7855978450000
Run tstart = 7856030610000, rTime = 7856126960000

Два времени, переданные для запуска, отличаются на 5,2 секунды (примерно на время, в течение которого я сделал паузу). Время двух эталонных часов отличается на 14,6 секунды (приблизительно общее время между вызовами Run). За исключением небольшого увеличения, которое диспетчер графов фильтров добавляет ко времени, переданному в Run (10 мс при первом вызове), я ожидаю, что они будут почти одинаковыми каждый раз, когда вызывается Run. Вместо этого время, переданное Run во втором вызове, примерно на 10 секунд отстает от эталонных часов. Я был бы чрезвычайно признателен за помощь в понимании того, почему время, переданное в Run при втором вызове, не совпадает (почти) со временем, возвращаемым эталонными часами при втором вызове.

ОБНОВЛЕНИЕ 2:

Проблема связана с драйвером Logitech версии 13.31.1044.0. См. ответ ниже.


person Stevens Miller    schedule 11.04.2012    source источник


Ответы (2)


Отрицательное время не имеет большого значения. По сути, это означает, что «образец СМИ должен был быть представлен некоторое время назад». Таким образом, вы можете подумать, что образец СМИ может быть отброшен? Иногда это так, иногда нет: представьте себе последовательность временно сжатых видеокадров с ключевым кадром, за которым следуют 10 дельта-кадров. Вы хотите, чтобы презентация начиналась с кадра № 5, как вы можете это сделать? Вы должны протолкнуться от ключевого кадра, чтобы декодер мог эффективно декодировать с точки соединения, иначе он не может начать с дельта-кадра. Декодер может доставить выходной кадр независимо от того, запаздывает он или нет, и именно так эти кадры в конечном итоге доходят до вас.

Другой сценарий, который приводит к отрицательному времени, вызван состоянием гонки потоков, потоковой передачи и управления. Поток захвата может начать свою работу, но не имеет базового «времени начала».

person Roman R.    schedule 11.04.2012
comment
Я бы понял это, если бы время потока на перезапущенном графике не было перезапущено с нуля. Каждый раз, когда я останавливаю и запускаю график, время потока снова начинается с нуля. Но примерно в одном из 12 случаев фильтр захвата (если это камера Logitech) запускается существенно (-15 000 000 или более единиц REFERENCE_TIME) раньше этого времени. По крайней мере, я ожидаю, что фильтр захвата будет согласовывать отношения между временем его представления и временем потока графа. - person Stevens Miller; 11.04.2012
comment
-15М это -1,5 секунды - довольно много но все равно попадает во второй абзац выше. - person Roman R.; 11.04.2012
comment
Могу ли я что-нибудь сделать, чтобы исправить это? Я пытаюсь сравнить время презентации со временем потока, чтобы решить, следует ли отбрасывать образец вместо его обработки в моем фильтре преобразования. Когда фильтр захвата начинается с отрицательного значения, с этого момента он остается так далеко за командой потока, не оставляя мне возможности (насколько я знаю) решить, настолько ли отстает образец от времени потока, что я должен удалить Это. - person Stevens Miller; 11.04.2012
comment
Время камеры отмечает это таким образом, что именно вы пытаетесь исправить? Это может быть не совсем то, что вы ожидаете, но это не сразу ошибка (при этом драйвер может делать что-то не лучшим образом). На бегущем графике вы всегда можете решить, опаздывает ли образец или нет, поскольку у вас есть его время, у вас есть часы, фильтр также получает базовое время для подсчета. Трех достаточно для принятия решений. - person Roman R.; 11.04.2012
comment
Да, это именно то, что я пытаюсь сделать: решить, опаздывает образец или нет. Для этого я получаю образец времени презентации, вызывая IMediaSample::GetTime, и получаю время потока, вызывая CBaseFilter::StreamTime (вы имеете в виду, что у вас есть часы?). MSDN, кажется, предполагает, что StreamTime возвращает значение, которое уже было смещено путем вычитания времени, переданного в Run при запуске графика. Это то, что вы называете базовым временем, или мне нужно получить его откуда-то еще? - person Stevens Miller; 11.04.2012
comment
Под часами я подразумеваю время и часы в DirectShow msdn.microsoft.com/en-us/library/windows/desktop/ - person Roman R.; 11.04.2012
comment
Спасибо еще раз. Я прочитал почти все в MSDN, что относится к этой теме. Все они, кажется, говорят, что я должен иметь возможность сравнивать время, которое я получаю от IMediaSample::GetTime, со временем, которое я получаю от CBaseFilter::StreamTime, так как они оба отсчитываются от нуля до времени начала, сохраняемого CBaseFilter. Для моей камеры WinBook это работает отлично. Для моих камер Logitech время презентации иногда перескакивает назад после вызова Stop, а затем Run. (Интересно, что вызов Pause, а затем Run перезапускает время презентации, но не время потока; этого также не происходит с WinBook.) - person Stevens Miller; 12.04.2012
comment
Run раз перезапуска. Run фильтра также получает аргумент, который соответствует базовому времени часов. Образец мультимедиа должен быть представлен во время часов графика, которое равно этому базовому времени плюс нулевое время представления. - person Roman R.; 12.04.2012

После долгих экспериментов я пришел к выводу, что проблема, скорее всего, связана с драйвером камеры Logitech 13.31.1044.0. С более ранним драйвером Logitech 12.10.1110, камерой Winbook DC-6120 (и ее драйвером) и камерой Chicony USB 2.0 (и ее драйвером) мне не удалось повторить проблему. Без видимой причины драйвер Logitech 13 будет доставлять образцы, начиная с отрицательного времени представления, примерно в одном из каждых дюжин или около того раз графика, включая его перезапуск (то есть после того, как я остановил его в graphedt, а затем снова запустил). ). Сравнение этого времени с временем потока не дает информации, описанной MSDN, относительно того, запланировано ли отображение образца в прошлом, настоящем или будущем, поскольку время потока, по-видимому, не затрагивается. При каждом перезапуске время потока снова начинается с нуля, как и следовало ожидать, независимо от того, в какое время начинается время презентации камеры. (Обратите внимание, что Logitech осуществляет потоковую передачу в подтипе RGB24 без сжатия кадров.)

Я работаю над многопоточным сквозным фильтром, который может переназначать время презентации со значениями, основанными на времени потока, и делать это достаточно быстро, чтобы «подделывать» правильные значения, и опубликую здесь, если я получу осмысленное результат. Кроме того, я буду документировать свои тесты и сообщать о них Logitech. Если они ответят, я тоже напишу это здесь.

Если кто-то еще работает с продуктами Logitech, которые используют вышеупомянутый драйвер (или иным образом наблюдают описанное мной поведение), пожалуйста, прокомментируйте здесь. Я был бы рад отправить вам копию моего фильтра, который регистрирует время, кадры и так далее. Мы могли бы работать вместе над поиском хорошего способа справиться с этим.

ОБНОВЛЕНИЕ

Написав простейший из возможных фильтров Transform (тот, который просто копирует негативное изображение входного IMediaSample в выходной файл), я смог достаточно последовательно воспроизвести это поведение. Примерно один из каждых пяти или шести раз я перезапускаю график, состоящий из Camera->Filter->Renderer, первые несколько образцов доставляются с отрицательным временем кадра, которое сильно отстает от времени потока и никогда не догоняет. (То есть время потока постоянно опережает время представления образцов). Опять же, этого никогда не происходит ни с другими камерами, ни со старым драйвером Logitech.

Вот интересная часть: если я добавлю некоторую задержку к методу Run фильтра (после переопределения CTransformFilter::Run), проблема исчезнет. Вот код:

STDMETHODIMP DLPassThrough::Run(REFERENCE_TIME tStart)
{
    Sleep(10);

    return CTransformFilter::Run(tStart);
}

Я могу сделать так, чтобы проблема появлялась и исчезала, комментируя или восстанавливая этот вызов "Sleep(10)". Все, что я могу предположить, это то, что код камеры является многопоточным и ему требуется некоторое время между вызовом «Пауза», который всегда предшествует вызову «Выполнить», и следующим вызовом «Выполнить», который он получает, чтобы очистить то, что он делает. Насколько я понимаю документы MSDN, диспетчер графов вызовет «Пауза» в средстве визуализации, затем в моем фильтре, затем в камере, прежде чем вернуться и вызвать «Выполнить» в средстве визуализации, моем фильтре, а затем в камере. Я считаю, что каждый из этих вызовов является синхронным, но если код камеры является многопоточным, он может по-прежнему работать с последним вызовом «Пауза» из диспетчера графов, когда вызывается его метод «Выполнить». Добавив задержку к методу «Выполнить» моего фильтра, можно увеличить задержку между самым последним вызовом камеры «Пауза» и следующим вызовом камеры «Выполнить».

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

ОБНОВЛЕНИЕ 2

Вот ответ Logitech:

Я хотел бы сообщить вам, что устройство было сделано в основном для работы с приложениями IM для потокового видео, а не как предмет для разработки программного обеспечения или фильтров.

person Stevens Miller    schedule 19.04.2012