- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

# samples/backend/v4l2_backend_main.cpp

Go to the documentation of this file.

    00001 /*
    00002  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
    00003  *
    00004  * Redistribution and use in source and binary forms, with or without
    00005  * modification, are permitted provided that the following conditions
    00006  * are met:
    00007  *  * Redistributions of source code must retain the above copyright
    00008  *    notice, this list of conditions and the following disclaimer.
    00009  *  * Redistributions in binary form must reproduce the above copyright
    00010  *    notice, this list of conditions and the following disclaimer in the
    00011  *    documentation and/or other materials provided with the distribution.
    00012  *  * Neither the name of NVIDIA CORPORATION nor the names of its
    00013  *    contributors may be used to endorse or promote products derived
    00014  *    from this software without specific prior written permission.
    00015  *
    00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
    00017  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    00019  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    00020  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    00021  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    00022  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    00023  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
    00024  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    00026  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00027  */
    00028
    00029 #include "NvUtils.h"
    00030 #include <errno.h>
    00031 #include <fstream>
    00032 #include <iostream>
    00033 #include <cstdlib>
    00034 #include <cstring>
    00035 #include <linux/videodev2.h>
    00036 #include <pthread.h>
    00037 #include <string.h>
    00038 #include <unistd.h>
    00039 #include "NvCudaProc.h"
    00040 #include "nvbuf_utils.h"
    00041 #include "v4l2_nv_extensions.h"
    00042 #include "v4l2_backend_test.h"
    00043 #include <sys/time.h>
    00044
    00045 #ifdef ENABLE_GIE
    00046 #include "gie_inference.h"
    00047 #endif
    00048
    00049 #define TEST_ERROR(cond, str, label) if(cond) { \
    00050                                         cerr << str << endl; \
    00051                                         error = 1; \
    00052                                         goto label; }
    00053
    00054 #define CHUNK_SIZE 4000000
    00055 #ifndef MIN
    00056 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
    00057 #endif
    00058
    00059 #define NAL_UNIT_START_CODE 0x00000001
    00060 #define MIN_CHUNK_SIZE      50
    00061 #define USE_CPU_FOR_INTFLOAT_CONVERSION 0
    00062
    00063 static const int IMAGE_WIDTH = 1920;
    00064 static const int IMAGE_HEIGHT = 1080;
    00065 const char *GOOGLE_NET_DEPLOY_NAME =
    00066         "../../data/model/GoogleNet-modified.prototxt";
    00067 const char *GOOGLE_NET_MODEL_NAME =
    00068         "../../data/model/GoogleNet-modified-online_iter_30000.caffemodel";
    00069
    00070 #define IS_NAL_UNIT_START(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
    00071         !buffer_ptr[2] && (buffer_ptr[3] == 1))
    00072
    00073 #define IS_NAL_UNIT_START1(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
    00074         (buffer_ptr[2] == 1))
    00075
    00076 using namespace std;
    00077
    00078 #ifdef ENABLE_GIE
    00079 #define OSD_BUF_NUM 100
    00080 static int frame_num = 1;  //this is used to filter image feeding to GIE
    00081
    00082 //following struture is used to conmmunicate between GIE thread and
    00083 //V4l2 capture thread
    00084 queue<Shared_Buffer> GIE_Buffer_Queue;
    00085 pthread_mutex_t      GIE_lock; // for dec and conv
    00086 pthread_cond_t       GIE_cond;
    00087 int                  GIE_Stop = 0;
    00088 pthread_t            GIE_Thread_handle;
    00089
    00090 using namespace nvinfer1;
    00091 using namespace nvcaffeparser1;
    00092
    00093 GIE_Context g_gie_context;
    00094 void *gie_thread(void *data);
    00095
    00096 #endif
    00097
    00098 EGLDisplay egl_display;
    00099 jpeg_enc_context_t g_jpeg_enc_context;
    00100
    00101 static uint64_t ts[CHANNEL_NUM];
    00102 static uint64_t time_scale[CHANNEL_NUM];
    00103
    00104 static int
    00105 init_jpeg_context()
    00106 {
    00107     pthread_mutex_init(&g_jpeg_enc_context.queue_lock, NULL);
    00108     g_jpeg_enc_context.JpegEnc = NvJPEGEncoder::createJPEGEncoder("jpeg_enc");
    00109
    00110     if (g_jpeg_enc_context.JpegEnc == NULL)
    00111     {
    00112         cout<<"create jpeg encode failed"<<endl;
    00113         return 0;
    00114     }
    00115
    00116     g_jpeg_enc_context.pbuf = new unsigned char[JPEG_ENC_BUF_SIZE];
    00117     g_jpeg_enc_context.buf_size = JPEG_ENC_BUF_SIZE;
    00118     memset(g_jpeg_enc_context.filename, 0,
    00119             sizeof(g_jpeg_enc_context.filename));
    00120
    00121     return 1;
    00122 }
    00123
    00124 static int
    00125 destroy_jpeg_context()
    00126 {
    00127     delete []g_jpeg_enc_context.pbuf;
    00128     if (g_jpeg_enc_context.JpegEnc)
    00129         delete g_jpeg_enc_context.JpegEnc;
    00130
    00131     return 1;
    00132 }
    00133
    00134 static int
    00135 read_decoder_input_nalu(ifstream * stream, NvBuffer * buffer,
    00136         char *parse_buffer, streamsize parse_buffer_size)
    00137 {
    00138     // Length is the size of the buffer in bytes
    00139     char *buffer_ptr = (char *) buffer->planes[0].data;
    00140
    00141     char *stream_ptr;
    00142     bool nalu_found = false;
    00143
    00144     streamsize bytes_read;
    00145     streamsize stream_initial_pos = stream->tellg();
    00146
    00147     stream->read(parse_buffer, parse_buffer_size);
    00148     bytes_read = stream->gcount();
    00149
    00150     if (bytes_read == 0)
    00151     {
    00152         return buffer->planes[0].bytesused = 0;
    00153     }
    00154
    00155     // Find the first NAL unit in the buffer
    00156     stream_ptr = parse_buffer;
    00157     while ((stream_ptr - parse_buffer) < (bytes_read - 3))
    00158     {
    00159         nalu_found = IS_NAL_UNIT_START(stream_ptr) ||
    00160                         IS_NAL_UNIT_START1(stream_ptr);
    00161         if (nalu_found)
    00162         {
    00163             break;
    00164         }
    00165         stream_ptr++;
    00166     }
    00167
    00168     // Reached end of buffer but could not find NAL unit
    00169     if (!nalu_found)
    00170     {
    00171         cerr << "Could not read nal unit from file. File seems to be corrupted"
    00172             << endl;
    00173         return -1;
    00174     }
    00175
    00176     memcpy(buffer_ptr, stream_ptr, 4);
    00177     buffer_ptr += 4;
    00178     buffer->planes[0].bytesused = 4;
    00179     stream_ptr += 4;
    00180
    00181     // Copy bytes till the next NAL unit is found
    00182     while ((stream_ptr - parse_buffer) < (bytes_read - 3))
    00183     {
    00184         if (IS_NAL_UNIT_START(stream_ptr) || IS_NAL_UNIT_START1(stream_ptr))
    00185         {
    00186             streamsize seekto = stream_initial_pos +
    00187                     (stream_ptr - parse_buffer);
    00188             if (stream->eof())
    00189             {
    00190                 stream->clear();
    00191             }
    00192             stream->seekg(seekto, stream->beg);
    00193             return 0;
    00194         }
    00195         *buffer_ptr = *stream_ptr;
    00196         buffer_ptr++;
    00197         stream_ptr++;
    00198         buffer->planes[0].bytesused++;
    00199     }
    00200
    00201     // Reached end of buffer but could not find NAL unit
    00202     cerr << "Could not read nal unit from file. File seems to be corrupted"
    00203             << endl;
    00204     return -1;
    00205 }
    00206
    00207 static int
    00208 read_decoder_input_chunk(ifstream * stream, NvBuffer * buffer)
    00209 {
    00210     //length is the size of the buffer in bytes
    00211     streamsize bytes_to_read = MIN(CHUNK_SIZE, buffer->planes[0].length);
    00212
    00213     stream->read((char *) buffer->planes[0].data, bytes_to_read);
    00214     // It is necessary to set bytesused properly, so that decoder knows how
    00215     // many bytes in the buffer are valid
    00216     buffer->planes[0].bytesused = stream->gcount();
    00217     return 0;
    00218 }
    00219
    00220
    00221 static int
    00222 init_decode_ts()
    00223 {
    00224     for (uint32_t i = 0; i < CHANNEL_NUM; i++)
    00225     {
    00226         ts[i] = 0L;
    00227         time_scale[i] = 33000 * 10;
    00228     }
    00229
    00230     return 1;
    00231 }
    00232
    00233 static int
    00234 assign_decode_ts(struct v4l2_buffer *v4l2_buf, uint32_t channel)
    00235 {
    00236     v4l2_buf->timestamp.tv_sec = ts[channel] + time_scale[channel];
    00237     ts[channel] += time_scale[channel];
    00238
    00239     return 1;
    00240 }
    00241
    00242
    00243 static nal_type_e
    00244 parse_nalu_unit(NvBuffer * buffer)
    00245 {
    00246     unsigned char *pbuf = buffer->planes[0].data;
    00247
    00248     return (nal_type_e)(*(pbuf + 4) & 0x1F);
    00249 }
    00250
    00251 static int
    00252 wait_for_nextFrame(context_t * ctx)
    00253 {
    00254     if (ctx->cpu_occupation_option == PARSER_DECODER_VIC_RENDER)
    00255         return 1;
    00256
    00257     pthread_mutex_lock(&ctx->fps_lock);
    00258     uint64_t decode_time_usec;
    00259     uint64_t decode_time_sec;
    00260     uint64_t decode_time_nsec;
    00261     struct timespec last_decode_time;
    00262     struct timeval now;
    00263     gettimeofday(&now, NULL);
    00264
    00265     last_decode_time.tv_sec = now.tv_sec;
    00266     last_decode_time.tv_nsec = now.tv_usec * 1000L;
    00267
    00268     decode_time_usec = 1000000L / ctx->fps;
    00269     decode_time_sec = decode_time_usec / 1000000;
    00270     decode_time_nsec = (decode_time_usec % 1000000) * 1000L;
    00271
    00272     last_decode_time.tv_sec += decode_time_sec;
    00273     last_decode_time.tv_nsec += decode_time_nsec;
    00274     last_decode_time.tv_sec += last_decode_time.tv_nsec / 1000000000UL;
    00275     last_decode_time.tv_nsec %= 1000000000UL;
    00276
    00277     pthread_cond_timedwait(&ctx->fps_cond, &ctx->fps_lock,
    00278                 &last_decode_time);
    00279     pthread_mutex_unlock(&ctx->fps_lock);
    00280
    00281     return 1;
    00282 }
    00283
    00284 static bool
    00285 conv_output_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00286                                    NvBuffer * buffer, NvBuffer * shared_buffer,
    00287                                    void *arg)
    00288 {
    00289     context_t *ctx = (context_t *) arg;
    00290     struct v4l2_buffer dec_capture_ret_buffer;
    00291     struct v4l2_plane planes[MAX_PLANES];
    00292
    00293     memset(&dec_capture_ret_buffer, 0, sizeof(dec_capture_ret_buffer));
    00294     memset(planes, 0, sizeof(planes));
    00295
    00296     dec_capture_ret_buffer.index = shared_buffer->index;
    00297     dec_capture_ret_buffer.m.planes = planes;
    00298
    00299     pthread_mutex_lock(&ctx->queue_lock);
    00300     ctx->conv_output_plane_buf_queue->push(buffer);
    00301
    00302     // Return the buffer dequeued from converter output plane
    00303     // back to decoder capture plane
    00304     if (ctx->dec->capture_plane.qBuffer(dec_capture_ret_buffer, NULL) < 0)
    00305     {
    00306         pthread_cond_broadcast(&ctx->queue_cond);
    00307         pthread_mutex_unlock(&ctx->queue_lock);
    00308         return false;
    00309     }
    00310
    00311     pthread_cond_broadcast(&ctx->queue_cond);
    00312     pthread_mutex_unlock(&ctx->queue_lock);
    00313
    00314     return true;
    00315 }
    00316
    00317 #ifdef ENABLE_GIE
    00318 static bool
    00319 conv1_output_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00320                                    NvBuffer * buffer, NvBuffer * shared_buffer,
    00321                                    void *arg)
    00322 {
    00323     context_t *ctx = (context_t *) arg;
    00324
    00325     pthread_mutex_lock(&ctx->queue1_lock);
    00326     ctx->conv1_output_plane_buf_queue->push(buffer);
    00327
    00328     pthread_cond_broadcast(&ctx->queue1_cond);
    00329     pthread_mutex_unlock(&ctx->queue1_lock);
    00330
    00331     return true;
    00332 }
    00333 #endif
    00334
    00335 static void *render_thread(void* arg)
    00336 {
    00337     context_t *ctx = (context_t *) arg;
    00338     Shared_Buffer gie_buffer;
    00339 #ifdef ENABLE_GIE
    00340     frame_bbox *bbox = NULL;
    00341     frame_bbox temp_bbox;
    00342     temp_bbox.g_rect_num = 0;
    00343     temp_bbox.g_rect = new NvOSD_RectParams[OSD_BUF_NUM];
    00344 #endif
    00345     while (1)
    00346     {
    00347         // waiting for buffer to come
    00348         pthread_mutex_lock(&ctx->render_lock);
    00349         if (ctx->render_buf_queue->empty())
    00350         {
    00351             if (ctx->stop_render)
    00352             {
    00353                 pthread_mutex_unlock(&ctx->render_lock);
    00354                 break;
    00355             }
    00356             else
    00357             {
    00358                 // wait 3 s for frame to come
    00359                 struct timespec timeout;
    00360                 timeout.tv_sec = time(0) + 3;
    00361                 timeout.tv_nsec = 0;
    00362                 int ret = pthread_cond_timedwait(&ctx->render_cond,
    00363                                         &ctx->render_lock, &timeout);
    00364                 // if no signal come in 3s, exit.
    00365                 if (ret != 0)
    00366                 {
    00367                     pthread_mutex_unlock(&ctx->render_lock);
    00368                     break;
    00369                 }
    00370                 // if no buffer come, we can exit now.
    00371                 if (ctx->render_buf_queue->empty())
    00372                 {
    00373                     pthread_mutex_unlock(&ctx->render_lock);
    00374                     break;
    00375                 }
    00376             }
    00377         }
    00378         //pop up buffer from queue to process
    00379         gie_buffer = ctx->render_buf_queue->front();
    00380         ctx->render_buf_queue->pop();
    00381         pthread_mutex_unlock(&ctx->render_lock);
    00382
    00383         struct v4l2_buffer *v4l2_buf = &gie_buffer.v4l2_buf;
    00384         NvBuffer *buffer             = gie_buffer.buffer;
    00385
    00386         if (ctx->cpu_occupation_option != PARSER_DECODER_VIC)
    00387         {
    00388 #ifndef ENABLE_GIE
    00389             // Create EGLImage from dmabuf fd
    00390             ctx->egl_image = NvEGLImageFromFd(egl_display,
    00391                                                 buffer->planes[0].fd);
    00392             if (ctx->egl_image == NULL)
    00393             {
    00394                 cerr << "Error while mapping dmabuf fd (" <<
    00395                         buffer->planes[0].fd << ") to EGLImage" << endl;
    00396                 return NULL;
    00397             }
    00398
    00399             // Running algo process with EGLImage via GPU multi cores
    00400             HandleEGLImage(&ctx->egl_image);
    00401
    00402             // Destroy EGLImage
    00403             NvDestroyEGLImage(egl_display, ctx->egl_image);
    00404             ctx->egl_image = NULL;
    00405 #else
    00406             // Render thread is waiting for result, wait here
    00407             if (gie_buffer.bProcess  == 1)
    00408             {
    00409                 sem_wait(&ctx->result_ready_sem);
    00410                 pthread_mutex_lock(&ctx->osd_lock);
    00411                 if (ctx->osd_queue->size() != 0)
    00412                 {
    00413                     bbox = ctx->osd_queue->front();
    00414                     if (bbox != NULL)
    00415                     {
    00416                         temp_bbox.g_rect_num = bbox->g_rect_num;
    00417                         memcpy(temp_bbox.g_rect, bbox->g_rect,
    00418                             OSD_BUF_NUM * sizeof(NvOSD_RectParams));
    00419                         delete []bbox->g_rect;
    00420                         delete bbox;
    00421                         bbox = NULL;
    00422                     }
    00423                     ctx->osd_queue->pop();
    00424                 }
    00425                 pthread_mutex_unlock(&ctx->osd_lock);
    00426             }
    00427
    00428             if (temp_bbox.g_rect_num != 0)
    00429             {
    00430                 nvosd_draw_rectangles(ctx->nvosd_context, MODE_HW,
    00431                     buffer->planes[0].fd, temp_bbox.g_rect_num, temp_bbox.g_rect);
    00432             }
    00433 #endif
    00434             // EglRenderer requires the fd of the 0th plane to render
    00435             ctx->renderer->render(buffer->planes[0].fd);
    00436             // Write raw video frame to file and return the buffer to converter
    00437             // capture plane
    00438             if (ctx->out_file)
    00439                 write_video_frame(ctx->out_file, *buffer);
    00440         }
    00441
    00442         if (ctx->conv->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
    00443         {
    00444             return NULL;
    00445         }
    00446     }
    00447 #ifdef ENABLE_GIE
    00448     delete []temp_bbox.g_rect;
    00449 #endif
    00450     return NULL;
    00451 }
    00452
    00453 static bool
    00454 conv_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00455                                     NvBuffer * buffer,
    00456                                     NvBuffer * shared_buffer,
    00457                                     void *arg)
    00458 {
    00459     context_t *ctx = (context_t *) arg;
    00460     Shared_Buffer batch_buffer;
    00461     batch_buffer.bProcess = 0;
    00462 #ifdef ENABLE_GIE
    00463     // here we only queue buffer for GIE process to conv1
    00464     if (ctx->channel < g_gie_context.getNumGieInstances() &&
    00465             (frame_num++ % g_gie_context.getFilterNum()) == 0)
    00466     {
    00467         int ret;
    00468         struct v4l2_buffer conv_capture_ret_buffer;
    00469         struct v4l2_plane planes[MAX_PLANES];
    00470
    00471         memset(&conv_capture_ret_buffer, 0, sizeof(conv_capture_ret_buffer));
    00472         memset(planes, 0, sizeof(planes));
    00473
    00474         NvBuffer *conv1_buffer;
    00475         pthread_mutex_lock(&ctx->queue1_lock);
    00476         while (ctx->conv1_output_plane_buf_queue->empty())
    00477         {
    00478             pthread_cond_wait(&ctx->queue1_cond, &ctx->queue1_lock);
    00479         }
    00480         conv1_buffer = ctx->conv1_output_plane_buf_queue->front();
    00481         ctx->conv1_output_plane_buf_queue->pop();
    00482         pthread_mutex_unlock(&ctx->queue1_lock);
    00483         conv_capture_ret_buffer.index = conv1_buffer->index;
    00484         conv_capture_ret_buffer.m.planes = planes;
    00485
    00486         ret = ctx->conv1->output_plane.qBuffer(conv_capture_ret_buffer,
    00487                 buffer);
    00488         if (ret < 0)
    00489         {
    00490             ctx->got_error = true;
    00491             return false;
    00492         }
    00493         batch_buffer.bProcess = 1;
    00494     }
    00495 #endif
    00496
    00497     // v4l2_buf is local in the DQthread and exists in the scope of the callback
    00498     // function only and not in the entire application. The application has to
    00499     // copy this for using at out of the callback.
    00500     memcpy(&batch_buffer.v4l2_buf, v4l2_buf, sizeof(v4l2_buffer));
    00501
    00502     batch_buffer.buffer = buffer;
    00503     batch_buffer.shared_buffer = shared_buffer;
    00504     batch_buffer.arg = arg;
    00505     pthread_mutex_lock(&ctx->render_lock);
    00506     ctx->render_buf_queue->push(batch_buffer);
    00507     pthread_cond_broadcast(&ctx->render_cond);
    00508     pthread_mutex_unlock(&ctx->render_lock);
    00509
    00510     return true;
    00511 }
    00512
    00513
    00514 #ifdef ENABLE_GIE
    00515 void *gie_thread(void *data)
    00516 {
    00517     int buf_num = 0;
    00518     EGLImageKHR egl_image = NULL;
    00519     struct v4l2_buffer *v4l2_buf;
    00520     NvBuffer *buffer;
    00521     NvBuffer *shared_buffer;
    00522     context_t *ctx;
    00523     int process_last_batch = 0;
    00524     float *gie_inputbuf = g_gie_context.getInputBuf();
    00525
    00526     while (1)
    00527     {
    00528         // wait for buffer for process to come
    00529         Shared_Buffer gie_buffer;
    00530         pthread_mutex_lock(&GIE_lock);
    00531         if(GIE_Buffer_Queue.empty())
    00532         {
    00533             if (GIE_Stop)
    00534             {
    00535                 pthread_mutex_unlock(&GIE_lock);
    00536                 break;
    00537             }
    00538             else
    00539             {
    00540                 // wait 3 s for frame to come
    00541                 struct timespec timeout;
    00542                 timeout.tv_sec = time(0) + 3;
    00543                 timeout.tv_nsec = 0;
    00544                 int ret =
    00545                     pthread_cond_timedwait(&GIE_cond, &GIE_lock, &timeout);
    00546                 if (ret != 0)
    00547                 {
    00548                     cout << "Timedout waiting for input data"<<endl;
    00549                 }
    00550             }
    00551         }
    00552         if (GIE_Buffer_Queue.size() != 0)
    00553         {
    00554             gie_buffer = GIE_Buffer_Queue.front();
    00555             GIE_Buffer_Queue.pop();
    00556         }
    00557         else
    00558         {
    00559             process_last_batch = 1;
    00560         }
    00561         pthread_mutex_unlock(&GIE_lock);
    00562         // we still have buffer, so accumulate buffer into batch
    00563         if (process_last_batch == 0)
    00564         {
    00565             v4l2_buf           = &gie_buffer.v4l2_buf;
    00566             buffer             = gie_buffer.buffer;
    00567             shared_buffer      = gie_buffer.shared_buffer;
    00568             ctx                = (context_t *)gie_buffer.arg;
    00569
    00570             int batch_offset = buf_num  * g_gie_context.getNetWidth() *
    00571                 g_gie_context.getNetHeight() * g_gie_context.getChannel();
    00572 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    00573             // copy with CPU is much slower than GPU
    00574             // but still keep it just in case customer want to save GPU
    00575             //generate input buffer for first time
    00576             unsigned char *data = buffer->planes[0].data;
    00577             int channel_offset = g_gie_context.getNetWidth() *
    00578                             g_gie_context.getNetHeight();
    00579             // copy buffer into input_buf
    00580             for (int i = 0; i < g_gie_context.getChannel(); i++)
    00581             {
    00582                 for (int j = 0; j < g_gie_context.getNetHeight(); j++)
    00583                 {
    00584                     for (int k = 0; k < g_gie_context.getNetWidth(); k++)
    00585                     {
    00586                         int total_offset = batch_offset + channel_offset * i +
    00587                             j * g_gie_context.getNetWidth() + k;
    00588                         gie_inputbuf[total_offset] =
    00589                             (float)(*(data + j * buffer->planes[0].fmt.stride
    00590                             + k * 4 + 3 - i - 1));
    00591                     }
    00592                 }
    00593             }
    00594 #else
    00595             // map fd into EGLImage, then copy it with GPU in parallel
    00596             // Create EGLImage from dmabuf fd
    00597             egl_image = NvEGLImageFromFd(egl_display,
    00598                                             buffer->planes[0].fd);
    00599             if (egl_image == NULL)
    00600             {
    00601                 cerr << "Error while mapping dmabuf fd (" <<
    00602                     buffer->planes[0].fd << ") to EGLImage" << endl;
    00603                 return NULL;
    00604             }
    00605
    00606             void *cuda_buf = g_gie_context.getBuffer(0);
    00607             // map eglimage into GPU address
    00608             mapEGLImage2Float(&egl_image,  g_gie_context.getNetWidth(),
    00609                 g_gie_context.getNetHeight(),
    00610                 (char *)cuda_buf +
    00611                 batch_offset * sizeof(float));
    00612
    00613             // Destroy EGLImage
    00614             NvDestroyEGLImage(egl_display, egl_image);
    00615             egl_image = NULL;
    00616 #endif
    00617             buf_num++;
    00618             // now we push it to capture plane to let v4l2 go on
    00619             if (ctx->conv1->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
    00620             {
    00621                 cout<<"conv1 queue buffer error"<<endl;
    00622             }
    00623             // buffer is not enough for a batch, continue to wait for buffer
    00624             if (buf_num < g_gie_context.getBatchSize())
    00625             {
    00626                 continue;
    00627             }
    00628         }
    00629         // if framenum equal batch_size * n
    00630         else if(buf_num == 0)
    00631         {
    00632             break;
    00633         }
    00634
    00635         // buffer comes, we begin to inference
    00636         buf_num = 0;
    00637         queue<vector<cv::Rect>> rectList_queue;
    00638 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    00639         g_gie_context.doInference(
    00640             rectList_queue, gie_inputbuf);
    00641 #else
    00642         g_gie_context.doInference(
    00643             rectList_queue);
    00644 #endif
    00645
    00646         while(!rectList_queue.empty())
    00647         {
    00648             vector<cv::Rect> rectList = rectList_queue.front();
    00649             rectList_queue.pop();
    00650             frame_bbox *bbox = new frame_bbox;
    00651             bbox->g_rect_num = 0;
    00652             bbox->g_rect = new NvOSD_RectParams[OSD_BUF_NUM];
    00653             for (int i = 0; i < rectList.size(); i++)
    00654             {
    00655                 cv::Rect &r = rectList[i];
    00656                 if ((r.width * IMAGE_WIDTH / g_gie_context.getNetWidth() < 10) ||
    00657                     (r.height * IMAGE_HEIGHT / g_gie_context.getNetHeight() < 10))
    00658                     continue;
    00659                 bbox->g_rect[bbox->g_rect_num].left =
    00660                     (unsigned int) (r.x * IMAGE_WIDTH / g_gie_context.getNetWidth());
    00661                 bbox->g_rect[bbox->g_rect_num].top =
    00662                     (unsigned int) (r.y * IMAGE_HEIGHT / g_gie_context.getNetHeight());
    00663                 bbox->g_rect[bbox->g_rect_num].width =
    00664                     (unsigned int) (r.width * IMAGE_WIDTH / g_gie_context.getNetWidth());
    00665                 bbox->g_rect[bbox->g_rect_num].height =
    00666                     (unsigned int) (r.height * IMAGE_HEIGHT / g_gie_context.getNetHeight());
    00667
    00668                 bbox->g_rect[bbox->g_rect_num].border_width = 5;
    00669                 bbox->g_rect[bbox->g_rect_num].has_bg_color = 0;
    00670                 bbox->g_rect[bbox->g_rect_num].border_color.red = 1.0f;
    00671                 bbox->g_rect[bbox->g_rect_num].border_color.green = 0.0;
    00672                 bbox->g_rect[bbox->g_rect_num].border_color.blue = 0.0;
    00673                 bbox->g_rect_num++;
    00674             }
    00675             pthread_mutex_lock(&ctx->osd_lock);
    00676             ctx->osd_queue->push(bbox);
    00677             pthread_mutex_unlock(&ctx->osd_lock);
    00678             //GIE has prepared result, notify here
    00679             sem_post(&ctx->result_ready_sem);
    00680         }
    00681         if (process_last_batch == 1)
    00682         {
    00683             break;
    00684         }
    00685     }
    00686
    00687     return NULL;
    00688 }
    00689
    00690 static bool
    00691 conv1_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00692                                     NvBuffer *buffer,
    00693                                     NvBuffer *shared_buffer,
    00694                                     void *arg)
    00695 {
    00696     //push buffer to process queue
    00697     Shared_Buffer gie_buffer;
    00698
    00699     // v4l2_buf is local in the DQthread and exists in the scope of the callback
    00700     // function only and not in the entire application. The application has to
    00701     // copy this for using at out of the callback.
    00702     memcpy(&gie_buffer.v4l2_buf, v4l2_buf, sizeof(v4l2_buffer));
    00703
    00704     gie_buffer.buffer = buffer;
    00705     gie_buffer.shared_buffer = shared_buffer;
    00706     gie_buffer.arg = arg;
    00707     pthread_mutex_lock(&GIE_lock);
    00708     GIE_Buffer_Queue.push(gie_buffer);
    00709     pthread_cond_broadcast(&GIE_cond);
    00710     pthread_mutex_unlock(&GIE_lock);
    00711
    00712     return true;
    00713 }
    00714 #endif
    00715
    00716 static void
    00717 query_and_set_capture(context_t * ctx)
    00718 {
    00719     NvVideoDecoder *dec = ctx->dec;
    00720     struct v4l2_format format;
    00721     struct v4l2_crop crop;
    00722     int32_t min_dec_capture_buffers;
    00723     int ret = 0;
    00724     int error = 0;
    00725     uint32_t window_width;
    00726     uint32_t window_height;
    00727     char OSDcontent[512];
    00728
    00729     // Get capture plane format from the decoder. This may change after
    00730     // an resolution change event
    00731     ret = dec->capture_plane.getFormat(format);
    00732     TEST_ERROR(ret < 0,
    00733             "Error: Could not get format from decoder capture plane", error);
    00734
    00735     // Get the display resolution from the decoder
    00736     ret = dec->capture_plane.getCrop(crop);
    00737     TEST_ERROR(ret < 0,
    00738            "Error: Could not get crop from decoder capture plane", error);
    00739
    00740     if (ctx->cpu_occupation_option == PARSER_DECODER_VIC_RENDER)
    00741     {
    00742         // Destroy the old instance of renderer as resolution might changed
    00743         delete ctx->renderer;
    00744
    00745         if (ctx->fullscreen)
    00746         {
    00747             // Required for fullscreen
    00748             window_width = window_height = 0;
    00749         }
    00750         else if (ctx->window_width && ctx->window_height)
    00751         {
    00752             // As specified by user on commandline
    00753             window_width = ctx->window_width;
    00754             window_height = ctx->window_height;
    00755         }
    00756         else
    00757         {
    00758             // Resolution got from the decoder
    00759             window_width = crop.c.width;
    00760             window_height = crop.c.height;
    00761         }
    00762
    00763         // If height or width are set to zero, EglRenderer creates a fullscreen
    00764         // window
    00765         ctx->renderer =
    00766             NvEglRenderer::createEglRenderer("renderer0", window_width,
    00767                                            window_height, ctx->window_x,
    00768                                            ctx->window_y);
    00769         TEST_ERROR(!ctx->renderer,
    00770                    "Error in setting up renderer. "
    00771                    "Check if X is running or run with --disable-rendering",
    00772                    error);
    00773
    00774         ctx->renderer->setFPS(ctx->fps);
    00775 #ifndef ENABLE_GIE
    00776         sprintf(OSDcontent, "Channel:%d", ctx->channel);
    00777         ctx->renderer->setOverlayText(OSDcontent, 800, 50);
    00778 #endif
    00779     }
    00780
    00781     // deinitPlane unmaps the buffers and calls REQBUFS with count 0
    00782     dec->capture_plane.deinitPlane();
    00783
    00784     // Not necessary to call VIDIOC_S_FMT on decoder capture plane.
    00785     // But decoder setCapturePlaneFormat function updates the class variables
    00786     ret = dec->setCapturePlaneFormat(format.fmt.pix_mp.pixelformat,
    00787                                      format.fmt.pix_mp.width,
    00788                                      format.fmt.pix_mp.height);
    00789     TEST_ERROR(ret < 0, "Error in setting decoder capture plane format",
    00790                 error);
    00791
    00792     // Get the minimum buffers which have to be requested on the capture plane
    00793     ret =
    00794         dec->getControl(V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
    00795                         min_dec_capture_buffers);
    00796     TEST_ERROR(ret < 0,
    00797                "Error while getting value for V4L2_CID_MIN_BUFFERS_FOR_CAPTURE",
    00798                error);
    00799
    00800     // Request (min + 5) buffers, export and map buffers
    00801     ret =
    00802         dec->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00803                                        min_dec_capture_buffers + 5, false,
    00804                                        false);
    00805     TEST_ERROR(ret < 0, "Error in decoder capture plane setup", error);
    00806
    00807     // For file write, first deinitialize output and capture planes
    00808     // of video converter and then use the new resolution from
    00809     // decoder event resolution change
    00810     ctx->conv->waitForIdle(1000);
    00811     ctx->conv->output_plane.stopDQThread();
    00812     ctx->conv->capture_plane.stopDQThread();
    00813
    00814     ctx->conv->output_plane.deinitPlane();
    00815     ctx->conv->capture_plane.deinitPlane();
    00816 #ifdef ENABLE_GIE
    00817     if (ctx->channel < g_gie_context.getNumGieInstances())
    00818     {
    00819         ctx->conv1->waitForIdle(1000);
    00820         ctx->conv1->output_plane.stopDQThread();
    00821         ctx->conv1->capture_plane.stopDQThread();
    00822
    00823         ctx->conv1->output_plane.deinitPlane();
    00824         ctx->conv1->capture_plane.deinitPlane();
    00825     }
    00826 #endif
    00827     while(!ctx->conv_output_plane_buf_queue->empty())
    00828     {
    00829         ctx->conv_output_plane_buf_queue->pop();
    00830     }
    00831 #ifdef ENABLE_GIE
    00832     if (ctx->channel < g_gie_context.getNumGieInstances())
    00833     {
    00834         while(!ctx->conv1_output_plane_buf_queue->empty())
    00835         {
    00836             ctx->conv1_output_plane_buf_queue->pop();
    00837         }
    00838     }
    00839 #endif
    00840     ret = ctx->conv->setOutputPlaneFormat(format.fmt.pix_mp.pixelformat,
    00841                                             format.fmt.pix_mp.width,
    00842                                             format.fmt.pix_mp.height,
    00843                                             V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
    00844     TEST_ERROR(ret < 0, "Error in converter output plane set format",
    00845                 error);
    00846
    00847     ret = ctx->conv->setCapturePlaneFormat(format.fmt.pix_mp.pixelformat,
    00848                                             crop.c.width,
    00849                                             crop.c.height,
    00850                                             V4L2_NV_BUFFER_LAYOUT_PITCH);
    00851     TEST_ERROR(ret < 0, "Error in converter capture plane set format",
    00852                 error);
    00853
    00854     ret = ctx->conv->setCropRect(0, 0, crop.c.width, crop.c.height);
    00855     TEST_ERROR(ret < 0, "Error while setting crop rect", error);
    00856
    00857 #ifdef ENABLE_GIE
    00858     if (ctx->channel < g_gie_context.getNumGieInstances())
    00859     {
    00860         ret = ctx->conv1->setOutputPlaneFormat(format.fmt.pix_mp.pixelformat,
    00861                                             crop.c.width,
    00862                                             crop.c.height,
    00863                                             V4L2_NV_BUFFER_LAYOUT_PITCH);
    00864         TEST_ERROR(ret < 0, "Error in converter output plane set format",
    00865                 error);
    00866
    00867         ret = ctx->conv1->setCapturePlaneFormat(V4L2_PIX_FMT_ABGR32,
    00868                                             g_gie_context.getNetWidth(),
    00869                                             g_gie_context.getNetHeight(),
    00870                                             V4L2_NV_BUFFER_LAYOUT_PITCH);
    00871         TEST_ERROR(ret < 0, "Error in converter capture plane set format",
    00872                 error);
    00873     }
    00874 #endif
    00875
    00876     ret =
    00877         ctx->conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF,
    00878                                             dec->capture_plane.
    00879                                             getNumBuffers(), false, false);
    00880     TEST_ERROR(ret < 0, "Error in converter output plane setup", error);
    00881
    00882     ret =
    00883         ctx->conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00884                                                  dec->capture_plane.
    00885                                                  getNumBuffers(), true, false);
    00886     TEST_ERROR(ret < 0, "Error in converter capture plane setup", error);
    00887 #ifdef ENABLE_GIE
    00888     if (ctx->channel < g_gie_context.getNumGieInstances())
    00889     {
    00890         ret =
    00891             ctx->conv1->output_plane.setupPlane(V4L2_MEMORY_DMABUF,
    00892                                             dec->capture_plane.
    00893                                             getNumBuffers(), false, false);
    00894         TEST_ERROR(ret < 0, "Error in converter output plane setup", error);
    00895
    00896         ret =
    00897             ctx->conv1->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00898                                                  dec->capture_plane.
    00899                                                  getNumBuffers(), true, false);
    00900         TEST_ERROR(ret < 0, "Error in converter capture plane setup", error);
    00901     }
    00902 #endif
    00903     ret = ctx->conv->output_plane.setStreamStatus(true);
    00904     TEST_ERROR(ret < 0, "Error in converter output plane streamon", error);
    00905
    00906     ret = ctx->conv->capture_plane.setStreamStatus(true);
    00907     TEST_ERROR(ret < 0, "Error in converter output plane streamoff",
    00908                 error);
    00909 #ifdef ENABLE_GIE
    00910     if (ctx->channel < g_gie_context.getNumGieInstances())
    00911     {
    00912         ret = ctx->conv1->output_plane.setStreamStatus(true);
    00913         TEST_ERROR(ret < 0, "Error in converter output plane streamon", error);
    00914
    00915         ret = ctx->conv1->capture_plane.setStreamStatus(true);
    00916         TEST_ERROR(ret < 0, "Error in converter output plane streamoff",
    00917                 error);
    00918     }
    00919 #endif
    00920     // Add all empty conv output plane buffers to conv_output_plane_buf_queue
    00921     for (uint32_t i = 0; i < ctx->conv->output_plane.getNumBuffers(); i++)
    00922     {
    00923         ctx->conv_output_plane_buf_queue->push(ctx->conv->output_plane.
    00924                 getNthBuffer(i));
    00925     }
    00926
    00927 #ifdef ENABLE_GIE
    00928     if (ctx->channel < g_gie_context.getNumGieInstances())
    00929     {
    00930         // Add all empty conv1 output plane buffers to conv1_output_plane_buf_queue
    00931         for (uint32_t i = 0; i < ctx->conv1->output_plane.getNumBuffers(); i++)
    00932         {
    00933             ctx->conv1_output_plane_buf_queue->push(ctx->conv1->output_plane.
    00934                     getNthBuffer(i));
    00935         }
    00936     }
    00937 #endif
    00938     for (uint32_t i = 0; i < ctx->conv->capture_plane.getNumBuffers(); i++)
    00939     {
    00940         struct v4l2_buffer v4l2_buf;
    00941         struct v4l2_plane planes[MAX_PLANES];
    00942
    00943         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00944         memset(planes, 0, sizeof(planes));
    00945
    00946         v4l2_buf.index = i;
    00947         v4l2_buf.m.planes = planes;
    00948         ret = ctx->conv->capture_plane.qBuffer(v4l2_buf, NULL);
    00949         TEST_ERROR(ret < 0, "Error Qing buffer at converter output plane",
    00950                     error);
    00951     }
    00952
    00953 #ifdef ENABLE_GIE
    00954     if (ctx->channel < g_gie_context.getNumGieInstances())
    00955     {
    00956         for (uint32_t i = 0; i < ctx->conv1->capture_plane.getNumBuffers();
    00957             i++)
    00958         {
    00959             struct v4l2_buffer v4l2_buf;
    00960             struct v4l2_plane planes[MAX_PLANES];
    00961
    00962             memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00963             memset(planes, 0, sizeof(planes));
    00964
    00965             v4l2_buf.index = i;
    00966             v4l2_buf.m.planes = planes;
    00967             ret = ctx->conv1->capture_plane.qBuffer(v4l2_buf, NULL);
    00968             TEST_ERROR(ret < 0, "Error Qing buffer at converter output plane",
    00969                     error);
    00970         }
    00971     }
    00972 #endif
    00973     ctx->conv->output_plane.startDQThread(ctx);
    00974     ctx->conv->capture_plane.startDQThread(ctx);
    00975 #ifdef ENABLE_GIE
    00976     if (ctx->channel < g_gie_context.getNumGieInstances())
    00977     {
    00978         ctx->conv1->output_plane.startDQThread(ctx);
    00979         ctx->conv1->capture_plane.startDQThread(ctx);
    00980     }
    00981 #endif
    00982     // Capture plane STREAMON
    00983     ret = dec->capture_plane.setStreamStatus(true);
    00984     TEST_ERROR(ret < 0, "Error in decoder capture plane streamon", error);
    00985
    00986     // Enqueue all the empty capture plane buffers
    00987     for (uint32_t i = 0; i < dec->capture_plane.getNumBuffers(); i++)
    00988     {
    00989         struct v4l2_buffer v4l2_buf;
    00990         struct v4l2_plane planes[MAX_PLANES];
    00991
    00992         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00993         memset(planes, 0, sizeof(planes));
    00994
    00995         v4l2_buf.index = i;
    00996         v4l2_buf.m.planes = planes;
    00997         ret = dec->capture_plane.qBuffer(v4l2_buf, NULL);
    00998         TEST_ERROR(ret < 0, "Error Qing buffer at output plane", error);
    00999     }
    01000     cout << "Query and set capture  successful" << endl;
    01001     return;
    01002
    01003 error:
    01004     if (error)
    01005     {
    01006         ctx->got_error = true;
    01007         cerr << "Error in " << __func__ << endl;
    01008     }
    01009 }
    01010
    01011 static void *
    01012 dec_capture_loop_fcn(void *arg)
    01013 {
    01014     context_t *ctx = (context_t *) arg;
    01015     NvVideoDecoder *dec = ctx->dec;
    01016     map<uint64_t, frame_info_t*>::iterator  iter;
    01017     struct v4l2_event ev;
    01018     int ret;
    01019
    01020     cout << "Starting decoder capture loop thread" << endl;
    01021     // Need to wait for the first Resolution change event, so that
    01022     // the decoder knows the stream resolution and can allocate appropriate
    01023     // buffers when we call REQBUFS
    01024     do
    01025     {
    01026         ret = dec->dqEvent(ev, 1000);
    01027         if (ret < 0)
    01028         {
    01029             if (errno == EAGAIN)
    01030             {
    01031                 cerr <<
    01032                     "Timed out waiting for first V4L2_EVENT_RESOLUTION_CHANGE"
    01033                     << endl;
    01034             }
    01035             else
    01036             {
    01037                 cerr << "Error in dequeueing decoder event" << endl;
    01038             }
    01039             ctx->got_error = true;
    01040             break;
    01041         }
    01042     }
    01043     while (ev.type != V4L2_EVENT_RESOLUTION_CHANGE);
    01044
    01045     // query_and_set_capture acts on the resolution change event
    01046     if (!ctx->got_error)
    01047         query_and_set_capture(ctx);
    01048
    01049     // Exit on error or EOS which is signalled in main()
    01050     while (!(ctx->got_error || dec->isInError() || ctx->got_eos))
    01051     {
    01052         NvBuffer *dec_buffer;
    01053
    01054         // Check for Resolution change again
    01055         ret = dec->dqEvent(ev, false);
    01056         if (ret == 0)
    01057         {
    01058             switch (ev.type)
    01059             {
    01060                 case V4L2_EVENT_RESOLUTION_CHANGE:
    01061                     query_and_set_capture(ctx);
    01062                     continue;
    01063             }
    01064         }
    01065
    01066         while (1)
    01067         {
    01068             struct v4l2_buffer v4l2_buf;
    01069             struct v4l2_plane planes[MAX_PLANES];
    01070
    01071             memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    01072             memset(planes, 0, sizeof(planes));
    01073             v4l2_buf.m.planes = planes;
    01074
    01075             // Dequeue a filled buffer
    01076             if (dec->capture_plane.dqBuffer(v4l2_buf, &dec_buffer, NULL, 0))
    01077             {
    01078                 if (errno == EAGAIN)
    01079                 {
    01080                     usleep(1000);
    01081                 }
    01082                 else
    01083                 {
    01084                     ctx->got_error = true;
    01085                     cerr << "Error while calling dequeue at capture plane" <<
    01086                         endl;
    01087                 }
    01088                 break;
    01089             }
    01090
    01091             if (ctx->do_stat)
    01092             {
    01093                 iter = ctx->frame_info_map->find(v4l2_buf.timestamp.tv_sec);
    01094                 if (iter == ctx->frame_info_map->end())
    01095                 {
    01096                     cout<<"image not return by decoder"<<endl;
    01097                 }
    01098                 else
    01099                 {
    01100                     gettimeofday(&iter->second->output_time, NULL);
    01101                 }
    01102             }
    01103
    01104             if (ctx->cpu_occupation_option == PARSER_DECODER)
    01105             {
    01106                 // Queue the buffer back once it has been used.
    01107                 if (dec->capture_plane.qBuffer(v4l2_buf, NULL) < 0)
    01108                 {
    01109                     ctx->got_error = true;
    01110                     cerr <<
    01111                         "Error while queueing buffer at decoder capture plane"
    01112                         << endl;
    01113                     break;
    01114                 }
    01115                 continue;
    01116             }
    01117             // If we need to write to file, give the buffer to video converter output plane
    01118             // instead of returning the buffer back to decoder capture plane
    01119             NvBuffer *conv_buffer;
    01120             struct v4l2_buffer conv_output_buffer;
    01121             struct v4l2_plane conv_planes[MAX_PLANES];
    01122
    01123             memset(&conv_output_buffer, 0, sizeof(conv_output_buffer));
    01124             memset(conv_planes, 0, sizeof(conv_planes));
    01125             conv_output_buffer.m.planes = conv_planes;
    01126
    01127             // Get an empty conv output plane buffer from conv_output_plane_buf_queue
    01128             pthread_mutex_lock(&ctx->queue_lock);
    01129             while (ctx->conv_output_plane_buf_queue->empty())
    01130             {
    01131                 pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
    01132             }
    01133             conv_buffer = ctx->conv_output_plane_buf_queue->front();
    01134             ctx->conv_output_plane_buf_queue->pop();
    01135             pthread_mutex_unlock(&ctx->queue_lock);
    01136
    01137             conv_output_buffer.index = conv_buffer->index;
    01138
    01139             if (ctx->conv->output_plane.
    01140                 qBuffer(conv_output_buffer, dec_buffer) < 0)
    01141             {
    01142                 ctx->got_error = true;
    01143                 cerr <<
    01144                     "Error while queueing buffer at converter output plane"
    01145                     << endl;
    01146                 break;
    01147             }
    01148
    01149         }
    01150     }
    01151
    01152     cout << "Exiting decoder capture loop thread" << endl;
    01153     // Signal EOS to the decoder capture loop
    01154     ctx->got_eos = true;
    01155
    01156     //Signal VIC to wait EOS
    01157     sem_post(&(ctx->dec_run_sem));
    01158     return NULL;
    01159 }
    01160
    01161 static void *
    01162 dec_feed_loop_fcn(void *arg)
    01163 {
    01164     context_t *ctx = (context_t *) arg;
    01165     int i = 0;
    01166     bool eos = false;
    01167     int ret;
    01168     char *nalu_parse_buffer = NULL;
    01169     nal_type_e nal_type;
    01170
    01171     if (ctx->input_nalu)
    01172     {
    01173         nalu_parse_buffer = new char[CHUNK_SIZE];
    01174     }
    01175
    01176     // Read encoded data and enqueue all the output plane buffers.
    01177     // Exit loop in case file read is complete.
    01178     while (!eos && !ctx->got_error && !ctx->dec->isInError() &&
    01179         i < (int)ctx->dec->output_plane.getNumBuffers())
    01180     {
    01181         struct v4l2_buffer v4l2_buf;
    01182         struct v4l2_plane planes[MAX_PLANES];
    01183         NvBuffer *buffer;
    01184
    01185         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    01186         memset(planes, 0, sizeof(planes));
    01187
    01188         buffer = ctx->dec->output_plane.getNthBuffer(i);
    01189         if (ctx->input_nalu)
    01190         {
    01191             read_decoder_input_nalu(ctx->in_file, buffer,
    01192                     nalu_parse_buffer, CHUNK_SIZE);
    01193             wait_for_nextFrame(ctx);
    01194             if (ctx->cpu_occupation_option == PARSER)
    01195             {
    01196                 if (buffer->planes[0].bytesused == 0)
    01197                 {
    01198                     cout<<"Input file read complete"<<endl;
    01199                     //Signal VIC to wait EOS
    01200                     sem_post(&(ctx->dec_run_sem));
    01201                     return NULL;
    01202                 }
    01203                 else
    01204                     continue;
    01205             }
    01206         }
    01207         else
    01208         {
    01209             read_decoder_input_chunk(ctx->in_file, buffer);
    01210         }
    01211
    01212         v4l2_buf.index = i;
    01213         if (ctx->input_nalu && ctx->do_stat)
    01214         {
    01215             nal_type = parse_nalu_unit(buffer);
    01216             switch (nal_type)
    01217             {
    01218                 case NAL_UNIT_CODED_SLICE:
    01219                 case NAL_UNIT_CODED_SLICE_DATAPART_A:
    01220                 case NAL_UNIT_CODED_SLICE_DATAPART_B:
    01221                 case NAL_UNIT_CODED_SLICE_DATAPART_C:
    01222                 case NAL_UNIT_CODED_SLICE_IDR:
    01223                 {
    01224                     assign_decode_ts(&v4l2_buf, ctx->channel);
    01225                     frame_info_t *frame_meta = new frame_info_t;
    01226                     memset(frame_meta, 0, sizeof(frame_info_t));
    01227
    01228                     frame_meta->timestamp = v4l2_buf.timestamp.tv_sec;
    01229                     gettimeofday(&frame_meta->input_time, NULL);
    01230                     frame_meta->nal_type = nal_type;
    01231
    01232                     ctx->frame_info_map->insert(
    01233                         pair< uint64_t, frame_info_t* >(
    01234                         v4l2_buf.timestamp.tv_sec, frame_meta));
    01235                     break;
    01236                 }
    01237                 default:
    01238                     break;
    01239             }
    01240         }
    01241         v4l2_buf.m.planes = planes;
    01242         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    01243         // It is necessary to queue an empty buffer to signal EOS to the decoder
    01244         // i.e. set v4l2_buf.m.planes[0].bytesused = 0 and queue the buffer
    01245         ret = ctx->dec->output_plane.qBuffer(v4l2_buf, NULL);
    01246         if (ret < 0)
    01247         {
    01248             cerr << "Error Qing buffer at output plane" << endl;
    01249             ctx->got_error = true;
    01250             break;
    01251         }
    01252         if (v4l2_buf.m.planes[0].bytesused == 0)
    01253         {
    01254             eos = true;
    01255             cout << "Input file read complete" << endl;
    01256             break;
    01257         }
    01258         i++;
    01259     }
    01260
    01261     // Since all the output plane buffers have been queued, we first need to
    01262     // dequeue a buffer from output plane before we can read new data into it
    01263     // and queue it again.
    01264     while (!eos && !ctx->got_error && !ctx->dec->isInError())
    01265     {
    01266         struct v4l2_buffer v4l2_buf;
    01267         struct v4l2_plane planes[MAX_PLANES];
    01268         NvBuffer *buffer;
    01269
    01270         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    01271         memset(planes, 0, sizeof(planes));
    01272         v4l2_buf.m.planes = planes;
    01273
    01274         ret = ctx->dec->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, -1);
    01275         if (ret < 0)
    01276         {
    01277             cerr << "Error DQing buffer at output plane" << endl;
    01278             ctx->got_error = true;
    01279             break;
    01280         }
    01281
    01282         if (ctx->input_nalu)
    01283         {
    01284             read_decoder_input_nalu(ctx->in_file, buffer,
    01285                                     nalu_parse_buffer, CHUNK_SIZE);
    01286             wait_for_nextFrame(ctx);
    01287         }
    01288         else
    01289         {
    01290             read_decoder_input_chunk(ctx->in_file, buffer);
    01291         }
    01292
    01293         if (ctx->input_nalu && ctx->do_stat)
    01294         {
    01295             nal_type = parse_nalu_unit(buffer);
    01296             switch (nal_type)
    01297             {
    01298                 case NAL_UNIT_CODED_SLICE:
    01299                 case NAL_UNIT_CODED_SLICE_DATAPART_A:
    01300                 case NAL_UNIT_CODED_SLICE_DATAPART_B:
    01301                 case NAL_UNIT_CODED_SLICE_DATAPART_C:
    01302                 case NAL_UNIT_CODED_SLICE_IDR:
    01303                 {
    01304                     assign_decode_ts(&v4l2_buf, ctx->channel);
    01305                     frame_info_t *frame_meta = new frame_info_t;
    01306                     memset(frame_meta, 0, sizeof(frame_info_t));
    01307
    01308                     frame_meta->timestamp = v4l2_buf.timestamp.tv_sec;
    01309                     gettimeofday(&frame_meta->input_time, NULL);
    01310                     frame_meta->nal_type = nal_type;
    01311                     ctx->frame_info_map->insert(
    01312                         pair< uint64_t, frame_info_t* >(
    01313                         v4l2_buf.timestamp.tv_sec, frame_meta));
    01314                     break;
    01315                 }
    01316                 default:
    01317                     break;
    01318             }
    01319         }
    01320         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    01321         ret = ctx->dec->output_plane.qBuffer(v4l2_buf, NULL);
    01322         if (ret < 0)
    01323         {
    01324             cerr << "Error Qing buffer at output plane" << endl;
    01325             ctx->got_error = true;
    01326             break;
    01327         }
    01328         if (v4l2_buf.m.planes[0].bytesused == 0)
    01329         {
    01330             eos = true;
    01331             cout << "Input file read complete" << endl;
    01332             break;
    01333         }
    01334     }
    01335
    01336     // After sending EOS, all the buffers from output plane should be dequeued.
    01337     // and after that capture plane loop should be signalled to stop.
    01338     while (ctx->dec->output_plane.getNumQueuedBuffers() > 0 &&
    01339            !ctx->got_error && !ctx->dec->isInError())
    01340     {
    01341         struct v4l2_buffer v4l2_buf;
    01342         struct v4l2_plane planes[MAX_PLANES];
    01343
    01344         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    01345         memset(planes, 0, sizeof(planes));
    01346
    01347         v4l2_buf.m.planes = planes;
    01348         ret = ctx->dec->output_plane.dqBuffer(v4l2_buf, NULL, NULL, -1);
    01349         if (ret < 0)
    01350         {
    01351             cerr << "Error DQing buffer at output plane" << endl;
    01352             ctx->got_error = true;
    01353             break;
    01354         }
    01355     }
    01356
    01357     if (ctx->input_nalu)
    01358     {
    01359         delete []nalu_parse_buffer;
    01360     }
    01361
    01362     ctx->got_eos = true;
    01363     return NULL;
    01364 }
    01365
    01366 static void
    01367 set_defaults(context_t * ctx)
    01368 {
    01369     memset(ctx, 0, sizeof(context_t));
    01370     ctx->fullscreen = false;
    01371     ctx->window_height = 0;
    01372     ctx->window_width = 0;
    01373     ctx->window_x = 0;
    01374     ctx->window_y = 0;
    01375     ctx->input_nalu = 1;
    01376     ctx->fps = 30;
    01377     ctx->do_stat = 0;
    01378     ctx->cpu_occupation_option = 0;
    01379     ctx->dec_status = 0;
    01380     ctx->conv_output_plane_buf_queue = new queue < NvBuffer * >;
    01381 #ifdef ENABLE_GIE
    01382     if (ctx->channel < g_gie_context.getNumGieInstances())
    01383     {
    01384         ctx->conv1_output_plane_buf_queue = new queue < NvBuffer * >;
    01385     }
    01386     pthread_mutex_init(&ctx->osd_lock, NULL);
    01387     ctx->osd_queue = new queue <frame_bbox*>;
    01388 #endif
    01389     ctx->render_buf_queue = new queue <Shared_Buffer>;
    01390     ctx->stop_render = 0;
    01391     ctx->frame_info_map = new map< uint64_t, frame_info_t* >;
    01392     ctx->nvosd_context = NULL;
    01393 }
    01394
    01395 #ifdef ENABLE_GIE
    01396 static void
    01397 set_globalcfg_default(global_cfg *cfg)
    01398 {
    01399     cfg->deployfile = GOOGLE_NET_DEPLOY_NAME;
    01400     cfg->modelfile = GOOGLE_NET_MODEL_NAME;
    01401 }
    01402 #endif
    01403
    01404 static void
    01405 get_disp_resolution(display_resolution_t *res)
    01406 {
    01407     if (NvEglRenderer::getDisplayResolution(
    01408             res->window_width, res->window_height) < 0)
    01409     {
    01410         cerr << "get resolution failed, program will exit" << endl;
    01411         exit(0);
    01412     }
    01413
    01414     return;
    01415 }
    01416
    01417 static void
    01418 do_statistic(context_t * ctx)
    01419 {
    01420     uint64_t accu_latency = 0;
    01421     uint64_t accu_frames = 0;
    01422     struct timeval start_time;
    01423     struct timeval end_time;
    01424     map<uint64_t, frame_info_t*>::iterator  iter;
    01425
    01426     for( iter = ctx->frame_info_map->begin();
    01427             iter != ctx->frame_info_map->end(); iter++)
    01428     {
    01429         if (iter->second->output_time.tv_sec != 0 &&
    01430                 iter->second->input_time.tv_sec != 0)
    01431         {
    01432             accu_latency += (iter->second->output_time.tv_sec -
    01433                                 iter->second->input_time.tv_sec) * 1000 +
    01434                                ( iter->second->output_time.tv_usec -
    01435                                 iter->second->input_time.tv_usec ) / 1000;
    01436             accu_frames++;
    01437             end_time = iter->second->output_time;
    01438         }
    01439
    01440         if (iter == ctx->frame_info_map->begin())
    01441         {
    01442             start_time = iter->second->input_time;
    01443         }
    01444     }
    01445
    01446     cout << "total frames:" << accu_frames<<endl;
    01447     cout <<"pipeline:" << ctx->channel << " avg_latency:(ms)" <<
    01448                 accu_latency / accu_frames << " fps:" <<
    01449                 accu_frames * 1000000 / (end_time.tv_sec * 1000000 +
    01450                 end_time.tv_usec - start_time.tv_sec * 1000000 -
    01451                 start_time.tv_usec ) << endl;
    01452 }
    01453
    01454 int
    01455 main(int argc, char *argv[])
    01456 {
    01457     context_t ctx[CHANNEL_NUM];
    01458     global_cfg cfg;
    01459     int error = 0;
    01460     int iterator;
    01461     map<uint64_t, frame_info_t*>::iterator  iter;
    01462     display_resolution_t disp_info;
    01463     char **argp;
    01464     memset(&cfg, 0, sizeof(global_cfg));
    01465 #ifdef ENABLE_GIE
    01466     set_globalcfg_default(&cfg);
    01467 #endif
    01468
    01469     argp = argv;
    01470     parse_global(&cfg, argc, &argp);
    01471
    01472     if (parse_csv_args(&ctx[0],
    01473 #ifdef ENABLE_GIE
    01474         &g_gie_context,
    01475 #endif
    01476         argc - cfg.channel_num - 1, argp))
    01477     {
    01478         fprintf(stderr, "Error parsing commandline arguments\n");
    01479         return -1;
    01480     }
    01481
    01482 #ifdef ENABLE_GIE
    01483 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    01484     g_gie_context.buildGieContext(cfg.deployfile, cfg.modelfile, true);
    01485 #else
    01486     g_gie_context.buildGieContext(cfg.deployfile, cfg.modelfile);
    01487 #endif
    01488     //Batchsize * FilterNum should be not bigger than buffers allocated by VIC
    01489     if (g_gie_context.getBatchSize() * g_gie_context.getFilterNum() > 10)
    01490     {
    01491         fprintf(stderr,
    01492             "Not enough buffers. Decrease gie-proc-interval and run again. Exiting\n");
    01493 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    01494         g_gie_context.destroyGieContext(true);
    01495 #else
    01496         g_gie_context.destroyGieContext();
    01497 #endif
    01498         return 0;
    01499     }
    01500     pthread_create(&GIE_Thread_handle, NULL, gie_thread, NULL);
    01501 #endif
    01502
    01503     get_disp_resolution(&disp_info);
    01504     init_decode_ts();
    01505
    01506     if (0)
    01507         init_jpeg_context();
    01508
    01509     // Get defalut EGL display
    01510     egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    01511     if (egl_display == EGL_NO_DISPLAY)
    01512     {
    01513         cout<<"Error while get EGL display connection"<<endl;
    01514         return -1;
    01515     }
    01516
    01517     // Init EGL display connection
    01518     if (!eglInitialize(egl_display, NULL, NULL))
    01519     {
    01520         cout<<"Erro while initialize EGL display connection"<<endl;
    01521         return -1;
    01522     }
    01523
    01524     for (iterator = 0; iterator < cfg.channel_num; iterator++)
    01525     {
    01526         int ret = 0;
    01527         sem_init(&(ctx[iterator].dec_run_sem), 0, 0);
    01528 #ifdef ENABLE_GIE
    01529         sem_init(&(ctx[iterator].result_ready_sem), 0, 0);
    01530 #endif
    01531         set_defaults(&ctx[iterator]);
    01532
    01533         char decname[512];
    01534         sprintf(decname, "dec%d", iterator);
    01535         ctx[iterator].channel = iterator;
    01536
    01537         if (parse_csv_args(&ctx[iterator],
    01538 #ifdef ENABLE_GIE
    01539             &g_gie_context,
    01540 #endif
    01541             argc - cfg.channel_num - 1, argp))
    01542         {
    01543             fprintf(stderr, "Error parsing commandline arguments\n");
    01544             return -1;
    01545         }
    01546         ctx[iterator].in_file_path = cfg.in_file_path[iterator];
    01547         ctx[iterator].nvosd_context = nvosd_create_context();
    01548         ctx[iterator].dec = NvVideoDecoder::createVideoDecoder(decname);
    01549         TEST_ERROR(!ctx[iterator].dec, "Could not create decoder", cleanup);
    01550
    01551         // Subscribe to Resolution change event
    01552         ret = ctx[iterator].dec->subscribeEvent(V4L2_EVENT_RESOLUTION_CHANGE,
    01553                         0, 0);
    01554         TEST_ERROR(ret < 0,
    01555                 "Could not subscribe to V4L2_EVENT_RESOLUTION_CHANGE",
    01556                 cleanup);
    01557
    01558         // Set V4L2_CID_MPEG_VIDEO_DISABLE_COMPLETE_FRAME_INPUT control to false
    01559         // so that application can send chunks/slice of encoded data instead of
    01560         // forming complete frames. This needs to be done before setting format
    01561         // on the output plane.
    01562         ret = ctx[iterator].dec->disableCompleteFrameInputBuffer();
    01563         TEST_ERROR(ret < 0, "Error in disableCompleteFrameInputBuffer", cleanup);
    01564
    01565         // Set format on the output plane
    01566         ret = ctx[iterator].dec->setOutputPlaneFormat(
    01567                     ctx[iterator].decoder_pixfmt, CHUNK_SIZE);
    01568         TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
    01569
    01570         // V4L2_CID_MPEG_VIDEO_DISABLE_DPB should be set after output plane
    01571         // set format
    01572         if (ctx[iterator].disable_dpb)
    01573         {
    01574             ret = ctx[iterator].dec->disableDPB();
    01575             TEST_ERROR(ret < 0, "Error in disableDPB", cleanup);
    01576         }
    01577
    01578         // Query, Export and Map the output plane buffers so that we can read
    01579         // encoded data into the buffers
    01580         ret = ctx[iterator].dec->output_plane.setupPlane(
    01581                 V4L2_MEMORY_MMAP, 10, true, false);
    01582         TEST_ERROR(ret < 0, "Error while setting up output plane", cleanup);
    01583
    01584         ctx[iterator].in_file = new ifstream(ctx[iterator].in_file_path);
    01585         TEST_ERROR(!ctx[iterator].in_file->is_open(),
    01586                 "Error opening input file", cleanup);
    01587
    01588         if (ctx[iterator].out_file_path)
    01589         {
    01590             ctx[iterator].out_file = new ofstream(ctx[iterator].out_file_path);
    01591             TEST_ERROR(!ctx[iterator].out_file->is_open(),
    01592                         "Error opening output file",
    01593                         cleanup);
    01594         }
    01595
    01596         pthread_create(&ctx[iterator].render_feed_handle, NULL,
    01597                                 render_thread, &ctx[iterator]);
    01598         // Create converter to convert from BL to PL for writing raw video
    01599         // to file
    01600         char convname[512];
    01601         sprintf(convname, "conv%d", iterator);
    01602         ctx[iterator].conv = NvVideoConverter::createVideoConverter(convname);
    01603         TEST_ERROR(!ctx[iterator].conv, "Could not create video converter",
    01604                 cleanup);
    01605
    01606         ctx[iterator].conv->output_plane.
    01607             setDQThreadCallback(conv_output_dqbuf_thread_callback);
    01608         ctx[iterator].conv->capture_plane.
    01609             setDQThreadCallback(conv_capture_dqbuf_thread_callback);
    01610 #ifdef ENABLE_GIE
    01611         if (iterator < g_gie_context.getNumGieInstances())
    01612         {
    01613             sprintf(convname, "conv1-%d", iterator);
    01614             ctx[iterator].conv1 =
    01615                    NvVideoConverter::createVideoConverter(convname);
    01616             TEST_ERROR(!ctx[iterator].conv1, "Could not create video converter",
    01617                 cleanup);
    01618
    01619             ctx[iterator].conv1->output_plane.
    01620                 setDQThreadCallback(conv1_output_dqbuf_thread_callback);
    01621             ctx[iterator].conv1->capture_plane.
    01622                 setDQThreadCallback(conv1_capture_dqbuf_thread_callback);
    01623         }
    01624 #endif
    01625         ret = ctx[iterator].dec->output_plane.setStreamStatus(true);
    01626         TEST_ERROR(ret < 0, "Error in output plane stream on", cleanup);
    01627         if (cfg.channel_num == 1)
    01628         {
    01629             ctx[iterator].window_width = disp_info.window_width;
    01630             ctx[iterator].window_height = disp_info.window_height;
    01631             ctx[iterator].window_x = 0;
    01632             ctx[iterator].window_y = 0;
    01633         }
    01634         else
    01635         {
    01636             if (iterator == 0)
    01637             {
    01638                 ctx[iterator].window_width = disp_info.window_width / 2;
    01639                 ctx[iterator].window_height = disp_info.window_height / 2;
    01640                 ctx[iterator].window_x = 0;
    01641                 ctx[iterator].window_y = 0;
    01642             }
    01643             else if (iterator == 1)
    01644             {
    01645                 ctx[iterator].window_width = disp_info.window_width / 2;
    01646                 ctx[iterator].window_height = disp_info.window_height / 2;
    01647                 ctx[iterator].window_x = disp_info.window_width / 2;
    01648                 ctx[iterator].window_y = 0;
    01649             }
    01650             else if (iterator == 2)
    01651             {
    01652                 ctx[iterator].window_width = disp_info.window_width / 2;
    01653                 ctx[iterator].window_height = disp_info.window_height / 2;
    01654                 ctx[iterator].window_x = 0;
    01655                 ctx[iterator].window_y = disp_info.window_height / 2;
    01656             }
    01657             else
    01658             {
    01659                 ctx[iterator].window_width = disp_info.window_width / 2;
    01660                 ctx[iterator].window_height = disp_info.window_height / 2;
    01661                 ctx[iterator].window_x = disp_info.window_width / 2;
    01662                 ctx[iterator].window_y = disp_info.window_height / 2;
    01663             }
    01664         }
    01665         if (ctx[iterator].cpu_occupation_option != PARSER)
    01666             pthread_create(&ctx[iterator].dec_capture_loop, NULL,
    01667                                 dec_capture_loop_fcn, &ctx[iterator]);
    01668         pthread_create(&ctx[iterator].dec_feed_handle, NULL,
    01669                                 dec_feed_loop_fcn, &ctx[iterator]);
    01670     }
    01671
    01672 cleanup:
    01673     for (iterator = 0; iterator < cfg.channel_num; iterator++)
    01674     {
    01675         sem_wait(&(ctx[iterator].dec_run_sem)); //we need wait to make sure decode get EOS
    01676
    01677         //send stop command to render, and wait it get consumed
    01678         ctx[iterator].stop_render = 1;
    01679         pthread_cond_broadcast(&ctx[iterator].render_cond);
    01680         pthread_join(ctx[iterator].render_feed_handle, NULL);
    01681 #ifdef ENABLE_GIE
    01682         if (GIE_Stop == 0)
    01683         {
    01684             GIE_Stop = 1;
    01685             pthread_cond_broadcast(&GIE_cond);
    01686             pthread_join(GIE_Thread_handle, NULL);
    01687         }
    01688 #endif
    01689         ctx[iterator].conv->waitForIdle(-1);
    01690         ctx[iterator].conv->capture_plane.stopDQThread();
    01691         ctx[iterator].conv->output_plane.stopDQThread();
    01692 #ifdef ENABLE_GIE
    01693         if (iterator < g_gie_context.getNumGieInstances())
    01694         {
    01695             ctx[iterator].conv1->waitForIdle(-1);
    01696             ctx[iterator].conv1->capture_plane.stopDQThread();
    01697             ctx[iterator].conv1->output_plane.stopDQThread();
    01698         }
    01699 #endif
    01700         pthread_join(ctx[iterator].dec_feed_handle, NULL);
    01701         if (ctx[iterator].cpu_occupation_option != PARSER)
    01702             pthread_join(ctx[iterator].dec_capture_loop, NULL);
    01703
    01704         if (ctx[iterator].dec->isInError())
    01705         {
    01706             cerr << "Decoder is in error" << endl;
    01707             error = 1;
    01708         }
    01709
    01710         if (ctx[iterator].got_error)
    01711         {
    01712             error = 1;
    01713         }
    01714
    01715         if (ctx[iterator].do_stat)
    01716             do_statistic(&ctx[iterator]);
    01717
    01718         sem_destroy(&(ctx[iterator].dec_run_sem));
    01719 #ifdef ENABLE_GIE
    01720         sem_destroy(&(ctx[iterator].result_ready_sem));
    01721         pthread_mutex_destroy(&ctx[iterator].osd_lock);
    01722 #endif
    01723         // The decoder destructor does all the cleanup i.e set streamoff on output and capture planes,
    01724         // unmap buffers, tell decoder to deallocate buffer (reqbufs ioctl with counnt = 0),
    01725         // and finally call v4l2_close on the fd.
    01726         delete ctx[iterator].dec;
    01727
    01728         // Similarly, EglRenderer destructor does all the cleanup
    01729         if (ctx->cpu_occupation_option == PARSER_DECODER_VIC_RENDER)
    01730             delete ctx[iterator].renderer;
    01731         delete ctx[iterator].in_file;
    01732         delete ctx[iterator].out_file;
    01733         delete ctx[iterator].conv_output_plane_buf_queue;
    01734         delete ctx[iterator].render_buf_queue;
    01735         if (!ctx[iterator].nvosd_context)
    01736         {
    01737             nvosd_destroy_context(ctx[iterator].nvosd_context);
    01738             ctx[iterator].nvosd_context = NULL;
    01739         }
    01740 #ifdef ENABLE_GIE
    01741         delete ctx[iterator].osd_queue;
    01742         if (iterator < g_gie_context.getNumGieInstances())
    01743         {
    01744            delete ctx[iterator].conv1_output_plane_buf_queue;
    01745         }
    01746 #endif
    01747
    01748         if (ctx[iterator].do_stat)
    01749         {
    01750             for( iter = ctx[iterator].frame_info_map->begin();
    01751                     iter != ctx[iterator].frame_info_map->end(); iter++)
    01752             {
    01753                 delete iter->second;
    01754             }
    01755         }
    01756         delete ctx[iterator].frame_info_map;
    01757
    01758         if (error)
    01759         {
    01760             cout << "App run failed" << endl;
    01761         }
    01762         else
    01763         {
    01764             cout << "App run was successful" << endl;
    01765         }
    01766     }
    01767 #ifdef ENABLE_GIE
    01768 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    01769     g_gie_context.destroyGieContext(true);
    01770 #else
    01771     g_gie_context.destroyGieContext();
    01772 #endif
    01773 #endif
    01774     // Terminate EGL display connection
    01775     if (egl_display)
    01776     {
    01777         if (!eglTerminate(egl_display))
    01778         {
    01779             cout<<"Error while terminate EGL display connection";
    01780             return -1;
    01781         }
    01782     }
    01783
    01784     if (0)
    01785         destroy_jpeg_context();
    01786
    01787     return -error;
    01788 }