mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +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"
|
"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": {
|
"d3d12h265dec": {
|
||||||
"author": "Seungha Yang <seungha@centricualr.com>",
|
"author": "Seungha Yang <seungha@centricualr.com>",
|
||||||
"description": "Direct3D12/DXVA based H.265 video decoder",
|
"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": {
|
"GstD3D12MSAAMode": {
|
||||||
"kind": "enum",
|
"kind": "enum",
|
||||||
"values": [
|
"values": [
|
||||||
|
|
|
@ -188,3 +188,7 @@ static const GstD3D12Format g_gst_d3d12_default_format_map[] = {
|
||||||
#undef MAKE_FORMAT_MAP_RGBP
|
#undef MAKE_FORMAT_MAP_RGBP
|
||||||
|
|
||||||
#define GST_D3D12_N_FORMATS G_N_ELEMENTS(g_gst_d3d12_default_format_map)
|
#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.h"
|
||||||
#include "gstd3d12-private.h"
|
#include "gstd3d12-private.h"
|
||||||
#include "gstd3d11on12.h"
|
#include "gstd3d11on12.h"
|
||||||
|
#include <directx/d3dx12.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -143,6 +144,8 @@ struct _GstD3D12DevicePrivate
|
||||||
GstD3D12CommandListPool *copy_cl_pool = nullptr;
|
GstD3D12CommandListPool *copy_cl_pool = nullptr;
|
||||||
GstD3D12CommandAllocatorPool *copy_ca_pool = nullptr;
|
GstD3D12CommandAllocatorPool *copy_ca_pool = nullptr;
|
||||||
|
|
||||||
|
guint rtv_inc_size;
|
||||||
|
|
||||||
guint adapter_index = 0;
|
guint adapter_index = 0;
|
||||||
guint device_id = 0;
|
guint device_id = 0;
|
||||||
guint vendor_id = 0;
|
guint vendor_id = 0;
|
||||||
|
@ -649,6 +652,9 @@ gst_d3d12_device_new_internal (const GstD3D12DeviceConstructData * data)
|
||||||
if (!priv->copy_ca_pool)
|
if (!priv->copy_ca_pool)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
priv->rtv_inc_size =
|
||||||
|
device->GetDescriptorHandleIncrementSize (D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -1107,3 +1113,75 @@ gst_d3d12_device_d3d12_debug (GstD3D12Device * device, const gchar * file,
|
||||||
|
|
||||||
info_queue->ClearStoredMessages ();
|
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 "gstd3d12.h"
|
||||||
#include "gstd3d12memory-private.h"
|
#include "gstd3d12memory-private.h"
|
||||||
|
#include "gstd3d12-private.h"
|
||||||
#include <directx/d3dx12.h>
|
#include <directx/d3dx12.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
|
@ -774,7 +775,20 @@ gst_d3d12_allocator_alloc_internal (GstD3D12Allocator * self,
|
||||||
return nullptr;
|
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 *
|
GstMemory *
|
||||||
|
|
|
@ -14,10 +14,14 @@ d3d12_sources = [
|
||||||
'gstd3d12descriptorpool.cpp',
|
'gstd3d12descriptorpool.cpp',
|
||||||
'gstd3d12device.cpp',
|
'gstd3d12device.cpp',
|
||||||
'gstd3d12download.cpp',
|
'gstd3d12download.cpp',
|
||||||
|
'gstd3d12dpbstorage.cpp',
|
||||||
'gstd3d12dxgicapture.cpp',
|
'gstd3d12dxgicapture.cpp',
|
||||||
|
'gstd3d12encoder.cpp',
|
||||||
|
'gstd3d12encoderbufferpool.cpp',
|
||||||
'gstd3d12fencedatapool.cpp',
|
'gstd3d12fencedatapool.cpp',
|
||||||
'gstd3d12format.cpp',
|
'gstd3d12format.cpp',
|
||||||
'gstd3d12h264dec.cpp',
|
'gstd3d12h264dec.cpp',
|
||||||
|
'gstd3d12h264enc.cpp',
|
||||||
'gstd3d12h265dec.cpp',
|
'gstd3d12h265dec.cpp',
|
||||||
'gstd3d12memory.cpp',
|
'gstd3d12memory.cpp',
|
||||||
'gstd3d12overlaycompositor.cpp',
|
'gstd3d12overlaycompositor.cpp',
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "gstd3d12screencapturedevice.h"
|
#include "gstd3d12screencapturedevice.h"
|
||||||
#include "gstd3d12screencapturesrc.h"
|
#include "gstd3d12screencapturesrc.h"
|
||||||
#include "gstd3d12h264dec.h"
|
#include "gstd3d12h264dec.h"
|
||||||
|
#include "gstd3d12h264enc.h"
|
||||||
#include "gstd3d12h265dec.h"
|
#include "gstd3d12h265dec.h"
|
||||||
#include "gstd3d12vp9dec.h"
|
#include "gstd3d12vp9dec.h"
|
||||||
#include "gstd3d12av1dec.h"
|
#include "gstd3d12av1dec.h"
|
||||||
|
@ -106,6 +107,9 @@ plugin_init (GstPlugin * plugin)
|
||||||
gst_d3d12_av1_dec_register (plugin, device, video_device.Get (),
|
gst_d3d12_av1_dec_register (plugin, device, video_device.Get (),
|
||||||
GST_RANK_NONE);
|
GST_RANK_NONE);
|
||||||
|
|
||||||
|
gst_d3d12_h264_enc_register (plugin, device, video_device.Get (),
|
||||||
|
GST_RANK_NONE);
|
||||||
|
|
||||||
gst_object_unref (device);
|
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('codecparsers')
|
||||||
subdir('codecs')
|
subdir('codecs')
|
||||||
subdir('d3d11')
|
subdir('d3d11')
|
||||||
|
subdir('d3d12')
|
||||||
subdir('directfb')
|
subdir('directfb')
|
||||||
subdir('gtk')
|
subdir('gtk')
|
||||||
subdir('ipcpipeline')
|
subdir('ipcpipeline')
|
||||||
|
|
Loading…
Reference in a new issue