Стоит задача по увеличению fps видеопотока. Сам алгоритм проверен на битмапах в консольном приложении. Теперь его необходимо встроить в фильтр. Как я понял нужно реализовывать Transform фильтр. По документации Tansform получает на вход один фрейм, работает над ним и выдает на выход один фрейм. Я предполагаю что фильтр получит frame c timestamp = 200-400, сгенерирует frame и отдаст на выход сгенеренный фрейм c timestamp = 200-300 и полученный фрейм c timestamp = 300-400. Не понятен механизм выдачи фильтром на выходной пин нескольких фреймов. В документации (DXSDK, msdn) я не нашел как это нужно реализовывать. Или я не по тому пути пошел?
Просто посмотрите код CTransformFilter::Receive() в проекте BaseClasses.
Когда приходит входной сэмпл, фильтр создает новый сэмпл с помощью InitializeOutputSample(), где буфер запрашивается у аллокатора выходного пина, потом новый сэмпл заполняется данными в Transform() и передается вниз (следующему фильтру). Вам нужно у себя переопределить Receive() и на каждый пришедший сэмпл создавать и посылать вниз два.
Здравствуйте, D. Mon, Вы писали:
DM>Верным путем идете, товарищи! (с)
DM>Просто посмотрите код CTransformFilter::Receive() в проекте BaseClasses. DM>Когда приходит входной сэмпл, фильтр создает новый сэмпл с помощью InitializeOutputSample(), где буфер запрашивается у аллокатора выходного пина, потом новый сэмпл заполняется данными в Transform() и передается вниз (следующему фильтру). Вам нужно у себя переопределить Receive() и на каждый пришедший сэмпл создавать и посылать вниз два.
Все получилось. Теперь встала следующая проблема. Для работы фильтра (метода Transform) нужен вспомогательный массивчик, я переопределил методы Pause() и Stop():
// освободим память за собой
delete [] bufExt;
bufExt = NULL;
m_iFrameNumber = 0;
return hr;
}//Stop
Собираю граф (Source->MyTrans->ColorSpaceConverter->VideoRenderer) и открываю его в graphedit. Он запускается, останавливается, можно закрыть graphedit во время работы и все вроде нормально. Но если запустить граф и минут через >5 закрыть graphedit (не останавливая граф) то получу:
Debug assertion failed!
file: dbgdel.cpp
line: 52
Здравствуйте, Dru-BY7, Вы писали:
DB> Теперь встала следующая проблема. Для работы фильтра (метода Transform) нужен вспомогательный массивчик, я переопределил методы Pause() и Stop()...
Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.
Здравствуйте, D. Mon, Вы писали:
DM>Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.
Подскажите еще, плиз. Для выделения/освобождение памяти вы используете new/delete или лучше использовать что-то другое?
Здравствуйте, D. Mon, Вы писали:
DM>Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.
Я переопределил эти методы но ошибка все равно вылазит. В принципе я не увидел разницу, т.к в переопределенном Stop я вначале вызывал Stop базового класса (который вызывал StopStreaming()), а потом освобождал данные. Я лочил критическую секцию m_csReceive в StopStreaming().
Здравствуйте, D. Mon, Вы писали:
DM>Верным путем идете, товарищи! (с)
DM>Просто посмотрите код CTransformFilter::Receive() в проекте BaseClasses. DM>Когда приходит входной сэмпл, фильтр создает новый сэмпл с помощью InitializeOutputSample(), где буфер запрашивается у аллокатора выходного пина, потом новый сэмпл заполняется данными в Transform() и передается вниз (следующему фильтру). Вам нужно у себя переопределить Receive() и на каждый пришедший сэмпл создавать и посылать вниз два.
Все так и сделал. Рендерер в статистике показывает что скорость выросла. Я закрасил треть созданного фрейма черным чтобы убедиться что фреймы чередуются на рендерере. Чтобы визуально оценить результат работы фильтра я решил добавить сохранение в файл. После фильтра вставил InfTee на него по одной ветке color space converter + renderer, по второй avi mux + file writer. Но в файл почему-то пишутся тока сгенерированные фреймы. В сводке файла указана его длинна 20 сек, а длина видео потока тока 10 сек. Добавил в фильтр изменение параметров AvgTimePerFrame и dwBitRate при вызове GetMediaType(), но на рендерер они не влияют. Как заставить писать в файл все фреймы?
Скорее всего дело в таймстемпах. Рендерер наверняка смотрит лишь на время начала сэмпла, а AVI Mux'у нужно, чтобы start time каждого сэмпла соответствовал end time предыдущего. Если между ними будут дырки, он будет вставлять пустые кадры. А если времена будут перекрываться, то он может кадры терять.
Re[4]: Увеличение fps (directshow)
От:
Аноним
Дата:
07.02.12 07:47
Оценка:
Здравствуйте, D. Mon, Вы писали:
DM>Скорее всего дело в таймстемпах. Рендерер наверняка смотрит лишь на время начала сэмпла, а AVI Mux'у нужно, чтобы start time каждого сэмпла соответствовал end time предыдущего. Если между ними будут дырки, он будет вставлять пустые кадры. А если времена будут перекрываться, то он может кадры терять.
Тогда бы запись и без моего фильтра сбоила. Я еще не видел start time каждого сэмпла соответствовал end time предыдущего (испробовано на различных web камерах Logitech). Сейчас работает так: в Receive() приходит фрейм длительностью 2.000.000 (скорость 5fps), tS = 4.096.245, tE = 6.096.245. Я генерю фрейм и ставлю tS = 4.096.245, tE = 5.096.245 и отправляю его, потом выставляю tS = 5.096.245, tE = 6.096.245 для оригинального и отправляю его. Оствльные поля копируются с оригинального фрейма. Может для AVI Mux необходимо устанавливать корректно и SetMediaTime(), а также править поля AvgTimePerFrame и dwBitRate для каждого фрейма?
> Сейчас работает так: в Receive() приходит фрейм длительностью 2.000.000 (скорость 5fps), tS = 4.096.245, tE = 6.096.245. Я генерю фрейм и ставлю tS = 4.096.245, tE = 5.096.245 и отправляю его, потом выставляю tS = 5.096.245, tE = 6.096.245 для оригинального и отправляю его.
Да, так и надо.
> Оствльные поля копируются с оригинального фрейма. Может для AVI Mux необходимо устанавливать корректно и SetMediaTime(), а также править поля AvgTimePerFrame и dwBitRate для каждого фрейма?
Битрейт ему пофиг, по идее, а AvgTimePerFrame можно поставить.