--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -48,40 +48,16 @@ using media::TimeIntervals;
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];
- }
- }
-
- void AppendPacket(const ogg_packet* aPacket)
- {
- size_t packetSize = aPacket->bytes;
- unsigned char* packetData = new unsigned char[packetSize];
- memcpy(packetData, aPacket->packet, packetSize);
- mHeaders.AppendElement(packetData);
- mHeaderLens.AppendElement(packetSize);
- }
-
- nsTArray<const unsigned char*> mHeaders;
- nsTArray<size_t> mHeaderLens;
-};
-
// Return the corresponding category in aKind based on the following specs.
// (https://www.whatwg.org/specs/web-apps/current-
// work/multipage/embedded-content.html#dom-audiotrack-kind) &
// (http://wiki.xiph.org/SkeletonHeaders)
const nsString
OggDemuxer::GetKind(const nsCString& aRole)
{
if (aRole.Find("audio/main") != -1 || aRole.Find("video/main") != -1) {
@@ -130,20 +106,16 @@ OggDemuxer::OggDemuxer(MediaResource* aR
: mTheoraState(nullptr)
, mVorbisState(nullptr)
, mOpusState(nullptr)
, mFlacState(nullptr)
, mOpusEnabled(MediaDecoder::IsOpusEnabled())
, mSkeletonState(nullptr)
, mAudioOggState(aResource)
, mVideoOggState(aResource)
- , mVorbisSerial(0)
- , mOpusSerial(0)
- , mTheoraSerial(0)
- , mFlacSerial(0)
, mIsChained(false)
, mTimedMetadataEvent(nullptr)
, mOnSeekableEvent(nullptr)
{
MOZ_COUNT_CTOR(OggDemuxer);
}
OggDemuxer::~OggDemuxer()
@@ -322,32 +294,27 @@ OggDemuxer::Reset(TrackInfo::TrackType a
return trackState->Reset();
}
OggState(aType).mNeedKeyframe = true;
return NS_OK;
}
bool
OggDemuxer::ReadHeaders(TrackInfo::TrackType aType,
- OggCodecState* aState,
- OggHeaders& aHeaders)
+ OggCodecState* aState)
{
while (!aState->DoneReadingHeaders()) {
DemuxUntilPacketAvailable(aType, aState);
ogg_packet* packet = aState->PacketOut();
if (!packet) {
OGG_DEBUG("Ran out of header packets early; deactivating stream %ld", aState->mSerial);
aState->Deactivate();
return false;
}
- // Save a copy of the header packet for the decoder to use later;
- // OggCodecState::DecodeHeader will free it when processing locally.
- aHeaders.AppendPacket(packet);
-
// Local OggCodecState needs to decode headers in order to process
// packet granulepos -> time mappings, etc.
if (!aState->DecodeHeader(packet)) {
OGG_DEBUG("Failed to decode ogg header packet; deactivating stream %ld", aState->mSerial);
aState->Deactivate();
return false;
}
}
@@ -367,76 +334,42 @@ OggDemuxer::BuildSerialList(nsTArray<uin
aTracks.AppendElement(mVorbisState->mSerial);
} else if (mOpusState) {
aTracks.AppendElement(mOpusState->mSerial);
}
}
}
void
-OggDemuxer::SetupTargetTheora(TheoraState* aTheoraState, OggHeaders& aHeaders)
+OggDemuxer::SetupTarget(OggCodecState** aSavedState, OggCodecState* aNewState)
{
- if (mTheoraState) {
- mTheoraState->Reset();
- }
-
- mInfo.mVideo = *aTheoraState->GetInfo()->GetAsVideoInfo();
- mTheoraState = aTheoraState;
- mTheoraSerial = aTheoraState->mSerial;
-}
-
-void
-OggDemuxer::SetupTargetVorbis(VorbisState* aVorbisState, OggHeaders& aHeaders)
-{
- if (mVorbisState) {
- mVorbisState->Reset();
+ if (*aSavedState) {
+ (*aSavedState)->Reset();
}
- mInfo.mAudio = *aVorbisState->GetInfo()->GetAsAudioInfo();
- mVorbisState = aVorbisState;
- mVorbisSerial = aVorbisState->mSerial;
-}
-
-void
-OggDemuxer::SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders)
-{
- if (mOpusState) {
- mOpusState->Reset();
+ if (aNewState->GetInfo()->GetAsAudioInfo()) {
+ mInfo.mAudio = *aNewState->GetInfo()->GetAsAudioInfo();
+ } else {
+ mInfo.mVideo = *aNewState->GetInfo()->GetAsVideoInfo();
}
-
- mInfo.mAudio = *aOpusState->GetInfo()->GetAsAudioInfo();
- mOpusState = aOpusState;
- mOpusSerial = aOpusState->mSerial;
-}
-
-void
-OggDemuxer::SetupTargetFlac(FlacState* aFlacState, OggHeaders& aHeaders)
-{
- if (mFlacState) {
- mFlacState->Reset();
- }
-
- mInfo.mAudio = *aFlacState->GetInfo()->GetAsAudioInfo();
- mFlacState = aFlacState;
- mFlacSerial = aFlacState->mSerial;
+ *aSavedState = aNewState;
}
void
OggDemuxer::SetupTargetSkeleton()
{
// Setup skeleton related information after mVorbisState & mTheroState
// being set (if they exist).
if (mSkeletonState) {
- OggHeaders headers;
if (!HasAudio() && !HasVideo()) {
// We have a skeleton track, but no audio or video, may as well disable
// the skeleton, we can't do anything useful with this media.
OGG_DEBUG("Deactivating skeleton stream %ld", mSkeletonState->mSerial);
mSkeletonState->Deactivate();
- } else if (ReadHeaders(TrackInfo::kAudioTrack, mSkeletonState, headers) &&
+ } else if (ReadHeaders(TrackInfo::kAudioTrack, mSkeletonState) &&
mSkeletonState->HasIndex()) {
// We don't particularly care about which track we are currently using
// as both MediaResource points to the same content.
// Extract the duration info out of the index, so we don't need to seek to
// the end of resource to get it.
nsTArray<uint32_t> tracks;
BuildSerialList(tracks);
int64_t duration = 0;
@@ -460,66 +393,42 @@ OggDemuxer::SetupMediaTracksInfo(const n
uint32_t serial = aSerials[i];
OggCodecState* codecState = mCodecStore.Get(serial);
MessageField* msgInfo = nullptr;
if (mSkeletonState && mSkeletonState->mMsgFieldStore.Contains(serial)) {
mSkeletonState->mMsgFieldStore.Get(serial, &msgInfo);
}
- if (codecState->GetType() == OggCodecState::TYPE_THEORA) {
- TheoraState* theoraState = static_cast<TheoraState*>(codecState);
- if (!(mTheoraState && mTheoraState->mSerial == theoraState->mSerial)) {
- continue;
- }
-
- mInfo.mVideo = *theoraState->GetInfo()->GetAsVideoInfo();
-
+ OggCodecState* primeState = nullptr;
+ switch (codecState->GetType()) {
+ case OggCodecState::TYPE_THEORA:
+ primeState = mTheoraState;
+ break;
+ case OggCodecState::TYPE_VORBIS:
+ primeState = mVorbisState;
+ break;
+ case OggCodecState::TYPE_OPUS:
+ primeState = mOpusState;
+ break;
+ case OggCodecState::TYPE_FLAC:
+ primeState = mFlacState;
+ break;
+ default:
+ break;
+ }
+ if (primeState && primeState == codecState) {
+ bool isAudio = primeState->GetInfo()->GetAsAudioInfo();
if (msgInfo) {
- InitTrack(msgInfo, &mInfo.mVideo, mTheoraState == theoraState);
- }
- } else if (codecState->GetType() == OggCodecState::TYPE_VORBIS) {
- VorbisState* vorbisState = static_cast<VorbisState*>(codecState);
- if (!(mVorbisState && mVorbisState->mSerial == vorbisState->mSerial)) {
- continue;
- }
-
- mInfo.mAudio = *vorbisState->GetInfo()->GetAsAudioInfo();
-
- if (msgInfo) {
- InitTrack(msgInfo, &mInfo.mAudio, mVorbisState == vorbisState);
+ InitTrack(msgInfo, isAudio ? static_cast<TrackInfo*>(&mInfo.mAudio)
+ : &mInfo.mVideo,
+ true);
}
-
- FillTags(&mInfo.mAudio, vorbisState->GetTags());
- } else if (codecState->GetType() == OggCodecState::TYPE_OPUS) {
- OpusState* opusState = static_cast<OpusState*>(codecState);
- if (!(mOpusState && mOpusState->mSerial == opusState->mSerial)) {
- continue;
- }
-
- mInfo.mAudio = *opusState->GetInfo()->GetAsAudioInfo();
-
- if (msgInfo) {
- InitTrack(msgInfo, &mInfo.mAudio, mOpusState == opusState);
- }
-
- FillTags(&mInfo.mAudio, opusState->GetTags());
- } else if (codecState->GetType() == OggCodecState::TYPE_FLAC) {
- FlacState* flacState = static_cast<FlacState*>(codecState);
- if (!(mFlacState && mFlacState->mSerial == flacState->mSerial)) {
- continue;
- }
-
- mInfo.mAudio = *flacState->GetInfo()->GetAsAudioInfo();
-
- if (msgInfo) {
- InitTrack(msgInfo, &mInfo.mAudio, mFlacState == flacState);
- }
-
- FillTags(&mInfo.mAudio, flacState->GetTags());
+ FillTags(isAudio ? static_cast<TrackInfo*>(&mInfo.mAudio) : &mInfo.mVideo,
+ primeState->GetTags());
}
}
}
void
OggDemuxer::FillTags(TrackInfo* aInfo, MetadataTags* aTags)
{
if (!aTags) {
@@ -585,52 +494,47 @@ OggDemuxer::ReadMetadata()
// We've read all BOS pages, so we know the streams contained in the media.
// 1. Find the first encountered Theora/Vorbis/Opus bitstream, and configure
// it as the target A/V bitstream.
// 2. Deactivate the rest of bitstreams for now, until we have MediaInfo
// support multiple track infos.
for (uint32_t i = 0; i < bitstreams.Length(); ++i) {
OggCodecState* s = bitstreams[i];
if (s) {
- OggHeaders headers;
if (s->GetType() == OggCodecState::TYPE_THEORA &&
- ReadHeaders(TrackInfo::kVideoTrack, s, headers)) {
+ ReadHeaders(TrackInfo::kVideoTrack, s)) {
if (!mTheoraState) {
- TheoraState* theoraState = static_cast<TheoraState*>(s);
- SetupTargetTheora(theoraState, headers);
+ SetupTarget(&mTheoraState, s);
} else {
s->Deactivate();
}
} else if (s->GetType() == OggCodecState::TYPE_VORBIS &&
- ReadHeaders(TrackInfo::kAudioTrack, s, headers)) {
+ ReadHeaders(TrackInfo::kAudioTrack, s)) {
if (!mVorbisState) {
- VorbisState* vorbisState = static_cast<VorbisState*>(s);
- SetupTargetVorbis(vorbisState, headers);
+ SetupTarget(&mVorbisState, s);
} else {
s->Deactivate();
}
} else if (s->GetType() == OggCodecState::TYPE_OPUS &&
- ReadHeaders(TrackInfo::kAudioTrack, s, headers)) {
+ ReadHeaders(TrackInfo::kAudioTrack, s)) {
if (mOpusEnabled) {
if (!mOpusState) {
- OpusState* opusState = static_cast<OpusState*>(s);
- SetupTargetOpus(opusState, headers);
+ SetupTarget(&mOpusState, s);
} else {
s->Deactivate();
}
} else {
NS_WARNING("Opus decoding disabled."
" See media.opus.enabled in about:config");
}
} else if (MediaPrefs::FlacInOgg() &&
s->GetType() == OggCodecState::TYPE_FLAC &&
- ReadHeaders(TrackInfo::kAudioTrack, s, headers)) {
+ ReadHeaders(TrackInfo::kAudioTrack, s)) {
if (!mFlacState) {
- FlacState* flacState = static_cast<FlacState*>(s);
- SetupTargetFlac(flacState, headers);
+ SetupTarget(&mFlacState, s);
} else {
s->Deactivate();
}
} else if (s->GetType() == OggCodecState::TYPE_SKELETON && !mSkeletonState) {
mSkeletonState = static_cast<SkeletonState*>(s);
} else {
// Deactivate any non-primary bitstreams.
s->Deactivate();
@@ -747,63 +651,62 @@ OggDemuxer::ReadOggChain(const media::Ti
return false;
}
MessageField* msgInfo = nullptr;
if (mSkeletonState && mSkeletonState->mMsgFieldStore.Contains(serial)) {
mSkeletonState->mMsgFieldStore.Get(serial, &msgInfo);
}
- OggHeaders vorbisHeaders;
if ((newVorbisState &&
- ReadHeaders(TrackInfo::kAudioTrack, newVorbisState, vorbisHeaders)) &&
+ ReadHeaders(TrackInfo::kAudioTrack, newVorbisState)) &&
(mVorbisState->GetInfo()->GetAsAudioInfo()->mRate ==
newVorbisState->GetInfo()->GetAsAudioInfo()->mRate) &&
(mVorbisState->GetInfo()->GetAsAudioInfo()->mChannels ==
newVorbisState->GetInfo()->GetAsAudioInfo()->mChannels)) {
- SetupTargetVorbis(newVorbisState, vorbisHeaders);
- LOG(LogLevel::Debug, ("New vorbis ogg link, serial=%d\n", mVorbisSerial));
+ SetupTarget(&mVorbisState, newVorbisState);
+ LOG(LogLevel::Debug,
+ ("New vorbis ogg link, serial=%d\n", mVorbisState->mSerial));
if (msgInfo) {
InitTrack(msgInfo, &mInfo.mAudio, true);
}
chained = true;
tags = newVorbisState->GetTags();
}
- OggHeaders opusHeaders;
if ((newOpusState &&
- ReadHeaders(TrackInfo::kAudioTrack, newOpusState, opusHeaders)) &&
+ ReadHeaders(TrackInfo::kAudioTrack, newOpusState)) &&
(mOpusState->GetInfo()->GetAsAudioInfo()->mRate ==
newOpusState->GetInfo()->GetAsAudioInfo()->mRate) &&
(mOpusState->GetInfo()->GetAsAudioInfo()->mChannels ==
newOpusState->GetInfo()->GetAsAudioInfo()->mChannels)) {
- SetupTargetOpus(newOpusState, opusHeaders);
+ SetupTarget(&mOpusState, newOpusState);
if (msgInfo) {
InitTrack(msgInfo, &mInfo.mAudio, true);
}
chained = true;
tags = newOpusState->GetTags();
}
- OggHeaders flacHeaders;
if ((newFlacState &&
- ReadHeaders(TrackInfo::kAudioTrack, newFlacState, flacHeaders)) &&
+ ReadHeaders(TrackInfo::kAudioTrack, newFlacState)) &&
(mFlacState->GetInfo()->GetAsAudioInfo()->mRate ==
newFlacState->GetInfo()->GetAsAudioInfo()->mRate) &&
(mFlacState->GetInfo()->GetAsAudioInfo()->mChannels ==
newFlacState->GetInfo()->GetAsAudioInfo()->mChannels)) {
- SetupTargetFlac(newFlacState, flacHeaders);
- LOG(LogLevel::Debug, ("New flac ogg link, serial=%d\n", mFlacSerial));
+ SetupTarget(&mFlacState, newFlacState);
+ LOG(LogLevel::Debug,
+ ("New flac ogg link, serial=%d\n", mFlacState->mSerial));
if (msgInfo) {
InitTrack(msgInfo, &mInfo.mAudio, true);
}
chained = true;
tags = newFlacState->GetTags();
}
@@ -1035,29 +938,29 @@ OggDemuxer::GetBuffered(TrackInfo::Track
// Page doesn't have an end time, advance to the next page
// until we find one.
startOffset += page.header_len + page.body_len;
continue;
}
uint32_t serial = ogg_page_serialno(&page);
if (aType == TrackInfo::kAudioTrack && mVorbisState &&
- serial == mVorbisSerial) {
+ serial == mVorbisState->mSerial) {
startTime = mVorbisState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kAudioTrack && mOpusState &&
- serial == mOpusSerial) {
+ serial == mOpusState->mSerial) {
startTime = mOpusState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kAudioTrack && mFlacState &&
- serial == mFlacSerial) {
+ serial == mFlacState->mSerial) {
startTime = mFlacState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kVideoTrack && mTheoraState &&
- serial == mTheoraSerial) {
+ serial == mTheoraState->mSerial) {
startTime = mTheoraState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (mCodecStore.Contains(serial)) {
// Stream is not the theora or vorbis stream we're playing,
// but is one that we have header data for.
startOffset += page.header_len + page.body_len;
continue;
} else {
@@ -1786,17 +1689,17 @@ OggDemuxer::SeekInBufferedRange(TrackInf
// We have an active Theora bitstream. Peek the next Theora frame, and
// extract its keyframe's time.
DemuxUntilPacketAvailable(aType, mTheoraState);
ogg_packet* packet = mTheoraState->PacketPeek();
if (packet && !mTheoraState->IsKeyframe(packet)) {
// First post-seek frame isn't a keyframe, seek back to previous keyframe,
// otherwise we'll get visual artifacts.
NS_ASSERTION(packet->granulepos != -1, "Must have a granulepos");
- int shift = mTheoraState->mKeyframe_granule_shift;
+ int shift = mTheoraState->KeyFrameGranuleJobs();
int64_t keyframeGranulepos = (packet->granulepos >> shift) << shift;
int64_t keyframeTime = mTheoraState->StartTime(keyframeGranulepos);
SEEK_LOG(LogLevel::Debug,
("Keyframe for %lld is at %lld, seeking back to it", frameTime,
keyframeTime));
aAdjustedTarget = std::min(aAdjustedTarget, keyframeTime);
}
}
--- a/dom/media/ogg/OggDemuxer.h
+++ b/dom/media/ogg/OggDemuxer.h
@@ -10,17 +10,16 @@
#include "MediaDataDemuxer.h"
#include "OggCodecState.h"
#include "OggCodecStore.h"
#include "MediaMetadataManager.h"
namespace mozilla {
class OggTrackDemuxer;
-class OggHeaders;
class OggDemuxer : public MediaDataDemuxer
{
public:
explicit OggDemuxer(MediaResource* aResource);
RefPtr<InitPromise> Init() override;
@@ -198,34 +197,31 @@ private:
// Read data and demux until a packet is available on the given stream state
void DemuxUntilPacketAvailable(TrackInfo::TrackType aType, OggCodecState* aState);
// Reads and decodes header packets for aState, until either header decode
// fails, or is complete. Initializes the codec state before returning.
// Returns true if reading headers and initializtion of the stream
// succeeds.
- bool ReadHeaders(TrackInfo::TrackType aType, OggCodecState* aState, OggHeaders& aHeaders);
+ bool ReadHeaders(TrackInfo::TrackType aType, OggCodecState* aState);
// Reads the next link in the chain.
bool ReadOggChain(const media::TimeUnit& aLastEndTime);
// Set this media as being a chain and notifies the state machine that the
// media is no longer seekable.
void SetChained();
// Fills aTracks with the serial numbers of each active stream, for use by
// various SkeletonState functions.
void BuildSerialList(nsTArray<uint32_t>& aTracks);
// Setup target bitstreams for decoding.
- void SetupTargetTheora(TheoraState* aTheoraState, OggHeaders& aHeaders);
- void SetupTargetVorbis(VorbisState* aVorbisState, OggHeaders& aHeaders);
- void SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders);
- void SetupTargetFlac(FlacState* aFlacState, OggHeaders& aHeaders);
+ void SetupTarget(OggCodecState** aSavedState, OggCodecState* aNewState);
void SetupTargetSkeleton();
void SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials);
void FillTags(TrackInfo* aInfo, MetadataTags* aTags);
// Compute an ogg page's checksum
ogg_uint32_t GetPageChecksum(ogg_page* aPage);
// Get the end time of aEndOffset. This is the playback position we'd reach
@@ -251,27 +247,27 @@ private:
MediaInfo mInfo;
nsTArray<RefPtr<OggTrackDemuxer>> mDemuxers;
// Map of codec-specific bitstream states.
OggCodecStore mCodecStore;
// Decode state of the Theora bitstream we're decoding, if we have video.
- TheoraState* mTheoraState;
+ OggCodecState* mTheoraState;
// Decode state of the Vorbis bitstream we're decoding, if we have audio.
- VorbisState* mVorbisState;
+ OggCodecState* mVorbisState;
// Decode state of the Opus bitstream we're decoding, if we have one.
- OpusState* mOpusState;
+ OggCodecState* mOpusState;
// Get the bitstream decode state for the given track type
// Decode state of the Flac bitstream we're decoding, if we have one.
- FlacState* mFlacState;
+ OggCodecState* mFlacState;
OggCodecState* GetTrackCodecState(TrackInfo::TrackType aType) const;
TrackInfo::TrackType GetCodecStateType(OggCodecState* aState) const;
// Represents the user pref media.opus.enabled at the time our
// contructor was called. We can't check it dynamically because
// we're not on the main thread;
bool mOpusEnabled;
@@ -292,27 +288,16 @@ private:
OggStateContext& OggState(TrackInfo::TrackType aType);
ogg_sync_state* OggSyncState(TrackInfo::TrackType aType);
MediaResourceIndex* Resource(TrackInfo::TrackType aType);
MediaResourceIndex* CommonResource();
OggStateContext mAudioOggState;
OggStateContext mVideoOggState;
- // Vorbis/Opus/Theora data used to compute timestamps. This is written on the
- // decoder thread and read on the main thread. All reading on the main
- // thread must be done after metadataloaded. We can't use the existing
- // data in the codec states due to threading issues. You must check the
- // associated mTheoraState or mVorbisState pointer is non-null before
- // using this codec data.
- uint32_t mVorbisSerial;
- uint32_t mOpusSerial;
- uint32_t mTheoraSerial;
- uint32_t mFlacSerial;
-
Maybe<int64_t> mStartTime;
// Booleans to indicate if we have audio and/or video data
bool HasVideo() const;
bool HasAudio() const;
bool HasSkeleton() const
{
return mSkeletonState != 0 && mSkeletonState->mActive;