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