- Main Page
- Modules
- Namespaces
- Classes
- Files

- Search for |

- File List
- File Members

# samples/03_video_cuda_enc/video_cuda_enc_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 "NvVideoEncoder.h"
    00030 #include "NvUtils.h"
    00031 #include <fstream>
    00032 #include <iostream>
    00033 #include <linux/videodev2.h>
    00034 #include <malloc.h>
    00035 #include <string.h>
    00036
    00037 #include "nvbuf_utils.h"
    00038 #include "NvCudaProc.h"
    00039 #include "video_cuda_enc.h"
    00040
    00041 #define TEST_ERROR(cond, str, label) if(cond) { \
    00042                                         cerr << str << endl; \
    00043                                         error = 1; \
    00044                                         goto label; }
    00045
    00046 using namespace std;
    00047
    00048 static void
    00049 abort(context_t *ctx)
    00050 {
    00051     ctx->got_error = true;
    00052     ctx->enc->abort();
    00053 }
    00054
    00055 static int
    00056 write_encoder_output_frame(ofstream * stream, NvBuffer * buffer)
    00057 {
    00058     stream->write((char *) buffer->planes[0].data, buffer->planes[0].bytesused);
    00059     return 0;
    00060 }
    00061
    00062 static bool
    00063 encoder_capture_plane_dq_callback(struct v4l2_buffer *v4l2_buf, NvBuffer * buffer,
    00064                                   NvBuffer * shared_buffer, void *arg)
    00065 {
    00066     context_t *ctx = (context_t *) arg;
    00067     NvVideoEncoder *enc = ctx->enc;
    00068
    00069     if (!v4l2_buf)
    00070     {
    00071         cerr << "Failed to dequeue buffer from encoder capture plane" << endl;
    00072         abort(ctx);
    00073         return false;
    00074     }
    00075
    00076     write_encoder_output_frame(ctx->out_file, buffer);
    00077
    00078     if (enc->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
    00079     {
    00080         cerr << "Error while Qing buffer at capture plane" << endl;
    00081         abort(ctx);
    00082         return false;
    00083     }
    00084
    00085     // GOT EOS from encoder. Stop dqthread.
    00086     if (buffer->planes[0].bytesused == 0)
    00087     {
    00088         return false;
    00089     }
    00090
    00091     return true;
    00092 }
    00093
    00094 static void
    00095 set_defaults(context_t * ctx)
    00096 {
    00097     memset(ctx, 0, sizeof(context_t));
    00098
    00099     ctx->bitrate = 4 * 1024 * 1024;
    00100     ctx->fps_n = 30;
    00101     ctx->fps_d = 1;
    00102 }
    00103
    00104 int
    00105 main(int argc, char *argv[])
    00106 {
    00107     context_t ctx;
    00108     int ret = 0;
    00109     int error = 0;
    00110     bool eos = false;
    00111
    00112     set_defaults(&ctx);
    00113
    00114     ctx.eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    00115     if (ctx.eglDisplay == EGL_NO_DISPLAY)
    00116     {
    00117         cout<<"Could not get EGL display connection"<<endl;
    00118         return -1;
    00119     }
    00120
    00121     // Initialize egl
    00122     if (!eglInitialize(ctx.eglDisplay, NULL, NULL))
    00123     {
    00124         cout<<"init EGL display failed"<<endl;
    00125         return -1;
    00126     }
    00127
    00128     ret = parse_csv_args(&ctx, argc, argv);
    00129     TEST_ERROR(ret < 0, "Error parsing commandline arguments", cleanup);
    00130
    00131     ctx.in_file = new ifstream(ctx.in_file_path);
    00132     TEST_ERROR(!ctx.in_file->is_open(), "Could not open input file", cleanup);
    00133
    00134     ctx.out_file = new ofstream(ctx.out_file_path);
    00135     TEST_ERROR(!ctx.out_file->is_open(), "Could not open output file", cleanup);
    00136
    00137     ctx.enc = NvVideoEncoder::createVideoEncoder("enc0");
    00138     TEST_ERROR(!ctx.enc, "Could not create encoder", cleanup);
    00139
    00140     // It is necessary that Capture Plane format be set before Output Plane
    00141     // format.
    00142     // Set encoder capture plane format. It is necessary to set width and
    00143     // height on thr capture plane as well
    00144     // Set encoder output plane format
    00145     ret =
    00146         ctx.enc->setCapturePlaneFormat(ctx.encoder_pixfmt, ctx.width,
    00147                                       ctx.height, 2 * 1024 * 1024);
    00148     TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
    00149
    00150     ret =
    00151         ctx.enc->setOutputPlaneFormat(V4L2_PIX_FMT_YUV420M, ctx.width,
    00152                                       ctx.height);
    00153     TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
    00154
    00155     ret = ctx.enc->setBitrate(ctx.bitrate);
    00156     TEST_ERROR(ret < 0, "Could not set bitrate", cleanup);
    00157
    00158     if (ctx.encoder_pixfmt == V4L2_PIX_FMT_H264)
    00159     {
    00160         ret = ctx.enc->setProfile(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
    00161     }
    00162     else
    00163     {
    00164         ret = ctx.enc->setProfile(V4L2_MPEG_VIDEO_H265_PROFILE_MAIN);
    00165     }
    00166     TEST_ERROR(ret < 0, "Could not set encoder profile", cleanup);
    00167
    00168     if (ctx.encoder_pixfmt == V4L2_PIX_FMT_H264)
    00169     {
    00170         ret = ctx.enc->setLevel(V4L2_MPEG_VIDEO_H264_LEVEL_5_0);
    00171         TEST_ERROR(ret < 0, "Could not set encoder level", cleanup);
    00172     }
    00173
    00174     ret = ctx.enc->setFrameRate(ctx.fps_n, ctx.fps_d);
    00175     TEST_ERROR(ret < 0, "Could not set framerate", cleanup);
    00176
    00177     // Query, Export and Map the output plane buffers so that we can read
    00178     // raw data into the buffers
    00179     ret = ctx.enc->output_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
    00180     TEST_ERROR(ret < 0, "Could not setup output plane", cleanup);
    00181
    00182     // Query, Export and Map the output plane buffers so that we can write
    00183     // encoded data from the buffers
    00184     ret = ctx.enc->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
    00185     TEST_ERROR(ret < 0, "Could not setup capture plane", cleanup);
    00186
    00187     // output plane STREAMON
    00188     ret = ctx.enc->output_plane.setStreamStatus(true);
    00189     TEST_ERROR(ret < 0, "Error in output plane streamon", cleanup);
    00190
    00191     // capture plane STREAMON
    00192     ret = ctx.enc->capture_plane.setStreamStatus(true);
    00193     TEST_ERROR(ret < 0, "Error in capture plane streamon", cleanup);
    00194
    00195     ctx.enc->capture_plane.
    00196         setDQThreadCallback(encoder_capture_plane_dq_callback);
    00197
    00198     // startDQThread starts a thread internally which calls the
    00199     // encoder_capture_plane_dq_callback whenever a buffer is dequeued
    00200     // on the plane
    00201     ctx.enc->capture_plane.startDQThread(&ctx);
    00202
    00203     // Enqueue all the empty capture plane buffers
    00204     for (uint32_t i = 0; i < ctx.enc->capture_plane.getNumBuffers(); i++)
    00205     {
    00206         struct v4l2_buffer v4l2_buf;
    00207         struct v4l2_plane planes[MAX_PLANES];
    00208
    00209         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00210         memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));
    00211
    00212         v4l2_buf.index = i;
    00213         v4l2_buf.m.planes = planes;
    00214
    00215         ret = ctx.enc->capture_plane.qBuffer(v4l2_buf, NULL);
    00216         if (ret < 0)
    00217         {
    00218             cerr << "Error while queueing buffer at capture plane" << endl;
    00219             abort(&ctx);
    00220             goto cleanup;
    00221         }
    00222     }
    00223
    00224     // Read video frame and queue all the output plane buffers
    00225     for (uint32_t i = 0; i < ctx.enc->output_plane.getNumBuffers() &&
    00226             !ctx.got_error; i++)
    00227     {
    00228         struct v4l2_buffer v4l2_buf;
    00229         struct v4l2_plane planes[MAX_PLANES];
    00230         NvBuffer *buffer = ctx.enc->output_plane.getNthBuffer(i);
    00231
    00232         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00233         memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));
    00234
    00235         v4l2_buf.index = i;
    00236         v4l2_buf.m.planes = planes;
    00237
    00238         if (read_video_frame(ctx.in_file, *buffer) < 0)
    00239         {
    00240             cerr << "Could not read complete frame from input file" << endl;
    00241             v4l2_buf.m.planes[0].bytesused = 0;
    00242         }
    00243
    00244         ctx.eglimg = NvEGLImageFromFd(ctx.eglDisplay, buffer->planes[0].fd);
    00245         HandleEGLImage(&ctx.eglimg);
    00246         NvDestroyEGLImage(ctx.eglDisplay, ctx.eglimg);
    00247
    00248         ret = ctx.enc->output_plane.qBuffer(v4l2_buf, NULL);
    00249         if (ret < 0)
    00250         {
    00251             cerr << "Error while queueing buffer at output plane" << endl;
    00252             abort(&ctx);
    00253             goto cleanup;
    00254         }
    00255
    00256         if (v4l2_buf.m.planes[0].bytesused == 0)
    00257         {
    00258             cerr << "File read complete." << endl;
    00259             eos = true;
    00260             break;
    00261         }
    00262     }
    00263
    00264     // Keep reading input till EOS is reached
    00265     while (!ctx.got_error && !ctx.enc->isInError() && !eos)
    00266     {
    00267         struct v4l2_buffer v4l2_buf;
    00268         struct v4l2_plane planes[MAX_PLANES];
    00269         NvBuffer *buffer;
    00270
    00271         memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    00272         memset(planes, 0, sizeof(planes));
    00273
    00274         v4l2_buf.m.planes = planes;
    00275
    00276         if (ctx.enc->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, 10) < 0)
    00277         {
    00278             cerr << "ERROR while DQing buffer at output plane" << endl;
    00279             abort(&ctx);
    00280             goto cleanup;
    00281         }
    00282
    00283         if (read_video_frame(ctx.in_file, *buffer) < 0)
    00284         {
    00285             cerr << "Could not read complete frame from input file" << endl;
    00286             v4l2_buf.m.planes[0].bytesused = 0;
    00287         }
    00288
    00289         ctx.eglimg = NvEGLImageFromFd(ctx.eglDisplay, buffer->planes[0].fd);
    00290         HandleEGLImage(&ctx.eglimg);
    00291         NvDestroyEGLImage(ctx.eglDisplay, ctx.eglimg);
    00292
    00293         ret = ctx.enc->output_plane.qBuffer(v4l2_buf, NULL);
    00294         if (ret < 0)
    00295         {
    00296             cerr << "Error while queueing buffer at output plane" << endl;
    00297             abort(&ctx);
    00298             goto cleanup;
    00299         }
    00300
    00301         if (v4l2_buf.m.planes[0].bytesused == 0)
    00302         {
    00303             cerr << "File read complete." << endl;
    00304             eos = true;
    00305             break;
    00306         }
    00307     }
    00308
    00309     // Wait till capture plane DQ Thread finishes
    00310     // i.e. all the capture plane buffers are dequeued
    00311     ctx.enc->capture_plane.waitForDQThread(2000);
    00312
    00313 cleanup:
    00314     if (ctx.enc && ctx.enc->isInError())
    00315     {
    00316         cerr << "Encoder is in error" << endl;
    00317         error = 1;
    00318     }
    00319     if (ctx.got_error)
    00320     {
    00321         error = 1;
    00322     }
    00323
    00324     delete ctx.enc;
    00325     delete ctx.in_file;
    00326     delete ctx.out_file;
    00327
    00328     free(ctx.in_file_path);
    00329     free(ctx.out_file_path);
    00330
    00331     if (!eglTerminate(ctx.eglDisplay))
    00332     {
    00333         cout<<"ERROR eglTerminate failed"<<endl;
    00334         error = 1;
    00335     }
    00336
    00337     if (!eglReleaseThread())
    00338     {
    00339         cout<<"ERROR eglReleaseThread failed"<<endl;
    00340         error = 1;
    00341     }
    00342
    00343     if (error)
    00344     {
    00345         cout << "App run failed" << endl;
    00346     }
    00347     else
    00348     {
    00349         cout << "App run was successful" << endl;
    00350     }
    00351     return -error;
    00352 }