gstreamer/subprojects/gst-plugins-bad/sys/nvcodec/gstnvencobject.h
Seungha Yang b1c14b0357 nvencoder: Fix b-frame encoding on Linux
On Windows, Win32 event handle is used to wait for encoded output,
but it's not available on Linux. We should delay bitstream locking
if encoder returns "need-more-input"

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4004>
2023-02-20 20:49:01 +00:00

258 lines
7.2 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);
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 <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 *> pending_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;
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<guint> buffer_seq_;
std::atomic<guint> resource_seq_;
std::atomic<guint> task_seq_;
};