Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiprofile.c
1 /*
2  *  gstvaapiprofile.c - VA profile abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  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  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * SECTION:gstvaapiprofile
24  * @short_description: VA profile abstraction
25  */
26
27 #include "sysdeps.h"
28 #include <string.h>
29 #include <gst/gstbuffer.h>
30 #include "gstvaapicompat.h"
31 #include "gstvaapiprofile.h"
32 #include "gstvaapiworkarounds.h"
33
34 typedef struct _GstVaapiProfileMap              GstVaapiProfileMap;
35 typedef struct _GstVaapiEntrypointMap           GstVaapiEntrypointMap;
36
37 struct _GstVaapiProfileMap {
38     GstVaapiProfile             profile;
39     VAProfile                   va_profile;
40     const char                 *caps_str;
41     const gchar                *profile_str;
42 };
43
44 struct _GstVaapiEntrypointMap {
45     GstVaapiEntrypoint          entrypoint;
46     VAEntrypoint                va_entrypoint;
47 };
48
49 /* Profiles */
50 static const GstVaapiProfileMap gst_vaapi_profiles[] = {
51     { GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple,
52       "video/mpeg, mpegversion=2", "simple"
53     },
54     { GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main,
55       "video/mpeg, mpegversion=2", "main"
56     },
57     { GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple,
58       "video/mpeg, mpegversion=4", "simple"
59     },
60     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
61       "video/mpeg, mpegversion=4", "advanced-simple"
62     },
63     { GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main,
64       "video/mpeg, mpegversion=4", "main"
65     },
66     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
67       "video/x-divx, divxversion=5", "advanced-simple"
68     },
69     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
70       "video/x-xvid", "advanced-simple"
71     },
72 #if VA_CHECK_VERSION(0,30,0)
73     { GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline,
74       "video/x-h263, variant=itu, h263version=h263", "baseline"
75     },
76 #endif
77     { GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline,
78       "video/x-h264", "baseline"
79     },
80     { GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main,
81       "video/x-h264", "main"
82     },
83     { GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High,
84       "video/x-h264", "high"
85     },
86     { GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple,
87       "video/x-wmv, wmvversion=3", "simple"
88     },
89     { GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main,
90       "video/x-wmv, wmvversion=3", "main"
91     },
92     { GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced,
93       "video/x-wmv, wmvversion=3, format=(fourcc)WVC1", "advanced"
94     },
95 #if VA_CHECK_VERSION(0,32,0)
96     { GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline,
97       "image/jpeg", "baseline"
98     },
99 #endif
100     { 0, }
101 };
102
103 /* Entry-points */
104 static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = {
105     { GST_VAAPI_ENTRYPOINT_VLD,          VAEntrypointVLD        },
106     { GST_VAAPI_ENTRYPOINT_IDCT,         VAEntrypointIDCT       },
107     { GST_VAAPI_ENTRYPOINT_MOCO,         VAEntrypointMoComp     },
108 #if VA_CHECK_VERSION(0,30,0)
109     { GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice   },
110 #endif
111     { 0, }
112 };
113
114 static const GstVaapiProfileMap *
115 get_profiles_map(GstVaapiProfile profile)
116 {
117     const GstVaapiProfileMap *m;
118
119     for (m = gst_vaapi_profiles; m->profile; m++)
120         if (m->profile == profile)
121             return m;
122     return NULL;
123 }
124
125 static const GstVaapiEntrypointMap *
126 get_entrypoints_map(GstVaapiEntrypoint entrypoint)
127 {
128     const GstVaapiEntrypointMap *m;
129
130     for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
131         if (m->entrypoint == entrypoint)
132             return m;
133     return NULL;
134 }
135
136 /**
137  * gst_vaapi_profile:
138  * @profile: a #VAProfile
139  *
140  * Converts a VA profile into the corresponding #GstVaapiProfile. If
141  * the profile cannot be represented by #GstVaapiProfile, then zero is
142  * returned.
143  *
144  * Return value: the #GstVaapiProfile describing the @profile
145  */
146 GstVaapiProfile
147 gst_vaapi_profile(VAProfile profile)
148 {
149     const GstVaapiProfileMap *m;
150
151     for (m = gst_vaapi_profiles; m->profile; m++)
152         if (m->va_profile == profile)
153             return m->profile;
154     return 0;
155 }
156
157 /**
158  * gst_vaapi_profile_from_codec_data:
159  * @codec: a #GstVaapiCodec
160  * @buffer: a #GstBuffer holding code data
161  *
162  * Tries to parse VA profile from @buffer data and @codec information.
163  *
164  * Return value: the #GstVaapiProfile described in @buffer
165  */
166 static GstVaapiProfile
167 gst_vaapi_profile_from_codec_data_h264(GstBuffer *buffer)
168 {
169     /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */
170     guchar * const buf = GST_BUFFER_DATA(buffer);
171
172     if (buf[0] != 1)    /* configurationVersion = 1 */
173         return 0;
174
175     switch (buf[1]) {   /* AVCProfileIndication */
176     case 66:    return GST_VAAPI_PROFILE_H264_BASELINE;
177     case 77:    return GST_VAAPI_PROFILE_H264_MAIN;
178     case 100:   return GST_VAAPI_PROFILE_H264_HIGH;
179     }
180     return 0;
181 }
182
183 static GstVaapiProfile
184 gst_vaapi_profile_from_codec_data(GstVaapiCodec codec, GstBuffer *buffer)
185 {
186     GstVaapiProfile profile;
187
188     if (!codec || !buffer)
189         return 0;
190
191     switch (codec) {
192     case GST_VAAPI_CODEC_H264:
193         profile = gst_vaapi_profile_from_codec_data_h264(buffer);
194         break;
195     default:
196         profile = 0;
197         break;
198     }
199     return profile;
200 }
201
202 /**
203  * gst_vaapi_profile_from_caps:
204  * @caps: a #GstCaps
205  *
206  * Converts @caps into the corresponding #GstVaapiProfile. If the
207  * profile cannot be represented by #GstVaapiProfile, then zero is
208  * returned.
209  *
210  * Return value: the #GstVaapiProfile describing the @caps
211  */
212 GstVaapiProfile
213 gst_vaapi_profile_from_caps(GstCaps *caps)
214 {
215     const GstVaapiProfileMap *m;
216     GstCaps *caps_test;
217     GstStructure *structure;
218     const gchar *profile_str;
219     GstVaapiProfile profile, best_profile;
220     GstBuffer *codec_data = NULL;
221     const gchar *name;
222     gsize namelen;
223
224     if (!caps)
225         return 0;
226
227     structure = gst_caps_get_structure(caps, 0);
228     if (!structure)
229         return 0;
230
231     name    = gst_structure_get_name(structure);
232     namelen = strlen(name);
233
234     profile_str = gst_structure_get_string(structure, "profile");
235     if (!profile_str) {
236         const GValue *v_codec_data;
237         v_codec_data = gst_structure_get_value(structure, "codec_data");
238         if (v_codec_data)
239             codec_data = gst_value_get_buffer(v_codec_data);
240     }
241
242     profile = 0;
243     best_profile = 0;
244     for (m = gst_vaapi_profiles; !profile && m->profile; m++) {
245         if (strncmp(name, m->caps_str, namelen) != 0)
246             continue;
247         caps_test = gst_caps_from_string(m->caps_str);;
248         if (gst_caps_is_always_compatible(caps, caps_test)) {
249             best_profile = m->profile;
250             if (profile_str && m->profile_str &&
251                 strcmp(profile_str, m->profile_str) == 0)
252                 profile = best_profile;
253         }
254         if (!profile) {
255             profile = gst_vaapi_profile_from_codec_data(
256                 gst_vaapi_profile_get_codec(m->profile),
257                 codec_data
258             );
259             if (!profile &&
260                 WORKAROUND_QTDEMUX_NO_H263_PROFILES &&
261                 strncmp(name, "video/x-h263", namelen) == 0) {
262                 /* HACK: qtdemux does not report profiles for h263 */
263                 profile = m->profile;
264             }
265         }
266         gst_caps_unref(caps_test);
267     }
268     return profile ? profile : best_profile;
269 }
270
271 /**
272  * gst_vaapi_profile_get_va_profile:
273  * @profile: a #GstVaapiProfile
274  *
275  * Converts a #GstVaapiProfile into the corresponding VA profile. If
276  * no matching VA profile was found, -1 is returned and this error
277  * must be reported to be fixed.
278  *
279  * Return value: the VA profile, or -1 if none was found
280  */
281 VAProfile
282 gst_vaapi_profile_get_va_profile(GstVaapiProfile profile)
283 {
284     const GstVaapiProfileMap * const m = get_profiles_map(profile);
285
286     return m ? m->va_profile : (VAProfile)-1;
287 }
288
289 /**
290  * gst_vaapi_profile_get_caps:
291  * @profile: a #GstVaapiProfile
292  *
293  * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no
294  * matching caps were found, %NULL is returned.
295  *
296  * Return value: the newly allocated #GstCaps, or %NULL if none was found
297  */
298 GstCaps *
299 gst_vaapi_profile_get_caps(GstVaapiProfile profile)
300 {
301     const GstVaapiProfileMap *m;
302     GstCaps *out_caps, *caps;
303
304     out_caps = gst_caps_new_empty();
305     if (!out_caps)
306         return NULL;
307
308     for (m = gst_vaapi_profiles; m->profile; m++) {
309         if (m->profile != profile)
310             continue;
311         caps = gst_caps_from_string(m->caps_str);
312         if (!caps)
313             continue;
314         gst_caps_set_simple(
315             caps,
316             "profile", G_TYPE_STRING, m->profile_str,
317             NULL
318         );
319         gst_caps_merge(out_caps, caps);
320     }
321     return out_caps;
322 }
323
324 /**
325  * gst_vaapi_profile_get_codec:
326  * @profile: a #GstVaapiProfile
327  *
328  * Extracts the #GstVaapiCodec from @profile.
329  *
330  * Return value: the #GstVaapiCodec from @profile
331  */
332 GstVaapiCodec
333 gst_vaapi_profile_get_codec(GstVaapiProfile profile)
334 {
335     GstVaapiCodec codec;
336
337     switch (profile) {
338     case GST_VAAPI_PROFILE_VC1_SIMPLE:
339     case GST_VAAPI_PROFILE_VC1_MAIN:
340         codec = GST_VAAPI_CODEC_WMV3;
341         break;
342     case GST_VAAPI_PROFILE_VC1_ADVANCED:
343         codec = GST_VAAPI_CODEC_VC1;
344         break;
345     case GST_VAAPI_PROFILE_JPEG_BASELINE:
346         codec = GST_VAAPI_CODEC_JPEG;
347         break;
348     default:
349         codec = (guint32)profile & GST_MAKE_FOURCC(0xff,0xff,0xff,0);
350         break;
351     }
352     return codec;
353 }
354
355 /**
356  * gst_vaapi_entrypoint:
357  * @entrypoint: a #VAEntrypoint
358  *
359  * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint.
360  * If the entry-point cannot be represented by #GstVaapiEntrypoint,
361  * then zero is returned.
362  *
363  * Return value: the #GstVaapiEntrypoint describing the @entrypoint
364  */
365 GstVaapiEntrypoint
366 gst_vaapi_entrypoint(VAEntrypoint entrypoint)
367 {
368     const GstVaapiEntrypointMap *m;
369
370     for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
371         if (m->va_entrypoint == entrypoint)
372             return m->entrypoint;
373     return 0;
374 }
375
376 /**
377  * gst_vaapi_entrypoint_get_va_entrypoint:
378  * @entrypoint: a #GstVaapiEntrypoint
379  *
380  * Converts a #GstVaapiEntrypoint into the corresponding VA
381  * entry-point. If no matching VA entry-point was found, -1 is
382  * returned and this error must be reported to be fixed.
383  *
384  * Return value: the VA entry-point, or -1 if none was found
385  */
386 VAEntrypoint
387 gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint)
388 {
389     const GstVaapiEntrypointMap * const m = get_entrypoints_map(entrypoint);
390
391     return m ? m->va_entrypoint : (VAEntrypoint)-1;
392 }