Author: ayoung
Date: Wed Mar  3 02:07:03 2010
New Revision: 8620

URL: http://svn.slimdevices.com/jive?rev=8620&view=rev
Log:
Fixed bug 15809: MP4 (AAC) file encoded with ffmpeg may not play because of use 
of unsupported encoding type 
Do a better job of parsing the 'esds' box and propagate errors back up.
Tested with a variety of AAC-LC, AAC-HD and ALAC tracks.

Modified:
    7.5/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alac.c
    7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.c
    7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.h

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alac.c
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alac.c?rev=8620&r1=8619&r2=8620&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alac.c 
(original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alac.c Wed 
Mar  3 02:07:03 2010
@@ -56,7 +56,7 @@
 
        if (!self->init) {
                if (!mp4_open(&self->mp4)) {
-                       current_decoder_state |= DECODE_STATE_UNDERRUN;
+                       current_decoder_state |= DECODE_STATE_ERROR | 
DECODE_STATE_NOT_SUPPORTED;
                        return FALSE;
                }
 

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.c
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.c?rev=8620&r1=8619&r2=8620&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.c (original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.c Wed Mar  3 02:07:03 
2010
@@ -10,20 +10,20 @@
 #include "audio/mp4.h"
 
 
-static void mp4_parse_container_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_track_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_track_header_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_sample_to_chunk_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_sample_table_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_sample_size_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_sample_size2_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_chunk_offset_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_chunk_large_offset_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_mp4a_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_esds_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_mdat_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_parse_alac_box(struct decode_mp4 *mp4, size_t r);
-static void mp4_skip_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_container_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_track_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_track_header_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_sample_to_chunk_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_sample_table_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_sample_size_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_sample_size2_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_chunk_offset_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_chunk_large_offset_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_mp4a_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_esds_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_mdat_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_parse_alac_box(struct decode_mp4 *mp4, size_t r);
+static int mp4_skip_box(struct decode_mp4 *mp4, size_t r);
 
 
 struct mp4_sample_to_chunk {
@@ -170,15 +170,40 @@
        return v;
 }
 
-
-static inline void mp4_skip(struct decode_mp4 *mp4, size_t n)
+static inline u8_t mp4_get_u8(struct decode_mp4 *mp4)
+{
+       mp4->ptr += 1;
+       mp4->off += 1;
+       return mp4->ptr[-1];
+}
+
+static u32_t mp4_get_descr_len(struct decode_mp4 *mp4)
+{
+       u8_t b;
+       u8_t numBytes = 0;
+       u32_t length = 0;
+
+    do
+    {
+        b = mp4_get_u8(mp4);
+        numBytes++;
+        length = (length << 7) | (b & 0x7F);
+    } while ((b & 0x80) && numBytes < 4);
+
+       mp4->box_size -= numBytes;
+
+    return length;
+}
+
+static inline int mp4_skip(struct decode_mp4 *mp4, size_t n)
 {
        mp4->ptr += n;
        mp4->off += n;
-}
-
-
-static void mp4_parse_container_box(struct decode_mp4 *mp4, size_t r)
+       return 1;
+}
+
+
+static int mp4_parse_container_box(struct decode_mp4 *mp4, size_t r)
 {
        static struct mp4_parser *parser;
        int i;
@@ -186,7 +211,7 @@
        /* mp4 box */
        if (r < 8) {
                mp4->box_size = 8;
-               return;
+               return 1;
        }
                        
        mp4->box_size = mp4_get_u32(mp4);
@@ -223,27 +248,29 @@
        else {
                mp4->f = mp4_skip_box;
        }
-}
-
-
-static void mp4_parse_track_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_track_box(struct decode_mp4 *mp4, size_t r)
 {
        mp4->track_idx = mp4->track_count++;
 
        mp4->track = realloc(mp4->track, sizeof(struct mp4_track) * 
mp4->track_count);
        memset(&mp4->track[mp4->track_idx], 0, sizeof(struct mp4_track));
 
-       mp4_parse_container_box(mp4 , r);
-}
-
-
-static void mp4_parse_track_header_box(struct decode_mp4 *mp4, size_t r)
+       return mp4_parse_container_box(mp4 , r);
+}
+
+
+static int mp4_parse_track_header_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
        int version;
 
        if (r < 24) {
-               return;
+               return 1;
        }
 
        mp4_get_fullbox(mp4, &version, NULL);
@@ -267,16 +294,18 @@
                mp4->box_size -= 16;
        }
        mp4->f = mp4_skip_box;
-}
-
-
-static void mp4_parse_sample_to_chunk_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_sample_to_chunk_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
 
        if (!track->sample_to_chunk) {
                if (r < 8) {
-                       return;
+                       return 1;
                }
 
                /* skip version, flags */
@@ -292,7 +321,7 @@
 
        while (track->chunk_num < track->sample_to_chunk_count) {
                if ((mp4->end - mp4->ptr) < 12) {
-                       return;
+                       return 1;
                }
 
                track->sample_to_chunk[track->chunk_num].first_chunk = 
mp4_get_u32(mp4);
@@ -308,16 +337,18 @@
 
        /* skip rest of box */
        mp4->f = mp4_skip_box;
-}
-
-
-static void mp4_parse_sample_table_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_sample_table_box(struct decode_mp4 *mp4, size_t r)
 {
        int entries;
 
        if (r < 8) {
                mp4->box_size = 8;
-               return;
+               return 1;
        }
 
        /* skip version, flags */
@@ -325,16 +356,18 @@
        entries = mp4_get_u32(mp4);
 
        mp4->f = &mp4_parse_container_box;
-}
-
-
-static void mp4_parse_sample_size_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_sample_size_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
 
        if (!track->sample_count) {
                if (r < 12) {
-                       return;
+                       return 1;
                }
 
                /* skip version, flags */
@@ -357,7 +390,7 @@
        if (track->fixed_sample_size == 0) {
                while (track->sample_num < track->sample_count) {
                        if ((mp4->end - mp4->ptr) < 4) {
-                               return;
+                               return 1;
                        }
 
                        track->sample_size[track->sample_num++] = 
mp4_get_u32(mp4);
@@ -369,23 +402,25 @@
                /* skip rest of box */
                mp4->f = mp4_skip_box;
        }
-}
-
-
-static void mp4_parse_sample_size2_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_sample_size2_box(struct decode_mp4 *mp4, size_t r)
 {
        LOG_ERROR(log_audio_codec, "need to implement stz2");
-       exit(-1);
-}
-
-
-static void mp4_parse_chunk_offset_box(struct decode_mp4 *mp4, size_t r)
+       return 0;
+}
+
+
+static int mp4_parse_chunk_offset_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
 
        if (!track->chunk_offset_count) {
                if (r < 8) {
-                       return;
+                       return 1;
                }
 
                /* skip version, flags */
@@ -401,7 +436,7 @@
 
        while (track->sample_num < track->chunk_offset_count) {
                if ((mp4->end - mp4->ptr) < 4) {
-                       return;
+                       return 1;
                }
 
                track->chunk_offset[track->sample_num++] = mp4_get_u32(mp4);
@@ -412,19 +447,25 @@
 
        /* skip rest of box */
        mp4->f = mp4_skip_box;
-}
-
-
-static void mp4_parse_chunk_large_offset_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_chunk_large_offset_box(struct decode_mp4 *mp4, size_t r)
 {
        LOG_ERROR(log_audio_codec, "need to implement co64");
-       exit(-1);
-}
-
-
-static void mp4_parse_mp4a_box(struct decode_mp4 *mp4, size_t r)
+       return 0;
+}
+
+
+static int mp4_parse_mp4a_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
+
+       if (r < 28) {
+               return 1;
+       }
 
        memcpy(track->data_format, mp4->box_type, sizeof(track->data_format));
 
@@ -440,14 +481,69 @@
        mp4_skip(mp4, 4); // sample rate
 
        mp4->f = mp4_parse_container_box;
-}
-
-
-static void mp4_parse_esds_box(struct decode_mp4 *mp4, size_t r)
+       return 1;
+}
+
+
+static int mp4_parse_esds_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
 
-       // FIXME parse this correctly
+       if (r < mp4->box_size) {
+               return 1;
+       }
+
+       /* skip version, flags */
+       mp4_skip(mp4, 4);
+       mp4->box_size -= 4;
+
+    /* get and verify ES_DescrTag */
+    if (mp4_get_u8(mp4) == 0x03)
+    {
+        /* read length */
+        if (mp4_get_descr_len(mp4) < 5 + 15) {
+               LOG_ERROR(log_audio_codec, "esds 0x03 tag-length too small");
+               return 0;
+        }
+
+        /* skip 3 bytes */
+        mp4_skip(mp4, 3);
+       mp4->box_size -= 4;
+    } else {
+        /* skip 2 bytes */
+       mp4_skip(mp4, 2);
+       mp4->box_size -= 3;
+    }
+
+    /* get and verify DecoderConfigDescrTab */
+    if (mp4_get_u8(mp4) != 0x04) {
+               LOG_ERROR(log_audio_codec, "esds 0x04 tag expected");
+       return 0;
+    }
+
+    /* read length */
+    if (mp4_get_descr_len(mp4) < 13) {
+               LOG_ERROR(log_audio_codec, "esds 0x04 tag-length too small");
+       return 0;
+    }
+
+    mp4_skip(mp4, 1);  // Audio type
+    mp4_skip(mp4, 4);  // 0x15000414 ????
+    mp4_skip(mp4, 4);  // max bitrate
+    mp4_skip(mp4, 4);  // avg bitrate
+       mp4->box_size -= 14;
+
+    /* get and verify DecSpecificInfoTag */
+    if (mp4_get_u8(mp4) != 0x05) {
+               LOG_ERROR(log_audio_codec, "esds 0x05 tag expected");
+       return 0;
+    };
+       mp4->box_size -= 1;
+
+    /* read length */
+    track->conf_size = mp4_get_descr_len(mp4);
+       track->conf = malloc(track->conf_size);
+       memcpy(track->conf, mp4->ptr, track->conf_size);
 
 #if 0
        {
@@ -458,15 +554,19 @@
                }
                printf("\n");
        }
-#endif
 
        track->conf_size = 10;
        track->conf = malloc(track->conf_size);
        memcpy(track->conf, mp4->ptr+35, track->conf_size);
-
+#endif
+
+       /* ignore the rest */
        mp4->f = mp4_skip_box;
 
+       return 1;
+
 #if 0
+       // The tag-length sequences 80 80 80 nn, might only be nn depending 
upon the encoder
        00 . 00 . 00 . 00 . // 4 bytes version/flags = 8-bit hex version + 
24-bit hex flags
        03 . // 1 byte ES descriptor type tag = 8-bit hex value 0x03
        80 . 80 . 80 . // 3 bytes extended descriptor type tag string = 3 * 
8-bit hex value
@@ -494,13 +594,13 @@
 }
 
 
-static void mp4_parse_mdat_box(struct decode_mp4 *mp4, size_t r)
+static int mp4_parse_mdat_box(struct decode_mp4 *mp4, size_t r)
 {
        int i;
 
        if (r < 12) {
                mp4->box_size = 16;
-               return;
+               return 1;
        }
 
        /* skip any wide atom */
@@ -521,15 +621,17 @@
        /* start streaming content */
        mp4->track_idx = 0;
        mp4->f = NULL;
-}
-
-
-static void mp4_parse_alac_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_parse_alac_box(struct decode_mp4 *mp4, size_t r)
 {
        struct mp4_track *track = &mp4->track[mp4->track_idx];
 
        if (r < mp4->box_size) {
-               return;
+               return 1;
        }
 
 #if 0
@@ -549,10 +651,12 @@
 
        /* skip rest of box */
        mp4->f = mp4_skip_box;
-}
-
-
-static void mp4_skip_box(struct decode_mp4 *mp4, size_t r)
+
+       return 1;
+}
+
+
+static int mp4_skip_box(struct decode_mp4 *mp4, size_t r)
 {
        size_t n;
 
@@ -563,6 +667,8 @@
        if (mp4->box_size == 0) {
                mp4->f = mp4_parse_container_box;
        }
+
+       return 1;
 }
 
 
@@ -586,11 +692,13 @@
 
                r = mp4_fill_buffer(mp4, &streaming);
                if (r < 0) {
+                       LOG_ERROR(log_audio_codec, "premature end of stream");
                        return 0;
                }
 
                /* parse box */
-               mp4->f(mp4, r);
+               if (!mp4->f(mp4, r))
+                       return 0;
        }
 
        /* headers parsed, found mdat */

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.h
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.h?rev=8620&r1=8619&r2=8620&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.h (original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/audio/mp4.h Wed Mar  3 02:07:03 
2010
@@ -9,7 +9,7 @@
 
 struct decode_mp4;
 
-typedef void (*mp4_read_box_t)(struct decode_mp4 *mp4, size_t r);
+typedef int (*mp4_read_box_t)(struct decode_mp4 *mp4, size_t r);
 
 struct decode_mp4 {
        /* parser state */

_______________________________________________
Jive-checkins mailing list
[email protected]
http://lists.slimdevices.com/mailman/listinfo/jive-checkins

Reply via email to