Support mpeg1,2 audio and mpeg1,2,4 video content extraction from .ts streams.

Change-Id: I9d2ee63495f161e30daba7c3aab16cb9d8ced6a5
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 5e471c1..3e48459 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -26,6 +26,7 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
+extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
 extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
 
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 576a850..b3b3af5 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -77,7 +77,7 @@
 
 sp<MetaData> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
     ATSParser::SourceType type =
-        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
 
     sp<AnotherPacketSource> source =
         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
@@ -131,7 +131,7 @@
 status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
     ATSParser::SourceType type =
-        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
 
     sp<AnotherPacketSource> source =
         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 2016282..bbc8a6e 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -87,7 +87,7 @@
 
 sp<MetaData> NuPlayer::StreamingSource::getFormat(bool audio) {
     ATSParser::SourceType type =
-        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
 
     sp<AnotherPacketSource> source =
         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
@@ -102,7 +102,7 @@
 status_t NuPlayer::StreamingSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
     ATSParser::SourceType type =
-        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
 
     sp<AnotherPacketSource> source =
         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 4189354..642b3a3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -909,6 +909,8 @@
         compressionFormat = OMX_VIDEO_CodingMPEG4;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
+        compressionFormat = OMX_VIDEO_CodingMPEG2;
     } else {
         TRESPASS();
     }
@@ -1647,6 +1649,10 @@
         componentName = "OMX.google.aac.decoder";
     } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_MPEG)) {
         componentName = "OMX.Nvidia.mp3.decoder";
+    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG2)) {
+        componentName = "OMX.Nvidia.mpeg2v.decode";
+    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+        componentName = "OMX.google.mpeg4.decoder";
     } else {
         TRESPASS();
     }
@@ -1670,7 +1676,8 @@
     mCodec->configureCodec(mime.c_str(), msg);
 
     sp<RefBase> obj;
-    if (msg->findObject("native-window", &obj)) {
+    if (msg->findObject("native-window", &obj)
+            && strncmp("OMX.google.", componentName.c_str(), 11)) {
         sp<NativeWindowWrapper> nativeWindow(
                 static_cast<NativeWindowWrapper *>(obj.get()));
         CHECK(nativeWindow != NULL);
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 4bdfc6f..5bbed5d 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -20,6 +20,7 @@
 
 #include "include/MP3Extractor.h"
 
+#include "include/avc_utils.h"
 #include "include/ID3.h"
 #include "include/VBRISeeker.h"
 #include "include/XINGSeeker.h"
@@ -44,158 +45,6 @@
 // Yes ... there are things that must indeed match...
 static const uint32_t kMask = 0xfffe0c00;
 
-// static
-bool MP3Extractor::get_mp3_frame_size(
-        uint32_t header, size_t *frame_size,
-        int *out_sampling_rate, int *out_channels,
-        int *out_bitrate, int *out_num_samples) {
-    *frame_size = 0;
-
-    if (out_sampling_rate) {
-        *out_sampling_rate = 0;
-    }
-
-    if (out_channels) {
-        *out_channels = 0;
-    }
-
-    if (out_bitrate) {
-        *out_bitrate = 0;
-    }
-
-    if (out_num_samples) {
-        *out_num_samples = 1152;
-    }
-
-    if ((header & 0xffe00000) != 0xffe00000) {
-        return false;
-    }
-
-    unsigned version = (header >> 19) & 3;
-
-    if (version == 0x01) {
-        return false;
-    }
-
-    unsigned layer = (header >> 17) & 3;
-
-    if (layer == 0x00) {
-        return false;
-    }
-
-    unsigned protection = (header >> 16) & 1;
-
-    unsigned bitrate_index = (header >> 12) & 0x0f;
-
-    if (bitrate_index == 0 || bitrate_index == 0x0f) {
-        // Disallow "free" bitrate.
-        return false;
-    }
-
-    unsigned sampling_rate_index = (header >> 10) & 3;
-
-    if (sampling_rate_index == 3) {
-        return false;
-    }
-
-    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
-    int sampling_rate = kSamplingRateV1[sampling_rate_index];
-    if (version == 2 /* V2 */) {
-        sampling_rate /= 2;
-    } else if (version == 0 /* V2.5 */) {
-        sampling_rate /= 4;
-    }
-
-    unsigned padding = (header >> 9) & 1;
-
-    if (layer == 3) {
-        // layer I
-
-        static const int kBitrateV1[] = {
-            32, 64, 96, 128, 160, 192, 224, 256,
-            288, 320, 352, 384, 416, 448
-        };
-
-        static const int kBitrateV2[] = {
-            32, 48, 56, 64, 80, 96, 112, 128,
-            144, 160, 176, 192, 224, 256
-        };
-
-        int bitrate =
-            (version == 3 /* V1 */)
-                ? kBitrateV1[bitrate_index - 1]
-                : kBitrateV2[bitrate_index - 1];
-
-        if (out_bitrate) {
-            *out_bitrate = bitrate;
-        }
-
-        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
-
-        if (out_num_samples) {
-            *out_num_samples = 384;
-        }
-    } else {
-        // layer II or III
-
-        static const int kBitrateV1L2[] = {
-            32, 48, 56, 64, 80, 96, 112, 128,
-            160, 192, 224, 256, 320, 384
-        };
-
-        static const int kBitrateV1L3[] = {
-            32, 40, 48, 56, 64, 80, 96, 112,
-            128, 160, 192, 224, 256, 320
-        };
-
-        static const int kBitrateV2[] = {
-            8, 16, 24, 32, 40, 48, 56, 64,
-            80, 96, 112, 128, 144, 160
-        };
-
-        int bitrate;
-        if (version == 3 /* V1 */) {
-            bitrate = (layer == 2 /* L2 */)
-                ? kBitrateV1L2[bitrate_index - 1]
-                : kBitrateV1L3[bitrate_index - 1];
-
-            if (out_num_samples) {
-                *out_num_samples = 1152;
-            }
-        } else {
-            // V2 (or 2.5)
-
-            bitrate = kBitrateV2[bitrate_index - 1];
-            if (out_num_samples) {
-                *out_num_samples = 576;
-            }
-        }
-
-        if (out_bitrate) {
-            *out_bitrate = bitrate;
-        }
-
-        if (version == 3 /* V1 */) {
-            *frame_size = 144000 * bitrate / sampling_rate + padding;
-        } else {
-            // V2 or V2.5
-            *frame_size = 72000 * bitrate / sampling_rate + padding;
-        }
-    }
-
-    if (out_sampling_rate) {
-        *out_sampling_rate = sampling_rate;
-    }
-
-    if (out_channels) {
-        int channel_mode = (header >> 6) & 3;
-
-        *out_channels = (channel_mode == 3) ? 1 : 2;
-    }
-
-    return true;
-}
-
 static bool Resync(
         const sp<DataSource> &source, uint32_t match_header,
         off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) {
@@ -297,7 +146,7 @@
 
         size_t frame_size;
         int sample_rate, num_channels, bitrate;
-        if (!MP3Extractor::get_mp3_frame_size(
+        if (!GetMPEGAudioFrameSize(
                     header, &frame_size,
                     &sample_rate, &num_channels, &bitrate)) {
             ++pos;
@@ -331,7 +180,7 @@
             }
 
             size_t test_frame_size;
-            if (!MP3Extractor::get_mp3_frame_size(
+            if (!GetMPEGAudioFrameSize(
                         test_header, &test_frame_size)) {
                 valid = false;
                 break;
@@ -437,7 +286,7 @@
     int sample_rate;
     int num_channels;
     int bitrate;
-    get_mp3_frame_size(
+    GetMPEGAudioFrameSize(
             header, &frame_size, &sample_rate, &num_channels, &bitrate);
 
     mMeta = new MetaData;
@@ -602,8 +451,9 @@
         uint32_t header = U32_AT((const uint8_t *)buffer->data());
 
         if ((header & kMask) == (mFixedHeader & kMask)
-            && MP3Extractor::get_mp3_frame_size(
-                header, &frame_size, &sample_rate, NULL, &bitrate, &num_samples)) {
+            && GetMPEGAudioFrameSize(
+                header, &frame_size, &sample_rate, NULL,
+                &bitrate, &num_samples)) {
             break;
         }
 
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8cd08bc..01f1fba 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -24,6 +24,7 @@
 const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
 const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
 const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
 
 const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ba495cc..6339710 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -163,7 +163,6 @@
 
 static const CodecInfo kDecoderInfo[] = {
     { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
-//    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.Nvidia.mp3.decoder" },
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
@@ -207,6 +206,7 @@
     { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
     { MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" },
     { MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" },
 };
 
 static const CodecInfo kEncoderInfo[] = {
@@ -534,6 +534,10 @@
             err = codec->configureCodec(meta, flags);
 
             if (err == OK) {
+                if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
+                    codec->mOnlySubmitOneBufferAtOneTime = true;
+                }
+
                 return codec;
             }
 
@@ -1357,6 +1361,8 @@
         compressionFormat = OMX_VIDEO_CodingH263;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VPX, mime)) {
         compressionFormat = OMX_VIDEO_CodingVPX;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
+        compressionFormat = OMX_VIDEO_CodingMPEG2;
     } else {
         LOGE("Not a supported video mime type: %s", mime);
         CHECK(!"Should not be here. Not a supported video mime type.");
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index 48bddc2..6f968be 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -20,6 +20,7 @@
 
 #include "include/VBRISeeker.h"
 
+#include "include/avc_utils.h"
 #include "include/MP3Extractor.h"
 
 #include <media/stagefright/foundation/ADebug.h>
@@ -46,7 +47,7 @@
     uint32_t tmp = U32_AT(&header[0]);
     size_t frameSize;
     int sampleRate;
-    if (!MP3Extractor::get_mp3_frame_size(tmp, &frameSize, &sampleRate)) {
+    if (!GetMPEGAudioFrameSize(tmp, &frameSize, &sampleRate)) {
         return NULL;
     }
 
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 95cf2d3..020e947 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -376,5 +376,236 @@
     return meta;
 }
 
+bool ExtractDimensionsFromVOLHeader(
+        const uint8_t *data, size_t size, int32_t *width, int32_t *height) {
+    ABitReader br(&data[4], size - 4);
+    br.skipBits(1);  // random_accessible_vol
+    unsigned video_object_type_indication = br.getBits(8);
+
+    CHECK_NE(video_object_type_indication,
+             0x21u /* Fine Granularity Scalable */);
+
+    unsigned video_object_layer_verid;
+    unsigned video_object_layer_priority;
+    if (br.getBits(1)) {
+        video_object_layer_verid = br.getBits(4);
+        video_object_layer_priority = br.getBits(3);
+    }
+    unsigned aspect_ratio_info = br.getBits(4);
+    if (aspect_ratio_info == 0x0f /* extended PAR */) {
+        br.skipBits(8);  // par_width
+        br.skipBits(8);  // par_height
+    }
+    if (br.getBits(1)) {  // vol_control_parameters
+        br.skipBits(2);  // chroma_format
+        br.skipBits(1);  // low_delay
+        if (br.getBits(1)) {  // vbv_parameters
+            br.skipBits(15);  // first_half_bit_rate
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // latter_half_bit_rate
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // first_half_vbv_buffer_size
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(3);  // latter_half_vbv_buffer_size
+            br.skipBits(11);  // first_half_vbv_occupancy
+            CHECK(br.getBits(1));  // marker_bit
+            br.skipBits(15);  // latter_half_vbv_occupancy
+            CHECK(br.getBits(1));  // marker_bit
+        }
+    }
+    unsigned video_object_layer_shape = br.getBits(2);
+    CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */);
+
+    CHECK(br.getBits(1));  // marker_bit
+    unsigned vop_time_increment_resolution = br.getBits(16);
+    CHECK(br.getBits(1));  // marker_bit
+
+    if (br.getBits(1)) {  // fixed_vop_rate
+        // range [0..vop_time_increment_resolution)
+
+        // vop_time_increment_resolution
+        // 2 => 0..1, 1 bit
+        // 3 => 0..2, 2 bits
+        // 4 => 0..3, 2 bits
+        // 5 => 0..4, 3 bits
+        // ...
+
+        CHECK_GT(vop_time_increment_resolution, 0u);
+        --vop_time_increment_resolution;
+
+        unsigned numBits = 0;
+        while (vop_time_increment_resolution > 0) {
+            ++numBits;
+            vop_time_increment_resolution >>= 1;
+        }
+
+        br.skipBits(numBits);  // fixed_vop_time_increment
+    }
+
+    CHECK(br.getBits(1));  // marker_bit
+    unsigned video_object_layer_width = br.getBits(13);
+    CHECK(br.getBits(1));  // marker_bit
+    unsigned video_object_layer_height = br.getBits(13);
+    CHECK(br.getBits(1));  // marker_bit
+
+    unsigned interlaced = br.getBits(1);
+
+    *width = video_object_layer_width;
+    *height = video_object_layer_height;
+
+    return true;
+}
+
+bool GetMPEGAudioFrameSize(
+        uint32_t header, size_t *frame_size,
+        int *out_sampling_rate, int *out_channels,
+        int *out_bitrate, int *out_num_samples) {
+    *frame_size = 0;
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = 0;
+    }
+
+    if (out_channels) {
+        *out_channels = 0;
+    }
+
+    if (out_bitrate) {
+        *out_bitrate = 0;
+    }
+
+    if (out_num_samples) {
+        *out_num_samples = 1152;
+    }
+
+    if ((header & 0xffe00000) != 0xffe00000) {
+        return false;
+    }
+
+    unsigned version = (header >> 19) & 3;
+
+    if (version == 0x01) {
+        return false;
+    }
+
+    unsigned layer = (header >> 17) & 3;
+
+    if (layer == 0x00) {
+        return false;
+    }
+
+    unsigned protection = (header >> 16) & 1;
+
+    unsigned bitrate_index = (header >> 12) & 0x0f;
+
+    if (bitrate_index == 0 || bitrate_index == 0x0f) {
+        // Disallow "free" bitrate.
+        return false;
+    }
+
+    unsigned sampling_rate_index = (header >> 10) & 3;
+
+    if (sampling_rate_index == 3) {
+        return false;
+    }
+
+    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+    int sampling_rate = kSamplingRateV1[sampling_rate_index];
+    if (version == 2 /* V2 */) {
+        sampling_rate /= 2;
+    } else if (version == 0 /* V2.5 */) {
+        sampling_rate /= 4;
+    }
+
+    unsigned padding = (header >> 9) & 1;
+
+    if (layer == 3) {
+        // layer I
+
+        static const int kBitrateV1[] = {
+            32, 64, 96, 128, 160, 192, 224, 256,
+            288, 320, 352, 384, 416, 448
+        };
+
+        static const int kBitrateV2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            144, 160, 176, 192, 224, 256
+        };
+
+        int bitrate =
+            (version == 3 /* V1 */)
+                ? kBitrateV1[bitrate_index - 1]
+                : kBitrateV2[bitrate_index - 1];
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+
+        if (out_num_samples) {
+            *out_num_samples = 384;
+        }
+    } else {
+        // layer II or III
+
+        static const int kBitrateV1L2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            160, 192, 224, 256, 320, 384
+        };
+
+        static const int kBitrateV1L3[] = {
+            32, 40, 48, 56, 64, 80, 96, 112,
+            128, 160, 192, 224, 256, 320
+        };
+
+        static const int kBitrateV2[] = {
+            8, 16, 24, 32, 40, 48, 56, 64,
+            80, 96, 112, 128, 144, 160
+        };
+
+        int bitrate;
+        if (version == 3 /* V1 */) {
+            bitrate = (layer == 2 /* L2 */)
+                ? kBitrateV1L2[bitrate_index - 1]
+                : kBitrateV1L3[bitrate_index - 1];
+
+            if (out_num_samples) {
+                *out_num_samples = 1152;
+            }
+        } else {
+            // V2 (or 2.5)
+
+            bitrate = kBitrateV2[bitrate_index - 1];
+            if (out_num_samples) {
+                *out_num_samples = 576;
+            }
+        }
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        if (version == 3 /* V1 */) {
+            *frame_size = 144000 * bitrate / sampling_rate + padding;
+        } else {
+            // V2 or V2.5
+            *frame_size = 72000 * bitrate / sampling_rate + padding;
+        }
+    }
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = sampling_rate;
+    }
+
+    if (out_channels) {
+        int channel_mode = (header >> 6) & 3;
+
+        *out_channels = (channel_mode == 3) ? 1 : 2;
+    }
+
+    return true;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index f6770b0..066c88e 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -223,6 +223,7 @@
 
             if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
                     mConfig->outputFrameSize == 0) {
+                LOGE("mp3 decoder returned error %d", decoderErr);
 
                 if (mConfig->outputFrameSize == 0) {
                     LOGE("Output frame size is 0");
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index cf1146b..c83d9e8 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -39,11 +39,6 @@
 
     virtual sp<MetaData> getMetaData();
 
-    static bool get_mp3_frame_size(
-            uint32_t header, size_t *frame_size,
-            int *out_sampling_rate = NULL, int *out_channels = NULL,
-            int *out_bitrate = NULL, int *out_num_samples = NULL);
-
 private:
     status_t mInitCheck;
 
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index afff824..15cd4d4 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -57,6 +57,16 @@
         unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration);
 
+// Given an MPEG4 video VOL-header chunk (starting with 0x00 0x00 0x01 0x2?)
+// parse it and fill in dimensions, returns true iff successful.
+bool ExtractDimensionsFromVOLHeader(
+        const uint8_t *data, size_t size, int32_t *width, int32_t *height);
+
+bool GetMPEGAudioFrameSize(
+        uint32_t header, size_t *frame_size,
+        int *out_sampling_rate = NULL, int *out_channels = NULL,
+        int *out_bitrate = NULL, int *out_num_samples = NULL);
+
 }  // namespace android
 
 #endif  // AVC_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 7d4bc6e..5bbc2b4 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -44,7 +44,7 @@
 static const size_t kTSPacketSize = 188;
 
 struct ATSParser::Program : public RefBase {
-    Program(ATSParser *parser, unsigned programMapPID);
+    Program(ATSParser *parser, unsigned programNumber, unsigned programMapPID);
 
     bool parsePID(
             unsigned pid, unsigned payload_unit_start_indicator,
@@ -63,8 +63,15 @@
         return mFirstPTSValid;
     }
 
+    unsigned number() const { return mProgramNumber; }
+
+    void updateProgramMapPID(unsigned programMapPID) {
+        mProgramMapPID = programMapPID;
+    }
+
 private:
     ATSParser *mParser;
+    unsigned mProgramNumber;
     unsigned mProgramMapPID;
     KeyedVector<unsigned, sp<Stream> > mStreams;
     bool mFirstPTSValid;
@@ -107,7 +114,7 @@
     DiscontinuityType mPendingDiscontinuity;
     sp<AMessage> mPendingDiscontinuityExtra;
 
-    ElementaryStreamQueue mQueue;
+    ElementaryStreamQueue *mQueue;
 
     void flush();
     void parsePES(ABitReader *br);
@@ -126,11 +133,14 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-ATSParser::Program::Program(ATSParser *parser, unsigned programMapPID)
+ATSParser::Program::Program(
+        ATSParser *parser, unsigned programNumber, unsigned programMapPID)
     : mParser(parser),
+      mProgramNumber(programNumber),
       mProgramMapPID(programMapPID),
       mFirstPTSValid(false),
       mFirstPTS(0) {
+    LOGV("new program number %u", programNumber);
 }
 
 bool ATSParser::Program::parsePID(
@@ -299,7 +309,7 @@
 }
 
 sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
-    size_t index = (type == MPEG2ADTS_AUDIO) ? 0 : 0;
+    size_t index = (type == AUDIO) ? 0 : 0;
 
     for (size_t i = 0; i < mStreams.size(); ++i) {
         sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
@@ -338,14 +348,43 @@
       mBuffer(new ABuffer(192 * 1024)),
       mPayloadStarted(false),
       mPendingDiscontinuity(DISCONTINUITY_NONE),
-      mQueue(streamType == 0x1b
-              ? ElementaryStreamQueue::H264 : ElementaryStreamQueue::AAC) {
+      mQueue(NULL) {
     mBuffer->setRange(0, 0);
 
+    switch (mStreamType) {
+        case STREAMTYPE_H264:
+            mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264);
+            break;
+        case STREAMTYPE_MPEG2_AUDIO_ATDS:
+            mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
+            break;
+        case STREAMTYPE_MPEG1_AUDIO:
+        case STREAMTYPE_MPEG2_AUDIO:
+            mQueue = new ElementaryStreamQueue(
+                    ElementaryStreamQueue::MPEG_AUDIO);
+            break;
+
+        case STREAMTYPE_MPEG1_VIDEO:
+        case STREAMTYPE_MPEG2_VIDEO:
+            mQueue = new ElementaryStreamQueue(
+                    ElementaryStreamQueue::MPEG_VIDEO);
+            break;
+
+        case STREAMTYPE_MPEG4_VIDEO:
+            mQueue = new ElementaryStreamQueue(
+                    ElementaryStreamQueue::MPEG4_VIDEO);
+            break;
+
+        default:
+            break;
+    }
+
     LOGV("new stream PID 0x%02x, type 0x%02x", elementaryPID, streamType);
 }
 
 ATSParser::Stream::~Stream() {
+    delete mQueue;
+    mQueue = NULL;
 }
 
 void ATSParser::Stream::parse(
@@ -397,7 +436,7 @@
         {
             bool isASeek = (type == DISCONTINUITY_SEEK);
 
-            mQueue.clear(!isASeek);
+            mQueue->clear(!isASeek);
 
             uint64_t resumeAtPTS;
             if (extra != NULL
@@ -444,6 +483,12 @@
 
     LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
 
+    if (packet_startcode_prefix != 1) {
+        LOGV("Supposedly payload_unit_start=1 unit does not start "
+             "with startcode.");
+        return;
+    }
+
     CHECK_EQ(packet_startcode_prefix, 0x000001u);
 
     unsigned stream_id = br->getBits(8);
@@ -611,22 +656,28 @@
         const uint8_t *data, size_t size) {
     LOGV("onPayloadData mStreamType=0x%02x", mStreamType);
 
+    if (mQueue == NULL) {
+        return;
+    }
+
     CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
     int64_t timeUs = mProgram->convertPTSToTimestamp(PTS);
 
-    status_t err = mQueue.appendData(data, size, timeUs);
+    status_t err = mQueue->appendData(data, size, timeUs);
 
     if (err != OK) {
         return;
     }
 
     sp<ABuffer> accessUnit;
-    while ((accessUnit = mQueue.dequeueAccessUnit()) != NULL) {
+    while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
         if (mSource == NULL) {
-            sp<MetaData> meta = mQueue.getFormat();
+            sp<MetaData> meta = mQueue->getFormat();
 
             if (meta != NULL) {
-                LOGV("created source!");
+                LOGV("Stream PID 0x%08x of type 0x%02x now has data.",
+                     mElementaryPID, mStreamType);
+
                 mSource = new AnotherPacketSource(meta);
 
                 if (mPendingDiscontinuity != DISCONTINUITY_NONE) {
@@ -638,13 +689,13 @@
 
                 mSource->queueAccessUnit(accessUnit);
             }
-        } else if (mQueue.getFormat() != NULL) {
+        } else if (mQueue->getFormat() != NULL) {
             // After a discontinuity we invalidate the queue's format
             // and won't enqueue any access units to the source until
             // the queue has reestablished the new format.
 
             if (mSource->getFormat() == NULL) {
-                mSource->setFormat(mQueue.getFormat());
+                mSource->setFormat(mQueue->getFormat());
             }
             mSource->queueAccessUnit(accessUnit);
         }
@@ -652,9 +703,30 @@
 }
 
 sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
-    if ((type == AVC_VIDEO && mStreamType == 0x1b)
-        || (type == MPEG2ADTS_AUDIO && mStreamType == 0x0f)) {
-        return mSource;
+    switch (type) {
+        case VIDEO:
+        {
+            if (mStreamType == STREAMTYPE_H264
+                    || mStreamType == STREAMTYPE_MPEG1_VIDEO
+                    || mStreamType == STREAMTYPE_MPEG2_VIDEO
+                    || mStreamType == STREAMTYPE_MPEG4_VIDEO) {
+                return mSource;
+            }
+            break;
+        }
+
+        case AUDIO:
+        {
+            if (mStreamType == STREAMTYPE_MPEG1_AUDIO
+                    || mStreamType == STREAMTYPE_MPEG2_AUDIO
+                    || mStreamType == STREAMTYPE_MPEG2_AUDIO_ATDS) {
+                return mSource;
+            }
+            break;
+        }
+
+        default:
+            break;
     }
 
     return NULL;
@@ -729,7 +801,21 @@
 
             LOGV("    program_map_PID = 0x%04x", programMapPID);
 
-            mPrograms.push(new Program(this, programMapPID));
+            bool found = false;
+            for (size_t index = 0; index < mPrograms.size(); ++index) {
+                const sp<Program> &program = mPrograms.itemAt(index);
+
+                if (program->number() == program_number) {
+                    program->updateProgramMapPID(programMapPID);
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                mPrograms.push(
+                        new Program(this, program_number, programMapPID));
+            }
         }
     }
 
@@ -805,8 +891,16 @@
 }
 
 sp<MediaSource> ATSParser::getSource(SourceType type) {
+    int which = -1;  // any
+
     for (size_t i = 0; i < mPrograms.size(); ++i) {
-        sp<MediaSource> source = mPrograms.editItemAt(i)->getSource(type);
+        const sp<Program> &program = mPrograms.editItemAt(i);
+
+        if (which >= 0 && (int)program->number() != which) {
+            continue;
+        }
+
+        sp<MediaSource> source = program->getSource(type);
 
         if (source != NULL) {
             return source;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 3936f05..1e6451d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -48,8 +48,8 @@
     void signalEOS(status_t finalResult);
 
     enum SourceType {
-        AVC_VIDEO,
-        MPEG2ADTS_AUDIO
+        VIDEO,
+        AUDIO
     };
     sp<MediaSource> getSource(SourceType type);
 
@@ -59,6 +59,17 @@
     virtual ~ATSParser();
 
 private:
+    enum {
+        // From ISO/IEC 13818-1: 2000 (E), Table 2-29
+        STREAMTYPE_MPEG1_VIDEO          = 0x01,
+        STREAMTYPE_MPEG2_VIDEO          = 0x02,
+        STREAMTYPE_MPEG1_AUDIO          = 0x03,
+        STREAMTYPE_MPEG2_AUDIO          = 0x04,
+        STREAMTYPE_MPEG2_AUDIO_ATDS     = 0x0f,
+        STREAMTYPE_MPEG4_VIDEO          = 0x10,
+        STREAMTYPE_H264                 = 0x1b,
+    };
+
     struct Program;
     struct Stream;
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index dcaf9f7..f8a1d84 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -27,6 +27,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 
 #include "include/avc_utils.h"
 
@@ -79,11 +80,49 @@
     return true;
 }
 
+static bool IsSeeminglyValidMPEGAudioHeader(const uint8_t *ptr, size_t size) {
+    if (size < 3) {
+        // Not enough data to verify header.
+        return false;
+    }
+
+    if (ptr[0] != 0xff || (ptr[1] >> 5) != 0x07) {
+        return false;
+    }
+
+    unsigned ID = (ptr[1] >> 3) & 3;
+
+    if (ID == 1) {
+        return false;  // reserved
+    }
+
+    unsigned layer = (ptr[1] >> 1) & 3;
+
+    if (layer == 0) {
+        return false;  // reserved
+    }
+
+    unsigned bitrateIndex = (ptr[2] >> 4);
+
+    if (bitrateIndex == 0x0f) {
+        return false;  // reserved
+    }
+
+    unsigned samplingRateIndex = (ptr[2] >> 2) & 3;
+
+    if (samplingRateIndex == 3) {
+        return false;  // reserved
+    }
+
+    return true;
+}
+
 status_t ElementaryStreamQueue::appendData(
         const void *data, size_t size, int64_t timeUs) {
     if (mBuffer == NULL || mBuffer->size() == 0) {
         switch (mMode) {
             case H264:
+            case MPEG_VIDEO:
             {
 #if 0
                 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
@@ -105,7 +144,40 @@
                 }
 
                 if (startOffset > 0) {
-                    LOGI("found something resembling an H.264 syncword at "
+                    LOGI("found something resembling an H.264/MPEG syncword at "
+                         "offset %ld",
+                         startOffset);
+                }
+
+                data = &ptr[startOffset];
+                size -= startOffset;
+#endif
+                break;
+            }
+
+            case MPEG4_VIDEO:
+            {
+#if 0
+                if (size < 3 || memcmp("\x00\x00\x01", data, 3)) {
+                    return ERROR_MALFORMED;
+                }
+#else
+                uint8_t *ptr = (uint8_t *)data;
+
+                ssize_t startOffset = -1;
+                for (size_t i = 0; i + 2 < size; ++i) {
+                    if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
+                        startOffset = i;
+                        break;
+                    }
+                }
+
+                if (startOffset < 0) {
+                    return ERROR_MALFORMED;
+                }
+
+                if (startOffset > 0) {
+                    LOGI("found something resembling an H.264/MPEG syncword at "
                          "offset %ld",
                          startOffset);
                 }
@@ -148,6 +220,33 @@
                 break;
             }
 
+            case MPEG_AUDIO:
+            {
+                uint8_t *ptr = (uint8_t *)data;
+
+                ssize_t startOffset = -1;
+                for (size_t i = 0; i < size; ++i) {
+                    if (IsSeeminglyValidMPEGAudioHeader(&ptr[i], size - i)) {
+                        startOffset = i;
+                        break;
+                    }
+                }
+
+                if (startOffset < 0) {
+                    return ERROR_MALFORMED;
+                }
+
+                if (startOffset > 0) {
+                    LOGI("found something resembling an MPEG audio "
+                         "syncword at offset %ld",
+                         startOffset);
+                }
+
+                data = &ptr[startOffset];
+                size -= startOffset;
+                break;
+            }
+
             default:
                 TRESPASS();
                 break;
@@ -190,11 +289,18 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
-    if (mMode == H264) {
-        return dequeueAccessUnitH264();
-    } else {
-        CHECK_EQ((unsigned)mMode, (unsigned)AAC);
-        return dequeueAccessUnitAAC();
+    switch (mMode) {
+        case H264:
+            return dequeueAccessUnitH264();
+        case AAC:
+            return dequeueAccessUnitAAC();
+        case MPEG_VIDEO:
+            return dequeueAccessUnitMPEGVideo();
+        case MPEG4_VIDEO:
+            return dequeueAccessUnitMPEG4Video();
+        default:
+            CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO);
+            return dequeueAccessUnitMPEGAudio();
     }
 }
 
@@ -455,4 +561,371 @@
     return NULL;
 }
 
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() {
+    const uint8_t *data = mBuffer->data();
+    size_t size = mBuffer->size();
+
+    if (size < 4) {
+        return NULL;
+    }
+
+    uint32_t header = U32_AT(data);
+
+    size_t frameSize;
+    int samplingRate, numChannels, bitrate, numSamples;
+    CHECK(GetMPEGAudioFrameSize(
+                header, &frameSize, &samplingRate, &numChannels,
+                &bitrate, &numSamples));
+
+    if (size < frameSize) {
+        return NULL;
+    }
+
+    sp<ABuffer> accessUnit = new ABuffer(frameSize);
+    memcpy(accessUnit->data(), data, frameSize);
+
+    memmove(mBuffer->data(),
+            mBuffer->data() + frameSize,
+            mBuffer->size() - frameSize);
+
+    mBuffer->setRange(0, mBuffer->size() - frameSize);
+
+    int64_t timeUs = fetchTimestamp(frameSize);
+    CHECK_GE(timeUs, 0ll);
+
+    accessUnit->meta()->setInt64("timeUs", timeUs);
+
+    if (mFormat == NULL) {
+        mFormat = new MetaData;
+        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        mFormat->setInt32(kKeySampleRate, samplingRate);
+        mFormat->setInt32(kKeyChannelCount, numChannels);
+    }
+
+    return accessUnit;
+}
+
+static void EncodeSize14(uint8_t **_ptr, size_t size) {
+    CHECK_LE(size, 0x3fff);
+
+    uint8_t *ptr = *_ptr;
+
+    *ptr++ = 0x80 | (size >> 7);
+    *ptr++ = size & 0x7f;
+
+    *_ptr = ptr;
+}
+
+static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
+    sp<ABuffer> esds = new ABuffer(csd->size() + 25);
+
+    uint8_t *ptr = esds->data();
+    *ptr++ = 0x03;
+    EncodeSize14(&ptr, 22 + csd->size());
+
+    *ptr++ = 0x00;  // ES_ID
+    *ptr++ = 0x00;
+
+    *ptr++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+    *ptr++ = 0x04;
+    EncodeSize14(&ptr, 16 + csd->size());
+
+    *ptr++ = 0x40;  // Audio ISO/IEC 14496-3
+
+    for (size_t i = 0; i < 12; ++i) {
+        *ptr++ = 0x00;
+    }
+
+    *ptr++ = 0x05;
+    EncodeSize14(&ptr, csd->size());
+
+    memcpy(ptr, csd->data(), csd->size());
+
+    return esds;
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
+    const uint8_t *data = mBuffer->data();
+    size_t size = mBuffer->size();
+
+    bool sawPictureStart = false;
+    int pprevStartCode = -1;
+    int prevStartCode = -1;
+    int currentStartCode = -1;
+
+    size_t offset = 0;
+    while (offset + 3 < size) {
+        if (memcmp(&data[offset], "\x00\x00\x01", 3)) {
+            ++offset;
+            continue;
+        }
+
+        pprevStartCode = prevStartCode;
+        prevStartCode = currentStartCode;
+        currentStartCode = data[offset + 3];
+
+        if (currentStartCode == 0xb3 && mFormat == NULL) {
+            memmove(mBuffer->data(), mBuffer->data() + offset, size - offset);
+            size -= offset;
+            (void)fetchTimestamp(offset);
+            offset = 0;
+            mBuffer->setRange(0, size);
+        }
+
+        if ((prevStartCode == 0xb3 && currentStartCode != 0xb5)
+                || (pprevStartCode == 0xb3 && prevStartCode == 0xb5)) {
+            // seqHeader without/with extension
+
+            if (mFormat == NULL) {
+                CHECK_GE(size, 7u);
+
+                unsigned width =
+                    (data[4] << 4) | data[5] >> 4;
+
+                unsigned height =
+                    ((data[5] & 0x0f) << 8) | data[6];
+
+                mFormat = new MetaData;
+                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+                mFormat->setInt32(kKeyWidth, width);
+                mFormat->setInt32(kKeyHeight, height);
+
+                LOGI("found MPEG2 video codec config (%d x %d)", width, height);
+
+                sp<ABuffer> csd = new ABuffer(offset);
+                memcpy(csd->data(), data, offset);
+
+                memmove(mBuffer->data(),
+                        mBuffer->data() + offset,
+                        mBuffer->size() - offset);
+
+                mBuffer->setRange(0, mBuffer->size() - offset);
+                size -= offset;
+                (void)fetchTimestamp(offset);
+                offset = 0;
+
+                // hexdump(csd->data(), csd->size());
+
+                sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
+                mFormat->setData(
+                        kKeyESDS, kTypeESDS, esds->data(), esds->size());
+
+                return NULL;
+            }
+        }
+
+        if (mFormat != NULL && currentStartCode == 0x00) {
+            // Picture start
+
+            if (!sawPictureStart) {
+                sawPictureStart = true;
+            } else {
+                sp<ABuffer> accessUnit = new ABuffer(offset);
+                memcpy(accessUnit->data(), data, offset);
+
+                memmove(mBuffer->data(),
+                        mBuffer->data() + offset,
+                        mBuffer->size() - offset);
+
+                mBuffer->setRange(0, mBuffer->size() - offset);
+
+                int64_t timeUs = fetchTimestamp(offset);
+                CHECK_GE(timeUs, 0ll);
+
+                offset = 0;
+
+                accessUnit->meta()->setInt64("timeUs", timeUs);
+
+                LOGV("returning MPEG video access unit at time %lld us",
+                      timeUs);
+
+                // hexdump(accessUnit->data(), accessUnit->size());
+
+                return accessUnit;
+            }
+        }
+
+        ++offset;
+    }
+
+    return NULL;
+}
+
+static ssize_t getNextChunkSize(
+        const uint8_t *data, size_t size) {
+    static const char kStartCode[] = "\x00\x00\x01";
+
+    if (size < 3) {
+        return -EAGAIN;
+    }
+
+    if (memcmp(kStartCode, data, 3)) {
+        TRESPASS();
+    }
+
+    size_t offset = 3;
+    while (offset + 2 < size) {
+        if (!memcmp(&data[offset], kStartCode, 3)) {
+            return offset;
+        }
+
+        ++offset;
+    }
+
+    return -EAGAIN;
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() {
+    uint8_t *data = mBuffer->data();
+    size_t size = mBuffer->size();
+
+    enum {
+        SKIP_TO_VISUAL_OBJECT_SEQ_START,
+        EXPECT_VISUAL_OBJECT_START,
+        EXPECT_VO_START,
+        EXPECT_VOL_START,
+        WAIT_FOR_VOP_START,
+        SKIP_TO_VOP_START,
+
+    } state;
+
+    if (mFormat == NULL) {
+        state = SKIP_TO_VISUAL_OBJECT_SEQ_START;
+    } else {
+        state = SKIP_TO_VOP_START;
+    }
+
+    int32_t width = -1, height = -1;
+
+    size_t offset = 0;
+    ssize_t chunkSize;
+    while ((chunkSize = getNextChunkSize(
+                    &data[offset], size - offset)) > 0) {
+        bool discard = false;
+
+        unsigned chunkType = data[offset + 3];
+
+        switch (state) {
+            case SKIP_TO_VISUAL_OBJECT_SEQ_START:
+            {
+                if (chunkType == 0xb0) {
+                    // Discard anything before this marker.
+
+                    state = EXPECT_VISUAL_OBJECT_START;
+                } else {
+                    discard = true;
+                }
+                break;
+            }
+
+            case EXPECT_VISUAL_OBJECT_START:
+            {
+                CHECK_EQ(chunkType, 0xb5);
+                state = EXPECT_VO_START;
+                break;
+            }
+
+            case EXPECT_VO_START:
+            {
+                CHECK_LE(chunkType, 0x1f);
+                state = EXPECT_VOL_START;
+                break;
+            }
+
+            case EXPECT_VOL_START:
+            {
+                CHECK((chunkType & 0xf0) == 0x20);
+
+                CHECK(ExtractDimensionsFromVOLHeader(
+                            &data[offset], chunkSize,
+                            &width, &height));
+
+                state = WAIT_FOR_VOP_START;
+                break;
+            }
+
+            case WAIT_FOR_VOP_START:
+            {
+                if (chunkType == 0xb3 || chunkType == 0xb6) {
+                    // group of VOP or VOP start.
+
+                    mFormat = new MetaData;
+                    mFormat->setCString(
+                            kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+
+                    mFormat->setInt32(kKeyWidth, width);
+                    mFormat->setInt32(kKeyHeight, height);
+
+                    LOGI("found MPEG4 video codec config (%d x %d)",
+                         width, height);
+
+                    sp<ABuffer> csd = new ABuffer(offset);
+                    memcpy(csd->data(), data, offset);
+
+                    // hexdump(csd->data(), csd->size());
+
+                    sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
+                    mFormat->setData(
+                            kKeyESDS, kTypeESDS,
+                            esds->data(), esds->size());
+
+                    discard = true;
+                    state = SKIP_TO_VOP_START;
+                }
+
+                break;
+            }
+
+            case SKIP_TO_VOP_START:
+            {
+                if (chunkType == 0xb6) {
+                    offset += chunkSize;
+
+                    sp<ABuffer> accessUnit = new ABuffer(offset);
+                    memcpy(accessUnit->data(), data, offset);
+
+                    memmove(data, &data[offset], size - offset);
+                    size -= offset;
+                    mBuffer->setRange(0, size);
+
+                    int64_t timeUs = fetchTimestamp(offset);
+                    CHECK_GE(timeUs, 0ll);
+
+                    offset = 0;
+
+                    accessUnit->meta()->setInt64("timeUs", timeUs);
+
+                    LOGV("returning MPEG4 video access unit at time %lld us",
+                         timeUs);
+
+                    // hexdump(accessUnit->data(), accessUnit->size());
+
+                    return accessUnit;
+                } else if (chunkType != 0xb3) {
+                    offset += chunkSize;
+                    discard = true;
+                }
+
+                break;
+            }
+
+            default:
+                TRESPASS();
+        }
+
+        if (discard) {
+            (void)fetchTimestamp(offset);
+            memmove(data, &data[offset], size - offset);
+            size -= offset;
+            offset = 0;
+            mBuffer->setRange(0, size);
+        } else {
+            offset += chunkSize;
+        }
+    }
+
+    return NULL;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 153cfe6..4035ed3 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -31,7 +31,10 @@
 struct ElementaryStreamQueue {
     enum Mode {
         H264,
-        AAC
+        AAC,
+        MPEG_AUDIO,
+        MPEG_VIDEO,
+        MPEG4_VIDEO,
     };
     ElementaryStreamQueue(Mode mode);
 
@@ -57,6 +60,9 @@
 
     sp<ABuffer> dequeueAccessUnitH264();
     sp<ABuffer> dequeueAccessUnitAAC();
+    sp<ABuffer> dequeueAccessUnitMPEGAudio();
+    sp<ABuffer> dequeueAccessUnitMPEGVideo();
+    sp<ABuffer> dequeueAccessUnitMPEG4Video();
 
     // consume a logical (compressed) access unit of size "size",
     // returns its timestamp in us (or -1 if no time information).
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index dfec47f..8250ad1 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -175,7 +175,7 @@
         if (!haveVideo) {
             sp<AnotherPacketSource> impl =
                 (AnotherPacketSource *)mParser->getSource(
-                        ATSParser::AVC_VIDEO).get();
+                        ATSParser::VIDEO).get();
 
             if (impl != NULL) {
                 haveVideo = true;
@@ -186,7 +186,7 @@
         if (!haveAudio) {
             sp<AnotherPacketSource> impl =
                 (AnotherPacketSource *)mParser->getSource(
-                        ATSParser::MPEG2ADTS_AUDIO).get();
+                        ATSParser::AUDIO).get();
 
             if (impl != NULL) {
                 haveAudio = true;
@@ -194,7 +194,7 @@
             }
         }
 
-        if (++numPacketsParsed > 2500) {
+        if (++numPacketsParsed > 10000) {
             break;
         }
     }
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 6819fef..a02591f 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -329,7 +329,7 @@
     return dst;
 }
 
-static bool ExtractDimensionsFromVOLHeader(
+static bool ExtractDimensionsMPEG4Config(
         const sp<ABuffer> &config, int32_t *width, int32_t *height) {
     *width = 0;
     *height = 0;
@@ -352,87 +352,11 @@
         return false;
     }
 
-    ABitReader br(&ptr[offset + 4], config->size() - offset - 4);
-    br.skipBits(1);  // random_accessible_vol
-    unsigned video_object_type_indication = br.getBits(8);
-
-    CHECK_NE(video_object_type_indication,
-             0x21u /* Fine Granularity Scalable */);
-
-    unsigned video_object_layer_verid;
-    unsigned video_object_layer_priority;
-    if (br.getBits(1)) {
-        video_object_layer_verid = br.getBits(4);
-        video_object_layer_priority = br.getBits(3);
-    }
-    unsigned aspect_ratio_info = br.getBits(4);
-    if (aspect_ratio_info == 0x0f /* extended PAR */) {
-        br.skipBits(8);  // par_width
-        br.skipBits(8);  // par_height
-    }
-    if (br.getBits(1)) {  // vol_control_parameters
-        br.skipBits(2);  // chroma_format
-        br.skipBits(1);  // low_delay
-        if (br.getBits(1)) {  // vbv_parameters
-            br.skipBits(15);  // first_half_bit_rate
-            CHECK(br.getBits(1));  // marker_bit
-            br.skipBits(15);  // latter_half_bit_rate
-            CHECK(br.getBits(1));  // marker_bit
-            br.skipBits(15);  // first_half_vbv_buffer_size
-            CHECK(br.getBits(1));  // marker_bit
-            br.skipBits(3);  // latter_half_vbv_buffer_size
-            br.skipBits(11);  // first_half_vbv_occupancy
-            CHECK(br.getBits(1));  // marker_bit
-            br.skipBits(15);  // latter_half_vbv_occupancy
-            CHECK(br.getBits(1));  // marker_bit
-        }
-    }
-    unsigned video_object_layer_shape = br.getBits(2);
-    CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */);
-
-    CHECK(br.getBits(1));  // marker_bit
-    unsigned vop_time_increment_resolution = br.getBits(16);
-    CHECK(br.getBits(1));  // marker_bit
-
-    if (br.getBits(1)) {  // fixed_vop_rate
-        // range [0..vop_time_increment_resolution)
-
-        // vop_time_increment_resolution
-        // 2 => 0..1, 1 bit
-        // 3 => 0..2, 2 bits
-        // 4 => 0..3, 2 bits
-        // 5 => 0..4, 3 bits
-        // ...
-
-        CHECK_GT(vop_time_increment_resolution, 0u);
-        --vop_time_increment_resolution;
-
-        unsigned numBits = 0;
-        while (vop_time_increment_resolution > 0) {
-            ++numBits;
-            vop_time_increment_resolution >>= 1;
-        }
-
-        br.skipBits(numBits);  // fixed_vop_time_increment
-    }
-
-    CHECK(br.getBits(1));  // marker_bit
-    unsigned video_object_layer_width = br.getBits(13);
-    CHECK(br.getBits(1));  // marker_bit
-    unsigned video_object_layer_height = br.getBits(13);
-    CHECK(br.getBits(1));  // marker_bit
-
-    unsigned interlaced = br.getBits(1);
-
-    *width = video_object_layer_width;
-    *height = video_object_layer_height;
-
-    LOGI("VOL dimensions = %dx%d", *width, *height);
-
-    return true;
+    return ExtractDimensionsFromVOLHeader(
+            &ptr[offset], config->size() - offset, width, height);
 }
 
-sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
+static sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
         const char *params, int32_t *width, int32_t *height) {
     *width = 0;
     *height = 0;
@@ -443,10 +367,12 @@
     sp<ABuffer> config = decodeHex(val);
     CHECK(config != NULL);
 
-    if (!ExtractDimensionsFromVOLHeader(config, width, height)) {
+    if (!ExtractDimensionsMPEG4Config(config, width, height)) {
         return NULL;
     }
 
+    LOGI("VOL dimensions = %dx%d", *width, *height);
+
     size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
     size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
     size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;