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 <errno.h>
00031 #include <fstream>
00032 #include <iostream>
00033 #include <malloc.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036
00037 #include "video_convert.h"
00038
00039 #define TEST_ERROR(cond, str, label) if(cond) { \
00040 cerr << str << endl; \
00041 error = 1; \
00042 goto label; }
00043
00044 using namespace std;
00045
00046 static void
00047 abort(context_t * ctx)
00048 {
00049 ctx->got_error = true;
00050 ctx->conv0->abort();
00051 if (ctx->conv1)
00052 {
00053 ctx->conv1->abort();
00054 }
00055 pthread_cond_broadcast(&ctx->queue_cond);
00056 }
00057 static bool
00058 conv0_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
00059 NvBuffer * buffer, NvBuffer * shared_buffer,
00060 void *arg)
00061 {
00062 context_t *ctx = (context_t *) arg;
00063 NvBuffer *conv1_buffer;
00064 struct v4l2_buffer conv1_qbuf;
00065 struct v4l2_plane planes[MAX_PLANES];
00066
00067 if (!v4l2_buf)
00068 {
00069 cerr << "Failed to dequeue buffer from conv0 capture plane" << endl;
00070 abort(ctx);
00071 return false;
00072 }
00073
00074 if (ctx->in_buftype == BUF_TYPE_NVBL || ctx->out_buftype == BUF_TYPE_NVBL)
00075 {
00076
00077 pthread_mutex_lock(&ctx->queue_lock);
00078 while (ctx->conv1_output_plane_buf_queue->empty() && !ctx->got_error)
00079 {
00080 pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
00081 }
00082
00083 if (ctx->got_error)
00084 {
00085 pthread_mutex_unlock(&ctx->queue_lock);
00086 return false;
00087 }
00088 conv1_buffer = ctx->conv1_output_plane_buf_queue->front();
00089 ctx->conv1_output_plane_buf_queue->pop();
00090 pthread_mutex_unlock(&ctx->queue_lock);
00091
00092 memset(&conv1_qbuf, 0, sizeof(conv1_qbuf));
00093 memset(&planes, 0, sizeof(planes));
00094
00095 conv1_qbuf.index = conv1_buffer->index;
00096 conv1_qbuf.m.planes = planes;
00097
00098
00099
00100 if (ctx->conv1->output_plane.qBuffer(conv1_qbuf, buffer) < 0)
00101 {
00102 cerr << "Error queueing buffer on conv1 output plane" << endl;
00103 abort(ctx);
00104 return false;
00105 }
00106
00107 if (v4l2_buf->m.planes[0].bytesused == 0)
00108 {
00109 return false;
00110 }
00111 }
00112 else
00113 {
00114 if (v4l2_buf->m.planes[0].bytesused == 0)
00115 {
00116 return false;
00117 }
00118 write_video_frame(ctx->out_file, *buffer);
00119 if (ctx->conv0->capture_plane.qBuffer(*v4l2_buf, buffer) < 0)
00120 {
00121 cerr << "Error queueing buffer on conv0 capture plane" << endl;
00122 abort(ctx);
00123 return false;
00124 }
00125 }
00126 return true;
00127 }
00128
00129 static bool
00130 conv1_output_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
00131 NvBuffer * buffer, NvBuffer * shared_buffer,
00132 void *arg)
00133 {
00134 context_t *ctx = (context_t *) arg;
00135 struct v4l2_buffer conv0_ret_qbuf;
00136 struct v4l2_plane planes[MAX_PLANES];
00137
00138 if (!v4l2_buf)
00139 {
00140 cerr << "Failed to dequeue buffer from conv1 output plane" << endl;
00141 abort(ctx);
00142 return false;
00143 }
00144
00145 memset(&conv0_ret_qbuf, 0, sizeof(conv0_ret_qbuf));
00146 memset(&planes, 0, sizeof(planes));
00147
00148
00149 conv0_ret_qbuf.index = shared_buffer->index;
00150 conv0_ret_qbuf.m.planes = planes;
00151
00152
00153
00154
00155 pthread_mutex_lock(&ctx->queue_lock);
00156 if (ctx->conv0->capture_plane.qBuffer(conv0_ret_qbuf, NULL) < 0)
00157 {
00158 cerr << "Error queueing buffer on conv0 capture plane" << endl;
00159 abort(ctx);
00160 return false;
00161 }
00162 ctx->conv1_output_plane_buf_queue->push(buffer);
00163 pthread_cond_broadcast(&ctx->queue_cond);
00164 pthread_mutex_unlock(&ctx->queue_lock);
00165
00166 if (v4l2_buf->m.planes[0].bytesused == 0)
00167 {
00168 return false;
00169 }
00170 return true;
00171 }
00172
00173 static bool
00174 conv1_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
00175 NvBuffer * buffer, NvBuffer * shared_buffer,
00176 void *arg)
00177 {
00178 context_t *ctx = (context_t *) arg;
00179
00180 if (!v4l2_buf)
00181 {
00182 cerr << "Failed to dequeue buffer from conv1 capture plane" << endl;
00183 abort(ctx);
00184 return false;
00185 }
00186
00187 if (v4l2_buf->m.planes[0].bytesused == 0)
00188 {
00189 return false;
00190 }
00191 write_video_frame(ctx->out_file, *buffer);
00192 if (ctx->conv1->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
00193 {
00194 cerr << "Error queueing buffer on conv1 capture plane" << endl;
00195 abort(ctx);
00196 return false;
00197 }
00198 return true;
00199 }
00200
00201 static void
00202 set_defaults(context_t * ctx)
00203 {
00204 memset(ctx, 0, sizeof(context_t));
00205 ctx->conv1_output_plane_buf_queue = new queue < NvBuffer * >;
00206 pthread_mutex_init(&ctx->queue_lock, NULL);
00207 pthread_cond_init(&ctx->queue_cond, NULL);
00208
00209 ctx->interpolation_method = (enum v4l2_interpolation_method) -1;
00210 ctx->tnr_algorithm = (enum v4l2_tnr_algorithm) -1;
00211 ctx->flip_method = (enum v4l2_flip_method) -1;
00212 }
00213
00214 int
00215 main(int argc, char *argv[])
00216 {
00217 context_t ctx;
00218 NvVideoConverter *main_conv;
00219 int ret = 0;
00220 int error = 0;
00221 bool eos = false;
00222
00223 set_defaults(&ctx);
00224
00225 ret = parse_csv_args(&ctx, argc, argv);
00226 TEST_ERROR(ret < 0, "Error parsing commandline arguments", cleanup);
00227
00228 TEST_ERROR(ctx.in_buftype == BUF_TYPE_NVBL &&
00229 ctx.out_buftype == BUF_TYPE_NVBL,
00230 "NV BL -> NV BL conversions are not supported", cleanup);
00231
00232 ctx.in_file = new ifstream(ctx.in_file_path);
00233 TEST_ERROR(!ctx.in_file->is_open(), "Could not open input file", cleanup);
00234
00235 ctx.out_file = new ofstream(ctx.out_file_path);
00236 TEST_ERROR(!ctx.out_file->is_open(), "Could not open output file", cleanup);
00237
00238 ctx.conv0 = NvVideoConverter::createVideoConverter("conv0");
00239 TEST_ERROR(!ctx.conv0, "Could not create Video Converter", cleanup);
00240
00241 if (ctx.in_buftype == BUF_TYPE_NVBL || ctx.out_buftype == BUF_TYPE_NVBL)
00242 {
00243 ctx.conv1 = NvVideoConverter::createVideoConverter("conv1");
00244 TEST_ERROR(!ctx.conv1, "Could not create Video Converter", cleanup);
00245 }
00246
00247 if (ctx.in_buftype == BUF_TYPE_NVBL)
00248 {
00249 main_conv = ctx.conv1;
00250 }
00251 else
00252 {
00253 main_conv = ctx.conv0;
00254 }
00255
00256 if (ctx.flip_method != -1)
00257 {
00258 ret = main_conv->setFlipMethod(ctx.flip_method);
00259 TEST_ERROR(ret < 0, "Could not set flip method", cleanup);
00260 }
00261
00262 if (ctx.interpolation_method != -1)
00263 {
00264 ret = main_conv->setInterpolationMethod(ctx.interpolation_method);
00265 TEST_ERROR(ret < 0, "Could not set interpolation method", cleanup);
00266 }
00267
00268 if (ctx.tnr_algorithm != -1)
00269 {
00270 ret = main_conv->setTnrAlgorithm(ctx.tnr_algorithm);
00271 TEST_ERROR(ret < 0, "Could not set tnr algorithm", cleanup);
00272 }
00273
00274 if (ctx.crop_rect.width != 0 && ctx.crop_rect.height != 0)
00275 {
00276 ret = main_conv->setCropRect(ctx.crop_rect.left, ctx.crop_rect.top,
00277 ctx.crop_rect.width, ctx.crop_rect.height);
00278 TEST_ERROR(ret < 0, "Could not set crop rect for conv0",
00279 cleanup);
00280 }
00281
00282
00283 ret = ctx.conv0->setOutputPlaneFormat(ctx.in_pixfmt, ctx.in_width,
00284 ctx.in_height, V4L2_NV_BUFFER_LAYOUT_PITCH);
00285 TEST_ERROR(ret < 0, "Could not set output plane format for conv0", cleanup);
00286
00287 if (ctx.in_buftype == BUF_TYPE_NVBL)
00288 {
00289
00290 ret = ctx.conv0->setCapturePlaneFormat(ctx.in_pixfmt, ctx.in_width,
00291 ctx.in_height, V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
00292 }
00293 else if (ctx.out_buftype == BUF_TYPE_NVBL)
00294 {
00295 ret = ctx.conv0->setCapturePlaneFormat(ctx.out_pixfmt, ctx.out_width,
00296 ctx.out_height, V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
00297 }
00298 else
00299 {
00300 ret = ctx.conv0->setCapturePlaneFormat(ctx.out_pixfmt, ctx.out_width,
00301 ctx.out_height, V4L2_NV_BUFFER_LAYOUT_PITCH);
00302 }
00303 TEST_ERROR(ret < 0, "Could not set capture plane format for conv0", cleanup);
00304
00305 if (ctx.in_buftype == BUF_TYPE_NVBL)
00306 {
00307
00308 ret =
00309 ctx.conv1->setOutputPlaneFormat(ctx.in_pixfmt, ctx.in_width,
00310 ctx.in_height, V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
00311 }
00312 else if (ctx.out_buftype == BUF_TYPE_NVBL)
00313 {
00314 ret =
00315 ctx.conv1->setOutputPlaneFormat(ctx.out_pixfmt, ctx.out_width,
00316 ctx.out_height, V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
00317 }
00318 TEST_ERROR(ret < 0, "Could not set output plane format for conv1", cleanup);
00319
00320 if (ctx.conv1)
00321 {
00322
00323 ret =
00324 ctx.conv1->setCapturePlaneFormat(ctx.out_pixfmt, ctx.out_width,
00325 ctx.out_height, V4L2_NV_BUFFER_LAYOUT_PITCH);
00326 TEST_ERROR(ret < 0, "Could not set capture plane format for conv1",
00327 cleanup);
00328 }
00329
00330
00331 if (ctx.in_buftype == BUF_TYPE_RAW)
00332 {
00333 ret = ctx.conv0->output_plane.setupPlane(V4L2_MEMORY_USERPTR, 10, false, true);
00334 }
00335 else
00336 {
00337 ret = ctx.conv0->output_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
00338 }
00339 TEST_ERROR(ret < 0, "Error while setting up output plane for conv0",
00340 cleanup);
00341
00342
00343
00344
00345 if (ctx.out_buftype == BUF_TYPE_RAW && ctx.in_buftype != BUF_TYPE_NVBL)
00346 {
00347 ret =
00348 ctx.conv0->capture_plane.setupPlane(V4L2_MEMORY_USERPTR, 10, false, true);
00349 }
00350 else if (ctx.in_buftype == BUF_TYPE_NVBL || ctx.out_buftype == BUF_TYPE_NVBL)
00351 {
00352 ret = ctx.conv0->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 10, false, false);
00353 }
00354 else
00355 {
00356 ret =
00357 ctx.conv0->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
00358 }
00359 TEST_ERROR(ret < 0, "Error while setting up capture plane for conv0",
00360 cleanup);
00361
00362
00363 ret = ctx.conv0->output_plane.setStreamStatus(true);
00364 TEST_ERROR(ret < 0, "Error in output plane streamon for conv0", cleanup);
00365
00366
00367 ret = ctx.conv0->capture_plane.setStreamStatus(true);
00368 TEST_ERROR(ret < 0, "Error in capture plane streamon for conv0", cleanup);
00369
00370 ctx.conv0->
00371 capture_plane.setDQThreadCallback(conv0_capture_dqbuf_thread_callback);
00372
00373 if (ctx.conv1)
00374 {
00375
00376
00377
00378 ret = ctx.conv1->output_plane.setupPlane(V4L2_MEMORY_DMABUF, 10, false,
00379 false);
00380 TEST_ERROR(ret < 0, "Error while setting up output plane for conv1",
00381 cleanup);
00382
00383
00384
00385 if (ctx.out_buftype == BUF_TYPE_RAW)
00386 {
00387 ret = ctx.conv1->capture_plane.setupPlane(V4L2_MEMORY_USERPTR, 10,
00388 false, true);
00389 }
00390 else
00391 {
00392 ret = ctx.conv1->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 10,
00393 true, false);
00394 }
00395 TEST_ERROR(ret < 0, "Error while setting up capture plane for conv1",
00396 cleanup);
00397
00398
00399 ret = ctx.conv1->output_plane.setStreamStatus(true);
00400 TEST_ERROR(ret < 0, "Error in output plane streamon for conv1", cleanup);
00401
00402
00403 ret = ctx.conv1->capture_plane.setStreamStatus(true);
00404 TEST_ERROR(ret < 0, "Error in capture plane streamon for conv1", cleanup);
00405
00406 ctx.conv1->output_plane.setDQThreadCallback(
00407 conv1_output_dqbuf_thread_callback);
00408 ctx.conv1->capture_plane.setDQThreadCallback(
00409 conv1_capture_dqbuf_thread_callback);
00410 }
00411
00412
00413
00414 ctx.conv0->capture_plane.startDQThread(&ctx);
00415 if (ctx.conv1)
00416 {
00417 ctx.conv1->output_plane.startDQThread(&ctx);
00418 ctx.conv1->capture_plane.startDQThread(&ctx);
00419 }
00420
00421
00422 for (uint32_t i = 0; i < ctx.conv0->capture_plane.getNumBuffers(); i++)
00423 {
00424 struct v4l2_buffer v4l2_buf;
00425 struct v4l2_plane planes[MAX_PLANES];
00426
00427 memset(&v4l2_buf, 0, sizeof(v4l2_buf));
00428 memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));
00429
00430 v4l2_buf.index = i;
00431 v4l2_buf.m.planes = planes;
00432
00433 ret = ctx.conv0->capture_plane.qBuffer(v4l2_buf, NULL);
00434 if (ret < 0)
00435 {
00436 cerr << "Error while queueing buffer at conv0 capture plane" << endl;
00437 abort(&ctx);
00438 goto cleanup;
00439 }
00440 }
00441
00442 if (ctx.conv1)
00443 {
00444
00445 for (uint32_t i = 0; i < ctx.conv1->output_plane.getNumBuffers(); i++)
00446 {
00447 ctx.conv1_output_plane_buf_queue->push(ctx.conv1->output_plane.
00448 getNthBuffer(i));
00449 }
00450
00451
00452 for (uint32_t i = 0; i < ctx.conv1->capture_plane.getNumBuffers(); i++)
00453 {
00454 struct v4l2_buffer v4l2_buf;
00455 struct v4l2_plane planes[MAX_PLANES];
00456
00457 memset(&v4l2_buf, 0, sizeof(v4l2_buf));
00458 memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));
00459
00460 v4l2_buf.index = i;
00461 v4l2_buf.m.planes = planes;
00462
00463 ret = ctx.conv1->capture_plane.qBuffer(v4l2_buf, NULL);
00464 if (ret < 0)
00465 {
00466 cerr << "Error while queueing buffer at conv1 capture plane"
00467 << endl;
00468 abort(&ctx);
00469 goto cleanup;
00470 }
00471 }
00472 }
00473
00474
00475 for (uint32_t i = 0; i < ctx.conv0->output_plane.getNumBuffers() &&
00476 !ctx.got_error && !eos; i++)
00477 {
00478 struct v4l2_buffer v4l2_buf;
00479 struct v4l2_plane planes[MAX_PLANES];
00480 NvBuffer *buffer = ctx.conv0->output_plane.getNthBuffer(i);
00481
00482 memset(&v4l2_buf, 0, sizeof(v4l2_buf));
00483 memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));
00484
00485 v4l2_buf.index = i;
00486 v4l2_buf.m.planes = planes;
00487
00488 if (read_video_frame(ctx.in_file, *buffer) < 0)
00489 {
00490 cerr << "Could not read complete frame from input file" << endl;
00491 cerr << "File read complete." << endl;
00492 v4l2_buf.m.planes[0].bytesused = 0;
00493 eos = true;
00494 }
00495
00496 ret = ctx.conv0->output_plane.qBuffer(v4l2_buf, NULL);
00497 if (ret < 0)
00498 {
00499 cerr << "Error while queueing buffer at conv0 output plane" << endl;
00500 abort(&ctx);
00501 goto cleanup;
00502 }
00503 }
00504
00505
00506 while (!ctx.got_error && !ctx.conv0->isInError() &&
00507 (!ctx.conv1 || !ctx.conv1->isInError()) && !eos)
00508 {
00509 struct v4l2_buffer v4l2_buf;
00510 struct v4l2_plane planes[MAX_PLANES];
00511 NvBuffer *buffer;
00512
00513 memset(&v4l2_buf, 0, sizeof(v4l2_buf));
00514 memset(planes, 0, sizeof(planes));
00515
00516 v4l2_buf.m.planes = planes;
00517
00518 if (ctx.conv0->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, 100) < 0)
00519 {
00520 cerr << "ERROR while DQing buffer at conv0 output plane" << endl;
00521 abort(&ctx);
00522 goto cleanup;
00523 }
00524
00525 if (read_video_frame(ctx.in_file, *buffer) < 0)
00526 {
00527 cerr << "Could not read complete frame from input file" << endl;
00528 cerr << "File read complete." << endl;
00529 v4l2_buf.m.planes[0].bytesused = 0;
00530 eos = true;
00531 }
00532
00533 ret = ctx.conv0->output_plane.qBuffer(v4l2_buf, NULL);
00534 if (ret < 0)
00535 {
00536 cerr << "Error while queueing buffer at conv0 output plane" << endl;
00537 abort(&ctx);
00538 goto cleanup;
00539 }
00540 }
00541
00542 if (!ctx.got_error)
00543 {
00544
00545 ctx.conv0->waitForIdle(-1);
00546 if (ctx.conv1)
00547 {
00548 ctx.conv1->waitForIdle(-1);
00549 }
00550 }
00551
00552 cleanup:
00553 if (ctx.conv0 && ctx.conv0->isInError())
00554 {
00555 cerr << "VideoConverter0 is in error" << endl;
00556 error = 1;
00557 }
00558
00559 if (ctx.conv1 && ctx.conv1->isInError())
00560 {
00561 cerr << "VideoConverter1 is in error" << endl;
00562 error = 1;
00563 }
00564
00565 if (ctx.got_error)
00566 {
00567 error = 1;
00568 }
00569
00570 delete ctx.conv1_output_plane_buf_queue;
00571 delete ctx.in_file;
00572 delete ctx.out_file;
00573
00574
00575 delete ctx.conv0;
00576 delete ctx.conv1;
00577
00578 free(ctx.in_file_path);
00579 free(ctx.out_file_path);
00580
00581 if (error)
00582 {
00583 cout << "App run failed" << endl;
00584 }
00585 else
00586 {
00587 cout << "App run was successful" << endl;
00588 }
00589 return -error;
00590 }