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
--- 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);