зеркало из 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;
|
header[6] = 0xfc;
|
||||||
|
|
||||||
aSample->Prepend(&header[0], ArrayLength(header));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,94 @@ FindInt64(sp<MetaData>& mMetaData, uint32_t mKey)
|
||||||
return value;
|
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
|
void
|
||||||
AudioDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
|
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);
|
frequency_index = Adts::GetFrequencyIndex(samples_per_second);
|
||||||
aac_profile = FindInt32(aMetaData, kKeyAACProfile);
|
aac_profile = FindInt32(aMetaData, kKeyAACProfile);
|
||||||
|
|
||||||
const void* data;
|
if (FindData(aMetaData, kKeyESDS, &extra_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);
|
|
||||||
|
|
||||||
ESDS esds(&extra_data[0], extra_data.length());
|
ESDS esds(&extra_data[0], extra_data.length());
|
||||||
|
|
||||||
|
const void* data;
|
||||||
|
size_t size;
|
||||||
if (esds.getCodecSpecificInfo(&data, &size) == OK) {
|
if (esds.getCodecSpecificInfo(&data, &size) == OK) {
|
||||||
audio_specific_config.append(reinterpret_cast<const uint8_t*>(data),
|
audio_specific_config.append(reinterpret_cast<const uint8_t*>(data),
|
||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crypto.Update(aMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -78,18 +164,14 @@ VideoDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
|
||||||
display_width = FindInt32(aMetaData, kKeyDisplayWidth);
|
display_width = FindInt32(aMetaData, kKeyDisplayWidth);
|
||||||
display_height = FindInt32(aMetaData, kKeyDisplayHeight);
|
display_height = FindInt32(aMetaData, kKeyDisplayHeight);
|
||||||
|
|
||||||
const void* data;
|
if (FindData(aMetaData, kKeyAVCC, &extra_data) && extra_data.length() >= 7) {
|
||||||
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);
|
|
||||||
// Set size of the NAL length to 4. The demuxer formats its output with
|
// Set size of the NAL length to 4. The demuxer formats its output with
|
||||||
// this NAL length size.
|
// this NAL length size.
|
||||||
extra_data[4] |= 3;
|
extra_data[4] |= 3;
|
||||||
annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
|
annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crypto.Update(aMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -126,6 +208,8 @@ MP4Sample::Update()
|
||||||
is_sync_point = FindInt32(m, kKeyIsSyncFrame);
|
is_sync_point = FindInt32(m, kKeyIsSyncFrame);
|
||||||
data = reinterpret_cast<uint8_t*>(mMediaBuffer->data());
|
data = reinterpret_cast<uint8_t*>(mMediaBuffer->data());
|
||||||
size = mMediaBuffer->range_length();
|
size = mMediaBuffer->range_length();
|
||||||
|
|
||||||
|
crypto.Update(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define BYTE_READER_H_
|
#define BYTE_READER_H_
|
||||||
|
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
namespace mp4_demuxer
|
namespace mp4_demuxer
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,7 @@ namespace mp4_demuxer
|
||||||
class ByteReader
|
class ByteReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ByteReader(mozilla::Vector<uint8_t>& aData)
|
ByteReader(const mozilla::Vector<uint8_t>& aData)
|
||||||
: mPtr(&aData[0]), mRemaining(aData.length())
|
: mPtr(&aData[0]), mRemaining(aData.length())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -72,6 +73,31 @@ public:
|
||||||
return result;
|
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:
|
private:
|
||||||
const uint8_t* mPtr;
|
const uint8_t* mPtr;
|
||||||
size_t mRemaining;
|
size_t mRemaining;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "mozilla/Types.h"
|
#include "mozilla/Types.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
|
|
||||||
namespace stagefright
|
namespace stagefright
|
||||||
|
@ -21,6 +22,51 @@ namespace mp4_demuxer
|
||||||
|
|
||||||
class MP4Demuxer;
|
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
|
class AudioDecoderConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -42,6 +88,7 @@ public:
|
||||||
int8_t frequency_index;
|
int8_t frequency_index;
|
||||||
mozilla::Vector<uint8_t> extra_data;
|
mozilla::Vector<uint8_t> extra_data;
|
||||||
mozilla::Vector<uint8_t> audio_specific_config;
|
mozilla::Vector<uint8_t> audio_specific_config;
|
||||||
|
CryptoTrack crypto;
|
||||||
|
|
||||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
||||||
bool IsValid();
|
bool IsValid();
|
||||||
|
@ -69,6 +116,7 @@ public:
|
||||||
|
|
||||||
mozilla::Vector<uint8_t> extra_data; // Unparsed AVCDecoderConfig payload.
|
mozilla::Vector<uint8_t> extra_data; // Unparsed AVCDecoderConfig payload.
|
||||||
mozilla::Vector<uint8_t> annex_b; // Parsed version for sample prepend.
|
mozilla::Vector<uint8_t> annex_b; // Parsed version for sample prepend.
|
||||||
|
CryptoTrack crypto;
|
||||||
|
|
||||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
|
||||||
bool IsValid();
|
bool IsValid();
|
||||||
|
@ -94,6 +142,8 @@ public:
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
CryptoSample crypto;
|
||||||
|
|
||||||
void Prepend(const uint8_t* aData, size_t aSize);
|
void Prepend(const uint8_t* aData, size_t aSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
MP4Sample* DemuxAudioSample();
|
MP4Sample* DemuxAudioSample();
|
||||||
MP4Sample* DemuxVideoSample();
|
MP4Sample* DemuxVideoSample();
|
||||||
|
|
||||||
|
const CryptoFile& Crypto() { return mCrypto; }
|
||||||
const AudioDecoderConfig& AudioConfig() { return mAudioConfig; }
|
const AudioDecoderConfig& AudioConfig() { return mAudioConfig; }
|
||||||
const VideoDecoderConfig& VideoConfig() { return mVideoConfig; }
|
const VideoDecoderConfig& VideoConfig() { return mVideoConfig; }
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ public:
|
||||||
private:
|
private:
|
||||||
AudioDecoderConfig mAudioConfig;
|
AudioDecoderConfig mAudioConfig;
|
||||||
VideoDecoderConfig mVideoConfig;
|
VideoDecoderConfig mVideoConfig;
|
||||||
|
CryptoFile mCrypto;
|
||||||
|
|
||||||
nsAutoPtr<StageFrightPrivate> mPrivate;
|
nsAutoPtr<StageFrightPrivate> mPrivate;
|
||||||
};
|
};
|
||||||
|
|
|
@ -111,6 +111,8 @@ MP4Demuxer::Init()
|
||||||
mPrivate->mVideoIndex.Init(index);
|
mPrivate->mVideoIndex.Init(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sp<MetaData> metaData = e->getMetaData();
|
||||||
|
mCrypto.Update(metaData);
|
||||||
|
|
||||||
return mPrivate->mAudio.get() || mPrivate->mVideo.get();
|
return mPrivate->mAudio.get() || mPrivate->mVideo.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,12 +137,12 @@ private:
|
||||||
|
|
||||||
struct Sample {
|
struct Sample {
|
||||||
off64_t offset;
|
off64_t offset;
|
||||||
size_t size;
|
uint32_t size;
|
||||||
uint32_t duration;
|
uint32_t duration;
|
||||||
uint32_t ctsOffset;
|
uint32_t ctsOffset;
|
||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
Vector<size_t> clearsizes;
|
Vector<uint16_t> clearsizes;
|
||||||
Vector<size_t> encryptedsizes;
|
Vector<uint32_t> encryptedsizes;
|
||||||
};
|
};
|
||||||
Vector<Sample> mCurrentSamples;
|
Vector<Sample> mCurrentSamples;
|
||||||
|
|
||||||
|
@ -1522,7 +1522,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
|
||||||
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
|
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
|
||||||
|
|
||||||
if (mPath.size() >= 2
|
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
|
// Information from the ESDS must be relied on for proper
|
||||||
// setup of sample rate and channel count for MPEG4 Audio.
|
// setup of sample rate and channel count for MPEG4 Audio.
|
||||||
// The generic header appears to only contain generic
|
// The generic header appears to only contain generic
|
||||||
|
|
Загрузка…
Ссылка в новой задаче