Bug 1322070: P5. Construct AudioInfo object from Opus CodecState. r?gerald
MozReview-Commit-ID: 3lCqIOuIhV2
--- a/dom/media/ogg/OggCodecState.cpp
+++ b/dom/media/ogg/OggCodecState.cpp
@@ -6,16 +6,17 @@
#include <string.h>
#include "mozilla/EndianUtils.h"
#include <stdint.h>
#include "nsDebug.h"
#include "OggCodecState.h"
+#include "OpusDecoder.h"
#include "OpusParser.h"
#include "VideoUtils.h"
#include <algorithm>
#include <opus/opus.h>
#include "opus/opus_multistream.h"
// On Android JellyBean, the hardware.h header redefines version_major and
@@ -990,35 +991,46 @@ OpusState::Init(void)
mDecoder = opus_multistream_decoder_create(mParser->mRate,
mParser->mChannels,
mParser->mStreams,
mParser->mCoupledStreams,
mParser->mMappingTable,
&error);
+ mInfo.mMimeType = NS_LITERAL_CSTRING("audio/opus");
+ mInfo.mRate = mParser->mRate;
+ mInfo.mChannels = mParser->mChannels;
+ mInfo.mBitDepth = 16;
+ // Save preskip & the first header packet for the Opus decoder
+ OpusDataDecoder::AppendCodecDelay(mInfo.mCodecSpecificConfig,
+ Time(0, mParser->mPreSkip));
+ if (!mHeaders.PeekFront()) {
+ return false;
+ }
+ mInfo.mCodecSpecificConfig->AppendElements(mHeaders.PeekFront()->packet,
+ mHeaders.PeekFront()->bytes);
+ mHeaders.Erase();
LOG(LogLevel::Debug, ("Opus decoder init"));
return error == OPUS_OK;
}
bool
OpusState::DecodeHeader(ogg_packet* aPacket)
{
nsAutoRef<ogg_packet> autoRelease(aPacket);
switch(mPacketCount++) {
// Parse the id header.
case 0:
mParser = new OpusParser;
if (!mParser->DecodeHeader(aPacket->packet, aPacket->bytes)) {
return false;
}
- mRate = mParser->mRate;
- mChannels = mParser->mChannels;
- mPreSkip = mParser->mPreSkip;
+ mHeaders.Append(autoRelease.disown());
break;
// Parse the metadata header.
case 1:
if (!mParser->DecodeTags(aPacket->packet, aPacket->bytes)) {
return false;
}
break;
@@ -1141,17 +1153,17 @@ OpusState::ReconstructOpusGranulepos(voi
"Must know last granulepos!");
int64_t gp;
// If this is the last page, and we've seen at least one previous page (or
// this is the first page)...
if (last->e_o_s) {
if (mPrevPageGranulepos != -1) {
// If this file only has one page and the final granule position is
// smaller than the pre-skip amount, we MUST reject the stream.
- if (!mDoneReadingHeaders && last->granulepos < mPreSkip)
+ if (!mDoneReadingHeaders && last->granulepos < mParser->mPreSkip)
return false;
int64_t last_gp = last->granulepos;
gp = mPrevPageGranulepos;
// Loop through the packets forwards, adding the current packet's
// duration to the previous granulepos to get the value for the
// current packet.
for (uint32_t i = 0; i < mUnstamped.Length() - 1; ++i) {
ogg_packet* packet = mUnstamped[i];
--- a/dom/media/ogg/OggCodecState.h
+++ b/dom/media/ogg/OggCodecState.h
@@ -393,48 +393,45 @@ public:
int64_t Time(int64_t aGranulepos) override;
int64_t PacketDuration(ogg_packet* aPacket) override;
bool Init() override;
nsresult Reset() override;
nsresult Reset(bool aStart);
bool IsHeader(ogg_packet* aPacket) override;
nsresult PageIn(ogg_page* aPage) override;
already_AddRefed<MediaRawData> PacketOutAsMediaRawData() override;
+ const TrackInfo* GetInfo() const override { return &mInfo; }
+
// Returns the end time that a granulepos represents.
static int64_t Time(int aPreSkip, int64_t aGranulepos);
- // Various fields from the Ogg Opus header.
- int mRate; // Sample rate the decoder uses (always 48 kHz).
- int mChannels; // Number of channels the stream encodes.
- uint16_t mPreSkip; // Number of samples to strip after decoder reset.
+ // Construct and return a table of tags from the metadata header.
+ MetadataTags* GetTags() override;
+private:
nsAutoPtr<OpusParser> mParser;
OpusMSDecoder* mDecoder;
// Granule position (end sample) of the last decoded Opus packet. This is
// used to calculate the amount we should trim from the last packet.
int64_t mPrevPacketGranulepos;
- // Construct and return a table of tags from the metadata header.
- MetadataTags* GetTags() override;
-
-private:
-
// Reconstructs the granulepos of Opus packets stored in the
// mUnstamped array. mUnstamped must be filled with consecutive packets from
// the stream, with the last packet having a known granulepos. Using this
// known granulepos, and the known frame numbers, we recover the granulepos
// of all frames in the array. This enables us to determine their timestamps.
bool ReconstructOpusGranulepos();
// Granule position (end sample) of the last decoded Opus page. This is
// used to calculate the Opus per-packet granule positions on the last page,
// where we may need to trim some samples from the end.
int64_t mPrevPageGranulepos;
-
+ AudioInfo mInfo;
+ OggPacketQueue mHeaders;
};
// Constructs a 32bit version number out of two 16 bit major,minor
// version numbers.
#define SKELETON_VERSION(major, minor) (((major)<<16)|(minor))
enum EMsgHeaderType {
eContentType,
--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -134,17 +134,16 @@ OggDemuxer::OggDemuxer(MediaResource* aR
, mOpusEnabled(MediaDecoder::IsOpusEnabled())
, mSkeletonState(nullptr)
, mAudioOggState(aResource)
, mVideoOggState(aResource)
, mVorbisSerial(0)
, mOpusSerial(0)
, mTheoraSerial(0)
, mFlacSerial(0)
- , mOpusPreSkip(0)
, mIsChained(false)
, mTimedMetadataEvent(nullptr)
, mOnSeekableEvent(nullptr)
{
MOZ_COUNT_CTOR(OggDemuxer);
PodZero(&mTheoraInfo);
}
@@ -442,31 +441,19 @@ OggDemuxer::SetupTargetVorbis(VorbisStat
void
OggDemuxer::SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders)
{
if (mOpusState) {
mOpusState->Reset();
}
- mInfo.mAudio.mMimeType = "audio/opus";
- mInfo.mAudio.mRate = aOpusState->mRate;
- mInfo.mAudio.mChannels = aOpusState->mChannels;
-
- // Save preskip & the first header packet for the Opus decoder
- uint64_t preSkip = aOpusState->Time(0, aOpusState->mPreSkip);
- uint8_t c[sizeof(preSkip)];
- BigEndian::writeUint64(&c[0], preSkip);
- mInfo.mAudio.mCodecSpecificConfig->AppendElements(&c[0], sizeof(preSkip));
- mInfo.mAudio.mCodecSpecificConfig->AppendElements(aHeaders.mHeaders[0],
- aHeaders.mHeaderLens[0]);
-
+ mInfo.mAudio = *aOpusState->GetInfo()->GetAsAudioInfo();
mOpusState = aOpusState;
mOpusSerial = aOpusState->mSerial;
- mOpusPreSkip = aOpusState->mPreSkip;
}
void
OggDemuxer::SetupTargetFlac(FlacState* aFlacState, OggHeaders& aHeaders)
{
if (mFlacState) {
mFlacState->Reset();
}
@@ -560,22 +547,22 @@ OggDemuxer::SetupMediaTracksInfo(const n
mInfo.mAudio.mChannels = vorbisState->mInfo.channels;
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);
}
- mInfo.mAudio.mRate = opusState->mRate;
- mInfo.mAudio.mChannels = opusState->mChannels;
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();
@@ -840,27 +827,26 @@ OggDemuxer::ReadOggChain(const media::Ti
chained = true;
tags = newVorbisState->GetTags();
}
OggHeaders opusHeaders;
if ((newOpusState &&
ReadHeaders(TrackInfo::kAudioTrack, newOpusState, opusHeaders)) &&
- (mOpusState->mRate == newOpusState->mRate) &&
- (mOpusState->mChannels == newOpusState->mChannels)) {
+ (mOpusState->GetInfo()->GetAsAudioInfo()->mRate ==
+ newOpusState->GetInfo()->GetAsAudioInfo()->mRate) &&
+ (mOpusState->GetInfo()->GetAsAudioInfo()->mChannels ==
+ newOpusState->GetInfo()->GetAsAudioInfo()->mChannels)) {
SetupTargetOpus(newOpusState, opusHeaders);
if (msgInfo) {
InitTrack(msgInfo, &mInfo.mAudio, true);
}
- mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/opus");
- mInfo.mAudio.mRate = newOpusState->mRate;
- mInfo.mAudio.mChannels = newOpusState->mChannels;
chained = true;
tags = newOpusState->GetTags();
}
OggHeaders flacHeaders;
if ((newFlacState &&
ReadHeaders(TrackInfo::kAudioTrack, newFlacState, flacHeaders)) &&
@@ -1112,17 +1098,17 @@ OggDemuxer::GetBuffered(TrackInfo::Track
uint32_t serial = ogg_page_serialno(&page);
if (aType == TrackInfo::kAudioTrack && mVorbisState &&
serial == mVorbisSerial) {
startTime = VorbisState::Time(&mVorbisInfo, granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kAudioTrack && mOpusState &&
serial == mOpusSerial) {
- startTime = OpusState::Time(mOpusPreSkip, granulepos);
+ startTime = mOpusState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kAudioTrack && mFlacState &&
serial == mFlacSerial) {
startTime = mFlacState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kVideoTrack && mTheoraState &&
serial == mTheoraSerial) {
startTime = TheoraState::Time(&mTheoraInfo, granulepos);
--- a/dom/media/ogg/OggDemuxer.h
+++ b/dom/media/ogg/OggDemuxer.h
@@ -304,17 +304,16 @@ private:
// 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;
vorbis_info mVorbisInfo;
- int mOpusPreSkip;
th_info mTheoraInfo;
Maybe<int64_t> mStartTime;
// Booleans to indicate if we have audio and/or video data
bool HasVideo() const;
bool HasAudio() const;
bool HasSkeleton() const