I’m testing the samples of the MultiMedia API.
Because I hope that in my program, I can create a decode thread many times and then destroy the decode thread, but I found that gstreamer in the set_state for READY, nveglglessink module called gst_eglglessink_stop (), will occur Xlib error, which lead to segment errors, I’m going to try MultiMediaAPI.
I changed the decode sample
Mainly the process does not exit the case, the cycle to create, destroy the decoding module.
After running, after more than 20 times to create, destroy the process, the process will be created every time when the leak about 40M memory, about 80 cycles will be run off the system kill.
I have tried the following command, a memory leak occurs
./video_decode ../../data/video/sample_outdoor_car_1080p_10fps.h264 H264 -wx 0 -wy 540 -ww 960 -wh 540
sudo -E ./video_decode test2.h264 H264 -wx 0 -wy 540 -ww 960 -wh 540 --stats
./video_decode test.h264 H264 -wx 0 -wy 540 -ww 960 -wh 540 --disable-rendering
My code is as follows, only changed the main function of the front and the last, an increase of a loop
please help.
int
main(int argc, char *argv[])
{
context_t ctx;
int ret = 0;
int error = 0;
uint32_t i;
bool eos = false;
char *nalu_parse_buffer = NULL;
NvApplicationProfiler &profiler = NvApplicationProfiler::getProfilerInstance();
/* I changed here !!!!!!!!!!!!!! */
while(1)
{
ret = 0;
error = 0;
eos = false;
nalu_parse_buffer = NULL;
set_defaults(&ctx);
if (parse_csv_args(&ctx, argc, argv))
{
fprintf(stderr, "Error parsing commandline arguments\n");
return -1;
}
ctx.dec = NvVideoDecoder::createVideoDecoder("dec0");
TEST_ERROR(!ctx.dec, "Could not create decoder", cleanup);
if (ctx.stats)
{
profiler.start(NvApplicationProfiler::DefaultSamplingInterval);
ctx.dec->enableProfiling();
}
// Subscribe to Resolution change event
ret = ctx.dec->subscribeEvent(V4L2_EVENT_RESOLUTION_CHANGE, 0, 0);
TEST_ERROR(ret < 0, "Could not subscribe to V4L2_EVENT_RESOLUTION_CHANGE",
cleanup);
if (ctx.input_nalu)
{
nalu_parse_buffer = new char[CHUNK_SIZE];
}
else
{
// Set V4L2_CID_MPEG_VIDEO_DISABLE_COMPLETE_FRAME_INPUT control to false
// so that application can send chunks of encoded data instead of forming
// complete frames. This needs to be done before setting format on the
// output plane.
ret = ctx.dec->disableCompleteFrameInputBuffer();
TEST_ERROR(ret < 0,
"Error in decoder disableCompleteFrameInputBuffer", cleanup);
}
// Set format on the output plane
ret = ctx.dec->setOutputPlaneFormat(ctx.decoder_pixfmt, CHUNK_SIZE);
TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
// V4L2_CID_MPEG_VIDEO_DISABLE_DPB should be set after output plane
// set format
if (ctx.disable_dpb)
{
ret = ctx.dec->disableDPB();
TEST_ERROR(ret < 0, "Error in decoder disableDPB", cleanup);
}
if (ctx.enable_metadata)
{
ret = ctx.dec->enableMetadataReporting();
TEST_ERROR(ret < 0, "Error while enabling metadata reporting", cleanup);
}
if (ctx.skip_frames)
{
ret = ctx.dec->setSkipFrames(ctx.skip_frames);
TEST_ERROR(ret < 0, "Error while setting skip frames param", cleanup);
}
// Query, Export and Map the output plane buffers so that we can read
// encoded data into the buffers
ret = ctx.dec->output_plane.setupPlane(V4L2_MEMORY_MMAP, 10, true, false);
TEST_ERROR(ret < 0, "Error while setting up output plane", cleanup);
ctx.in_file = new ifstream(ctx.in_file_path);
TEST_ERROR(!ctx.in_file->is_open(), "Error opening input file", cleanup);
if (ctx.out_file_path)
{
printf("%s,%d\n",__func__, __LINE__);
ctx.out_file = new ofstream(ctx.out_file_path);
TEST_ERROR(!ctx.out_file->is_open(), "Error opening output file",
cleanup);
}
if (ctx.out_file || (!ctx.disable_rendering && !ctx.stats))
{
// Create converter to convert from BL to PL for writing raw video
// to file
ctx.conv = NvVideoConverter::createVideoConverter("conv0");
TEST_ERROR(!ctx.conv, "Could not create video converter", cleanup);
ctx.conv->output_plane.
setDQThreadCallback(conv0_output_dqbuf_thread_callback);
ctx.conv->capture_plane.
setDQThreadCallback(conv0_capture_dqbuf_thread_callback);
if (ctx.stats)
{
ctx.conv->enableProfiling();
}
}
ret = ctx.dec->output_plane.setStreamStatus(true);
TEST_ERROR(ret < 0, "Error in output plane stream on", cleanup);
pthread_create(&ctx.dec_capture_loop, NULL, dec_capture_loop_fcn, &ctx);
// Read encoded data and enqueue all the output plane buffers.
// Exit loop in case file read is complete.
i = 0;
while (!eos && !ctx.got_error && !ctx.dec->isInError() &&
i < ctx.dec->output_plane.getNumBuffers())
{
struct v4l2_buffer v4l2_buf;
struct v4l2_plane planes[MAX_PLANES];
NvBuffer *buffer;
memset(&v4l2_buf, 0, sizeof(v4l2_buf));
memset(planes, 0, sizeof(planes));
buffer = ctx.dec->output_plane.getNthBuffer(i);
if (ctx.input_nalu)
{
read_decoder_input_nalu(ctx.in_file, buffer, nalu_parse_buffer,
CHUNK_SIZE);
}
else
{
read_decoder_input_chunk(ctx.in_file, buffer);
}
v4l2_buf.index = i;
v4l2_buf.m.planes = planes;
v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
// It is necessary to queue an empty buffer to signal EOS to the decoder
// i.e. set v4l2_buf.m.planes[0].bytesused = 0 and queue the buffer
ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
if (ret < 0)
{
cerr << "Error Qing buffer at output plane" << endl;
abort(&ctx);
break;
}
if (v4l2_buf.m.planes[0].bytesused == 0)
{
eos = true;
cout << "Input file read complete" << endl;
break;
}
i++;
}
printf("%s,%d\n",__func__, __LINE__);
// Since all the output plane buffers have been queued, we first need to
// dequeue a buffer from output plane before we can read new data into it
// and queue it again.
while (!eos && !ctx.got_error && !ctx.dec->isInError())
{
struct v4l2_buffer v4l2_buf;
struct v4l2_plane planes[MAX_PLANES];
NvBuffer *buffer;
memset(&v4l2_buf, 0, sizeof(v4l2_buf));
memset(planes, 0, sizeof(planes));
v4l2_buf.m.planes = planes;
ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, -1);
if (ret < 0)
{
cerr << "Error DQing buffer at output plane" << endl;
abort(&ctx);
break;
}
if (ctx.input_nalu)
{
read_decoder_input_nalu(ctx.in_file, buffer, nalu_parse_buffer,
CHUNK_SIZE);
}
else
{
read_decoder_input_chunk(ctx.in_file, buffer);
}
v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
ret = ctx.dec->output_plane.qBuffer(v4l2_buf, NULL);
if (ret < 0)
{
cerr << "Error Qing buffer at output plane" << endl;
abort(&ctx);
break;
}
if (v4l2_buf.m.planes[0].bytesused == 0)
{
eos = true;
cout << "Input file read complete" << endl;
break;
}
}
// After sending EOS, all the buffers from output plane should be dequeued.
// and after that capture plane loop should be signalled to stop.
while (ctx.dec->output_plane.getNumQueuedBuffers() > 0 &&
!ctx.got_error && !ctx.dec->isInError())
{
struct v4l2_buffer v4l2_buf;
struct v4l2_plane planes[MAX_PLANES];
memset(&v4l2_buf, 0, sizeof(v4l2_buf));
memset(planes, 0, sizeof(planes));
v4l2_buf.m.planes = planes;
ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, NULL, NULL, -1);
if (ret < 0)
{
cerr << "Error DQing buffer at output plane" << endl;
abort(&ctx);
break;
}
}
// Signal EOS to the decoder capture loop
ctx.got_eos = true;
if (ctx.conv)
{
ctx.conv->capture_plane.waitForDQThread(-1);
}
if (ctx.stats)
{
profiler.stop();
ctx.dec->printProfilingStats(cout);
if (ctx.conv)
{
ctx.conv->printProfilingStats(cout);
}
if (ctx.renderer)
{
ctx.renderer->printProfilingStats(cout);
}
profiler.printProfilerData(cout);
}
cleanup:
if (ctx.dec_capture_loop)
{
pthread_join(ctx.dec_capture_loop, NULL);
}
if (ctx.conv && ctx.conv->isInError())
{
cerr << "Converter is in error" << endl;
error = 1;
}
if (ctx.dec && ctx.dec->isInError())
{
cerr << "Decoder is in error" << endl;
error = 1;
}
if (ctx.got_error)
{
error = 1;
}
// The decoder destructor does all the cleanup i.e set streamoff on output and capture planes,
// unmap buffers, tell decoder to deallocate buffer (reqbufs ioctl with counnt = 0),
// and finally call v4l2_close on the fd.
delete ctx.dec;
delete ctx.conv;
// Similarly, EglRenderer destructor does all the cleanup
delete ctx.renderer;
delete ctx.in_file;
delete ctx.out_file;
delete ctx.conv_output_plane_buf_queue;
delete[] nalu_parse_buffer;
/* I changed here !!!!!!!!!!!!!! */
sleep (4);
}
free(ctx.in_file_path);
free(ctx.out_file_path);
if (error)
{
cout << "App run failed" << endl;
}
else
{
cout << "App run was successful" << endl;
}
return -error;
}