mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-15 12:56:33 +00:00
b1c14b0357
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>
258 lines
7.2 KiB
C++
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_;
|
|
};
|