ISampleGrabberFilter шаг за шагом
У меня есть конечная точка графа, SampleGrabber, где я получаю несжатые данные всех кадров, используя функцию обратного вызова.
В моем коде интерфейса верхнего уровня я хочу иметь функцию ReadNextFrame(), которая получает данные следующего кадра на графике (пока он не достигнет конца файла).
Плохая реализация с точки зрения производительности - это передача nextFrameIndex классу grabberCB, указывающий, какой кадр мне нужен в данный момент. Так что моя функция обратного вызова пропустит все остальные кадры и выберет только тот, который я хочу. Это дорого, так как график должен пройти весь файл для выбора данных одного кадра.
Я заметил, что есть интерфейс IVideoFrameStep, который идеально подходит для меня. Но похоже, что этот интерфейс не совместим с Sample Grabber, и его документация гласит:
Декодеры, которые реализуют поиск с точностью до кадра в Microsoft DirectShow, должны реализовать набор свойств AM_KSPROPSETID_FrameStep, который используется в сочетании с интерфейсом IVideoFrameStep.
Я попытался подключить его к моему графику, но функция IVideoFrameStep::CanStep() вернула мне значение false, что означает, что я не могу использовать его с Sample Grabber.
Итак, мой вопрос: есть ли простое и эффективное с точки зрения производительности решение, чтобы я мог иметь свой график, чтобы сохранить текущее состояние, а затем сделать один кадр вперед и получить данные с помощью Sample Grabber?
1 ответ
Вы обнаружили, что IVideoFrameStep
имеет определенные требования к работе, и идея заключается в том, что весь график фильтра выполняет переходы состояний, запускает и приостанавливает воспроизведение только одного кадра.
Чтобы получить все кадры по одному с помощью Sample Grabber, вы можете реализовать более простой подход, который не предъявляет особых требований.
- Ваш график фильтра работает; имело бы смысл убрать часы с графика - смотрите
IMediaFilter::SetSyncSource(NULL)
- Иметь образец Grabber на интересующей позиции с
SampleCB
Перезвоните - Как только у вас есть
SampleCB
выполнить, выполнить свою работу с данными и указать доступность фрейма для кода более высокого уровня, который запускает график - Пока внутри
SampleCB
и #3 выше сделано, не возвращайтесь из метода и вместо этого ожидайте события, которое указывает на то, что вы готовы продолжить - Код приложения высокого уровня обработает фрейм и установит событие с #4 выше, позволяя
SampleCB
выйти и продолжить работу по получению нового кадра; с новым кадром вы повторяете с #3 выше.
То есть твой SampleCB
wait блокирует весь конвейер, сохраняя его состояние в течение необходимого времени, позволяя вам обрабатывать кадр за кадром в удобном темпе.
Псевдокод для SampleCB
будет (с событиями ручной установки / сброса):
data m_Data;
event m_DataAvailability;
event m_NextFrameRequest;
void SampleCB(Frame)
{
m_Data = Frame.GetData();
m_DataAvailability.Set();
m_NextFrameRequest.WaitFor(); // Sleeping here until signaled to continue
m_NextFrameRequest.Reset();
}
data ReadNextFrame()
{
m_DataAvailability.WaitFor();
data Data = m_Data;
m_DataAvailability.Reset(); // Current data processed, we need next portion
m_NextFrameRequest.Set(); // Indicate that we allow next callback call
return Data; // Make captured frame available
}