mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1098126 - Add CENC support to MoofParser; r=edwin
This commit is contained in:
parent
2140036c4f
commit
8a5dd08528
@ -165,6 +165,8 @@ public:
|
||||
std::max(mEnd, aByteRange.mEnd));
|
||||
}
|
||||
|
||||
int64_t Length() { return mEnd - mStart; }
|
||||
|
||||
int64_t mStart, mEnd;
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@ using namespace mozilla;
|
||||
namespace mp4_demuxer {
|
||||
|
||||
Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent)
|
||||
: mContext(aContext), mType(0), mParent(aParent)
|
||||
: mContext(aContext), mParent(aParent)
|
||||
{
|
||||
uint8_t header[8];
|
||||
MediaByteRange headerRange(aOffset, aOffset + sizeof(header));
|
||||
@ -69,7 +69,7 @@ Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent)
|
||||
}
|
||||
|
||||
Box::Box()
|
||||
: mContext(nullptr), mType(0)
|
||||
: mContext(nullptr)
|
||||
{}
|
||||
|
||||
Box
|
||||
|
@ -2,6 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mp4_demuxer/ByteReader.h"
|
||||
#include "mp4_demuxer/Index.h"
|
||||
#include "mp4_demuxer/Interval.h"
|
||||
#include "mp4_demuxer/MoofParser.h"
|
||||
@ -84,27 +85,54 @@ SampleIterator::SampleIterator(Index* aIndex)
|
||||
|
||||
MP4Sample* SampleIterator::GetNext()
|
||||
{
|
||||
nsAutoPtr<MP4Sample> sample(Get());
|
||||
if (!sample) {
|
||||
Sample* s(Get());
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Next();
|
||||
|
||||
nsAutoPtr<MP4Sample> sample(new MP4Sample());
|
||||
sample->decode_timestamp = s->mDecodeTime;
|
||||
sample->composition_timestamp = s->mCompositionRange.start;
|
||||
sample->duration = s->mCompositionRange.Length();
|
||||
sample->byte_offset = s->mByteRange.mStart;
|
||||
sample->is_sync_point = s->mSync;
|
||||
sample->size = s->mByteRange.Length();
|
||||
|
||||
// Do the blocking read
|
||||
sample->data = sample->extra_buffer = new uint8_t[sample->size];
|
||||
|
||||
size_t bytesRead;
|
||||
mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
|
||||
&bytesRead);
|
||||
if (!mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
|
||||
&bytesRead) || bytesRead != sample->size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Lets just return what we've got so that we propagate the error
|
||||
sample->size = bytesRead;
|
||||
|
||||
Next();
|
||||
if (!s->mCencRange.IsNull()) {
|
||||
// The size comes from an 8 bit field
|
||||
nsAutoTArray<uint8_t, 256> cenc;
|
||||
cenc.SetLength(s->mCencRange.Length());
|
||||
if (!mIndex->mSource->ReadAt(s->mCencRange.mStart, &cenc[0], cenc.Length(),
|
||||
&bytesRead) || bytesRead != cenc.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
ByteReader reader(cenc);
|
||||
sample->crypto.valid = true;
|
||||
reader.ReadArray(sample->crypto.iv, 16);
|
||||
if (reader.Remaining()) {
|
||||
uint16_t count = reader.ReadU16();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
sample->crypto.plain_sizes.AppendElement(reader.ReadU16());
|
||||
sample->crypto.encrypted_sizes.AppendElement(reader.ReadU32());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
MP4Sample* SampleIterator::Get()
|
||||
Sample* SampleIterator::Get()
|
||||
{
|
||||
if (!mIndex->mMoofParser) {
|
||||
return nullptr;
|
||||
@ -114,7 +142,7 @@ MP4Sample* SampleIterator::Get()
|
||||
while (true) {
|
||||
if (mCurrentMoof == moofs.Length()) {
|
||||
if (!mIndex->mMoofParser->BlockingReadNextMoof()) {
|
||||
return nsAutoPtr<MP4Sample>();
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mCurrentMoof < moofs.Length());
|
||||
}
|
||||
@ -124,17 +152,7 @@ MP4Sample* SampleIterator::Get()
|
||||
mCurrentSample = 0;
|
||||
++mCurrentMoof;
|
||||
}
|
||||
Sample& s = moofs[mCurrentMoof].mIndex[mCurrentSample];
|
||||
nsAutoPtr<MP4Sample> sample(new MP4Sample());
|
||||
sample->decode_timestamp = s.mDecodeTime;
|
||||
sample->composition_timestamp = s.mCompositionRange.start;
|
||||
sample->duration = s.mCompositionRange.end - s.mCompositionRange.start;
|
||||
sample->byte_offset = s.mByteRange.mStart;
|
||||
sample->is_sync_point = s.mSync;
|
||||
|
||||
sample->size = s.mByteRange.mEnd - s.mByteRange.mStart;
|
||||
|
||||
return sample.forget();
|
||||
return &moofs[mCurrentMoof].mIndex[mCurrentSample];
|
||||
}
|
||||
|
||||
void SampleIterator::Next()
|
||||
@ -148,16 +166,16 @@ void SampleIterator::Seek(Microseconds aTime)
|
||||
size_t syncSample = 0;
|
||||
mCurrentMoof = 0;
|
||||
mCurrentSample = 0;
|
||||
while (true) {
|
||||
nsAutoPtr<MP4Sample> sample(Get());
|
||||
if (sample->composition_timestamp > aTime) {
|
||||
Sample* sample;
|
||||
while (!!(sample = Get())) {
|
||||
if (sample->mCompositionRange.start > aTime) {
|
||||
break;
|
||||
}
|
||||
if (sample->is_sync_point) {
|
||||
if (sample->mSync) {
|
||||
syncMoof = mCurrentMoof;
|
||||
syncSample = mCurrentSample;
|
||||
}
|
||||
if (sample->composition_timestamp == aTime) {
|
||||
if (sample->mCompositionRange.start == aTime) {
|
||||
break;
|
||||
}
|
||||
Next();
|
||||
|
@ -173,6 +173,71 @@ Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts) :
|
||||
ParseTraf(box, aTrex, aMdhd, aEdts);
|
||||
}
|
||||
}
|
||||
ProcessCenc();
|
||||
}
|
||||
|
||||
bool
|
||||
Moof::GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges)
|
||||
{
|
||||
aByteRanges->Clear();
|
||||
|
||||
Saiz* saiz = nullptr;
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == mSaizs.Length()) {
|
||||
return false;
|
||||
}
|
||||
if (mSaizs[i].mAuxInfoType == aType) {
|
||||
saiz = &mSaizs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Saio* saio = nullptr;
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == mSaios.Length()) {
|
||||
return false;
|
||||
}
|
||||
if (mSaios[i].mAuxInfoType == aType) {
|
||||
saio = &mSaios[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (saio->mOffsets.Length() == 1) {
|
||||
aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
|
||||
uint64_t offset = mRange.mStart + saio->mOffsets[0];
|
||||
for (size_t i = 0; i < saiz->mSampleInfoSize.Length(); i++) {
|
||||
aByteRanges->AppendElement(
|
||||
MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
|
||||
offset += saiz->mSampleInfoSize[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (saio->mOffsets.Length() == saiz->mSampleInfoSize.Length()) {
|
||||
aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
|
||||
for (size_t i = 0; i < saio->mOffsets.Length(); i++) {
|
||||
uint64_t offset = mRange.mStart + saio->mOffsets[i];
|
||||
aByteRanges->AppendElement(
|
||||
MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Moof::ProcessCenc()
|
||||
{
|
||||
nsTArray<MediaByteRange> cencRanges;
|
||||
if (!GetAuxInfo(AtomType("cenc"), &cencRanges) ||
|
||||
cencRanges.Length() != mIndex.Length()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < cencRanges.Length(); i++) {
|
||||
mIndex[i].mCencRange = cencRanges[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -191,6 +256,10 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts)
|
||||
if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
|
||||
ParseTrun(box, tfhd, tfdt, aMdhd, aEdts);
|
||||
}
|
||||
} else if (box.IsType("saiz")) {
|
||||
mSaizs.AppendElement(Saiz(box));
|
||||
} else if (box.IsType("saio")) {
|
||||
mSaios.AppendElement(Saio(box));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,7 +354,7 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts)
|
||||
}
|
||||
ctsOrder.Sort(CtsComparator());
|
||||
|
||||
for (int i = 0; i < ctsOrder.Length(); i++) {
|
||||
for (size_t i = 0; i < ctsOrder.Length(); i++) {
|
||||
if (i + 1 < ctsOrder.Length()) {
|
||||
ctsOrder[i]->mCompositionRange.end = ctsOrder[i + 1]->mCompositionRange.start;
|
||||
}
|
||||
@ -417,4 +486,48 @@ Edts::Edts(Box& aBox)
|
||||
NS_ASSERTION(segment_duration == 0, "Can't handle edits with fixed durations");
|
||||
reader->DiscardRemaining();
|
||||
}
|
||||
|
||||
Saiz::Saiz(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
|
||||
{
|
||||
BoxReader reader(aBox);
|
||||
uint32_t flags = reader->ReadU32();
|
||||
uint8_t version = flags >> 24;
|
||||
|
||||
if (flags & 1) {
|
||||
mAuxInfoType = reader->ReadU32();
|
||||
mAuxInfoTypeParameter = reader->ReadU32();
|
||||
}
|
||||
uint8_t defaultSampleInfoSize = reader->ReadU8();
|
||||
uint32_t count = reader->ReadU32();
|
||||
if (defaultSampleInfoSize) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
mSampleInfoSize.AppendElement(defaultSampleInfoSize);
|
||||
}
|
||||
} else {
|
||||
reader->ReadArray(mSampleInfoSize, count);
|
||||
}
|
||||
}
|
||||
|
||||
Saio::Saio(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
|
||||
{
|
||||
BoxReader reader(aBox);
|
||||
uint32_t flags = reader->ReadU32();
|
||||
uint8_t version = flags >> 24;
|
||||
|
||||
if (flags & 1) {
|
||||
mAuxInfoType = reader->ReadU32();
|
||||
mAuxInfoTypeParameter = reader->ReadU32();
|
||||
}
|
||||
size_t count = reader->ReadU32();
|
||||
mOffsets.SetCapacity(count);
|
||||
if (version == 0) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
mOffsets.AppendElement(reader->ReadU32());
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
mOffsets.AppendElement(reader->ReadU64());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
media/libstagefright/binding/include/mp4_demuxer/AtomType.h
Normal file
30
media/libstagefright/binding/include/mp4_demuxer/AtomType.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ATOM_TYPE_H_
|
||||
#define ATOM_TYPE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozilla/Endian.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mp4_demuxer {
|
||||
|
||||
class AtomType
|
||||
{
|
||||
public:
|
||||
AtomType() : mType(0) { }
|
||||
AtomType(uint32_t aType) : mType(aType) { }
|
||||
AtomType(const char* aType) : mType(BigEndian::readUint32(aType)) { }
|
||||
bool operator==(const AtomType& aType) const { return mType == aType.mType; }
|
||||
|
||||
private:
|
||||
uint32_t mType;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mp4_demuxer/AtomType.h"
|
||||
#include "mp4_demuxer/ByteReader.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -42,13 +43,8 @@ public:
|
||||
uint64_t Length() const { return mRange.mEnd - mRange.mStart; }
|
||||
uint64_t NextOffset() const { return mRange.mEnd; }
|
||||
const MediaByteRange& Range() const { return mRange; }
|
||||
|
||||
const Box* Parent() const { return mParent; }
|
||||
|
||||
bool IsType(const char* aType) const
|
||||
{
|
||||
return mType == BigEndian::readUint32(aType);
|
||||
}
|
||||
bool IsType(const char* aType) const { return mType == AtomType(aType); }
|
||||
|
||||
Box Next() const;
|
||||
Box FirstChild() const;
|
||||
@ -59,7 +55,7 @@ private:
|
||||
BoxContext* mContext;
|
||||
mozilla::MediaByteRange mRange;
|
||||
uint64_t mChildOffset;
|
||||
uint32_t mType;
|
||||
AtomType mType;
|
||||
const Box* mParent;
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,12 @@ public:
|
||||
: mPtr(aData), mRemaining(aSize)
|
||||
{
|
||||
}
|
||||
template<size_t S>
|
||||
ByteReader(const nsAutoTArray<uint8_t, S>& aData)
|
||||
: mPtr(&aData[0]), mRemaining(aData.Length())
|
||||
{
|
||||
}
|
||||
|
||||
void SetData(const nsTArray<uint8_t>& aData)
|
||||
{
|
||||
MOZ_ASSERT(!mPtr && !mRemaining);
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
void Seek(Microseconds aTime);
|
||||
|
||||
private:
|
||||
MP4Sample* Get();
|
||||
Sample* Get();
|
||||
void Next();
|
||||
nsRefPtr<Index> mIndex;
|
||||
size_t mCurrentMoof;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef MOOF_PARSER_H_
|
||||
#define MOOF_PARSER_H_
|
||||
|
||||
#include "mp4_demuxer/AtomType.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
@ -109,15 +110,49 @@ public:
|
||||
struct Sample
|
||||
{
|
||||
mozilla::MediaByteRange mByteRange;
|
||||
mozilla::MediaByteRange mCencRange;
|
||||
Microseconds mDecodeTime;
|
||||
Interval<Microseconds> mCompositionRange;
|
||||
bool mSync;
|
||||
};
|
||||
|
||||
class Saiz
|
||||
{
|
||||
public:
|
||||
Saiz(Box& aBox);
|
||||
|
||||
AtomType mAuxInfoType;
|
||||
uint32_t mAuxInfoTypeParameter;
|
||||
nsTArray<uint8_t> mSampleInfoSize;
|
||||
};
|
||||
|
||||
class Saio
|
||||
{
|
||||
public:
|
||||
Saio(Box& aBox);
|
||||
|
||||
AtomType mAuxInfoType;
|
||||
uint32_t mAuxInfoTypeParameter;
|
||||
nsTArray<uint64_t> mOffsets;
|
||||
};
|
||||
|
||||
class AuxInfo {
|
||||
public:
|
||||
AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio);
|
||||
bool GetByteRanges(nsTArray<MediaByteRange>* aByteRanges);
|
||||
|
||||
private:
|
||||
|
||||
int64_t mMoofOffset;
|
||||
Saiz& mSaiz;
|
||||
Saio& mSaio;
|
||||
};
|
||||
|
||||
class Moof
|
||||
{
|
||||
public:
|
||||
Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts);
|
||||
bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
|
||||
void FixRounding(const Moof& aMoof);
|
||||
|
||||
mozilla::MediaByteRange mRange;
|
||||
@ -125,9 +160,15 @@ public:
|
||||
Interval<Microseconds> mTimeRange;
|
||||
nsTArray<Sample> mIndex;
|
||||
|
||||
nsTArray<Saiz> mSaizs;
|
||||
nsTArray<Saio> mSaios;
|
||||
|
||||
private:
|
||||
void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts);
|
||||
void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts);
|
||||
void ParseSaiz(Box& aBox);
|
||||
void ParseSaio(Box& aBox);
|
||||
bool ProcessCenc();
|
||||
uint64_t mMaxRoundingError;
|
||||
};
|
||||
|
||||
|
@ -185,7 +185,15 @@ MP4Sample*
|
||||
MP4Demuxer::DemuxAudioSample()
|
||||
{
|
||||
if (mPrivate->mAudioIterator) {
|
||||
return mPrivate->mAudioIterator->GetNext();
|
||||
nsAutoPtr<MP4Sample> sample(mPrivate->mAudioIterator->GetNext());
|
||||
if (sample) {
|
||||
if (sample->crypto.valid) {
|
||||
sample->crypto.mode = mAudioConfig.crypto.mode;
|
||||
sample->crypto.iv_size = mAudioConfig.crypto.iv_size;
|
||||
sample->crypto.key.AppendElements(mAudioConfig.crypto.key);
|
||||
}
|
||||
}
|
||||
return sample.forget();
|
||||
}
|
||||
|
||||
nsAutoPtr<MP4Sample> sample(new MP4Sample());
|
||||
@ -209,6 +217,11 @@ MP4Demuxer::DemuxVideoSample()
|
||||
nsAutoPtr<MP4Sample> sample(mPrivate->mVideoIterator->GetNext());
|
||||
if (sample) {
|
||||
sample->prefix_data = mVideoConfig.annex_b;
|
||||
if (sample->crypto.valid) {
|
||||
sample->crypto.mode = mVideoConfig.crypto.mode;
|
||||
sample->crypto.iv_size = mVideoConfig.crypto.iv_size;
|
||||
sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
|
||||
}
|
||||
}
|
||||
return sample.forget();
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ if CONFIG['OS_TARGET'] != 'Android':
|
||||
EXPORTS.mp4_demuxer += [
|
||||
'binding/include/mp4_demuxer/Adts.h',
|
||||
'binding/include/mp4_demuxer/AnnexB.h',
|
||||
'binding/include/mp4_demuxer/AtomType.h',
|
||||
'binding/include/mp4_demuxer/BufferStream.h',
|
||||
'binding/include/mp4_demuxer/ByteReader.h',
|
||||
'binding/include/mp4_demuxer/DecoderData.h',
|
||||
|
Loading…
Reference in New Issue
Block a user