Bug 945863 - Handle CodecDelay and SeekPreroll for Opus in WebM. r=kinetik

This commit is contained in:
Jan Gerber 2013-12-10 10:36:05 +01:00
parent 38439ea439
commit e286df484b
2 changed files with 28 additions and 10 deletions

View File

@ -11,6 +11,7 @@
#include "WebMBufferedParser.h" #include "WebMBufferedParser.h"
#include "mozilla/dom/TimeRanges.h" #include "mozilla/dom/TimeRanges.h"
#include "VorbisUtils.h" #include "VorbisUtils.h"
#include <algorithm>
#define VPX_DONT_DEFINE_STDINT_TYPES #define VPX_DONT_DEFINE_STDINT_TYPES
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
@ -147,6 +148,7 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
mOpusParser(nullptr), mOpusParser(nullptr),
mOpusDecoder(nullptr), mOpusDecoder(nullptr),
mSkip(0), mSkip(0),
mSeekPreroll(0),
#endif #endif
mVideoTrack(0), mVideoTrack(0),
mAudioTrack(0), mAudioTrack(0),
@ -218,10 +220,20 @@ nsresult WebMReader::ResetDecode()
res = NS_ERROR_FAILURE; res = NS_ERROR_FAILURE;
} }
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
// Ignore failed results from vorbis_synthesis_restart. They // Ignore failed results from vorbis_synthesis_restart. They
// aren't fatal and it fails when ResetDecode is called at a // aren't fatal and it fails when ResetDecode is called at a
// time when no vorbis data has been read. // time when no vorbis data has been read.
vorbis_synthesis_restart(&mVorbisDsp); vorbis_synthesis_restart(&mVorbisDsp);
#ifdef MOZ_OPUS
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
if (mOpusDecoder) {
// Reset the decoder.
opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE);
mSkip = mOpusParser->mPreSkip;
}
#endif
}
mVideoPackets.Reset(); mVideoPackets.Reset();
mAudioPackets.Reset(); mAudioPackets.Reset();
@ -431,6 +443,8 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
mInfo.mAudio.mChannels = mOpusParser->mChannels; mInfo.mAudio.mChannels = mOpusParser->mChannels;
mInfo.mAudio.mChannels = mInfo.mAudio.mChannels > 2 ? 2 : mInfo.mAudio.mChannels; mInfo.mAudio.mChannels = mInfo.mAudio.mChannels > 2 ? 2 : mInfo.mAudio.mChannels;
mChannels = mInfo.mAudio.mChannels;
mSeekPreroll = params.seek_preroll;
#endif #endif
} else { } else {
Cleanup(); Cleanup();
@ -627,6 +641,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
if (ret < 0) if (ret < 0)
return false; return false;
NS_ASSERTION(ret == frames, "Opus decoded too few audio samples"); NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
CheckedInt64 startTime = tstamp_usecs;
// Trim the initial frames while the decoder is settling. // Trim the initial frames while the decoder is settling.
if (mSkip > 0) { if (mSkip > 0) {
@ -643,7 +658,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]); nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
trimBuffer[i] = buffer[skipFrames*channels + i]; trimBuffer[i] = buffer[skipFrames*channels + i];
startTime = startTime + FramesToUsecs(skipFrames, rate);
frames = keepFrames; frames = keepFrames;
buffer = trimBuffer; buffer = trimBuffer;
@ -708,14 +723,12 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
NS_WARNING("Int overflow converting WebM audio duration"); NS_WARNING("Int overflow converting WebM audio duration");
return false; return false;
} }
CheckedInt64 time = startTime - (mCodecDelay / NS_PER_USEC);
CheckedInt64 time = tstamp_usecs;
if (!time.isValid()) { if (!time.isValid()) {
NS_WARNING("Int overflow adding total_duration and tstamp_usecs"); NS_WARNING("Int overflow shifting tstamp by codec delay");
nestegg_free_packet(aPacket); nestegg_free_packet(aPacket);
return false; return false;
}; };
AudioQueue().Push(new AudioData(mDecoder->GetResource()->Tell(), AudioQueue().Push(new AudioData(mDecoder->GetResource()->Tell(),
time.value(), time.value(),
duration.value(), duration.value(),
@ -982,7 +995,11 @@ nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack; uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack;
int r = nestegg_track_seek(mContext, trackToSeek, aTarget * NS_PER_USEC); uint64_t target = aTarget * NS_PER_USEC;
if (mSeekPreroll) {
target = std::max(static_cast<uint64_t>(aStartTime * NS_PER_USEC), target - mSeekPreroll);
}
int r = nestegg_track_seek(mContext, trackToSeek, target);
if (r != 0) { if (r != 0) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

View File

@ -197,6 +197,7 @@ private:
nsAutoPtr<OpusParser> mOpusParser; nsAutoPtr<OpusParser> mOpusParser;
OpusMSDecoder *mOpusDecoder; OpusMSDecoder *mOpusDecoder;
int mSkip; // Number of samples left to trim before playback. int mSkip; // Number of samples left to trim before playback.
uint64_t mSeekPreroll; // Number of nanoseconds that must be discarded after seeking.
#endif #endif
// Queue of video and audio packets that have been read but not decoded. These // Queue of video and audio packets that have been read but not decoded. These