Bug 1069660 - Factor Vorbis and Opus decoding out.

This commit is contained in:
Matthew Gregan 2014-09-30 14:14:40 +13:00
parent a0648a0cdf
commit 672372df86
2 changed files with 208 additions and 183 deletions

View File

@ -531,7 +531,6 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
return false;
}
const uint32_t rate = mInfo.mAudio.mRate;
uint64_t tstamp_usecs = tstamp / NS_PER_USEC;
if (mAudioStartUsec == -1) {
// This is the first audio chunk. Assume the start time of our decode
@ -542,8 +541,8 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
// the previous audio chunk, we need to increment the packet count so that
// the vorbis decode doesn't use data from before the gap to help decode
// from after the gap.
CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, rate);
CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, rate);
CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, mInfo.mAudio.mRate);
CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, mInfo.mAudio.mRate);
if (!tstamp_frames.isValid() || !decoded_frames.isValid()) {
NS_WARNING("Int overflow converting WebM times to frames");
return false;
@ -555,7 +554,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
}
if (tstamp_frames.value() > decoded_frames.value()) {
#ifdef DEBUG
CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), rate);
CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), mInfo.mAudio.mRate);
LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio stream\n",
usecs.isValid() ? usecs.value() : -1,
tstamp_frames.value() - decoded_frames.value()));
@ -574,7 +573,25 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
return false;
}
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
ogg_packet opacket = InitOggPacket(data, length, false, false, -1);
if (!DecodeVorbis(data, length, aOffset, tstamp_usecs, &total_frames)) {
return false;
}
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
#ifdef MOZ_OPUS
if (!DecodeOpus(data, length, aOffset, tstamp_usecs, aPacket)) {
return false;
}
#endif
}
}
return true;
}
bool WebMReader::DecodeVorbis(unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs, int32_t* aTotalFrames)
{
ogg_packet opacket = InitOggPacket(aData, aLength, false, false, -1);
if (vorbis_synthesis(&mVorbisBlock, &opacket) != 0) {
return false;
@ -593,7 +610,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
// time derived from the timecode of the first packet that produced
// data.
if (frames == 0 && mAudioFrames == 0) {
AudioQueue().Push(new AudioData(aOffset, tstamp_usecs, 0, 0, nullptr, mChannels, rate));
AudioQueue().Push(new AudioData(aOffset, aTstampUsecs, 0, 0, nullptr, mChannels, mInfo.mAudio.mRate));
}
while (frames > 0) {
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames * mChannels]);
@ -604,31 +621,31 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
}
}
CheckedInt64 duration = FramesToUsecs(frames, rate);
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
if (!duration.isValid()) {
NS_WARNING("Int overflow converting WebM audio duration");
return false;
}
CheckedInt64 total_duration = FramesToUsecs(total_frames, rate);
CheckedInt64 total_duration = FramesToUsecs(*aTotalFrames, mInfo.mAudio.mRate);
if (!total_duration.isValid()) {
NS_WARNING("Int overflow converting WebM audio total_duration");
return false;
}
CheckedInt64 time = total_duration + tstamp_usecs;
CheckedInt64 time = total_duration + aTstampUsecs;
if (!time.isValid()) {
NS_WARNING("Int overflow adding total_duration and tstamp_usecs");
NS_WARNING("Int overflow adding total_duration and aTstampUsecs");
return false;
};
total_frames += frames;
*aTotalFrames += frames;
AudioQueue().Push(new AudioData(aOffset,
time.value(),
duration.value(),
frames,
buffer.forget(),
mChannels,
rate));
mInfo.mAudio.mRate));
mAudioFrames += frames;
if (vorbis_synthesis_read(&mVorbisDsp, frames) != 0) {
return false;
@ -636,17 +653,23 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
}
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
return true;
}
#ifdef MOZ_OPUS
bool WebMReader::DecodeOpus(unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs, nestegg_packet* aPacket)
{
uint32_t channels = mOpusParser->mChannels;
// Maximum value is 63*2880, so there's no chance of overflow.
int32_t frames_number = opus_packet_get_nb_frames(data, length);
int32_t frames_number = opus_packet_get_nb_frames(aData, aLength);
if (frames_number <= 0)
return false; // Invalid packet header.
int32_t samples = opus_packet_get_samples_per_frame(data,
(opus_int32) rate);
int32_t samples = opus_packet_get_samples_per_frame(aData,
(opus_int32) mInfo.mAudio.mRate);
int32_t frames = frames_number*samples;
// A valid Opus packet must be between 2.5 and 120 ms long.
@ -657,17 +680,17 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
// Decode to the appropriate sample type.
#ifdef MOZ_SAMPLE_TYPE_FLOAT32
int ret = opus_multistream_decode_float(mOpusDecoder,
data, length,
aData, aLength,
buffer, frames, false);
#else
int ret = opus_multistream_decode(mOpusDecoder,
data, length,
aData, aLength,
buffer, frames, false);
#endif
if (ret < 0)
return false;
NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
CheckedInt64 startTime = tstamp_usecs;
CheckedInt64 startTime = aTstampUsecs;
// Trim the initial frames while the decoder is settling.
if (mSkip > 0) {
@ -683,7 +706,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
int samples = keepFrames * channels;
nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]);
PodCopy(trimBuffer.get(), buffer.get() + skipFrames*channels, samples);
startTime = startTime + FramesToUsecs(skipFrames, rate);
startTime = startTime + FramesToUsecs(skipFrames, mInfo.mAudio.mRate);
frames = keepFrames;
buffer = trimBuffer;
@ -692,9 +715,9 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
}
int64_t discardPadding = 0;
r = nestegg_packet_discard_padding(aPacket, &discardPadding);
(void) nestegg_packet_discard_padding(aPacket, &discardPadding);
if (discardPadding > 0) {
CheckedInt64 discardFrames = UsecsToFrames(discardPadding / NS_PER_USEC, rate);
CheckedInt64 discardFrames = UsecsToFrames(discardPadding / NS_PER_USEC, mInfo.mAudio.mRate);
if (!discardFrames.isValid()) {
NS_WARNING("Int overflow in DiscardPadding");
return false;
@ -738,7 +761,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
return false;
}
CheckedInt64 duration = FramesToUsecs(frames, rate);
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
if (!duration.isValid()) {
NS_WARNING("Int overflow converting WebM audio duration");
return false;
@ -748,23 +771,19 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
NS_WARNING("Int overflow shifting tstamp by codec delay");
return false;
};
AudioQueue().Push(new AudioData(mDecoder->GetResource()->Tell(),
AudioQueue().Push(new AudioData(aOffset,
time.value(),
duration.value(),
frames,
buffer.forget(),
mChannels,
rate));
mInfo.mAudio.mRate));
mAudioFrames += frames;
#else
return false;
#endif /* MOZ_OPUS */
}
}
return true;
}
#endif /* MOZ_OPUS */
nsReturnRef<NesteggPacketHolder> WebMReader::NextPacket(TrackType aTrackType)
{

View File

@ -176,6 +176,12 @@ protected:
// must be held during this call. The caller is responsible for freeing
// aPacket.
bool DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset);
bool DecodeVorbis(unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs, int32_t* aTotalFrames);
#ifdef MOZ_OPUS
bool DecodeOpus(unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs, nestegg_packet* aPacket);
#endif
// Release context and set to null. Called when an error occurs during
// reading metadata or destruction of the reader itself.