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
--- 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,