Увеличение fps (directshow)
От: Dru-7 Беларусь  
Дата: 19.01.12 18:43
Оценка:
Здравствуйте,

Стоит задача по увеличению fps видеопотока. Сам алгоритм проверен на битмапах в консольном приложении. Теперь его необходимо встроить в фильтр. Как я понял нужно реализовывать Transform фильтр. По документации Tansform получает на вход один фрейм, работает над ним и выдает на выход один фрейм. Я предполагаю что фильтр получит frame c timestamp = 200-400, сгенерирует frame и отдаст на выход сгенеренный фрейм c timestamp = 200-300 и полученный фрейм c timestamp = 300-400. Не понятен механизм выдачи фильтром на выходной пин нескольких фреймов. В документации (DXSDK, msdn) я не нашел как это нужно реализовывать. Или я не по тому пути пошел?
Re: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 20.01.12 08:38
Оценка:
Верным путем идете, товарищи! (с)

Просто посмотрите код CTransformFilter::Receive() в проекте BaseClasses.
Когда приходит входной сэмпл, фильтр создает новый сэмпл с помощью InitializeOutputSample(), где буфер запрашивается у аллокатора выходного пина, потом новый сэмпл заполняется данными в Transform() и передается вниз (следующему фильтру). Вам нужно у себя переопределить Receive() и на каждый пришедший сэмпл создавать и посылать вниз два.
Re[2]: Увеличение fps (directshow)
От: Dru-7 Беларусь  
Дата: 20.01.12 10:57
Оценка:
Спасибо за подсказку, а то у меня уже начали рождаться извращенные идеи как это обойти.
Re[2]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 30.01.12 19:39
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Верным путем идете, товарищи! (с)


DM>Просто посмотрите код CTransformFilter::Receive() в проекте BaseClasses.

DM>Когда приходит входной сэмпл, фильтр создает новый сэмпл с помощью InitializeOutputSample(), где буфер запрашивается у аллокатора выходного пина, потом новый сэмпл заполняется данными в Transform() и передается вниз (следующему фильтру). Вам нужно у себя переопределить Receive() и на каждый пришедший сэмпл создавать и посылать вниз два.

Все получилось. Теперь встала следующая проблема. Для работы фильтра (метода Transform) нужен вспомогательный массивчик, я переопределил методы Pause() и Stop():

STDMETHODIMP MyTrans::Pause()
{
CAutoLock lock_it(m_pLock);

// Инициализируем переменные если стартуем фильтр
if (m_State == State_Stopped)
{
bufExt = (unsigned __int8*)new unsigned __int8[10000];

#ifdef DEBUG
QueryPerformanceFrequency(&Freq);
#endif //(DEBUG)
}

return CTransformFilter::Pause();
}//Pause

STDMETHODIMP MyTrans::Stop()
{
CAutoLock lock_it(m_pLock);

HRESULT hr = CTransformFilter::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

expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

по call стеку это происходит на строке: delete [] bufExt;

В чем я не прав?
Re[3]: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.12 04:01
Оценка:
Здравствуйте, Dru-BY7, Вы писали:

DB> Теперь встала следующая проблема. Для работы фильтра (метода Transform) нужен вспомогательный массивчик, я переопределил методы Pause() и Stop()...


Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.
Re[4]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 31.01.12 15:35
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.


Подскажите еще, плиз. Для выделения/освобождение памяти вы используете new/delete или лучше использовать что-то другое?
Re[5]: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.12 16:44
Оценка:
Под сэмплы память выделяет аллокатор при нужном пине, а под частные данные да, использую обычные new/delete.
Re[4]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 01.02.12 17:24
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Для выделения и освобождения данных лучше переопределить методы StartStreaming и StopStreaming. Я обычно так делаю, и все работает правильно.


Я переопределил эти методы но ошибка все равно вылазит. В принципе я не увидел разницу, т.к в переопределенном Stop я вначале вызывал Stop базового класса (который вызывал StopStreaming()), а потом освобождал данные. Я лочил критическую секцию m_csReceive в StopStreaming().
Re[5]: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 02.02.12 02:57
Оценка:
Здравствуйте, Dru-BY7, Вы писали:

DB>Я переопределил эти методы но ошибка все равно вылазит.


Значит надо ее искать, нет ли проездов по памяти, лишних освобождений и т.д., тут уже удаленно не угадаешь.
Re[6]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 06.02.12 16:50
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Значит надо ее искать, нет ли проездов по памяти, лишних освобождений и т.д., тут уже удаленно не угадаешь.


Нашел, я вылазил в некоторых случаях за границу буфера. Спасибо за помощь.
Re[2]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 06.02.12 18:19
Оценка:
Здравствуйте, 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(), но на рендерер они не влияют. Как заставить писать в файл все фреймы?
Re[3]: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 07.02.12 06:34
Оценка:
Скорее всего дело в таймстемпах. Рендерер наверняка смотрит лишь на время начала сэмпла, а 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 для каждого фрейма?
Re[4]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 07.02.12 07:51
Оценка:
Сорри, Аноним это я, забыл авторизоваться
Re[5]: Увеличение fps (directshow)
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 07.02.12 09:37
Оценка:
> Сейчас работает так: в 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 можно поставить.
Re[6]: Увеличение fps (directshow)
От: Dru-BY7 Беларусь  
Дата: 07.02.12 16:40
Оценка:
Разобрался, ему нужно было корректно выставить SetMediaTime().
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.