зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1022434 - Extract crypto information from MP4 demuxer; r=cpearce
* * * Bug 1022434 - "[EME] Expose decryption data in MP4Samples" []
This commit is contained in:
Родитель
11bdb873e7
Коммит
229a6bf2e3
|
@ -56,6 +56,14 @@ Adts::ConvertEsdsToAdts(uint16_t aChannelCount, int8_t aFrequencyIndex,
|
|||
header[6] = 0xfc;
|
||||
|
||||
aSample->Prepend(&header[0], ArrayLength(header));
|
||||
if (aSample->crypto.valid) {
|
||||
if (aSample->crypto.plain_sizes.Length() == 0) {
|
||||
aSample->crypto.plain_sizes.AppendElement(kADTSHeaderSize);
|
||||
aSample->crypto.encrypted_sizes.AppendElement(aSample->size - kADTSHeaderSize);
|
||||
} else {
|
||||
aSample->crypto.plain_sizes[0] += kADTSHeaderSize;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,94 @@ FindInt64(sp<MetaData>& mMetaData, uint32_t mKey)
|
|||
return value;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
static bool
|
||||
FindData(sp<MetaData>& aMetaData, uint32_t aKey, mozilla::Vector<T, N>* aDest)
|
||||
{
|
||||
const void* data;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
aDest->clear();
|
||||
// There's no point in checking that the type matches anything because it
|
||||
// isn't set consistently in the MPEG4Extractor.
|
||||
if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDest->append(reinterpret_cast<const T*>(data), size / sizeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool
|
||||
FindData(sp<MetaData>& aMetaData, uint32_t aKey, nsTArray<T>* aDest)
|
||||
{
|
||||
const void* data;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
aDest->Clear();
|
||||
// There's no point in checking that the type matches anything because it
|
||||
// isn't set consistently in the MPEG4Extractor.
|
||||
if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDest->AppendElements(reinterpret_cast<const T*>(data), size / sizeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoFile::DoUpdate(sp<MetaData>& aMetaData)
|
||||
{
|
||||
const void* data;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// There's no point in checking that the type matches anything because it
|
||||
// isn't set consistently in the MPEG4Extractor.
|
||||
if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteReader reader(reinterpret_cast<const uint8_t*>(data), size);
|
||||
while (reader.Remaining()) {
|
||||
PsshInfo psshInfo;
|
||||
if (!reader.ReadArray(psshInfo.uuid, 16)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader.CanReadType<uint32_t>()) {
|
||||
return false;
|
||||
}
|
||||
auto length = reader.ReadType<uint32_t>();
|
||||
|
||||
if (!reader.ReadArray(psshInfo.data, length)) {
|
||||
return false;
|
||||
}
|
||||
pssh.append(Move(psshInfo));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTrack::Update(sp<MetaData>& aMetaData)
|
||||
{
|
||||
valid = aMetaData->findInt32(kKeyCryptoMode, &mode) &&
|
||||
aMetaData->findInt32(kKeyCryptoDefaultIVSize, &iv_size) &&
|
||||
FindData(aMetaData, kKeyCryptoKey, &key);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoSample::Update(sp<MetaData>& aMetaData)
|
||||
{
|
||||
CryptoTrack::Update(aMetaData);
|
||||
valid = valid && FindData(aMetaData, kKeyPlainSizes, &plain_sizes) &&
|
||||
FindData(aMetaData, kKeyEncryptedSizes, &encrypted_sizes) &&
|
||||
FindData(aMetaData, kKeyCryptoIV, &iv);
|
||||
}
|
||||
|
||||
void
|
||||
AudioDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
|
||||
{
|
||||
|
@ -46,20 +134,18 @@ AudioDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
|
|||
frequency_index = Adts::GetFrequencyIndex(samples_per_second);
|
||||
aac_profile = FindInt32(aMetaData, kKeyAACProfile);
|
||||
|
||||
const void* data;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
if (aMetaData->findData(kKeyESDS, &type, &data, &size)) {
|
||||
extra_data.clear();
|
||||
extra_data.append(reinterpret_cast<const uint8_t*>(data), size);
|
||||
|
||||
if (FindData(aMetaData, kKeyESDS, &extra_data)) {
|
||||
ESDS esds(&extra_data[0], extra_data.length());
|
||||
|
||||
const void* data;
|
||||
size_t size;
|
||||
if (esds.getCodecSpecificInfo(&data, &size) == OK) {
|
||||
audio_specific_config.append(reinterpret_cast<const uint8_t*>(data),
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
crypto.Update(aMetaData);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -78,18 +164,14 @@ VideoDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
|
|||
display_width = FindInt32(aMetaData, kKeyDisplayWidth);
|
||||
display_height = FindInt32(aMetaData, kKeyDisplayHeight);
|
||||
|
||||
const void* data;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
if (aMetaData->findData(kKeyAVCC, &type, &data, &size) && size >= 7) {
|
||||
extra_data.clear();
|
||||
extra_data.append(reinterpret_cast<const uint8_t*>(data), size);
|
||||
if (FindData(aMetaData, kKeyAVCC, &extra_data) && extra_data.length() >= 7) {
|
||||
// Set size of the NAL length to 4. The demuxer formats its output with
|
||||
// this NAL length size.
|
||||
extra_data[4] |= 3;
|
||||
annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
|
||||
}
|
||||
|
||||
crypto.Update(aMetaData);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -126,6 +208,8 @@ MP4Sample::Update()
|
|||
is_sync_point = FindInt32(m, kKeyIsSyncFrame);
|
||||
data = reinterpret_cast<uint8_t*>(mMediaBuffer->data());
|
||||
size = mMediaBuffer->range_length();
|
||||
|
||||
crypto.Update(m);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define BYTE_READER_H_
|
||||
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
@ -13,7 +14,7 @@ namespace mp4_demuxer
|
|||
class ByteReader
|
||||
{
|
||||
public:
|
||||
ByteReader(mozilla::Vector<uint8_t>& aData)
|
||||
ByteReader(const mozilla::Vector<uint8_t>& aData)
|
||||
: mPtr(&aData[0]), mRemaining(aData.length())
|
||||
{
|
||||
}
|
||||
|
@ -72,6 +73,31 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
template <typename T> bool CanReadType() { return mRemaining >= sizeof(T); }
|
||||
|
||||
template <typename T> T ReadType()
|
||||
{
|
||||
auto ptr = Read(sizeof(T));
|
||||
if (!ptr) {
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
return *reinterpret_cast<const T*>(ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ReadArray(nsTArray<T>& aDest, size_t aLength)
|
||||
{
|
||||
auto ptr = Read(aLength * sizeof(T));
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDest.Clear();
|
||||
aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* mPtr;
|
||||
size_t mRemaining;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace stagefright
|
||||
|
@ -21,6 +22,51 @@ namespace mp4_demuxer
|
|||
|
||||
class MP4Demuxer;
|
||||
|
||||
struct PsshInfo
|
||||
{
|
||||
PsshInfo() {}
|
||||
PsshInfo(PsshInfo&& aOther) : uuid(aOther.uuid), data(aOther.data) {}
|
||||
nsTArray<uint8_t> uuid;
|
||||
nsTArray<uint8_t> data;
|
||||
};
|
||||
|
||||
class CryptoFile
|
||||
{
|
||||
public:
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData)
|
||||
{
|
||||
valid = DoUpdate(aMetaData);
|
||||
}
|
||||
|
||||
bool valid;
|
||||
mozilla::Vector<PsshInfo> pssh;
|
||||
|
||||
private:
|
||||
bool DoUpdate(stagefright::sp<stagefright::MetaData>& aMetaData);
|
||||
};
|
||||
|
||||
class CryptoTrack
|
||||
{
|
||||
public:
|
||||
CryptoTrack() : valid(false) {}
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData);
|
||||
|
||||
bool valid;
|
||||
int32_t mode;
|
||||
int32_t iv_size;
|
||||
nsTArray<uint8_t> key;
|
||||
};
|
||||
|
||||
class CryptoSample : public CryptoTrack
|
||||
{
|
||||
public:
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData);
|
||||
|
||||
nsTArray<uint16_t> plain_sizes;
|
||||
nsTArray<uint32_t> encrypted_sizes;
|
||||
nsTArray<uint8_t> iv;
|
||||
};
|
||||
|
||||
class AudioDecoderConfig
|
||||
{
|
||||
public:
|
||||
|
@ -42,6 +88,7 @@ public:
|
|||
int8_t frequency_index;
|
||||
mozilla::Vector<uint8_t> extra_data;
|
||||
mozilla::Vector<uint8_t> audio_specific_config;
|
||||
CryptoTrack crypto;
|
||||
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
||||
bool IsValid();
|
||||
|
@ -69,6 +116,7 @@ public:
|
|||
|
||||
mozilla::Vector<uint8_t> extra_data; // Unparsed AVCDecoderConfig payload.
|
||||
mozilla::Vector<uint8_t> annex_b; // Parsed version for sample prepend.
|
||||
CryptoTrack crypto;
|
||||
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
||||
bool IsValid();
|
||||
|
@ -94,6 +142,8 @@ public:
|
|||
uint8_t* data;
|
||||
size_t size;
|
||||
|
||||
CryptoSample crypto;
|
||||
|
||||
void Prepend(const uint8_t* aData, size_t aSize);
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
MP4Sample* DemuxAudioSample();
|
||||
MP4Sample* DemuxVideoSample();
|
||||
|
||||
const CryptoFile& Crypto() { return mCrypto; }
|
||||
const AudioDecoderConfig& AudioConfig() { return mAudioConfig; }
|
||||
const VideoDecoderConfig& VideoConfig() { return mVideoConfig; }
|
||||
|
||||
|
@ -62,6 +63,7 @@ public:
|
|||
private:
|
||||
AudioDecoderConfig mAudioConfig;
|
||||
VideoDecoderConfig mVideoConfig;
|
||||
CryptoFile mCrypto;
|
||||
|
||||
nsAutoPtr<StageFrightPrivate> mPrivate;
|
||||
};
|
||||
|
|
|
@ -111,6 +111,8 @@ MP4Demuxer::Init()
|
|||
mPrivate->mVideoIndex.Init(index);
|
||||
}
|
||||
}
|
||||
sp<MetaData> metaData = e->getMetaData();
|
||||
mCrypto.Update(metaData);
|
||||
|
||||
return mPrivate->mAudio.get() || mPrivate->mVideo.get();
|
||||
}
|
||||
|
|
|
@ -137,12 +137,12 @@ private:
|
|||
|
||||
struct Sample {
|
||||
off64_t offset;
|
||||
size_t size;
|
||||
uint32_t size;
|
||||
uint32_t duration;
|
||||
uint32_t ctsOffset;
|
||||
uint8_t iv[16];
|
||||
Vector<size_t> clearsizes;
|
||||
Vector<size_t> encryptedsizes;
|
||||
Vector<uint16_t> clearsizes;
|
||||
Vector<uint32_t> encryptedsizes;
|
||||
};
|
||||
Vector<Sample> mCurrentSamples;
|
||||
|
||||
|
@ -1522,7 +1522,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
|
|||
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
|
||||
|
||||
if (mPath.size() >= 2
|
||||
&& mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a')) {
|
||||
&& (mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a') ||
|
||||
(mPath[mPath.size() - 2] == FOURCC('e', 'n', 'c', 'a')))) {
|
||||
// Information from the ESDS must be relied on for proper
|
||||
// setup of sample rate and channel count for MPEG4 Audio.
|
||||
// The generic header appears to only contain generic
|
||||
|
|
Загрузка…
Ссылка в новой задаче