1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260 |
- /*
- * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "NvApplicationProfiler.h"
- #include "NvUtils.h"
- #include <errno.h>
- #include <fstream>
- #include <iostream>
- #include <linux/videodev2.h>
- #include <malloc.h>
- #include <pthread.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <poll.h>
- #include <nvbuf_utils.h>
- #include "video_decode.h"
- #include "nvbuf_utils.h"
- #define TEST_ERROR(cond, str, label) if(cond) { \
- cerr << str << endl; \
- error = 1; \
- goto label; }
- #define MICROSECOND_UNIT 1000000
- #define CHUNK_SIZE 4000000
- #define MIN(a,b) (((a) < (b)) ? (a) : (b))
- #define IS_NAL_UNIT_START(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
- !buffer_ptr[2] && (buffer_ptr[3] == 1))
- #define IS_NAL_UNIT_START1(buffer_ptr) (!buffer_ptr[0] && !buffer_ptr[1] && \
- (buffer_ptr[2] == 1))
- #define H264_NAL_UNIT_CODED_SLICE 1
- #define H264_NAL_UNIT_CODED_SLICE_IDR 5
- #define HEVC_NUT_TRAIL_N 0
- #define HEVC_NUT_RASL_R 9
- #define HEVC_NUT_BLA_W_LP 16
- #define HEVC_NUT_CRA_NUT 21
- #define IVF_FILE_HDR_SIZE 32
- #define IVF_FRAME_HDR_SIZE 12
- #define IS_H264_NAL_CODED_SLICE(buffer_ptr) ((buffer_ptr[0] & 0x1F) == H264_NAL_UNIT_CODED_SLICE)
- #define IS_H264_NAL_CODED_SLICE_IDR(buffer_ptr) ((buffer_ptr[0] & 0x1F) == H264_NAL_UNIT_CODED_SLICE_IDR)
- #define GET_H265_NAL_UNIT_TYPE(buffer_ptr) ((buffer_ptr[0] & 0x7E) >> 1)
- using namespace std;
- bool gbNewData = false;
- #include <QWaitCondition>
- #include <QMutex>
- QWaitCondition gwc;
- QMutex gWaitMutex;
- int gndatasize = 0;
- char * gstrbuffer;
- QMutex gMutexLock;
- bool gbNewOut = false;
- QWaitCondition gwcout;
- char * gstrout;
- QMutex gWaitMutexout;
- QMutex gMutexout;
- int gnoutsize = 0;
- void read_grpc_frame(NvBuffer * buffer)
- {
- while(gbNewData == false)
- {
- gWaitMutex.lock();
- gwc.wait(&gWaitMutex,10);
- gWaitMutex.unlock();
- }
- std::cout<<"grpc data. "<<std::endl;
- gMutexLock.lock();
- memcpy((char *) buffer->planes[0].data,gstrbuffer,gndatasize);
- buffer->planes[0].bytesused = gndatasize;
- gbNewData = false;
- gMutexLock.unlock();
- }
- /**
- * Read the input NAL unit for h264/H265/Mpeg2/Mpeg4 decoder.
- *
- * @param stream : Input stream
- * @param buffer : NvBuffer pointer
- * @param parse_buffer : parse buffer pointer
- * @param parse_buffer_size : chunk size
- * @param ctx : Decoder context
- */
- static int
- read_decoder_input_nalu(ifstream * stream, NvBuffer * buffer,
- char *parse_buffer, streamsize parse_buffer_size, context_t * ctx)
- {
- /* Length is the size of the buffer in bytes. */
- char *buffer_ptr = (char *) buffer->planes[0].data;
- int h265_nal_unit_type;
- char *stream_ptr;
- bool nalu_found = false;
- streamsize bytes_read;
- streamsize stream_initial_pos = stream->tellg();
- stream->read(parse_buffer, parse_buffer_size);
- bytes_read = stream->gcount();
- if (bytes_read == 0)
- {
- return buffer->planes[0].bytesused = 0;
- }
- /* Find the first NAL unit in the buffer. */
- stream_ptr = parse_buffer;
- while ((stream_ptr - parse_buffer) < (bytes_read - 3))
- {
- nalu_found = IS_NAL_UNIT_START(stream_ptr) ||
- IS_NAL_UNIT_START1(stream_ptr);
- if (nalu_found)
- {
- break;
- }
- stream_ptr++;
- }
- /* Reached end of buffer but could not find NAL unit. */
- if (!nalu_found)
- {
- cerr << "Could not read nal unit from file. EOF or file corrupted"
- << endl;
- return -1;
- }
- memcpy(buffer_ptr, stream_ptr, 4);
- buffer_ptr += 4;
- buffer->planes[0].bytesused = 4;
- stream_ptr += 4;
- if (ctx->copy_timestamp)
- {
- if (ctx->decoder_pixfmt == V4L2_PIX_FMT_H264) {
- if ((IS_H264_NAL_CODED_SLICE(stream_ptr)) ||
- (IS_H264_NAL_CODED_SLICE_IDR(stream_ptr)))
- ctx->flag_copyts = true;
- else
- ctx->flag_copyts = false;
- } else if (ctx->decoder_pixfmt == V4L2_PIX_FMT_H265) {
- h265_nal_unit_type = GET_H265_NAL_UNIT_TYPE(stream_ptr);
- if ((h265_nal_unit_type >= HEVC_NUT_TRAIL_N && h265_nal_unit_type <= HEVC_NUT_RASL_R) ||
- (h265_nal_unit_type >= HEVC_NUT_BLA_W_LP && h265_nal_unit_type <= HEVC_NUT_CRA_NUT))
- ctx->flag_copyts = true;
- else
- ctx->flag_copyts = false;
- }
- }
- /* Copy bytes till the next NAL unit is found. */
- while ((stream_ptr - parse_buffer) < (bytes_read - 3))
- {
- if (IS_NAL_UNIT_START(stream_ptr) || IS_NAL_UNIT_START1(stream_ptr))
- {
- streamsize seekto = stream_initial_pos +
- (stream_ptr - parse_buffer);
- if(stream->eof())
- {
- stream->clear();
- }
- stream->seekg(seekto, stream->beg);
- return 0;
- }
- *buffer_ptr = *stream_ptr;
- buffer_ptr++;
- stream_ptr++;
- buffer->planes[0].bytesused++;
- }
- /* Reached end of buffer but could not find NAL unit. */
- cerr << "Could not read nal unit from file. EOF or file corrupted"
- << endl;
- return -1;
- }
- /**
- * Read the input chunks for h264/H265/Mpeg2/Mpeg4 decoder.
- *
- * @param stream : Input stream
- * @param buffer : NvBuffer pointer
- */
- static int
- read_decoder_input_chunk(ifstream * stream, NvBuffer * buffer)
- {
- read_grpc_frame(buffer);
- return 0;
- /* Length is the size of the buffer in bytes */
- streamsize bytes_to_read = MIN(CHUNK_SIZE, buffer->planes[0].length);
- stream->read((char *) buffer->planes[0].data, bytes_to_read);
- std::cout<<"read chunk size: "<<bytes_to_read<<std::endl;
- /* NOTE: It is necessary to set bytesused properly, so that decoder knows how
- many bytes in the buffer are valid. */
- buffer->planes[0].bytesused = stream->gcount();\
- std::cout<<"read: "<<buffer->planes[0].bytesused<<std::endl;
- if(buffer->planes[0].bytesused == 0)
- {
- stream->clear();
- stream->seekg(0,stream->beg);
- }
- return 0;
- }
- /**
- * Read the input chunks for Vp8/Vp9 decoder.
- *
- * @param ctx : Decoder context
- * @param buffer : NvBuffer pointer
- */
- static int
- read_vpx_decoder_input_chunk(context_t *ctx, NvBuffer * buffer)
- {
- ifstream *stream = ctx->in_file[0];
- int Framesize;
- unsigned char *bitstreambuffer = (unsigned char *)buffer->planes[0].data;
- if (ctx->vp9_file_header_flag == 0)
- {
- stream->read((char *) buffer->planes[0].data, IVF_FILE_HDR_SIZE);
- if (stream->gcount() != IVF_FILE_HDR_SIZE)
- {
- cerr << "Couldn't read IVF FILE HEADER" << endl;
- return -1;
- }
- if (!((bitstreambuffer[0] == 'D') && (bitstreambuffer[1] == 'K') &&
- (bitstreambuffer[2] == 'I') && (bitstreambuffer[3] == 'F')))
- {
- cerr << "It's not a valid IVF file \n" << endl;
- return -1;
- }
- cout << "It's a valid IVF file" << endl;
- ctx->vp9_file_header_flag = 1;
- }
- stream->read((char *) buffer->planes[0].data, IVF_FRAME_HDR_SIZE);
- if (!stream->gcount())
- {
- cout << "End of stream" << endl;
- return 0;
- }
- if (stream->gcount() != IVF_FRAME_HDR_SIZE)
- {
- cerr << "Couldn't read IVF FRAME HEADER" << endl;
- return -1;
- }
- Framesize = (bitstreambuffer[3]<<24) + (bitstreambuffer[2]<<16) +
- (bitstreambuffer[1]<<8) + bitstreambuffer[0];
- buffer->planes[0].bytesused = Framesize;
- stream->read((char *) buffer->planes[0].data, Framesize);
- if (stream->gcount() != Framesize)
- {
- cerr << "Couldn't read Framesize" << endl;
- return -1;
- }
- return 0;
- }
- /**
- * Exit on error.
- *
- * @param ctx : Decoder context
- */
- static void
- abort(context_t *ctx)
- {
- ctx->got_error = true;
- ctx->dec->abort();
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx->conv)
- {
- ctx->conv->abort();
- pthread_cond_broadcast(&ctx->queue_cond);
- }
- #endif
- }
- #ifndef USE_NVBUF_TRANSFORM_API
- /**
- * converter output-plane deque buffer callback function.
- *
- * @param v4l2_buf : v4l2 buffer
- * @param buffer : NvBuffer pointer
- * @param shared_buffer : shared NvBuffer pointer
- * @param ctx : Decoder context
- * @param arg : context pointer
- */
- static bool
- conv0_output_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
- NvBuffer * buffer, NvBuffer * shared_buffer,
- void *arg)
- {
- context_t *ctx = (context_t *) arg;
- struct v4l2_buffer dec_capture_ret_buffer;
- struct v4l2_plane planes[MAX_PLANES];
- if (!v4l2_buf)
- {
- cerr << "Error while dequeueing conv output plane buffer" << endl;
- abort(ctx);
- return false;
- }
- if (v4l2_buf->m.planes[0].bytesused == 0)
- {
- return false;
- }
- memset(&dec_capture_ret_buffer, 0, sizeof(dec_capture_ret_buffer));
- memset(planes, 0, sizeof(planes));
- dec_capture_ret_buffer.index = shared_buffer->index;
- dec_capture_ret_buffer.m.planes = planes;
- if (ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- dec_capture_ret_buffer.m.planes[0].m.fd =
- ctx->dmabuff_fd[shared_buffer->index];
- pthread_mutex_lock(&ctx->queue_lock);
- ctx->conv_output_plane_buf_queue->push(buffer);
- /* Return the buffer dequeued from converter output plane
- back to decoder capture plane. */
- if (ctx->dec->capture_plane.qBuffer(dec_capture_ret_buffer, NULL) < 0)
- {
- abort(ctx);
- return false;
- }
- pthread_cond_broadcast(&ctx->queue_cond);
- pthread_mutex_unlock(&ctx->queue_lock);
- return true;
- }
- /**
- * converter capture-plane deque buffer callback function.
- *
- * @param v4l2_buf : v4l2 buffer
- * @param buffer : NvBuffer
- * @param shared_buffer : shared NvBuffer
- * @param arg : context pointer
- */
- static bool
- conv0_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
- NvBuffer * buffer, NvBuffer * shared_buffer,
- void *arg)
- {
- context_t *ctx = (context_t *) arg;
- if (!v4l2_buf)
- {
- cerr << "Error while dequeueing conv capture plane buffer" << endl;
- abort(ctx);
- return false;
- }
- if (v4l2_buf->m.planes[0].bytesused == 0)
- {
- return false;
- }
- /* Write raw video frame to file. */
- if (!ctx->stats && ctx->out_file)
- {
- write_video_frame(ctx->out_file, *buffer);
- }
- /* Render converted video. */
- if (!ctx->stats && !ctx->disable_rendering)
- {
- ctx->renderer->render(buffer->planes[0].fd);
- }
- /* Return the buffer to converter capture plane. */
- if (ctx->conv->capture_plane.qBuffer(*v4l2_buf, NULL) < 0)
- {
- return false;
- }
- return true;
- }
- #endif
- /**
- * Report decoder input header error metadata.
- *
- * @param ctx : Decoder context
- * @param input_metadata : Pointer to decoder input header error metadata struct
- */
- static int
- report_input_metadata(context_t *ctx, v4l2_ctrl_videodec_inputbuf_metadata *input_metadata)
- {
- int ret = -1;
- uint32_t frame_num = ctx->dec->output_plane.getTotalDequeuedBuffers() - 1;
- /* NOTE: Bits represent types of error as defined with v4l2_videodec_input_error_type. */
- if (input_metadata->nBitStreamError & V4L2_DEC_ERROR_SPS) {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_SPS " << endl;
- } else if (input_metadata->nBitStreamError & V4L2_DEC_ERROR_PPS) {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_PPS " << endl;
- } else if (input_metadata->nBitStreamError & V4L2_DEC_ERROR_SLICE_HDR) {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_SLICE_HDR " << endl;
- } else if (input_metadata->nBitStreamError & V4L2_DEC_ERROR_MISSING_REF_FRAME) {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_MISSING_REF_FRAME " << endl;
- } else if (input_metadata->nBitStreamError & V4L2_DEC_ERROR_VPS) {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_VPS " << endl;
- } else {
- cout << "Frame " << frame_num << " BitStreamError : ERROR_None " << endl;
- ret = 0;
- }
- return ret;
- }
- /**
- * Report decoder output metadata.
- *
- * @param ctx : Decoder context
- * @param metadata : Pointer to decoder output metadata struct
- */
- static void
- report_metadata(context_t *ctx, v4l2_ctrl_videodec_outputbuf_metadata *metadata)
- {
- uint32_t frame_num = ctx->dec->capture_plane.getTotalDequeuedBuffers() - 1;
- cout << "Frame " << frame_num << endl;
- if (metadata->bValidFrameStatus)
- {
- if (ctx->decoder_pixfmt == V4L2_PIX_FMT_H264)
- {
- /* metadata for H264 input stream. */
- switch(metadata->CodecParams.H264DecParams.FrameType)
- {
- case 0:
- cout << "FrameType = B" << endl;
- break;
- case 1:
- cout << "FrameType = P" << endl;
- break;
- case 2:
- cout << "FrameType = I";
- if (metadata->CodecParams.H264DecParams.dpbInfo.currentFrame.bIdrFrame)
- {
- cout << " (IDR)";
- }
- cout << endl;
- break;
- }
- cout << "nActiveRefFrames = " << metadata->CodecParams.H264DecParams.dpbInfo.nActiveRefFrames << endl;
- }
- if (ctx->decoder_pixfmt == V4L2_PIX_FMT_H265)
- {
- /* metadata for HEVC input stream. */
- switch(metadata->CodecParams.HEVCDecParams.FrameType)
- {
- case 0:
- cout << "FrameType = B" << endl;
- break;
- case 1:
- cout << "FrameType = P" << endl;
- break;
- case 2:
- cout << "FrameType = I";
- if (metadata->CodecParams.HEVCDecParams.dpbInfo.currentFrame.bIdrFrame)
- {
- cout << " (IDR)";
- }
- cout << endl;
- break;
- }
- cout << "nActiveRefFrames = " << metadata->CodecParams.HEVCDecParams.dpbInfo.nActiveRefFrames << endl;
- }
- if (metadata->FrameDecStats.DecodeError)
- {
- /* decoder error status metadata. */
- v4l2_ctrl_videodec_statusmetadata *dec_stats =
- &metadata->FrameDecStats;
- cout << "ErrorType=" << dec_stats->DecodeError << " Decoded MBs=" <<
- dec_stats->DecodedMBs << " Concealed MBs=" <<
- dec_stats->ConcealedMBs << endl;
- }
- }
- else
- {
- cout << "No valid metadata for frame" << endl;
- }
- }
- #ifndef USE_NVBUF_TRANSFORM_API
- /**
- * Send EndOfStream for converter.
- *
- * @param ctx : Decoder context
- */
- static int
- sendEOStoConverter(context_t *ctx)
- {
- /* Check if converter is running. */
- if (ctx->conv->output_plane.getStreamStatus())
- {
- NvBuffer *conv_buffer;
- 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;
- pthread_mutex_lock(&ctx->queue_lock);
- /* Wait till converter output buffer queue is empty. */
- while (ctx->conv_output_plane_buf_queue->empty())
- {
- pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
- }
- conv_buffer = ctx->conv_output_plane_buf_queue->front();
- ctx->conv_output_plane_buf_queue->pop();
- pthread_mutex_unlock(&ctx->queue_lock);
- v4l2_buf.index = conv_buffer->index;
- /* Enqueue EOS buffer on converter output plane. */
- return ctx->conv->output_plane.qBuffer(v4l2_buf, NULL);
- }
- return 0;
- }
- #endif
- /**
- * Query and Set Capture plane.
- *
- * @param ctx : Decoder context
- */
- static void
- query_and_set_capture(context_t * ctx)
- {
- NvVideoDecoder *dec = ctx->dec;
- struct v4l2_format format;
- struct v4l2_crop crop;
- int32_t min_dec_capture_buffers;
- int ret = 0;
- int error = 0;
- uint32_t window_width;
- uint32_t window_height;
- NvBufferCreateParams input_params = {0};
- NvBufferCreateParams cParams = {0};
- /* Get capture plane format from the decoder.
- This may change after resolution change event.
- Refer ioctl VIDIOC_G_FMT */
- ret = dec->capture_plane.getFormat(format);
- TEST_ERROR(ret < 0,
- "Error: Could not get format from decoder capture plane", error);
- /* Get the display resolution from the decoder.
- Refer ioctl VIDIOC_G_CROP */
- ret = dec->capture_plane.getCrop(crop);
- TEST_ERROR(ret < 0,
- "Error: Could not get crop from decoder capture plane", error);
- cout << "Video Resolution: " << crop.c.width << "x" << crop.c.height
- << endl;
- ctx->display_height = crop.c.height;
- ctx->display_width = crop.c.width;
- #ifdef USE_NVBUF_TRANSFORM_API
- if(ctx->dst_dma_fd != -1)
- {
- NvBufferDestroy(ctx->dst_dma_fd);
- ctx->dst_dma_fd = -1;
- }
- /* Create PitchLinear output buffer for transform. */
- input_params.payloadType = NvBufferPayload_SurfArray;
- input_params.width = crop.c.width;
- input_params.height = crop.c.height;
- input_params.layout = NvBufferLayout_Pitch;
- if (ctx->out_pixfmt == 1)
- input_params.colorFormat = NvBufferColorFormat_NV12;
- else if (ctx->out_pixfmt == 2)
- input_params.colorFormat = NvBufferColorFormat_YUV420;
- else if (ctx->out_pixfmt == 3)
- input_params.colorFormat = NvBufferColorFormat_NV16;
- else if (ctx->out_pixfmt == 4)
- input_params.colorFormat = NvBufferColorFormat_NV24;
- input_params.nvbuf_tag = NvBufferTag_VIDEO_CONVERT;
- ret = NvBufferCreateEx (&ctx->dst_dma_fd, &input_params);
- TEST_ERROR(ret == -1, "create dmabuf failed", error);
- #else
- /* For file write, first deinitialize output and capture planes
- of video converter and then use the new resolution from
- decoder event resolution change. */
- if (ctx->conv)
- {
- ret = sendEOStoConverter(ctx);
- TEST_ERROR(ret < 0,
- "Error while queueing EOS buffer on converter output",
- error);
- ctx->conv->capture_plane.waitForDQThread(2000);
- ctx->conv->output_plane.deinitPlane();
- ctx->conv->capture_plane.deinitPlane();
- while(!ctx->conv_output_plane_buf_queue->empty())
- {
- ctx->conv_output_plane_buf_queue->pop();
- }
- }
- #endif
- if (!ctx->disable_rendering)
- {
- /* Destroy the old instance of renderer as resolution might have changed. */
- delete ctx->renderer;
- if (ctx->fullscreen)
- {
- /* Required for fullscreen. */
- window_width = window_height = 0;
- }
- else if (ctx->window_width && ctx->window_height)
- {
- /* As specified by user on commandline. */
- window_width = ctx->window_width;
- window_height = ctx->window_height;
- }
- else
- {
- /* Resolution got from the decoder. */
- window_width = crop.c.width;
- window_height = crop.c.height;
- }
- /* If height or width are set to zero, EglRenderer creates a fullscreen
- window for rendering. */
- ctx->renderer =
- NvEglRenderer::createEglRenderer("renderer0", window_width,
- window_height, ctx->window_x,
- ctx->window_y);
- TEST_ERROR(!ctx->renderer,
- "Error in setting up renderer. "
- "Check if X is running or run with --disable-rendering",
- error);
- if (ctx->stats)
- {
- /* Enable profiling for renderer if stats are requested. */
- ctx->renderer->enableProfiling();
- }
- /* Set fps for rendering. */
- ctx->renderer->setFPS(ctx->fps);
- }
- /* deinitPlane unmaps the buffers and calls REQBUFS with count 0 */
- dec->capture_plane.deinitPlane();
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- {
- for(int index = 0 ; index < ctx->numCapBuffers ; index++)
- {
- if(ctx->dmabuff_fd[index] != 0)
- {
- ret = NvBufferDestroy (ctx->dmabuff_fd[index]);
- TEST_ERROR(ret < 0, "Failed to Destroy NvBuffer", error);
- }
- }
- }
- /* Not necessary to call VIDIOC_S_FMT on decoder capture plane.
- But decoder setCapturePlaneFormat function updates the class variables */
- ret = dec->setCapturePlaneFormat(format.fmt.pix_mp.pixelformat,
- format.fmt.pix_mp.width,
- format.fmt.pix_mp.height);
- TEST_ERROR(ret < 0, "Error in setting decoder capture plane format", error);
- ctx->video_height = format.fmt.pix_mp.height;
- ctx->video_width = format.fmt.pix_mp.width;
- /* Get the minimum buffers which have to be requested on the capture plane. */
- ret = dec->getMinimumCapturePlaneBuffers(min_dec_capture_buffers);
- TEST_ERROR(ret < 0,
- "Error while getting value of minimum capture plane buffers",
- error);
- /* Request (min + extra) buffers, export and map buffers. */
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_MMAP)
- {
- /* Request, Query and export decoder capture plane buffers.
- Refer ioctl VIDIOC_REQBUFS, VIDIOC_QUERYBUF and VIDIOC_EXPBUF */
- ret =
- dec->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
- min_dec_capture_buffers + ctx->extra_cap_plane_buffer, false,
- false);
- TEST_ERROR(ret < 0, "Error in decoder capture plane setup", error);
- }
- else if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- {
- /* Set colorformats for relevant colorspaces. */
- switch(format.fmt.pix_mp.colorspace)
- {
- case V4L2_COLORSPACE_SMPTE170M:
- if (format.fmt.pix_mp.quantization == V4L2_QUANTIZATION_DEFAULT)
- {
- cout << "Decoder colorspace ITU-R BT.601 with standard range luma (16-235)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12;
- }
- else
- {
- cout << "Decoder colorspace ITU-R BT.601 with extended range luma (0-255)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12_ER;
- }
- break;
- case V4L2_COLORSPACE_REC709:
- if (format.fmt.pix_mp.quantization == V4L2_QUANTIZATION_DEFAULT)
- {
- cout << "Decoder colorspace ITU-R BT.709 with standard range luma (16-235)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12_709;
- }
- else
- {
- cout << "Decoder colorspace ITU-R BT.709 with extended range luma (0-255)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12_709_ER;
- }
- break;
- case V4L2_COLORSPACE_BT2020:
- {
- cout << "Decoder colorspace ITU-R BT.2020" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12_2020;
- }
- break;
- default:
- cout << "supported colorspace details not available, use default" << endl;
- if (format.fmt.pix_mp.quantization == V4L2_QUANTIZATION_DEFAULT)
- {
- cout << "Decoder colorspace ITU-R BT.601 with standard range luma (16-235)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12;
- }
- else
- {
- cout << "Decoder colorspace ITU-R BT.601 with extended range luma (0-255)" << endl;
- cParams.colorFormat = NvBufferColorFormat_NV12_ER;
- }
- break;
- }
- ctx->numCapBuffers = min_dec_capture_buffers + ctx->extra_cap_plane_buffer;
- /* Create decoder capture plane buffers. */
- for (int index = 0; index < ctx->numCapBuffers; index++)
- {
- cParams.width = crop.c.width;
- cParams.height = crop.c.height;
- cParams.layout = NvBufferLayout_BlockLinear;
- cParams.payloadType = NvBufferPayload_SurfArray;
- cParams.nvbuf_tag = NvBufferTag_VIDEO_DEC;
- ret = NvBufferCreateEx(&ctx->dmabuff_fd[index], &cParams);
- TEST_ERROR(ret < 0, "Failed to create buffers", error);
- }
- /* Request buffers on decoder capture plane.
- Refer ioctl VIDIOC_REQBUFS */
- ret = dec->capture_plane.reqbufs(V4L2_MEMORY_DMABUF,ctx->numCapBuffers);
- TEST_ERROR(ret, "Error in request buffers on capture plane", error);
- }
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx->conv)
- {
- /* Set Converter output plane format.
- Refer ioctl VIDIOC_S_FMT */
- ret = ctx->conv->setOutputPlaneFormat(format.fmt.pix_mp.pixelformat,
- format.fmt.pix_mp.width,
- format.fmt.pix_mp.height,
- V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR);
- TEST_ERROR(ret < 0, "Error in converter output plane set format",
- error);
- /* Set Converter capture plane format.
- Refer ioctl VIDIOC_S_FMT */
- ret = ctx->conv->setCapturePlaneFormat((ctx->out_pixfmt == 1 ?
- V4L2_PIX_FMT_NV12M :
- V4L2_PIX_FMT_YUV420M),
- crop.c.width,
- crop.c.height,
- V4L2_NV_BUFFER_LAYOUT_PITCH);
- TEST_ERROR(ret < 0, "Error in converter capture plane set format",
- error);
- /* Set Converter crop rectangle. */
- ret = ctx->conv->setCropRect(0, 0, crop.c.width, crop.c.height);
- TEST_ERROR(ret < 0, "Error while setting crop rect", error);
- if (ctx->rescale_method) {
- /* Rescale full range [0-255] to limited range [16-235].
- Refer V4L2_CID_VIDEO_CONVERT_YUV_RESCALE_METHOD */
- ret = ctx->conv->setYUVRescale(ctx->rescale_method);
- TEST_ERROR(ret < 0, "Error while setting YUV rescale", error);
- }
- /* Request buffers on converter output plane.
- Refer ioctl VIDIOC_REQBUFS */
- ret =
- ctx->conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF,
- dec->capture_plane.
- getNumBuffers(), false, false);
- TEST_ERROR(ret < 0, "Error in converter output plane setup", error);
- /* Request, Query and export converter capture plane buffers.
- Refer ioctl VIDIOC_REQBUFS, VIDIOC_QUERYBUF and VIDIOC_EXPBUF */
- ret =
- ctx->conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP,
- dec->capture_plane.
- getNumBuffers(), true, false);
- TEST_ERROR(ret < 0, "Error in converter capture plane setup", error);
- /* Converter output plane STREAMON.
- Refer ioctl VIDIOC_STREAMON */
- ret = ctx->conv->output_plane.setStreamStatus(true);
- TEST_ERROR(ret < 0, "Error in converter output plane streamon", error);
- /* Converter capture plane STREAMON.
- Refer ioctl VIDIOC_STREAMON */
- ret = ctx->conv->capture_plane.setStreamStatus(true);
- TEST_ERROR(ret < 0, "Error in converter output plane streamoff", error);
- /* Add all empty conv output plane buffers to conv_output_plane_buf_queue. */
- for (uint32_t i = 0; i < ctx->conv->output_plane.getNumBuffers(); i++)
- {
- ctx->conv_output_plane_buf_queue->push(ctx->conv->output_plane.
- getNthBuffer(i));
- }
- /* Enqueue converter capture plane buffers. */
- for (uint32_t i = 0; i < ctx->conv->capture_plane.getNumBuffers(); i++)
- {
- 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.index = i;
- v4l2_buf.m.planes = planes;
- ret = ctx->conv->capture_plane.qBuffer(v4l2_buf, NULL);
- TEST_ERROR(ret < 0, "Error Qing buffer at converter capture plane",
- error);
- }
- /* Start deque thread for converter output plane. */
- ctx->conv->output_plane.startDQThread(ctx);
- /* Start deque thread for converter capture plane. */
- ctx->conv->capture_plane.startDQThread(ctx);
- }
- #endif
- /* Decoder capture plane STREAMON.
- Refer ioctl VIDIOC_STREAMON */
- ret = dec->capture_plane.setStreamStatus(true);
- TEST_ERROR(ret < 0, "Error in decoder capture plane streamon", error);
- /* Enqueue all the empty decoder capture plane buffers. */
- for (uint32_t i = 0; i < dec->capture_plane.getNumBuffers(); i++)
- {
- 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.index = i;
- v4l2_buf.m.planes = planes;
- v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- v4l2_buf.memory = ctx->capture_plane_mem_type;
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- v4l2_buf.m.planes[0].m.fd = ctx->dmabuff_fd[i];
- ret = dec->capture_plane.qBuffer(v4l2_buf, NULL);
- TEST_ERROR(ret < 0, "Error Qing buffer at output plane", error);
- }
- cout << "Query and set capture successful" << endl;
- return;
- error:
- if (error)
- {
- abort(ctx);
- cerr << "Error in " << __func__ << endl;
- }
- }
- /**
- * Decoder polling thread loop function.
- *
- * @param args : void arguments
- */
- static void *decoder_pollthread_fcn(void *arg)
- {
- context_t *ctx = (context_t *) arg;
- v4l2_ctrl_video_device_poll devicepoll;
- cout << "Starting Device Poll Thread " << endl;
- memset(&devicepoll, 0, sizeof(v4l2_ctrl_video_device_poll));
- /* Wait here until you are signalled to issue the Poll call.
- Check if the abort status is set , if so exit.
- Else issue the Poll on the decoder and block.
- When the Poll returns, signal the decoder thread to continue. */
- while (!ctx->got_error && !ctx->dec->isInError())
- {
- /* wait on polling semaphore */
- sem_wait(&ctx->pollthread_sema);
- if (ctx->got_eos)
- {
- cout << "Decoder got eos, exiting poll thread \n";
- return NULL;
- }
- devicepoll.req_events = POLLIN | POLLOUT | POLLERR | POLLPRI;
- /* This call shall wait in the v4l2 decoder library.
- Refer V4L2_CID_MPEG_VIDEO_DEVICE_POLL */
- ctx->dec->DevicePoll(&devicepoll);
- /* We can check the devicepoll.resp_events bitmask to see
- which events are set. */
- sem_post(&ctx->decoderthread_sema);
- }
- return NULL;
- }
- #include <chrono>
- /**
- * Decoder capture thread loop function.
- *
- * @param args : void arguments
- */
- static void *
- dec_capture_loop_fcn(void *arg)
- {
- context_t *ctx = (context_t *) arg;
- NvVideoDecoder *dec = ctx->dec;
- struct v4l2_event ev;
- int ret;
- cout << "Starting decoder capture loop thread" << endl;
- /* Need to wait for the first Resolution change event, so that
- the decoder knows the stream resolution and can allocate appropriate
- buffers when we call REQBUFS. */
- do
- {
- /* Refer ioctl VIDIOC_DQEVENT */
- ret = dec->dqEvent(ev, 50000);
- if (ret < 0)
- {
- if (errno == EAGAIN)
- {
- cerr <<
- "Timed out waiting for first V4L2_EVENT_RESOLUTION_CHANGE"
- << endl;
- }
- else
- {
- cerr << "Error in dequeueing decoder event" << endl;
- }
- abort(ctx);
- break;
- }
- }
- while ((ev.type != V4L2_EVENT_RESOLUTION_CHANGE) && !ctx->got_error);
- /* Received the resolution change event, now can do query_and_set_capture. */
- if (!ctx->got_error)
- query_and_set_capture(ctx);
- /* Exit on error or EOS which is signalled in main() */
- while (!(ctx->got_error || dec->isInError() || ctx->got_eos))
- {
- NvBuffer *dec_buffer;
- /* Check for Resolution change again.
- Refer ioctl VIDIOC_DQEVENT */
- ret = dec->dqEvent(ev, false);
- if (ret == 0)
- {
- switch (ev.type)
- {
- case V4L2_EVENT_RESOLUTION_CHANGE:
- query_and_set_capture(ctx);
- continue;
- }
- }
- /* Decoder capture loop */
- while (1)
- {
- // std::cout<<"start "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<std::endl;
- 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;
- /* Dequeue a filled buffer. */
- if (dec->capture_plane.dqBuffer(v4l2_buf, &dec_buffer, NULL, 0))
- {
- if (errno == EAGAIN)
- {
- usleep(1000);
- }
- else
- {
- abort(ctx);
- cerr << "Error while calling dequeue at capture plane" <<
- endl;
- }
- break;
- }
- if (ctx->enable_metadata)
- {
- v4l2_ctrl_videodec_outputbuf_metadata dec_metadata;
- /* Get the decoder output metadata on capture-plane.
- Refer V4L2_CID_MPEG_VIDEODEC_METADATA */
- ret = dec->getMetadata(v4l2_buf.index, dec_metadata);
- if (ret == 0)
- {
- report_metadata(ctx, &dec_metadata);
- }
- }
- if (ctx->copy_timestamp && ctx->input_nalu && ctx->stats)
- {
- cout << "[" << v4l2_buf.index << "]" "dec capture plane dqB timestamp [" <<
- v4l2_buf.timestamp.tv_sec << "s" << v4l2_buf.timestamp.tv_usec << "us]" << endl;
- }
- if (!ctx->disable_rendering && ctx->stats)
- {
- /* EglRenderer requires the fd of the 0th plane to render the buffer. */
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- dec_buffer->planes[0].fd = ctx->dmabuff_fd[v4l2_buf.index];
- ctx->renderer->render(dec_buffer->planes[0].fd);
- }
- /* If we need to write to file or display the buffer, give
- the buffer to video converter output plane instead of
- returning the buffer back to decoder capture plane. */
- if (ctx->out_file || (!ctx->disable_rendering && !ctx->stats))
- {
- #ifndef USE_NVBUF_TRANSFORM_API
- NvBuffer *conv_buffer;
- struct v4l2_buffer conv_output_buffer;
- struct v4l2_plane conv_planes[MAX_PLANES];
- memset(&conv_output_buffer, 0, sizeof(conv_output_buffer));
- memset(conv_planes, 0, sizeof(conv_planes));
- conv_output_buffer.m.planes = conv_planes;
- /* Get an empty conv output plane buffer from conv_output_plane_buf_queue. */
- pthread_mutex_lock(&ctx->queue_lock);
- while (ctx->conv_output_plane_buf_queue->empty())
- {
- pthread_cond_wait(&ctx->queue_cond, &ctx->queue_lock);
- }
- conv_buffer = ctx->conv_output_plane_buf_queue->front();
- ctx->conv_output_plane_buf_queue->pop();
- pthread_mutex_unlock(&ctx->queue_lock);
- conv_output_buffer.index = conv_buffer->index;
- if (ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- dec_buffer->planes[0].fd = ctx->dmabuff_fd[v4l2_buf.index];
- /* enqueue converter output plane buffer. */
- if (ctx->conv->output_plane.
- qBuffer(conv_output_buffer, dec_buffer) < 0)
- {
- abort(ctx);
- cerr <<
- "Error while queueing buffer at converter output plane"
- << endl;
- break;
- }
- #else
- /* Clip & Stitch can be done by adjusting rectangle. */
- NvBufferRect src_rect, dest_rect;
- src_rect.top = 0;
- src_rect.left = 0;
- src_rect.width = ctx->display_width;
- src_rect.height = ctx->display_height;
- dest_rect.top = 0;
- dest_rect.left = 0;
- dest_rect.width = ctx->display_width;
- dest_rect.height = ctx->display_height;
- NvBufferTransformParams transform_params;
- memset(&transform_params,0,sizeof(transform_params));
- /* Indicates which of the transform parameters are valid. */
- transform_params.transform_flag = NVBUFFER_TRANSFORM_FILTER;
- transform_params.transform_flip = NvBufferTransform_None;
- transform_params.transform_filter = NvBufferTransform_Filter_Nearest;
- transform_params.src_rect = src_rect;
- transform_params.dst_rect = dest_rect;
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- dec_buffer->planes[0].fd = ctx->dmabuff_fd[v4l2_buf.index];
- /* Perform Blocklinear to PitchLinear conversion. */
- // std::cout<<"before "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<std::endl;
- ret = NvBufferTransform(dec_buffer->planes[0].fd, ctx->dst_dma_fd, &transform_params);
- // std::cout<<"after "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<std::endl;
- if (ret == -1)
- {
- cerr << "Transform failed" << endl;
- break;
- }
- /* Write raw video frame to file. */
- if (!ctx->stats && ctx->out_file)
- {
- /* Dumping two planes for NV12, NV16, NV24 and three for I420 */
- dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);
- dump_dmabuf(ctx->dst_dma_fd, 1, ctx->out_file);
- if (ctx->out_pixfmt == 2)
- {
- dump_dmabuf(ctx->dst_dma_fd, 2, ctx->out_file);
- }
- }
- static int a = 1;
- if(a > -1)
- {
- if (!ctx->stats && !ctx->disable_rendering)
- {
- ctx->renderer->render(ctx->dst_dma_fd);
- }
- a = 0;
- }
- a++;
- // std::cout<<"after2 "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<std::endl;
- /* If not writing to file, Queue the buffer back once it has been used. */
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- v4l2_buf.m.planes[0].m.fd = ctx->dmabuff_fd[v4l2_buf.index];
- if (dec->capture_plane.qBuffer(v4l2_buf, NULL) < 0)
- {
- abort(ctx);
- cerr <<
- "Error while queueing buffer at decoder capture plane"
- << endl;
- break;
- }
- #endif
- }
- else
- {
- /* If not writing to file, Queue the buffer back once it has been used. */
- if(ctx->capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- v4l2_buf.m.planes[0].m.fd = ctx->dmabuff_fd[v4l2_buf.index];
- if (dec->capture_plane.qBuffer(v4l2_buf, NULL) < 0)
- {
- abort(ctx);
- cerr <<
- "Error while queueing buffer at decoder capture plane"
- << endl;
- break;
- }
- }
- }
- }
- #ifndef USE_NVBUF_TRANSFORM_API
- /* Send EOS to converter */
- if (ctx->conv)
- {
- if (sendEOStoConverter(ctx) < 0)
- {
- cerr << "Error while queueing EOS buffer on converter output"
- << endl;
- }
- }
- #endif
- cout << "Exiting decoder capture loop thread" << endl;
- return NULL;
- }
- /**
- * Set the default values for decoder context members.
- *
- * @param ctx : Decoder context
- */
- static void
- set_defaults(context_t * ctx)
- {
- memset(ctx, 0, sizeof(context_t));
- ctx->fullscreen = false;
- ctx->window_height = 360;
- ctx->window_width = 640;
- ctx->window_x = 300;
- ctx->window_y = 0;
- ctx->out_pixfmt = 1;
- ctx->fps = 30;
- ctx->output_plane_mem_type = V4L2_MEMORY_MMAP;
- ctx->capture_plane_mem_type = V4L2_MEMORY_DMABUF;
- ctx->vp9_file_header_flag = 0;
- ctx->vp8_file_header_flag = 0;
- ctx->stress_test = 1;
- ctx->copy_timestamp = false;
- ctx->flag_copyts = false;
- ctx->start_ts = 0;
- ctx->file_count = 1;
- ctx->dec_fps = 30;
- ctx->dst_dma_fd = -1;
- ctx->bLoop = false;
- ctx->bQueue = false;
- ctx->loop_count = 0;
- ctx->max_perf = 0;
- ctx->extra_cap_plane_buffer = 1;
- ctx->blocking_mode = 1;
- #ifndef USE_NVBUF_TRANSFORM_API
- ctx->conv_output_plane_buf_queue = new queue < NvBuffer * >;
- ctx->rescale_method = V4L2_YUV_RESCALE_NONE;
- #endif
- pthread_mutex_init(&ctx->queue_lock, NULL);
- pthread_cond_init(&ctx->queue_cond, NULL);
- }
- /**
- * Decode processing function for non-blocking mode.
- *
- * @param ctx : Decoder context
- * @param eos : end of stream
- * @param current_file : current file
- * @param current_loop : iterator count
- * @param nalu_parse_buffer : input parsed nal unit
- */
- static bool decoder_proc_nonblocking(context_t &ctx, bool eos, uint32_t current_file,
- int current_loop, char *nalu_parse_buffer)
- {
- /* NOTE: In non-blocking mode, we will have this function do below things:
- 1) Issue signal to PollThread so it starts Poll and wait until we are signalled.
- 2) After we are signalled, it means there is something to dequeue, either output plane
- or capture plane or there's an event.
- 3) Try dequeuing from all three and then act appropriately.
- 4) After enqueuing go back to the same loop. */
- /* 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. */
- int allow_DQ = true;
- int ret = 0;
- struct v4l2_buffer temp_buf;
- struct v4l2_event ev;
- while (!ctx.got_error && !ctx.dec->isInError())
- {
- struct v4l2_buffer v4l2_output_buf;
- struct v4l2_plane output_planes[MAX_PLANES];
- struct v4l2_buffer v4l2_capture_buf;
- struct v4l2_plane capture_planes[MAX_PLANES];
- NvBuffer *output_buffer = NULL;
- NvBuffer *capture_buffer = NULL;
- memset(&v4l2_output_buf, 0, sizeof(v4l2_output_buf));
- memset(output_planes, 0, sizeof(output_planes));
- v4l2_output_buf.m.planes = output_planes;
- memset(&v4l2_capture_buf, 0, sizeof(v4l2_capture_buf));
- memset(capture_planes, 0, sizeof(capture_planes));
- v4l2_capture_buf.m.planes = capture_planes;
- /* Call for SetPollInterrupt.
- Refer V4L2_CID_MPEG_SET_POLL_INTERRUPT */
- ctx.dec->SetPollInterrupt();
- /* Since buffers have been queued, issue a post to start polling and
- then wait here. */
- sem_post(&ctx.pollthread_sema);
- sem_wait(&ctx.decoderthread_sema);
- /* Call for dequeuing an event.
- Refer ioctl VIDIOC_DQEVENT */
- ret = ctx.dec->dqEvent(ev, 0);
- if (ret == 0)
- {
- if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE)
- {
- /* Received the resolution change event, now can do query_and_set_capture. */
- cout << "Got V4L2_EVENT_RESOLUTION_CHANGE EVENT \n";
- query_and_set_capture(&ctx);
- }
- }
- else if (ret < 0 && errno == EINVAL)
- {
- cerr << "Error in dequeueing decoder event" << endl;
- abort(&ctx);
- }
- /* dequeue from the output plane and enqueue back the buffers after reading. */
- while (1)
- {
- if ( (eos) && (ctx.dec->output_plane.getNumQueuedBuffers() == 0) )
- {
- cout << "Done processing all the buffers returning \n";
- return true;
- }
- /* dequeue a buffer for output plane. */
- if (allow_DQ)
- {
- ret = ctx.dec->output_plane.dqBuffer(v4l2_output_buf, &output_buffer, NULL, 0);
- if (ret < 0)
- {
- if (errno == EAGAIN)
- goto check_capture_buffers;
- else
- {
- cerr << "Error DQing buffer at output plane" << endl;
- abort(&ctx);
- break;
- }
- }
- }
- else
- {
- allow_DQ = true;
- memcpy(&v4l2_output_buf,&temp_buf,sizeof(v4l2_buffer));
- output_buffer = ctx.dec->output_plane.getNthBuffer(v4l2_output_buf.index);
- }
- if ((v4l2_output_buf.flags & V4L2_BUF_FLAG_ERROR) && ctx.enable_input_metadata)
- {
- v4l2_ctrl_videodec_inputbuf_metadata dec_input_metadata;
- /* Get the decoder input metadata.
- Refer V4L2_CID_MPEG_VIDEODEC_INPUT_METADATA */
- ret = ctx.dec->getInputMetadata(v4l2_output_buf.index, dec_input_metadata);
- if (ret == 0)
- {
- ret = report_input_metadata(&ctx, &dec_input_metadata);
- if (ret == -1)
- {
- cerr << "Error with input stream header parsing" << endl;
- }
- }
- }
- if (eos)
- {
- /* Got End Of Stream, no more queueing of buffers on OUTPUT plane. */
- goto check_capture_buffers;
- }
- if ((ctx.decoder_pixfmt == V4L2_PIX_FMT_H264) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_H265) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG2) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG4))
- {
- if (ctx.input_nalu)
- {
- /* read the input nal unit. */
- read_decoder_input_nalu(ctx.in_file[current_file], output_buffer, nalu_parse_buffer,
- CHUNK_SIZE, &ctx);
- }
- else
- {
- /* read the input chunks. */
- read_decoder_input_chunk(ctx.in_file[current_file], output_buffer);
- }
- }
- if (ctx.decoder_pixfmt == V4L2_PIX_FMT_VP9 || ctx.decoder_pixfmt == V4L2_PIX_FMT_VP8)
- {
- /* read the input chunks. */
- ret = read_vpx_decoder_input_chunk(&ctx, output_buffer);
- if (ret != 0)
- cerr << "Couldn't read chunk" << endl;
- }
- v4l2_output_buf.m.planes[0].bytesused = output_buffer->planes[0].bytesused;
- if (ctx.input_nalu && ctx.copy_timestamp && ctx.flag_copyts)
- {
- /* Update the timestamp. */
- v4l2_output_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ctx.timestamp += ctx.timestampincr;
- v4l2_output_buf.timestamp.tv_sec = ctx.timestamp / (MICROSECOND_UNIT);
- v4l2_output_buf.timestamp.tv_usec = ctx.timestamp % (MICROSECOND_UNIT);
- }
- if (v4l2_output_buf.m.planes[0].bytesused == 0)
- {
- if (ctx.bQueue)
- {
- current_file++;
- if(current_file != ctx.file_count)
- {
- allow_DQ = false;
- memcpy(&temp_buf, &v4l2_output_buf, sizeof(v4l2_buffer));
- continue;
- }
- }
- if(ctx.bLoop)
- {
- current_file = current_file % ctx.file_count;
- allow_DQ = false;
- memcpy(&temp_buf, &v4l2_output_buf,sizeof(v4l2_buffer));
- if (ctx.loop_count == 0 || current_loop < ctx.loop_count )
- {
- current_loop++;
- continue;
- }
- }
- }
- /* enqueue a buffer for output plane. */
- ret = ctx.dec->output_plane.qBuffer(v4l2_output_buf, NULL);
- if (ret < 0)
- {
- cerr << "Error Qing buffer at output plane" << endl;
- abort(&ctx);
- break;
- }
- if (v4l2_output_buf.m.planes[0].bytesused == 0)
- {
- eos = true;
- cout << "Input file read complete" << endl;
- goto check_capture_buffers;
- }
- }
- check_capture_buffers:
- /* Dequeue from the capture plane and write them to file and enqueue back. */
- while (1)
- {
- if (!ctx.dec->capture_plane.getStreamStatus())
- {
- cout << "Capture plane not ON, skipping capture plane \n";
- break;
- }
- /* Dequeue a filled buffer. */
- ret = ctx.dec->capture_plane.dqBuffer(v4l2_capture_buf, &capture_buffer, NULL, 0);
- if (ret < 0)
- {
- if (errno == EAGAIN)
- break;
- else
- {
- abort(&ctx);
- cerr << "Error while calling dequeue at capture plane" <<
- endl;
- }
- break;
- }
- if (capture_buffer == NULL)
- {
- cout << "Got CAPTURE BUFFER NULL \n";
- break;
- }
- if (ctx.enable_metadata)
- {
- v4l2_ctrl_videodec_outputbuf_metadata dec_metadata;
- /* Get the decoder output metadata on capture-plane.
- Refer V4L2_CID_MPEG_VIDEODEC_METADATA */
- ret = ctx.dec->getMetadata(v4l2_capture_buf.index, dec_metadata);
- if (ret == 0)
- {
- report_metadata(&ctx, &dec_metadata);
- }
- }
- if (ctx.copy_timestamp && ctx.input_nalu && ctx.stats)
- {
- cout << "[" << v4l2_capture_buf.index << "]" "dec capture plane dqB timestamp [" <<
- v4l2_capture_buf.timestamp.tv_sec << "s" << v4l2_capture_buf.timestamp.tv_usec << "us]" << endl;
- }
- if (!ctx.disable_rendering && ctx.stats)
- {
- /* Rendering the buffer.
- NOTE: EglRenderer requires the fd of the 0th plane to render the buffer. */
- if(ctx.capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- capture_buffer->planes[0].fd = ctx.dmabuff_fd[v4l2_capture_buf.index];
- if (ctx.renderer->render(capture_buffer->planes[0].fd) == -1)
- {
- abort(&ctx);
- cerr << "Error while queueing buffer for rendering "
- << endl;
- break;
- }
- }
- /* Get the decoded buffer data dumped to file. */
- if (ctx.out_file || (!ctx.disable_rendering && !ctx.stats))
- {
- NvBufferRect src_rect, dest_rect;
- src_rect.top = 0;
- src_rect.left = 0;
- src_rect.width = ctx.display_width;
- src_rect.height = ctx.display_height;
- dest_rect.top = 0;
- dest_rect.left = 0;
- dest_rect.width = ctx.display_width;
- dest_rect.height = ctx.display_height;
- NvBufferTransformParams transform_params;
- memset(&transform_params, 0, sizeof(transform_params));
- /* Indicates which of the transform parameters are valid. */
- transform_params.transform_flag = NVBUFFER_TRANSFORM_FILTER;
- transform_params.transform_flip = NvBufferTransform_None;
- transform_params.transform_filter = NvBufferTransform_Filter_Nearest;
- transform_params.src_rect = src_rect;
- transform_params.dst_rect = dest_rect;
- if(ctx.capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- capture_buffer->planes[0].fd = ctx.dmabuff_fd[v4l2_capture_buf.index];
- /* Perform Blocklinear to PitchLinear conversion. */
- ret = NvBufferTransform(capture_buffer->planes[0].fd, ctx.dst_dma_fd, &transform_params);
- if (ret == -1)
- {
- cerr << "Transform failed" << endl;
- break;
- }
- /* Write raw video frame to file. */
- if (!ctx.stats && ctx.out_file)
- {
- /* Dumping two planes for NV12, NV16, NV24 and three for I420 */
- cout << "Writing to file \n";
- dump_dmabuf(ctx.dst_dma_fd, 0, ctx.out_file);
- dump_dmabuf(ctx.dst_dma_fd, 1, ctx.out_file);
- if (ctx.out_pixfmt == 2)
- {
- dump_dmabuf(ctx.dst_dma_fd, 2, ctx.out_file);
- }
- }
- /* Rendering the buffer. */
- if (!ctx.stats && !ctx.disable_rendering)
- {
- ctx.renderer->render(ctx.dst_dma_fd);
- }
- /* Queue the buffer back once it has been used.
- NOTE: If we are not rendering, queue the buffer back here immediately. */
- if(ctx.capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- v4l2_capture_buf.m.planes[0].m.fd = ctx.dmabuff_fd[v4l2_capture_buf.index];
- if (ctx.dec->capture_plane.qBuffer(v4l2_capture_buf, NULL) < 0)
- {
- abort(&ctx);
- cerr << "Error while queueing buffer at decoder capture plane"
- << endl;
- break;
- }
- }
- }
- }
- return eos;
- }
- #include <chrono>
- /**
- * Decode processing function for blocking mode.
- *
- * @param ctx : Decoder context
- * @param eos : end of stream
- * @param current_file : current file
- * @param current_loop : iterator count
- * @param nalu_parse_buffer : input parsed nal unit
- */
- static bool decoder_proc_blocking(context_t &ctx, bool eos, uint32_t current_file,
- int current_loop, char *nalu_parse_buffer)
- {
- int allow_DQ = true;
- int ret = 0;
- struct v4l2_buffer temp_buf;
- /* 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())
- {
- std::cout<<"oo"<<std::endl;
- 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;
- /* dequeue a buffer for output plane. */
- if(allow_DQ)
- {
- std::cout<<"dq "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<< std::endl;
- ret = ctx.dec->output_plane.dqBuffer(v4l2_buf, &buffer, NULL, -1);
- std::cout<<"out dq "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<< std::endl;
- if (ret < 0)
- {
- cerr << "Error DQing buffer at output plane" << endl;
- abort(&ctx);
- break;
- }
- }
- else
- {
- allow_DQ = true;
- memcpy(&v4l2_buf,&temp_buf,sizeof(v4l2_buffer));
- buffer = ctx.dec->output_plane.getNthBuffer(v4l2_buf.index);
- }
- if ((v4l2_buf.flags & V4L2_BUF_FLAG_ERROR) && ctx.enable_input_metadata)
- {
- v4l2_ctrl_videodec_inputbuf_metadata dec_input_metadata;
- /* Get the decoder input metadata.
- Refer V4L2_CID_MPEG_VIDEODEC_INPUT_METADATA */
- ret = ctx.dec->getInputMetadata(v4l2_buf.index, dec_input_metadata);
- if (ret == 0)
- {
- ret = report_input_metadata(&ctx, &dec_input_metadata);
- if (ret == -1)
- {
- cerr << "Error with input stream header parsing" << endl;
- }
- }
- }
- if ((ctx.decoder_pixfmt == V4L2_PIX_FMT_H264) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_H265) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG2) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG4))
- {
- if (ctx.input_nalu)
- {
- /* read the input nal unit. */
- read_decoder_input_nalu(ctx.in_file[current_file], buffer, nalu_parse_buffer,
- CHUNK_SIZE, &ctx);
- }
- else
- {
- /* read the input chunks. */
- read_decoder_input_chunk(ctx.in_file[current_file], buffer);
- }
- }
- if (ctx.decoder_pixfmt == V4L2_PIX_FMT_VP9 || ctx.decoder_pixfmt == V4L2_PIX_FMT_VP8)
- {
- /* read the input chunks. */
- ret = read_vpx_decoder_input_chunk(&ctx, buffer);
- if (ret != 0)
- cerr << "Couldn't read chunk" << endl;
- }
- v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
- if (ctx.input_nalu && ctx.copy_timestamp && ctx.flag_copyts)
- {
- /* Update the timestamp. */
- v4l2_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ctx.timestamp += ctx.timestampincr;
- v4l2_buf.timestamp.tv_sec = ctx.timestamp / (MICROSECOND_UNIT);
- v4l2_buf.timestamp.tv_usec = ctx.timestamp % (MICROSECOND_UNIT);
- }
- if (v4l2_buf.m.planes[0].bytesused == 0)
- {
- if (ctx.bQueue)
- {
- current_file++;
- if(current_file != ctx.file_count)
- {
- allow_DQ = false;
- memcpy(&temp_buf,&v4l2_buf,sizeof(v4l2_buffer));
- continue;
- }
- }
- if(ctx.bLoop)
- {
- current_file = current_file % ctx.file_count;
- allow_DQ = false;
- memcpy(&temp_buf,&v4l2_buf,sizeof(v4l2_buffer));
- }
- }
- /* enqueue a buffer for output plane. */
- 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;
- }
- }
- return eos;
- }
- /**
- * Decode processing function.
- *
- * @param ctx : Decoder context
- * @param argc : Argument Count
- * @param argv : Argument Vector
- */
- static int
- decode_proc(context_t& ctx, int argc, char *argv[])
- {
- int ret = 0;
- int error = 0;
- uint32_t current_file = 0;
- uint32_t i;
- bool eos = false;
- int current_loop = 0;
- char *nalu_parse_buffer = NULL;
- NvApplicationProfiler &profiler = NvApplicationProfiler::getProfilerInstance();
- /* Set default values for decoder context members. */
- set_defaults(&ctx);
- /* Set thread name for decoder Output Plane thread. */
- pthread_setname_np(pthread_self(), "DecOutPlane");
- /* Parse application command line options. */
- if (parse_csv_args(&ctx, argc, argv))
- {
- fprintf(stderr, "Error parsing commandline arguments\n");
- return -1;
- }
- /* Create NvVideoDecoder object for blocking or non-blocking I/O mode. */
- if (ctx.blocking_mode)
- {
- cout << "Creating decoder in blocking mode \n";
- ctx.dec = NvVideoDecoder::createVideoDecoder("dec0");
- }
- else
- {
- cout << "Creating decoder in non-blocking mode \n";
- ctx.dec = NvVideoDecoder::createVideoDecoder("dec0", O_NONBLOCK);
- }
- TEST_ERROR(!ctx.dec, "Could not create decoder", cleanup);
- /* Open the input file. */
- ctx.in_file = (std::ifstream **)malloc(sizeof(std::ifstream *)*ctx.file_count);
- for (uint32_t i = 0 ; i < ctx.file_count ; i++)
- {
- ctx.in_file[i] = new ifstream(ctx.in_file_path[i]);
- TEST_ERROR(!ctx.in_file[i]->is_open(), "Error opening input file", cleanup);
- }
- /* Open the output file. */
- if (ctx.out_file_path)
- {
- ctx.out_file = new ofstream(ctx.out_file_path);
- TEST_ERROR(!ctx.out_file->is_open(), "Error opening output file",
- cleanup);
- }
- /* Enable profiling for decoder if stats are requested. */
- if (ctx.stats)
- {
- profiler.start(NvApplicationProfiler::DefaultSamplingInterval);
- ctx.dec->enableProfiling();
- }
- /* Subscribe to Resolution change event.
- Refer ioctl VIDIOC_SUBSCRIBE_EVENT */
- ret = ctx.dec->subscribeEvent(V4L2_EVENT_RESOLUTION_CHANGE, 0, 0);
- TEST_ERROR(ret < 0, "Could not subscribe to V4L2_EVENT_RESOLUTION_CHANGE",
- cleanup);
- /* Set format on the output plane.
- Refer ioctl VIDIOC_S_FMT */
- ret = ctx.dec->setOutputPlaneFormat(ctx.decoder_pixfmt, CHUNK_SIZE);
- TEST_ERROR(ret < 0, "Could not set output plane format", cleanup);
- /* Configure for frame input mode for decoder.
- Refer V4L2_CID_MPEG_VIDEO_DISABLE_COMPLETE_FRAME_INPUT */
- if (ctx.input_nalu)
- {
- /* Input to the decoder will be nal units. */
- nalu_parse_buffer = new char[CHUNK_SIZE];
- printf("Setting frame input mode to 0 \n");
- ret = ctx.dec->setFrameInputMode(0);
- TEST_ERROR(ret < 0,
- "Error in decoder setFrameInputMode", cleanup);
- }
- else
- {
- /* Input to the decoder will be a chunk of bytes.
- NOTE: 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. */
- printf("Setting frame input mode to 1 \n");
- ret = ctx.dec->setFrameInputMode(1);
- TEST_ERROR(ret < 0,
- "Error in decoder setFrameInputMode", cleanup);
- }
- /* Disable decoder DPB management.
- NOTE: 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);
- }
- /* Enable decoder error and metadata reporting.
- Refer V4L2_CID_MPEG_VIDEO_ERROR_REPORTING */
- if (ctx.enable_metadata || ctx.enable_input_metadata)
- {
- ret = ctx.dec->enableMetadataReporting();
- TEST_ERROR(ret < 0, "Error while enabling metadata reporting", cleanup);
- }
- /* Enable max performance mode by using decoder max clock settings.
- Refer V4L2_CID_MPEG_VIDEO_MAX_PERFORMANCE */
- if (ctx.max_perf)
- {
- ret = ctx.dec->setMaxPerfMode(ctx.max_perf);
- TEST_ERROR(ret < 0, "Error while setting decoder to max perf", cleanup);
- }
- /* Set the skip frames property of the decoder.
- Refer V4L2_CID_MPEG_VIDEO_SKIP_FRAMES */
- 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 can read
- encoded data into the buffers. */
- if (ctx.output_plane_mem_type == V4L2_MEMORY_MMAP) {
- /* configure decoder output plane for MMAP io-mode.
- Refer ioctl VIDIOC_REQBUFS, VIDIOC_QUERYBUF and VIDIOC_EXPBUF */
- ret = ctx.dec->output_plane.setupPlane(V4L2_MEMORY_MMAP, 2, true, false);
- } else if (ctx.output_plane_mem_type == V4L2_MEMORY_USERPTR) {
- /* configure decoder output plane for USERPTR io-mode.
- Refer ioctl VIDIOC_REQBUFS */
- ret = ctx.dec->output_plane.setupPlane(V4L2_MEMORY_USERPTR, 10, false, true);
- }
- TEST_ERROR(ret < 0, "Error while setting up output plane", cleanup);
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx.out_file || (!ctx.disable_rendering && !ctx.stats))
- {
- /* Create converter object for Block-linear to Pitch-linear
- transform required for writing decoded raw video to file. */
- ctx.conv = NvVideoConverter::createVideoConverter("conv0");
- TEST_ERROR(!ctx.conv, "Could not create video converter", cleanup);
- /* Set dqbuffer thread callback for converter output-plane. */
- ctx.conv->output_plane.
- setDQThreadCallback(conv0_output_dqbuf_thread_callback);
- /* Set dqbuffer thread callback for converter capture-plane. */
- ctx.conv->capture_plane.
- setDQThreadCallback(conv0_capture_dqbuf_thread_callback);
- /* Enable profiling for converter if stats are requested. */
- if (ctx.stats)
- {
- ctx.conv->enableProfiling();
- }
- }
- #endif
- /* Start stream processing on decoder output-plane.
- Refer ioctl VIDIOC_STREAMON */
- ret = ctx.dec->output_plane.setStreamStatus(true);
- TEST_ERROR(ret < 0, "Error in output plane stream on", cleanup);
- /* Enable copy timestamp with start timestamp in seconds for decode fps.
- NOTE: Used to demonstrate how timestamp can be associated with an
- individual H264/H265 frame to achieve video-synchronization. */
- if (ctx.copy_timestamp && ctx.input_nalu) {
- ctx.timestamp = (ctx.start_ts * MICROSECOND_UNIT);
- ctx.timestampincr = (MICROSECOND_UNIT * 16) / ((uint32_t) (ctx.dec_fps * 16));
- }
- /* Read encoded data and enqueue all the output plane buffers.
- Exit loop in case file read is complete. */
- i = 0;
- current_loop = 1;
- 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.decoder_pixfmt == V4L2_PIX_FMT_H264) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_H265) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG2) ||
- (ctx.decoder_pixfmt == V4L2_PIX_FMT_MPEG4))
- {
- if (ctx.input_nalu)
- {
- /* read the input nal unit. */
- read_decoder_input_nalu(ctx.in_file[current_file], buffer, nalu_parse_buffer,
- CHUNK_SIZE, &ctx);
- }
- else
- {
- /* read the input chunks. */
- read_decoder_input_chunk(ctx.in_file[current_file], buffer);
- }
- }
- if (ctx.decoder_pixfmt == V4L2_PIX_FMT_VP9 || ctx.decoder_pixfmt == V4L2_PIX_FMT_VP8)
- {
- /* read the input chunks. */
- ret = read_vpx_decoder_input_chunk(&ctx, buffer);
- if (ret != 0)
- cerr << "Couldn't read chunk" << endl;
- }
- v4l2_buf.index = i;
- v4l2_buf.m.planes = planes;
- v4l2_buf.m.planes[0].bytesused = buffer->planes[0].bytesused;
- if (ctx.input_nalu && ctx.copy_timestamp && ctx.flag_copyts)
- {
- /* Update the timestamp. */
- v4l2_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ctx.timestamp += ctx.timestampincr;
- v4l2_buf.timestamp.tv_sec = ctx.timestamp / (MICROSECOND_UNIT);
- v4l2_buf.timestamp.tv_usec = ctx.timestamp % (MICROSECOND_UNIT);
- }
- if (v4l2_buf.m.planes[0].bytesused == 0)
- {
- if (ctx.bQueue)
- {
- current_file++;
- if(current_file != ctx.file_count)
- {
- continue;
- }
- }
- if(ctx.bLoop)
- {
- current_file = current_file % ctx.file_count;
- if(ctx.loop_count == 0 || current_loop < ctx.loop_count )
- {
- current_loop++;
- continue;
- }
- }
- }
- /* 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++;
- }
- /* Create threads for decoder output */
- if (ctx.blocking_mode)
- {
- pthread_create(&ctx.dec_capture_loop, NULL, dec_capture_loop_fcn, &ctx);
- /* Set thread name for decoder Capture Plane thread. */
- pthread_setname_np(ctx.dec_capture_loop, "DecCapPlane");
- }
- else
- {
- sem_init(&ctx.pollthread_sema, 0, 0);
- sem_init(&ctx.decoderthread_sema, 0, 0);
- pthread_create(&ctx.dec_pollthread, NULL, decoder_pollthread_fcn, &ctx);
- cout << "Created the PollThread and Decoder Thread \n";
- /* Set thread name for decoder Poll thread. */
- pthread_setname_np(ctx.dec_pollthread, "DecPollThread");
- }
- if (ctx.blocking_mode)
- eos = decoder_proc_blocking(ctx, eos, current_file, current_loop, nalu_parse_buffer);
- else
- eos = decoder_proc_nonblocking(ctx, eos, current_file, current_loop, nalu_parse_buffer);
- /* After sending EOS, all the buffers from output plane should be dequeued.
- and after that capture plane loop should be signalled to stop. */
- if (ctx.blocking_mode)
- {
- 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;
- }
- if ((v4l2_buf.flags & V4L2_BUF_FLAG_ERROR) && ctx.enable_input_metadata)
- {
- v4l2_ctrl_videodec_inputbuf_metadata dec_input_metadata;
- /* Get the decoder input metadata.
- Refer V4L2_CID_MPEG_VIDEODEC_INPUT_METADATA */
- ret = ctx.dec->getInputMetadata(v4l2_buf.index, dec_input_metadata);
- if (ret == 0)
- {
- ret = report_input_metadata(&ctx, &dec_input_metadata);
- if (ret == -1)
- {
- cerr << "Error with input stream header parsing" << endl;
- abort(&ctx);
- break;
- }
- }
- }
- }
- }
- /* Signal EOS to the decoder capture loop. */
- ctx.got_eos = true;
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx.conv)
- {
- ctx.conv->capture_plane.waitForDQThread(-1);
- }
- #endif
- if (ctx.stats)
- {
- profiler.stop();
- ctx.dec->printProfilingStats(cout);
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx.conv)
- {
- ctx.conv->printProfilingStats(cout);
- }
- #endif
- if (ctx.renderer)
- {
- ctx.renderer->printProfilingStats(cout);
- }
- profiler.printProfilerData(cout);
- }
- cleanup:
- if (ctx.blocking_mode && ctx.dec_capture_loop)
- {
- pthread_join(ctx.dec_capture_loop, NULL);
- }
- else if (!ctx.blocking_mode)
- {
- /* Clear the poll interrupt to get the decoder's poll thread out. */
- ctx.dec->ClearPollInterrupt();
- /* If Pollthread is waiting on, signal it to exit the thread. */
- sem_post(&ctx.pollthread_sema);
- pthread_join(ctx.dec_pollthread, NULL);
- }
- if(ctx.capture_plane_mem_type == V4L2_MEMORY_DMABUF)
- {
- for(int index = 0 ; index < ctx.numCapBuffers ; index++)
- {
- if(ctx.dmabuff_fd[index] != 0)
- {
- ret = NvBufferDestroy (ctx.dmabuff_fd[index]);
- if(ret < 0)
- {
- cerr << "Failed to Destroy NvBuffer" << endl;
- }
- }
- }
- }
- #ifndef USE_NVBUF_TRANSFORM_API
- if (ctx.conv && ctx.conv->isInError())
- {
- cerr << "Converter is in error" << endl;
- error = 1;
- }
- #endif
- 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 count = 0), and finally call v4l2_close on the fd. */
- delete ctx.dec;
- #ifndef USE_NVBUF_TRANSFORM_API
- delete ctx.conv;
- #endif
- /* Similarly, EglRenderer destructor does all the cleanup. */
- delete ctx.renderer;
- for (uint32_t i = 0 ; i < ctx.file_count ; i++)
- delete ctx.in_file[i];
- delete ctx.out_file;
- #ifndef USE_NVBUF_TRANSFORM_API
- delete ctx.conv_output_plane_buf_queue;
- #else
- if(ctx.dst_dma_fd != -1)
- {
- NvBufferDestroy(ctx.dst_dma_fd);
- ctx.dst_dma_fd = -1;
- }
- #endif
- delete[] nalu_parse_buffer;
- free (ctx.in_file);
- for (uint32_t i = 0 ; i < ctx.file_count ; i++)
- free (ctx.in_file_path[i]);
- free (ctx.in_file_path);
- free(ctx.out_file_path);
- if (!ctx.blocking_mode)
- {
- sem_destroy(&ctx.pollthread_sema);
- sem_destroy(&ctx.decoderthread_sema);
- }
- return -error;
- }
- void StartDecode()
- {
- context_t ctx;
- int targc = 3;
- char * targv[3];
- targv[0] = "videoc_encode";
- targv[1] = "H264";
- targv[2] = "/home/nvidia/testh264.mp4";
- int ret = decode_proc(ctx,targc,targv);
- }
- /**
- * Start of video Decode application.
- *
- * @param argc : Argument Count
- * @param argv : Argument Vector
- */
- //int
- //main(int argc, char *argv[])
- //{
- // /* create decoder context. */
- // context_t ctx;
- // int ret = 0;
- // /* save decode iterator number */
- // int iterator_num = 0;
- // int targc = 3;
- // char * targv[3];
- // targv[0] = "videoc_encode";
- // targv[1] = "H264";
- // targv[2] = "/home/nvidia/testh264.mp4";
- //// targv[2] = strwidth;
- //// targv[3] = strheight;
- //// targv[5] = "/home/nvidia/testh264.mp4";
- // do
- // {
- // /* Invoke video decode function. */
- // ret = decode_proc(ctx,targc,targv);
- // // ret = decode_proc(ctx, argc, argv);
- // iterator_num++;
- // } while((ctx.stress_test != iterator_num) && ret == 0);
- // /* Report application run status on exit. */
- // if (ret)
- // {
- // cout << "App run failed" << endl;
- // }
- // else
- // {
- // cout << "App run was successful" << endl;
- // }
- // return ret;
- //}
|