00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
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
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
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
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
00146
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
00281
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
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
00323 HandleEGLImage(&ctx->egl_image);
00324
00325
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
00342
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
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
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
00404
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
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
00424
00425
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
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
00448 delete ctx->renderer;
00449
00450 if (ctx->fullscreen)
00451 {
00452
00453 window_width = window_height = 0;
00454 }
00455 else if (ctx->window_width && ctx->window_height)
00456 {
00457
00458 window_width = ctx->window_width;
00459 window_height = ctx->window_height;
00460 }
00461 else
00462 {
00463
00464 window_width = crop.c.width;
00465 window_height = crop.c.height;
00466 }
00467
00468
00469
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
00483 dec->capture_plane.deinitPlane();
00484
00485
00486
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
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
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
00506
00507
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
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
00574 ret = dec->capture_plane.setStreamStatus(true);
00575 TEST_ERROR(ret < 0, "Error in decoder capture plane streamon", error);
00576
00577
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
00615
00616
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
00639 if (!ctx->got_error)
00640 query_and_set_capture(ctx);
00641
00642
00643 while (!(ctx->got_error || dec->isInError() || ctx->got_eos))
00644 {
00645 NvBuffer *dec_buffer;
00646
00647
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
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
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
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
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
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
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
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
00818
00819
00820
00821 ret = ctx.dec->disableCompleteFrameInputBuffer();
00822 TEST_ERROR(ret < 0,
00823 "Error in decoder disableCompleteFrameInputBuffer", cleanup);
00824 }
00825
00826
00827 ret = ctx.dec->setOutputPlaneFormat(ctx.decoder_pixfmt, CHUNK_SIZE);
00828 TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
00829
00830
00831
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
00848
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
00864
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
00892
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
00910
00911
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
00957
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
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
01002
01003
01004 delete ctx.dec;
01005 delete ctx.conv;
01006
01007
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
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 }