- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

# samples/04_video_dec_gie/video_dec_gie_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 <errno.h>
    00030 #include <fstream>
    00031 #include <iostream>
    00032 #include <linux/videodev2.h>
    00033 #include <malloc.h>
    00034 #include <pthread.h>
    00035 #include <string.h>
    00036 #include <unistd.h>
    00037 #include <sys/prctl.h>
    00038
    00039 #include "NvUtils.h"
    00040 #include "NvCudaProc.h"
    00041 #include "nvbuf_utils.h"
    00042 #include "video_dec_gie.h"
    00043 #include "gie_inference.h"
    00044
    00045 #define USE_CPU_FOR_INTFLOAT_CONVERSION 0
    00046
    00047 #define TEST_ERROR(cond, str, label) if(cond) { \
    00048                            cerr << str << endl; \
    00049                            error = 1; \
    00050                            goto label; }
    00051
    00052 #define CHUNK_SIZE 4000000
    00053
    00054 #define IS_NAL_UNIT_START(buffer_ptr) \
    00055             (!buffer_ptr[0] && !buffer_ptr[1] && \
    00056              !buffer_ptr[2] && (buffer_ptr[3] == 1))
    00057
    00058 const char *GOOGLE_NET_DEPLOY_NAME =
    00059              "../../data/model/GoogleNet-modified.prototxt";
    00060 const char *GOOGLE_NET_MODEL_NAME =
    00061              "../../data/model/GoogleNet-modified-online_iter_30000.caffemodel";
    00062
    00063 using namespace std;
    00064 using namespace nvinfer1;
    00065 using namespace nvcaffeparser1;
    00066
    00067 static void
    00068 abort(context_t *ctx)
    00069 {
    00070     ctx->got_error = true;
    00071     ctx->dec->abort();
    00072     if (ctx->conv)
    00073     {
    00074         ctx->conv->abort();
    00075         pthread_cond_broadcast(&ctx->queue_cond);
    00076     }
    00077 }
    00078
    00079 static int
    00080 read_decoder_input_chunk(ifstream * stream, NvBuffer * buffer)
    00081 {
    00082     //length is the size of the buffer in bytes
    00083     streamsize bytes_to_read = MIN(CHUNK_SIZE, buffer->planes[0].length);
    00084
    00085     stream->read((char *) buffer->planes[0].data, bytes_to_read);
    00086
    00087     // It is necessary to set bytesused properly, so that decoder knows how
    00088     // many bytes in the buffer are valid
    00089     buffer->planes[0].bytesused = stream->gcount();
    00090     return 0;
    00091 }
    00092
    00093 static int
    00094 sendEOStoConverter(context_t *ctx)
    00095 {
    00096     // Check if converter is running
    00097     if (ctx->conv->output_plane.getStreamStatus())
    00098     {
    00099         NvBuffer *conv_buffer;
    00100         struct v4l2_buffer v4l2_buf;
    00101         struct v4l2_plane planes[MAX_PLANES];
    00102
    00103         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00104         memset(&planes, 0, sizeof(planes));
    00105
    00106         v4l2_buf.m.planes = planes;
    00107         pthread_mutex_lock(&ctx->queue_lock);
    00108         while (ctx->conv_output_plane_buf_queue->empty())
    00109         {
    00110             pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
    00111         }
    00112         conv_buffer = ctx->conv_output_plane_buf_queue->front();
    00113         ctx->conv_output_plane_buf_queue->pop();
    00114         pthread_mutex_unlock(&ctx->queue_lock);
    00115
    00116         v4l2_buf.index = conv_buffer->index;
    00117
    00118         // Queue EOS buffer on converter output plane
    00119         return ctx->conv->output_plane.qBuffer(v4l2_buf, NULL);
    00120     }
    00121     return 0;
    00122 }
    00123
    00124 static bool
    00125 initConv(context_t * ctx)
    00126 {
    00127     int ret = 0;
    00128     struct v4l2_format format;
    00129
    00130     ret = ctx->dec->capture_plane.getFormat(format);
    00131     if (ret < 0)
    00132     {
    00133         cerr << "Error: Could not get format from decoder capture plane" << endl;
    00134         return false;
    00135     }
    00136
    00137     ret = ctx->conv->setOutputPlaneFormat(format.fmt.pix_mp.pixelformat,
    00138                                           format.fmt.pix_mp.width,
    00139                                           format.fmt.pix_mp.height,
    00140                                           V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
    00141     if(ret < 0)
    00142     {
    00143         cerr << "Error in converter output plane set format" << endl;
    00144         return false;
    00145     }
    00146
    00147     // 1. Convert YUV to RGB
    00148     // 2. Scale to the resolution GIE needs
    00149     // 3. Convert Block buffer layout to Pitch buffer layout
    00150     ret = ctx->conv->setCapturePlaneFormat(V4L2_PIX_FMT_ABGR32,
    00151                                            ctx->gie_ctx->getNetWidth(),
    00152                                            ctx->gie_ctx->getNetHeight(),
    00153                                            V4L2_NV_BUFFER_LAYOUT_PITCH);
    00154     if (ret < 0)
    00155     {
    00156         cerr << "Error in converter capture plane set format" << endl;
    00157         return false;
    00158     }
    00159
    00160     ret = ctx->conv->setCropRect(0, 0, ctx->dec_width, ctx->dec_height);
    00161     if (ret < 0)
    00162     {
    00163         cerr << "Error while setting crop rect" << endl;
    00164         return false;
    00165     }
    00166
    00167     ret = ctx->conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF,
    00168                                    ctx->dec->capture_plane.getNumBuffers(),
    00169                                    false,
    00170                                    false);
    00171     if (ret < 0)
    00172     {
    00173         cerr << "Error in converter output plane setup" << endl;
    00174         return false;
    00175     }
    00176
    00177     ret = ctx->conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00178                              ctx->dec->capture_plane.getNumBuffers(),
    00179                              true,
    00180                              false);
    00181     if (ret < 0)
    00182     {
    00183         cerr << "Error in converter capture plane setup" << endl;
    00184         return false;
    00185     }
    00186
    00187     ret = ctx->conv->output_plane.setStreamStatus(true);
    00188     if (ret < 0)
    00189     {
    00190         cerr << "Error in converter output plane streamon" << endl;
    00191         return false;
    00192     }
    00193
    00194     ret = ctx->conv->capture_plane.setStreamStatus(true);
    00195     if (ret < 0)
    00196     {
    00197         cerr << "Error in converter output plane streamoff" << endl;
    00198         return false;
    00199     }
    00200
    00201     // Add all empty conv output plane buffers to conv_output_plane_buf_queue
    00202     for (uint32_t i = 0; i < ctx->conv->output_plane.getNumBuffers(); i++)
    00203     {
    00204         ctx->conv_output_plane_buf_queue->push(ctx->conv->output_plane.
    00205                     getNthBuffer(i));
    00206     }
    00207
    00208     for (uint32_t i = 0; i < ctx->conv->capture_plane.getNumBuffers(); i++)
    00209     {
    00210         struct v4l2_buffer v4l2_buf;
    00211         struct v4l2_plane planes[MAX_PLANES];
    00212
    00213         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00214         memset(planes, 0, sizeof(planes));
    00215
    00216         v4l2_buf.index = i;
    00217         v4l2_buf.m.planes = planes;
    00218         ret = ctx->conv->capture_plane.qBuffer(v4l2_buf, NULL);
    00219         if (ret < 0)
    00220         {
    00221             cerr << "Error Qing buffer at converter capture plane" << endl;
    00222             return false;
    00223         }
    00224     }
    00225     ctx->conv->output_plane.startDQThread(ctx);
    00226     ctx->conv->capture_plane.startDQThread(ctx);
    00227
    00228     return true;
    00229 }
    00230
    00231 static bool
    00232 deinitConv(context_t * ctx)
    00233 {
    00234     int ret;
    00235
    00236     ret = sendEOStoConverter(ctx);
    00237     if (ret < 0)
    00238     {
    00239         cerr << "Error while queueing EOS buffer on converter output" << endl;
    00240         return false;
    00241     }
    00242     // Wait for EOS buffer to arrive on capture plane
    00243     ctx->conv->capture_plane.waitForDQThread(2000);
    00244
    00245     ctx->conv->output_plane.deinitPlane();
    00246     ctx->conv->capture_plane.deinitPlane();
    00247
    00248     while(!ctx->conv_output_plane_buf_queue->empty())
    00249     {
    00250         ctx->conv_output_plane_buf_queue->pop();
    00251     }
    00252     return true;
    00253 }
    00254
    00255 static void
    00256 resChange(context_t * ctx)
    00257 {
    00258     NvVideoDecoder *dec = ctx->dec;
    00259     struct v4l2_format format;
    00260     struct v4l2_crop crop;
    00261     int32_t min_dec_capture_buffers;
    00262     int ret = 0;
    00263     int error = 0;
    00264
    00265     // Get capture plane format from the decoder. This may change after
    00266     // an resolution change event
    00267     ret = dec->capture_plane.getFormat(format);
    00268     TEST_ERROR(ret < 0,
    00269                "Error: Could not get format from decoder capture plane", error);
    00270
    00271     // Get the display resolution from the decoder
    00272     ret = dec->capture_plane.getCrop(crop);
    00273     TEST_ERROR(ret < 0,
    00274                "Error: Could not get crop from decoder capture plane", error);
    00275     ctx->dec_width = crop.c.width;
    00276     ctx->dec_height = crop.c.height;
    00277
    00278     cout << "Video Resolution: " << ctx->dec_width << "x" << ctx->dec_height << endl;
    00279
    00280     // First deinitialize output and capture planes
    00281     // of video converter and then use the new resolution from
    00282     // decoder event resolution change
    00283     ret = deinitConv(ctx);
    00284
    00285     // deinitPlane unmaps the buffers and calls REQBUFS with count 0
    00286     dec->capture_plane.deinitPlane();
    00287
    00288     // Not necessary to call VIDIOC_S_FMT on decoder capture plane.
    00289     // But decoder setCapturePlaneFormat function updates the class variables
    00290     ret = dec->setCapturePlaneFormat(format.fmt.pix_mp.pixelformat,
    00291                                      format.fmt.pix_mp.width,
    00292                                      format.fmt.pix_mp.height);
    00293     TEST_ERROR(ret < 0, "Error in setting decoder capture plane format", error);
    00294
    00295     // Get the minimum buffers which have to be requested on the capture plane
    00296     ret = dec->getMinimumCapturePlaneBuffers(min_dec_capture_buffers);
    00297     TEST_ERROR(ret < 0,
    00298                "Error while getting value of minimum capture plane buffers",
    00299                error);
    00300
    00301     // Request (min + 5) buffers, export and map buffers
    00302     ret = dec->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00303                                        min_dec_capture_buffers,
    00304                                        false,
    00305                                        false);
    00306     TEST_ERROR(ret < 0, "Error in decoder capture plane setup", error);
    00307
    00308     if (ctx->conv)
    00309     {
    00310         ret = initConv(ctx);
    00311         TEST_ERROR(ret == false, "initConv failed", error);
    00312     }
    00313
    00314     // Capture plane STREAMON
    00315     ret = dec->capture_plane.setStreamStatus(true);
    00316     TEST_ERROR(ret < 0, "Error in decoder capture plane streamon", error);
    00317
    00318     // Enqueue all the empty capture plane buffers
    00319     for (uint32_t i = 0; i < dec->capture_plane.getNumBuffers(); i++)
    00320     {
    00321         struct v4l2_buffer v4l2_buf;
    00322         struct v4l2_plane planes[MAX_PLANES];
    00323
    00324         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00325         memset(planes, 0, sizeof(planes));
    00326
    00327         v4l2_buf.index = i;
    00328         v4l2_buf.m.planes = planes;
    00329         ret = dec->capture_plane.qBuffer(v4l2_buf, NULL);
    00330         TEST_ERROR(ret < 0, "Error Qing buffer at output plane", error);
    00331     }
    00332
    00333     cout << "Resolution change successful" << endl;
    00334     return;
    00335
    00336 error:
    00337     if (error)
    00338     {
    00339         abort(ctx);
    00340         cerr << "Error in " << __func__ << endl;
    00341     }
    00342 }
    00343
    00344 // Give the buffer to video converter output plane
    00345 static bool
    00346 decFillBufConv(context_t *ctx, NvBuffer *dec_buf)
    00347 {
    00348     NvBuffer *conv_buffer;
    00349     struct v4l2_buffer conv_output_buffer;
    00350     struct v4l2_plane conv_planes[MAX_PLANES];
    00351
    00352     memset(&conv_output_buffer, 0, sizeof(conv_output_buffer));
    00353     memset(conv_planes, 0, sizeof(conv_planes));
    00354     conv_output_buffer.m.planes = conv_planes;
    00355
    00356     // Get an empty conv output plane buffer from conv_output_plane_buf_queue
    00357     pthread_mutex_lock(&ctx->queue_lock);
    00358     while (ctx->conv_output_plane_buf_queue->empty())
    00359     {
    00360         pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
    00361     }
    00362     conv_buffer = ctx->conv_output_plane_buf_queue->front();
    00363     ctx->conv_output_plane_buf_queue->pop();
    00364     pthread_mutex_unlock(&ctx->queue_lock);
    00365
    00366     conv_output_buffer.index = conv_buffer->index;
    00367
    00368     if (ctx->conv->output_plane.qBuffer(conv_output_buffer, dec_buf) < 0)
    00369     {
    00370         abort(ctx);
    00371         cerr << "Error while queueing buffer at converter output plane"
    00372              << endl;
    00373         return false;
    00374     }
    00375     return true;
    00376 }
    00377
    00378 static void*
    00379 decCaptureLoop(void *arg)
    00380 {
    00381     context_t *ctx = (context_t *) arg;
    00382     NvVideoDecoder *dec = ctx->dec;
    00383     struct v4l2_event ev;
    00384     int ret;
    00385
    00386     cout << "Starting decoder capture loop thread" << endl;
    00387     prctl (PR_SET_NAME, "decCap", 0, 0, 0);
    00388
    00389     // Need to wait for the first Resolution change event, so that
    00390     // the decoder knows the stream resolution and can allocate appropriate
    00391     // buffers when we call REQBUFS
    00392     do
    00393     {
    00394         ret = dec->dqEvent(ev, -1);
    00395         if (ret < 0)
    00396         {
    00397             if (errno == EAGAIN)
    00398             {
    00399                 cerr << "Timed out waiting for first V4L2_EVENT_RESOLUTION_CHANGE"
    00400                      << endl;
    00401             }
    00402             else
    00403             {
    00404                 cerr << "Error in dequeueing decoder event" << endl;
    00405             }
    00406             abort(ctx);
    00407             break;
    00408         }
    00409     }
    00410     while (ev.type != V4L2_EVENT_RESOLUTION_CHANGE);
    00411
    00412     // Handle resolution change event
    00413     if (!ctx->got_error)
    00414         resChange(ctx);
    00415
    00416     // Exit on error or EOS which is signalled in main()
    00417     while (!(ctx->got_error || dec->isInError() || ctx->got_eos))
    00418     {
    00419         NvBuffer *dec_buffer;
    00420
    00421         // Check for Resolution change again
    00422         ret = dec->dqEvent(ev, false);
    00423         if (ret == 0)
    00424         {
    00425             switch (ev.type)
    00426             {
    00427                 case V4L2_EVENT_RESOLUTION_CHANGE:
    00428                     resChange(ctx);
    00429                     continue;
    00430             }
    00431         }
    00432
    00433         struct v4l2_buffer v4l2_buf;
    00434         struct v4l2_plane planes[MAX_PLANES];
    00435         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00436         memset(planes, 0, sizeof(planes));
    00437         v4l2_buf.m.planes = planes;
    00438
    00439         // Dequeue a filled buffer
    00440         if (dec->capture_plane.dqBuffer(v4l2_buf, &dec_buffer, NULL, 0))
    00441         {
    00442             if (errno == EAGAIN)
    00443             {
    00444                 usleep(1000);
    00445             }
    00446             else
    00447             {
    00448                 abort(ctx);
    00449                 cerr << "Error while calling dequeue at capture plane"
    00450                      << endl;
    00451             }
    00452             continue;
    00453         }
    00454
    00455         // Give the buffer to video converter output plane
    00456         if (ctx->conv)
    00457         {
    00458             if (!decFillBufConv(ctx, dec_buffer))
    00459                 continue;
    00460         }
    00461     }
    00462
    00463     cout << "Exiting decoder capture loop thread" << endl;
    00464     return NULL;
    00465 }
    00466
    00467 static void*
    00468 gieThread(void *arg)
    00469 {
    00470     int buf_num = 0;
    00471     EGLImageKHR egl_image = NULL;
    00472     struct v4l2_buffer *v4l2_buf;
    00473     NvBuffer *buffer;
    00474     NvBuffer *shared_buffer;
    00475     context_t *ctx = (context_t *)arg;
    00476     int process_last_batch = 0;
    00477     float *gie_inputbuf = ctx->gie_ctx->getInputBuf();
    00478     prctl (PR_SET_NAME, "gieThread", 0, 0, 0);
    00479
    00480     // Get default EGL display
    00481     ctx->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    00482     if (ctx->egl_display == EGL_NO_DISPLAY)
    00483     {
    00484         cerr << "Error while get EGL display connection" << endl;
    00485         return NULL;
    00486     }
    00487
    00488     // Init EGL display connection
    00489     if (!eglInitialize(ctx->egl_display, NULL, NULL))
    00490     {
    00491         cerr << "Erro while initialize EGL display connection" << endl;
    00492         return NULL;
    00493     }
    00494
    00495     while (1)
    00496     {
    00497         // wait for buffer for process to come
    00498         Shared_Buffer gie_buffer;
    00499         pthread_mutex_lock(&ctx->gie_lock);
    00500         if(ctx->gie_buf_queue->empty())
    00501         {
    00502             if (ctx->gie_stop && buf_num == 0)
    00503             {
    00504                 pthread_mutex_unlock(&ctx->gie_lock);
    00505                 break;
    00506             }
    00507             else if (!ctx->gie_stop)
    00508             {
    00509                 // waits 50 ms for the frame to come
    00510                 struct timespec timeout;
    00511                 long time_in_ms = 50;
    00512                 timeout.tv_sec = time(0);
    00513                 timeout.tv_nsec = time_in_ms * 1000000;
    00514                 int ret =
    00515                     pthread_cond_timedwait(&ctx->gie_cond, &ctx->gie_lock, &timeout);
    00516                 if (ret != 0)
    00517                 {
    00518                     pthread_mutex_unlock(&ctx->gie_lock);
    00519                     continue;
    00520                 }
    00521             }
    00522         }
    00523         if (ctx->gie_buf_queue->size() != 0)
    00524         {
    00525             gie_buffer = ctx->gie_buf_queue->front();
    00526             ctx->gie_buf_queue->pop();
    00527         }
    00528         else
    00529         {
    00530             process_last_batch = 1;
    00531         }
    00532         pthread_mutex_unlock(&ctx->gie_lock);
    00533
    00534         // we still have buffer, so accumulate buffer into batch
    00535         if (process_last_batch == 0)
    00536         {
    00537             v4l2_buf           = &gie_buffer.v4l2_buf;
    00538             buffer             = gie_buffer.buffer;
    00539             shared_buffer      = gie_buffer.shared_buffer;
    00540             ctx                = (context_t *)gie_buffer.arg;
    00541
    00542             int batch_offset = buf_num  * ctx->gie_ctx->getNetWidth() *
    00543                         ctx->gie_ctx->getNetHeight() * ctx->gie_ctx->getChannel();
    00544 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    00545             // copy with CPU is much slower than GPU
    00546             // but still keep it just in case customer want to save GPU
    00547             //generate input buffer for first time
    00548             unsigned char *data = buffer->planes[0].data;
    00549             int channel_offset = ctx->gie_ctx->getNetWidth() *
    00550                             ctx->gie_ctx->getNetHeight();
    00551             // copy buffer into input_buf
    00552             for (int i = 0; i < ctx->gie_ctx->getChannel(); i++)
    00553             {
    00554                 for (int j = 0; j < ctx->gie_ctx->getNetHeight(); j++)
    00555                 {
    00556                     for (int k = 0; k < ctx->gie_ctx->getNetWidth(); k++)
    00557                     {
    00558                         int total_offset = batch_offset + channel_offset * i +
    00559                             j * ctx->gie_ctx->getNetWidth() + k;
    00560                         gie_inputbuf[total_offset] =
    00561                             (float)(*(data + j * buffer->planes[0].fmt.stride
    00562                             + k * 4 + 3 - i - 1));
    00563                     }
    00564                 }
    00565             }
    00566 #else
    00567             // map fd into EGLImage, then copy it with GPU in parallel
    00568             // Create EGLImage from dmabuf fd
    00569             egl_image = NvEGLImageFromFd(ctx->egl_display, buffer->planes[0].fd);
    00570             if (egl_image == NULL)
    00571             {
    00572                 cerr << "Error while mapping dmabuf fd ("
    00573                      << buffer->planes[0].fd << ") to EGLImage"
    00574                      << endl;
    00575                 return NULL;
    00576             }
    00577
    00578             void *cuda_buf = ctx->gie_ctx->getBuffer(0);
    00579
    00580             // map eglimage into GPU address
    00581             mapEGLImage2Float(&egl_image,  ctx->gie_ctx->getNetWidth(),
    00582                               ctx->gie_ctx->getNetHeight(),
    00583                               (char *)cuda_buf + batch_offset * sizeof(float));
    00584
    00585             // Destroy EGLImage
    00586             NvDestroyEGLImage(ctx->egl_display, egl_image);
    00587             egl_image = NULL;
    00588 #endif
    00589             buf_num++;
    00590
    00591             // now we push it to capture plane to let v4l2 go on
    00592             if (ctx->conv->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
    00593             {
    00594                 cout<<"conv queue buffer error"<<endl;
    00595             }
    00596
    00597             // buffer is not enough for a batch, continue to wait for buffer
    00598             if (buf_num < ctx->gie_ctx->getBatchSize() && !ctx->gie_stop)
    00599             {
    00600                 continue;
    00601             }
    00602         }
    00603         else if(buf_num == 0) // framenum equal batch_size * n
    00604         {
    00605             break;
    00606         }
    00607
    00608         // buffer comes, we begin to inference
    00609         buf_num = 0;
    00610         queue<vector<cv::Rect>> rectList_queue;
    00611 #if USE_CPU_FOR_INTFLOAT_CONVERSION
    00612         ctx->gie_ctx->doInference(
    00613             rectList_queue, gie_inputbuf);
    00614 #else
    00615         ctx->gie_ctx->doInference(
    00616             rectList_queue);
    00617 #endif
    00618         while(!rectList_queue.empty())
    00619         {
    00620             vector<cv::Rect> rectList = rectList_queue.front();
    00621             rectList_queue.pop();
    00622
    00623             for (int i = 0; i < rectList.size(); i++)
    00624             {
    00625                 cv::Rect &r = rectList[i];
    00626                 cout <<"  x "<< r.x <<" y: " << r.y
    00627                      <<" width "<< r.width <<" height "<< r.height
    00628                      << endl;
    00629             }
    00630         }
    00631         if (process_last_batch == 1)
    00632         {
    00633             break;
    00634         }
    00635     }
    00636
    00637     // Terminate EGL display connection
    00638     if (ctx->egl_display)
    00639     {
    00640         if (!eglTerminate(ctx->egl_display))
    00641         {
    00642             cerr << "Error while terminate EGL display connection\n" << endl;
    00643             return NULL;
    00644         }
    00645     }
    00646     return NULL;
    00647 }
    00648
    00649 static bool
    00650 conv0_outputDqbufThreadCallback(struct v4l2_buffer *v4l2_buf,
    00651                                        NvBuffer * buffer,
    00652                                        NvBuffer * shared_buffer,
    00653                                        void *arg)
    00654 {
    00655     context_t *ctx = (context_t *) arg;
    00656     struct v4l2_buffer dec_capture_ret_buffer;
    00657     struct v4l2_plane planes[MAX_PLANES];
    00658
    00659     if (!v4l2_buf)
    00660     {
    00661         cerr << "Failed to dequeue buffer from conv0 output plane" << endl;
    00662         abort(ctx);
    00663         return false;
    00664     }
    00665
    00666     if (v4l2_buf->m.planes[0].bytesused == 0)
    00667     {
    00668         return false;
    00669     }
    00670
    00671     memset(&dec_capture_ret_buffer, 0, sizeof(dec_capture_ret_buffer));
    00672     memset(planes, 0, sizeof(planes));
    00673
    00674     dec_capture_ret_buffer.index = shared_buffer->index;
    00675     dec_capture_ret_buffer.m.planes = planes;
    00676
    00677     pthread_mutex_lock(&ctx->queue_lock);
    00678     ctx->conv_output_plane_buf_queue->push(buffer);
    00679
    00680     // Return the buffer dequeued from converter output plane
    00681     // back to decoder capture plane
    00682     if (ctx->dec->capture_plane.qBuffer(dec_capture_ret_buffer, NULL) < 0)
    00683     {
    00684         abort(ctx);
    00685         return false;
    00686     }
    00687
    00688     pthread_cond_broadcast(&ctx->queue_cond);
    00689     pthread_mutex_unlock(&ctx->queue_lock);
    00690
    00691     return true;
    00692 }
    00693
    00694 static bool
    00695 conv0_captureDqbufThreadCallback(struct v4l2_buffer *v4l2_buf,
    00696                                     NvBuffer *buffer,
    00697                                     NvBuffer *shared_buffer,
    00698                                     void *arg)
    00699 {
    00700     context_t * ctx = (context_t*) arg;
    00701
    00702     if (!v4l2_buf)
    00703     {
    00704         cerr << "Failed to dequeue buffer from conv0 output plane" << endl;
    00705         abort(ctx);
    00706         return false;
    00707     }
    00708     if (v4l2_buf->m.planes[0].bytesused == 0)
    00709     {
    00710         return false;
    00711     }
    00712
    00713     //push buffer to process queue
    00714     Shared_Buffer gie_buffer;
    00715
    00716     // v4l2_buf is local in the DQthread and exists in the scope of the callback
    00717     // function only and not in the entire application. The application has to
    00718     // copy this for using at out of the callback.
    00719     memcpy(&gie_buffer.v4l2_buf, v4l2_buf, sizeof(v4l2_buffer));
    00720
    00721     gie_buffer.buffer = buffer;
    00722     gie_buffer.shared_buffer = shared_buffer;
    00723     gie_buffer.arg = arg;
    00724     pthread_mutex_lock(&ctx->gie_lock);
    00725     ctx->gie_buf_queue->push(gie_buffer);
    00726     pthread_cond_broadcast(&ctx->gie_cond);
    00727     pthread_mutex_unlock(&ctx->gie_lock);
    00728
    00729     return true;
    00730 }
    00731
    00732 static void
    00733 setDefaults(context_t * ctx)
    00734 {
    00735     memset(ctx, 0, sizeof(context_t));
    00736     ctx->deployfile = GOOGLE_NET_DEPLOY_NAME;
    00737     ctx->modelfile = GOOGLE_NET_MODEL_NAME;
    00738     ctx->gie_ctx = new GIE_Context;
    00739     ctx->gie_ctx->setDumpResult(true);
    00740     ctx->gie_buf_queue = new queue<Shared_Buffer>;
    00741
    00742     ctx->conv_output_plane_buf_queue = new queue < NvBuffer * >;
    00743     pthread_mutex_init(&ctx->queue_lock, NULL);
    00744     pthread_cond_init(&ctx->queue_cond, NULL);
    00745 }
    00746
    00747 int
    00748 main(int argc, char *argv[])
    00749 {
    00750     context_t ctx;
    00751     int ret = 0;
    00752     int error = 0;
    00753     uint32_t i;
    00754     bool eos = false;
    00755     char *nalu_parse_buffer = NULL;
    00756
    00757     setDefaults(&ctx);
    00758
    00759     if (parseCsvArgs(&ctx, ctx.gie_ctx, argc, argv))
    00760     {
    00761         cerr << "Error parsing commandline arguments." << endl;
    00762         return -1;
    00763     }
    00764
    00765     ctx.in_file = new ifstream(ctx.in_file_path);
    00766     TEST_ERROR(!ctx.in_file->is_open(), "Error opening input file", cleanup);
    00767
    00768     // Step-1: Create Decoder
    00769     ctx.dec = NvVideoDecoder::createVideoDecoder("dec0");
    00770     TEST_ERROR(!ctx.dec, "Could not create decoder", cleanup);
    00771
    00772     // Subscribe to Resolution change event
    00773     ret = ctx.dec->subscribeEvent(V4L2_EVENT_RESOLUTION_CHANGE, 0, 0);
    00774     TEST_ERROR(ret < 0, "Could not subscribe to V4L2_EVENT_RESOLUTION_CHANGE", cleanup);
    00775
    00776     // Set V4L2_CID_MPEG_VIDEO_DISABLE_COMPLETE_FRAME_INPUT control to false
    00777     // so that application can send chunks of encoded data instead of forming
    00778     // complete frames. This needs to be done before setting format on the
    00779     // output plane.
    00780     ret = ctx.dec->disableCompleteFrameInputBuffer();
    00781     TEST_ERROR(ret < 0, "Error in decoder disableCompleteFrameInputBuffer", cleanup);
    00782
    00783     // Set format on the output plane
    00784     ret = ctx.dec->setOutputPlaneFormat(ctx.decoder_pixfmt, 2 * 1024 * 1024);
    00785     TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
    00786
    00787     // V4L2_CID_MPEG_VIDEO_DISABLE_DPB should be set after output plane
    00788     // set format
    00789     if (ctx.disable_dpb)
    00790     {
    00791         ret = ctx.dec->disableDPB();
    00792         TEST_ERROR(ret < 0, "Error in disableDPB", cleanup);
    00793     }
    00794
    00795     // Query, Export and Map the output plane buffers so that we can read
    00796     // encoded data into the buffers
    00797     ret = ctx.dec->output_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
    00798     TEST_ERROR(ret < 0, "Error while setting up output plane", cleanup);
    00799
    00800     // Step-2: Create Conv0
    00801     // Create converter to convert from BL to PL for writing raw video
    00802     // to file or crop the frame and display
    00803     ctx.conv = NvVideoConverter::createVideoConverter("conv0");
    00804     TEST_ERROR(!ctx.conv, "Could not create video converter", cleanup);
    00805     ctx.conv->output_plane.setDQThreadCallback(conv0_outputDqbufThreadCallback);
    00806     ctx.conv->capture_plane.setDQThreadCallback(conv0_captureDqbufThreadCallback);
    00807
    00808     // Step-3: Create GIE
    00809     ctx.gie_ctx->buildGieContext(ctx.deployfile, ctx.modelfile);
    00810     pthread_create(&ctx.gie_thread_handle, NULL, gieThread, &ctx);
    00811
    00812     // Start decoder after GIE
    00813     ret = ctx.dec->output_plane.setStreamStatus(true);
    00814     TEST_ERROR(ret < 0, "Error in output plane stream on", cleanup);
    00815     pthread_create(&ctx.dec_capture_loop, NULL, decCaptureLoop, &ctx);
    00816
    00817     // Step-4: Input encoded data to decoder until EOF.
    00818     // Read encoded data and enqueue all the output plane buffers.
    00819     // Exit loop in case file read is complete.
    00820     i = 0;
    00821     while (!eos && !ctx.got_error && !ctx.dec->isInError() &&
    00822             i < ctx.dec->output_plane.getNumBuffers())
    00823     {
    00824         struct v4l2_buffer v4l2_buf;
    00825         struct v4l2_plane planes[MAX_PLANES];
    00826         NvBuffer *buffer;
    00827
    00828         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00829         memset(planes, 0, sizeof(planes));
    00830
    00831         buffer = ctx.dec->output_plane.getNthBuffer(i);
    00832         read_decoder_input_chunk(ctx.in_file, buffer);
    00833
    00834         v4l2_buf.index = i;
    00835         v4l2_buf.m.planes = planes;
    00836         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    00837
    00838         // It is necessary to queue an empty buffer to signal EOS to the decoder
    00839         // i.e. set v4l2_buf.m.planes[0].bytesused = 0 and queue the buffer
    00840         ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
    00841         if (ret < 0)
    00842         {
    00843             cerr << "Error Qing buffer at output plane" << endl;
    00844             abort(&ctx);
    00845             break;
    00846         }
    00847         if (v4l2_buf.m.planes[0].bytesused == 0)
    00848         {
    00849             eos = true;
    00850             cout << "Input file read complete" << endl;
    00851             break;
    00852         }
    00853         i++;
    00854     }
    00855
    00856     // Since all the output plane buffers have been queued, we first need to
    00857     // dequeue a buffer from output plane before we can read new data into it
    00858     // and queue it again.
    00859     while (!eos && !ctx.got_error && !ctx.dec->isInError())
    00860     {
    00861         struct v4l2_buffer v4l2_buf;
    00862         struct v4l2_plane planes[MAX_PLANES];
    00863         NvBuffer *buffer;
    00864
    00865         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00866         memset(planes, 0, sizeof(planes));
    00867
    00868         v4l2_buf.m.planes = planes;
    00869
    00870         ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, -1);
    00871         if (ret < 0)
    00872         {
    00873             cerr << "Error DQing buffer at output plane" << endl;
    00874             abort(&ctx);
    00875             break;
    00876         }
    00877
    00878         read_decoder_input_chunk(ctx.in_file, buffer);
    00879
    00880         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    00881         ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
    00882         if (ret < 0)
    00883         {
    00884             cerr << "Error Qing buffer at output plane" << endl;
    00885             abort(&ctx);
    00886             break;
    00887         }
    00888         if (v4l2_buf.m.planes[0].bytesused == 0)
    00889         {
    00890             eos = true;
    00891             cout << "Input file read complete" << endl;
    00892             break;
    00893         }
    00894     }
    00895
    00896     // Step-5: Handling EOS.
    00897     // After sending EOS, all the buffers from output plane should be dequeued.
    00898     // and after that capture plane loop should be signalled to stop.
    00899     while (ctx.dec->output_plane.getNumQueuedBuffers() > 0 &&
    00900            !ctx.got_error && !ctx.dec->isInError())
    00901     {
    00902         struct v4l2_buffer v4l2_buf;
    00903         struct v4l2_plane planes[MAX_PLANES];
    00904
    00905         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00906         memset(planes, 0, sizeof(planes));
    00907
    00908         v4l2_buf.m.planes = planes;
    00909         ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, NULL, NULL, -1);
    00910         if (ret < 0)
    00911         {
    00912             cerr << "Error DQing buffer at output plane" << endl;
    00913             abort(&ctx);
    00914             break;
    00915         }
    00916     }
    00917
    00918 cleanup:
    00919     // Signal EOS to the decoder capture loop
    00920     ctx.got_eos = true;
    00921     if (ctx.dec_capture_loop)
    00922     {
    00923         pthread_join(ctx.dec_capture_loop, NULL);
    00924     }
    00925
    00926     if (ctx.gie_stop == 0)
    00927     {
    00928         ctx.gie_stop = 1;
    00929         pthread_cond_broadcast(&ctx.gie_cond);
    00930         pthread_join(ctx.gie_thread_handle, NULL);
    00931     }
    00932
    00933     // Send EOS to converter
    00934     if (ctx.conv)
    00935     {
    00936         if (sendEOStoConverter(&ctx) < 0)
    00937         {
    00938             cerr << "Error while queueing EOS buffer on converter output"
    00939                  << endl;
    00940         }
    00941         ctx.conv->capture_plane.waitForDQThread(-1);
    00942     }
    00943
    00944     if (ctx.dec && ctx.dec->isInError())
    00945     {
    00946         cerr << "Decoder is in error" << endl;
    00947         error = 1;
    00948     }
    00949     if (ctx.got_error)
    00950     {
    00951         error = 1;
    00952     }
    00953
    00954     // The decoder destructor does all the cleanup i.e set streamoff on output and capture planes,
    00955     // unmap buffers, tell decoder to deallocate buffer (reqbufs ioctl with counnt = 0),
    00956     // and finally call v4l2_close on the fd.
    00957     delete ctx.dec;
    00958     delete ctx.conv;
    00959
    00960     // Similarly, EglRenderer destructor does all the cleanup
    00961     //delete ctx.renderer;
    00962     delete ctx.in_file;
    00963     delete ctx.conv_output_plane_buf_queue;
    00964     delete []nalu_parse_buffer;
    00965
    00966     free(ctx.in_file_path);
    00967
    00968     delete ctx.gie_buf_queue;
    00969     ctx.gie_ctx->destroyGieContext();
    00970     delete ctx.gie_ctx;
    00971
    00972     if (error)
    00973     {
    00974         cout << "App run failed" << endl;
    00975     }
    00976     else
    00977     {
    00978         cout << "App run was successful" << endl;
    00979     }
    00980     return -error;
    00981 }