Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронная запись видеофайлов 
:(
    Опции темы
bra1ss
Дата 11.1.2011, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



Имеются две камеры. Нужно выводить изображение на экран с одной из них, и одновременно с этим по нажатию кнопки писать видео с обеих камер в два файла.

Код

Camera cam1, cam2; // класс Camera - часть SDK, поставляемого вместе с камерами
Image rawImg1, rawImg2, processedImg1, processedImg2; // класс Image - тоже из SDK
bool thread2; // активен ли поток для записи со 2 камеры
PGRavi avi1, avi2; // PGRavi - класс для файла avi, за добавление кадра к файлу отвечает функция appendFrame (через AVIStreamWrite)

// основной поток программы

while (preview)
{
    // получение синхронных кадров из буфера камеры
    cam1.RetrieveBuffer(&rawImg1);        
    if (!capture)
        cam2.RetrieveBuffer(&rawImg2);
        
    // если запись и поток 2 не активен, то запуск потока на запись со 2 камеры
    if ((capture) && (!thread2))
    {
        thread2 = true;
        AfxBeginThread(ThreadGrabImage2, this);
    }

    // преобразование кадра из RAW8 в RGB
    rawImg1.Convert(PIXEL_FORMAT_BGRU, &processedImg1); 
                        
    // запись в файл кадра с 1 камеры
    if (capture)
        avi1.appendFrame(processedImg1.GetData());
                            
    // отрисовать кадр на экране
    RedrawAllViews(); 
}

// поток на запись файла для 2 камеры ((ThreadGrabImage2) 

while (capture)
    {
        
        cam2.RetrieveBuffer(&rawImg2);
        
        // конверт + запись кадра в файл
        rawImg2.Convert(PIXEL_FORMAT_BGRU, &processedImg2);
        avi2.appendFrame(processedImg2.GetData());
    } 
    

Но потоки работают неодинаково по времени, и, соответственно, в записанных видеофайлах получается разное число кадров, а синхронность крайне важна. В одном потоке весь код реализовать не получится, т.к. превью будет тормозить, нужно распараллеливать. Можно ли как-то синхронизовать потоки без потери быстродействия? Или вообще лучше делать совершенно по-другому?
PM MAIL   Вверх
borisbn
Дата 11.1.2011, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 2
Всего: 135



Если нужна абсолютная синхронность, то я бы делал регистрацию в файлы в одном потоке, а в дополнительном потоке занимался бы отрисовкой с той частотой кадров, которая получается.

Псевдокод:
Код

Поток 1:
while ( 1 )
{
    cam1.receive( data1 );
    cam2.receive( data2 );
    if ( recordingNow )
    {
        writeToFile( 1, data1 );
        writeToFile( 2, data2 );
    }
    sendToDrawBuffer( data1 );
}

Поток 2:
while ( 1 )
{
    waitForDataToDraw();
    drawOneFrame();
    clearDrawBuffer();
}



Это сообщение отредактировал(а) borisbn - 11.1.2011, 17:24


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
bra1ss
Дата 11.1.2011, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



Цитата(borisbn @ 11.1.2011,  17:15)
я бы делал регистрацию в файлы в одном потоке, а в дополнительном потоке занимался бы отрисовкой с той частотой кадров, которая получается

При таком раскладе частота кадров отрисовки недостаточна. Нужно как-то аккуратно развести процесс записи в два файла по потокам без существенной потери частоты отрисовки.
PM MAIL   Вверх
borisbn
Дата 12.1.2011, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 2
Всего: 135



Ну, тогда так:

Псевдокод:
Код

Поток 1:
while ( 1 )
{
    cam1.receive( data1 );
    cam2.receive( data2 );
    if ( recordingNow )
    {
        sendToWrite( 1, data1 );
        sendToWrite( 2, data2 );
    }
    drawOneFrame();
}

Поток 2, 3:
while ( 1 )
{
    waitForDataToWrite();
    data = writeBuff.front();
    writeToFile( data );
    writeBuff.pop_front();
}


Но что-то не верится, что в первом варианте не хватит производительности. У тебя КПК что ли ? Или ЦП уже и так загружен на 100% ? Какая нужна частота кадров ? У меня была схожая задача на камерах AXIS. Отрисовывалось так, что глазу было приятно и писалось с 8-ми камер, при этом загрузка ЦП была 20-30%.

Цитата(bra1ss @  11.1.2011,  21:45 Найти цитируемый пост)
При таком раскладе частота кадров отрисовки недостаточна

Прикинул или проверил ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
bra1ss
Дата 12.1.2011, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



ЦП загружен несильно, около 30%. Частота кадров - 25 кадров/с. Но один цикл потока выполняется слишком долго, соответственно частота обработанных и показанных кадров от того снижается. Используя только одну камеру запись в файл + показ видео работает адекватно, но стоит добавить в этот же поток обработку кадра со второй камеры, время работы цикла увеличивается, и частота кадров снижается.

Сейчас попробую по второму алгоритму, спасибо.




PM MAIL   Вверх
bra1ss
Дата 14.1.2011, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



Циклы в потоках 2, 3 вновь выполняются разное количество времени, в результате в один файл записывается больше кадров, чем во второй.

Немного видоизменил алгоритм, теперь частота кадров в норме, потерь кадров нет, всё синхронно, но производительность поднялась до 50%. С учетом того, что программа в дальнейшем будет работать в системе с гораздо менее производительным процессором, немного настораживает.

Код

Поток 1:
while ( 1 )
{
    cam1.receive( data1 );
    cam2.receive( data2 );
    if ( recordingNow )
    {
        beginThread2();
    }
    writeToFile( data1 );
    drawOneFrame();
    if ( recordingNow )
    {
        waitForEndThread2();
    }
}

Поток 2:
{
    writeToFile( data2 );
}


Это сообщение отредактировал(а) bra1ss - 14.1.2011, 11:47
PM MAIL   Вверх
borisbn
Дата 14.1.2011, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 2
Всего: 135



Цитата(bra1ss @  14.1.2011,  11:46 Найти цитируемый пост)
но производительность поднялась до 50%

неудивительно. запуск потока в windows'е очень затратная операция. 
Цитата(bra1ss @  14.1.2011,  11:46 Найти цитируемый пост)
Циклы в потоках 2, 3 вновь выполняются разное количество времени, в результате в один файл записывается больше кадров, чем во второй.

А вот это не понятно, потому, что по логике, если sendToWrite( X ) вызвался 1000 раз, то и waitForDataToWrite потока X вызвался 1000 раз, и, соответственно, writeToFile потока X вызвался 1000 раз.
IMHO, если сделаешь всё в точности, как в этом алгоритме ( в моём 2-м ), то всё должно работать как надо


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
bra1ss
Дата 17.1.2011, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



Реализовал следующим образом:

Код

Поток 1

...
if (capture)
{
    v1.push_back(processedImg1.GetData());
    v2.push_back(processedImg2.GetData());
}
...

Потоки 2,3
while (1)
{
    if (v1.size() > 0)
    {
        avi1.appendFrame(v1[0]))
        v1.erase(v1.begin());
    }
    Sleep(1);
}


С сихронностью проблем теперь нет, но процессор это особенно не разгрузило, те же 50%. Видимо, проблема в реализации функции appendFrame.
PM MAIL   Вверх
borisbn
Дата 17.1.2011, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 2
Всего: 135



Цитата(bra1ss @  17.1.2011,  10:30 Найти цитируемый пост)
Видимо, проблема в реализации функции appendFrame.

у меня сразу было такое подозрение smile

и ты ж не забываешь обращаться к stl-спискам (v1, v2) через критические секции ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
bra1ss
Дата 3.2.2011, 09:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 26.7.2010

Репутация: нет
Всего: нет



На время пришлось отойти от проекта, теперь снова вернулся к нему. С синхронностью проблем действительно нет, но проблема в другом: почему-то в записанных видеофайлах наблюдаются "проскоки" и зависания изображения на несколько кадров, на превью при этом все в порядке. Опытным путем установлено, что функция appendFrame вместо обычных 10-15 секунд, иногда может выполниться 200-300. Именно поэтому я её и вывел из критической секции в потоке 2. Все кадры из потока 1 последовательно должны добавляться в stl-очередь vect1 (на превью всё в порядке, плавное изображение), и по идее также последовательно оттуда должны в потоке 2 забираться и обрабатываться дальше уже сколько угодно времени, но потерь происходить не должно. А в реале получается, что на превью идут кадры: 1, 2, 3, 4, 5, 6, 7, 8. А в записанном файле получается что-то вроде: 1, 2, 6, 6, 6, 7, 8.



Код

Поток 1
{
...
    if (capture)
    {
        csection1.Lock();
        vect1.push(processedImg1.GetData());
        csection1.Unlock();
        csection2.Lock();
        vect2.push(processedImg2.GetData());
        csection2.Unlock();
    }
...
}

Потоки 2, 3
{
    while (1)
    {
        if (!vect1.empty())
        {
            csection1.Lock();
            temp1 = vect1.front();
            vect1.pop();
            csection1.Unlock();
            avi1.appendFrame(temp1);

        }        
        Sleep(1);
    }

}


Это сообщение отредактировал(а) bra1ss - 3.2.2011, 09:49
PM MAIL   Вверх
borisbn
Дата 3.2.2011, 10:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 2
Всего: 135



bra1ss, ты показал код только превью, хотя
Цитата(bra1ss @  3.2.2011,  09:48 Найти цитируемый пост)
на превью при этом все в порядке

покажи как пишутся файлы


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0564 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.