Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Прикладное программирование на CC++ с нуля до мультимедийных и сетевых приложений
.pdf
VCL для записи и воспроизведения видео 181
Ðèñ. 5.13
пактно. Не забудем, однако, отметить, что размер упомянутого заголовочного
файла VIDGRAB.hpp довольно внушителен.
//—————————————————————————————————————-
//#pragma hdrstop
#include "VidGrab.hpp"
#include "Unit1.h"
//—————————————————————————————————————-
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TVideoGrabber *VideoGrabber;
BOOL VideoGrabberCreated;
//—————————————————————————————————————-
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//—————————————————————————————————————-
void __fastcall TForm1::FormCreate(TObject *Sender)
{
VideoGrabberCreated = false;
}

182 Глава 5. Программирование работы с видео
//—————————————————————————————————————-
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (VideoGrabber == NULL) {
VideoGrabber = new TVideoGrabber (this);
VideoGrabber->UseNearestVideoSize (320, 240, true);
VideoGrabber->Parent = this;
VideoGrabber->Left = 280;
VideoGrabber->Top = 50;
VideoGrabber->StartPreview();
VideoGrabberCreated = true;
}
else
VideoGrabber->StartPreview();
RadioGroup1->Enabled = true;
Button4->Enabled = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button2Click(TObject *Sender)
{
if (VideoGrabberCreated) {
VideoGrabber->Free();
VideoGrabberCreated = false;
VideoGrabber = NULL; }
Close();
}
//—————————————————————————————————————-
void __fastcall TForm1::Button3Click(TObject *Sender)
{
VideoGrabber->StopPreview();
}
//—————————————————————————————————————void __fastcall TForm1::RadioGroup1Click(TObject *Sender)
{
switch (RadioGroup1->ItemIndex) {
case 0: VideoGrabber->UseNearestVideoSize (80 , 60 , true); break;
case 1: VideoGrabber->UseNearestVideoSize (160, 120, true); break;
case 2: VideoGrabber->UseNearestVideoSize (320, 240, true); break;
}
}
//—————————————————————————————————————void __fastcall TForm1::Button4Click(TObject *Sender)
{
VideoGrabber->FrameRate = StrToFloat(Edit1->Text);
}
//—————————————————————————————————————-
Начнем комментарии к программе с того, что здесь мы не используем
компонент VidGrab в явном визуальном представлении — мы не помещаем на
форму готовый объект VideoGrabber. Это можно было бы сделать, перейдя в

VCL для записи и воспроизведения видео 183
палитре визуальных компонентов на вкладку Datastead и взяв оттуда одноименный (впрочем, единственный) объект. С целью дальнейшего освоения
объектно-ориентированного программирования поступим по-другому. Строка
TVideoGrabber *VideoGrabber; в глобальных декларациях объявляет объект
нужного нам класса TvideoGrabber. Как можно видеть, объявляется указатель
на объект с именем VideoGrabber.
Главные «события» в программе разворачиваются в обработчике кнопки
Button1. Как легко догадаться, здесь сначала выполняется одна из двух ветвей
условного выражения. Первая ветвь срабатывает, если наш объект еще не
инициализирован, его адрес есть NULL. Это происходит только один раз при
старте программы. Оператор VideoGrabber = new TVideoGrabber (this); как раз
и создает объект, после чего он имеет конкретный адрес. Далее в этой ветви
выполняется метод нашего класса UseNearestVideoSize. Эта функция устанавливает горизонтальный и вертикальный размеры области отображения. Точнее, подбирается наиболее близкая к заданной первыми аргументами пара из
набора допустимых значений. Последний параметр, установленный в ЛОЖЬ
(false), оставляет в качестве размеров окна пару допустимых значений. Если
же этот параметр есть ИСТИНА (true), то размеры картинки «подгоняются»
до значений, заданных первыми аргументами. После этого определяется родительское окно области отображения. У нас это — собственное окно формы, поэтому задается значение this. Два следующих выражения задают координаты левого верхнего угла области отображения относительно того же угла
родительского îêíà. Íó и, наконец, запускается просмотр методом
VideoGrabber->StartPreview(); и переменная VideoGrabberCreated становится
истинной. Эта булевская переменная, которая при запуске задается ложной
(в функции FormCreate), необходима именно для определения факта создания объекта.
Вторая ветвь будет срабатывать при повторных нажатиях кнопки и просто
перезапускать предварительный просмотр. Кроме того, обработчик кнопки
при первом нажатии делает доступными радиокнопки и редактор частоты
кадров, которые изначально следует сделать недоступными в инспекторе объектов. С обработчиком кнопки Button2 все ясно. Здесь все освобождается, все
уничтожается и все закрывается, включая саму программу.
С кнопкой Button3 также все понятно: метод StopPreview нашего класса
временно приостанавливает просмотр изображения.
В обработчике группы радиокнопок установлен переключатель выбора одного из трех размеров видеообласти — конструкция нам уже знакомая из предыдущих программ. А о функции UseNearestVideoSize все необходимые слова
уже сказаны. Наконец, кнопка Button4 выполняет присваивание свойству
FrameRate (частота кадров) значение, указанное в поле редактирования Edit1.
Вот, собственно, и все, что необходимо прокомментировать по этой программе. Следует заметить, что для нормального функционирования приложения необходимо принять меры к тому, чтобы возможности изменения размеров
видеообласти и частоты кадров предоставлялись только после первого запуска
просмотра. С этой целью в программе сделано так, что группа радиокнопок и

184 Глава 5. Программирование работы с видео
кнопка ÎÊ первоначально недоступны. При проектировании формы необходимо свойство Enabled этих объектов установить в ЛОЖЬ (false).
В следующей программе, использующей компонент VideoGrabber, поставим задачи записи кадра захваченного изображения в файл статического рисунка и создания файла видеоклипа. В соответствии с возможностями пакета
спроектируем в программе возможность выбора сохранения кадра в файл
либо типа .bmp, ëèáî òèïà .jpg. При создании видеоклипа спроектируем возможность записи со звуковым сопровождением или без такового.
Внешний вид рабочего окна программы будет подобен следующему рисунку. Кнопка СТАРТ открывает предварительный просмотр изображения с
камеры. Кнопка СОХРАНИТЬ КАДР выполняет подготовительные действия
для захвата кадра и делает доступным выбор формата файла картинки с помощью соответствующих радиокнопок. ÎÊ непосредственно создает файл изображения, а кнопка СМОТРЕТЬ КАДР отображает файл на экран. Вторая
ветвь: СОХРАНИТЬ КЛИП, ÇÂÓÊ, СТАРТ è ÑÒÎÏ производит запись подвижного и, при необходимости, сопровождаемого звуком изображения в
AVI-файл. При нажатии кнопки ВОСПРОИЗВЕСТИ КЛИП ниже этой надписи будет воспроизведен записанный фрагмент (рис. 5.14).
Ðèñ. 5.14
На этот раз поработаем с объектом VideoGrabber естественным для визуальных компонентов способом: поместим его на форму из раздела палитры
VCL под названием Datastead. Его рабочая область на рисунке размещена у

VCL для записи и воспроизведения видео 185
нас справа вверху, а размеры области отрегулированы вручную. Разместив на
форме все перечисленные кнопки и группы радиокнопок, сделайте их, кроме
первой кнопки СТАРТ и последней кнопки STOP, изначально недоступными
(свойство Enabled задайте равным false), а область VideoGrabber невидимым
(свойство Visible установите в false). Кроме того, на форму необходимо установить визуальный компонент Image со вкладки Additional палитры VCL.
У нас он установлен в левой нижней части окна. Теперь переходим к листингу программы, представленному ниже.
//—————————————————————————————————————#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//—————————————————————————————————————#pragma package(smart_init)
#pragma link "VidGrab"
#pragma resource "*.dfm"
TForm1 *Form1;
//—————————————————————————————————————__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//—————————————————————————————————————void __fastcall TForm1::Button1Click(TObject *Sender)
{
RadioGroup1->Enabled = true;
VideoGrabber1->FrameGrabber = fg_BothStreams;
Button3->Enabled = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button6Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex)
Image1->Picture->LoadFromFile("11.jpg");
else
Image1->Picture->LoadFromFile("11.bmp");
}
//—————————————————————————————————————void __fastcall TForm1::Button7Click(TObject *Sender)
{
VideoGrabber1->StopPreview();
VideoGrabber1->Visible = true;
VideoGrabber1->FrameRate = 12;
VideoGrabber1->StartPreview();
Button1->Enabled = true;
Button2->Enabled = true;
}
//—————————————————————————————————————-

186 Глава 5. Программирование работы с видео
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex)
VideoGrabber1->CaptureFrameTo(fc_JpegFile,"11.jpg");
else
VideoGrabber1->CaptureFrameTo(fc_BmpFile,"11.bmp");
Button6->Enabled = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button8Click(TObject *Sender)
{
Close();
}
//—————————————————————————————————————void __fastcall TForm1::Button2Click(TObject *Sender)
{
//VideoGrabber1->PreallocCapFileEnabled = true;
//VideoGrabber1->PreallocCapFileSizeInMB = 1;
VideoGrabber1->CaptureFileName = "11.avi";
RadioGroup2->Enabled = true;
Button4->Enabled = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button4Click(TObject *Sender)
{
if(RadioGroup2->ItemIndex == 0)
VideoGrabber1->AudioCapture = true;
VideoGrabber1->StartAVICapture();
Button5->Enabled = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button5Click(TObject *Sender)
{
VideoGrabber1->StopAVICapture();
}
//—————————————————————————————————————void __fastcall TForm1::Button9Click(TObject *Sender)
{
VideoGrabber1->Top = 224;
VideoGrabber1->StopPreview();
VideoGrabber1->PlayerFileName = "11.avi";
VideoGrabber1->OpenPlayer();
VideoGrabber1->RunPlayer();
}
//—————————————————————————————————————void __fastcall TForm1::Button10Click(TObject *Sender)
{
VideoGrabber1->ClosePlayer();
}
//—————————————————————————————————————-

VCL для записи и воспроизведения видео 187
Обработчик кнопки СТАРТ (Button7) делает видимой область предварительного просмотра, устанавливает частоту кадров равной 12, запускает просмотр и разрешает использование кнопок СОХРАНИТЬ КАДР è СОХРА-
ÍÈÒÜ ÊËÈÏ. Обработчик СОХРАНИТЬ КАДР делает доступной группу радиокнопок ФОРМАТ, где выбирается формат файла (bmp èëè jpg). Строка
VideoGrabber1->FrameGrabber = fg_BothStreams;
позволяет одновременно использовать предварительный просмотр и захват
изображения. Далее становится доступной кнопка ÎÊ (Button3), непосредственно выполняющая захват. Здесь, в зависимости от состояния группы
радиокнопок ФОРМАТ, выполняется захват снимка либо в файл 11.bmp,
ëèáî â ôàéë 11.jpg — работает метод VideoGrabber1->CaptureFrameTo. По
окончании записи в файл становится доступной кнопка СМОТРЕТЬ КАДР
(Button6).
Компонент Image позволяет просмотреть графическое изображение. Для
этого необходимо загрузить соответствующий файл с метода Image1->
Picture->LoadFromFile. Как можно видеть из текста обработчика кнопки, аргументом метода является имя файла, а конкретный загружаемый файл зависит
от выбранного ранее формата.
Переходим к ветви создания файла видеоклипа. В обработчике кнопки
СОХРАНИТЬ КЛИП (Button2) обратите внимание на «закомментированные»
первые две строки. В коммерческой версии пакета VidGrab имеется возможность предварительного задания (ограничения) размера создаваемого файла.
Это очень разумно, поскольку запись подвижного изображения потребляет
дисковую память в невероятных количествах. К сожалению, в shareware-версии это возможность не реализована, и прерывать захват видео придется вручную. Действующие же операторы в обработчике задают имя файла для клипа — «11.avi», разрешают использование группы радиокнопок ÇÂÓÊ и делают
доступной кнопку СТАРТ (Button4).
В зависимости от состояния группы ÇÂÓÊ, в кнопке СТАРТ выполняется
или не выполняется операция VideoGrabber1->AudioCapture = true;, то есть
разрешается или не разрешается запись в файл звука вместе с видео. Сам захват подвижного изображения производится методом StartAVICapture. Становится доступной кнопка ÑÒÎÏ (Button5), которая останавливает запись. В результате на диске в рабочем каталоге проекта образуется заказываемый файл.
В пакете VidGrab имеется возможность подключения собственного плеера
для воспроизведения avi-файлов. Обработчик кнопки ВОСПРОИЗВЕСТИ
ÊËÈÏ (Button9) как раз этим и занимается. По умолчанию область воспроизведения клипа совпадает с областью предварительного просмотра. Мы переместим ее вниз оператором VideoGrabber1->Top = 224;. Все остальные операции в функции-обработчике совершенно понятны из названий используемых
методов. Наконец, кнопка ÑÒÎÏ ÊËÈÏ (Button10) прекращает воспроизведение файла, а кнопка STOP вообще закрывает приложение.
Как можно видеть, использование визуальных компонентов разгружает
разработчика от программирования многих рутинных операций, а код про
-

188 Глава 5. Программирование работы с видео
граммы выглядит очень компактным. В то же время недоступность некоторых
внутренних операций в работе VCL может вызывать определенные проблемы.
Так, например, при программировании записи звука средствами Windows API
видели, что реально записанные данные первоначально помещаются в
мы
блок оперативной памяти и только потом переписываются в файл. Блок памяти был у нас «под рукой» — мы знали его адрес и могли свободно оперировать с этими данными. В рассмотренном выше пакете доступ к блоку в памяти скрыт, и это зачастую нежелательно. В частности, в задачах IP-телефонии
может потребоваться передача данных по сети без превращения их в файл.
Как с этим быть при использовании VCL — не вполне понятно.
Программирование видео
средствами Win32 API
Итак, использование VCL несколько облегчает программистскую работу,
но, как мы видели в предыдущем разделе, может накладывать ограничения на
использование в создаваемых программных продуктах. И что делать, чтобы
избежать этих ограничений? Использовать средства программирования более
низкого уровня, чем мы сейчас и займемся.
Стандартным инструментарием для программирования работы с видео
являются средства Win32 API (Windows SDK), как и при работе со звуком.
Следует заметить, что в сравнении с последним захват, обработка и воспроизведение видео здесь выполняется все же более высокоуровнево. Используются
так называемые макросы, описание которых дается в заголовочном файле
vfw.h, берущем свое происхождение от довольно старой системы VIDEO for
WINDOWS. В этой связи «глубинные» операции видеозахвата и здесь остаются скрытыми от разработчика. В частности, по-прежнему остается «экранированным» непосредственный доступ к блокам оперативной памяти, промежуточно хранящих изображение. Однако к делу...
На данном этапе поставим задачу разработки приложения, способного
получать с камеры статическое или подвижное изображение и сохранять его в
файле картинки или файле клипа соответственно. Интерфейс программы в
момент после запуска приложения представлен на рисунке. После старта программы в левом верхнем углу окна отображается статический кадр, полученный в начальный момент работы. Доступными будут три кнопки. Кнопка
START VIEW FRAMES запускает цикл последовательного получения и воспроизведения кадров. Поскольку смена кадров производится достаточно быстро, в видеоокне мы будем видеть фактически непрерывно меняющееся изображение. С помощью кнопки AVI RECORD можно стартовать запись видеоклипа в файл. При этом в видеоокне организуется синхронное отображение
записываемого. Для остановки записи необходимо нажать левую кнопку
мыши, вообще говоря, в любом месте окна. Для исключения разночтений мы
предлагаем сделать щелчок в указанном месте экрана: CLICK HERE TO STOP
RECORD (ðèñ. 5.15).

Программирование видео средствами Win32 API 189
Ðèñ. 5.15
Кнопка CLOSE закрывает программу в любой момент, когда это возможно — когда эта кнопка активна. Если вы активировали первую кнопку, то становится доступной и кнопка SAVE FRAME — запись статической картинки в
файл. Доступная в этом состоянии кнопка STOP VIEW FRAMES закрывает
цикл просмотра кадров.
Проектирование приложения начинается с размещения на форме перечисленных кнопок, две из которых необходимо сделать недоступными в начальном состоянии — установить их свойство Visible â false. Далее будем следовать по тексту программы, представленному в листинге.
//—————————————————————————————————————-
#include <vcl.h>
#pragma hdrstop
#include <vfw.h>
#include "Unit1.h"
//—————————————————————————————————————-
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HWND hWnd;
BOOL KEY = true;
CAPTUREPARMS cappar;
//—————————————————————————————————————-
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)

190 Глава 5. Программирование работы с видео
{
}
//—————————————————————————————————————void __fastcall TForm1::FormCreate(TObject *Sender)
{
hWnd=capCreateCaptureWindow("Capture Window",WS_CHILD|WS_VISIBLE,
0,0,128,128,Handle,0xffff);
capDriverConnect(hWnd,0);
capFileSetCaptureFile(hWnd,"AVIfile.avi");
cappar.dwRequestMicroSecPerFrame=66667;
cappar.fMakeUserHitOKToCapture=false;
cappar.wPercentDropForError=10;
cappar.fYield=false;
cappar.dwIndexSize=34952;
cappar.wChunkGranularity=0;
cappar.fUsingDOSMemory=0;
cappar.wNumVideoRequested=5;
cappar.fCaptureAudio=true;
cappar.wNumAudioRequested=4;
cappar.vKeyAbort=VK_ESCAPE;
cappar.fAbortLeftMouse=true;
cappar.fAbortRightMouse=true;
cappar.fLimitEnabled=true;
cappar.wTimeLimit=16;
cappar.fMCIControl=false;
cappar.fStepMCIDevice=false;
cappar.dwMCIStartTime=false;
cappar.dwMCIStopTime=false;
cappar.fStepCaptureAt2x=false;
cappar.wStepCaptureAverageFrames=0;
cappar.dwAudioBufferSize=0;
cappar.fDisableWriteCache=NULL;
cappar.AVStreamMaster=AVSTREAMMASTER_AUDIO;
capCaptureSetSetup(hWnd,&cappar,sizeof(cappar));
}
//—————————————————————————————————————void __fastcall TForm1::Button1Click(TObject *Sender)
{
Button2->Enabled = true;
Button3->Enabled = true;
Button4->Enabled = false;
while(KEY)
{ capGrabFrame(hWnd);
Application->ProcessMessages(); }
KEY = true;
}
//—————————————————————————————————————void __fastcall TForm1::Button2Click(TObject *Sender)
{
Button4->Enabled = true;
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
