Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Прикладное программирование на CC++ с нуля до мультимедийных и сетевых приложений
.pdf
Финал: свой видеотелефон 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 экз.
Заказ №
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
