Userful gstreamer-vaapi
[vaapi:cpu-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  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2012-2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapiprofile
27  * @short_description: VA profile abstraction
28  */
29
30 #include "sysdeps.h"
31 #include <string.h>
32 #include <gst/gstbuffer.h>
33 #include "gstvaapicompat.h"
34 #include "gstvaapiprofile.h"
35 #include "gstvaapiworkarounds.h"
36
37 typedef struct _GstVaapiCodecMap                GstVaapiCodecMap;
38 typedef struct _GstVaapiProfileMap              GstVaapiProfileMap;
39 typedef struct _GstVaapiEntrypointMap           GstVaapiEntrypointMap;
40
41 struct _GstVaapiCodecMap {
42     GstVaapiCodec               codec;
43     const gchar                *name;
44 };
45
46 struct _GstVaapiProfileMap {
47     GstVaapiProfile             profile;
48     VAProfile                   va_profile;
49     const char                 *media_str;
50     const gchar                *profile_str;
51 };
52
53 struct _GstVaapiEntrypointMap {
54     GstVaapiEntrypoint          entrypoint;
55     VAEntrypoint                va_entrypoint;
56 };
57
58 /* Codecs */
59 static const GstVaapiCodecMap gst_vaapi_codecs[] = {
60     { GST_VAAPI_CODEC_MPEG1,    "mpeg1" },
61     { GST_VAAPI_CODEC_MPEG2,    "mpeg2" },
62     { GST_VAAPI_CODEC_MPEG4,    "mpeg4" },
63     { GST_VAAPI_CODEC_H263,     "h263"  },
64     { GST_VAAPI_CODEC_H264,     "h264"  },
65     { GST_VAAPI_CODEC_WMV3,     "wmv3"  },
66     { GST_VAAPI_CODEC_VC1,      "vc1"   },
67     { GST_VAAPI_CODEC_JPEG,     "jpeg"  },
68     { 0, }
69 };
70
71 /* Profiles */
72 static const GstVaapiProfileMap gst_vaapi_profiles[] = {
73     { GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple,
74       "video/mpeg, mpegversion=2", "simple"
75     },
76     { GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main,
77       "video/mpeg, mpegversion=2", "main"
78     },
79     { GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple,
80       "video/mpeg, mpegversion=4", "simple"
81     },
82     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
83       "video/mpeg, mpegversion=4", "advanced-simple"
84     },
85     { GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main,
86       "video/mpeg, mpegversion=4", "main"
87     },
88     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
89       "video/x-divx, divxversion=5", "advanced-simple"
90     },
91     { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
92       "video/x-xvid", "advanced-simple"
93     },
94 #if VA_CHECK_VERSION(0,30,0)
95     { GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline,
96       "video/x-h263, variant=itu, h263version=h263", "baseline"
97     },
98 #endif
99     { GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline,
100       "video/x-h264", "baseline"
101     },
102 #if VA_CHECK_VERSION(0,31,1)
103     { GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE,
104       VAProfileH264ConstrainedBaseline,
105       "video/x-h264", "constrained-baseline"
106     },
107 #endif
108     { GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main,
109       "video/x-h264", "main"
110     },
111     { GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High,
112       "video/x-h264", "high"
113     },
114     { GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple,
115       "video/x-wmv, wmvversion=3", "simple"
116     },
117     { GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main,
118       "video/x-wmv, wmvversion=3", "main"
119     },
120     { GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced,
121       "video/x-wmv, wmvversion=3, " GST_MAKE_FORMAT_STRING(WVC1), "advanced"
122     },
123 #if VA_CHECK_VERSION(0,32,0)
124     { GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline,
125       "image/jpeg", "baseline"
126     },
127 #endif
128     { 0, }
129 };
130
131 /* Entry-points */
132 static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = {
133     { GST_VAAPI_ENTRYPOINT_VLD,          VAEntrypointVLD        },
134     { GST_VAAPI_ENTRYPOINT_IDCT,         VAEntrypointIDCT       },
135     { GST_VAAPI_ENTRYPOINT_MOCO,         VAEntrypointMoComp     },
136 #if VA_CHECK_VERSION(0,30,0)
137     { GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice   },
138 #endif
139     { 0, }
140 };
141
142 static const GstVaapiCodecMap *
143 get_codecs_map(GstVaapiCodec codec)
144 {
145     const GstVaapiCodecMap *m;
146
147     for (m = gst_vaapi_codecs; m->codec; m++)
148         if (m->codec == codec)
149             return m;
150     return NULL;
151 }
152
153 static const GstVaapiProfileMap *
154 get_profiles_map(GstVaapiProfile profile)
155 {
156     const GstVaapiProfileMap *m;
157
158     for (m = gst_vaapi_profiles; m->profile; m++)
159         if (m->profile == profile)
160             return m;
161     return NULL;
162 }
163
164 static const GstVaapiEntrypointMap *
165 get_entrypoints_map(GstVaapiEntrypoint entrypoint)
166 {
167     const GstVaapiEntrypointMap *m;
168
169     for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
170         if (m->entrypoint == entrypoint)
171             return m;
172     return NULL;
173 }
174
175 /**
176  * gst_vaapi_codec_get_name:
177  * @codec: a #GstVaapiCodec
178  *
179  * Returns a string representation for the supplied @codec type.
180  *
181  * Return value: the statically allocated string representation of @codec
182  */
183 const gchar *
184 gst_vaapi_codec_get_name(GstVaapiCodec codec)
185 {
186     const GstVaapiCodecMap * const m = get_codecs_map(codec);
187
188     return m ? m->name : NULL;
189 }
190
191 /**
192  * gst_vaapi_profile:
193  * @profile: a #VAProfile
194  *
195  * Converts a VA profile into the corresponding #GstVaapiProfile. If
196  * the profile cannot be represented by #GstVaapiProfile, then zero is
197  * returned.
198  *
199  * Return value: the #GstVaapiProfile describing the @profile
200  */
201 GstVaapiProfile
202 gst_vaapi_profile(VAProfile profile)
203 {
204     const GstVaapiProfileMap *m;
205
206     for (m = gst_vaapi_profiles; m->profile; m++)
207         if (m->va_profile == profile)
208             return m->profile;
209     return 0;
210 }
211
212 /**
213  * gst_vaapi_profile_get_name:
214  * @profile: a #GstVaapiProfile
215  *
216  * Returns a string representation for the supplied @profile.
217  *
218  * Return value: the statically allocated string representation of @profile
219  */
220 const gchar *
221 gst_vaapi_profile_get_name(GstVaapiProfile profile)
222 {
223     const GstVaapiProfileMap * const m = get_profiles_map(profile);
224
225     return m ? m->profile_str : NULL;
226 }
227
228 /**
229  * gst_vaapi_profile_get_media_type_name:
230  * @profile: a #GstVaapiProfile
231  *
232  * Returns a string representation for the media type of the supplied
233  * @profile.
234  *
235  * Return value: the statically allocated string representation of
236  *   @profile media type
237  */
238 const gchar *
239 gst_vaapi_profile_get_media_type_name(GstVaapiProfile profile)
240 {
241     const GstVaapiProfileMap * const m = get_profiles_map(profile);
242
243     return m ? m->media_str : NULL;
244 }
245
246 /**
247  * gst_vaapi_profile_from_codec_data:
248  * @codec: a #GstVaapiCodec
249  * @buffer: a #GstBuffer holding code data
250  *
251  * Tries to parse VA profile from @buffer data and @codec information.
252  *
253  * Return value: the #GstVaapiProfile described in @buffer
254  */
255 static GstVaapiProfile
256 gst_vaapi_profile_from_codec_data_h264(GstBuffer *buffer)
257 {
258     /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */
259     guchar buf[3];
260
261     if (gst_buffer_extract(buffer, 0, buf, sizeof(buf)) != sizeof(buf))
262         return 0;
263
264     if (buf[0] != 1)    /* configurationVersion = 1 */
265         return 0;
266
267     switch (buf[1]) {   /* AVCProfileIndication */
268     case 66:    return ((buf[2] & 0x40) ?
269                         GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE :
270                         GST_VAAPI_PROFILE_H264_BASELINE);
271     case 77:    return GST_VAAPI_PROFILE_H264_MAIN;
272     case 100:   return GST_VAAPI_PROFILE_H264_HIGH;
273     }
274     return 0;
275 }
276
277 static GstVaapiProfile
278 gst_vaapi_profile_from_codec_data(GstVaapiCodec codec, GstBuffer *buffer)
279 {
280     GstVaapiProfile profile;
281
282     if (!codec || !buffer)
283         return 0;
284
285     switch (codec) {
286     case GST_VAAPI_CODEC_H264:
287         profile = gst_vaapi_profile_from_codec_data_h264(buffer);
288         break;
289     default:
290         profile = 0;
291         break;
292     }
293     return profile;
294 }
295
296 /**
297  * gst_vaapi_profile_from_caps:
298  * @caps: a #GstCaps
299  *
300  * Converts @caps into the corresponding #GstVaapiProfile. If the
301  * profile cannot be represented by #GstVaapiProfile, then zero is
302  * returned.
303  *
304  * Return value: the #GstVaapiProfile describing the @caps
305  */
306 GstVaapiProfile
307 gst_vaapi_profile_from_caps(const GstCaps *caps)
308 {
309     const GstVaapiProfileMap *m;
310     GstCaps *caps_test;
311     GstStructure *structure;
312     const gchar *profile_str;
313     GstVaapiProfile profile, best_profile;
314     GstBuffer *codec_data = NULL;
315     const gchar *name;
316     gsize namelen;
317
318     if (!caps)
319         return 0;
320
321     structure = gst_caps_get_structure(caps, 0);
322     if (!structure)
323         return 0;
324
325     name    = gst_structure_get_name(structure);
326     namelen = strlen(name);
327
328     profile_str = gst_structure_get_string(structure, "profile");
329     if (!profile_str) {
330         const GValue *v_codec_data;
331         v_codec_data = gst_structure_get_value(structure, "codec_data");
332         if (v_codec_data)
333             codec_data = gst_value_get_buffer(v_codec_data);
334     }
335
336     profile = 0;
337     best_profile = 0;
338     for (m = gst_vaapi_profiles; !profile && m->profile; m++) {
339         if (strncmp(name, m->media_str, namelen) != 0)
340             continue;
341         caps_test = gst_caps_from_string(m->media_str);
342         if (gst_caps_is_always_compatible(caps, caps_test)) {
343             best_profile = m->profile;
344             if (profile_str && m->profile_str &&
345                 strcmp(profile_str, m->profile_str) == 0)
346                 profile = best_profile;
347         }
348         if (!profile) {
349             profile = gst_vaapi_profile_from_codec_data(
350                 gst_vaapi_profile_get_codec(m->profile),
351                 codec_data
352             );
353             if (!profile &&
354                 WORKAROUND_QTDEMUX_NO_H263_PROFILES &&
355                 strncmp(name, "video/x-h263", namelen) == 0) {
356                 /* HACK: qtdemux does not report profiles for h263 */
357                 profile = m->profile;
358             }
359         }
360         gst_caps_unref(caps_test);
361     }
362     return profile ? profile : best_profile;
363 }
364
365 /**
366  * gst_vaapi_profile_get_va_profile:
367  * @profile: a #GstVaapiProfile
368  *
369  * Converts a #GstVaapiProfile into the corresponding VA profile. If
370  * no matching VA profile was found, -1 is returned and this error
371  * must be reported to be fixed.
372  *
373  * Return value: the VA profile, or -1 if none was found
374  */
375 VAProfile
376 gst_vaapi_profile_get_va_profile(GstVaapiProfile profile)
377 {
378     const GstVaapiProfileMap * const m = get_profiles_map(profile);
379
380     return m ? m->va_profile : (VAProfile)-1;
381 }
382
383 /**
384  * gst_vaapi_profile_get_caps:
385  * @profile: a #GstVaapiProfile
386  *
387  * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no
388  * matching caps were found, %NULL is returned.
389  *
390  * Return value: the newly allocated #GstCaps, or %NULL if none was found
391  */
392 GstCaps *
393 gst_vaapi_profile_get_caps(GstVaapiProfile profile)
394 {
395     const GstVaapiProfileMap *m;
396     GstCaps *out_caps, *caps;
397
398     out_caps = gst_caps_new_empty();
399     if (!out_caps)
400         return NULL;
401
402     for (m = gst_vaapi_profiles; m->profile; m++) {
403         if (m->profile != profile)
404             continue;
405         caps = gst_caps_from_string(m->media_str);
406         if (!caps)
407             continue;
408         gst_caps_set_simple(
409             caps,
410             "profile", G_TYPE_STRING, m->profile_str,
411             NULL
412         );
413         out_caps = gst_caps_merge(out_caps, caps);
414     }
415     return out_caps;
416 }
417
418 /**
419  * gst_vaapi_profile_get_codec:
420  * @profile: a #GstVaapiProfile
421  *
422  * Extracts the #GstVaapiCodec from @profile.
423  *
424  * Return value: the #GstVaapiCodec from @profile
425  */
426 GstVaapiCodec
427 gst_vaapi_profile_get_codec(GstVaapiProfile profile)
428 {
429     GstVaapiCodec codec;
430
431     switch (profile) {
432     case GST_VAAPI_PROFILE_VC1_SIMPLE:
433     case GST_VAAPI_PROFILE_VC1_MAIN:
434         codec = GST_VAAPI_CODEC_WMV3;
435         break;
436     case GST_VAAPI_PROFILE_VC1_ADVANCED:
437         codec = GST_VAAPI_CODEC_VC1;
438         break;
439     case GST_VAAPI_PROFILE_JPEG_BASELINE:
440         codec = GST_VAAPI_CODEC_JPEG;
441         break;
442     default:
443         codec = (guint32)profile & GST_MAKE_FOURCC(0xff,0xff,0xff,0);
444         break;
445     }
446     return codec;
447 }
448
449 /**
450  * gst_vaapi_entrypoint:
451  * @entrypoint: a #VAEntrypoint
452  *
453  * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint.
454  * If the entry-point cannot be represented by #GstVaapiEntrypoint,
455  * then zero is returned.
456  *
457  * Return value: the #GstVaapiEntrypoint describing the @entrypoint
458  */
459 GstVaapiEntrypoint
460 gst_vaapi_entrypoint(VAEntrypoint entrypoint)
461 {
462     const GstVaapiEntrypointMap *m;
463
464     for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
465         if (m->va_entrypoint == entrypoint)
466             return m->entrypoint;
467     return 0;
468 }
469
470 /**
471  * gst_vaapi_entrypoint_get_va_entrypoint:
472  * @entrypoint: a #GstVaapiEntrypoint
473  *
474  * Converts a #GstVaapiEntrypoint into the corresponding VA
475  * entry-point. If no matching VA entry-point was found, -1 is
476  * returned and this error must be reported to be fixed.
477  *
478  * Return value: the VA entry-point, or -1 if none was found
479  */
480 VAEntrypoint
481 gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint)
482 {
483     const GstVaapiEntrypointMap * const m = get_entrypoints_map(entrypoint);
484
485     return m ? m->va_entrypoint : (VAEntrypoint)-1;
486 }