Как я могу обеспечить правильную частоту кадров при записи анимации с использованием DirectShow? - PullRequest
3 голосов
/ 13 мая 2011

Я пытаюсь записать анимацию (компьютерную графику, а не видео) в файл WMV с помощью DirectShow.Настройка:

  • Источник Push, который использует растровое изображение в памяти, содержащее кадр анимации.Каждый раз, когда вызывается FillBuffer (), данные растрового изображения копируются в выборку, а в выборку ставятся временные метки с начальным временем (номер кадра * длина кадра) и длительностью (длина кадра).Частота кадров в фильтре равна 10 кадрам в секунду.

  • Фильтр модуля записи ASF.У меня есть файл пользовательского профиля, который устанавливает видео на 10 кадров в секунду.Это фильтр только для видео, поэтому нет звука.

Контакты подключаются, и когда график запускается, создается файл wmv.Но ...

Проблема в том, что DirectShow загружает данные из Push-источника со скоростью, превышающей 10 FPS.Таким образом, результирующий wmv, воспроизводимый и содержащий правильную анимацию (а также сообщающий о правильном FPS), воспроизводит анимацию несколько раз слишком медленно, потому что во время записи в видео было добавлено слишком много кадров.То есть 10-секундное видео со скоростью 10 кадров в секунду должно иметь только 100 кадров, но в него вставляется около 500 кадров, в результате чего продолжительность видео составляет 50 секунд.

Моя первая попытка найти решение состояла в том, чтобы простозамедлите вызов FillBuffer (), добавив sleep () на 1/10 секунды.И это действительно работает более или менее.Но это кажется хакерским, и я подвергаю сомнению, хорошо ли это будет работать при более высоких FPS.

Так что мне интересно, есть ли лучший способ сделать это.На самом деле, я предполагаю, что есть лучший способ, и я просто скучаю по нему.Или мне просто нужно придумать способ задержки FillBuffer () в Push-источнике и использовать лучший механизм синхронизации?

Буду признателен за любые предложения!

Ответы [ 2 ]

2 голосов
/ 13 мая 2011

Я делаю это с потоками.Основной поток добавляет растровые изображения в список, а поток записывающего устройства принимает растровые изображения из этого списка.

Основной поток

  • Анимируйте графику в момент времени T и визуализируйте растровое изображение
  • Добавить растровое изображение в список визуализации.Если список заполнен (скажем, более 8 кадров), подождите.Это значит, что вы не будете использовать слишком много памяти.
  • Advance T с дельта-временем, соответствующим желаемой частоте кадров

Поток рендеринга

  • Когда кадрзапрошенный, выберите и удалите растровое изображение из списка визуализацииЕсли список пуст, подождите.

Вам нужна многопотоковая структура, такая как TThreadList, для хранения растровых изображений.Немного сложно разобраться, но ваш нынешний подход гарантированно приведет к проблемам со временем.

1 голос
/ 13 мая 2011

Я делаю только то, что нужно для моего приложения для записи (www.videophill.com), чтобы протестировать все это.

Я использую Sleep() метод для задержки кадров, но принимаюбольшая забота, чтобы гарантировать, что метки времени кадров правильны.Кроме того, при Sleep() переходе от кадра к кадру, пожалуйста, попробуйте использовать «абсолютную» разницу во времени, потому что Sleep(100) будет спать около 100 мс, а не 100 мс.

Если это не будет работать для вас,Вы всегда можете перейти на IReferenceClock, но я думаю, что это излишне.

Итак:

DateTime start=DateTime.Now;
int frameCounter=0;
while (wePush)
{
    FillDataBuffer(...);
    frameCounter++;
    DateTime nextFrameTime=start.AddMilliseconds(frameCounter*100);
    int delay=(nextFrameTime-DateTime.Now).TotalMilliseconds;
    Sleep(delay);
}

РЕДАКТИРОВАТЬ:

Имейте в виду: IWMWritter не зависит от времени, так какПока вы кормите его ОБРАЗЦАМИ с правильной отметкой времени.

...