Bug 1240201: [vorbis] P1. Properly determine sample duration and time in webm demuxer. r=kinetik

This commit is contained in:
Jean-Yves Avenard 2016-01-21 02:26:49 +11:00
Родитель 05e96f1126
Коммит 9b20eae811
4 изменённых файлов: 119 добавлений и 4 удалений

Просмотреть файл

@ -17,9 +17,63 @@ extern mozilla::LogModule* GetPDMLog();
namespace mozilla {
ogg_packet InitVorbisPacket(const unsigned char* aData, size_t aLength,
bool aBOS, bool aEOS,
int64_t aGranulepos, int64_t aPacketNo)
VorbisPacketSampleCounter::VorbisPacketSampleCounter()
: mError(0)
, mVorbisPacketCount(0)
{
vorbis_info_init(&mVorbisInfo);
vorbis_comment_init(&mVorbisComment);
}
bool
VorbisPacketSampleCounter::Init(const nsTArray<const uint8_t*>& aHeaders,
const nsTArray<size_t>& aHeaderLens)
{
for (size_t i = 0; i < aHeaders.Length(); i++) {
ogg_packet pkt =
VorbisDataDecoder::InitVorbisPacket(aHeaders[i], aHeaderLens[i],
i == 0, false, 0, mVorbisPacketCount++);
if ((mError = vorbis_synthesis_headerin(&mVorbisInfo, &mVorbisComment, &pkt))) {
return false;
}
}
return true;
}
int
VorbisPacketSampleCounter::GetNumSamples(const uint8_t* aData, size_t aLength)
{
if (mError) {
return -1;
}
ogg_packet pkt =
VorbisDataDecoder::InitVorbisPacket(aData, aLength, false, false, -1, mVorbisPacketCount++);
long blockSize = vorbis_packet_blocksize(&mVorbisInfo, &pkt);
if (blockSize < 0) {
return blockSize;
}
int nsamples;
if (mVorbisLastBlockSize) {
nsamples = mVorbisLastBlockSize.ref() / 4 + blockSize / 4;
} else {
// The first packet will output no audio, so set its count as 0.
nsamples = 0;
}
mVorbisLastBlockSize = Some(blockSize);
return nsamples;
}
VorbisPacketSampleCounter::~VorbisPacketSampleCounter()
{
vorbis_info_clear(&mVorbisInfo);
vorbis_comment_clear(&mVorbisComment);
}
/* static */
ogg_packet
VorbisDataDecoder::InitVorbisPacket(const unsigned char* aData, size_t aLength,
bool aBOS, bool aEOS,
int64_t aGranulepos, int64_t aPacketNo)
{
ogg_packet packet;
packet.packet = const_cast<unsigned char*>(aData);

Просмотреть файл

@ -17,6 +17,25 @@
namespace mozilla {
class VorbisPacketSampleCounter
{
public:
VorbisPacketSampleCounter();
~VorbisPacketSampleCounter();
bool Init(const nsTArray<const uint8_t*>& aHeaders,
const nsTArray<size_t>& aHeaderLens);
int GetNumSamples(const uint8_t* aData, size_t aLength);
void Reset() { mVorbisLastBlockSize.reset(); }
private:
int mError;
vorbis_info mVorbisInfo;
vorbis_comment mVorbisComment;
int64_t mVorbisPacketCount;
Maybe<long> mVorbisLastBlockSize;
};
class VorbisDataDecoder : public MediaDataDecoder
{
public:
@ -34,6 +53,10 @@ public:
// Return true if mimetype is Vorbis
static bool IsVorbis(const nsACString& aMimeType);
static ogg_packet InitVorbisPacket(const unsigned char* aData, size_t aLength,
bool aBOS, bool aEOS,
int64_t aGranulepos, int64_t aPacketNo);
private:
nsresult DecodeHeader(const unsigned char* aData, size_t aLength);

Просмотреть файл

@ -12,11 +12,13 @@
#include "WebMBufferedParser.h"
#include "gfx2DGlue.h"
#include "mozilla/Endian.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Preferences.h"
#include "mozilla/SharedThreadPool.h"
#include "MediaDataDemuxer.h"
#include "nsAutoRef.h"
#include "NesteggPacketHolder.h"
#include "VideoUtils.h"
#include "XiphExtradata.h"
#include "prprf.h"
@ -417,6 +419,13 @@ WebMDemuxer::ReadMetadata()
mInfo.mAudio.mCodecSpecificConfig->AppendElements(headers[0],
headerLens[0]);
}
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
if (!mVorbisCounter.Init(headers, headerLens)) {
return NS_ERROR_FAILURE;
}
}
uint64_t duration = 0;
r = nestegg_duration(mContext, &duration);
if (!r) {
@ -542,6 +551,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
(void) nestegg_packet_discard_padding(holder->Packet(), &discardPadding);
for (uint32_t i = 0; i < count; ++i) {
int64_t duration = next_tstamp - tstamp;
unsigned char* data;
size_t length;
r = nestegg_packet_data(holder->Packet(), i, &data, &length);
@ -552,6 +562,26 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
bool isKeyframe = false;
if (aType == TrackInfo::kAudioTrack) {
isKeyframe = true;
// Check if we have more than one audio frame in a webm block, if so
// determine the duration of each individual frame.
// We make the last frame end time match the start time of the next block
// unless it would make the duration of that frame negative.
if (count > 1 && (i != count - 1 || duration <= 0)) {
switch (mAudioCodec) {
case NESTEGG_CODEC_VORBIS:
{
int nsamples = mVorbisCounter.GetNumSamples(data, length);
if (nsamples < 0) {
return false;
}
duration =
FramesToTimeUnit(nsamples, mInfo.mAudio.mRate).ToMicroseconds();
break;
}
default:
break;
}
}
} else if (aType == TrackInfo::kVideoTrack) {
vpx_codec_stream_info_t si;
PodZero(&si);
@ -572,7 +602,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
RefPtr<MediaRawData> sample = new MediaRawData(data, length);
sample->mTimecode = tstamp;
sample->mTime = tstamp;
sample->mDuration = next_tstamp - tstamp;
sample->mDuration = duration;
sample->mOffset = holder->Offset();
sample->mKeyframe = isKeyframe;
if (discardPadding) {
@ -582,6 +612,9 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl
sample->mExtraData->AppendElements(&c[0], 8);
}
aSamples->Push(sample);
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
tstamp += duration;
}
}
return true;
}
@ -721,6 +754,7 @@ WebMDemuxer::SeekInternal(const media::TimeUnit& aTarget)
mLastAudioFrameTime.reset();
mLastVideoFrameTime.reset();
mVorbisCounter.Reset();
return NS_OK;
}

Просмотреть файл

@ -9,8 +9,10 @@
#include "nsTArray.h"
#include "MediaDataDemuxer.h"
#include "NesteggPacketHolder.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "VorbisDecoder.h"
typedef struct nestegg nestegg;
namespace mozilla {
@ -199,6 +201,8 @@ private:
// as nestegg only performs 1-byte read at a time.
int64_t mLastWebMBlockOffset;
const bool mIsMediaSource;
VorbisPacketSampleCounter mVorbisCounter;
};
class WebMTrackDemuxer : public MediaTrackDemuxer