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, вы можете реализовать более простой подход, который не предъявляет особых требований.

  1. Ваш график фильтра работает; имело бы смысл убрать часы с графика - смотрите IMediaFilter::SetSyncSource(NULL)
  2. Иметь образец Grabber на интересующей позиции с SampleCB Перезвоните
  3. Как только у вас есть SampleCB выполнить, выполнить свою работу с данными и указать доступность фрейма для кода более высокого уровня, который запускает график
  4. Пока внутри SampleCB и #3 выше сделано, не возвращайтесь из метода и вместо этого ожидайте события, которое указывает на то, что вы готовы продолжить
  5. Код приложения высокого уровня обработает фрейм и установит событие с #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
}
Другие вопросы по тегам