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 <gst/gstbuffer.h>
32 #include "gstvaapicompat.h"
33 #include "gstvaapiprofile.h"
34 #include "gstvaapiworkarounds.h"
35 
36 typedef struct _GstVaapiCodecMap GstVaapiCodecMap;
37 typedef struct _GstVaapiProfileMap GstVaapiProfileMap;
38 typedef struct _GstVaapiEntrypointMap GstVaapiEntrypointMap;
39 
40 struct _GstVaapiCodecMap
41 {
42   GstVaapiCodec codec;
43   const gchar *name;
44 };
45 
46 struct _GstVaapiProfileMap
47 {
48   GstVaapiProfile profile;
49   VAProfile va_profile;
50   const char *media_str;
51   const gchar *profile_str;
52 };
53 
54 struct _GstVaapiEntrypointMap
55 {
56   GstVaapiEntrypoint entrypoint;
57   VAEntrypoint va_entrypoint;
58 };
59 
60 /* Codecs */
61 static const GstVaapiCodecMap gst_vaapi_codecs[] = {
62   {GST_VAAPI_CODEC_MPEG1, "mpeg1"},
63   {GST_VAAPI_CODEC_MPEG2, "mpeg2"},
64   {GST_VAAPI_CODEC_MPEG4, "mpeg4"},
65   {GST_VAAPI_CODEC_H263, "h263"},
66   {GST_VAAPI_CODEC_H264, "h264"},
67   {GST_VAAPI_CODEC_WMV3, "wmv3"},
68   {GST_VAAPI_CODEC_VC1, "vc1"},
69   {GST_VAAPI_CODEC_JPEG, "jpeg"},
70   {GST_VAAPI_CODEC_VP8, "vp8"},
71   {GST_VAAPI_CODEC_H265, "h265"},
72   {GST_VAAPI_CODEC_VP9, "vp9"},
73   {0,}
74 };
75 
76 /* Profiles */
77 static const GstVaapiProfileMap gst_vaapi_profiles[] = {
78   {GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple,
79       "video/mpeg, mpegversion=2", "simple"},
80   {GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main,
81       "video/mpeg, mpegversion=2", "main"},
82   {GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple,
83       "video/mpeg, mpegversion=4", "simple"},
84   {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
85       "video/mpeg, mpegversion=4", "advanced-simple"},
86   {GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main,
87       "video/mpeg, mpegversion=4", "main"},
88   {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
89       "video/x-divx, divxversion=5", "advanced-simple"},
90   {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
91       "video/x-xvid", "advanced-simple"},
92   {GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline,
93       "video/x-h263, variant=itu, h263version=h263", "baseline"},
94 #if !VA_CHECK_VERSION(1,0,0)
95   {GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline,
96       "video/x-h264", "baseline"},
97 #endif
98   {GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE,
99         VAProfileH264ConstrainedBaseline,
100       "video/x-h264", "constrained-baseline"},
101   {GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main,
102       "video/x-h264", "main"},
103   {GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High,
104       "video/x-h264", "high"},
105   {GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, VAProfileH264MultiviewHigh,
106       "video/x-h264", "multiview-high"},
107   {GST_VAAPI_PROFILE_H264_STEREO_HIGH, VAProfileH264StereoHigh,
108       "video/x-h264", "stereo-high"},
109   {GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple,
110       "video/x-wmv, wmvversion=3", "simple"},
111   {GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main,
112       "video/x-wmv, wmvversion=3", "main"},
113   {GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced,
114       "video/x-wmv, wmvversion=3, format=(string)WVC1", "advanced"},
115   {GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline,
116       "image/jpeg", NULL},
117   {GST_VAAPI_PROFILE_VP8, VAProfileVP8Version0_3,
118       "video/x-vp8", NULL},
119   {GST_VAAPI_PROFILE_H265_MAIN, VAProfileHEVCMain,
120       "video/x-h265", "main"},
121   {GST_VAAPI_PROFILE_H265_MAIN10, VAProfileHEVCMain10,
122       "video/x-h265", "main-10"},
123 #if VA_CHECK_VERSION(1,2,0)
124   {GST_VAAPI_PROFILE_H265_MAIN_422_10, VAProfileHEVCMain422_10,
125       "video/x-h265", "main-422-10"},
126   {GST_VAAPI_PROFILE_H265_MAIN_444, VAProfileHEVCMain444,
127       "video/x-h265", "main-444"},
128   {GST_VAAPI_PROFILE_H265_MAIN_444_10, VAProfileHEVCMain444_10,
129       "video/x-h265", "main-444-10"},
130 #endif
131   {GST_VAAPI_PROFILE_VP9_0, VAProfileVP9Profile0,
132       "video/x-vp9", "profile0"},
133   {GST_VAAPI_PROFILE_VP9_1, VAProfileVP9Profile1,
134       "video/x-vp9", "profile1"},
135   {GST_VAAPI_PROFILE_VP9_2, VAProfileVP9Profile2,
136       "video/x-vp9", "profile2"},
137   {GST_VAAPI_PROFILE_VP9_3, VAProfileVP9Profile3,
138       "video/x-vp9", "profile3"},
139   {0,}
140 };
141 
142 /* Entry-points */
143 static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = {
144   {GST_VAAPI_ENTRYPOINT_VLD, VAEntrypointVLD},
145   {GST_VAAPI_ENTRYPOINT_IDCT, VAEntrypointIDCT},
146   {GST_VAAPI_ENTRYPOINT_MOCO, VAEntrypointMoComp},
147   {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice},
148   {GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE, VAEntrypointEncPicture},
149 #if VA_CHECK_VERSION(0,39,1)
150   {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP, VAEntrypointEncSliceLP},
151 #endif
152 #if USE_H264_FEI_ENCODER
153   {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI, VAEntrypointFEI},
154 #endif
155   {0,}
156 };
157 
158 static const GstVaapiCodecMap *
get_codecs_map(GstVaapiCodec codec)159 get_codecs_map (GstVaapiCodec codec)
160 {
161   const GstVaapiCodecMap *m;
162 
163   for (m = gst_vaapi_codecs; m->codec; m++)
164     if (m->codec == codec)
165       return m;
166   return NULL;
167 }
168 
169 static const GstVaapiProfileMap *
get_profiles_map(GstVaapiProfile profile)170 get_profiles_map (GstVaapiProfile profile)
171 {
172   const GstVaapiProfileMap *m;
173 
174   for (m = gst_vaapi_profiles; m->profile; m++)
175     if (m->profile == profile)
176       return m;
177   return NULL;
178 }
179 
180 static const GstVaapiEntrypointMap *
get_entrypoints_map(GstVaapiEntrypoint entrypoint)181 get_entrypoints_map (GstVaapiEntrypoint entrypoint)
182 {
183   const GstVaapiEntrypointMap *m;
184 
185   for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
186     if (m->entrypoint == entrypoint)
187       return m;
188   return NULL;
189 }
190 
191 /**
192  * gst_vaapi_codec_get_name:
193  * @codec: a #GstVaapiCodec
194  *
195  * Returns a string representation for the supplied @codec type.
196  *
197  * Return value: the statically allocated string representation of @codec
198  */
199 const gchar *
gst_vaapi_codec_get_name(GstVaapiCodec codec)200 gst_vaapi_codec_get_name (GstVaapiCodec codec)
201 {
202   const GstVaapiCodecMap *const m = get_codecs_map (codec);
203 
204   return m ? m->name : NULL;
205 }
206 
207 /**
208  * gst_vaapi_profile:
209  * @profile: a #VAProfile
210  *
211  * Converts a VA profile into the corresponding #GstVaapiProfile. If
212  * the profile cannot be represented by #GstVaapiProfile, then zero is
213  * returned.
214  *
215  * Return value: the #GstVaapiProfile describing the @profile
216  */
217 GstVaapiProfile
gst_vaapi_profile(VAProfile profile)218 gst_vaapi_profile (VAProfile profile)
219 {
220   const GstVaapiProfileMap *m;
221 
222   for (m = gst_vaapi_profiles; m->profile; m++)
223     if (m->va_profile == profile)
224       return m->profile;
225   return 0;
226 }
227 
228 /**
229  * gst_vaapi_profile_get_name:
230  * @profile: a #GstVaapiProfile
231  *
232  * Returns a string representation for the supplied @profile.
233  *
234  * Return value: the statically allocated string representation of @profile
235  */
236 const gchar *
gst_vaapi_profile_get_name(GstVaapiProfile profile)237 gst_vaapi_profile_get_name (GstVaapiProfile profile)
238 {
239   const GstVaapiProfileMap *const m = get_profiles_map (profile);
240 
241   return m ? m->profile_str : NULL;
242 }
243 
244 /**
245  * gst_vaapi_profile_get_media_type_name:
246  * @profile: a #GstVaapiProfile
247  *
248  * Returns a string representation for the media type of the supplied
249  * @profile.
250  *
251  * Return value: the statically allocated string representation of
252  *   @profile media type
253  */
254 const gchar *
gst_vaapi_profile_get_media_type_name(GstVaapiProfile profile)255 gst_vaapi_profile_get_media_type_name (GstVaapiProfile profile)
256 {
257   const GstVaapiProfileMap *const m = get_profiles_map (profile);
258 
259   return m ? m->media_str : NULL;
260 }
261 
262 /**
263  * gst_vaapi_profile_from_codec_data:
264  * @codec: a #GstVaapiCodec
265  * @buffer: a #GstBuffer holding code data
266  *
267  * Tries to parse VA profile from @buffer data and @codec information.
268  *
269  * Return value: the #GstVaapiProfile described in @buffer
270  */
271 static GstVaapiProfile
gst_vaapi_profile_from_codec_data_h264(GstBuffer * buffer)272 gst_vaapi_profile_from_codec_data_h264 (GstBuffer * buffer)
273 {
274   /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */
275   guchar buf[3];
276 
277   if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf))
278     return 0;
279 
280   if (buf[0] != 1)              /* configurationVersion = 1 */
281     return 0;
282 
283   switch (buf[1]) {             /* AVCProfileIndication */
284     case 66:
285       return ((buf[2] & 0x40) ?
286           GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE :
287           GST_VAAPI_PROFILE_H264_BASELINE);
288     case 77:
289       return GST_VAAPI_PROFILE_H264_MAIN;
290     case 100:
291       return GST_VAAPI_PROFILE_H264_HIGH;
292     case 118:
293       return GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
294     case 128:
295       return GST_VAAPI_PROFILE_H264_STEREO_HIGH;
296 
297   }
298   return 0;
299 }
300 
301 static GstVaapiProfile
gst_vaapi_profile_from_codec_data_h265(GstBuffer * buffer)302 gst_vaapi_profile_from_codec_data_h265 (GstBuffer * buffer)
303 {
304   /* ISO/IEC 14496-15:  HEVC file format */
305   guchar buf[3];
306 
307   if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf))
308     return 0;
309 
310   if (buf[0] != 1)              /* configurationVersion = 1 */
311     return 0;
312 
313   if (buf[1] & 0xc0)            /* general_profile_space = 0 */
314     return 0;
315 
316   switch (buf[1] & 0x1f) {      /* HEVCProfileIndication */
317     case 1:
318       return GST_VAAPI_PROFILE_H265_MAIN;
319     case 2:
320       return GST_VAAPI_PROFILE_H265_MAIN10;
321     case 3:
322       return GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE;
323     case 4:
324       return GST_VAAPI_PROFILE_H265_MAIN_422_10;
325     case 5:
326       return GST_VAAPI_PROFILE_H265_MAIN_444;
327   }
328   return 0;
329 }
330 
331 static GstVaapiProfile
gst_vaapi_profile_from_codec_data(GstVaapiCodec codec,GstBuffer * buffer)332 gst_vaapi_profile_from_codec_data (GstVaapiCodec codec, GstBuffer * buffer)
333 {
334   GstVaapiProfile profile;
335 
336   if (!codec || !buffer)
337     return 0;
338 
339   switch (codec) {
340     case GST_VAAPI_CODEC_H264:
341       profile = gst_vaapi_profile_from_codec_data_h264 (buffer);
342       break;
343     case GST_VAAPI_CODEC_H265:
344       profile = gst_vaapi_profile_from_codec_data_h265 (buffer);
345       break;
346     default:
347       profile = 0;
348       break;
349   }
350   return profile;
351 }
352 
353 /**
354  * gst_vaapi_profile_from_caps:
355  * @caps: a #GstCaps
356  *
357  * Converts @caps into the corresponding #GstVaapiProfile. If the
358  * profile cannot be represented by #GstVaapiProfile, then zero is
359  * returned.
360  *
361  * Return value: the #GstVaapiProfile describing the @caps
362  */
363 GstVaapiProfile
gst_vaapi_profile_from_caps(const GstCaps * caps)364 gst_vaapi_profile_from_caps (const GstCaps * caps)
365 {
366   const GstVaapiProfileMap *m;
367   GstCaps *caps_test;
368   GstStructure *structure;
369   const gchar *profile_str;
370   GstVaapiProfile profile, best_profile;
371   GstBuffer *codec_data = NULL;
372   const gchar *name;
373   gsize namelen;
374 
375   if (!caps)
376     return 0;
377 
378   structure = gst_caps_get_structure (caps, 0);
379   if (!structure)
380     return 0;
381 
382   name = gst_structure_get_name (structure);
383   namelen = strlen (name);
384 
385   profile_str = gst_structure_get_string (structure, "profile");
386   if (!profile_str) {
387     const GValue *v_codec_data;
388     v_codec_data = gst_structure_get_value (structure, "codec_data");
389     if (v_codec_data)
390       codec_data = gst_value_get_buffer (v_codec_data);
391   }
392 
393   profile = 0;
394   best_profile = 0;
395   for (m = gst_vaapi_profiles; !profile && m->profile; m++) {
396     if (strncmp (name, m->media_str, namelen) != 0)
397       continue;
398     caps_test = gst_caps_from_string (m->media_str);
399     if (gst_caps_is_always_compatible (caps, caps_test)) {
400       best_profile = m->profile;
401       if (profile_str && m->profile_str &&
402           strcmp (profile_str, m->profile_str) == 0)
403         profile = best_profile;
404     }
405     if (!profile) {
406       profile =
407           gst_vaapi_profile_from_codec_data (gst_vaapi_profile_get_codec
408           (m->profile), codec_data);
409       if (!profile && WORKAROUND_QTDEMUX_NO_H263_PROFILES
410           && strncmp (name, "video/x-h263", namelen) == 0) {
411         /* HACK: qtdemux does not report profiles for h263 */
412         profile = m->profile;
413       }
414     }
415     gst_caps_unref (caps_test);
416   }
417   return profile ? profile : best_profile;
418 }
419 
420 /**
421  * gst_vaapi_profile_get_va_profile:
422  * @profile: a #GstVaapiProfile
423  *
424  * Converts a #GstVaapiProfile into the corresponding VA profile. If
425  * no matching VA profile was found, -1 is returned and this error
426  * must be reported to be fixed.
427  *
428  * Return value: the VA profile, or -1 if none was found
429  */
430 VAProfile
gst_vaapi_profile_get_va_profile(GstVaapiProfile profile)431 gst_vaapi_profile_get_va_profile (GstVaapiProfile profile)
432 {
433   const GstVaapiProfileMap *const m = get_profiles_map (profile);
434 
435   return m ? m->va_profile : (VAProfile) - 1;
436 }
437 
438 /**
439  * gst_vaapi_profile_get_caps:
440  * @profile: a #GstVaapiProfile
441  *
442  * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no
443  * matching caps were found, %NULL is returned.
444  *
445  * Return value: the newly allocated #GstCaps, or %NULL if none was found
446  */
447 GstCaps *
gst_vaapi_profile_get_caps(GstVaapiProfile profile)448 gst_vaapi_profile_get_caps (GstVaapiProfile profile)
449 {
450   const GstVaapiProfileMap *m;
451   GstCaps *out_caps, *caps;
452 
453   out_caps = gst_caps_new_empty ();
454   if (!out_caps)
455     return NULL;
456 
457   for (m = gst_vaapi_profiles; m->profile; m++) {
458     if (m->profile != profile)
459       continue;
460     caps = gst_caps_from_string (m->media_str);
461     if (!caps)
462       continue;
463     gst_caps_set_simple (caps, "profile", G_TYPE_STRING, m->profile_str, NULL);
464     out_caps = gst_caps_merge (out_caps, caps);
465   }
466   return out_caps;
467 }
468 
469 /**
470  * gst_vaapi_profile_get_codec:
471  * @profile: a #GstVaapiProfile
472  *
473  * Extracts the #GstVaapiCodec from @profile.
474  *
475  * Return value: the #GstVaapiCodec from @profile
476  */
477 GstVaapiCodec
gst_vaapi_profile_get_codec(GstVaapiProfile profile)478 gst_vaapi_profile_get_codec (GstVaapiProfile profile)
479 {
480   GstVaapiCodec codec;
481 
482   switch (profile) {
483     case GST_VAAPI_PROFILE_VC1_SIMPLE:
484     case GST_VAAPI_PROFILE_VC1_MAIN:
485       codec = GST_VAAPI_CODEC_WMV3;
486       break;
487     case GST_VAAPI_PROFILE_VC1_ADVANCED:
488       codec = GST_VAAPI_CODEC_VC1;
489       break;
490     case GST_VAAPI_PROFILE_JPEG_BASELINE:
491       codec = GST_VAAPI_CODEC_JPEG;
492       break;
493     default:
494       codec = (guint32) profile & GST_MAKE_FOURCC (0xff, 0xff, 0xff, 0);
495       break;
496   }
497   return codec;
498 }
499 
500 /**
501  * gst_vaapi_entrypoint:
502  * @entrypoint: a #VAEntrypoint
503  *
504  * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint.
505  * If the entry-point cannot be represented by #GstVaapiEntrypoint,
506  * then zero is returned.
507  *
508  * Return value: the #GstVaapiEntrypoint describing the @entrypoint
509  */
510 GstVaapiEntrypoint
gst_vaapi_entrypoint(VAEntrypoint entrypoint)511 gst_vaapi_entrypoint (VAEntrypoint entrypoint)
512 {
513   const GstVaapiEntrypointMap *m;
514 
515   for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
516     if (m->va_entrypoint == entrypoint)
517       return m->entrypoint;
518   return 0;
519 }
520 
521 /**
522  * gst_vaapi_entrypoint_get_va_entrypoint:
523  * @entrypoint: a #GstVaapiEntrypoint
524  *
525  * Converts a #GstVaapiEntrypoint into the corresponding VA
526  * entry-point. If no matching VA entry-point was found, -1 is
527  * returned and this error must be reported to be fixed.
528  *
529  * Return value: the VA entry-point, or -1 if none was found
530  */
531 VAEntrypoint
gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint)532 gst_vaapi_entrypoint_get_va_entrypoint (GstVaapiEntrypoint entrypoint)
533 {
534   const GstVaapiEntrypointMap *const m = get_entrypoints_map (entrypoint);
535 
536   return m ? m->va_entrypoint : (VAEntrypoint) - 1;
537 }
538