Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Deniz Ugur, Romain Bouqueau, Sohaib Larbi
5 : * Copyright (c) Motion Spell
6 : * All rights reserved
7 : *
8 : * This file is part of the GPAC/GStreamer wrapper
9 : *
10 : * This GPAC/GStreamer wrapper is free software; you can redistribute it
11 : * and/or modify it under the terms of the GNU Affero General Public License
12 : * as published by the Free Software Foundation; either version 3, or (at
13 : * your option) any later version.
14 : *
15 : * This GPAC/GStreamer wrapper is distributed in the hope that it will be
16 : * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Affero General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Affero General Public
21 : * License along with this library; see the file LICENSE. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "common.h"
27 : #include "gpacmessages.h"
28 : #include "lib/pid.h"
29 :
30 : #define CAPS_HANDLER_SIGNATURE(prop_nickname) \
31 : gboolean prop_nickname##_caps_handler(GPAC_PID_PROP_IMPL_ARGS)
32 :
33 : #define DEFAULT_HANDLER(prop_nickname) \
34 : gboolean prop_nickname##_caps_handler(GPAC_PID_PROP_IMPL_ARGS) \
35 : { \
36 : return FALSE; \
37 : }
38 :
39 : #define GET_MEDIA_AND_CODEC \
40 : GstStructure* structure = gst_caps_get_structure(priv->caps, 0); \
41 : const gchar* media_type_full = gst_structure_get_name(structure); \
42 : g_auto(GStrv) media_type_parts = g_strsplit(media_type_full, "/", 2); \
43 : gchar* media = media_type_parts[0]; \
44 : gchar* codec = media_type_parts[1];
45 :
46 : //
47 : // Default Caps handlers
48 : //
49 21 : DEFAULT_HANDLER(duration)
50 :
51 : //
52 : // Caps handlers
53 : //
54 21 : CAPS_HANDLER_SIGNATURE(stream_type)
55 : {
56 42 : GET_MEDIA_AND_CODEC
57 :
58 : // Get the stream type
59 21 : u32 stream_type = gf_stream_type_by_name(media);
60 21 : if (stream_type == GF_STREAM_UNKNOWN) {
61 0 : GST_ELEMENT_ERROR(
62 : element, LIBRARY, FAILED, (NULL), ("Unknown stream type"));
63 0 : return FALSE;
64 : }
65 :
66 : // Check the subtype
67 21 : if (!g_strcmp0(media, "video")) {
68 18 : const gchar* subtype = gst_structure_get_string(structure, "stream-format");
69 18 : if (!g_strcmp0(subtype, "avc") || !g_strcmp0(subtype, "hev1"))
70 16 : SET_PROP(GF_PROP_PID_ISOM_SUBTYPE, PROP_STRING(subtype));
71 : }
72 :
73 : // Set the stream type
74 21 : SET_PROP(GF_PROP_PID_STREAM_TYPE, PROP_UINT(stream_type));
75 21 : return TRUE;
76 : }
77 :
78 21 : CAPS_HANDLER_SIGNATURE(codec_id)
79 : {
80 42 : GET_MEDIA_AND_CODEC
81 21 : GF_CodecID codec_id = GF_CODECID_NONE;
82 :
83 : // In most cases the substring after "x-" can be used to query the codec id
84 21 : if (g_str_has_prefix(codec, "x-")) {
85 18 : codec_id = gf_codecid_parse(codec + 2);
86 18 : if (codec_id != GF_CODECID_NONE)
87 18 : goto finish;
88 : }
89 :
90 : // See caps.h for the supported formats
91 : // For the other cases, we will match the codec id manually
92 3 : if (!g_strcmp0(media, "audio")) {
93 3 : if (!g_strcmp0(codec, "mpeg"))
94 3 : codec_id = GF_CODECID_AAC_MPEG4;
95 : }
96 :
97 : // If we still couldn't determine the codec id, log a warning
98 3 : if (codec_id == GF_CODECID_NONE) {
99 0 : GST_ELEMENT_ERROR(element,
100 : STREAM,
101 : FAILED,
102 : (NULL),
103 : ("Could not determine codec id for %s/%s", media, codec));
104 0 : return FALSE;
105 : }
106 :
107 3 : finish:
108 : // Set the codec id
109 21 : SET_PROP(GF_PROP_PID_CODECID, PROP_UINT(codec_id));
110 21 : return TRUE;
111 : }
112 :
113 21 : CAPS_HANDLER_SIGNATURE(unframed)
114 : {
115 42 : GET_MEDIA_AND_CODEC
116 :
117 : const gchar* stream_format =
118 21 : gst_structure_get_string(structure, "stream-format");
119 :
120 : // Check if the stream is framed
121 21 : gboolean framed = TRUE;
122 21 : if (!g_strcmp0(media, "video")) {
123 18 : if (stream_format) {
124 35 : if (!g_strcmp0(stream_format, "byte-stream") ||
125 17 : !g_strcmp0(stream_format, "obu-stream"))
126 2 : framed = FALSE;
127 : }
128 3 : } else if (!g_strcmp0(media, "audio")) {
129 3 : gst_structure_get_boolean(structure, "framed", &framed);
130 : }
131 :
132 : //* For AVC, HEVC, AV1, etc. our caps always ask for streams with start codes.
133 : //* So we'll always have unframed data. But for maximum compatibility, we may
134 : //* allow framed data and explicitly load "unframer" in gpac.
135 :
136 : // Push the caps with the unframed property
137 21 : gf_filter_override_caps(gf_filter_pid_get_owner(pid), NULL, 0);
138 21 : gf_filter_push_caps(gf_filter_pid_get_owner(pid),
139 : GF_PROP_PID_UNFRAMED,
140 21 : &PROP_BOOL(!framed),
141 : NULL,
142 : GF_CAPS_OUTPUT,
143 : 0);
144 :
145 : // Set the unframed property
146 21 : SET_PROP(GF_PROP_PID_UNFRAMED, PROP_BOOL(!framed));
147 21 : return TRUE;
148 : }
149 :
150 21 : CAPS_HANDLER_SIGNATURE(width)
151 : {
152 42 : GET_MEDIA_AND_CODEC
153 :
154 : // Only process video media
155 21 : if (g_strcmp0(media, "video"))
156 3 : return TRUE;
157 :
158 18 : gint width = -1;
159 18 : gst_structure_get_int(structure, "width", &width);
160 18 : if (width <= 0) {
161 0 : GST_ELEMENT_ERROR(element, LIBRARY, FAILED, (NULL), ("Invalid width"));
162 0 : return FALSE;
163 : }
164 :
165 : // Set the width property
166 18 : SET_PROP(GF_PROP_PID_WIDTH, PROP_UINT(width));
167 18 : return TRUE;
168 : }
169 :
170 21 : CAPS_HANDLER_SIGNATURE(height)
171 : {
172 42 : GET_MEDIA_AND_CODEC
173 :
174 : // Only process video media
175 21 : if (g_strcmp0(media, "video"))
176 3 : return TRUE;
177 :
178 18 : gint height = -1;
179 18 : gst_structure_get_int(structure, "height", &height);
180 18 : if (height <= 0) {
181 0 : GST_ELEMENT_ERROR(element, LIBRARY, FAILED, (NULL), ("Invalid height"));
182 0 : return FALSE;
183 : }
184 :
185 : // Set the height property
186 18 : SET_PROP(GF_PROP_PID_HEIGHT, PROP_UINT(height));
187 18 : return TRUE;
188 : }
189 :
190 21 : CAPS_HANDLER_SIGNATURE(sample_rate)
191 : {
192 42 : GET_MEDIA_AND_CODEC
193 :
194 : // Only process audio media
195 21 : if (g_strcmp0(media, "audio"))
196 18 : return TRUE;
197 :
198 3 : gint rate = -1;
199 3 : gst_structure_get_int(structure, "rate", &rate);
200 3 : if (rate <= 0) {
201 0 : GST_ELEMENT_ERROR(
202 : element, LIBRARY, FAILED, (NULL), ("Invalid sample rate"));
203 0 : return FALSE;
204 : }
205 :
206 : // Set the sample rate property
207 3 : SET_PROP(GF_PROP_PID_SAMPLE_RATE, PROP_UINT(rate));
208 3 : return TRUE;
209 : }
210 :
211 21 : CAPS_HANDLER_SIGNATURE(fps)
212 : {
213 42 : GET_MEDIA_AND_CODEC
214 :
215 : // Only process video media
216 21 : if (g_strcmp0(media, "video"))
217 3 : return TRUE;
218 :
219 18 : gint num = -1, denom = -1;
220 18 : gst_structure_get_fraction(structure, "framerate", &num, &denom);
221 18 : if (num < 0 || denom < 0)
222 0 : return FALSE;
223 :
224 : // Set the framerate property
225 18 : SET_PROP(GF_PROP_PID_FPS, PROP_FRAC_INT(num, denom));
226 18 : return TRUE;
227 : }
228 :
229 21 : CAPS_HANDLER_SIGNATURE(timescale)
230 : {
231 42 : GET_MEDIA_AND_CODEC
232 :
233 21 : guint64 timescale = 0;
234 21 : if (!g_strcmp0(media, "video")) {
235 : const GF_PropertyValue* p =
236 18 : gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
237 18 : if (p)
238 18 : timescale = p->value.frac.num;
239 3 : } else if (!g_strcmp0(media, "audio")) {
240 : const GF_PropertyValue* p =
241 3 : gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
242 3 : if (p)
243 3 : timescale = p->value.uint;
244 : } else {
245 0 : GST_ELEMENT_ERROR(element,
246 : LIBRARY,
247 : FAILED,
248 : ("Unsupported media type (%s) for timescale", media),
249 : (NULL));
250 0 : return FALSE;
251 : }
252 :
253 21 : if (timescale == 0)
254 0 : return FALSE;
255 :
256 : // Set the timescale property
257 21 : SET_PROP(GF_PROP_PID_TIMESCALE, PROP_UINT(timescale));
258 21 : return TRUE;
259 : }
260 :
261 21 : CAPS_HANDLER_SIGNATURE(num_channels)
262 : {
263 42 : GET_MEDIA_AND_CODEC
264 :
265 : // Only process audio media
266 21 : if (g_strcmp0(media, "audio"))
267 18 : return TRUE;
268 :
269 3 : gint channels = -1;
270 3 : gst_structure_get_int(structure, "channels", &channels);
271 :
272 : // Set the number of channels property
273 3 : SET_PROP(GF_PROP_PID_NUM_CHANNELS, PROP_UINT(channels));
274 3 : return TRUE;
275 : }
276 :
277 21 : CAPS_HANDLER_SIGNATURE(decoder_config)
278 : {
279 21 : SKIP_IF_SET(GF_PROP_PID_DECODER_CONFIG);
280 :
281 21 : GstStructure* structure = gst_caps_get_structure(priv->caps, 0);
282 :
283 : // Get the codec data
284 21 : const GValue* codec_data = gst_structure_get_value(structure, "codec_data");
285 21 : if (!GST_VALUE_HOLDS_BUFFER(codec_data))
286 2 : return TRUE;
287 :
288 19 : GstBuffer* buffer = gst_value_get_buffer(codec_data);
289 19 : g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
290 19 : if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
291 0 : GST_ELEMENT_ERROR(
292 : element, STREAM, FAILED, (NULL), ("Failed to map codec_data buffer"));
293 0 : return FALSE;
294 : }
295 :
296 : // Copy the data
297 19 : u8* data = (u8*)g_malloc0(map.size);
298 19 : memcpy((void*)data, map.data, map.size);
299 :
300 : // Set the decoder config property
301 19 : SET_PROP(GF_PROP_PID_DECODER_CONFIG, PROP_CONST_DATA(data, map.size));
302 19 : return TRUE;
303 : }
|