From c639aad6d8894f57c02e620f52ccf49e51b64866 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 21 Sep 2011 13:19:54 -0700 Subject: Support some .avi files containing H.264 video, log warnings if audio/video unsupported Change-Id: Ie7280f25f2bd19f32234c08673e64ceb65833677 related-to-bug: 5349382 --- media/libstagefright/AVIExtractor.cpp | 103 +++++++++++++++++++++++++--- media/libstagefright/avc_utils.cpp | 2 +- media/libstagefright/include/AVIExtractor.h | 1 + 3 files changed, 94 insertions(+), 12 deletions(-) (limited to 'media') diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp index 4e46414..d47e5d1 100644 --- a/media/libstagefright/AVIExtractor.cpp +++ b/media/libstagefright/AVIExtractor.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "AVIExtractor" #include +#include "include/avc_utils.h" #include "include/AVIExtractor.h" #include @@ -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 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 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, diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index 07aa140..153ee33 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -297,7 +297,7 @@ sp MakeAVCCodecSpecificData(const sp &accessUnit) { sp 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); diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h index b575347..75ce68d 100644 --- a/media/libstagefright/include/AVIExtractor.h +++ b/media/libstagefright/include/AVIExtractor.h @@ -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); -- cgit v1.1