Bug 1232045 - WebMDemuxer handles resolution changes. r=jya
authorBryce Van Dyk <bvandyk@mozilla.com>
Tue, 15 Mar 2016 00:28:47 +1300
changeset 290546 7a8fb7e6f6f915ad87eba700b4f36ff0c0d5ecab
parent 290545 84f912382f78363398ad538abbe0fadb5100020a
child 290547 3d31cc25fd3b28b928a7f4b90f481fb66976363f
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1232045
milestone48.0a1
Bug 1232045 - WebMDemuxer handles resolution changes. r=jya Update the WebMDemuxer to detect changes in resolution. When it does so it changes the streamID so that we get a new decoder created to handle the resolution change. The demuxer will also update media info in these cases, so the new decoder has the correct information. The demuxer will only handle resolution changes on key frames, files that attempt changes other times are not considered valid at this stage. If a resolution change cannot be performed because nest_egg cannot read track info, or because the new resolution is invalid, a change will not take place. MozReview-Commit-ID: 1JKz3mGbEvi
dom/media/webm/WebMDemuxer.cpp
dom/media/webm/WebMDemuxer.h
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -6,16 +6,17 @@
 
 #include "nsError.h"
 #include "MediaDecoderStateMachine.h"
 #include "AbstractMediaDecoder.h"
 #include "MediaResource.h"
 #include "WebMDemuxer.h"
 #include "WebMBufferedParser.h"
 #include "gfx2DGlue.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Endian.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SharedThreadPool.h"
 #include "MediaDataDemuxer.h"
 #include "nsAutoRef.h"
 #include "NesteggPacketHolder.h"
 #include "XiphExtradata.h"
 #include "prprf.h"           // leaving it for PR_vsnprintf()
@@ -37,16 +38,18 @@ using namespace gfx;
 LazyLogModule gWebMDemuxerLog("WebMDemuxer");
 LazyLogModule gNesteggLog("Nestegg");
 
 // How far ahead will we look when searching future keyframe. In microseconds.
 // This value is based on what appears to be a reasonable value as most webm
 // files encountered appear to have keyframes located < 4s.
 #define MAX_LOOK_AHEAD 10000000
 
+static Atomic<uint32_t> sStreamSourceID(0u);
+
 // Functions for reading and seeking using WebMDemuxer required for
 // nestegg_io. The 'user data' passed to these functions is the
 // demuxer.
 static int webmdemux_read(void* aBuffer, size_t aLength, void* aUserData)
 {
   MOZ_ASSERT(aUserData);
   MOZ_ASSERT(aLength < UINT32_MAX);
   WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
@@ -567,32 +570,51 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
         case NESTEGG_CODEC_VP8:
           vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
           break;
         case NESTEGG_CODEC_VP9:
           vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si);
           break;
       }
       isKeyframe = si.is_kf;
+      if (isKeyframe) {
+        // We only look for resolution changes on keyframes for both VP8 and
+        // VP9. Other resolution changes are invalid.
+        if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() &&
+            (si.w != mLastSeenFrameWidth.value() ||
+             si.h != mLastSeenFrameHeight.value())) {
+          // We ignore cropping information on resizes during streams.
+          // Cropping alone is rare, and we do not consider cropping to
+          // still be valid after a resolution change
+          mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h);
+          mInfo.mVideo.mImage = nsIntRect(0, 0, si.w, si.h);
+          mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID);
+        }
+        mLastSeenFrameWidth = Some(si.w);
+        mLastSeenFrameHeight = Some(si.h);
+      }
     }
 
     WEBM_DEBUG("push sample tstamp: %ld next_tstamp: %ld length: %ld kf: %d",
                tstamp, next_tstamp, length, isKeyframe);
     RefPtr<MediaRawData> sample = new MediaRawData(data, length);
     sample->mTimecode = tstamp;
     sample->mTime = tstamp;
     sample->mDuration = next_tstamp - tstamp;
     sample->mOffset = holder->Offset();
     sample->mKeyframe = isKeyframe;
     if (discardPadding && i == count - 1) {
       uint8_t c[8];
       BigEndian::writeInt64(&c[0], discardPadding);
       sample->mExtraData = new MediaByteBuffer;
       sample->mExtraData->AppendElements(&c[0], 8);
     }
+    if (aType == TrackInfo::kVideoTrack) {
+      sample->mTrackInfo = mSharedVideoTrackInfo;
+    }
     aSamples->Push(sample);
   }
   return true;
 }
 
 RefPtr<NesteggPacketHolder>
 WebMDemuxer::NextPacket(TrackInfo::TrackType aType)
 {
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -196,16 +196,22 @@ private:
   bool mHasAudio;
   bool mNeedReIndex;
 
   // The last complete block parsed by the WebMBufferedState. -1 if not set.
   // We cache those values rather than retrieving them for performance reasons
   // as nestegg only performs 1-byte read at a time.
   int64_t mLastWebMBlockOffset;
   const bool mIsMediaSource;
+
+  Maybe<uint32_t> mLastSeenFrameWidth;
+  Maybe<uint32_t> mLastSeenFrameHeight;
+  // This will be populated only if a resolution change occurs, otherwise it
+  // will be left as null so the original metadata is used
+  RefPtr<SharedTrackInfo> mSharedVideoTrackInfo;
 };
 
 class WebMTrackDemuxer : public MediaTrackDemuxer
 {
 public:
   WebMTrackDemuxer(WebMDemuxer* aParent,
                   TrackInfo::TrackType aType,
                   uint32_t aTrackNumber);