tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / gst-libs / gst / pbutils / codec-utils.c
1 /* GStreamer base utils library codec-specific utility functions
2  * Copyright (C) 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
3  *               2010 Collabora Multimedia
4  *               2010 Nokia Corporation
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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstpbutilscodecutils
24  * @short_description: Miscellaneous codec-specific utility functions
25  *
26  * <refsect2>
27  * <para>
28  * Provides codec-specific ulility functions such as functions to provide the
29  * codec profile and level in human-readable string form from header data.
30  * </para>
31  * </refsect2>
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "pbutils.h"
39
40 #include <string.h>
41
42 #define GST_SIMPLE_CAPS_HAS_NAME(caps,name) \
43     gst_structure_has_name(gst_caps_get_structure((caps),0),(name))
44
45 #define GST_SIMPLE_CAPS_HAS_FIELD(caps,field) \
46     gst_structure_has_field(gst_caps_get_structure((caps),0),(field))
47
48 static const gchar *
49 digit_to_string (guint digit)
50 {
51   static const char itoa[][2] = {
52     "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
53   };
54
55   if (G_LIKELY (digit < 10))
56     return itoa[digit];
57   else
58     return NULL;
59 }
60
61 /**
62  * gst_codec_utils_aac_get_sample_rate_from_index:
63  * @sr_idx: Sample rate index as from the AudioSpecificConfig (MPEG-4
64  *          container) or ADTS frame header
65  *
66  * Translates the sample rate index found in AAC headers to the actual sample
67  * rate.
68  *
69  * Returns: The sample rate if @sr_idx is valid, 0 otherwise.
70  *
71  * Since: 0.10.31
72  */
73 guint
74 gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx)
75 {
76   static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
77     32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
78   };
79
80   if (G_LIKELY (sr_idx < G_N_ELEMENTS (aac_sample_rates)))
81     return aac_sample_rates[sr_idx];
82
83   GST_WARNING ("Invalid sample rate index %u", sr_idx);
84   return 0;
85 }
86
87 /**
88  * gst_codec_utils_aac_get_profile:
89  * @audio_config: a pointer to the AudioSpecificConfig as specified in the
90  *                Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
91  *                gst_codec_utils_aac_get_level() for a more details).
92  * @len: Length of @audio_config in bytes
93  *
94  * Returns the profile of the given AAC stream as a string. The profile is
95  * determined using the AudioObjectType field which is in the first 5 bits of
96  * @audio_config.
97  *
98  * <note>
99  * HE-AAC support has not yet been implemented.
100  * </note>
101  *
102  * Returns: The profile as a const string and %NULL if the profile could not be
103  * determined.
104  *
105  * Since: 0.10.31
106  */
107 const gchar *
108 gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len)
109 {
110   guint profile;
111
112   if (len < 1)
113     return NULL;
114
115   GST_MEMDUMP ("audio config", audio_config, len);
116
117   profile = audio_config[0] >> 3;
118   switch (profile) {
119     case 1:
120       return "main";
121     case 2:
122       return "lc";
123     case 3:
124       return "ssr";
125     case 4:
126       return "ltp";
127     default:
128       break;
129   }
130
131   GST_DEBUG ("Invalid profile idx: %u", profile);
132   return NULL;
133 }
134
135 /**
136  * gst_codec_utils_aac_get_level:
137  * @audio_config: a pointer to the AudioSpecificConfig as specified in the
138  *                Elementary Stream Descriptor (esds) in ISO/IEC 14496-1.
139  * @len: Length of @audio_config in bytes
140  *
141  * Determines the level of a stream as defined in ISO/IEC 14496-3. For AAC LC
142  * streams, the constraints from the AAC audio profile are applied. For AAC
143  * Main, LTP, SSR and others, the Main profile is used.
144  *
145  * The @audio_config parameter follows the following format, starting from the
146  * most significant bit of the first byte:
147  *
148  * <itemizedlist>
149  *   <listitem><para>
150  *     Bit 0:4 contains the AudioObjectType
151  *   </para></listitem>
152  *   <listitem><para>
153  *     Bit 5:8 contains the sample frequency index (if this is 0xf, then the
154  *             next 24 bits define the actual sample frequency, and subsequent
155  *             fields are appropriately shifted).
156  *    </para></listitem>
157  *   <listitem><para>
158  *     Bit 9:12 contains the channel configuration
159  *   </para></listitem>
160  * </itemizedlist>
161  *
162  * <note>
163  * HE-AAC support has not yet been implemented.
164  * </note>
165  *
166  * Returns: The level as a const string and %NULL if the level could not be
167  * determined.
168  *
169  * Since: 0.10.31
170  */
171 const gchar *
172 gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len)
173 {
174   int profile, sr_idx, channel_config, rate;
175   /* Number of single channel elements, channel pair elements, low frequency
176    * elements, independently switched coupling channel elements, and
177    * dependently switched coupling channel elements.
178    *
179    * Note: The 2 CCE types are ignored for now as they require us to actually
180    * parse the first frame, and they are rarely found in actual streams.
181    */
182   int num_sce = 0, num_cpe = 0, num_lfe = 0, num_cce_indep = 0, num_cce_dep = 0;
183   int num_channels;
184   /* Processor and RAM Complexity Units (calculated and "reference" for single
185    * channel) */
186   int pcu, rcu, pcu_ref, rcu_ref;
187   int ret = -1;
188
189   g_return_val_if_fail (audio_config != NULL, NULL);
190
191   if (len < 2)
192     return NULL;
193
194   GST_MEMDUMP ("audio config", audio_config, len);
195
196   profile = audio_config[0] >> 3;
197   /* FIXME: add support for sr_idx = 0xf */
198   sr_idx = ((audio_config[0] & 0x7) << 1) | ((audio_config[1] & 0x80) >> 7);
199   rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
200   channel_config = (audio_config[1] & 0x7f) >> 3;
201
202   if (rate == 0)
203     return NULL;
204
205   switch (channel_config) {
206     case 0:
207       /* Channel config is defined in the AudioObjectType's SpecificConfig,
208        * which requires some amount of digging through the headers. I only see
209        * this done in the MPEG conformance streams - FIXME */
210       GST_WARNING ("Found a stream with channel configuration in the "
211           "AudioSpecificConfig. Please file a bug with a link to the media if "
212           "possible.");
213       return NULL;
214     case 1:
215       /* front center */
216       num_sce = 1;
217       break;
218     case 2:
219       /* front left and right */
220       num_cpe = 1;
221       break;
222     case 3:
223       /* front left, right, and center */
224       num_sce = 1;
225       num_cpe = 1;
226       break;
227     case 4:
228       /* front left, right, and center; rear surround */
229       num_sce = 2;
230       num_cpe = 1;
231       break;
232     case 5:
233       /* front left, right, and center; rear left and right surround */
234       num_sce = 1;
235       num_cpe = 2;
236       break;
237     case 6:
238       /* front left, right, center and LFE; rear left and right surround */
239       num_sce = 1;
240       num_cpe = 2;
241       break;
242     case 7:
243       /* front left, right, center and LFE; outside front left and right;
244        * rear left and right surround */
245       num_sce = 1;
246       num_cpe = 3;
247       num_lfe = 1;
248       break;
249     default:
250       GST_WARNING ("Unknown channel config in header: %d", channel_config);
251       return NULL;
252   }
253
254   switch (profile) {
255     case 0:                    /* NULL */
256       GST_WARNING ("profile 0 is not a valid profile");
257       return NULL;
258     case 2:                    /* LC */
259       pcu_ref = 3;
260       rcu_ref = 3;
261       break;
262     case 3:                    /* SSR */
263       pcu_ref = 4;
264       rcu_ref = 3;
265       break;
266     case 4:                    /* LTP */
267       pcu_ref = 4;
268       rcu_ref = 4;
269       break;
270     case 1:                    /* Main */
271     default:
272       /* Other than a couple of ER profiles, Main is the worst-case */
273       pcu_ref = 5;
274       rcu_ref = 5;
275       break;
276   }
277
278   /* "fs_ref" is 48000 Hz for AAC Main/LC/SSR/LTP. SBR's fs_ref is defined as
279    * 24000/48000 (in/out), for SBR streams. Actual support is a FIXME */
280
281   pcu = ((float) rate / 48000) * pcu_ref *
282       ((2 * num_cpe) + num_sce + num_lfe + num_cce_indep + (0.3 * num_cce_dep));
283
284   rcu = ((float) rcu_ref) * (num_sce + (0.5 * num_lfe) + (0.5 * num_cce_indep) +
285       (0.4 * num_cce_dep));
286
287   if (num_cpe < 2)
288     rcu += (rcu_ref + (rcu_ref - 1)) * num_cpe;
289   else
290     rcu += (rcu_ref + (rcu_ref - 1) * ((2 * num_cpe) - 1));
291
292   num_channels = num_sce + (2 * num_cpe) + num_lfe;
293
294   if (profile == 2) {
295     /* AAC LC => return the level as per the 'AAC Profile' */
296     if (num_channels <= 2 && rate <= 24000 && pcu <= 3 && rcu <= 5)
297       ret = 1;
298     else if (num_channels <= 2 && rate <= 48000 && pcu <= 6 && rcu <= 5)
299       ret = 2;
300     /* There is no level 3 for the AAC Profile */
301     else if (num_channels <= 5 && rate <= 48000 && pcu <= 19 && rcu <= 15)
302       ret = 4;
303     else if (num_channels <= 5 && rate <= 96000 && pcu <= 38 && rcu <= 15)
304       ret = 5;
305   } else {
306     /* Return the level as per the 'Main Profile' */
307     if (pcu < 40 && rcu < 20)
308       ret = 1;
309     else if (pcu < 80 && rcu < 64)
310       ret = 2;
311     else if (pcu < 160 && rcu < 128)
312       ret = 3;
313     else if (pcu < 320 && rcu < 256)
314       ret = 4;
315   }
316
317   if (ret == -1) {
318     GST_WARNING ("couldn't determine level: profile=%u, rate=%u, "
319         "channel_config=%u, pcu=%d,rcu=%d", profile, rate, channel_config, pcu,
320         rcu);
321     return NULL;
322   } else {
323     return digit_to_string (ret);
324   }
325 }
326
327 /**
328  * gst_codec_utils_aac_caps_set_level_and_profile:
329  * @caps: the #GstCaps to which level and profile fields are to be added
330  * @audio_config: a pointer to the AudioSpecificConfig as specified in the
331  *                Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
332  *                below for a more details).
333  * @len: Length of @audio_config in bytes
334  *
335  * Sets the level and profile on @caps if it can be determined from
336  * @audio_config. See gst_codec_utils_aac_get_level() and
337  * gst_codec_utils_aac_get_profile() for more details on the parameters.
338  * @caps must be audio/mpeg caps with an "mpegversion" field of either 2 or 4.
339  * If mpegversion is 4, the "base-profile" field is also set in @caps.
340  *
341  * Returns: %TRUE if the level and profile could be set, %FALSE otherwise.
342  *
343  * Since: 0.10.31
344  */
345 gboolean
346 gst_codec_utils_aac_caps_set_level_and_profile (GstCaps * caps,
347     const guint8 * audio_config, guint len)
348 {
349   GstStructure *s;
350   const gchar *level, *profile;
351   int mpegversion = 0;
352
353   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
354   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE);
355   g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_NAME (caps, "audio/mpeg"), FALSE);
356   g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_FIELD (caps, "mpegversion"), FALSE);
357   g_return_val_if_fail (audio_config != NULL, FALSE);
358
359   s = gst_caps_get_structure (caps, 0);
360
361   gst_structure_get_int (s, "mpegversion", &mpegversion);
362   g_return_val_if_fail (mpegversion == 2 || mpegversion == 4, FALSE);
363
364   level = gst_codec_utils_aac_get_level (audio_config, len);
365
366   if (level != NULL)
367     gst_structure_set (s, "level", G_TYPE_STRING, level, NULL);
368
369   profile = gst_codec_utils_aac_get_profile (audio_config, len);
370
371   if (profile != NULL) {
372     if (mpegversion == 4) {
373       gst_structure_set (s, "base-profile", G_TYPE_STRING, profile,
374           "profile", G_TYPE_STRING, profile, NULL);
375     } else {
376       gst_structure_set (s, "profile", G_TYPE_STRING, profile, NULL);
377     }
378   }
379
380   GST_LOG ("profile : %s", (profile) ? profile : "---");
381   GST_LOG ("level   : %s", (level) ? level : "---");
382
383   return (level != NULL && profile != NULL);
384 }
385
386 /**
387  * gst_codec_utils_h264_get_profile:
388  * @sps: Pointer to the sequence parameter set for the stream.
389  * @len: Length of the data available in @sps.
390  *
391  * Converts the profile indication (profile_idc) in the stream's
392  * sequence parameter set into a string. The SPS is expected to have the
393  * following format, as defined in the H.264 specification. The SPS is viewed
394  * as a bitstream here, with bit 0 being the most significant bit of the first
395  * byte.
396  *
397  * <itemizedlist>
398  * <listitem><para>Bit 0:7   - Profile indication</para></listitem>
399  * <listitem><para>Bit 8     - constraint_set0_flag</para></listitem>
400  * <listitem><para>Bit 9     - constraint_set1_flag</para></listitem>
401  * <listitem><para>Bit 10    - constraint_set2_flag</para></listitem>
402  * <listitem><para>Bit 11    - constraint_set3_flag</para></listitem>
403  * <listitem><para>Bit 12    - constraint_set3_flag</para></listitem>
404  * <listitem><para>Bit 13:15 - Reserved</para></listitem>
405  * <listitem><para>Bit 16:24 - Level indication</para></listitem>
406  * </itemizedlist>
407  *
408  * Returns: The profile as a const string, or %NULL if there is an error.
409  *
410  * Since: 0.10.31
411  */
412 const gchar *
413 gst_codec_utils_h264_get_profile (const guint8 * sps, guint len)
414 {
415   const gchar *profile = NULL;
416   gint csf1, csf3;
417
418   g_return_val_if_fail (sps != NULL, NULL);
419
420   if (len < 2)
421     return NULL;
422
423   GST_MEMDUMP ("SPS", sps, len);
424
425   csf1 = (sps[1] & 0x40) >> 6;
426   csf3 = (sps[1] & 0x10) >> 4;
427
428   switch (sps[0]) {
429     case 66:
430       if (csf1)
431         profile = "constrained-baseline";
432       else
433         profile = "baseline";
434       break;
435     case 77:
436       profile = "main";
437       break;
438     case 88:
439       profile = "extended";
440       break;
441     case 100:
442       profile = "high";
443       break;
444     case 110:
445       if (csf3)
446         profile = "high-10-intra";
447       else
448         profile = "high-10";
449       break;
450     case 122:
451       if (csf3)
452         profile = "high-4:2:2-intra";
453       else
454         profile = "high-4:2:2";
455       break;
456     case 244:
457       if (csf3)
458         profile = "high-4:4:4-intra";
459       else
460         profile = "high-4:4:4";
461       break;
462     case 44:
463       profile = "cavlc-4:4:4-intra";
464       break;
465     default:
466       return NULL;
467   }
468
469   return profile;
470 }
471
472 /**
473  * gst_codec_utils_h264_get_level:
474  * @sps: Pointer to the sequence parameter set for the stream.
475  * @len: Length of the data available in @sps.
476  *
477  * Converts the level indication (level_idc) in the stream's
478  * sequence parameter set into a string. The SPS is expected to have the
479  * same format as for gst_codec_utils_h264_get_profile().
480  *
481  * Returns: The level as a const string, or %NULL if there is an error.
482  *
483  * Since: 0.10.31
484  */
485 const gchar *
486 gst_codec_utils_h264_get_level (const guint8 * sps, guint len)
487 {
488   gint csf3;
489
490   g_return_val_if_fail (sps != NULL, NULL);
491
492   if (len < 3)
493     return NULL;
494
495   GST_MEMDUMP ("SPS", sps, len);
496
497   csf3 = (sps[1] & 0x10) >> 4;
498
499   if (sps[2] == 11 && csf3)
500     return "1b";
501   else if (sps[2] % 10 == 0)
502     return digit_to_string (sps[2] / 10);
503   else {
504     switch (sps[2]) {
505       case 11:
506         return "1.1";
507       case 12:
508         return "1.2";
509       case 13:
510         return "1.3";
511       case 21:
512         return "2.1";
513       case 22:
514         return "2.2";
515       case 31:
516         return "3.1";
517       case 32:
518         return "3.2";
519       case 41:
520         return "4.1";
521       case 42:
522         return "4.2";
523       case 51:
524         return "5.1";
525       default:
526         return NULL;
527     }
528   }
529 }
530
531 /**
532  * gst_codec_utils_h264_get_level_idc:
533  * @level: A level string from caps
534  *
535  * Transform a level string from the caps into the level_idc
536  *
537  * Returns: the level_idc or 0 if the level is unknown
538  *
539  * Since: 0.10.36
540  */
541 guint8
542 gst_codec_utils_h264_get_level_idc (const gchar * level)
543 {
544   g_return_val_if_fail (level != NULL, 0);
545
546   if (!strcmp (level, "1"))
547     return 10;
548   else if (!strcmp (level, "1b"))
549     return 9;
550   else if (!strcmp (level, "1.1"))
551     return 11;
552   else if (!strcmp (level, "1.2"))
553     return 12;
554   else if (!strcmp (level, "1.3"))
555     return 13;
556   else if (!strcmp (level, "2"))
557     return 20;
558   else if (!strcmp (level, "2.1"))
559     return 21;
560   else if (!strcmp (level, "2.2"))
561     return 22;
562   else if (!strcmp (level, "3"))
563     return 30;
564   else if (!strcmp (level, "3.1"))
565     return 31;
566   else if (!strcmp (level, "3.2"))
567     return 32;
568   else if (!strcmp (level, "4"))
569     return 40;
570   else if (!strcmp (level, "4.1"))
571     return 41;
572   else if (!strcmp (level, "4.2"))
573     return 42;
574   else if (!strcmp (level, "5"))
575     return 50;
576   else if (!strcmp (level, "5.1"))
577     return 51;
578
579   GST_WARNING ("Invalid level %s", level);
580   return 0;
581 }
582
583 /**
584  * gst_codec_utils_h264_caps_set_level_and_profile:
585  * @caps: the #GstCaps to which the level and profile are to be added
586  * @sps: Pointer to the sequence parameter set for the stream.
587  * @len: Length of the data available in @sps.
588  *
589  * Sets the level and profile in @caps if it can be determined from @sps. See
590  * gst_codec_utils_h264_get_level() and gst_codec_utils_h264_get_profile()
591  * for more details on the parameters.
592  *
593  * Returns: %TRUE if the level and profile could be set, %FALSE otherwise.
594  *
595  * Since: 0.10.31
596  */
597 gboolean
598 gst_codec_utils_h264_caps_set_level_and_profile (GstCaps * caps,
599     const guint8 * sps, guint len)
600 {
601   const gchar *level, *profile;
602
603   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
604   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE);
605   g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_NAME (caps, "video/x-h264"), FALSE);
606   g_return_val_if_fail (sps != NULL, FALSE);
607
608   level = gst_codec_utils_h264_get_level (sps, len);
609
610   if (level != NULL)
611     gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
612
613   profile = gst_codec_utils_h264_get_profile (sps, len);
614
615   if (profile != NULL)
616     gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
617
618   GST_LOG ("profile : %s", (profile) ? profile : "---");
619   GST_LOG ("level   : %s", (level) ? level : "---");
620
621   return (level != NULL && profile != NULL);
622 }
623
624 /**
625  * gst_codec_utils_mpeg4video_get_profile:
626  * @vis_obj_seq: Pointer to the visual object sequence for the stream.
627  * @len: Length of the data available in @sps.
628  *
629  * Converts the profile indication in the stream's visual object sequence into
630  * a string. @vis_obj_seq is expected to be the data following the visual
631  * object sequence start code. Only the first byte
632  * (profile_and_level_indication) is used.
633  *
634  * Returns: The profile as a const string, or NULL if there is an error.
635  *
636  * Since: 0.10.31
637  */
638 const gchar *
639 gst_codec_utils_mpeg4video_get_profile (const guint8 * vis_obj_seq, guint len)
640 {
641   /* The profile/level codes are from 14496-2, table G-1, and the Wireshark
642    * sources: epan/dissectors/packet-mp4ves.c */
643
644   /* These are a direct mapping from the integer profile id -> string. Profiles
645    * 0x6, 0xe and 0xf can correspond to more than one profile depending on the
646    * second 4 bits of vis_obj_seq[0], so they are handled separately. */
647   static const char *profiles[] = { "simple", "simple-scalable", "core",
648     "main", "n-bit", "scalable", NULL, "basic-animated-texture", "hybrid",
649     "advanced-real-time-simple", "core-scalable", "advanced-coding-efficiency",
650     "advanced-core", "advanced-scalable-texture",
651   };
652   int profile_id, level_id;
653
654   g_return_val_if_fail (vis_obj_seq != NULL, NULL);
655
656   if (len < 1)
657     return NULL;
658
659   GST_MEMDUMP ("VOS", vis_obj_seq, len);
660
661   profile_id = vis_obj_seq[0] >> 4;
662   level_id = vis_obj_seq[0] & 0xf;
663
664   GST_LOG ("profile_id = %d, level_id = %d", profile_id, level_id);
665
666   if (profile_id != 6 && profile_id < 0xe)
667     return profiles[profile_id];
668
669   if (profile_id != 0xf && level_id == 0)
670     return NULL;
671
672   switch (profile_id) {
673     case 0x6:
674       if (level_id < 3)
675         return "simple-face";
676       else if (level_id < 5)
677         return "simple-fba";
678       break;
679
680     case 0xe:
681       if (level_id < 5)
682         return "simple-studio";
683       else if (level_id < 9)
684         return "core-studio";
685       break;
686
687     case 0xf:
688       if (level_id < 6)
689         return "advanced-simple";
690       else if (level_id > 7 && level_id < 0xe)
691         return "fine-granularity-scalable";
692       break;
693   }
694
695   return NULL;
696 }
697
698 /**
699  * gst_codec_utils_mpeg4video_get_level:
700  * @vis_obj_seq: Pointer to the visual object sequence for the stream.
701  * @len: Length of the data available in @sps.
702  *
703  * Converts the level indication in the stream's visual object sequence into
704  * a string. @vis_obj_seq is expected to be the data following the visual
705  * object sequence start code. Only the first byte
706  * (profile_and_level_indication) is used.
707  *
708  * Returns: The level as a const string, or NULL if there is an error.
709  *
710  * Since: 0.10.31
711  */
712 const gchar *
713 gst_codec_utils_mpeg4video_get_level (const guint8 * vis_obj_seq, guint len)
714 {
715   /* The profile/level codes are from 14496-2, table G-1, the Wireshark
716    * sources: epan/dissectors/packet-mp4ves.c and the Xvid Sources:
717    * src/xvid.h.
718    * Levels 4a and 5 for SP were added in Amendment 2, level 6 in Amendment 4
719    * (see Xvid sources vfw/config.c)
720    *
721    * Each profile has a different maximum level it defines. Some of them still
722    * need special case handling, because not all levels start from 1, and the
723    * Simple profile defines an intermediate level as well. */
724   static const int level_max[] = { 6, 2, 2, 4, 2, 1, 2, 2, 2, 4, 3, 4, 2, 3, 4,
725     5
726   };
727   int profile_id, level_id;
728
729   g_return_val_if_fail (vis_obj_seq != NULL, NULL);
730
731   if (len < 1)
732     return NULL;
733
734   GST_MEMDUMP ("VOS", vis_obj_seq, len);
735
736   profile_id = vis_obj_seq[0] >> 4;
737   level_id = vis_obj_seq[0] & 0xf;
738
739   GST_LOG ("profile_id = %d, level_id = %d", profile_id, level_id);
740
741   if (profile_id != 0xf && level_id == 0)
742     return NULL;
743
744   /* Let's do some validation of the level */
745   switch (profile_id) {
746     case 0x3:
747       if (level_id == 1)
748         return NULL;
749       break;
750
751     case 0x4:
752       if (level_id != 2)
753         return NULL;
754       break;
755
756     case 0x6:
757       if (level_id > 5)
758         return NULL;
759       break;
760
761     case 0xe:
762       if (level_id > 9)
763         return NULL;
764       break;
765
766     case 0xf:
767       if (level_id == 6 || level_id == 7 || level_id > 0xd)
768         return NULL;
769       break;
770   }
771
772   if (profile_id == 0 && level_id == 8)
773     /* Simple Profile / Level 0 */
774     return "0";
775   else if (profile_id == 0 && level_id == 9)
776     /* Simple Profile / Level 0b */
777     return "0b";
778   else if (profile_id == 0 && level_id == 4)
779     /* Simple Profile / Level 4a */
780     return "4a";
781   else if (profile_id == 0xf && level_id > 7)
782     /* Fine Granularity Scalable Profile */
783     return digit_to_string (level_id - 8);
784   else if (level_id <= level_max[profile_id])
785     /* Levels for all other cases */
786     return digit_to_string (level_id);
787
788   return NULL;
789 }
790
791 /**
792  * gst_codec_utils_mpeg4video_caps_set_level_and_profile:
793  * @caps: the #GstCaps to which the level and profile are to be added
794  * @vis_obj_seq: Pointer to the visual object sequence for the stream.
795  * @len: Length of the data available in @sps.
796  *
797  * Sets the level and profile in @caps if it can be determined from
798  * @vis_obj_seq. See gst_codec_utils_mpeg4video_get_level() and
799  * gst_codec_utils_mpeg4video_get_profile() for more details on the
800  * parameters.
801  *
802  * Returns: %TRUE if the level and profile could be set, %FALSE otherwise.
803  *
804  * Since: 0.10.31
805  */
806 gboolean
807 gst_codec_utils_mpeg4video_caps_set_level_and_profile (GstCaps * caps,
808     const guint8 * vis_obj_seq, guint len)
809 {
810   const gchar *profile, *level;
811
812   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
813   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE);
814   g_return_val_if_fail (vis_obj_seq != NULL, FALSE);
815
816   profile = gst_codec_utils_mpeg4video_get_profile (vis_obj_seq, len);
817
818   if (profile != NULL)
819     gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
820
821   level = gst_codec_utils_mpeg4video_get_level (vis_obj_seq, len);
822
823   if (level != NULL)
824     gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
825
826   GST_LOG ("profile : %s", (profile) ? profile : "---");
827   GST_LOG ("level   : %s", (level) ? level : "---");
828
829   return (profile != NULL && level != NULL);
830 }