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 "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
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
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
00141
00142
00143
00144
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
00178
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
00183
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
00188 ret = ctx.enc->output_plane.setStreamStatus(true);
00189 TEST_ERROR(ret < 0, "Error in output plane streamon", cleanup);
00190
00191
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
00199
00200
00201 ctx.enc->capture_plane.startDQThread(&ctx);
00202
00203
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
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
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
00310
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 }