Bug 1232045 - WebMDemuxer handles resolution changes r=jya draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Tue, 15 Mar 2016 00:28:47 +1300
changeset 344865 18c821477f9b94762055ba6f3609eefbce2bffc4
parent 344864 a7d69f146a52ccfa013aa3aed251ae8086ef84d8
child 344866 10d6514e029a2361d992105f331dc1d992bb6cfa
push id13936
push userbvandyk@mozilla.com
push dateFri, 25 Mar 2016 22:26:15 +0000
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);