YT1-1627-000 H.264Data Protocol Tutorial E

  • 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;

    }