1 /* GStreamer
2 * Copyright (C) 2008 David Schleef <ds@schleef.org>
3 * Copyright (C) 2012 Collabora Ltd.
4 * Author : Edward Hervey <edward@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/video/video.h>
27 #include "gstvideoutilsprivate.h"
28
29 /*
30 * Takes caps and copies its video fields to tmpl_caps
31 */
32 static GstCaps *
__gst_video_element_proxy_caps(GstElement * element,GstCaps * templ_caps,GstCaps * caps)33 __gst_video_element_proxy_caps (GstElement * element, GstCaps * templ_caps,
34 GstCaps * caps)
35 {
36 GstCaps *result = gst_caps_new_empty ();
37 gint i, j;
38 gint templ_caps_size = gst_caps_get_size (templ_caps);
39 gint caps_size = gst_caps_get_size (caps);
40
41 for (i = 0; i < templ_caps_size; i++) {
42 GQuark q_name =
43 gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i));
44 GstCapsFeatures *features = gst_caps_get_features (templ_caps, i);
45
46 for (j = 0; j < caps_size; j++) {
47 const GstStructure *caps_s = gst_caps_get_structure (caps, j);
48 const GValue *val;
49 GstStructure *s;
50 GstCaps *tmp = gst_caps_new_empty ();
51
52 s = gst_structure_new_id_empty (q_name);
53 if ((val = gst_structure_get_value (caps_s, "width")))
54 gst_structure_set_value (s, "width", val);
55 if ((val = gst_structure_get_value (caps_s, "height")))
56 gst_structure_set_value (s, "height", val);
57 if ((val = gst_structure_get_value (caps_s, "framerate")))
58 gst_structure_set_value (s, "framerate", val);
59 if ((val = gst_structure_get_value (caps_s, "pixel-aspect-ratio")))
60 gst_structure_set_value (s, "pixel-aspect-ratio", val);
61 if ((val = gst_structure_get_value (caps_s, "colorimetry")))
62 gst_structure_set_value (s, "colorimetry", val);
63 if ((val = gst_structure_get_value (caps_s, "chroma-site")))
64 gst_structure_set_value (s, "chroma-site", val);
65
66 gst_caps_append_structure_full (tmp, s,
67 gst_caps_features_copy (features));
68 result = gst_caps_merge (result, tmp);
69 }
70 }
71
72 return result;
73 }
74
75 /**
76 * __gst_video_element_proxy_getcaps:
77 * @element: a #GstElement
78 * @sinkpad: the element's sink #GstPad
79 * @srcpad: the element's source #GstPad
80 * @initial_caps: initial caps
81 * @filter: filter caps
82 *
83 * Returns caps that express @initial_caps (or sink template caps if
84 * @initial_caps == NULL) restricted to resolution/format/...
85 * combinations supported by downstream elements (e.g. muxers).
86 *
87 * Returns: a #GstCaps owned by caller
88 */
89 GstCaps *
__gst_video_element_proxy_getcaps(GstElement * element,GstPad * sinkpad,GstPad * srcpad,GstCaps * initial_caps,GstCaps * filter)90 __gst_video_element_proxy_getcaps (GstElement * element, GstPad * sinkpad,
91 GstPad * srcpad, GstCaps * initial_caps, GstCaps * filter)
92 {
93 GstCaps *templ_caps, *src_templ_caps;
94 GstCaps *peer_caps;
95 GstCaps *allowed;
96 GstCaps *fcaps, *filter_caps;
97
98 /* Allow downstream to specify width/height/framerate/PAR constraints
99 * and forward them upstream for video converters to handle
100 */
101 templ_caps = initial_caps ? gst_caps_ref (initial_caps) :
102 gst_pad_get_pad_template_caps (sinkpad);
103 src_templ_caps = gst_pad_get_pad_template_caps (srcpad);
104 if (filter && !gst_caps_is_any (filter)) {
105 GstCaps *proxy_filter =
106 __gst_video_element_proxy_caps (element, src_templ_caps, filter);
107
108 peer_caps = gst_pad_peer_query_caps (srcpad, proxy_filter);
109 gst_caps_unref (proxy_filter);
110 } else {
111 peer_caps = gst_pad_peer_query_caps (srcpad, NULL);
112 }
113
114 allowed = gst_caps_intersect_full (peer_caps, src_templ_caps,
115 GST_CAPS_INTERSECT_FIRST);
116
117 gst_caps_unref (src_templ_caps);
118 gst_caps_unref (peer_caps);
119
120 if (!allowed || gst_caps_is_any (allowed)) {
121 fcaps = templ_caps;
122 goto done;
123 } else if (gst_caps_is_empty (allowed)) {
124 fcaps = gst_caps_ref (allowed);
125 goto done;
126 }
127
128 GST_LOG_OBJECT (element, "template caps %" GST_PTR_FORMAT, templ_caps);
129 GST_LOG_OBJECT (element, "allowed caps %" GST_PTR_FORMAT, allowed);
130
131 filter_caps = __gst_video_element_proxy_caps (element, templ_caps, allowed);
132
133 fcaps = gst_caps_intersect (filter_caps, templ_caps);
134 gst_caps_unref (filter_caps);
135 gst_caps_unref (templ_caps);
136
137 if (filter) {
138 GST_LOG_OBJECT (element, "intersecting with %" GST_PTR_FORMAT, filter);
139 filter_caps = gst_caps_intersect (fcaps, filter);
140 gst_caps_unref (fcaps);
141 fcaps = filter_caps;
142 }
143
144 done:
145 gst_caps_replace (&allowed, NULL);
146
147 GST_LOG_OBJECT (element, "proxy caps %" GST_PTR_FORMAT, fcaps);
148
149 return fcaps;
150 }
151
152 gboolean
__gst_video_rawvideo_convert(GstVideoCodecState * state,GstFormat src_format,gint64 src_value,GstFormat * dest_format,gint64 * dest_value)153 __gst_video_rawvideo_convert (GstVideoCodecState * state,
154 GstFormat src_format, gint64 src_value,
155 GstFormat * dest_format, gint64 * dest_value)
156 {
157 gboolean res = FALSE;
158 guint vidsize;
159 guint fps_n, fps_d;
160
161 g_return_val_if_fail (dest_format != NULL, FALSE);
162 g_return_val_if_fail (dest_value != NULL, FALSE);
163
164 if (src_format == *dest_format || src_value == 0 || src_value == -1) {
165 *dest_value = src_value;
166 return TRUE;
167 }
168
169 vidsize = GST_VIDEO_INFO_SIZE (&state->info);
170 fps_n = GST_VIDEO_INFO_FPS_N (&state->info);
171 fps_d = GST_VIDEO_INFO_FPS_D (&state->info);
172
173 if (src_format == GST_FORMAT_BYTES &&
174 *dest_format == GST_FORMAT_DEFAULT && vidsize) {
175 /* convert bytes to frames */
176 *dest_value = gst_util_uint64_scale_int (src_value, 1, vidsize);
177 res = TRUE;
178 } else if (src_format == GST_FORMAT_DEFAULT &&
179 *dest_format == GST_FORMAT_BYTES && vidsize) {
180 /* convert bytes to frames */
181 *dest_value = src_value * vidsize;
182 res = TRUE;
183 } else if (src_format == GST_FORMAT_DEFAULT &&
184 *dest_format == GST_FORMAT_TIME && fps_n) {
185 /* convert frames to time */
186 *dest_value = gst_util_uint64_scale (src_value, GST_SECOND * fps_d, fps_n);
187 res = TRUE;
188 } else if (src_format == GST_FORMAT_TIME &&
189 *dest_format == GST_FORMAT_DEFAULT && fps_d) {
190 /* convert time to frames */
191 *dest_value = gst_util_uint64_scale (src_value, fps_n, GST_SECOND * fps_d);
192 res = TRUE;
193 } else if (src_format == GST_FORMAT_TIME &&
194 *dest_format == GST_FORMAT_BYTES && fps_d && vidsize) {
195 /* convert time to bytes */
196 *dest_value = gst_util_uint64_scale (src_value,
197 fps_n * (guint64) vidsize, GST_SECOND * fps_d);
198 res = TRUE;
199 } else if (src_format == GST_FORMAT_BYTES &&
200 *dest_format == GST_FORMAT_TIME && fps_n && vidsize) {
201 /* convert bytes to time */
202 *dest_value = gst_util_uint64_scale (src_value,
203 GST_SECOND * fps_d, fps_n * (guint64) vidsize);
204 res = TRUE;
205 }
206
207 return res;
208 }
209
210 gboolean
__gst_video_encoded_video_convert(gint64 bytes,gint64 time,GstFormat src_format,gint64 src_value,GstFormat * dest_format,gint64 * dest_value)211 __gst_video_encoded_video_convert (gint64 bytes, gint64 time,
212 GstFormat src_format, gint64 src_value, GstFormat * dest_format,
213 gint64 * dest_value)
214 {
215 gboolean res = FALSE;
216
217 g_return_val_if_fail (dest_format != NULL, FALSE);
218 g_return_val_if_fail (dest_value != NULL, FALSE);
219
220 if (G_UNLIKELY (src_format == *dest_format || src_value == 0 ||
221 src_value == -1)) {
222 if (dest_value)
223 *dest_value = src_value;
224 return TRUE;
225 }
226
227 if (bytes <= 0 || time <= 0) {
228 GST_DEBUG ("not enough metadata yet to convert");
229 goto exit;
230 }
231
232 switch (src_format) {
233 case GST_FORMAT_BYTES:
234 switch (*dest_format) {
235 case GST_FORMAT_TIME:
236 *dest_value = gst_util_uint64_scale (src_value, time, bytes);
237 res = TRUE;
238 break;
239 default:
240 res = FALSE;
241 }
242 break;
243 case GST_FORMAT_TIME:
244 switch (*dest_format) {
245 case GST_FORMAT_BYTES:
246 *dest_value = gst_util_uint64_scale (src_value, bytes, time);
247 res = TRUE;
248 break;
249 default:
250 res = FALSE;
251 }
252 break;
253 default:
254 GST_DEBUG ("unhandled conversion from %d to %d", src_format,
255 *dest_format);
256 res = FALSE;
257 }
258
259 exit:
260 return res;
261 }
262