- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

# samples/02_video_dec_cuda/videodec_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 "NvCudaProc.h"
    00031 #include "nvbuf_utils.h"
    00032 #include <errno.h>
    00033 #include <fstream>
    00034 #include <iostream>
    00035 #include <string>
    00036 #include <linux/videodev2.h>
    00037 #include <malloc.h>
    00038 #include <pthread.h>
    00039 #include <string.h>
    00040 #include <unistd.h>
    00041 #include <stdlib.h>
    00042 #include <sys/prctl.h>
    00043
    00044 #include "videodec.h"
    00045 #include "nvosd.h"
    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 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
    00054
    00055 #define IS_NAL_UNIT_START(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
    00056         !buffer_ptr[2] && (buffer_ptr[3] == 1))
    00057
    00058 #define IS_NAL_UNIT_START1(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
    00059         (buffer_ptr[2] == 1))
    00060
    00061 #define BORDER_WIDTH 5
    00062
    00063 using namespace std;
    00064
    00065 static int
    00066 read_decoder_input_nalu(ifstream * stream, NvBuffer * buffer,
    00067         char *parse_buffer, streamsize parse_buffer_size)
    00068 {
    00069     // Length is the size of the buffer in bytes
    00070     char *buffer_ptr = (char *) buffer->planes[0].data;
    00071
    00072     char *stream_ptr;
    00073     bool nalu_found = false;
    00074
    00075     streamsize bytes_read;
    00076     streamsize stream_initial_pos = stream->tellg();
    00077
    00078     stream->read(parse_buffer, parse_buffer_size);
    00079     bytes_read = stream->gcount();
    00080
    00081     if (bytes_read == 0)
    00082     {
    00083         return buffer->planes[0].bytesused = 0;
    00084     }
    00085
    00086     // Find the first NAL unit in the buffer
    00087     stream_ptr = parse_buffer;
    00088     while ((stream_ptr - parse_buffer) < (bytes_read - 3))
    00089     {
    00090         nalu_found = IS_NAL_UNIT_START(stream_ptr) ||
    00091                     IS_NAL_UNIT_START1(stream_ptr);
    00092         if (nalu_found)
    00093         {
    00094             break;
    00095         }
    00096         stream_ptr++;
    00097     }
    00098
    00099     // Reached end of buffer but could not find NAL unit
    00100     if (!nalu_found)
    00101     {
    00102         cerr << "Could not read nal unit from file. File seems to be corrupted"
    00103             << endl;
    00104         return -1;
    00105     }
    00106
    00107     memcpy(buffer_ptr, stream_ptr, 4);
    00108     buffer_ptr += 4;
    00109     buffer->planes[0].bytesused = 4;
    00110     stream_ptr += 4;
    00111
    00112     // Copy bytes till the next NAL unit is found
    00113     while ((stream_ptr - parse_buffer) < (bytes_read - 3))
    00114     {
    00115         if (IS_NAL_UNIT_START(stream_ptr) || IS_NAL_UNIT_START1(stream_ptr))
    00116         {
    00117             streamsize seekto = stream_initial_pos +
    00118                     (stream_ptr - parse_buffer);
    00119             if(stream->eof())
    00120             {
    00121                 stream->clear();
    00122             }
    00123             stream->seekg(seekto, stream->beg);
    00124             return 0;
    00125         }
    00126         *buffer_ptr = *stream_ptr;
    00127         buffer_ptr++;
    00128         stream_ptr++;
    00129         buffer->planes[0].bytesused++;
    00130     }
    00131
    00132     // Reached end of buffer but could not find NAL unit
    00133     cerr << "Could not read nal unit from file. File seems to be corrupted"
    00134             << endl;
    00135     return -1;
    00136 }
    00137
    00138 static int
    00139 read_decoder_input_chunk(ifstream * stream, NvBuffer * buffer)
    00140 {
    00141     //length is the size of the buffer in bytes
    00142     streamsize bytes_to_read = MIN(CHUNK_SIZE, buffer->planes[0].length);
    00143
    00144     stream->read((char *) buffer->planes[0].data, bytes_to_read);
    00145     // It is necessary to set bytesused properly, so that decoder knows how
    00146     // many bytes in the buffer are valid
    00147     buffer->planes[0].bytesused = stream->gcount();
    00148     return 0;
    00149 }
    00150
    00151 static void
    00152 abort(context_t *ctx)
    00153 {
    00154     ctx->got_error = true;
    00155     ctx->dec->abort();
    00156     if (ctx->conv)
    00157     {
    00158         ctx->conv->abort();
    00159         pthread_cond_broadcast(&ctx->queue_cond);
    00160     }
    00161 }
    00162
    00163 static void
    00164 get_rect(context_t *ctx)
    00165 {
    00166     unsigned int i;
    00167     string line;
    00168     int frameNum = 0;
    00169     int rect_id = 0;
    00170     ctx->g_rect_num = 0;
    00171
    00172     if (ctx->osd_file->is_open())
    00173     {
    00174         while (getline(*ctx->osd_file, line))
    00175         {
    00176             std::string frameNumPrefix = "frame:";
    00177             std::string rectNumPrefix = " has rect:";
    00178             std::string xywhPrefix = "x,y,w,h:";
    00179             if (line.compare(0, frameNumPrefix.size(), frameNumPrefix) == 0)
    00180             {
    00181                 string strFrameNum = line.substr(6, line.find(rectNumPrefix) - 6);
    00182                 frameNum = atoi(strFrameNum.c_str());
    00183                 string strRectNum =
    00184                             line.substr(line.find(rectNumPrefix) + rectNumPrefix.size(),
    00185                                         line.size());
    00186                 ctx->g_rect_num = atoi(strRectNum.c_str());
    00187
    00188                 if (log_level >= LOG_LEVEL_DEBUG)
    00189                 {
    00190                     cout << "frameNum: " << frameNum
    00191                          << " Rect Num: " << ctx->g_rect_num << endl;
    00192                 }
    00193             }
    00194             else if (std::string::npos != line.find(xywhPrefix))
    00195             {
    00196                 string xywh = line.substr(line.find(xywhPrefix) + xywhPrefix.size(),
    00197                                           line.size());
    00198                 for (i = 0; i < xywh.size(); ++i)
    00199                 {
    00200                     if (isspace(xywh.at(i))) xywh.replace(i, 1, 1, ':');
    00201                 }
    00202                 string x = xywh.substr(0, xywh.find(":"));
    00203                 xywh = xywh.substr(x.size() + 1);
    00204                 string y = xywh.substr(0, xywh.find(":"));
    00205                 xywh = xywh.substr(y.size() + 1);
    00206                 string w = xywh.substr(0, xywh.find(":"));
    00207                 xywh = xywh.substr(w.size() + 1);
    00208                 string h = xywh.substr(0);
    00209                 ctx->g_rect[rect_id].left =  atof(x.c_str()) * ctx->dec_width;
    00210                 ctx->g_rect[rect_id].top =  atof(y.c_str()) * ctx->dec_height;
    00211                 ctx->g_rect[rect_id].width = atof(w.c_str()) * ctx->dec_width;
    00212                 ctx->g_rect[rect_id].height = atof(h.c_str()) * ctx->dec_height;
    00213
    00214                 if (log_level >= LOG_LEVEL_DEBUG)
    00215                 {
    00216                     cout << "xywh: " << ctx->g_rect[rect_id].left << ":"
    00217                                      << ctx->g_rect[rect_id].top << ":"
    00218                                      << ctx->g_rect[rect_id].width << ":"
    00219                                      << ctx->g_rect[rect_id].height << endl;
    00220                 }
    00221
    00222                 if (ctx->g_rect[rect_id].width < 10 ||
    00223                     ctx->g_rect[rect_id].height < 10)
    00224                 {
    00225                     if (log_level >= LOG_LEVEL_WARN)
    00226                     {
    00227                         cout << "Invalid xywh." << endl;
    00228                     }
    00229                     ctx->g_rect_num--;
    00230                     continue;
    00231                 }
    00232
    00233                 for (i = 0; i < (unsigned int) ctx->g_rect_num; ++i)
    00234                 {
    00235                     ctx->g_rect[i].border_width = BORDER_WIDTH;
    00236                     ctx->g_rect[i].border_color.red = 1.0f;
    00237                     ctx->g_rect[i].border_color.green = 0.0;
    00238                     ctx->g_rect[i].border_color.blue = 0.0;
    00239                 }
    00240                 rect_id ++;
    00241             }
    00242             else
    00243             {
    00244                 break;
    00245             }
    00246         }
    00247     }
    00248 }
    00249
    00250 static bool
    00251 conv0_output_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00252                                    NvBuffer * buffer, NvBuffer * shared_buffer,
    00253                                    void *arg)
    00254 {
    00255     context_t *ctx = (context_t *) arg;
    00256     struct v4l2_buffer dec_capture_ret_buffer;
    00257     struct v4l2_plane planes[MAX_PLANES];
    00258
    00259     if (!v4l2_buf)
    00260     {
    00261         cerr << "Failed to dequeue buffer from conv0 output plane" << endl;
    00262         abort(ctx);
    00263         return false;
    00264     }
    00265
    00266     if (v4l2_buf->m.planes[0].bytesused == 0)
    00267     {
    00268         return false;
    00269     }
    00270
    00271     memset(&dec_capture_ret_buffer, 0, sizeof(dec_capture_ret_buffer));
    00272     memset(planes, 0, sizeof(planes));
    00273
    00274     dec_capture_ret_buffer.index = shared_buffer->index;
    00275     dec_capture_ret_buffer.m.planes = planes;
    00276
    00277     pthread_mutex_lock(&ctx->queue_lock);
    00278     ctx->conv_output_plane_buf_queue->push(buffer);
    00279
    00280     // Return the buffer dequeued from converter output plane
    00281     // back to decoder capture plane
    00282     if (ctx->dec->capture_plane.qBuffer(dec_capture_ret_buffer, NULL) < 0)
    00283     {
    00284         abort(ctx);
    00285         return false;
    00286     }
    00287
    00288     pthread_cond_broadcast(&ctx->queue_cond);
    00289     pthread_mutex_unlock(&ctx->queue_lock);
    00290
    00291     return true;
    00292 }
    00293
    00294 static bool
    00295 conv0_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
    00296                                     NvBuffer * buffer, NvBuffer * shared_buffer,
    00297                                     void *arg)
    00298 {
    00299     context_t *ctx = (context_t *) arg;
    00300
    00301     if (!v4l2_buf)
    00302     {
    00303         cerr << "Failed to dequeue buffer from conv0 output plane" << endl;
    00304         abort(ctx);
    00305         return false;
    00306     }
    00307
    00308     if (v4l2_buf->m.planes[0].bytesused == 0)
    00309     {
    00310         return false;
    00311     }
    00312
    00313     // Create EGLImage from dmabuf fd
    00314     ctx->egl_image = NvEGLImageFromFd(ctx->egl_display, buffer->planes[0].fd);
    00315     if (ctx->egl_image == NULL)
    00316     {
    00317         fprintf(stderr, "Error while mapping dmabuf fd (0x%X) to EGLImage\n",
    00318                  buffer->planes[0].fd);
    00319         return false;
    00320     }
    00321
    00322     // Running algo process with EGLImage via GPU multi cores
    00323     HandleEGLImage(&ctx->egl_image);
    00324
    00325     // Destroy EGLImage
    00326     NvDestroyEGLImage(ctx->egl_display, ctx->egl_image);
    00327     ctx->egl_image = NULL;
    00328
    00329     if (ctx->enable_osd) {
    00330         get_rect(ctx);
    00331     }
    00332
    00333     if (ctx->g_rect_num > 0) {
    00334         nvosd_draw_rectangles(ctx->nvosd_context,
    00335                               MODE_HW,
    00336                               buffer->planes[0].fd,
    00337                               ctx->g_rect_num,
    00338                               ctx->g_rect);
    00339      }
    00340
    00341     // Write raw video frame to file and return the buffer to converter
    00342     // capture plane
    00343     if (ctx->out_file)
    00344     {
    00345         write_video_frame(ctx->out_file, *buffer);
    00346     }
    00347
    00348     if (!ctx->disable_rendering)
    00349     {
    00350         ctx->renderer->render(buffer->planes[0].fd);
    00351     }
    00352
    00353     if (ctx->conv->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
    00354     {
    00355         return false;
    00356     }
    00357     return true;
    00358 }
    00359
    00360 static int
    00361 sendEOStoConverter(context_t *ctx)
    00362 {
    00363     // Check if converter is running
    00364     if (ctx->conv->output_plane.getStreamStatus())
    00365     {
    00366         NvBuffer *conv_buffer;
    00367         struct v4l2_buffer v4l2_buf;
    00368         struct v4l2_plane planes[MAX_PLANES];
    00369
    00370         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00371         memset(&planes, 0, sizeof(planes));
    00372
    00373         v4l2_buf.m.planes = planes;
    00374         pthread_mutex_lock(&ctx->queue_lock);
    00375         while (ctx->conv_output_plane_buf_queue->empty())
    00376         {
    00377             pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
    00378         }
    00379         conv_buffer = ctx->conv_output_plane_buf_queue->front();
    00380         ctx->conv_output_plane_buf_queue->pop();
    00381         pthread_mutex_unlock(&ctx->queue_lock);
    00382
    00383         v4l2_buf.index = conv_buffer->index;
    00384
    00385         // Queue EOS buffer on converter output plane
    00386         return ctx->conv->output_plane.qBuffer(v4l2_buf, NULL);
    00387     }
    00388     return 0;
    00389 }
    00390
    00391 static void
    00392 query_and_set_capture(context_t * ctx)
    00393 {
    00394     NvVideoDecoder *dec = ctx->dec;
    00395     struct v4l2_format format;
    00396     struct v4l2_crop crop;
    00397     int32_t min_dec_capture_buffers;
    00398     int ret = 0;
    00399     int error = 0;
    00400     uint32_t window_width;
    00401     uint32_t window_height;
    00402
    00403     // Get capture plane format from the decoder. This may change after
    00404     // an resolution change event
    00405     ret = dec->capture_plane.getFormat(format);
    00406     TEST_ERROR(ret < 0,
    00407                "Error: Could not get format from decoder capture plane", error);
    00408
    00409     // Get the display resolution from the decoder
    00410     ret = dec->capture_plane.getCrop(crop);
    00411     TEST_ERROR(ret < 0,
    00412                "Error: Could not get crop from decoder capture plane", error);
    00413
    00414     cout << "Video Resolution: " << crop.c.width << "x" << crop.c.height
    00415         << endl;
    00416
    00417     if (ctx->enable_osd)
    00418     {
    00419         ctx->dec_width = crop.c.width;
    00420         ctx->dec_height = crop.c.height;
    00421     }
    00422
    00423     // For file write, first deinitialize output and capture planes
    00424     // of video converter and then use the new resolution from
    00425     // decoder event resolution change
    00426     if (ctx->conv)
    00427     {
    00428         ret = sendEOStoConverter(ctx);
    00429         TEST_ERROR(ret < 0,
    00430                    "Error while queueing EOS buffer on converter output",
    00431                    error);
    00432
    00433         // Wait for EOS buffer to arrive on capture plane
    00434         ctx->conv->capture_plane.waitForDQThread(2000);
    00435
    00436         ctx->conv->output_plane.deinitPlane();
    00437         ctx->conv->capture_plane.deinitPlane();
    00438
    00439         while(!ctx->conv_output_plane_buf_queue->empty())
    00440         {
    00441             ctx->conv_output_plane_buf_queue->pop();
    00442         }
    00443     }
    00444
    00445     if (!ctx->disable_rendering)
    00446     {
    00447         // Destroy the old instance of renderer as resolution might have changed
    00448         delete ctx->renderer;
    00449
    00450         if (ctx->fullscreen)
    00451         {
    00452             // Required for fullscreen
    00453             window_width = window_height = 0;
    00454         }
    00455         else if (ctx->window_width && ctx->window_height)
    00456         {
    00457             // As specified by user on commandline
    00458             window_width = ctx->window_width;
    00459             window_height = ctx->window_height;
    00460         }
    00461         else
    00462         {
    00463             // Resolution got from the decoder
    00464             window_width = crop.c.width;
    00465             window_height = crop.c.height;
    00466         }
    00467
    00468         // If height or width are set to zero, EglRenderer creates a fullscreen
    00469         // window
    00470         ctx->renderer =
    00471             NvEglRenderer::createEglRenderer("renderer0", window_width,
    00472                                            window_height, ctx->window_x,
    00473                                            ctx->window_y);
    00474         TEST_ERROR(!ctx->renderer,
    00475                    "Error in setting up renderer. "
    00476                    "Check if X is running or run with --disable-rendering",
    00477                    error);
    00478
    00479         ctx->renderer->setFPS(ctx->fps);
    00480     }
    00481
    00482     // deinitPlane unmaps the buffers and calls REQBUFS with count 0
    00483     dec->capture_plane.deinitPlane();
    00484
    00485     // Not necessary to call VIDIOC_S_FMT on decoder capture plane.
    00486     // But decoder setCapturePlaneFormat function updates the class variables
    00487     ret = dec->setCapturePlaneFormat(format.fmt.pix_mp.pixelformat,
    00488                                      format.fmt.pix_mp.width,
    00489                                      format.fmt.pix_mp.height);
    00490     TEST_ERROR(ret < 0, "Error in setting decoder capture plane format", error);
    00491
    00492     // Get the minimum buffers which have to be requested on the capture plane
    00493     ret = dec->getMinimumCapturePlaneBuffers(min_dec_capture_buffers);
    00494     TEST_ERROR(ret < 0,
    00495                "Error while getting value of minimum capture plane buffers",
    00496                error);
    00497
    00498     // Request (min + 5) buffers, export and map buffers
    00499     ret =
    00500         dec->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00501                                        min_dec_capture_buffers + 5, false,
    00502                                        false);
    00503     TEST_ERROR(ret < 0, "Error in decoder capture plane setup", error);
    00504
    00505     // For file write, first deinitialize output and capture planes
    00506     // of video converter and then use the new resolution from
    00507     // decoder event resolution change
    00508     if (ctx->conv)
    00509     {
    00510         ret = ctx->conv->setOutputPlaneFormat(format.fmt.pix_mp.pixelformat,
    00511                                               format.fmt.pix_mp.width,
    00512                                               format.fmt.pix_mp.height,
    00513                                               V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
    00514         TEST_ERROR(ret < 0, "Error in converter output plane set format",
    00515                    error);
    00516
    00517         ret = ctx->conv->setCapturePlaneFormat((ctx->out_pixfmt == 1 ?
    00518                                                     V4L2_PIX_FMT_NV12M :
    00519                                                     V4L2_PIX_FMT_YUV420M),
    00520                                                 crop.c.width,
    00521                                                 crop.c.height,
    00522                                                 V4L2_NV_BUFFER_LAYOUT_PITCH);
    00523         TEST_ERROR(ret < 0, "Error in converter capture plane set format",
    00524                    error);
    00525
    00526         ret = ctx->conv->setCropRect(0, 0, crop.c.width, crop.c.height);
    00527         TEST_ERROR(ret < 0, "Error while setting crop rect", error);
    00528
    00529         ret =
    00530             ctx->conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF,
    00531                                                 dec->capture_plane.
    00532                                                 getNumBuffers(), false, false);
    00533         TEST_ERROR(ret < 0, "Error in converter output plane setup", error);
    00534
    00535         ret =
    00536             ctx->conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
    00537                                                  dec->capture_plane.
    00538                                                  getNumBuffers(), true, false);
    00539         TEST_ERROR(ret < 0, "Error in converter capture plane setup", error);
    00540
    00541         ret = ctx->conv->output_plane.setStreamStatus(true);
    00542         TEST_ERROR(ret < 0, "Error in converter output plane streamon", error);
    00543
    00544         ret = ctx->conv->capture_plane.setStreamStatus(true);
    00545         TEST_ERROR(ret < 0, "Error in converter output plane streamoff", error);
    00546
    00547         // Add all empty conv output plane buffers to conv_output_plane_buf_queue
    00548         for (uint32_t i = 0; i < ctx->conv->output_plane.getNumBuffers(); i++)
    00549         {
    00550             ctx->conv_output_plane_buf_queue->push(ctx->conv->output_plane.
    00551                     getNthBuffer(i));
    00552         }
    00553
    00554         for (uint32_t i = 0; i < ctx->conv->capture_plane.getNumBuffers(); i++)
    00555         {
    00556             struct v4l2_buffer v4l2_buf;
    00557             struct v4l2_plane planes[MAX_PLANES];
    00558
    00559             memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00560             memset(planes, 0, sizeof(planes));
    00561
    00562             v4l2_buf.index = i;
    00563             v4l2_buf.m.planes = planes;
    00564             ret = ctx->conv->capture_plane.qBuffer(v4l2_buf, NULL);
    00565             TEST_ERROR(ret < 0, "Error Qing buffer at converter capture plane",
    00566                        error);
    00567         }
    00568         ctx->conv->output_plane.startDQThread(ctx);
    00569         ctx->conv->capture_plane.startDQThread(ctx);
    00570
    00571     }
    00572
    00573     // Capture plane STREAMON
    00574     ret = dec->capture_plane.setStreamStatus(true);
    00575     TEST_ERROR(ret < 0, "Error in decoder capture plane streamon", error);
    00576
    00577     // Enqueue all the empty capture plane buffers
    00578     for (uint32_t i = 0; i < dec->capture_plane.getNumBuffers(); i++)
    00579     {
    00580         struct v4l2_buffer v4l2_buf;
    00581         struct v4l2_plane planes[MAX_PLANES];
    00582
    00583         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00584         memset(planes, 0, sizeof(planes));
    00585
    00586         v4l2_buf.index = i;
    00587         v4l2_buf.m.planes = planes;
    00588         ret = dec->capture_plane.qBuffer(v4l2_buf, NULL);
    00589         TEST_ERROR(ret < 0, "Error Qing buffer at output plane", error);
    00590     }
    00591
    00592     cout << "Query and set capture successful" << endl;
    00593     return;
    00594
    00595 error:
    00596     if (error)
    00597     {
    00598         abort(ctx);
    00599         cerr << "Error in " << __func__ << endl;
    00600     }
    00601 }
    00602
    00603 static void *
    00604 dec_capture_loop_fcn(void *arg)
    00605 {
    00606     context_t *ctx = (context_t *) arg;
    00607     NvVideoDecoder *dec = ctx->dec;
    00608     struct v4l2_event ev;
    00609     int ret;
    00610
    00611     cout << "Starting decoder capture loop thread" << endl;
    00612     prctl (PR_SET_NAME, "dec_cap", 0, 0, 0);
    00613
    00614     // Need to wait for the first Resolution change event, so that
    00615     // the decoder knows the stream resolution and can allocate appropriate
    00616     // buffers when we call REQBUFS
    00617     do
    00618     {
    00619         ret = dec->dqEvent(ev, 1000);
    00620         if (ret < 0)
    00621         {
    00622             if (errno == EAGAIN)
    00623             {
    00624                 cerr <<
    00625                     "Timed out waiting for first V4L2_EVENT_RESOLUTION_CHANGE"
    00626                     << endl;
    00627             }
    00628             else
    00629             {
    00630                 cerr << "Error in dequeueing decoder event" << endl;
    00631             }
    00632             abort(ctx);
    00633             break;
    00634         }
    00635     }
    00636     while (ev.type != V4L2_EVENT_RESOLUTION_CHANGE);
    00637
    00638     // query_and_set_capture acts on the resolution change event
    00639     if (!ctx->got_error)
    00640         query_and_set_capture(ctx);
    00641
    00642     // Exit on error or EOS which is signalled in main()
    00643     while (!(ctx->got_error || dec->isInError() || ctx->got_eos))
    00644     {
    00645         NvBuffer *dec_buffer;
    00646
    00647         // Check for Resolution change again
    00648         ret = dec->dqEvent(ev, false);
    00649         if (ret == 0)
    00650         {
    00651             switch (ev.type)
    00652             {
    00653                 case V4L2_EVENT_RESOLUTION_CHANGE:
    00654                     query_and_set_capture(ctx);
    00655                     continue;
    00656             }
    00657         }
    00658
    00659         while (1)
    00660         {
    00661             struct v4l2_buffer v4l2_buf;
    00662             struct v4l2_plane planes[MAX_PLANES];
    00663
    00664             memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00665             memset(planes, 0, sizeof(planes));
    00666             v4l2_buf.m.planes = planes;
    00667
    00668             // Dequeue a filled buffer
    00669             if (dec->capture_plane.dqBuffer(v4l2_buf, &dec_buffer, NULL, 0))
    00670             {
    00671                 if (errno == EAGAIN)
    00672                 {
    00673                     usleep(1000);
    00674                 }
    00675                 else
    00676                 {
    00677                     abort(ctx);
    00678                     cerr << "Error while calling dequeue at capture plane" <<
    00679                         endl;
    00680                 }
    00681                 break;
    00682             }
    00683
    00684             // Give the buffer to video converter output plane
    00685             if (ctx->conv)
    00686             {
    00687                 NvBuffer *conv_buffer;
    00688                 struct v4l2_buffer conv_output_buffer;
    00689                 struct v4l2_plane conv_planes[MAX_PLANES];
    00690
    00691                 memset(&conv_output_buffer, 0, sizeof(conv_output_buffer));
    00692                 memset(conv_planes, 0, sizeof(conv_planes));
    00693                 conv_output_buffer.m.planes = conv_planes;
    00694
    00695                 // Get an empty conv output plane buffer from conv_output_plane_buf_queue
    00696                 pthread_mutex_lock(&ctx->queue_lock);
    00697                 while (ctx->conv_output_plane_buf_queue->empty())
    00698                 {
    00699                     pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
    00700                 }
    00701                 conv_buffer = ctx->conv_output_plane_buf_queue->front();
    00702                 ctx->conv_output_plane_buf_queue->pop();
    00703                 pthread_mutex_unlock(&ctx->queue_lock);
    00704
    00705                 conv_output_buffer.index = conv_buffer->index;
    00706
    00707                 if (ctx->conv->output_plane.
    00708                         qBuffer(conv_output_buffer, dec_buffer) < 0)
    00709                 {
    00710                     abort(ctx);
    00711                     cerr <<
    00712                         "Error while queueing buffer at converter output plane"
    00713                         << endl;
    00714                     break;
    00715                 }
    00716             }
    00717             else
    00718             {
    00719                 if (ctx->dec->capture_plane.qBuffer(v4l2_buf, NULL) < 0)
    00720                 {
    00721                     abort(ctx);
    00722                     cerr << "Error while queueing buffer at decoder capture plane"
    00723                          << endl;
    00724                     break;
    00725                 }
    00726             }
    00727         }
    00728     }
    00729
    00730     // Send EOS to converter
    00731     if (ctx->conv)
    00732     {
    00733         if (sendEOStoConverter(ctx) < 0)
    00734         {
    00735             cerr << "Error while queueing EOS buffer on converter output"
    00736                  << endl;
    00737         }
    00738     }
    00739
    00740     cout << "Exiting decoder capture loop thread" << endl;
    00741     return NULL;
    00742 }
    00743
    00744 static void
    00745 set_defaults(context_t * ctx)
    00746 {
    00747     memset(ctx, 0, sizeof(context_t));
    00748     ctx->fullscreen = false;
    00749     ctx->window_height = 0;
    00750     ctx->window_width = 0;
    00751     ctx->window_x = 0;
    00752     ctx->window_y = 0;
    00753     ctx->out_pixfmt = 1;
    00754     ctx->fps = 30;
    00755     ctx->nvosd_context = NULL;
    00756
    00757     ctx->conv_output_plane_buf_queue = new queue < NvBuffer * >;
    00758     pthread_mutex_init(&ctx->queue_lock, NULL);
    00759     pthread_cond_init(&ctx->queue_cond, NULL);
    00760 }
    00761
    00762 int
    00763 main(int argc, char *argv[])
    00764 {
    00765     context_t ctx;
    00766     int ret = 0;
    00767     int error = 0;
    00768     uint32_t i;
    00769     bool eos = false;
    00770     char *nalu_parse_buffer = NULL;
    00771
    00772     set_defaults(&ctx);
    00773
    00774     if (parse_csv_args(&ctx, argc, argv))
    00775     {
    00776         fprintf(stderr, "Error parsing commandline arguments\n");
    00777         return -1;
    00778     }
    00779
    00780     // Get defalut EGL display
    00781     ctx.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    00782     if (ctx.egl_display == EGL_NO_DISPLAY)
    00783     {
    00784         fprintf(stderr, "Error while get EGL display connection\n");
    00785         return -1;
    00786     }
    00787
    00788     // Init EGL display connection
    00789     if (!eglInitialize(ctx.egl_display, NULL, NULL))
    00790     {
    00791         fprintf(stderr, "Erro while initialize EGL display connection\n");
    00792         return -1;
    00793     }
    00794
    00795     if (ctx.enable_osd) {
    00796         ctx.nvosd_context = nvosd_create_context();
    00797         cout << "ctx.osd_file_path:" << ctx.osd_file_path << endl;
    00798
    00799         ctx.osd_file = new ifstream(ctx.osd_file_path);
    00800         TEST_ERROR(!ctx.osd_file->is_open(), "Error opening osd file", cleanup);
    00801     }
    00802
    00803     ctx.dec = NvVideoDecoder::createVideoDecoder("dec0");
    00804     TEST_ERROR(!ctx.dec, "Could not create decoder", cleanup);
    00805
    00806     // Subscribe to Resolution change event
    00807     ret = ctx.dec->subscribeEvent(V4L2_EVENT_RESOLUTION_CHANGE, 0, 0);
    00808     TEST_ERROR(ret < 0, "Could not subscribe to V4L2_EVENT_RESOLUTION_CHANGE",
    00809             cleanup);
    00810
    00811     if (ctx.input_nalu)
    00812     {
    00813         nalu_parse_buffer = new char[CHUNK_SIZE];
    00814     }
    00815     else
    00816     {
    00817         // Set V4L2_CID_MPEG_VIDEO_DISABLE_COMPLETE_FRAME_INPUT control to false
    00818         // so that application can send chunks of encoded data instead of forming
    00819         // complete frames. This needs to be done before setting format on the
    00820         // output plane.
    00821         ret = ctx.dec->disableCompleteFrameInputBuffer();
    00822         TEST_ERROR(ret < 0,
    00823                 "Error in decoder disableCompleteFrameInputBuffer", cleanup);
    00824     }
    00825
    00826     // Set format on the output plane
    00827     ret = ctx.dec->setOutputPlaneFormat(ctx.decoder_pixfmt, CHUNK_SIZE);
    00828     TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
    00829
    00830     // Query, Export and Map the output plane buffers so that we can read
    00831     // encoded data into the buffers
    00832     ret = ctx.dec->output_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
    00833     TEST_ERROR(ret < 0, "Error while setting up output plane", cleanup);
    00834
    00835     ctx.in_file = new ifstream(ctx.in_file_path);
    00836     TEST_ERROR(!ctx.in_file->is_open(), "Error opening input file", cleanup);
    00837
    00838     if (ctx.out_file_path)
    00839     {
    00840         ctx.out_file = new ofstream(ctx.out_file_path);
    00841         TEST_ERROR(!ctx.out_file->is_open(), "Error opening output file",
    00842                 cleanup);
    00843     }
    00844
    00845     if (ctx.out_file || !ctx.disable_rendering)
    00846     {
    00847         // Create converter to convert from BL to PL for writing raw video
    00848         // to file or crop the frame and display
    00849         ctx.conv = NvVideoConverter::createVideoConverter("conv0");
    00850         TEST_ERROR(!ctx.conv, "Could not create video converter", cleanup);
    00851         ctx.conv->output_plane.
    00852             setDQThreadCallback(conv0_output_dqbuf_thread_callback);
    00853         ctx.conv->capture_plane.
    00854             setDQThreadCallback(conv0_capture_dqbuf_thread_callback);
    00855
    00856     }
    00857
    00858     ret = ctx.dec->output_plane.setStreamStatus(true);
    00859     TEST_ERROR(ret < 0, "Error in output plane stream on", cleanup);
    00860
    00861     pthread_create(&ctx.dec_capture_loop, NULL, dec_capture_loop_fcn, &ctx);
    00862
    00863     // Read encoded data and enqueue all the output plane buffers.
    00864     // Exit loop in case file read is complete.
    00865     i = 0;
    00866     while (!eos && !ctx.got_error && !ctx.dec->isInError() &&
    00867             i < ctx.dec->output_plane.getNumBuffers())
    00868     {
    00869         struct v4l2_buffer v4l2_buf;
    00870         struct v4l2_plane planes[MAX_PLANES];
    00871         NvBuffer *buffer;
    00872
    00873         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00874         memset(planes, 0, sizeof(planes));
    00875
    00876         buffer = ctx.dec->output_plane.getNthBuffer(i);
    00877         if (ctx.input_nalu)
    00878         {
    00879             read_decoder_input_nalu(ctx.in_file, buffer, nalu_parse_buffer,
    00880                     CHUNK_SIZE);
    00881         }
    00882         else
    00883         {
    00884             read_decoder_input_chunk(ctx.in_file, buffer);
    00885         }
    00886
    00887         v4l2_buf.index = i;
    00888         v4l2_buf.m.planes = planes;
    00889         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    00890
    00891         // It is necessary to queue an empty buffer to signal EOS to the decoder
    00892         // i.e. set v4l2_buf.m.planes[0].bytesused = 0 and queue the buffer
    00893         ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
    00894         if (ret < 0)
    00895         {
    00896             cerr << "Error Qing buffer at output plane" << endl;
    00897             abort(&ctx);
    00898             break;
    00899         }
    00900         if (v4l2_buf.m.planes[0].bytesused == 0)
    00901         {
    00902             eos = true;
    00903             cout << "Input file read complete" << endl;
    00904             break;
    00905         }
    00906         i++;
    00907     }
    00908
    00909     // Since all the output plane buffers have been queued, we first need to
    00910     // dequeue a buffer from output plane before we can read new data into it
    00911     // and queue it again.
    00912     while (!eos && !ctx.got_error && !ctx.dec->isInError())
    00913     {
    00914         struct v4l2_buffer v4l2_buf;
    00915         struct v4l2_plane planes[MAX_PLANES];
    00916         NvBuffer *buffer;
    00917
    00918         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00919         memset(planes, 0, sizeof(planes));
    00920
    00921         v4l2_buf.m.planes = planes;
    00922
    00923         ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, -1);
    00924         if (ret < 0)
    00925         {
    00926             cerr << "Error DQing buffer at output plane" << endl;
    00927             abort(&ctx);
    00928             break;
    00929         }
    00930
    00931         if (ctx.input_nalu)
    00932         {
    00933             read_decoder_input_nalu(ctx.in_file, buffer, nalu_parse_buffer,
    00934                     CHUNK_SIZE);
    00935         }
    00936         else
    00937         {
    00938             read_decoder_input_chunk(ctx.in_file, buffer);
    00939         }
    00940         v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
    00941         ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
    00942         if (ret < 0)
    00943         {
    00944             cerr << "Error Qing buffer at output plane" << endl;
    00945             abort(&ctx);
    00946             break;
    00947         }
    00948         if (v4l2_buf.m.planes[0].bytesused == 0)
    00949         {
    00950             eos = true;
    00951             cout << "Input file read complete" << endl;
    00952             break;
    00953         }
    00954     }
    00955
    00956     // After sending EOS, all the buffers from output plane should be dequeued.
    00957     // and after that capture plane loop should be signalled to stop.
    00958     while (ctx.dec->output_plane.getNumQueuedBuffers() > 0 &&
    00959            !ctx.got_error && !ctx.dec->isInError())
    00960     {
    00961         struct v4l2_buffer v4l2_buf;
    00962         struct v4l2_plane planes[MAX_PLANES];
    00963
    00964         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00965         memset(planes, 0, sizeof(planes));
    00966
    00967         v4l2_buf.m.planes = planes;
    00968         ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, NULL, NULL, -1);
    00969         if (ret < 0)
    00970         {
    00971             cerr << "Error DQing buffer at output plane" << endl;
    00972             abort(&ctx);
    00973             break;
    00974         }
    00975     }
    00976
    00977     // Signal EOS to the decoder capture loop
    00978     ctx.got_eos = true;
    00979
    00980     if (ctx.conv)
    00981     {
    00982         ctx.conv->capture_plane.waitForDQThread(-1);
    00983     }
    00984
    00985 cleanup:
    00986     if (ctx.dec_capture_loop)
    00987     {
    00988         pthread_join(ctx.dec_capture_loop, NULL);
    00989     }
    00990
    00991     if (ctx.dec && ctx.dec->isInError())
    00992     {
    00993         cerr << "Decoder is in error" << endl;
    00994         error = 1;
    00995     }
    00996     if (ctx.got_error)
    00997     {
    00998         error = 1;
    00999     }
    01000
    01001     // The decoder destructor does all the cleanup i.e set streamoff on output and capture planes,
    01002     // unmap buffers, tell decoder to deallocate buffer (reqbufs ioctl with counnt = 0),
    01003     // and finally call v4l2_close on the fd.
    01004     delete ctx.dec;
    01005     delete ctx.conv;
    01006
    01007     // Similarly, EglRenderer destructor does all the cleanup
    01008     delete ctx.renderer;
    01009     delete ctx.in_file;
    01010     delete ctx.out_file;
    01011     delete ctx.conv_output_plane_buf_queue;
    01012     delete []nalu_parse_buffer;
    01013
    01014     free(ctx.in_file_path);
    01015     free(ctx.out_file_path);
    01016     if (ctx.enable_osd) {
    01017         ctx.osd_file->close();
    01018         free(ctx.osd_file_path);
    01019     }
    01020
    01021     // Terminate EGL display connection
    01022     if (ctx.egl_display)
    01023     {
    01024         if(!eglTerminate(ctx.egl_display))
    01025         {
    01026             fprintf(stderr, "Error while terminate EGL display connection\n");
    01027             return -1;
    01028         }
    01029     }
    01030     if (ctx.enable_osd)
    01031     {
    01032         nvosd_destroy_context(ctx.nvosd_context);
    01033         ctx.nvosd_context = NULL;
    01034     }
    01035
    01036     if (error)
    01037     {
    01038         cout << "App run failed" << endl;
    01039     }
    01040     else
    01041     {
    01042         cout << "App run was successful" << endl;
    01043     }
    01044     return -error;
    01045 }