Upload
balikci
View
221
Download
0
Embed Size (px)
Citation preview
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
1/32
NETWORK CAMERA Protocol Spec.
H.264 Data Protocol Tutorial
Ver. 1.0
YT1-1627-000
April 20, 2011
CANON INC.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
2/32
2
Change Tracking List
Version Date Revised page Note
Ver. 1.0 April 20, 2011 - -
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
3/32
3
Table of Contents
1
Sample Program for Saving H.264 Video Data .......................................................................... 4
1.1 Creating a Project .................................................................................................... 6
1.2 Creating a Camera Communication Class .............................................................. 8
1.3 Creating a NAL Data Extraction Class................................................................... 14
1.4 Creating a File Save Class .................................................................................... 26
1.5 Combining the Classes .......................................................................................... 29
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
4/32
4
1 Sample Program for Saving H.264 Video Data
The following shows the sample program for saving H.264 video data using VC++.
This sample program acquires H.264 video data in an MP4 fragment format from the
camera, removes the MP4 header from the data, and saves it to a PC as data reproducible
with general decoders.
WvCameraSession Class
It acquires H.264 video data in the MP4 fragment format from the camera. Then, it
writes the acquired data into an MP4 buffer for passing the data to the
WvH264DataExtract class.
WvH264DataExtract Class
It extracts the H.264 video data from the MP4 buffer and removes the MP4 header.
Then, it writes the data without the MP4 header into a H.264 buffer for passing the
data to the WvFileSave class.
WvFileSave Class
It extracts the data without the MP4 header from the H.264 buffer, and then saves it to
a PC.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
5/32
5
The specification for the sample program is as follows:
Win32 command-line application (using MFC)
Execution methodSimpleH264DataExtract.exe -o {File to save to} -d {Image transmission duration (sec.)}
When a file to save to is not specified, the save location is C:\h264.dat.
When the duration is not specified, 0 is specified, and the processing continues until the
program ends.
The settings of H.264 video data follow the present settings of the camera.
When the press of the Ctrl and C buttons or the end of command prompt is detected,
the end processing is performed.
In a sample code, the cameras temporary IP address is 192.168.100.1. For actual use,
replace the temporary IP address with an actual one.
The image data acquired from the camera is referred to as MP4 data and the data with the
MP4 header removed from the image data as H.264 data.
The sample program is written in Visual C++, and the operation has been confirmed in
Visual C++ 2008 Professional Edition.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
6/32
6
1.1 Creating a Project
Select File > New > Project,and then select Win32 Console Application. Enter
SimpleH264DataExtract in the Name field, and then press the OK button.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
7/32
7
Check the MFC checkbox under Add common header files for in Application Settings of
the Win32 Application Wizard, and then press the Finish button.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
8/32
8
1.2 Creating a Camera Communication Class
Select Project > Add Classto open the Add Class dialog. Select C++ Class, and then
press the Add button.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
9/32
9
Enter WvCameraSession in the Class Name field, and then press the Finish button.
The following explains what this class performs.
The class generates a thread in which the following is performed: executing the
video.cgi command (sessionless), acquiring H.264 video data in MP4 fragment format
from the camera and then writing the data into the MP4 data buffer.
The thread starts with the StartGetVideo function and stops with the StopGetVideo
function.
The main processing for the WvCameraSession class is the GetVideo function. The
following explains the flow of the function (WvCameraSession.cpp).
1. It starts an HTTP communication with the camera using WinInet.
It transmits the video.cgi command to the camera, and ends the processing when the
HTTP status code is a value other than 200.
(Line number 32 - 76)
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
10/32
10
2. It acquires a response from the camera, and writes the response into the MP4 data
buffer.
It continues the processing until the stop flag becomes true due to calling theStopGetVideo function or until the image transmission from the camera ends. When a
failure in the communication with the camera server such as network disconnection
occurs, it displays a message and ends the processing.
(Line number 78 - 106)
3. It deletes each object, and performs the end processing of the HTTP communication.
(Line number 109 - 113)
The details of the file are as follows:
WvCameraSession.h
1
2
3
4
5
6
7
8
9
10
1112
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#pragmaonce
#include
#include
classWvCameraSession
{
public:
WvCameraSession(CString hostname,intduration);
~WvCameraSession(void);
private:
CString hostname; //Host name of the camera
//Duration in which an image is transmitted from the camera(sec.)
int duration;
bool stop; //Flag for stopping the image data
std::deque * mp4Buffer; //MP4 data buffer
//Object for the exclusive control of the MP4 data buffer
CCriticalSection * keyMP4;
CWinThread * thread; //Object for the thread control
private:
staticUINT ThreadProc(LPVOID pParam);
UINT GetVideo();
public:
voidStartGetVideo(std::deque * mp4Buffer, CCriticalSection * keyMP4);
voidStopGetVideo();
voidWaitThreadProc();
};
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
11/32
11
WvCameraSession.cpp
1
2
34
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2829
30
31
32
33
34
35
36
37
38
3940
41
42
43
44
45
46
47
48
49
50
51
52
#include"StdAfx.h"
#include"WvCameraSession.h"
#include#include
WvCameraSession::WvCameraSession(CString hostname,intduration)
{
this->stop =false;
this->mp4Buffer = NULL;
this->keyMP4 = NULL;
this->thread = NULL;
this->hostname = hostname;
this->duration = duration;
}
WvCameraSession::~WvCameraSession(void)
{
this->mp4Buffer = NULL;
this->keyMP4 = NULL;
this->thread = NULL;
}
//Acquire H.264 video data from the camera
UINT WvCameraSession::GetVideo()
{
DWORD dwStatus;
BYTE buffer[1024];
UINT readByte;CString command;
UINT ret = 0;
command.Format(_T("%s%d"), _T("/-wvhttp-01-/video.cgi?v=h264&duration="),
duration);
CInternetSession inet = CInternetSession(_T("SimpleH264DataExtract"));
CHttpConnection *pHttpCon = inet.GetHttpConnection(hostname,
CHttpConnection::HTTP_VERB_GET,
80,
NULL,NULL);
CHttpFile *pFile = pHttpCon->OpenRequest(CHttpConnection::HTTP_VERB_GET,
command,
NULL,
1,
NULL,
_T("HTTP/1.1"),
NULL);
try
{
pFile->SendRequest();
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
12/32
12
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
6970
71
72
73
74
75
76
77
78
79
80
8182
83
84
85
86
87
88
89
90
91
92
9394
95
96
97
98
99
100
101
102
103
104
105
catch(CInternetException * e)
{
CString err;
TCHAR buf[512];
e->GetErrorMessage(buf, 512);
err.Format(_T("Error occurred : %d / %s\n"), e->m_dwError, buf);
::AfxMessageBox(err, MB_OK | MB_ICONEXCLAMATION);
ret = -1;
gotoEXIT;
}
pFile->QueryInfoStatusCode(dwStatus);
if(dwStatus != 200)
{
CString err;
err.Format(_T("HTTP error : %d\n"), dwStatus);
::AfxMessageBox(err, MB_OK | MB_ICONEXCLAMATION);
ret = -1;
gotoEXIT;
}
while(1)
{
try
{ readByte = pFile->Read(buffer, 1024);
keyMP4->Lock();
mp4Buffer->insert(mp4Buffer->end(), buffer, buffer + 1024);
keyMP4->Unlock();
if((readByte < 1024) || (stop ==true))
{
break;
}
}
catch(CInternetException * e)
{
CString err;TCHAR buf[512];
e->GetErrorMessage(buf, 512);
err.Format(_T("Error occurred : %d / %s\n"), e->m_dwError, buf);
::AfxMessageBox(err, MB_OK | MB_ICONEXCLAMATION);
ret = -1;
gotoEXIT;
}
::Sleep(1);
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
13/32
13
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121122
123
124
125
126
127
128
129
130
131
132
133134
135
136
137
138
139
140
141
142
143
144
145
EXIT:
pFile->Close();
pHttpCon->Close();
inet.Close();
deletepFile;
deletepHttpCon;
returnret;
}
//Start the thread
UINT WvCameraSession::ThreadProc(LPVOID pParam)
{
WvCameraSession * session = (WvCameraSession*)pParam;
returnsession->GetVideo();}
//Start the H.264 video data acquition processing
voidWvCameraSession::StartGetVideo(std::deque * mp4Buffer, CCriticalSection *
keyMP4)
{
this->stop =false;
this->mp4Buffer = mp4Buffer;
this->keyMP4 = keyMP4;
thread = AfxBeginThread(ThreadProc,this);
}
//End the H.264 video data acquition processing
voidWvCameraSession::StopGetVideo()
{
stop =true;
}
voidWvCameraSession::WaitThreadProc()
{
WaitForSingleObject(thread->m_hThread, INFINITE);
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
14/32
14
1.3 Creating a NAL Data Extraction ClassSelect Project > Add Classto open the Add Classdialog. Select C++ Class, and then
press the Add button.
Enter WvH264DataExtract in the Class Name field, and then press the Finish button.
The H.264 data transmitted from the camera is in the MP4 fragment format compliant with
ISO/IEC 14496-10, ISO/IEC 14496-12 and ISO/IEC 14496-15. The data have the
following box structure.
ftyp (File Type Box)
It is a description about a file type. Only one box of this kind is included in the head of a
stream from the camera.
moov (Movie Box)It includes initial settings items required for video playback such as image size, frame
rate and time information. Only one box of this kind is included in a stream from the
camera.
moof (Movie Fragment Box)
It includes a sequence No., frame type and others.
mdat (Media Data Box)
Main body of media data
The H.264 video data is divided in processing units called NAL (Network Abstraction Layer)
units, and encrypted. The NAL units include the following information.
SPS (Sequence Parameter Set) header
Information required for decoding a stream
PPS (Picture Parameter Set) header
Information required for decoding each picture
Picture data
H.264 image data (hereafter, referred to as NAL data)
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
15/32
15
The SPS/PPS headers are stored in the avcC (AVC Configuration) box inside the moov box.
The NAL data is stored in the mdat box.
The number of NAL data in the mdat box differs depending on the settings of the camera.
The default value is 1.
The following explains what this class performs.
The class generates a thread in which the following is performed: analyzing the H.264
video data acquired in the camera communication class, extracting the NAL data, and
then writing the extracted NAL data into the H.264 video data buffer.
The thread starts with the StartExtractData function and stops with the StopExtractData
function.
The main processing for the WvH264DataExtract class is the ExtractData function. The
following explains the flow of the function (WvH264DataExtract.cpp).
1. It extracts 1024-byte data from the H.264 data buffer where the H.264 video data in the
MP4 fragment format is stored.
(Line number 255 - 268)
2. It searches the avcC box for the SPS and PPS headers only once after the processing
starts. When it finds the headers, it writes the header information into the H.264 data
buffer. Otherwise, it ends the processing.
(Line number 270 - 289)
3. It searches the mdat box. When it does not find the mdat box, it returns to the
processing 1.
(Line number 291 - 310)
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
16/32
16
4. It extracts the data as much as the size of the mdat box from the MP4 data buffer.
(Line number 312 - 342)
5. It writes into the H.264 data buffer the NAL structure data taken out of the extracteddata.
(Line number 344 - 348)
6. It returns to the processing 1.
The processing continues until the stop flag becomes true. When the camera
communication class thread ends, the stop flag becomes true.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
17/32
17
The details of the file are as follows:
WvH264DataExtract.h
1
2
3
4
5
6
7
8
9
10
11
12
13
1415
16
17
18
19
20
21
22
23
24
25
2627
28
29
30
31
32
33
34
35
#pragmaonce
#include
#include
classWvH264DataExtract
{
public:
WvH264DataExtract(void);
~WvH264DataExtract(void);
private:
//Flag for stopping the MP4 header analysis processing
boolstop;
std::deque * mp4Buffer; //MP4 data buffer
std::deque * h264Buffer;//H.264 data buffer
//Object for the exclusive control of the MP4 data buffer
CCriticalSection * keyMP4;
//Object for the exclusive control of the H.264 data buffer
CCriticalSection * keyH264;
CWinThread * thread; //Object for the thread control
private:
staticUINT ThreadProc(LPVOID pParam);
UINT ExtractData();
intSPSPPS_extract(BYTE * buf,intindex);
intNAL_extract(BYTE * buf,intindex,intmdat_size);
voidWriteBuffer(BYTE buf);
voidWriteBuffers(BYTE * buf,intsize);
intGetBuffers(BYTE * buf,intsize);
public:
voidStartExtractData(std::deque * mp4Buffer, std::deque * h264Buffer,
CCriticalSection * keyMP4, CCriticalSection * keyH264);
voidStopExtractData();
voidWaitThreadProc();
};
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
18/32
18
WvH264DataExtract.cpp
1
2
34
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2829
30
31
32
33
34
35
36
37
38
39
4041
42
43
44
45
46
47
48
49
50
51
52
53
#include"StdAfx.h"
#include"WvH264DataExtract.h"
#defineSEARCH_SPSPPS 0
#defineWRITE_SPS 1
#defineWRITE_PPS 2
constBYTE hex_avcC[4] = {0x61, 0x76, 0x63, 0x43};
constBYTE hex_mdat[4] = {0x6D, 0x64, 0x61, 0x74};
constBYTE hex_SCP[4] = {0x00, 0x00, 0x00, 0x01};
WvH264DataExtract::WvH264DataExtract(void)
{
this->stop =false;
this->mp4Buffer = NULL;
this->h264Buffer = NULL;
this->keyMP4 = NULL;
this->keyH264 = NULL;
this->thread = NULL;
}
WvH264DataExtract::~WvH264DataExtract(void)
{
this->mp4Buffer = NULL;
this->h264Buffer = NULL;
this->keyMP4 = NULL;
this->keyH264 = NULL;
this->thread = NULL;}
staticsize_t hex2dec(char* hex)
{
size_t num = 0;
int buf;
int i;
for(i = 0; ; i++) {
if(hex[i] >='0'&& hex[i] ='a'&& hex[i] ='A'&& hex[i]
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
19/32
19
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
7071
72
73
74
75
76
77
78
79
80
81
8283
84
85
86
87
88
89
90
91
92
93
94
9596
97
98
99
100
101
102
103
104
105
106
107
num = 0xFFFFFFFF;
break;
}
num *= 16;
num += buf;
if(i >= 8)
{
//Overflow
num = 0xFFFFFFFF;
break;
}
}
return(num);
}
staticintGetSize(BYTE * buf,intsize){
int i;
int data_size = 0;
BYTE size_hex_buf[4];
charsize_hex[10];
charformat[20] ="";
if(size > 4)
{
return0;
}
for(i = 0; i < size; i++){
size_hex_buf[i] = buf[i];
strcat(format,"%02x");
}
sprintf(size_hex, format, size_hex_buf[0], size_hex_buf[1],
size_hex_buf[2], size_hex_buf[3]);
data_size = hex2dec(size_hex);
returndata_size;
}
//Write the 1-byte data into the buffervoidWvH264DataExtract::WriteBuffer(BYTE buf)
{
this->keyH264->Lock();
this->h264Buffer->push_back(buf);
this->keyH264->Unlock();
}
///Write the data as much as the specified size into the buffer
voidWvH264DataExtract::WriteBuffers(BYTE * buf,intsize)
{
if(size < 0)
{
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
20/32
20
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124125
126
127
128
129
130
131
132
133
134
135
136137
138
139
140
141
142
143
144
145
146
147
148
149150
151
152
153
154
155
156
157
158
159
160
161
return;
}
this->keyH264->Lock();
this->h264Buffer->insert(h264Buffer->end(), buf, buf + size);
this->keyH264->Unlock();
}
//Read the data as much as the specified size from the buffer
intWvH264DataExtract::GetBuffers(BYTE * buf,intsize)
{
inti;
if(size < 0)
{
return0;
}
while(stop ==false){
if(mp4Buffer->empty() ==false&& (int)mp4Buffer->size() > size)
{
keyMP4->Lock();
for(i = 0; i < size; i++)
{
buf[i] = (BYTE)mp4Buffer->front();
mp4Buffer->pop_front();
}
keyMP4->Unlock();
returnsize;
}else
{
::Sleep(1);
continue;
}
}
return0;
}
//Extract the SPS and PPS headers from the avcC box
intWvH264DataExtract::SPSPPS_extract(BYTE * buf,intindex)
{
boolSPSflg =false;boolPPSflg =false;
BYTE dat;
int i;
int cnt = 0;
int condition = SEARCH_SPSPPS;
int avcC_size = 0;
int SPSPPS_size = 0;
avcC_size = GetSize(buf + index, 4);
for(i = 4; i < avcC_size; i++)
{
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
21/32
21
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177178
179
180
181
182
183
184
185
186
187
188189
190
191
192
193
194
195
196
197
198
199
200
201202
203
204
205
206
207
208
209
210
211
212
213
dat = buf[index + i];
switch(condition)
{
caseSEARCH_SPSPPS:
if(dat == 0x67)
{
WriteBuffers((BYTE*)hex_SCP, 4);
SPSPPS_size = GetSize(buf + (index + i - 2),
2);
condition = WRITE_SPS;
cnt = 0;
i--;
}
elseif(dat == 0x68)
{
WriteBuffers((BYTE*)hex_SCP, 4);SPSPPS_size = GetSize(buf + (index + i - 2),
2);
condition = WRITE_PPS;
cnt = 0;
i--;
}
break;
caseWRITE_SPS:
WriteBuffer(dat);
cnt++;
if(cnt >= SPSPPS_size)
{ SPSflg =true;
condition = SEARCH_SPSPPS;
cnt = 0;
}
break;
caseWRITE_PPS:
WriteBuffer(dat);
cnt++;
if(cnt >= SPSPPS_size)
{
PPSflg =true;
condition = SEARCH_SPSPPS;
cnt = 0;}
break;
default:
printf("error : writing SPS or PPS\n");
return-1;
}
}
if(!SPSflg | !PPSflg)
{
printf("error : not found SPS or PPS\n");
return-1;
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
22/32
22
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230231
232
233
234
235
236
237
238
239
240
241
242243
244
245
246
247
248
249
250
251
252
253
254
255256
257
258
259
260
261
262
263
264
265
266
267
}
returnindex + i;
}
//Extract the NAL data from the mdat box mdat
intWvH264DataExtract::NAL_extract(BYTE * buf,intindex,intmdat_size)
{
int nal_size = 0;
int mdat_size_count = 8;
while(mdat_size_count < mdat_size)
{
WriteBuffers((BYTE*)hex_SCP, 4);
nal_size = GetSize(buf + index, 4);
WriteBuffers(buf + index + 4, nal_size);
mdat_size_count += nal_size + 4;
index += nal_size + 4;
}
returnindex;
}
//Extract the NAL data from the H.264 video data acquired from the camera
UINT WvH264DataExtract::ExtractData()
{
int i;
int read_size = 0;int buf_size = 0;
int bufBack_size = 0;
BYTE * buf = NULL;
BYTE * bufBack = NULL;
int mdat_size = 0;
boolSPSPPSfound =false;
UINT ret = 0;
printf("H.264 data extracting.");
while(stop ==false)
{
read_size = 0;buf_size = 1024;
buf = (BYTE*)malloc(buf_size);
if(bufBack_size > 0)
{
memcpy(buf, bufBack, bufBack_size);
free(bufBack);
bufBack = NULL;
}
if(GetBuffers(buf + bufBack_size, buf_size - bufBack_size) == 0)
{
break;
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
23/32
23
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283284
285
286
287
288
289
290
291
292
293
294
295296
297
298
299
300
301
302
303
304
305
306
307
308309
310
311
312
313
314
315
316
317
318
319
320
bufBack_size = 0;
if(SPSPPSfound ==false)
{
//Extract the SPS and PPS hearders from the avcC box
for(i = 0; i = mdat_size)
{
if(buf_size - read_size == mdat_size)
{
bufBack_size = 0;
}
else
{
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
24/32
24
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347348
349
350
351
352
353
354
355
356
357
358
359
360361
362
363
364
365
366
367
368
369
370
371
372
bufBack_size = buf_size - (read_size + mdat_size);
bufBack = (BYTE*)malloc(bufBack_size);
memcpy(bufBack, buf + read_size + mdat_size,
bufBack_size);
}
}
else
{
bufBack_size = buf_size - read_size;
memmove(buf, buf + read_size, bufBack_size);
buf_size = mdat_size;
bufBack = (BYTE*)realloc(buf, buf_size);
buf = bufBack;
bufBack = NULL;
if(GetBuffers(buf + bufBack_size, buf_size - bufBack_size) ==0)
{
break;
}
read_size = 0;
bufBack_size = 0;
}
//Extract the NAL data from the mdat box
read_size = NAL_extract(buf, read_size, mdat_size);
free(buf);buf = NULL;
printf(".");
}
printf("\n");
printf("H.264 data extracted.\n");
EXIT:
if(buf)
{
free(buf);
buf = NULL;}
if(bufBack)
{
free(bufBack);
bufBack = NULL;
}
returnret;
}
//Start the thread
UINT WvH264DataExtract::ThreadProc(LPVOID pParam)
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
25/32
25
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388389
390
391
392
393
394
395
396
397
398
399
400
{
WvH264DataExtract * extract = (WvH264DataExtract*)pParam;
returnextract->ExtractData();
}
//Start the NAL data extraction processing
voidWvH264DataExtract::StartExtractData(std::deque * mp4Buffer, std::deque *
h264Buffer, CCriticalSection * keyMP4, CCriticalSection * keyH264)
{
this->stop =false;
this->mp4Buffer = mp4Buffer;
this->h264Buffer = h264Buffer;
this->keyMP4 = keyMP4;
this->keyH264 = keyH264;
thread = AfxBeginThread(ThreadProc,this);}
//End the NAL data extraction processing
voidWvH264DataExtract::StopExtractData()
{
this->stop =true;
}
voidWvH264DataExtract::WaitThreadProc()
{
WaitForSingleObject(thread->m_hThread, INFINITE);
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
26/32
26
1.4 Creating a File Save Class
Select Project> Add Classto open the Add Classdialog. Select C++ Class, and then
press the Add button.
Enter WvSaveFile in the Class Name field, and then press the Finish button.
The following explains what this class performs.
The class generates a thread in which the following is performed: writing into the file the
NAL data extracted in the NAL data extraction class.
The thread starts with the StartSaveFile function and stops with the StopSaveFile
function.
The details of the file are as follows:
WvSaveFile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25
26
27
28
29
#pragmaonce
#include
#include
classWvSaveFile
{
public:
WvSaveFile(CString filepath);
~WvSaveFile(void);
private:
CString filepath; //Pass to a file to save to
CFile * out; //File operation object
//Flag for stopping the data saving procssing
bool stop;
std::deque * h264Buffer; //H.264 data buffer
//Object for the exclusive control of the H.264 data buffer
CCriticalSection * keyH264;CWinThread * thread; //Object for the thread control
private:
staticUINT ThreadProc(LPVOID pParam);
UINT SaveFile();
public:
voidStartSaveFile(std::deque * h264Buffer, CCriticalSection * keyH264);
voidStopSaveFile();
voidWaitThreadProc();
};
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
27/32
27
WvSaveFile.cpp
1
2
34
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2829
30
31
32
33
34
35
36
37
38
39
4041
42
43
44
45
46
47
48
49
50
51
52
53
#include"StdAfx.h"
#include"WvSaveFile.h"
WvSaveFile::WvSaveFile(CString filepath)
{
this->stop =false;
this->h264Buffer = NULL;
this->keyH264 = NULL;
this->thread = NULL;
this->filepath = filepath;
}
WvSaveFile::~WvSaveFile(void)
{
this->h264Buffer = NULL;
this->keyH264 = NULL;
this->thread = NULL;
}
//Save the extracted NAL data into the file
UINT WvSaveFile::SaveFile()
{
int i;
chartmp;
//File open
try
{out =newCFile(this->filepath.GetBuffer(),
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
}
catch(CFileException * e)
{
CString err;
TCHAR buf[512];
e->GetErrorMessage(buf,512);
err.Format(_T("Error occurred : %d / %s\n"), e->m_cause, buf);
::AfxMessageBox(err, MB_OK | MB_ICONEXCLAMATION);
e->Delete();
return-1;
}
//Write the data in the buffer into the file
while(stop ==false)
{
if(h264Buffer->empty() ==false)
{
keyH264->Lock();
for(i = 0; i < (int)h264Buffer->size(); i++)
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
28/32
28
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
7071
72
73
74
75
76
77
78
79
80
81
8283
84
85
86
87
88
89
90
91
92
93
94
9596
97
98
99
100
101
102
{
tmp = (char)h264Buffer->front();
out->Write(&tmp, 1);
h264Buffer->pop_front();
}
keyH264->Unlock();
}
}
//Write the data remained in the buffer into the file
for(i = 0; i < (int)h264Buffer->size(); i++)
{
tmp = (char)h264Buffer->front();
out->Write(&tmp, 1);
h264Buffer->pop_front();
}
deleteout;
return0;
}
//Start the thread
UINT WvSaveFile::ThreadProc(LPVOID pParam)
{
WvSaveFile * savefile = (WvSaveFile*)pParam;
returnsavefile->SaveFile();
}
//Start the NAL data saving processing
voidWvSaveFile::StartSaveFile(std::deque * h264Buffer, CCriticalSection * keyH264)
{
this->stop =false;
this->h264Buffer = h264Buffer;
this->keyH264 = keyH264;
thread = AfxBeginThread(ThreadProc,this);
}
//End the NAL data saving processing
voidWvSaveFile::StopSaveFile()
{this->stop =true;
}
voidWvSaveFile::WaitThreadProc()
{
WaitForSingleObject(thread->m_hThread, INFINITE);
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
29/32
29
1.5 Combining the Classes
Using each class enables the implementation of the sample program for saving H.264 videodata.
The following explains what this class performs.
The class generates the objects of the WvCameraSession class, the
WvH264DataExtract class and the WvSaveFile class.
It starts a thread of each class, and then starts performing the processing for acquiring
the H.264 video data, extracting the NAL data and saving the extracted data.
The processing continues until the communication with camera ends after the lapse of a
specified duration or until the end event by the user occurs.
Notes on this sample program are as follows:
A buffer ring is used to pass data between the WvCameraSession and the
WvH264DataExtract and between the WvH264DataExtract class and the WvSaveFile
class, individually. A buffer is provided at a calling source to share the buffer between the
classes. When the buffer is operated, an exclusive control is performed with the
CCriticalSection.
After starting, the end of the thread of the WvCameraSession class is waited, and the
program goes into the standby status. When the communication with the camera ends,
the thread ends. Also, the press of the Ctrl and C or the end of command prompt is
detected, the StopGetVideo function is called to end the thread. After that, the
WvH264DataExtract class and the WvSaveFile class are stopped in that order so as to
process the data remained in the buffer.
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
30/32
30
Open the SimpleH264DataExtract.h and SimpleH264DataExtract.cpp files, and write as
follows:
SimpleH264DataExtract.h1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragmaonce
#include"resource.h"
#include"WvCameraSession.h"
#include"WvH264DataExtract.h"
#include"WvSaveFile.h"
std::deque mp4Buffer;
std::deque h264Buffer;
WvCameraSession * session;
WvH264DataExtract * extract;
WvSaveFile * savefile;
CCriticalSection keyMP4;
CCriticalSection keyH264;
SimpleH264DataExtract.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1819
20
21
22
23
24
25
26
27
28
29
30
31
// SimpleH264DataExtract.cpp : Define the entry point of the console application
//
#include"stdafx.h"
#include"SimpleH264DataExtract.h"
#include"Windows.h"
#ifdef_DEBUG
#define new DEBUG_NEW
#endif
//The one and only application object
CWinApp theApp;
usingnamespacestd;
//Console event handler
BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
{
switch(dwCtrlType)
{
caseCTRL_C_EVENT: //Press the Ctrl and C
caseCTRL_CLOSE_EVENT: //Console end
session->StopGetVideo();
returnTRUE;
}
returnFALSE;
}
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
31/32
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
4849
50
51
52
53
54
55
56
57
58
59
6061
62
63
64
65
66
67
68
69
70
71
7273
74
75
76
77
78
79
80
81
82
83
84
int_tmain(intargc, TCHAR* argv[], TCHAR* envp[])
{
intnRetCode = 0;
//initialize MFC and print and error on failure.
if(!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: Change error code to suit your needs.
_tprintf(_T("Fatal error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
int duration = 0;
CString output = _T("C:\\h264.dat");
if(argc > 1)
{
for(inti = 1; i < argc; i++)
{
if(argv[i][0] =='-')
{
switch(argv[i][1]){
case'o':
if(i + 1 < argc)
{
output = argv[i + 1];
}break;
case'd':
if(i + 1 < argc)
{
duration = _ttoi(argv[i
+ 1]);
}
break;
}
}
}
}
//Add the console event handler
BOOL ret = SetConsoleCtrlHandler(ConsoleCtrlHandler,true);
if(ret ==false)
{
return-1;
}
//Create the class object
session =newWvCameraSession(_T("192.168.100.1"), duration);
extract =newWvH264DataExtract();
savefile =newWvSaveFile(output);
8/3/2019 YT1-1627-000 H.264Data Protocol Tutorial E
32/32
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101102
103
104
105
106
107
108
109
110
//Initialize the buffer
mp4Buffer.clear();
h264Buffer.clear();
//Start the thread
session->StartGetVideo(&mp4Buffer, &keyMP4);
extract->StartExtractData(&mp4Buffer, &h264Buffer, &keyMP4, &keyH264);
savefile->StartSaveFile(&h264Buffer, &keyH264);
//Monitor the camera communication thread
session->WaitThreadProc();
//Stop the thread
extract->StopExtractData();
extract->WaitThreadProc();
savefile->StopSaveFile();
savefile->WaitThreadProc();
//Discard the class object
deletesession;
deleteextract;
deletesavefile;
}
returnnRetCode;
}