Bug 1322070: P6. Construct AudioInfo object from Vorbis CodecState. r?gerald
MozReview-Commit-ID: GitrIqFbSVd
--- a/dom/media/ogg/OggCodecState.cpp
+++ b/dom/media/ogg/OggCodecState.cpp
@@ -13,16 +13,17 @@
#include "OggCodecState.h"
#include "OpusDecoder.h"
#include "OpusParser.h"
#include "VideoUtils.h"
#include <algorithm>
#include <opus/opus.h>
#include "opus/opus_multistream.h"
+#include "XiphExtradata.h"
// On Android JellyBean, the hardware.h header redefines version_major and
// version_minor, which breaks our build. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=912702#c6
#ifdef MOZ_WIDGET_GONK
#ifdef version_major
#undef version_major
#endif
@@ -621,54 +622,55 @@ TheoraState::ReconstructTheoraGranulepos
nsresult
VorbisState::Reset()
{
nsresult res = NS_OK;
if (mActive && vorbis_synthesis_restart(&mDsp) != 0) {
res = NS_ERROR_FAILURE;
}
+ mHeaders.Erase();
if (NS_FAILED(OggCodecState::Reset())) {
return NS_ERROR_FAILURE;
}
mGranulepos = 0;
mPrevVorbisBlockSize = 0;
return res;
}
VorbisState::VorbisState(ogg_page* aBosPage)
: OggCodecState(aBosPage, true)
, mPrevVorbisBlockSize(0)
, mGranulepos(0)
{
MOZ_COUNT_CTOR(VorbisState);
- vorbis_info_init(&mInfo);
+ vorbis_info_init(&mVorbisInfo);
vorbis_comment_init(&mComment);
memset(&mDsp, 0, sizeof(vorbis_dsp_state));
memset(&mBlock, 0, sizeof(vorbis_block));
}
VorbisState::~VorbisState()
{
MOZ_COUNT_DTOR(VorbisState);
Reset();
vorbis_block_clear(&mBlock);
vorbis_dsp_clear(&mDsp);
- vorbis_info_clear(&mInfo);
+ vorbis_info_clear(&mVorbisInfo);
vorbis_comment_clear(&mComment);
}
bool
VorbisState::DecodeHeader(ogg_packet* aPacket)
{
- nsAutoRef<ogg_packet> autoRelease(aPacket);
+ mHeaders.Append(aPacket);
mPacketCount++;
- int ret = vorbis_synthesis_headerin(&mInfo,
+ int ret = vorbis_synthesis_headerin(&mVorbisInfo,
&mComment,
aPacket);
// We must determine when we've read the last header packet.
// vorbis_synthesis_headerin() does not tell us when it's read the last
// header, so we must keep track of the headers externally.
//
// There are 3 header packets, the Identification, Comment, and Setup
// headers, which must be in that order. If they're out of order, the file
@@ -684,55 +686,74 @@ VorbisState::DecodeHeader(ogg_packet* aP
bool isSetupHeader = aPacket->bytes > 0 && aPacket->packet[0] == 0x5;
if (ret < 0 || mPacketCount > 3) {
// We've received an error, or the first three packets weren't valid
// header packets. Assume bad input. Our caller will deactivate the
// bitstream.
return false;
- } else if (ret == 0 && isSetupHeader && mPacketCount == 3) {
+ } else if (!ret && isSetupHeader && mPacketCount == 3) {
// Successfully read the three header packets.
// The bitstream remains active.
mDoneReadingHeaders = true;
}
+
return true;
}
bool
VorbisState::Init()
{
if (!mActive) {
return false;
}
- int ret = vorbis_synthesis_init(&mDsp, &mInfo);
+ int ret = vorbis_synthesis_init(&mDsp, &mVorbisInfo);
if (ret != 0) {
NS_WARNING("vorbis_synthesis_init() failed initializing vorbis bitstream");
return mActive = false;
}
ret = vorbis_block_init(&mDsp, &mBlock);
if (ret != 0) {
NS_WARNING("vorbis_block_init() failed initializing vorbis bitstream");
if (mActive) {
vorbis_dsp_clear(&mDsp);
}
return mActive = false;
}
+
+ nsTArray<const unsigned char*> headers;
+ nsTArray<size_t> headerLens;
+ for (size_t i = 0; i < mHeaders.Length(); i++) {
+ headers.AppendElement(mHeaders[i]->packet);
+ headerLens.AppendElement(mHeaders[i]->bytes);
+ }
+ // Save header packets for the decoder
+ if (!XiphHeadersToExtradata(mInfo.mCodecSpecificConfig,
+ headers, headerLens)) {
+ return mActive = false;
+ }
+ mHeaders.Erase();
+ mInfo.mMimeType = NS_LITERAL_CSTRING("audio/vorbis");
+ mInfo.mRate = mVorbisInfo.rate;
+ mInfo.mChannels = mVorbisInfo.channels;
+ mInfo.mBitDepth = 16;
+
return true;
}
int64_t
VorbisState::Time(int64_t granulepos)
{
if (!mActive) {
return -1;
}
- return VorbisState::Time(&mInfo, granulepos);
+ return VorbisState::Time(&mVorbisInfo, granulepos);
}
int64_t
VorbisState::Time(vorbis_info* aInfo, int64_t aGranulepos)
{
if (aGranulepos == -1 || aInfo->rate == 0) {
return -1;
}
@@ -833,17 +854,17 @@ VorbisState::ReconstructVorbisGranulepos
// each packet.
NS_ASSERTION(mUnstamped.Length() > 0, "Length must be > 0");
ogg_packet* last = mUnstamped.LastElement();
NS_ASSERTION(last->e_o_s || last->granulepos >= 0,
"Must know last granulepos!");
if (mUnstamped.Length() == 1) {
ogg_packet* packet = mUnstamped[0];
- long blockSize = vorbis_packet_blocksize(&mInfo, packet);
+ long blockSize = vorbis_packet_blocksize(&mVorbisInfo, packet);
if (blockSize < 0) {
// On failure vorbis_packet_blocksize returns < 0. If we've got
// a bad packet, we just assume that decode will have to skip this
// packet, i.e. assume 0 samples are decodable from this packet.
blockSize = 0;
mPrevVorbisBlockSize = 0;
}
long samples = mPrevVorbisBlockSize / 4 + blockSize / 4;
@@ -864,18 +885,18 @@ VorbisState::ReconstructVorbisGranulepos
bool unknownGranulepos = last->granulepos == -1;
int totalSamples = 0;
for (int32_t i = mUnstamped.Length() - 1; i > 0; i--) {
ogg_packet* packet = mUnstamped[i];
ogg_packet* prev = mUnstamped[i-1];
ogg_int64_t granulepos = packet->granulepos;
NS_ASSERTION(granulepos != -1, "Must know granulepos!");
- long prevBlockSize = vorbis_packet_blocksize(&mInfo, prev);
- long blockSize = vorbis_packet_blocksize(&mInfo, packet);
+ long prevBlockSize = vorbis_packet_blocksize(&mVorbisInfo, prev);
+ long blockSize = vorbis_packet_blocksize(&mVorbisInfo, packet);
if (blockSize < 0 || prevBlockSize < 0) {
// On failure vorbis_packet_blocksize returns < 0. If we've got
// a bad packet, we just assume that decode will have to skip this
// packet, i.e. assume 0 samples are decodable from this packet.
blockSize = 0;
prevBlockSize = 0;
}
@@ -889,17 +910,17 @@ VorbisState::ReconstructVorbisGranulepos
if (unknownGranulepos) {
for (uint32_t i = 0; i < mUnstamped.Length(); i++) {
ogg_packet* packet = mUnstamped[i];
packet->granulepos += mGranulepos + totalSamples + 1;
}
}
ogg_packet* first = mUnstamped[0];
- long blockSize = vorbis_packet_blocksize(&mInfo, first);
+ long blockSize = vorbis_packet_blocksize(&mVorbisInfo, first);
if (blockSize < 0) {
mPrevVorbisBlockSize = 0;
blockSize = 0;
}
long samples = (mPrevVorbisBlockSize == 0) ? 0 :
mPrevVorbisBlockSize / 4 + blockSize / 4;
int64_t start = first->granulepos - samples;
@@ -915,17 +936,17 @@ VorbisState::ReconstructVorbisGranulepos
for (uint32_t i = 0; i < mUnstamped.Length() - 1; i++) {
mUnstamped[i]->granulepos += pruned;
}
#ifdef VALIDATE_VORBIS_SAMPLE_CALCULATION
mVorbisPacketSamples[last] -= pruned;
#endif
}
- mPrevVorbisBlockSize = vorbis_packet_blocksize(&mInfo, last);
+ mPrevVorbisBlockSize = vorbis_packet_blocksize(&mVorbisInfo, last);
mPrevVorbisBlockSize = std::max(static_cast<long>(0), mPrevVorbisBlockSize);
mGranulepos = last->granulepos;
return NS_OK;
}
OpusState::OpusState(ogg_page* aBosPage)
: OggCodecState(aBosPage, true)
--- a/dom/media/ogg/OggCodecState.h
+++ b/dom/media/ogg/OggCodecState.h
@@ -63,16 +63,21 @@ class OggPacketQueue : private nsDeque
public:
OggPacketQueue() : nsDeque(new OggPacketDeallocator()) {}
~OggPacketQueue() { Erase(); }
bool IsEmpty() { return nsDeque::GetSize() == 0; }
void Append(ogg_packet* aPacket);
ogg_packet* PopFront() { return static_cast<ogg_packet*>(nsDeque::PopFront()); }
ogg_packet* PeekFront() { return static_cast<ogg_packet*>(nsDeque::PeekFront()); }
ogg_packet* Pop() { return static_cast<ogg_packet*>(nsDeque::Pop()); }
+ ogg_packet* operator[](size_t aIndex) const
+ {
+ return static_cast<ogg_packet*>(nsDeque::ObjectAt(aIndex));
+ }
+ size_t Length() const { return nsDeque::GetSize(); }
void PushFront(ogg_packet* aPacket) { nsDeque::PushFront(aPacket); }
void Erase() { nsDeque::Erase(); }
};
// Encapsulates the data required for decoding an ogg bitstream and for
// converting granulepos to timestamps.
class OggCodecState
{
@@ -275,29 +280,31 @@ public:
CodecType GetType() override { return TYPE_VORBIS; }
bool DecodeHeader(ogg_packet* aPacket) override;
int64_t Time(int64_t granulepos) override;
int64_t PacketDuration(ogg_packet* aPacket) override;
bool Init() override;
nsresult Reset() override;
bool IsHeader(ogg_packet* aPacket) override;
nsresult PageIn(ogg_page* aPage) override;
+ const TrackInfo* GetInfo() const override { return &mInfo; }
// Return a hash table with tag metadata.
MetadataTags* GetTags() override;
- // Returns the end time that a granulepos represents.
- static int64_t Time(vorbis_info* aInfo, int64_t aGranulePos);
-
- vorbis_info mInfo;
+private:
+ AudioInfo mInfo;
+ vorbis_info mVorbisInfo;
vorbis_comment mComment;
vorbis_dsp_state mDsp;
vorbis_block mBlock;
+ OggPacketQueue mHeaders;
-private:
+ // Returns the end time that a granulepos represents.
+ static int64_t Time(vorbis_info* aInfo, int64_t aGranulePos);
// Reconstructs the granulepos of Vorbis packets stored in the mUnstamped
// array.
nsresult ReconstructVorbisGranulepos();
// The "block size" of the previously decoded Vorbis packet, or 0 if we've
// not yet decoded anything. This is used to calculate the number of samples
// in a Vorbis packet, since each Vorbis packet depends on the previous
--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -416,30 +416,17 @@ OggDemuxer::SetupTargetTheora(TheoraStat
void
OggDemuxer::SetupTargetVorbis(VorbisState* aVorbisState, OggHeaders& aHeaders)
{
if (mVorbisState) {
mVorbisState->Reset();
}
- // Copy Vorbis info data for time computations on other threads.
- memcpy(&mVorbisInfo, &aVorbisState->mInfo, sizeof(mVorbisInfo));
- mVorbisInfo.codec_setup = nullptr;
-
- mInfo.mAudio.mMimeType = "audio/vorbis";
- mInfo.mAudio.mRate = aVorbisState->mInfo.rate;
- mInfo.mAudio.mChannels = aVorbisState->mInfo.channels;
-
- // Save header packets for the decoder
- if (!XiphHeadersToExtradata(mInfo.mAudio.mCodecSpecificConfig,
- aHeaders.mHeaders, aHeaders.mHeaderLens)) {
- return;
- }
-
+ mInfo.mAudio = *aVorbisState->GetInfo()->GetAsAudioInfo();
mVorbisState = aVorbisState;
mVorbisSerial = aVorbisState->mSerial;
}
void
OggDemuxer::SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders)
{
if (mOpusState) {
@@ -532,24 +519,22 @@ OggDemuxer::SetupMediaTracksInfo(const n
mInfo.mVideo.mDisplay = displaySize;
}
} 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, &mInfo.mAudio, mVorbisState == vorbisState);
}
- mInfo.mAudio.mRate = vorbisState->mInfo.rate;
- 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();
@@ -807,28 +792,27 @@ OggDemuxer::ReadOggChain(const media::Ti
MessageField* msgInfo = nullptr;
if (mSkeletonState && mSkeletonState->mMsgFieldStore.Contains(serial)) {
mSkeletonState->mMsgFieldStore.Get(serial, &msgInfo);
}
OggHeaders vorbisHeaders;
if ((newVorbisState &&
ReadHeaders(TrackInfo::kAudioTrack, newVorbisState, vorbisHeaders)) &&
- (mVorbisState->mInfo.rate == newVorbisState->mInfo.rate) &&
- (mVorbisState->mInfo.channels == newVorbisState->mInfo.channels)) {
+ (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));
if (msgInfo) {
InitTrack(msgInfo, &mInfo.mAudio, true);
}
- mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/vorbis");
- mInfo.mAudio.mRate = newVorbisState->mInfo.rate;
- mInfo.mAudio.mChannels = newVorbisState->mInfo.channels;
chained = true;
tags = newVorbisState->GetTags();
}
OggHeaders opusHeaders;
if ((newOpusState &&
ReadHeaders(TrackInfo::kAudioTrack, newOpusState, opusHeaders)) &&
@@ -1094,17 +1078,17 @@ OggDemuxer::GetBuffered(TrackInfo::Track
// 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) {
- startTime = VorbisState::Time(&mVorbisInfo, granulepos);
+ startTime = mVorbisState->Time(granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
} else if (aType == TrackInfo::kAudioTrack && mOpusState &&
serial == mOpusSerial) {
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);
--- a/dom/media/ogg/OggDemuxer.h
+++ b/dom/media/ogg/OggDemuxer.h
@@ -303,17 +303,16 @@ private:
// 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;
- vorbis_info mVorbisInfo;
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