gstreamer/subprojects/gst-plugins-bad/sys/nvcodec/gstnvencobject.h
Seungha Yang eb0fca4180 nvencoder: Reuse input resource
Call input resource map functions (i.e., nvEncRegisterResource,
nvEncUnregisterResource, nvEncMapInputResource, and
nvEncUnmapInputResource) only once and reuse the mapped resources,
instead of per input frame map/unmap

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3884>
2023-02-16 17:49:54 +00:00

248 lines
7 KiB
C++

/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.com>
*
* 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 <gst/gst.h>
#include <gst/video/video.h>
#include <gst/cuda/gstcuda.h>
#ifdef G_OS_WIN32
#include <gst/d3d11/gstd3d11.h>
#endif
#include "nvEncodeAPI.h"
#include "gstnvenc.h"
#include <memory>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <set>
#include <string>
#include <atomic>
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);
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
class GstNvEncObject : public std::enable_shared_from_this <GstNvEncObject>
{
public:
static bool IsSuccess (NVENCSTATUS status,
GstNvEncObject * self,
const gchar * file,
const gchar * function,
gint line);
static std::shared_ptr<GstNvEncObject>
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 <GstNvEncBuffer *> 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 <GstNvEncResource *> resource_queue_;
/* list of GstNvEncResource in task_queue */
std::set <GstNvEncResource *> active_resource_queue_;
std::queue <GstNvEncTask *> task_queue_;
std::queue <GstNvEncTask *> 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;
NV_ENC_DEVICE_TYPE device_type_ = NV_ENC_DEVICE_TYPE_CUDA;
NV_ENC_BUFFER_FORMAT buffer_format_ = NV_ENC_BUFFER_FORMAT_UNDEFINED;
std::atomic<guint> buffer_seq_;
std::atomic<guint> resource_seq_;
std::atomic<guint> task_seq_;
};