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