- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

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