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

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

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
Финал: свой видеотелефон 231
Ðèñ. 6.8
Ðèñ. 6.9
Далее в программе следует описание обработчика нажатия кнопки Button4 (YES). Основными моментами здесь являются:
1. Инициализация сокетной библиотеки функцией WSAStartup.
2. Создание сокетов UDP для трансляции звука (два сокета — на прием и
на передачу).
3. Создание сокетов ТСР для транспортировки изображения.
4. Подготовка структур и выполнение знакомых нам предварительных
операций для работы со звуком.
5. Создание окна захвата видео с помощью функции capCreateCapture- Window и реализация других дополнительных действий, также знакомых нам из предыдущих рассмотрений.
Нажатие кнопки Button5 (ВЫБОР) передает в информационное поле подсказку, предлагающую установить режим разрешения или запрета приема и передачи звука и изображения. Также здесь выполнены необходимые дейст­вия по визуализации и установке доступности соответствующих компонентов на форме.
Далее описана процедура создания формы FormCreate. Здесь всего лишь производится ввод в информационное поле первичной подсказки. А следую­щие 3 функции TrackBar1Change, SetVolume è TrackBar2Change связаны с ра ботой микшеров, рассмотрение которой, как мы договорились, оставляем на
-
232 Глава 6. IP-телефония своими руками
самостоятельную проработку читателю. И на этом описание модуля Unit1.cpp можно считать законченным.
Модуль Unit.cpp относится к форме, из окна которой устанавливаются номера коммуникационных портов ТСР и UDP, показанного выше.
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" #include <winsock2.h> #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; extern sockaddr_in local_addrTCP_outin; extern sockaddr_in dest_addrTCP; extern sockaddr_in dest_addr; extern sockaddr_in local_addr; //—————————————————————————————————————­__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner) { } //—————————————————————————————————————­void __fastcall TForm2::Button1Click(TObject *Sender) {
local_addrTCP_outin.sin_port=htons(StrToInt(Edit1->Text)); dest_addrTCP.sin_port=htons(StrToInt(Edit3->Text)); dest_addr.sin_port=htons(StrToInt(Edit4->Text)); local_addr.sin_port=htons(StrToInt(Edit2->Text)); Close();
}
Можно видеть, что модуль содержит «пустой» конструктор класса формы и функцию-обработчик нажатия единственной кнопки окна. Тело функции состоит из знакомых нам операций задания передачи номеров портов соке­там. По окончанию этих операций окно данной формы закрывается.
Блок Unit3.h — Unit3.cpp представляет собой нить (thread) для передачи корреспонденту звуковых данных. Приведем без комментариев заголовочный файл блока. Во всех остальных блоках нитей заголовки будут выглядеть ана­логично.
#ifndef Unit3H #define Unit3H //—————————————————————————————————————­#include <Classes.hpp> //—————————————————————————————————————­class Tout : public TThread { private: protected:
void __fastcall Execute();
Финал: свой видеотелефон 233
public:
__fastcall Tout(bool CreateSuspended); }; //—————————————————————————————————————­#endif
//—————————————————————————————————————­#ifndef Unit3H #define Unit3H //—————————————————————————————————————­#include <Classes.hpp> //—————————————————————————————————————­class Tout : public TThread { private: protected:
void __fastcall Execute();
public:
__fastcall Tout(bool CreateSuspended); }; //—————————————————————————————————————­#endif
В соответствии с технологией создания нитей в файле реализации описа-
на функция Execute:
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit3.h" #include <winsock2.h> #include <mmsystem.h> #pragma package(smart_init) extern BOOL KEY; extern HWAVEIN hWaveIn; extern LPWAVEHDR lpHdr,lpDhr; extern SOCKET sock_out; extern long BufAll; extern sockaddr_in dest_addr; //—————————————————————————————————————­__fastcall Tout::Tout(bool CreateSuspended)
: TThread(CreateSuspended) {} //—————————————————————————————————————­void __fastcall Tout::Execute() {
waveInAddBuffer(hWaveIn,lpHdr,sizeof(WAVEHDR));
waveInStart(hWaveIn);
while(!(1&(lpHdr->dwFlags))); while(KEY) {
waveInAddBuffer(hWaveIn,lpDhr,sizeof(WAVEHDR));
waveInStart(hWaveIn);
sendto(sock_out,lpHdr->lpData,BufAll,0,(sockaddr *)
234 Глава 6. IP-телефония своими руками
&dest_addr,sizeof(dest_addr));
while(!(1&(lpDhr->dwFlags)));
waveInAddBuffer(hWaveIn,lpHdr,sizeof(WAVEHDR));
waveInStart(hWaveIn); sendto(sock_out,lpDhr->lpData,BufAll,0,(sockaddr *)
&dest_addr,sizeof(dest_addr));
while(!(1&(lpHdr->dwFlags)));
}
}
Итак, здесь сначала звуковой карте передается блок памяти lpHdr, в кото­рый производится запись звука до заполнения блока. Далее в цикле, преры­ваемом только сигнальной переменной KEY (конец работы программы), про­изводится следующее. Заполняется другой звуковой блок lpDhr, параллельно с этим первый блок отсылается сокетом корреспонденту. После заполнения второго блока звуковой карте снова отдается второй первый блок, а второй передается сокетом. Поскольку все это происходит в цикле, мы имеем непре­рывный процесс работы с двумя блоками: один из них заполняется, а другой в это же время передается. Ткое чередование позволяет избежать пауз, которые возникали бы при операциях только с одним блоком.
В паре Unit4.h—Unit4.cpp в соответствующей нити производится прием и воспроизведение звуковой информации.
#include <vcl.h> #pragma hdrstop #include "Unit4.h" #include "Unit1.h" #include <winsock2.h> #include <mmsystem.h> #pragma package(smart_init) extern BOOL KEY; extern HWAVEOUT hWaveOut; extern LPWAVEHDR lpHdr1,lpHdr2; extern SOCKET sock_in; extern long BufAll; sockaddr_in client_addr; int client_addr_size = sizeof(client_addr); //———————————————————————————— __fastcall Tin::Tin(bool CreateSuspended)
: TThread(CreateSuspended) {} //—————————————————————————————— void __fastcall Tin::Execute() {
recvfrom(sock_in,lpHdr2->lpData,BufAll,0,
(sockaddr *) &client_addr, &client_addr_size); while(KEY) {
waveOutWrite(hWaveOut,lpHdr2,sizeof(WAVEHDR));
recvfrom(sock_in,lpHdr1->lpData,BufAll,0,(sockaddr *)
&client_addr, &client_addr_size);
Финал: свой видеотелефон 235
waveOutWrite(hWaveOut,lpHdr1,sizeof(WAVEHDR));
recvfrom(sock_in,lpHdr2->lpData,BufAll,0,(sockaddr *)
&client_addr, &client_addr_size);
}
}
Здесь в функции Execute сначала происходит прием звуковых данных в буфер lpHdr2. Затем в цикле этот буфер воспроизводится и одновременно принимается следующая посылка в буфер lpHdr1 Далее в цикле же второй блок lpHdr1 проигрывается, а lpHdr2 записывается. Таким образом, и здесь мы оперируем с двумя буферами звуковых данных во избежание пауз при приеме и воспроизведении.
Работа с изображением в нашей программе также базируется на нитях. Модуль Unit5.cpp представляет собой реализацию функции Execute нити пе­редачи картинки.
#include <vcl.h> #pragma hdrstop #include <vfw.h> #include "Unit1.h" #include "Unit5.h" #include <winsock2.h> #include <jpeg.hpp> #include <vcl\Clipbrd.hpp> #pragma package(smart_init) extern SOCKET my_sock; char buf1[16000]; extern BOOL KEY; TJPEGImage *jpg = new TJPEGImage(); TClipboard *pCB = Clipboard(); Graphics::TBitmap *pBitmap = new Graphics::TBitmap(); TMemoryStream* pms = new TMemoryStream(); extern HWND hWnd; //—————————————————————————————————————­__fastcall VideoOut::VideoOut(bool CreateSuspended)
: TThread(CreateSuspended) {} //—————————————————————————————————————­void __fastcall VideoOut::Execute() {
while((recv(my_sock,buf1,sizeof(buf1),0)>0)&&KEY)
{
capGrabFrame(hWnd); capEditCopy(hWnd); pBitmap->LoadFromClipboardFormat(CF_BITMAP,
pCB->GetAsHandle(CF_BITMAP),0); jpg->Assign(pBitmap); jpg->CompressionQuality=32; jpg->Compress(); jpg->SaveToStream(pms); pms->Position = 0; pms->ReadBuffer(buf1,pms->Size); pms->Position = 0; send(my_sock,buf1,pms->Size,0); pms->Clear();
}
}
236 Глава 6. IP-телефония своими руками
Функция целиком состоит из цикла, который (при разрешающем состоя­нии сигнальной переменной KEY) получает из сокета любые данные, как только таковоые поступают. Поступление данных является сигналом для вы­полнения тела цикла, а в цикле следует ряд знакомых нам операций по запи­си, сжатию и отправке картинки. Подчеркнем, что, в отличие от звука, мы здесь не заботимся о непрерывности видео — кадр записывается и отсылается по мере поступления чего-либо в сокет my_sock. В этой связи в данной нити мы используем только один буфер buf1. Как мы увидим далее, это самое «что-либо» будет специальным сообщением от принимающей изображение стороны.
Нить Unit6.cpp работает на приеме изображения.
#pragma hdrstop #include "Unit6.h" #include "Unit1.h" #include <jpeg.hpp> #pragma package(smart_init) int recsizeOutIn; extern SOCKET client_socket; char buff[16000]; extern BOOL KEY; TMemoryStream* pmsIn2 = new TMemoryStream(); TJPEGImage *jpgIn2 = new TJPEGImage(); extern int www,hhh; //—————————————————————————————————————­__fastcall OutIn::OutIn(bool CreateSuspended)
: TThread(CreateSuspended) {} //—————————————————————————————————————­void __fastcall OutIn::Execute() {
while(((recsizeOutIn=recv(client_socket,buff,sizeof(buff),0))>0)&&KEY)
{
pmsIn2->Position = 0; pmsIn2->WriteBuffer(buff,recsizeOutIn); pmsIn2->Position = 0; jpgIn2->LoadFromStream(pmsIn2); pmsIn2->Clear(); Form1->Canvas->Draw(0,0,jpgIn2); send(client_socket,"GO",2,0);
}
}
Функция представляет собой цикл, принимающий переданный другой строной блок аудиоданных. Как только такой блок поступает, производится его воспроизведение, а в ответ отсылается строка символов «GO» — это и есть то самое информационное сообщение, о котором мы только что писали. Сно­ва напомним, что сама техника чтения из сокета и воспроизведения картинки нам знакома по предыдущим разделам.
Пары Unit7.h—Unit7.cpp и Unit8.h—Unit8.cpp совершенно аналогичны парам 6—5 соответственно. Понятно, что на каждой стороне должен быть свой и приемник и передатчик информации — отдельные нити.
Наконец, нам осталось обратиться к последнему модулю Unit9.cpp.
Финал: свой видеотелефон 237
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit9.h" //—————————————————————————————————————­#pragma package(smart_init) #pragma resource "*.dfm" TForm9 *Form9; extern int jj; //—————————————————————————————————————­__fastcall TForm9::TForm9(TComponent* Owner)
: TForm(Owner) {} //—————————————————————————————————————-
void __fastcall TForm9::Button1Click(TObject *Sender) {
jj=StrToInt(Form9->Edit1->Text);
Form9->Close(); } //—————————————————————————————————————-
Как мы говорили ранее, при запуске программы имеется возможность выбора одного из нескольких драйверов устройств видеоввода, если их в сис­теме несколько. Выполняется это вызовом соответствующего пункта главного меню. При этом отображается дополнительное окно — форма, названная в нашем приложении Form9. На форме имеется единственная кнопка, нажатие которой и обрабатывется модулем Unit9. А здесь всего лишь производит при­своение соответствующего значения глобальной переменной jj и закрытие до­полнительного окна. Переменная jj используется в главном основном модуле так, как это описано ранее.
***
Итак, уважаемый читатель, мы с вами можем, наконец, поставить фи­нальную точку. Если этой финальной точкой для читателя стала работающая программа собственного видеотелефона и если читатель хотя бы в основном разобрался в том, как эта программа работает, и, самое главное, если читатель имеет интерес и возможность к дальнейшему совершенствовании этого при­ложения, то автор свою задачу выполнил!
Оглавление
Введение ...................................................3
Глава 1. ЯЗЫК ПРОГРАММИРОВАНИЯ С ....................... 6
Немного о TURBO C++ .................................... 6
Этапы обработки программ ................................. 8
Наша первая программа ................................... 10
Вывод информации на экран, функция printf ................... 13
Арифметические выражения, математические
и некоторые другие полезные функции ....................... 16
Выражения присваивания и ввод данных в программу ............ 20
Условные выражения ..................................... 23
Циклические выражения .................................. 26
Массивы ............................................... 31
Адреса и указатели ....................................... 36
Функции .............................................. 38
Файлы ................................................ 46
Графические возможности TURBO C++ ...................... 51
Глава 2. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
ПРОГРАММИРОВАНИЕ И С++ BUILDER ............... 58
Техника работы в С++ Builder .............................. 58
Структуры ............................................. 67
Классы ................................................ 70
Перегрузка функций и операторов ........................... 77
Многопотоковые приложения ............................... 82
Глава 3. ПЕРЕДАЧА ИНФОРМАЦИИ В СЕТЯХ .................. 88
Введение в компьютерные коммуникации ..................... 88
Простейшие коммуникационные программы ................... 92
Программирование сокетов ................................ 107
Коммуникации по телефонным линиям ...................... 118
Оглавление 239
Глава 4. ЗАПИСЬ, ОБРАБОТКА И ВОСПРОИЗВЕДЕНИЕ
ЗВУКА ........................................... 133
Аналоговый и цифровой звук .............................. 133
Звуковое оснащение компьютера ........................... 136
Основы программирования звукозаписи ...................... 140
Программы записи и воспроизведения звука ................... 143
Программируем сжатие аудиоинформации .................... 152
Глава 5. ПРОГРАММИРОВАНИЕ РАБОТЫ С ВИДЕО ............ 168
Ввод и вывод изображения ................................ 168
VCL для записи и воспроизведения видео ..................... 177
Программирование видео средствами Win32 API ................ 188
Сжатие видеоинформации ................................ 193
Работа с видео в системе DirectX ........................... 195
Глава 6. IP-ТЕЛЕФОНИЯ СВОИМИ РУКАМИ .................. 205
Очень краткое вступление ................................. 205
Передача аудио в реальном времени ......................... 207
Не звуком единым... ..................................... 212
Финал: свой видеотелефон ................................ 219
В. Иванов
Прикладное
программирование на C/C++:
с нуля до мультимедийных
и сетевых приложений
Издание второе, стереотипное
Ответственный за выпуск: В. Митин
Верстка и обложка: СОЛОН-ПРЕСС
По вопросам приобретения обращаться:
ООО «СОЛОН-ПРЕСС»
123001, г. Москва, а/я 82
Телефон: (495) 617-39-64
E-mail: kniga@solon-press.ru, www.solon-press.ru
Распространение через сеть магазинов и маркетплейсов
ООО КТК «Галактика»
115487, г. Москва, проспект Андропова, д. 38
Телефоны: (499) 782-38-89
E-mail: books@alians-kniga.ru, https://www.galaktika-dmk.com/
По вопросам подписки на журнал «Ремонт & Сервис» обращаться:
ООО «СОЛОН-ПРЕСС»
тел.: (495) 617-39-64, www.remserv.ru
ООО «СОЛОН-ПРЕСС»
115487, г. Москва,
пр-кт Андропова, дом 38, помещение № 8, комната № 2.
Формат 70×100/16. Объем 15 п. л. Тираж 100 экз.
Заказ №