Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Прикладное программирование на CC++ с нуля до мультимедийных и сетевых приложений

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
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;