Bug 784329 - Part 7: Add sanity checking of video format metadata. r=doublec
authorChris Peterson <cpeterson@mozilla.com>
Fri, 14 Sep 2012 16:03:07 -0700
changeset 107760 1d094717509176597e551e37167b1986f6eff706
parent 107759 0c380a0dbf45ed45b7a7e4bbb235d15388e7906c
child 107761 1d109159eb0818d98f3320e5b7fced07dfb956eb
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersdoublec
bugs784329
milestone18.0a1
Bug 784329 - Part 7: Add sanity checking of video format metadata. r=doublec
media/omx-plugin/OmxPlugin.cpp
--- a/media/omx-plugin/OmxPlugin.cpp
+++ b/media/omx-plugin/OmxPlugin.cpp
@@ -7,16 +7,18 @@
 #include <stagefright/MediaExtractor.h>
 #include <stagefright/MetaData.h>
 #include <stagefright/OMXCodec.h>
 #ifdef MOZ_WIDGET_GONK
 #include <OMX.h>
 #else
 #include <stagefright/OMXClient.h>
 #endif
+
+#include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 #include "MPAPI.h"
 
 #include "android/log.h"
 
 #undef LOG
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "OmxPlugin" , ## args)
 
@@ -283,20 +285,16 @@ bool OmxDecoder::Init() {
   ssize_t audioTrackIndex = -1;
   ssize_t videoTrackIndex = -1;
   const char *audioMime = NULL;
   const char *videoMime = NULL;
 
   for (size_t i = 0; i < extractor->countTracks(); ++i) {
     sp<MetaData> meta = extractor->getTrackMetaData(i);
 
-    int32_t bitRate;
-    if (!meta->findInt32(kKeyBitRate, &bitRate))
-      bitRate = 0;
-
     const char *mime;
     if (!meta->findCString(kKeyMIMEType, &mime)) {
       continue;
     }
 
     if (videoTrackIndex == -1 && !strncasecmp(mime, "video/", 6)) {
       videoTrackIndex = i;
       videoMime = mime;
@@ -344,16 +342,18 @@ bool OmxDecoder::Init() {
     status_t status = videoSource->start();
     if (status != OK) {
       LOG("videoSource->start() failed with status %#x", status);
       return false;
     }
 
     int64_t durationUs;
     if (videoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+      if (durationUs < 0)
+        LOG("video duration %lld should be nonnegative", durationUs);
       if (durationUs > totalDurationUs)
         totalDurationUs = durationUs;
     }
   }
 
   sp<MediaSource> audioTrack;
   sp<MediaSource> audioSource;
   if (audioTrackIndex != -1 && (audioTrack = extractor->getTrack(audioTrackIndex)) != NULL)
@@ -375,16 +375,18 @@ bool OmxDecoder::Init() {
     status_t status = audioSource->start();
     if (status != OK) {
       LOG("audioSource->start() failed with status %#x", status);
       return false;
     }
 
     int64_t durationUs;
     if (audioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+      if (durationUs < 0)
+        LOG("audio duration %lld should be nonnegative", durationUs);
       if (durationUs > totalDurationUs)
         totalDurationUs = durationUs;
     }
   }
 
   // set decoder state
   mVideoTrack = videoTrack;
   mVideoSource = videoSource;
@@ -400,16 +402,26 @@ bool OmxDecoder::Init() {
   if (mAudioSource.get()) {
     if (mAudioSource->read(&mAudioBuffer) != INFO_FORMAT_CHANGED) {
       sp<MetaData> meta = mAudioSource->getFormat();
       if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) ||
           !meta->findInt32(kKeySampleRate, &mAudioSampleRate)) {
         return false;
       }
       mAudioMetadataRead = true;
+
+      if (mAudioChannels < 0) {
+        LOG("audio channel count %d must be nonnegative", mAudioChannels);
+        return false;
+      }
+
+      if (mAudioSampleRate < 0) {
+        LOG("audio sample rate %d must be nonnegative", mAudioSampleRate);
+        return false;
+      }
     }
     else if (!SetAudioFormat()) {
         return false;
     }
   }
   return true;
 }
 
@@ -432,51 +444,83 @@ bool OmxDecoder::SetVideoFormat() {
 
   if (!format->findInt32(kKeyWidth, &mVideoStride) ||
       !format->findInt32(kKeyHeight, &mVideoSliceHeight) ||
       !format->findCString(kKeyDecoderComponent, &componentName) ||
       !format->findInt32(kKeyColorFormat, &mVideoColorFormat) ) {
     return false;
   }
 
+  if (mVideoStride <= 0) {
+    LOG("stride %d must be positive", mVideoStride);
+    return false;
+  }
+
+  if (mVideoSliceHeight <= 0) {
+    LOG("slice height %d must be positive", mVideoSliceHeight);
+    return false;
+  }
+
   int32_t cropRight, cropBottom;
   if (!format->findRect(kKeyCropRect, &mVideoCropLeft, &mVideoCropTop,
                                       &cropRight, &cropBottom)) {
     mVideoCropLeft = 0;
     mVideoCropTop = 0;
     cropRight = mVideoStride - 1;
     cropBottom = mVideoSliceHeight - 1;
     LOG("crop rect not available, assuming no cropping");
   }
 
+  if (mVideoCropLeft < 0 || mVideoCropLeft >= cropRight || cropRight >= mVideoStride ||
+      mVideoCropTop < 0 || mVideoCropTop >= cropBottom || cropBottom >= mVideoSliceHeight) {
+    LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
+    return false;
+  }
+
   mVideoWidth = cropRight - mVideoCropLeft + 1;
   mVideoHeight = cropBottom - mVideoCropTop + 1;
+  MOZ_ASSERT(mVideoWidth > 0 && mVideoWidth <= mVideoStride);
+  MOZ_ASSERT(mVideoHeight > 0 && mVideoHeight <= mVideoSliceHeight);
 
   if (!format->findInt32(kKeyRotation, &mVideoRotation)) {
     mVideoRotation = 0;
     LOG("rotation not available, assuming 0");
   }
 
+  if (mVideoRotation != 0 && mVideoRotation != 90 &&
+      mVideoRotation != 180 && mVideoRotation != 270) {
+    LOG("invalid rotation %d, assuming 0", mVideoRotation);
+  }
+
   LOG("width: %d height: %d component: %s format: %#x stride: %d sliceHeight: %d rotation: %d crop: %d,%d-%d,%d",
       mVideoWidth, mVideoHeight, componentName, mVideoColorFormat,
       mVideoStride, mVideoSliceHeight, mVideoRotation,
       mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
 
   return true;
 }
 
 bool OmxDecoder::SetAudioFormat() {
   // If the format changed, update our cached info.
   if (!mAudioSource->getFormat()->findInt32(kKeyChannelCount, &mAudioChannels) ||
       !mAudioSource->getFormat()->findInt32(kKeySampleRate, &mAudioSampleRate)) {
     return false;
   }
 
-  LOG("channelCount: %d sampleRate: %d",
-      mAudioChannels, mAudioSampleRate);
+  LOG("channelCount: %d sampleRate: %d", mAudioChannels, mAudioSampleRate);
+
+  if (mAudioChannels < 0) {
+    LOG("audio channel count %d must be nonnegative", mAudioChannels);
+    return false;
+  }
+
+  if (mAudioSampleRate < 0) {
+    LOG("audio sample rate %d must be nonnegative", mAudioSampleRate);
+    return false;
+  }
 
   return true;
 }
 
 void OmxDecoder::ReleaseVideoBuffer() {
   if (mVideoBuffer) {
     mVideoBuffer->release();
     mVideoBuffer = NULL;
@@ -577,16 +621,18 @@ bool OmxDecoder::ToVideoFrame(VideoFrame
 bool OmxDecoder::ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, int32_t aAudioChannels, int32_t aAudioSampleRate)
 {
   aFrame->Set(aTimeUs, reinterpret_cast<char *>(aData) + aDataOffset, aSize, aAudioChannels, aAudioSampleRate);
   return true;
 }
 
 bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs)
 {
+  MOZ_ASSERT(aSeekTimeUs >= -1);
+
   if (!mVideoSource.get())
     return false;
 
   ReleaseVideoBuffer();
 
   status_t err;
 
   if (aSeekTimeUs != -1) {
@@ -594,32 +640,32 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
     options.setSeekTo(aSeekTimeUs);
     err = mVideoSource->read(&mVideoBuffer, &options);
   } else {
     err = mVideoSource->read(&mVideoBuffer);
   }
 
   if (err == OK && mVideoBuffer->range_length() > 0) {
     int64_t timeUs;
-    int32_t unreadable;
     int32_t keyFrame;
 
     if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
-      LOG("no key time");
+      LOG("no frame time");
+      return false;
+    }
+
+    if (timeUs < 0) {
+      LOG("frame time %lld must be nonnegative", timeUs);
       return false;
     }
 
     if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
        keyFrame = 0;
     }
 
-    if (!mVideoBuffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)) {
-      unreadable = 0;
-    }
-
     char *data = reinterpret_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
     size_t length = mVideoBuffer->range_length();
 
     if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) {
       return false;
     }
   }
   else if (err == INFO_FORMAT_CHANGED) {
@@ -637,16 +683,18 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
     LOG("mVideoSource ERROR %#x", err);
   }
 
   return err == OK;
 }
 
 bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
 {
+  MOZ_ASSERT(aSeekTimeUs >= -1);
+
   status_t err;
   if (mAudioMetadataRead && aSeekTimeUs == -1) {
     // Use the data read into the buffer during metadata time
     err = OK;
   }
   else {
     ReleaseAudioBuffer();
     if (aSeekTimeUs != -1) {
@@ -658,18 +706,25 @@ bool OmxDecoder::ReadAudio(AudioFrame *a
     }
   }
   mAudioMetadataRead = false;
 
   aSeekTimeUs = -1;
 
   if (err == OK && mAudioBuffer->range_length() != 0) {
     int64_t timeUs;
-    if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs))
+    if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
+      LOG("no frame time");
       return false;
+    }
+
+    if (timeUs < 0) {
+      LOG("frame time %lld must be nonnegative", timeUs);
+      return false;
+    }
 
     return ToAudioFrame(aFrame, timeUs,
                         mAudioBuffer->data(),
                         mAudioBuffer->range_offset(),
                         mAudioBuffer->range_length(),
                         mAudioChannels, mAudioSampleRate);
   }
   else if (err == INFO_FORMAT_CHANGED) {