/* GStreamer * Copyright (C) 2023 Seungha Yang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #ifdef G_OS_WIN32 #include #endif #include "nvEncodeAPI.h" #include "gstnvenc.h" #include #include #include #include #include #include #include G_BEGIN_DECLS #define GST_TYPE_NV_ENC_BUFFER (gst_nv_enc_buffer_get_type ()) struct GstNvEncBuffer; GType gst_nv_enc_buffer_get_type (void); NVENCSTATUS gst_nv_enc_buffer_lock (GstNvEncBuffer * buffer, gpointer * data, guint32 * pitch); void gst_nv_enc_buffer_unlock (GstNvEncBuffer * buffer); static inline GstNvEncBuffer * gst_nv_enc_buffer_ref (GstNvEncBuffer * buffer) { return (GstNvEncBuffer *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (buffer)); } static inline void gst_nv_enc_buffer_unref (GstNvEncBuffer * buffer) { gst_mini_object_unref (GST_MINI_OBJECT_CAST (buffer)); } static inline void gst_clear_nv_encoder_buffer (GstNvEncBuffer ** buffer) { if (buffer && *buffer) { gst_nv_enc_buffer_unref (*buffer); *buffer = NULL; } } #define GST_TYPE_NV_ENC_RESOURCE (gst_nv_enc_resource_get_type ()) struct GstNvEncResource; GType gst_nv_enc_resource_get_type (void); static inline GstNvEncResource * gst_nv_enc_resource_ref (GstNvEncResource * resource) { return (GstNvEncResource *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (resource)); } static inline void gst_nv_enc_resource_unref (GstNvEncResource * resource) { gst_mini_object_unref (GST_MINI_OBJECT_CAST (resource)); } static inline void gst_clear_nv_encoder_resource (GstNvEncResource ** resource) { if (resource && *resource) { gst_nv_enc_resource_unref (*resource); *resource = NULL; } } #define GST_TYPE_NV_ENC_TASK (gst_nv_enc_task_get_type ()) struct GstNvEncTask; GType gst_nv_enc_task_get_type (void); gboolean gst_nv_enc_task_set_buffer (GstNvEncTask * task, GstNvEncBuffer * buffer); gboolean gst_nv_enc_task_set_resource (GstNvEncTask * task, GstBuffer * buffer, GstNvEncResource * resource); GArray * gst_nv_enc_task_get_sei_payload (GstNvEncTask * task); NVENCSTATUS gst_nv_enc_task_lock_bitstream (GstNvEncTask * task, NV_ENC_LOCK_BITSTREAM * bitstream); void gst_nv_enc_task_unlock_bitstream (GstNvEncTask * task); static inline GstNvEncTask * gst_nv_enc_task_ref (GstNvEncTask * task) { return (GstNvEncTask *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (task)); } static inline void gst_nv_enc_task_unref (GstNvEncTask * task) { gst_mini_object_unref (GST_MINI_OBJECT_CAST (task)); } const gchar * nvenc_status_to_string (NVENCSTATUS status); G_END_DECLS enum GstNvEncCodec { GST_NV_ENC_CODEC_H264, GST_NV_ENC_CODEC_H265, }; class GstNvEncObject : public std::enable_shared_from_this { public: static bool IsSuccess (NVENCSTATUS status, GstNvEncObject * self, const gchar * file, const gchar * function, gint line); static std::shared_ptr CreateInstance (GstElement * client, GstObject * device, NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS * params); ~GstNvEncObject (); gpointer GetHandle (); guint GetTaskSize (); NVENCSTATUS InitSession (NV_ENC_INITIALIZE_PARAMS * params, GstCudaStream * stream, const GstVideoInfo * info, guint pool_size); NVENCSTATUS Reconfigure (NV_ENC_RECONFIGURE_PARAMS * params); void SetFlushing (bool flushing); NVENCSTATUS Encode (GstVideoCodecFrame * codec_frame, NV_ENC_PIC_STRUCT pic_struct, GstNvEncTask * task); NVENCSTATUS Drain (GstNvEncTask * task); GstFlowReturn GetOutput (GstNvEncTask ** task); NVENCSTATUS LockBitstream (NV_ENC_LOCK_BITSTREAM * bitstream); NVENCSTATUS UnlockBitstream (NV_ENC_OUTPUT_PTR output_ptr); NVENCSTATUS AcquireBuffer (GstNvEncBuffer ** buffer); NVENCSTATUS AcquireResource (GstMemory * mem, GstNvEncResource ** resource); GstFlowReturn AcquireTask (GstNvEncTask ** task, bool force); void PushEmptyTask (GstNvEncTask * task); void PushEmptyBuffer (GstNvEncBuffer * buffer); void ReleaseResource (GstNvEncResource * resource); void DeactivateResource (GstNvEncResource * resource); bool DeviceLock (); bool DeviceUnlock (); private: void releaseResourceUnlocked (GstNvEncResource * resource); void releaseTaskUnlocked (GstNvEncTask * task); NVENCSTATUS acquireResourceCuda (GstMemory * mem, GstNvEncResource ** resource); #ifdef G_OS_WIN32 NVENCSTATUS acquireResourceD3D11 (GstMemory * mem, GstNvEncResource ** resource); #endif void runResourceGC (); private: std::string id_; std::mutex lock_; std::recursive_mutex resource_lock_; std::condition_variable cond_; /* holding unused GstNvEncBuffer object, holding ownership */ std::queue buffer_queue_; /* GstNvEncResource resource is always owned by GstMemory. * below two data struct will track the resource's life cycle */ /* list of all registered GstNvEncResource, without ownership */ std::set resource_queue_; /* list of GstNvEncResource in task_queue */ std::set active_resource_queue_; std::queue task_queue_; std::queue pending_task_queue_; std::queue empty_task_queue_; gint64 user_token_; GstCudaContext *context_ = nullptr; GstCudaStream *stream_ = nullptr; #ifdef G_OS_WIN32 GstD3D11Device *device_ = nullptr; #endif GstVideoInfo info_; gpointer session_ = nullptr; bool initialized_ = false; bool flushing_ = false; guint task_size_ = 0; guint lookahead_ = 0; NV_ENC_DEVICE_TYPE device_type_ = NV_ENC_DEVICE_TYPE_CUDA; NV_ENC_BUFFER_FORMAT buffer_format_ = NV_ENC_BUFFER_FORMAT_UNDEFINED; GstNvEncCodec codec_; std::atomic buffer_seq_; std::atomic resource_seq_; std::atomic task_seq_; };