1 /* GStreamer
2 * Copyright (C) <2021> Collabora Ltd.
3 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/pbutils/pbutils.h>
26
27 #include "gstalphadecodebin.h"
28
29 GST_DEBUG_CATEGORY_STATIC (alphadecodebin_debug);
30 #define GST_CAT_DEFAULT (alphadecodebin_debug)
31
32 typedef struct
33 {
34 GstBin parent;
35
36 gboolean constructed;
37 const gchar *missing_element;
38 } GstAlphaDecodeBinPrivate;
39
40 #define gst_alpha_decode_bin_parent_class parent_class
41 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstAlphaDecodeBin, gst_alpha_decode_bin,
42 GST_TYPE_BIN,
43 G_ADD_PRIVATE (GstAlphaDecodeBin);
44 GST_DEBUG_CATEGORY_INIT (alphadecodebin_debug, "alphadecodebin", 0,
45 "alphadecodebin"));
46
47 static GstStaticPadTemplate gst_alpha_decode_bin_src_template =
48 GST_STATIC_PAD_TEMPLATE ("src",
49 GST_PAD_SRC,
50 GST_PAD_ALWAYS,
51 GST_STATIC_CAPS ("ANY")
52 );
53
54 static gboolean
gst_alpha_decode_bin_open(GstAlphaDecodeBin * self)55 gst_alpha_decode_bin_open (GstAlphaDecodeBin * self)
56 {
57 GstAlphaDecodeBinPrivate *priv =
58 gst_alpha_decode_bin_get_instance_private (self);
59
60 if (priv->missing_element) {
61 gst_element_post_message (GST_ELEMENT (self),
62 gst_missing_element_message_new (GST_ELEMENT (self),
63 priv->missing_element));
64 } else if (!priv->constructed) {
65 GST_ELEMENT_ERROR (self, CORE, FAILED,
66 ("Failed to construct alpha decoder pipeline."), (NULL));
67 }
68
69 return priv->constructed;
70 }
71
72 static GstStateChangeReturn
gst_alpha_decode_bin_change_state(GstElement * element,GstStateChange transition)73 gst_alpha_decode_bin_change_state (GstElement * element,
74 GstStateChange transition)
75 {
76 GstAlphaDecodeBin *self = GST_ALPHA_DECODE_BIN (element);
77
78 switch (transition) {
79 case GST_STATE_CHANGE_NULL_TO_READY:
80 if (!gst_alpha_decode_bin_open (self))
81 return GST_STATE_CHANGE_FAILURE;
82 break;
83 default:
84 break;
85 }
86
87 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
88 }
89
90 static void
gst_alpha_decode_bin_constructed(GObject * obj)91 gst_alpha_decode_bin_constructed (GObject * obj)
92 {
93 GstAlphaDecodeBin *self = GST_ALPHA_DECODE_BIN (obj);
94 GstAlphaDecodeBinPrivate *priv =
95 gst_alpha_decode_bin_get_instance_private (self);
96 GstAlphaDecodeBinClass *klass = GST_ALPHA_DECODE_BIN_GET_CLASS (self);
97 GstPad *src_gpad, *sink_gpad;
98 GstPad *src_pad = NULL, *sink_pad = NULL;
99 GstElement *alphademux = NULL;
100 GstElement *queue = NULL;
101 GstElement *alpha_queue = NULL;
102 GstElement *decoder = NULL;
103 GstElement *alpha_decoder = NULL;
104 GstElement *alphacombine = NULL;
105
106 /* setup ghost pads */
107 sink_gpad = gst_ghost_pad_new_no_target_from_template ("sink",
108 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink"));
109 gst_element_add_pad (GST_ELEMENT (self), sink_gpad);
110
111 src_gpad = gst_ghost_pad_new_no_target_from_template ("src",
112 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src"));
113 gst_element_add_pad (GST_ELEMENT (self), src_gpad);
114
115 /* create elements */
116 alphademux = gst_element_factory_make ("codecalphademux", NULL);
117 if (!alphademux) {
118 priv->missing_element = "codecalphademux";
119 goto cleanup;
120 }
121
122 queue = gst_element_factory_make ("queue", NULL);
123 alpha_queue = gst_element_factory_make ("queue", NULL);
124 if (!queue || !alpha_queue) {
125 priv->missing_element = "queue";
126 goto cleanup;
127 }
128
129 decoder = gst_element_factory_make (klass->decoder_name, "maindec");
130 if (!decoder) {
131 priv->missing_element = klass->decoder_name;
132 goto cleanup;
133 }
134
135 alpha_decoder = gst_element_factory_make (klass->decoder_name, "alphadec");
136 if (!alpha_decoder) {
137 priv->missing_element = klass->decoder_name;
138 goto cleanup;
139 }
140
141 /* We disable QoS on decoders because we need to maintain frame pairing in
142 * order for alphacombine to work. */
143 g_object_set (decoder, "qos", FALSE, NULL);
144 g_object_set (alpha_decoder, "qos", FALSE, NULL);
145
146 alphacombine = gst_element_factory_make ("alphacombine", NULL);
147 if (!alphacombine) {
148 priv->missing_element = "alphacombine";
149 goto cleanup;
150 }
151
152 gst_bin_add_many (GST_BIN (self), alphademux, queue, alpha_queue, decoder,
153 alpha_decoder, alphacombine, NULL);
154
155 /* link elements */
156 sink_pad = gst_element_get_static_pad (alphademux, "sink");
157 gst_ghost_pad_set_target (GST_GHOST_PAD (sink_gpad), sink_pad);
158 gst_clear_object (&sink_pad);
159
160 gst_element_link_pads (alphademux, "src", queue, "sink");
161 gst_element_link_pads (queue, "src", decoder, "sink");
162 gst_element_link_pads (decoder, "src", alphacombine, "sink");
163
164 gst_element_link_pads (alphademux, "alpha", alpha_queue, "sink");
165 gst_element_link_pads (alpha_queue, "src", alpha_decoder, "sink");
166 gst_element_link_pads (alpha_decoder, "src", alphacombine, "alpha");
167
168 src_pad = gst_element_get_static_pad (alphacombine, "src");
169 gst_ghost_pad_set_target (GST_GHOST_PAD (src_gpad), src_pad);
170 gst_object_unref (src_pad);
171
172 g_object_set (queue, "max-size-bytes", 0, "max-size-time", 0,
173 "max-size-buffers", 1, NULL);
174 g_object_set (alpha_queue, "max-size-bytes", 0, "max-size-time", 0,
175 "max-size-buffers", 1, NULL);
176
177 /* signal success, we will handle this in NULL->READY transition */
178 priv->constructed = TRUE;
179 return;
180
181 cleanup:
182 gst_clear_object (&alphademux);
183 gst_clear_object (&queue);
184 gst_clear_object (&alpha_queue);
185 gst_clear_object (&decoder);
186 gst_clear_object (&alpha_decoder);
187 gst_clear_object (&alphacombine);
188
189 G_OBJECT_CLASS (parent_class)->constructed (obj);
190 }
191
192 static void
gst_alpha_decode_bin_class_init(GstAlphaDecodeBinClass * klass)193 gst_alpha_decode_bin_class_init (GstAlphaDecodeBinClass * klass)
194 {
195 GstElementClass *element_class = (GstElementClass *) klass;
196 GObjectClass *obj_class = (GObjectClass *) klass;
197
198 /* This is needed to access the subclass class instance, otherwise we cannot
199 * read the class parameters */
200 obj_class->constructed = gst_alpha_decode_bin_constructed;
201
202 gst_element_class_add_static_pad_template (element_class,
203 &gst_alpha_decode_bin_src_template);
204 element_class->change_state =
205 GST_DEBUG_FUNCPTR (gst_alpha_decode_bin_change_state);
206
207 /* let's make the doc generator happy */
208 gst_type_mark_as_plugin_api (GST_TYPE_ALPHA_DECODE_BIN, 0);
209 }
210
211 static void
gst_alpha_decode_bin_init(GstAlphaDecodeBin * self)212 gst_alpha_decode_bin_init (GstAlphaDecodeBin * self)
213 {
214 }
215