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