OSDN Git Service

Support some .avi files containing H.264 video, log warnings if audio/video unsupported
authorAndreas Huber <andih@google.com>
Wed, 21 Sep 2011 20:19:54 +0000 (13:19 -0700)
committerAndreas Huber <andih@google.com>
Wed, 21 Sep 2011 20:19:54 +0000 (13:19 -0700)
Change-Id: Ie7280f25f2bd19f32234c08673e64ceb65833677
related-to-bug: 5349382

media/libstagefright/AVIExtractor.cpp
media/libstagefright/avc_utils.cpp
media/libstagefright/include/AVIExtractor.h

index 4e46414..d47e5d1 100644 (file)
@@ -18,6 +18,7 @@
 #define LOG_TAG "AVIExtractor"
 #include <utils/Log.h>
 
+#include "include/avc_utils.h"
 #include "include/AVIExtractor.h"
 
 #include <binder/ProcessState.h>
@@ -362,6 +363,13 @@ static const char *GetMIMETypeForHandler(uint32_t handler) {
         case FOURCC('X', 'V', 'I', 'X'):
             return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
+        // from http://wiki.multimedia.cx/index.php?title=H264
+        case FOURCC('a', 'v', 'c', '1'):
+        case FOURCC('d', 'a', 'v', 'c'):
+        case FOURCC('x', '2', '6', '4'):
+        case FOURCC('v', 's', 's', 'h'):
+            return MEDIA_MIMETYPE_VIDEO_AVC;
+
         default:
             return NULL;
     }
@@ -406,6 +414,14 @@ status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
             return ERROR_MALFORMED;
         }
 
+        if (mime == NULL) {
+            LOGW("Unsupported video format '%c%c%c%c'",
+                 (char)(handler >> 24),
+                 (char)((handler >> 16) & 0xff),
+                 (char)((handler >> 8) & 0xff),
+                 (char)(handler & 0xff));
+        }
+
         kind = Track::VIDEO;
     } else if (type == FOURCC('a', 'u', 'd', 's')) {
         if (mime && strncasecmp(mime, "audio/", 6)) {
@@ -473,8 +489,11 @@ status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
         track->mMeta->setInt32(kKeyHeight, height);
     } else {
         uint32_t format = U16LE_AT(data);
+
         if (format == 0x55) {
             track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        } else {
+            LOGW("Unsupported audio format = 0x%04x", format);
         }
 
         uint32_t numChannels = U16LE_AT(&data[2]);
@@ -646,21 +665,26 @@ status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
 
         AString mime = tmp;
 
-        if (!strncasecmp("video/", mime.c_str(), 6)
-                && track->mThumbnailSampleIndex >= 0) {
-            int64_t thumbnailTimeUs;
-            CHECK_EQ((status_t)OK,
-                     getSampleTime(i, track->mThumbnailSampleIndex,
-                                   &thumbnailTimeUs));
+        if (!strncasecmp("video/", mime.c_str(), 6)) {
+            if (track->mThumbnailSampleIndex >= 0) {
+                int64_t thumbnailTimeUs;
+                CHECK_EQ((status_t)OK,
+                         getSampleTime(i, track->mThumbnailSampleIndex,
+                                       &thumbnailTimeUs));
 
-            track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+                track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+            }
+
+            status_t err = OK;
 
             if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
-                status_t err = addMPEG4CodecSpecificData(i);
+                err = addMPEG4CodecSpecificData(i);
+            } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
+                err = addH264CodecSpecificData(i);
+            }
 
-                if (err != OK) {
-                    return err;
-                }
+            if (err != OK) {
+                return err;
             }
         }
 
@@ -781,6 +805,63 @@ status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
     return OK;
 }
 
+status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
+    Track *track = &mTracks.editItemAt(trackIndex);
+
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    int64_t timeUs;
+
+    // Extract codec specific data from the first non-empty sample.
+
+    size_t sampleIndex = 0;
+    for (;;) {
+        status_t err =
+            getSampleInfo(
+                    trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs);
+
+        if (err != OK) {
+            return err;
+        }
+
+        if (size > 0) {
+            break;
+        }
+
+        ++sampleIndex;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    sp<MetaData> meta = MakeAVCCodecSpecificData(buffer);
+
+    if (meta == NULL) {
+        LOGE("Unable to extract AVC codec specific data");
+        return ERROR_MALFORMED;
+    }
+
+    int32_t width, height;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+
+    uint32_t type;
+    const void *csd;
+    size_t csdSize;
+    CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
+
+    track->mMeta->setInt32(kKeyWidth, width);
+    track->mMeta->setInt32(kKeyHeight, width);
+    track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
+
+    return OK;
+}
+
 status_t AVIExtractor::getSampleInfo(
         size_t trackIndex, size_t sampleIndex,
         off64_t *offset, size_t *size, bool *isKey,
index 07aa140..153ee33 100644 (file)
@@ -297,7 +297,7 @@ sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
 
-    meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+    meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
     meta->setInt32(kKeyWidth, width);
     meta->setInt32(kKeyHeight, height);
 
index b575347..75ce68d 100644 (file)
@@ -101,6 +101,7 @@ private:
             size_t *sampleIndex) const;
 
     status_t addMPEG4CodecSpecificData(size_t trackIndex);
+    status_t addH264CodecSpecificData(size_t trackIndex);
 
     static bool IsCorrectChunkType(
         ssize_t trackIndex, Track::Kind kind, uint32_t chunkType);