Bug 1320705: P7. Ensure audio decoder is recreated when chaining encountered. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 02 Dec 2016 12:28:28 +1100
changeset 447404 a1e2d03a1a81d22ed77b5cf62645f0b81674be53
parent 447403 fe5c78e38dc20a283d96ccd8357750f7475eb5f6
child 447405 da4bdb7cb2e441bb9eb06e426e3372ffa34c7770
push id38050
push userbmo:jyavenard@mozilla.com
push dateSun, 04 Dec 2016 20:45:36 +0000
reviewersgerald
bugs1320705
milestone53.0a1
Bug 1320705: P7. Ensure audio decoder is recreated when chaining encountered. r?gerald The Opus decoder will error if we feed it new data if it has seen the last packet of a stream. MozReview-Commit-ID: Kw3cZuEKxie
dom/media/ogg/OggDemuxer.cpp
dom/media/ogg/OggDemuxer.h
--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsError.h"
 #include "MediaDecoderStateMachine.h"
 #include "AbstractMediaDecoder.h"
 #include "OggDemuxer.h"
 #include "OggCodecState.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "MediaDataDemuxer.h"
 #include "nsAutoRef.h"
 #include "XiphExtradata.h"
 #include "MediaPrefs.h"
@@ -45,16 +46,18 @@ using media::TimeIntervals;
 // from an exisiting connection than to do another bisection inside that
 // small range, which would open a new HTTP connetion.
 static const uint32_t OGG_SEEK_FUZZ_USECS = 500000;
 
 // The number of microseconds of "pre-roll" we use for Opus streams.
 // The specification recommends 80 ms.
 static const int64_t OGG_SEEK_OPUS_PREROLL = 80 * USECS_PER_MS;
 
+static Atomic<uint32_t> sStreamSourceID(0u);
+
 class OggHeaders
 {
 public:
   OggHeaders() {}
   ~OggHeaders()
   {
     for (size_t i = 0; i < mHeaders.Length(); i++) {
       delete[] mHeaders[i];
@@ -880,16 +883,19 @@ OggDemuxer::ReadOggChain(const media::Ti
     mInfo.mMediaSeekable = false;
     mDecodedAudioDuration += aLastEndTime;
     if (mTimedMetadataEvent) {
       mTimedMetadataEvent->Notify(
         TimedMetadata(mDecodedAudioDuration,
                       Move(tags),
                       nsAutoPtr<MediaInfo>(new MediaInfo(mInfo))));
     }
+    // Setup a new TrackInfo so that the MediaFormatReader will flush the
+    // current decoder.
+    mSharedAudioTrackInfo = new SharedTrackInfo(mInfo.mAudio, ++sStreamSourceID);
     return true;
   }
 
   return false;
 }
 
 OggDemuxer::OggStateContext&
 OggDemuxer::OggState(TrackInfo::TrackType aType)
@@ -1483,29 +1489,36 @@ OggTrackDemuxer::Seek(const TimeUnit& aT
 }
 
 RefPtr<MediaRawData>
 OggTrackDemuxer::NextSample()
 {
   if (mQueuedSample) {
     RefPtr<MediaRawData> nextSample = mQueuedSample;
     mQueuedSample = nullptr;
+    if (mType == TrackInfo::kAudioTrack) {
+      nextSample->mTrackInfo = mParent->mSharedAudioTrackInfo;
+    }
     return nextSample;
   }
   ogg_packet* packet = mParent->GetNextPacket(mType);
   if (!packet) {
     return nullptr;
   }
   // Check the eos state in case we need to look for chained streams.
   bool eos = packet->e_o_s;
   OggCodecState* state = mParent->GetTrackCodecState(mType);
-  RefPtr<MediaRawData> data = state->PacketOutAsMediaRawData();;
+  RefPtr<MediaRawData> data = state->PacketOutAsMediaRawData();
+  if (mType == TrackInfo::kAudioTrack) {
+    data->mTrackInfo = mParent->mSharedAudioTrackInfo;
+  }
   if (eos) {
     // We've encountered an end of bitstream packet; check for a chained
     // bitstream following this one.
+    // This will also update mSharedAudioTrackInfo.
     mParent->ReadOggChain(TimeUnit::FromMicroseconds(data->GetEndTime()));
   }
   return data;
 }
 
 RefPtr<OggTrackDemuxer::SamplesPromise>
 OggTrackDemuxer::GetSamples(int32_t aNumSamples)
 {
--- a/dom/media/ogg/OggDemuxer.h
+++ b/dom/media/ogg/OggDemuxer.h
@@ -335,16 +335,23 @@ private:
 
   // Total audio duration played so far.
   media::TimeUnit mDecodedAudioDuration;
 
   // Events manager
   TimedMetadataEventProducer* mTimedMetadataEvent;
   MediaEventProducer<void>* mOnSeekableEvent;
 
+  // This will be populated only if a content change occurs, otherwise it
+  // will be left as null so the original metadata is used.
+  // It is updated once a chained ogg is encountered.
+  // As Ogg chaining is only supported for audio, we only need an audio track
+  // info.
+  RefPtr<SharedTrackInfo> mSharedAudioTrackInfo;
+
   friend class OggTrackDemuxer;
 };
 
 class OggTrackDemuxer : public MediaTrackDemuxer
 {
 public:
   OggTrackDemuxer(OggDemuxer* aParent,
                   TrackInfo::TrackType aType,