зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1240201: [vorbis] P1. Properly determine sample duration and time in webm demuxer. r=kinetik
This commit is contained in:
Родитель
05e96f1126
Коммит
9b20eae811
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче