1 /* GStreamer
2 * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
3 * Copyright (C) 2011 Nokia Corporation. All rights reserved.
4 * Contact: Stefan Kost <stefan.kost@nokia.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/audio/audio.h>
27 #ifdef G_OS_WIN32
28 #include <windows.h>
29 #endif
30
31 #include "gstaudioutilsprivate.h"
32
33 /*
34 * Takes caps and copies its audio fields to tmpl_caps
35 */
36 static GstCaps *
__gst_audio_element_proxy_caps(GstElement * element,GstCaps * templ_caps,GstCaps * caps)37 __gst_audio_element_proxy_caps (GstElement * element, GstCaps * templ_caps,
38 GstCaps * caps)
39 {
40 GstCaps *result = gst_caps_new_empty ();
41 gint i, j;
42 gint templ_caps_size = gst_caps_get_size (templ_caps);
43 gint caps_size = gst_caps_get_size (caps);
44
45 for (i = 0; i < templ_caps_size; i++) {
46 GQuark q_name =
47 gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i));
48 GstCapsFeatures *features = gst_caps_get_features (templ_caps, i);
49
50 for (j = 0; j < caps_size; j++) {
51 const GstStructure *caps_s = gst_caps_get_structure (caps, j);
52 const GValue *val;
53 GstStructure *s;
54 GstCaps *tmp = gst_caps_new_empty ();
55
56 s = gst_structure_new_id_empty (q_name);
57 if ((val = gst_structure_get_value (caps_s, "rate")))
58 gst_structure_set_value (s, "rate", val);
59 if ((val = gst_structure_get_value (caps_s, "channels")))
60 gst_structure_set_value (s, "channels", val);
61 if ((val = gst_structure_get_value (caps_s, "channels-mask")))
62 gst_structure_set_value (s, "channels-mask", val);
63
64 gst_caps_append_structure_full (tmp, s,
65 gst_caps_features_copy (features));
66 result = gst_caps_merge (result, tmp);
67 }
68 }
69
70 return result;
71 }
72
73 /**
74 * __gst_audio_element_proxy_getcaps:
75 * @element: a #GstElement
76 * @sinkpad: the element's sink #GstPad
77 * @srcpad: the element's source #GstPad
78 * @initial_caps: initial caps
79 * @filter: filter caps
80 *
81 * Returns caps that express @initial_caps (or sink template caps if
82 * @initial_caps == NULL) restricted to rate/channels/...
83 * combinations supported by downstream elements (e.g. muxers).
84 *
85 * Returns: a #GstCaps owned by caller
86 */
87 GstCaps *
__gst_audio_element_proxy_getcaps(GstElement * element,GstPad * sinkpad,GstPad * srcpad,GstCaps * initial_caps,GstCaps * filter)88 __gst_audio_element_proxy_getcaps (GstElement * element, GstPad * sinkpad,
89 GstPad * srcpad, GstCaps * initial_caps, GstCaps * filter)
90 {
91 GstCaps *templ_caps, *src_templ_caps;
92 GstCaps *peer_caps;
93 GstCaps *allowed;
94 GstCaps *fcaps, *filter_caps;
95
96 /* Allow downstream to specify rate/channels constraints
97 * and forward them upstream for audio converters to handle
98 */
99 templ_caps = initial_caps ? gst_caps_ref (initial_caps) :
100 gst_pad_get_pad_template_caps (sinkpad);
101 src_templ_caps = gst_pad_get_pad_template_caps (srcpad);
102 if (filter && !gst_caps_is_any (filter)) {
103 GstCaps *proxy_filter =
104 __gst_audio_element_proxy_caps (element, src_templ_caps, filter);
105
106 peer_caps = gst_pad_peer_query_caps (srcpad, proxy_filter);
107 gst_caps_unref (proxy_filter);
108 } else {
109 peer_caps = gst_pad_peer_query_caps (srcpad, NULL);
110 }
111
112 allowed = gst_caps_intersect_full (peer_caps, src_templ_caps,
113 GST_CAPS_INTERSECT_FIRST);
114
115 gst_caps_unref (src_templ_caps);
116 gst_caps_unref (peer_caps);
117
118 if (!allowed || gst_caps_is_any (allowed)) {
119 fcaps = templ_caps;
120 goto done;
121 } else if (gst_caps_is_empty (allowed)) {
122 fcaps = gst_caps_ref (allowed);
123 goto done;
124 }
125
126 GST_LOG_OBJECT (element, "template caps %" GST_PTR_FORMAT, templ_caps);
127 GST_LOG_OBJECT (element, "allowed caps %" GST_PTR_FORMAT, allowed);
128
129 filter_caps = __gst_audio_element_proxy_caps (element, templ_caps, allowed);
130
131 fcaps = gst_caps_intersect (filter_caps, templ_caps);
132 gst_caps_unref (filter_caps);
133 gst_caps_unref (templ_caps);
134
135 if (filter) {
136 GST_LOG_OBJECT (element, "intersecting with %" GST_PTR_FORMAT, filter);
137 filter_caps = gst_caps_intersect (fcaps, filter);
138 gst_caps_unref (fcaps);
139 fcaps = filter_caps;
140 }
141
142 done:
143 gst_caps_replace (&allowed, NULL);
144
145 GST_LOG_OBJECT (element, "proxy caps %" GST_PTR_FORMAT, fcaps);
146
147 return fcaps;
148 }
149
150 /**
151 * __gst_audio_encoded_audio_convert:
152 * @fmt: audio format of the encoded audio
153 * @bytes: number of encoded bytes
154 * @samples: number of encoded samples
155 * @src_format: source format
156 * @src_value: source value
157 * @dest_format: destination format
158 * @dest_value: destination format
159 *
160 * Helper function to convert @src_value in @src_format to @dest_value in
161 * @dest_format for encoded audio data. Conversion is possible between
162 * BYTE and TIME format by using estimated bitrate based on
163 * @samples and @bytes (and @fmt).
164 */
165 gboolean
__gst_audio_encoded_audio_convert(GstAudioInfo * fmt,gint64 bytes,gint64 samples,GstFormat src_format,gint64 src_value,GstFormat * dest_format,gint64 * dest_value)166 __gst_audio_encoded_audio_convert (GstAudioInfo * fmt,
167 gint64 bytes, gint64 samples, GstFormat src_format,
168 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
169 {
170 gboolean res = FALSE;
171
172 g_return_val_if_fail (dest_format != NULL, FALSE);
173 g_return_val_if_fail (dest_value != NULL, FALSE);
174
175 if (G_UNLIKELY (src_format == *dest_format || src_value == 0 ||
176 src_value == -1)) {
177 if (dest_value)
178 *dest_value = src_value;
179 return TRUE;
180 }
181
182 if (samples == 0 || bytes == 0 || fmt->rate == 0) {
183 GST_DEBUG ("not enough metadata yet to convert");
184 goto exit;
185 }
186
187 bytes *= fmt->rate;
188
189 switch (src_format) {
190 case GST_FORMAT_BYTES:
191 switch (*dest_format) {
192 case GST_FORMAT_TIME:
193 *dest_value = gst_util_uint64_scale (src_value,
194 GST_SECOND * samples, bytes);
195 res = TRUE;
196 break;
197 default:
198 res = FALSE;
199 }
200 break;
201 case GST_FORMAT_TIME:
202 switch (*dest_format) {
203 case GST_FORMAT_BYTES:
204 *dest_value = gst_util_uint64_scale (src_value, bytes,
205 samples * GST_SECOND);
206 res = TRUE;
207 break;
208 default:
209 res = FALSE;
210 }
211 break;
212 default:
213 res = FALSE;
214 }
215
216 exit:
217 return res;
218 }
219
220 #ifdef G_OS_WIN32
221 /* *INDENT-OFF* */
222 static struct
223 {
224 HMODULE dll;
225 gboolean tried_loading;
226
227 FARPROC AvSetMmThreadCharacteristics;
228 FARPROC AvRevertMmThreadCharacteristics;
229 } _gst_audio_avrt_tbl = { 0 };
230 /* *INDENT-ON* */
231 #endif
232
233 static gboolean
__gst_audio_init_thread_priority(void)234 __gst_audio_init_thread_priority (void)
235 {
236 #ifdef G_OS_WIN32
237 if (_gst_audio_avrt_tbl.tried_loading)
238 return _gst_audio_avrt_tbl.dll != NULL;
239
240 if (!_gst_audio_avrt_tbl.dll)
241 _gst_audio_avrt_tbl.dll = LoadLibrary (TEXT ("avrt.dll"));
242
243 if (!_gst_audio_avrt_tbl.dll) {
244 GST_WARNING ("Failed to set thread priority, can't find avrt.dll");
245 _gst_audio_avrt_tbl.tried_loading = TRUE;
246 return FALSE;
247 }
248
249 _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics =
250 GetProcAddress (_gst_audio_avrt_tbl.dll, "AvSetMmThreadCharacteristicsA");
251 _gst_audio_avrt_tbl.AvRevertMmThreadCharacteristics =
252 GetProcAddress (_gst_audio_avrt_tbl.dll,
253 "AvRevertMmThreadCharacteristics");
254
255 _gst_audio_avrt_tbl.tried_loading = TRUE;
256 #endif
257
258 return TRUE;
259 }
260
261 /*
262 * Increases the priority of the thread it's called from
263 */
264 gboolean
__gst_audio_set_thread_priority(void)265 __gst_audio_set_thread_priority (void)
266 {
267 #ifdef G_OS_WIN32
268 DWORD taskIndex = 0;
269 #endif
270
271 if (!__gst_audio_init_thread_priority ())
272 return FALSE;
273
274 #ifdef G_OS_WIN32
275 /* This is only used from ringbuffer thread functions, so we don't need to
276 * ever need to revert the thread priorities. */
277 return _gst_audio_avrt_tbl.AvSetMmThreadCharacteristics (TEXT ("Pro Audio"),
278 &taskIndex) != 0;
279 #else
280 return TRUE;
281 #endif
282 }
283