/* * Copyright (c) 2016-2022, 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 "Error.h" #include "Thread.h" #include "nvmmapi/NvNativeBuffer.h" #include "ArgusHelpers.h" #include #include #include #include #include #include #include #include "NvBufSurface.h" #include "nvbuf_utils.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Argus; using namespace EGLStream; /* Constant configuration */ static const int MAX_ENCODER_FRAMES = 5; static const uint64_t WAIT_FOR_EVENT_TIMEOUT = 1500000000; static const uint64_t ACQUIRE_FRAME_TIMEOUT = 3000000000; /* This value is tricky. Too small value will impact the FPS */ static const int NUM_BUFFERS = 30; /* Configurations which can be overrided by cmdline */ static std::string OUTPUT_FILENAME ("output"); static std::string CODEC ("H264"); static uint32_t ENCODER_PIXFMT = V4L2_PIX_FMT_H264; static uint32_t CAPTURE_TIME = 5; // In seconds. static uint32_t SENSOR_MODE_INDEX = 0; static uint8_t BITRATE = 14; static std::vector cameraPTS; /* Debug print macros */ #define PRODUCER_PRINT(...) printf("PRODUCER: " __VA_ARGS__) #define CONSUMER_PRINT(...) printf("CONSUMER: " __VA_ARGS__) #define CHECK_ERROR(expr) \ do { \ if ((expr) < 0) { \ abort(); \ ORIGINATE_ERROR(#expr " failed"); \ } \ } while (0); static EGLDisplay eglDisplay = EGL_NO_DISPLAY; namespace ArgusSamples { /******************************************************************************* * Base Consumer thread: * Creates an EGLStream::FrameConsumer object to read frames from the * OutputStream, then creates/populates an NvBuffer (dmabuf) from the frames * to be processed by processV4L2Fd. ******************************************************************************/ class ConsumerThread : public Thread { public: explicit ConsumerThread(OutputStream* stream, std::string outputName) : m_stream(stream), m_outputName(outputName), m_dmabuf(-1) { errorStatus = false; } bool errorStatus; ~ConsumerThread(); protected: /** @name Thread methods */ /**@{*/ bool threadInitialize(); bool threadExecute(); bool threadShutdown(); /**@}*/ bool createGstPipeline(); void gstHandleMessage(GstElement * pipeline); bool gstFinishPipeline(); GstElement *m_pipeline; GstElement *m_source; GstState m_state; uint32_t m_numFrames = 0; OutputStream* m_stream; std::string m_outputName; UniqueObj m_consumer; int m_dmabuf; private: void printErrorStatus(Argus::Status status); }; void ConsumerThread::printErrorStatus(Argus::Status status) { switch (status) { case Argus::STATUS_OK: CONSUMER_PRINT("Argus::STATUS_OK \n"); break; case Argus::STATUS_INVALID_PARAMS: CONSUMER_PRINT("Argus::STATUS_INVALID_PARAMS \n"); break; case Argus::STATUS_INVALID_SETTINGS: CONSUMER_PRINT("Argus::STATUS_INVALID_SETTINGS \n"); break; case Argus::STATUS_UNAVAILABLE: CONSUMER_PRINT("Argus::STATUS_UNAVAILABLE \n"); break; case Argus::STATUS_OUT_OF_MEMORY: CONSUMER_PRINT("Argus::STATUS_OUT_OF_MEMORY \n"); break; case Argus::STATUS_UNIMPLEMENTED: CONSUMER_PRINT("Argus::STATUS_UNIMPLEMENTED \n"); break; case Argus::STATUS_TIMEOUT: CONSUMER_PRINT("Argus::STATUS_TIMEOUT \n"); break; case Argus::STATUS_CANCELLED: CONSUMER_PRINT("Argus::STATUS_CANCELLED \n"); break; case Argus::STATUS_DISCONNECTED: CONSUMER_PRINT("Argus::STATUS_DISCONNECTED \n"); break; case Argus::STATUS_END_OF_STREAM: CONSUMER_PRINT("Argus::STATUS_END_OF_STREAM \n"); break; default: CONSUMER_PRINT("BAD STATUS \n"); break; } return; } ConsumerThread::~ConsumerThread() { if (m_dmabuf != -1) NvBufSurf::NvDestroy(m_dmabuf); } bool ConsumerThread::threadInitialize() { /* Create the FrameConsumer. */ m_consumer = UniqueObj(FrameConsumer::create(m_stream)); if (!m_consumer) ORIGINATE_ERROR("Failed to create FrameConsumer"); if (!createGstPipeline()) ORIGINATE_ERROR("Failed to create Gstreamer Pipeline"); return true; } static void notify_to_destroy (gpointer user_data) { GST_INFO ("NvBufferDestroy(%d)", *(int *)user_data); NvBufferDestroy(*(int *)user_data); g_free(user_data); } bool ConsumerThread::threadExecute() { IEGLOutputStream *iEglOutputStream = interface_cast(m_stream); IFrameConsumer *iFrameConsumer = interface_cast(m_consumer); /* Wait until the producer has connected to the stream. */ CONSUMER_PRINT("Waiting until producer is connected...\n"); if (iEglOutputStream->waitUntilConnected() != STATUS_OK) ORIGINATE_ERROR("Stream failed to connect."); CONSUMER_PRINT("Producer has connected; continuing.\n"); GstBuffer *buffer; GstFlowReturn ret; GstMapInfo map = {0}; gpointer data = NULL, user_data = NULL; NvBufferParams par; GstMemoryFlags flags = (GstMemoryFlags)0; while (true) { Argus::Status argusStatus; /* Acquire a frame. */ UniqueObj frame(iFrameConsumer->acquireFrame(ACQUIRE_FRAME_TIMEOUT, &argusStatus)); if (argusStatus != Argus::STATUS_OK) { printErrorStatus(argusStatus); errorStatus = true; break; } IFrame *iFrame = interface_cast