mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
d3d12: Add H.264 video encoder
Adding video encoder element Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5808>
This commit is contained in:
parent
bf420a3a20
commit
4e1bf149d0
17 changed files with 6151 additions and 1 deletions
|
@ -11614,6 +11614,290 @@
|
|||
},
|
||||
"rank": "none"
|
||||
},
|
||||
"d3d12h264enc": {
|
||||
"author": "Seungha Yang <seungha@centricular.com>",
|
||||
"description": "Direct3D12 H.264 Video Encoder",
|
||||
"hierarchy": [
|
||||
"GstD3D12H264Enc",
|
||||
"GstD3D12Encoder",
|
||||
"GstVideoEncoder",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"interfaces": [
|
||||
"GstPreset"
|
||||
],
|
||||
"klass": "Codec/Encoder/Video/Hardware",
|
||||
"pad-templates": {
|
||||
"sink": {
|
||||
"caps": "video/x-raw(memory:D3D12Memory):\n format: NV12\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n interlace-mode: progressive\nvideo/x-raw:\n format: NV12\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n interlace-mode: progressive\n",
|
||||
"direction": "sink",
|
||||
"presence": "always"
|
||||
},
|
||||
"src": {
|
||||
"caps": "video/x-h264:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n stream-format: byte-stream\n alignment: au\n profile: { (string)high, (string)main, (string)constrained-baseline }\n",
|
||||
"direction": "src",
|
||||
"presence": "always"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"aud": {
|
||||
"blurb": "Use AU delimiter",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "true",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"bitrate": {
|
||||
"blurb": "Target bitrate in kbits/second. Used for \"cbr\", \"vbr\", and \"qvbr\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "2000",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"cc-insert": {
|
||||
"blurb": "Closed Caption insert mode",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "insert (0)",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "GstD3D12EncoderSeiInsertMode",
|
||||
"writable": true
|
||||
},
|
||||
"frame-analysis": {
|
||||
"blurb": "Enable 2 pass encoding if supported by hardware",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "false",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"gop-size": {
|
||||
"blurb": "Size of GOP (0 = infinite)",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "60",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"max-bitrate": {
|
||||
"blurb": "Peak bitrate in kbits/second. Used for \"vbr\", and \"qvbr\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "4000",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-b": {
|
||||
"blurb": "Constant QP value for B frames. Used for \"cqp\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "23",
|
||||
"max": "51",
|
||||
"min": "1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-i": {
|
||||
"blurb": "Constant QP value for I frames. Used for \"cqp\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "23",
|
||||
"max": "51",
|
||||
"min": "1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-init": {
|
||||
"blurb": "Initial QP value. Used for \"cbr\", \"vbr\", and \"qvbr\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "51",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-max": {
|
||||
"blurb": "Maximum QP value for \"cbr\", \"vbr\", and \"qvbr\" rate control. To enable min/max QP setting, \"qp-max >= qp-min > 0\" condition should be satisfied",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "51",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-min": {
|
||||
"blurb": "Minimum QP value for \"cbr\", \"vbr\", and \"qvbr\" rate control. To enable min/max QP setting, \"qp-max >= qp-min > 0\" condition should be satisfied",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "51",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qp-p": {
|
||||
"blurb": "Constant QP value for P frames. Used for \"cqp\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "23",
|
||||
"max": "51",
|
||||
"min": "1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"qvbr-quality": {
|
||||
"blurb": "Constant quality target value for \"qvbr\" rate control",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "23",
|
||||
"max": "51",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"rate-control": {
|
||||
"blurb": "Rate Control Method",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "vbr (3)",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "GstD3D12EncoderRateControl",
|
||||
"writable": true
|
||||
},
|
||||
"rate-control-support": {
|
||||
"blurb": "Supported rate control modes",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "(none)",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "GstD3D12EncoderRateControlSupport",
|
||||
"writable": false
|
||||
},
|
||||
"ref-frames": {
|
||||
"blurb": "Preferred number of reference frames. Actual number of reference frames can be limited depending on hardware (0 = unspecified)",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "16",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"slice-mode": {
|
||||
"blurb": "Slice partiton mode",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "full (0)",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "GstD3D12EncoderSubregionLayout",
|
||||
"writable": true
|
||||
},
|
||||
"slice-mode-support": {
|
||||
"blurb": "Supported slice partition modes",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "full",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "GstD3D12EncoderSubregionLayoutSupport",
|
||||
"writable": false
|
||||
},
|
||||
"slice-partition": {
|
||||
"blurb": "Slice partition threshold interpreted depending on \"slice-mode\". If set zero, full frame encoding will be selected without partitioning regardless of requested \"slice-mode\"",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "none"
|
||||
},
|
||||
"d3d12h265dec": {
|
||||
"author": "Seungha Yang <seungha@centricualr.com>",
|
||||
"description": "Direct3D12/DXVA based H.265 video decoder",
|
||||
|
@ -12415,6 +12699,194 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12Encoder": {
|
||||
"hierarchy": [
|
||||
"GstD3D12Encoder",
|
||||
"GstVideoEncoder",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"interfaces": [
|
||||
"GstPreset"
|
||||
],
|
||||
"kind": "object",
|
||||
"properties": {
|
||||
"adapter-luid": {
|
||||
"blurb": "DXGI Adapter LUID (Locally Unique Identifier) of created device",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "9223372036854775807",
|
||||
"min": "-9223372036854775808",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gint64",
|
||||
"writable": false
|
||||
},
|
||||
"device-id": {
|
||||
"blurb": "DXGI Device ID",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": false
|
||||
},
|
||||
"vendor-id": {
|
||||
"blurb": "DXGI Vendor ID",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"GstD3D12EncoderRateControl": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Constant QP",
|
||||
"name": "cqp",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"desc": "Constant bitrate",
|
||||
"name": "cbr",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"desc": "Variable bitrate",
|
||||
"name": "vbr",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"desc": "Constant quality variable bitrate",
|
||||
"name": "qvbr",
|
||||
"value": "4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12EncoderRateControlSupport": {
|
||||
"kind": "flags",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Constant QP",
|
||||
"name": "cqp",
|
||||
"value": "0x00000002"
|
||||
},
|
||||
{
|
||||
"desc": "Constant bitrate",
|
||||
"name": "cbr",
|
||||
"value": "0x00000004"
|
||||
},
|
||||
{
|
||||
"desc": "Variable bitrate",
|
||||
"name": "vbr",
|
||||
"value": "0x00000008"
|
||||
},
|
||||
{
|
||||
"desc": "Constant quality variable bitrate",
|
||||
"name": "qvbr",
|
||||
"value": "0x00000010"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12EncoderSeiInsertMode": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Insert",
|
||||
"name": "insert",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"desc": "Insert and drop",
|
||||
"name": "insert-and-drop",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"desc": "Disabled",
|
||||
"name": "disabled",
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12EncoderSubregionLayout": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Full frame without partitioning",
|
||||
"name": "full",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"desc": "Bytes per subregion",
|
||||
"name": "bytes",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"desc": "Coding units (e.g., macroblock) per subregion",
|
||||
"name": "coding-units",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"desc": "Uniform rows per subregion",
|
||||
"name": "rows",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"desc": "Uniform subregions per frame",
|
||||
"name": "subregions",
|
||||
"value": "4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12EncoderSubregionLayoutSupport": {
|
||||
"kind": "flags",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Full frame without partitioning",
|
||||
"name": "full",
|
||||
"value": "0x00000001"
|
||||
},
|
||||
{
|
||||
"desc": "Bytes per subregion",
|
||||
"name": "bytes",
|
||||
"value": "0x00000002"
|
||||
},
|
||||
{
|
||||
"desc": "Coding units (e.g., macroblock) per subregion",
|
||||
"name": "coding-units",
|
||||
"value": "0x00000004"
|
||||
},
|
||||
{
|
||||
"desc": "Uniform rows (in coding-unit) per subregion",
|
||||
"name": "rows",
|
||||
"value": "0x00000008"
|
||||
},
|
||||
{
|
||||
"desc": "Uniform subregions per frame",
|
||||
"name": "subregions",
|
||||
"value": "0x00000010"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12MSAAMode": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
|
|
|
@ -188,3 +188,7 @@ static const GstD3D12Format g_gst_d3d12_default_format_map[] = {
|
|||
#undef MAKE_FORMAT_MAP_RGBP
|
||||
|
||||
#define GST_D3D12_N_FORMATS G_N_ELEMENTS(g_gst_d3d12_default_format_map)
|
||||
|
||||
void gst_d3d12_device_clear_yuv_texture (GstD3D12Device * device,
|
||||
GstMemory * mem);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "gstd3d12.h"
|
||||
#include "gstd3d12-private.h"
|
||||
#include "gstd3d11on12.h"
|
||||
#include <directx/d3dx12.h>
|
||||
#include <wrl.h>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
@ -143,6 +144,8 @@ struct _GstD3D12DevicePrivate
|
|||
GstD3D12CommandListPool *copy_cl_pool = nullptr;
|
||||
GstD3D12CommandAllocatorPool *copy_ca_pool = nullptr;
|
||||
|
||||
guint rtv_inc_size;
|
||||
|
||||
guint adapter_index = 0;
|
||||
guint device_id = 0;
|
||||
guint vendor_id = 0;
|
||||
|
@ -649,6 +652,9 @@ gst_d3d12_device_new_internal (const GstD3D12DeviceConstructData * data)
|
|||
if (!priv->copy_ca_pool)
|
||||
goto error;
|
||||
|
||||
priv->rtv_inc_size =
|
||||
device->GetDescriptorHandleIncrementSize (D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
return self;
|
||||
|
||||
error:
|
||||
|
@ -1107,3 +1113,75 @@ gst_d3d12_device_d3d12_debug (GstD3D12Device * device, const gchar * file,
|
|||
|
||||
info_queue->ClearStoredMessages ();
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d12_device_clear_yuv_texture (GstD3D12Device * device, GstMemory * mem)
|
||||
{
|
||||
auto priv = device->priv;
|
||||
auto dmem = GST_D3D12_MEMORY_CAST (mem);
|
||||
ComPtr < ID3D12DescriptorHeap > heap;
|
||||
|
||||
auto resource = gst_d3d12_memory_get_resource_handle (dmem);
|
||||
auto desc = resource->GetDesc ();
|
||||
|
||||
if (desc.Format != DXGI_FORMAT_NV12 && desc.Format != DXGI_FORMAT_P010 &&
|
||||
desc.Format != DXGI_FORMAT_P016) {
|
||||
return;
|
||||
}
|
||||
|
||||
gst_d3d12_memory_get_render_target_view_heap (dmem, &heap);
|
||||
if (!heap)
|
||||
return;
|
||||
|
||||
GstD3D12CommandAllocator *gst_ca = nullptr;
|
||||
gst_d3d12_command_allocator_pool_acquire (priv->direct_ca_pool, &gst_ca);
|
||||
if (!gst_ca)
|
||||
return;
|
||||
|
||||
ComPtr < ID3D12CommandAllocator > ca;
|
||||
gst_d3d12_command_allocator_get_handle (gst_ca, &ca);
|
||||
|
||||
GstD3D12CommandList *gst_cl = nullptr;
|
||||
gst_d3d12_command_list_pool_acquire (priv->direct_cl_pool,
|
||||
ca.Get (), &gst_cl);
|
||||
if (!gst_cl) {
|
||||
gst_d3d12_command_allocator_unref (gst_ca);
|
||||
return;
|
||||
}
|
||||
|
||||
ComPtr < ID3D12CommandList > cl_base;
|
||||
ComPtr < ID3D12GraphicsCommandList > cl;
|
||||
|
||||
gst_d3d12_command_list_get_handle (gst_cl, &cl_base);
|
||||
cl_base.As (&cl);
|
||||
|
||||
auto rtv_handle =
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE (heap->GetCPUDescriptorHandleForHeapStart
|
||||
(),
|
||||
priv->rtv_inc_size);
|
||||
|
||||
const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
cl->ClearRenderTargetView (rtv_handle, clear_color, 0, nullptr);
|
||||
|
||||
auto hr = cl->Close ();
|
||||
if (!gst_d3d12_result (hr, device)) {
|
||||
gst_clear_d3d12_command_list (&gst_cl);
|
||||
gst_clear_d3d12_command_allocator (&gst_ca);
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D12CommandList *cmd_list[] = { cl.Get () };
|
||||
guint64 fence_val = 0;
|
||||
hr = gst_d3d12_command_queue_execute_command_lists (priv->direct_queue,
|
||||
1, cmd_list, &fence_val);
|
||||
auto ret = gst_d3d12_result (hr, device);
|
||||
gst_d3d12_command_list_unref (gst_cl);
|
||||
|
||||
if (ret) {
|
||||
gst_d3d12_command_queue_set_notify (priv->direct_queue, fence_val,
|
||||
gst_ca, (GDestroyNotify) gst_d3d12_command_allocator_unref);
|
||||
dmem->fence_value = fence_val;
|
||||
} else {
|
||||
gst_d3d12_command_allocator_unref (gst_ca);
|
||||
}
|
||||
}
|
||||
|
|
333
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dpbstorage.cpp
Normal file
333
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dpbstorage.cpp
Normal file
|
@ -0,0 +1,333 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstd3d12dpbstorage.h"
|
||||
#include <wrl.h>
|
||||
#include <vector>
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_d3d12_dpb_storage_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d12_dpb_storage_debug
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct OwnedTexture
|
||||
{
|
||||
ComPtr<ID3D12Resource> texture;
|
||||
guint subresource = 0;
|
||||
gboolean is_free = TRUE;
|
||||
};
|
||||
|
||||
struct GstD3D12DpbStoragePrivate
|
||||
{
|
||||
gboolean array_of_textures;
|
||||
DXGI_FORMAT format;
|
||||
guint width;
|
||||
guint height;
|
||||
D3D12_RESOURCE_FLAGS resource_flags;
|
||||
std::vector<ID3D12Resource *> dpb;
|
||||
std::vector<guint> dpb_subresource;
|
||||
std::vector<OwnedTexture> pool;
|
||||
ComPtr<ID3D12Resource> base_texture;
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
struct _GstD3D12DpbStorage
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstD3D12Device *device;
|
||||
GstD3D12DpbStoragePrivate *priv;
|
||||
};
|
||||
|
||||
static void gst_d3d12_dpb_storage_finalize (GObject * object);
|
||||
|
||||
#define gst_d3d12_dpb_storage_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D12DpbStorage, gst_d3d12_dpb_storage, GST_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_d3d12_dpb_storage_class_init (GstD3D12DpbStorageClass * klass)
|
||||
{
|
||||
auto object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gst_d3d12_dpb_storage_finalize;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_d3d12_dpb_storage_debug, "d3d12dpbstorage", 0,
|
||||
"d3d12dpbstorage");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_dpb_storage_init (GstD3D12DpbStorage * self)
|
||||
{
|
||||
self->priv = new GstD3D12DpbStoragePrivate ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_dpb_storage_finalize (GObject * object)
|
||||
{
|
||||
auto self = GST_D3D12_DPB_STORAGE (object);
|
||||
|
||||
delete self->priv;
|
||||
gst_clear_object (&self->device);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
allocate_texture (ID3D12Device * device, DXGI_FORMAT format, guint width,
|
||||
guint height, D3D12_RESOURCE_FLAGS resource_flags, guint array_size,
|
||||
ID3D12Resource ** texture)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES prop =
|
||||
CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT);
|
||||
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D (format,
|
||||
width, height, array_size, 1, 1, 0, resource_flags);
|
||||
|
||||
return device->CreateCommittedResource (&prop, D3D12_HEAP_FLAG_NONE,
|
||||
&desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS (texture));
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_dpb_storage_acquire_frame (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE * frame)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), FALSE);
|
||||
g_return_val_if_fail (frame, FALSE);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
for (size_t i = 0; i < priv->pool.size (); i++) {
|
||||
auto & it = priv->pool[i];
|
||||
if (it.is_free) {
|
||||
frame->pReconstructedPicture = it.texture.Get ();
|
||||
frame->ReconstructedPictureSubresource = it.subresource;
|
||||
it.is_free = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priv->array_of_textures) {
|
||||
GST_ERROR_OBJECT (storage, "No available free texture");
|
||||
frame->pReconstructedPicture = nullptr;
|
||||
frame->ReconstructedPictureSubresource = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
auto device = gst_d3d12_device_get_device_handle (storage->device);
|
||||
|
||||
OwnedTexture new_texture;
|
||||
new_texture.is_free = FALSE;
|
||||
HRESULT hr = allocate_texture (device, priv->format, priv->width,
|
||||
priv->height, priv->resource_flags, 1, &new_texture.texture);
|
||||
|
||||
if (!gst_d3d12_result (hr, storage->device)) {
|
||||
GST_ERROR_OBJECT (storage, "Couldn't allocate texture");
|
||||
frame->pReconstructedPicture = nullptr;
|
||||
frame->ReconstructedPictureSubresource = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
frame->pReconstructedPicture = new_texture.texture.Get ();
|
||||
frame->ReconstructedPictureSubresource = 0;
|
||||
|
||||
priv->pool.push_back (new_texture);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_dpb_storage_add_frame (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE * frame)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), FALSE);
|
||||
g_return_val_if_fail (frame, FALSE);
|
||||
g_return_val_if_fail (frame->pReconstructedPicture, FALSE);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
priv->dpb.insert (priv->dpb.begin (), frame->pReconstructedPicture);
|
||||
priv->dpb_subresource.insert (priv->dpb_subresource.begin (),
|
||||
frame->ReconstructedPictureSubresource);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_dpb_storage_get_reference_frames (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES * ref_frames)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), FALSE);
|
||||
g_return_val_if_fail (ref_frames, FALSE);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
ref_frames->NumTexture2Ds = priv->dpb.size ();
|
||||
ref_frames->ppTexture2Ds = priv->dpb.data ();
|
||||
if (priv->array_of_textures)
|
||||
ref_frames->pSubresources = nullptr;
|
||||
else
|
||||
ref_frames->pSubresources = priv->dpb_subresource.data ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_dpb_storage_release_frame (GstD3D12DpbStorage * self,
|
||||
ID3D12Resource * texture, guint subresource)
|
||||
{
|
||||
auto priv = self->priv;
|
||||
|
||||
if (priv->array_of_textures) {
|
||||
for (size_t i = 0; i < priv->pool.size (); i++) {
|
||||
auto & it = priv->pool[i];
|
||||
if (texture == it.texture.Get () && it.subresource == subresource) {
|
||||
it.is_free = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
} else {
|
||||
g_return_if_fail (subresource < priv->pool.size ());
|
||||
|
||||
priv->pool[subresource].is_free = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_dpb_storage_remove_oldest_frame (GstD3D12DpbStorage * storage)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), FALSE);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
if (priv->dpb.empty ()) {
|
||||
GST_WARNING_OBJECT (storage, "DPB is empty now");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_d3d12_dpb_storage_release_frame (storage,
|
||||
priv->dpb.back (), priv->dpb_subresource.back ());
|
||||
|
||||
priv->dpb.pop_back ();
|
||||
priv->dpb_subresource.pop_back ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d12_dpb_storage_clear_dpb (GstD3D12DpbStorage * storage)
|
||||
{
|
||||
g_return_if_fail (GST_IS_D3D12_DPB_STORAGE (storage));
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
g_assert (priv->dpb.size () == priv->dpb_subresource.size ());
|
||||
|
||||
for (size_t i = 0; i < priv->dpb.size (); i++) {
|
||||
gst_d3d12_dpb_storage_release_frame (storage,
|
||||
priv->dpb[i], priv->dpb_subresource[i]);
|
||||
}
|
||||
|
||||
priv->dpb.clear ();
|
||||
priv->dpb_subresource.clear ();
|
||||
}
|
||||
|
||||
guint
|
||||
gst_d3d12_dpb_storage_get_dpb_size (GstD3D12DpbStorage * storage)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), 0);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
return priv->dpb.size ();
|
||||
}
|
||||
|
||||
guint
|
||||
gst_d3d12_dpb_storage_get_pool_size (GstD3D12DpbStorage * storage)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DPB_STORAGE (storage), 0);
|
||||
|
||||
auto priv = storage->priv;
|
||||
|
||||
return priv->pool.size ();
|
||||
}
|
||||
|
||||
GstD3D12DpbStorage *
|
||||
gst_d3d12_dpb_storage_new (GstD3D12Device * device, guint dpb_size,
|
||||
gboolean use_array_of_textures, DXGI_FORMAT format, guint width,
|
||||
guint height, D3D12_RESOURCE_FLAGS resource_flags)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
|
||||
|
||||
auto self = (GstD3D12DpbStorage *)
|
||||
g_object_new (GST_TYPE_D3D12_DPB_STORAGE, nullptr);
|
||||
gst_object_ref_sink (self);
|
||||
|
||||
self->device = (GstD3D12Device *) gst_object_ref (device);
|
||||
auto priv = self->priv;
|
||||
auto device_handle = gst_d3d12_device_get_device_handle (device);
|
||||
HRESULT hr;
|
||||
|
||||
if (use_array_of_textures) {
|
||||
for (guint i = 0; i < dpb_size; i++) {
|
||||
OwnedTexture texture;
|
||||
|
||||
hr = allocate_texture (device_handle,
|
||||
format, width, height, resource_flags, 1, &texture.texture);
|
||||
if (!gst_d3d12_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't allocate initial texture");
|
||||
gst_object_unref (self);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
priv->pool.push_back (texture);
|
||||
}
|
||||
} else {
|
||||
hr = allocate_texture (device_handle,
|
||||
format, width, height, resource_flags, dpb_size, &priv->base_texture);
|
||||
|
||||
if (!gst_d3d12_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't allocate initial texture");
|
||||
gst_object_unref (self);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
priv->pool.resize (dpb_size);
|
||||
|
||||
for (guint i = 0; i < dpb_size; i++) {
|
||||
priv->pool[i].texture = priv->base_texture;
|
||||
priv->pool[i].subresource = i;
|
||||
}
|
||||
}
|
||||
|
||||
priv->width = width;
|
||||
priv->height = height;
|
||||
priv->resource_flags = resource_flags;
|
||||
priv->array_of_textures = use_array_of_textures;
|
||||
priv->dpb.reserve (dpb_size);
|
||||
priv->dpb_subresource.reserve (dpb_size);
|
||||
|
||||
return self;
|
||||
}
|
57
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dpbstorage.h
Normal file
57
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12dpbstorage.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* 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 "gstd3d12.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D12_DPB_STORAGE (gst_d3d12_dpb_storage_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstD3D12DpbStorage, gst_d3d12_dpb_storage,
|
||||
GST, D3D12_DPB_STORAGE, GstObject);
|
||||
|
||||
GstD3D12DpbStorage * gst_d3d12_dpb_storage_new (GstD3D12Device * device,
|
||||
guint dpb_size,
|
||||
gboolean use_array_of_textures,
|
||||
DXGI_FORMAT format,
|
||||
guint width,
|
||||
guint height,
|
||||
D3D12_RESOURCE_FLAGS resource_flags);
|
||||
|
||||
gboolean gst_d3d12_dpb_storage_acquire_frame (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE * frame);
|
||||
|
||||
gboolean gst_d3d12_dpb_storage_add_frame (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE * frame);
|
||||
|
||||
gboolean gst_d3d12_dpb_storage_get_reference_frames (GstD3D12DpbStorage * storage,
|
||||
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES * ref_frames);
|
||||
|
||||
gboolean gst_d3d12_dpb_storage_remove_oldest_frame (GstD3D12DpbStorage * storage);
|
||||
|
||||
void gst_d3d12_dpb_storage_clear_dpb (GstD3D12DpbStorage * storage);
|
||||
|
||||
guint gst_d3d12_dpb_storage_get_dpb_size (GstD3D12DpbStorage * storage);
|
||||
|
||||
guint gst_d3d12_dpb_storage_get_pool_size (GstD3D12DpbStorage * storage);
|
||||
|
||||
G_END_DECLS
|
1646
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12encoder.cpp
Normal file
1646
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12encoder.cpp
Normal file
File diff suppressed because it is too large
Load diff
119
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12encoder.h
Normal file
119
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12encoder.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2024 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 "gstd3d12.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER (gst_d3d12_encoder_get_type())
|
||||
#define GST_D3D12_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D12_ENCODER,GstD3D12Encoder))
|
||||
#define GST_D3D12_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_D3D12_ENCODER,GstD3D12EncoderClass))
|
||||
#define GST_D3D12_ENCODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_D3D12_ENCODER,GstD3D12EncoderClass))
|
||||
#define GST_IS_D3D12_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D12_ENCODER))
|
||||
#define GST_IS_D3D12_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D12_ENCODER))
|
||||
|
||||
struct GstD3D12EncoderPrivate;
|
||||
|
||||
struct GstD3D12EncoderConfig
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_PROFILE_DESC profile_desc;
|
||||
D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codec_config;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA layout;
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE gop_struct;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC resolution;
|
||||
D3D12_VIDEO_ENCODER_SUPPORT_FLAGS support_flags;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP cqp;;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR cbr;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR vbr;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR qvbr;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL rate_control;
|
||||
guint max_subregions;
|
||||
};
|
||||
|
||||
enum GstD3D12EncoderSeiInsertMode
|
||||
{
|
||||
GST_D3D12_ENCODER_SEI_INSERT,
|
||||
GST_D3D12_ENCODER_SEI_INSERT_AND_DROP,
|
||||
GST_D3D12_ENCODER_SEI_DISABLED,
|
||||
};
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_RATE_CONTROL (gst_d3d12_encoder_rate_control_get_type ())
|
||||
GType gst_d3d12_encoder_rate_control_get_type (void);
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_RATE_CONTROL_SUPPORT (gst_d3d12_encoder_rate_control_support_get_type ())
|
||||
GType gst_d3d12_encoder_rate_control_support_get_type (void);
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_SUBREGION_LAYOUT (gst_d3d12_encoder_subregion_layout_get_type())
|
||||
GType gst_d3d12_encoder_subregion_layout_get_type (void);
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_SUBREGION_LAYOUT_SUPPORT (gst_d3d12_encoder_subregion_layout_support_get_type ())
|
||||
GType gst_d3d12_encoder_subregion_layout_support_get_type (void);
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_SEI_INSERT_MODE (gst_d3d12_encoder_sei_insert_mode_get_type ())
|
||||
GType gst_d3d12_encoder_sei_insert_mode_get_type (void);
|
||||
|
||||
struct GstD3D12Encoder
|
||||
{
|
||||
GstVideoEncoder parent;
|
||||
|
||||
GstD3D12Device *device;
|
||||
|
||||
GstD3D12EncoderPrivate *priv;
|
||||
};
|
||||
|
||||
struct GstD3D12EncoderClass
|
||||
{
|
||||
GstVideoEncoderClass parent_class;
|
||||
|
||||
D3D12_VIDEO_ENCODER_CODEC codec;
|
||||
gint64 adapter_luid;
|
||||
guint device_id;
|
||||
guint vendor_id;
|
||||
|
||||
gboolean (*new_sequence) (GstD3D12Encoder * encoder,
|
||||
ID3D12VideoDevice * video_device,
|
||||
GstVideoCodecState * state,
|
||||
GstD3D12EncoderConfig * config);
|
||||
|
||||
gboolean (*start_frame) (GstD3D12Encoder * encoder,
|
||||
ID3D12VideoDevice * video_device,
|
||||
GstVideoCodecFrame * frame,
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC * seq_ctrl,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_DESC * picture_ctrl,
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE * recon_pic,
|
||||
GstD3D12EncoderConfig * config,
|
||||
gboolean * need_new_session);
|
||||
|
||||
gboolean (*end_frame) (GstD3D12Encoder * encoder);
|
||||
};
|
||||
|
||||
GType gst_d3d12_encoder_get_type (void);
|
||||
|
||||
gboolean gst_d3d12_encoder_check_needs_new_session (D3D12_VIDEO_ENCODER_SUPPORT_FLAGS support_flags,
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS seq_flags);
|
||||
|
||||
#define CHECK_SUPPORT_FLAG(flags, f) \
|
||||
((flags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_ ##f) != 0)
|
||||
|
||||
G_END_DECLS
|
|
@ -0,0 +1,326 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2024 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you cln 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstd3d12encoderbufferpool.h"
|
||||
#include <directx/d3dx12.h>
|
||||
#include <wrl.h>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_d3d12_encoder_buffer_pool_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d12_encoder_buffer_pool_debug
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct _GstD3D12EncoderBuffer : public GstMiniObject
|
||||
{
|
||||
GstD3D12EncoderBufferPool *pool = nullptr;
|
||||
ComPtr<ID3D12Resource> metadata;
|
||||
ComPtr<ID3D12Resource> resolved_metadata;
|
||||
ComPtr<ID3D12Resource> bitstream;
|
||||
};
|
||||
|
||||
struct GstD3D12EncoderBufferPoolPrivate
|
||||
{
|
||||
~GstD3D12EncoderBufferPoolPrivate ()
|
||||
{
|
||||
while (!buffer_pool.empty ()) {
|
||||
auto buf = buffer_pool.front ();
|
||||
buffer_pool.pop ();
|
||||
gst_mini_object_unref (buf);
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Device> device;
|
||||
|
||||
std::mutex lock;
|
||||
std::condition_variable cond;
|
||||
std::queue<GstD3D12EncoderBuffer *>buffer_pool;
|
||||
|
||||
guint metadata_size;
|
||||
guint resolved_metadata_size;
|
||||
guint bitstream_size;
|
||||
guint pool_size;
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
struct _GstD3D12EncoderBufferPool
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstD3D12EncoderBufferPoolPrivate *priv;
|
||||
};
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstD3D12EncoderBuffer, gst_d3d12_encoder_buffer);
|
||||
|
||||
static void gst_d3d12_encoder_buffer_pool_finalize (GObject * object);
|
||||
|
||||
#define gst_d3d12_encoder_buffer_pool_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D12EncoderBufferPool,
|
||||
gst_d3d12_encoder_buffer_pool, GST_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_d3d12_encoder_buffer_pool_class_init (GstD3D12EncoderBufferPoolClass *
|
||||
klass)
|
||||
{
|
||||
auto object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gst_d3d12_encoder_buffer_pool_finalize;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_d3d12_encoder_buffer_pool_debug,
|
||||
"d3d12encoderbufferpool", 0, "d3d12encoderbufferpool");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_encoder_buffer_pool_init (GstD3D12EncoderBufferPool * self)
|
||||
{
|
||||
self->priv = new GstD3D12EncoderBufferPoolPrivate ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_encoder_buffer_pool_finalize (GObject * object)
|
||||
{
|
||||
auto self = GST_D3D12_ENCODER_BUFFER_POOL (object);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Finalize");
|
||||
|
||||
delete self->priv;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_encoder_buffer_free (GstD3D12EncoderBuffer * buffer)
|
||||
{
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
static GstD3D12EncoderBuffer *
|
||||
gst_d3d12_encoder_buffer_pool_alloc (GstD3D12EncoderBufferPool * self)
|
||||
{
|
||||
auto priv = self->priv;
|
||||
D3D12_HEAP_PROPERTIES prop =
|
||||
CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT);
|
||||
D3D12_RESOURCE_DESC desc =
|
||||
CD3DX12_RESOURCE_DESC::Buffer (priv->metadata_size);
|
||||
|
||||
ComPtr < ID3D12Resource > metadata;
|
||||
auto hr = priv->device->CreateCommittedResource (&prop,
|
||||
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
|
||||
nullptr, IID_PPV_ARGS (&metadata));
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't metadata buffer, hr: 0x%x", (guint) hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prop = CD3DX12_HEAP_PROPERTIES (D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
||||
D3D12_MEMORY_POOL_L0);
|
||||
desc = CD3DX12_RESOURCE_DESC::Buffer (priv->resolved_metadata_size);
|
||||
ComPtr < ID3D12Resource > resolved_metadata;
|
||||
hr = priv->device->CreateCommittedResource (&prop,
|
||||
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
|
||||
nullptr, IID_PPV_ARGS (&resolved_metadata));
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't metadata buffer, hr: 0x%x", (guint) hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
desc = CD3DX12_RESOURCE_DESC::Buffer (priv->bitstream_size);
|
||||
ComPtr < ID3D12Resource > bitstream;
|
||||
hr = priv->device->CreateCommittedResource (&prop,
|
||||
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
|
||||
nullptr, IID_PPV_ARGS (&bitstream));
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't metadata buffer, hr: 0x%x", (guint) hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto new_buf = new GstD3D12EncoderBuffer ();
|
||||
|
||||
gst_mini_object_init (new_buf, 0, gst_d3d12_encoder_buffer_get_type (),
|
||||
nullptr, nullptr,
|
||||
(GstMiniObjectFreeFunction) gst_d3d12_encoder_buffer_free);
|
||||
new_buf->metadata = metadata;
|
||||
new_buf->resolved_metadata = resolved_metadata;
|
||||
new_buf->bitstream = bitstream;
|
||||
|
||||
return new_buf;
|
||||
}
|
||||
|
||||
GstD3D12EncoderBufferPool *
|
||||
gst_d3d12_encoder_buffer_pool_new (GstD3D12Device * device,
|
||||
guint metadata_size, guint resolved_metadata_size, guint bitstream_size,
|
||||
guint pool_size)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
|
||||
|
||||
auto self = (GstD3D12EncoderBufferPool *)
|
||||
g_object_new (GST_TYPE_D3D12_ENCODER_BUFFER_POOL, nullptr);
|
||||
gst_object_ref_sink (self);
|
||||
|
||||
auto priv = self->priv;
|
||||
priv->device = gst_d3d12_device_get_device_handle (device);;
|
||||
priv->metadata_size = metadata_size;
|
||||
priv->resolved_metadata_size = resolved_metadata_size;
|
||||
priv->bitstream_size = bitstream_size;
|
||||
priv->pool_size = pool_size;
|
||||
|
||||
for (guint i = 0; i < pool_size; i++) {
|
||||
auto new_buf = gst_d3d12_encoder_buffer_pool_alloc (self);
|
||||
if (!new_buf) {
|
||||
gst_object_unref (self);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
priv->buffer_pool.push (new_buf);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d12_encoder_buffer_pool_release (GstD3D12EncoderBufferPool * pool,
|
||||
GstD3D12EncoderBuffer * buffer)
|
||||
{
|
||||
auto priv = pool->priv;
|
||||
{
|
||||
std::lock_guard < std::mutex > lk (priv->lock);
|
||||
buffer->dispose = nullptr;
|
||||
buffer->pool = nullptr;
|
||||
priv->buffer_pool.push (buffer);
|
||||
priv->cond.notify_one ();
|
||||
}
|
||||
|
||||
gst_object_unref (pool);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d12_encoder_buffer_dispose (GstD3D12EncoderBuffer * buffer)
|
||||
{
|
||||
if (!buffer->pool)
|
||||
return TRUE;
|
||||
|
||||
gst_mini_object_ref (buffer);
|
||||
gst_d3d12_encoder_buffer_pool_release (buffer->pool, buffer);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_encoder_buffer_pool_acquire (GstD3D12EncoderBufferPool * pool,
|
||||
GstD3D12EncoderBuffer ** buffer)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_ENCODER_BUFFER_POOL (pool), FALSE);
|
||||
g_return_val_if_fail (buffer, FALSE);
|
||||
|
||||
*buffer = nullptr;
|
||||
|
||||
auto priv = pool->priv;
|
||||
GstD3D12EncoderBuffer *new_buf = nullptr;
|
||||
|
||||
{
|
||||
std::unique_lock < std::mutex > lk (priv->lock);
|
||||
if (priv->pool_size > 0) {
|
||||
while (priv->buffer_pool.empty ())
|
||||
priv->cond.wait (lk);
|
||||
}
|
||||
|
||||
if (!priv->buffer_pool.empty ()) {
|
||||
new_buf = priv->buffer_pool.front ();
|
||||
priv->buffer_pool.pop ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!new_buf)
|
||||
new_buf = gst_d3d12_encoder_buffer_pool_alloc (pool);
|
||||
|
||||
if (!new_buf)
|
||||
return FALSE;
|
||||
|
||||
new_buf->pool = (GstD3D12EncoderBufferPool *) gst_object_ref (pool);
|
||||
new_buf->dispose =
|
||||
(GstMiniObjectDisposeFunction) gst_d3d12_encoder_buffer_dispose;
|
||||
|
||||
*buffer = new_buf;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstD3D12EncoderBuffer *
|
||||
gst_d3d12_encoder_buffer_ref (GstD3D12EncoderBuffer * buffer)
|
||||
{
|
||||
return (GstD3D12EncoderBuffer *) gst_mini_object_ref (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d12_encoder_buffer_unref (GstD3D12EncoderBuffer * buffer)
|
||||
{
|
||||
gst_mini_object_unref (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
gst_clear_d3d12_encoder_buffer (GstD3D12EncoderBuffer ** buffer)
|
||||
{
|
||||
gst_clear_mini_object (buffer);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_encoder_buffer_get_metadata (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** metadata)
|
||||
{
|
||||
g_return_val_if_fail (buffer, FALSE);
|
||||
g_return_val_if_fail (metadata, FALSE);
|
||||
|
||||
*metadata = buffer->metadata.Get ();
|
||||
(*metadata)->AddRef ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_encoder_buffer_get_resolved_metadata (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** resolved_metadata)
|
||||
{
|
||||
g_return_val_if_fail (buffer, FALSE);
|
||||
g_return_val_if_fail (resolved_metadata, FALSE);
|
||||
|
||||
*resolved_metadata = buffer->resolved_metadata.Get ();
|
||||
(*resolved_metadata)->AddRef ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_encoder_buffer_get_bitstream (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** bitstream)
|
||||
{
|
||||
g_return_val_if_fail (buffer, FALSE);
|
||||
g_return_val_if_fail (bitstream, FALSE);
|
||||
|
||||
*bitstream = buffer->bitstream.Get ();
|
||||
(*bitstream)->AddRef ();
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2024 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 "gstd3d12.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D12_ENCODER_BUFFER_POOL (gst_d3d12_encoder_buffer_pool_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstD3D12EncoderBufferPool,
|
||||
gst_d3d12_encoder_buffer_pool, GST, D3D12_ENCODER_BUFFER_POOL, GstObject);
|
||||
|
||||
typedef struct _GstD3D12EncoderBuffer GstD3D12EncoderBuffer;
|
||||
|
||||
GstD3D12EncoderBufferPool * gst_d3d12_encoder_buffer_pool_new (GstD3D12Device * device,
|
||||
guint metadata_size,
|
||||
guint resolved_metadata_size,
|
||||
guint bitstream_size,
|
||||
guint pool_size);
|
||||
|
||||
gboolean gst_d3d12_encoder_buffer_pool_acquire (GstD3D12EncoderBufferPool * pool,
|
||||
GstD3D12EncoderBuffer ** buffer);
|
||||
|
||||
GstD3D12EncoderBuffer * gst_d3d12_encoder_buffer_ref (GstD3D12EncoderBuffer * buffer);
|
||||
|
||||
void gst_d3d12_encoder_buffer_unref (GstD3D12EncoderBuffer * buffer);
|
||||
|
||||
void gst_clear_d3d12_encoder_buffer (GstD3D12EncoderBuffer ** buffer);
|
||||
|
||||
gboolean gst_d3d12_encoder_buffer_get_metadata (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** metadata);
|
||||
|
||||
gboolean gst_d3d12_encoder_buffer_get_resolved_metadata (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** resolved_metadata);
|
||||
|
||||
gboolean gst_d3d12_encoder_buffer_get_bitstream (GstD3D12EncoderBuffer * buffer,
|
||||
ID3D12Resource ** bitstream);
|
||||
|
||||
G_END_DECLS
|
||||
|
2482
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264enc.cpp
Normal file
2482
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264enc.cpp
Normal file
File diff suppressed because it is too large
Load diff
33
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264enc.h
Normal file
33
subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264enc.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2024 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 "gstd3d12.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gst_d3d12_h264_enc_register (GstPlugin * plugin,
|
||||
GstD3D12Device * device,
|
||||
ID3D12VideoDevice * video_device,
|
||||
guint rank);
|
||||
|
||||
G_END_DECLS
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "gstd3d12.h"
|
||||
#include "gstd3d12memory-private.h"
|
||||
#include "gstd3d12-private.h"
|
||||
#include <directx/d3dx12.h>
|
||||
#include <string.h>
|
||||
#include <wrl.h>
|
||||
|
@ -774,7 +775,20 @@ gst_d3d12_allocator_alloc_internal (GstD3D12Allocator * self,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return gst_d3d12_allocator_alloc_wrapped (self, device, resource.Get (), 0);
|
||||
auto mem =
|
||||
gst_d3d12_allocator_alloc_wrapped (self, device, resource.Get (), 0);
|
||||
if (!mem)
|
||||
return nullptr;
|
||||
|
||||
/* Initialize YUV texture with black color */
|
||||
if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
|
||||
(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0 &&
|
||||
(heap_flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) == 0 &&
|
||||
desc->DepthOrArraySize == 1) {
|
||||
gst_d3d12_device_clear_yuv_texture (device, mem);
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
GstMemory *
|
||||
|
|
|
@ -14,10 +14,14 @@ d3d12_sources = [
|
|||
'gstd3d12descriptorpool.cpp',
|
||||
'gstd3d12device.cpp',
|
||||
'gstd3d12download.cpp',
|
||||
'gstd3d12dpbstorage.cpp',
|
||||
'gstd3d12dxgicapture.cpp',
|
||||
'gstd3d12encoder.cpp',
|
||||
'gstd3d12encoderbufferpool.cpp',
|
||||
'gstd3d12fencedatapool.cpp',
|
||||
'gstd3d12format.cpp',
|
||||
'gstd3d12h264dec.cpp',
|
||||
'gstd3d12h264enc.cpp',
|
||||
'gstd3d12h265dec.cpp',
|
||||
'gstd3d12memory.cpp',
|
||||
'gstd3d12overlaycompositor.cpp',
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "gstd3d12screencapturedevice.h"
|
||||
#include "gstd3d12screencapturesrc.h"
|
||||
#include "gstd3d12h264dec.h"
|
||||
#include "gstd3d12h264enc.h"
|
||||
#include "gstd3d12h265dec.h"
|
||||
#include "gstd3d12vp9dec.h"
|
||||
#include "gstd3d12av1dec.h"
|
||||
|
@ -106,6 +107,9 @@ plugin_init (GstPlugin * plugin)
|
|||
gst_d3d12_av1_dec_register (plugin, device, video_device.Get (),
|
||||
GST_RANK_NONE);
|
||||
|
||||
gst_d3d12_h264_enc_register (plugin, device, video_device.Get (),
|
||||
GST_RANK_NONE);
|
||||
|
||||
gst_object_unref (device);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,508 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <stdlib.h>
|
||||
#include "../key-handler.h"
|
||||
|
||||
static gchar *rc_modes[] = {
|
||||
"cqp", "cbr", "vbr", "qvbr"
|
||||
};
|
||||
|
||||
static gchar *slice_modes[] = {
|
||||
"full", "subregions"
|
||||
};
|
||||
|
||||
static GMainLoop *loop = NULL;
|
||||
static gint width = 640;
|
||||
static gint height = 480;
|
||||
static guint bitrate = 1000;
|
||||
static guint max_bitrate = 2000;
|
||||
static guint rc_index = 0;
|
||||
static guint qp_i = 24;
|
||||
static guint qp_p = 24;
|
||||
static guint qp_b = 24;
|
||||
static guint max_qp = 51;
|
||||
static guint gop_size = 30;
|
||||
static guint ref_frames = 0;
|
||||
static guint slice_mode_index = 0;
|
||||
static guint num_slices = 2;
|
||||
|
||||
#define BITRATE_STEP 100
|
||||
|
||||
G_LOCK_DEFINE_STATIC (input_lock);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *capsfilter;
|
||||
GstElement *encoder;
|
||||
gulong probe_id;
|
||||
|
||||
gint prev_width;
|
||||
gint prev_height;
|
||||
} TestCallbackData;
|
||||
|
||||
static void
|
||||
print_keyboard_help (void)
|
||||
{
|
||||
/* *INDENT-OFF* */
|
||||
static struct
|
||||
{
|
||||
const gchar *key_desc;
|
||||
const gchar *key_help;
|
||||
} key_controls[] = {
|
||||
{
|
||||
"q", "Quit"}, {
|
||||
"right arrow", "Increase Width"}, {
|
||||
"left arrow", "Decrease Width"}, {
|
||||
"up arrow", "Increase Height"}, {
|
||||
"down arrow", "Decrease Height"}, {
|
||||
"f", "Sends force keyunit event"}, {
|
||||
"]", "Increase bitrate by 100 kbps"}, {
|
||||
"[", "Decrease bitrate by 100 kbps"}, {
|
||||
"}", "Increase max-bitrate by 100 kbps"}, {
|
||||
"{", "Decrease max-bitrate by 100 kbps"}, {
|
||||
"r", "Toggle rate-control mode"}, {
|
||||
"<", "Decrease GOP size"}, {
|
||||
">", "Increase GOP size"}, {
|
||||
"+", "Incrase ref-frames"}, {
|
||||
"-", "Decrase ref-frames"}, {
|
||||
"I", "Increase QP-I"}, {
|
||||
"i", "Decrease QP-I"}, {
|
||||
"P", "Increase QP-P"}, {
|
||||
"p", "Decrease QP-P"}, {
|
||||
"m", "Toggle slice mode"}, {
|
||||
"S", "Incrase number of slices"}, {
|
||||
"s", "Decrease number of slices"}, {
|
||||
"k", "show keyboard shortcuts"}
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
guint i, chars_to_pad, desc_len, max_desc_len = 0;
|
||||
|
||||
gst_print ("\n\n%s\n\n", "Keyboard controls:");
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
|
||||
desc_len = g_utf8_strlen (key_controls[i].key_desc, -1);
|
||||
max_desc_len = MAX (max_desc_len, desc_len);
|
||||
}
|
||||
++max_desc_len;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
|
||||
chars_to_pad = max_desc_len - g_utf8_strlen (key_controls[i].key_desc, -1);
|
||||
gst_print ("\t%s", key_controls[i].key_desc);
|
||||
gst_print ("%-*s: ", chars_to_pad, "");
|
||||
gst_print ("%s\n", key_controls[i].key_help);
|
||||
}
|
||||
gst_print ("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_cb (gchar input, gboolean is_ascii, gpointer user_data)
|
||||
{
|
||||
TestCallbackData *data = (TestCallbackData *) user_data;
|
||||
|
||||
G_LOCK (input_lock);
|
||||
|
||||
if (!is_ascii) {
|
||||
switch (input) {
|
||||
case KB_ARROW_UP:
|
||||
height += 2;
|
||||
gst_println ("Increase height to %d", height);
|
||||
break;
|
||||
case KB_ARROW_DOWN:
|
||||
height -= 2;
|
||||
height = MAX (height, 16);
|
||||
gst_println ("Decrease height to %d", height);
|
||||
break;
|
||||
case KB_ARROW_LEFT:
|
||||
width -= 2;
|
||||
width = MAX (width, 16);
|
||||
gst_println ("Decrease width to %d", width);
|
||||
break;
|
||||
case KB_ARROW_RIGHT:
|
||||
width += 2;
|
||||
gst_println ("Increase width to %d", width);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (input) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
print_keyboard_help ();
|
||||
break;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
gst_element_send_event (data->pipeline, gst_event_new_eos ());
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
case 'f':
|
||||
{
|
||||
GstEvent *event =
|
||||
gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
|
||||
TRUE, 0);
|
||||
gst_println ("Sending force keyunit event");
|
||||
gst_element_send_event (data->encoder, event);
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
if (bitrate < G_MAXUINT64 - BITRATE_STEP) {
|
||||
bitrate += BITRATE_STEP;
|
||||
max_bitrate = MAX (max_bitrate, bitrate);
|
||||
gst_println ("Increase bitrate to %" G_GUINT64_FORMAT, bitrate);
|
||||
g_object_set (data->encoder, "bitrate", bitrate, "max-bitrate",
|
||||
max_bitrate, NULL);
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
if (bitrate > 2 * BITRATE_STEP) {
|
||||
bitrate -= BITRATE_STEP;
|
||||
gst_println ("Decrease bitrate to %" G_GUINT64_FORMAT, bitrate);
|
||||
g_object_set (data->encoder, "bitrate", bitrate, NULL);
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
if (max_bitrate < G_MAXUINT64 - BITRATE_STEP) {
|
||||
max_bitrate += BITRATE_STEP;
|
||||
gst_println ("Increase max bitrate to %" G_GUINT64_FORMAT,
|
||||
max_bitrate);
|
||||
g_object_set (data->encoder, "max-bitrate", max_bitrate, NULL);
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
if (max_bitrate > 2 * BITRATE_STEP) {
|
||||
max_bitrate -= BITRATE_STEP;
|
||||
bitrate = MAX (bitrate, max_bitrate);
|
||||
gst_println ("Decrease max bitrate to %" G_GUINT64_FORMAT,
|
||||
max_bitrate);
|
||||
g_object_set (data->encoder, "bitrate", bitrate, "max-bitrate",
|
||||
max_bitrate, NULL);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
rc_index++;
|
||||
rc_index %= G_N_ELEMENTS (rc_modes);
|
||||
gst_println ("Change rate control mode to %s", rc_modes[rc_index]);
|
||||
gst_util_set_object_arg (G_OBJECT (data->encoder), "rate-control",
|
||||
rc_modes[rc_index]);
|
||||
break;
|
||||
case '<':
|
||||
gop_size--;
|
||||
gst_println ("Updating GOP size to %u", gop_size);
|
||||
g_object_set (data->encoder, "gop-size", gop_size, NULL);
|
||||
break;
|
||||
case '>':
|
||||
gop_size++;
|
||||
gst_println ("Updating GOP size to %u", gop_size);
|
||||
g_object_set (data->encoder, "gop-size", gop_size, NULL);
|
||||
break;
|
||||
case '+':
|
||||
ref_frames++;
|
||||
ref_frames %= 17;
|
||||
gst_println ("Updating ref frames to %u", ref_frames);
|
||||
g_object_set (data->encoder, "ref-frames", ref_frames, NULL);
|
||||
break;
|
||||
case '-':
|
||||
ref_frames--;
|
||||
ref_frames %= 17;
|
||||
gst_println ("Updating ref frames to %u", ref_frames);
|
||||
g_object_set (data->encoder, "ref-frames", ref_frames, NULL);
|
||||
break;
|
||||
case 'I':
|
||||
qp_i++;
|
||||
qp_i %= 52;
|
||||
if (qp_i == 0)
|
||||
qp_i++;
|
||||
gst_println ("Updating QP-I to %d", qp_i);
|
||||
g_object_set (data->encoder, "qp-i", qp_i, NULL);
|
||||
break;
|
||||
case 'i':
|
||||
qp_i--;
|
||||
qp_i %= 52;
|
||||
if (qp_i == 0)
|
||||
qp_i = 51;
|
||||
gst_println ("Updating QP-I to %d", qp_i);
|
||||
g_object_set (data->encoder, "qp-i", qp_i, NULL);
|
||||
break;
|
||||
case 'P':
|
||||
qp_p++;
|
||||
qp_p %= 52;
|
||||
if (qp_p == 0)
|
||||
qp_p++;
|
||||
gst_println ("Updating QP-P to %d", qp_p);
|
||||
g_object_set (data->encoder, "qp-p", qp_p, NULL);
|
||||
break;
|
||||
case 'p':
|
||||
qp_p--;
|
||||
qp_p %= 52;
|
||||
if (qp_p == 0)
|
||||
qp_p = 51;
|
||||
gst_println ("Updating QP-P to %d", qp_i);
|
||||
g_object_set (data->encoder, "qp-p", qp_i, NULL);
|
||||
break;
|
||||
case 'm':
|
||||
slice_mode_index++;
|
||||
slice_mode_index %= G_N_ELEMENTS (slice_modes);
|
||||
gst_println ("Updating slice mode to %s",
|
||||
slice_modes[slice_mode_index]);
|
||||
gst_util_set_object_arg (G_OBJECT (data->encoder), "slice-mode",
|
||||
slice_modes[slice_mode_index]);
|
||||
break;
|
||||
case 'S':
|
||||
num_slices++;
|
||||
gst_println ("Updating slice partition to %u", num_slices);
|
||||
g_object_set (data->encoder, "slice-partition", num_slices, NULL);
|
||||
break;
|
||||
case 's':
|
||||
num_slices--;
|
||||
gst_println ("Updating slice partition to %u", num_slices);
|
||||
g_object_set (data->encoder, "slice-partition", num_slices, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
G_UNLOCK (input_lock);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
|
||||
{
|
||||
switch (GST_MESSAGE_TYPE (msg)) {
|
||||
case GST_MESSAGE_ERROR:{
|
||||
GError *err;
|
||||
gchar *dbg;
|
||||
|
||||
gst_message_parse_error (msg, &err, &dbg);
|
||||
gst_printerrln ("ERROR %s", err->message);
|
||||
if (dbg != NULL)
|
||||
gst_printerrln ("ERROR debug information: %s", dbg);
|
||||
g_clear_error (&err);
|
||||
g_free (dbg);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_encoder_available (const gchar * encoder_name)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
GstElement *elem;
|
||||
|
||||
elem = gst_element_factory_make (encoder_name, NULL);
|
||||
if (!elem) {
|
||||
gst_printerrln ("%s is not available", encoder_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gst_element_set_state (elem,
|
||||
GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
|
||||
gst_printerrln ("cannot open device");
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
gst_element_set_state (elem, GST_STATE_NULL);
|
||||
gst_object_unref (elem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstPadProbeReturn
|
||||
resolution_change_probe (GstPad * pad, GstPadProbeInfo * info,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstPadProbeReturn ret = GST_PAD_PROBE_OK;
|
||||
TestCallbackData *data = (TestCallbackData *) user_data;
|
||||
|
||||
G_LOCK (input_lock);
|
||||
|
||||
if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info))) {
|
||||
GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
|
||||
GstPad *peer = gst_pad_get_peer (pad);
|
||||
GstFlowReturn flow_ret = GST_FLOW_OK;
|
||||
|
||||
ret = GST_PAD_PROBE_HANDLED;
|
||||
|
||||
if (peer) {
|
||||
flow_ret = gst_pad_chain (peer, buffer);
|
||||
|
||||
if (flow_ret != GST_FLOW_OK) {
|
||||
gst_pad_remove_probe (pad, data->probe_id);
|
||||
data->probe_id = 0;
|
||||
} else {
|
||||
if (data->prev_width != width || data->prev_height != height) {
|
||||
GstCaps *caps = NULL;
|
||||
gint next_width, next_height;
|
||||
|
||||
next_width = width;
|
||||
next_height = height;
|
||||
|
||||
g_object_get (data->capsfilter, "caps", &caps, NULL);
|
||||
caps = gst_caps_make_writable (caps);
|
||||
gst_caps_set_simple (caps,
|
||||
"width", G_TYPE_INT, next_width, "height", G_TYPE_INT,
|
||||
next_height, NULL);
|
||||
g_object_set (data->capsfilter, "caps", caps, NULL);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
data->prev_width = next_width;
|
||||
data->prev_height = next_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
G_UNLOCK (input_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar ** argv)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *capsfilter, *enc, *enc_queue, *dec, *parser, *queue, *sink;
|
||||
GstStateChangeReturn sret;
|
||||
GError *error = NULL;
|
||||
GOptionContext *option_ctx;
|
||||
GstCaps *caps;
|
||||
TestCallbackData data = { 0, };
|
||||
GstPad *pad;
|
||||
gchar *encoder_name = NULL;
|
||||
/* *INDENT-OFF* */
|
||||
GOptionEntry options[] = {
|
||||
{"encoder", 0, 0, G_OPTION_ARG_STRING, &encoder_name,
|
||||
"Video encoder element to test, default: d3d12h264enc"},
|
||||
{NULL}
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#define MAKE_ELEMENT_AND_ADD(elem, name) G_STMT_START { \
|
||||
GstElement *_elem = gst_element_factory_make (name, NULL); \
|
||||
if (!_elem) { \
|
||||
gst_printerrln ("%s is not available", name); \
|
||||
exit (1); \
|
||||
} \
|
||||
gst_println ("Adding element %s", name); \
|
||||
elem = _elem; \
|
||||
gst_bin_add (GST_BIN (pipeline), elem); \
|
||||
} G_STMT_END
|
||||
|
||||
option_ctx =
|
||||
g_option_context_new ("d3d12 video encoder dynamic reconfigure example");
|
||||
g_option_context_add_main_entries (option_ctx, options, NULL);
|
||||
g_option_context_set_help_enabled (option_ctx, TRUE);
|
||||
if (!g_option_context_parse (option_ctx, &argc, &argv, &error)) {
|
||||
gst_printerrln ("option parsing failed: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_option_context_free (option_ctx);
|
||||
gst_init (NULL, NULL);
|
||||
|
||||
if (!encoder_name)
|
||||
encoder_name = g_strdup ("d3d12h264enc");
|
||||
|
||||
if (!check_encoder_available (encoder_name)) {
|
||||
gst_printerrln ("Cannot load %s plugin", encoder_name);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* prepare the pipeline */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
pipeline = gst_pipeline_new (NULL);
|
||||
|
||||
MAKE_ELEMENT_AND_ADD (src, "videotestsrc");
|
||||
g_object_set (src, "pattern", 1, "is-live", TRUE, NULL);
|
||||
|
||||
MAKE_ELEMENT_AND_ADD (capsfilter, "capsfilter");
|
||||
MAKE_ELEMENT_AND_ADD (enc, encoder_name);
|
||||
|
||||
g_object_set (enc, "bitrate", bitrate, "max-bitrate", max_bitrate,
|
||||
"qp-i", qp_i, "qp-p", qp_p, "gop-size", 30, NULL);
|
||||
|
||||
gst_util_set_object_arg (G_OBJECT (enc), "rate-control", rc_modes[rc_index]);
|
||||
|
||||
MAKE_ELEMENT_AND_ADD (enc_queue, "queue");
|
||||
MAKE_ELEMENT_AND_ADD (parser, "h264parse");
|
||||
MAKE_ELEMENT_AND_ADD (dec, "d3d12h264dec");
|
||||
MAKE_ELEMENT_AND_ADD (queue, "queue");
|
||||
MAKE_ELEMENT_AND_ADD (sink, "d3d12videosink");
|
||||
|
||||
if (!gst_element_link_many (src, capsfilter, enc, enc_queue,
|
||||
parser, dec, queue, sink, NULL)) {
|
||||
gst_printerrln ("Failed to link element");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
|
||||
width, "height", G_TYPE_INT, height, NULL);
|
||||
g_object_set (capsfilter, "caps", caps, NULL);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
data.pipeline = pipeline;
|
||||
data.capsfilter = capsfilter;
|
||||
data.encoder = enc;
|
||||
|
||||
pad = gst_element_get_static_pad (capsfilter, "src");
|
||||
data.probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
|
||||
(GstPadProbeCallback) resolution_change_probe, &data, NULL);
|
||||
gst_object_unref (pad);
|
||||
data.prev_width = width;
|
||||
data.prev_height = height;
|
||||
|
||||
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_msg, &data);
|
||||
|
||||
/* run the pipeline */
|
||||
sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (sret == GST_STATE_CHANGE_FAILURE) {
|
||||
gst_printerrln ("Pipeline doesn't want to playing\n");
|
||||
} else {
|
||||
set_key_handler ((KeyInputCallback) keyboard_cb, &data);
|
||||
g_main_loop_run (loop);
|
||||
unset_key_handler ();
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
|
||||
|
||||
gst_object_unref (pipeline);
|
||||
g_main_loop_unref (loop);
|
||||
g_free (encoder_name);
|
||||
|
||||
return 0;
|
||||
}
|
10
subprojects/gst-plugins-bad/tests/examples/d3d12/meson.build
Normal file
10
subprojects/gst-plugins-bad/tests/examples/d3d12/meson.build
Normal file
|
@ -0,0 +1,10 @@
|
|||
if host_system != 'windows'
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
executable('d3d12enc-dynamic-reconfigure',
|
||||
['d3d12enc-dynamic-reconfigure.c', '../key-handler.c'],
|
||||
include_directories : [configinc],
|
||||
dependencies: [gst_dep, gstbase_dep, gstvideo_dep],
|
||||
c_args : gst_plugins_bad_args,
|
||||
install: false)
|
|
@ -4,6 +4,7 @@ subdir('camerabin2')
|
|||
subdir('codecparsers')
|
||||
subdir('codecs')
|
||||
subdir('d3d11')
|
||||
subdir('d3d12')
|
||||
subdir('directfb')
|
||||
subdir('gtk')
|
||||
subdir('ipcpipeline')
|
||||
|
|
Loading…
Reference in a new issue