Handle clearkey encrypted WebMs. Requesting feedback: r?cpearce
draft
Handle clearkey encrypted WebMs. Requesting feedback: r?cpearce
Make sure an encrypted event is created for WebMs. Handle encrypted WebM
streams for the clearkey case.
MozReview-Commit-ID: BSvSOHoNbQA
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -333,17 +333,17 @@ MediaFormatReader::OnDemuxerInitDone(nsr
mIsEncrypted = crypto && crypto->IsEncrypted();
if (mDecoder && crypto && crypto->IsEncrypted()) {
#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
- new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
+ new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType));
}
#endif // MOZ_EME
mInfo.mCrypto = *crypto;
}
int64_t videoDuration = HasVideo() ? mInfo.mVideo.mDuration : 0;
int64_t audioDuration = HasAudio() ? mInfo.mAudio.mDuration : 0;
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -493,9 +493,46 @@ IsAACContentType(const nsAString& aConte
},
[](const nsAString& codec) {
return codec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC
codec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC
codec.EqualsLiteral("mp4a.67"); // MPEG2 AAC-LC
});
}
+bool
+IsVorbisContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("audio/webm") ||
+ type.EqualsLiteral("audio/ogg");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vorbis");
+ });
+}
+
+bool
+IsVP8ContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("video/webm");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vp8");
+ });
+}
+
+bool
+IsVP9ContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("video/webm");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vp9");
+ });
+}
+
} // end namespace mozilla
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -323,20 +323,35 @@ private:
};
void
LogToBrowserConsole(const nsAString& aMsg);
bool
ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs);
+// Should only be called from main thread due to nsContentTypeParser
bool
IsH264ContentType(const nsAString& aContentType);
+// Should only be called from main thread due to nsContentTypeParser
bool
IsAACContentType(const nsAString& aContentType);
+// Should only be called from main thread due to nsContentTypeParser
bool
IsAACCodecString(const nsAString& aCodec);
+// Should only be called from main thread due to nsContentTypeParser
+bool
+IsVorbisContentType(const nsAString& aContentType);
+
+// Should only be called from main thread due to nsContentTypeParser
+bool
+IsVP8ContentType(const nsAString& aContentType);
+
+// Should only be called from main thread due to nsContentTypeParser
+bool
+IsVP9ContentType(const nsAString& aContentType);
+
} // end namespace mozilla
#endif
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -30,16 +30,17 @@
#include "GMPUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
#include "DecoderDoctorDiagnostics.h"
+#include "WebMDecoder.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
@@ -350,16 +351,44 @@ GMPDecryptsAndDecodesH264(mozIGeckoMedia
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
return HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
NS_LITERAL_CSTRING("h264"));
}
+static bool
+GMPDecryptsAndDecodesVP8(mozIGeckoMediaPluginService* aGMPS,
+ const nsAString& aKeySystem,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPS,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ return HaveGMPFor(aGMPS,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp8"));
+}
+
+static bool
+GMPDecryptsAndDecodesVP9(mozIGeckoMediaPluginService* aGMPS,
+ const nsAString& aKeySystem,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPS,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ return HaveGMPFor(aGMPS,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp9"));
+}
+
// If this keysystem's CDM explicitly says it doesn't support decoding,
// that means it's OK with passing the decrypted samples back to Gecko
// for decoding.
static bool
GMPDecryptsAndGeckoDecodesH264(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aContentType,
DecoderDoctorDiagnostics* aDiagnostics)
@@ -407,35 +436,102 @@ GMPDecryptsAndGeckoDecodesAAC(mozIGeckoM
}
return false;
}
#endif
return MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics);
}
static bool
+GMPDecryptsAndGeckoDecodesVorbis(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVorbisContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
+ NS_LITERAL_CSTRING("vorbis")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
+GMPDecryptsAndGeckoDecodesVP8(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVP8ContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp8")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
+GMPDecryptsAndGeckoDecodesVP9(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVP9ContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp9")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
IsSupportedAudio(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aAudioType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- return IsAACContentType(aAudioType) &&
- (GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) ||
- GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics));
+ if (IsAACContentType(aAudioType)) {
+ return GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics);
+ }
+ if (IsVorbisContentType(aAudioType)) {
+ // GMP does not decode Vorbis, so don't bother checking
+ return GMPDecryptsAndGeckoDecodesVorbis(aGMPService, aKeySystem, aAudioType, aDiagnostics);
+ }
+ return false;
}
static bool
IsSupportedVideo(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aVideoType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- return IsH264ContentType(aVideoType) &&
- (GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) ||
- GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics));
+ if (IsH264ContentType(aVideoType)) {
+ return GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ if (IsVP8ContentType(aVideoType)) {
+ return GMPDecryptsAndDecodesVP8(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesVP8(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ if (IsVP9ContentType(aVideoType)) {
+ return GMPDecryptsAndDecodesVP9(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesVP9(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ return false;
}
static bool
IsSupported(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemConfiguration& aConfig,
DecoderDoctorDiagnostics* aDiagnostics)
{
@@ -469,17 +565,17 @@ IsSupportedInitDataType(const nsString&
// All supported keySystems can handle "cenc" initDataType.
// ClearKey also supports "keyids" and "webm" initDataTypes.
return aCandidate.EqualsLiteral("cenc") ||
((aKeySystem.EqualsLiteral("org.w3.clearkey")
#ifdef MOZ_WIDEVINE_EME
|| aKeySystem.EqualsLiteral("com.widevine.alpha")
#endif
) &&
- (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm)")));
+ (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm")));
}
static bool
GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemConfiguration& aCandidate,
MediaKeySystemConfiguration& aOutConfig,
DecoderDoctorDiagnostics* aDiagnostics)
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1045,17 +1045,17 @@ TrackBuffersManager::OnDemuxerInitDone(n
}
UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
if (crypto && crypto->IsEncrypted()) {
#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
- new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
+ new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType));
}
#endif // MOZ_EME
info.mCrypto = *crypto;
// We clear our crypto init data array, so the MediaFormatReader will
// not emit an encrypted event for the same init data again.
info.mCrypto.mInitDatas.Clear();
mEncrypted = true;
}
--- a/dom/media/webm/WebMDecoder.cpp
+++ b/dom/media/webm/WebMDecoder.cpp
@@ -4,16 +4,17 @@
* 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 "mozilla/Preferences.h"
#include "MediaDecoderStateMachine.h"
#include "WebMDemuxer.h"
#include "WebMDecoder.h"
#include "VideoUtils.h"
+#include "nsContentTypeParser.h"
namespace mozilla {
MediaDecoderStateMachine* WebMDecoder::CreateStateMachine()
{
mReader =
new MediaFormatReader(this, new WebMDemuxer(GetResource()), GetVideoFrameContainer());
return new MediaDecoderStateMachine(this, mReader);
@@ -65,16 +66,32 @@ WebMDecoder::CanHandleMediaType(const ns
continue;
}
// Some unsupported codec.
return false;
}
return true;
}
+/* static */ bool
+WebMDecoder::CanHandleMediaType(const nsAString& aContentType)
+{
+ nsContentTypeParser parser(aContentType);
+ nsAutoString mimeType;
+ nsresult rv = parser.GetType(mimeType);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+ nsString codecs;
+ parser.GetParameter("codecs", codecs);
+
+ return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType),
+ codecs);
+}
+
void
WebMDecoder::GetMozDebugReaderData(nsAString& aString)
{
if (mReader) {
mReader->GetMozDebugReaderData(aString);
}
}
--- a/dom/media/webm/WebMDecoder.h
+++ b/dom/media/webm/WebMDecoder.h
@@ -28,16 +28,18 @@ public:
// Returns true if aMIMEType is a type that we think we can render with the
// a WebM platform decoder backend. If aCodecs is non emtpy, it is filled
// with a comma-delimited list of codecs to check support for. Notes in
// out params whether the codecs string contains Opus/Vorbis or VP8/VP9.
static bool CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
const nsAString& aCodecs);
+ static bool CanHandleMediaType(const nsAString& aContentType);
+
void GetMozDebugReaderData(nsAString& aString) override;
private:
RefPtr<MediaFormatReader> mReader;
};
} // namespace mozilla
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -359,16 +359,17 @@ WebMDemuxer::ReadMetadata()
mInfo.mVideo.mStereoMode = StereoMode::RIGHT_LEFT;
break;
}
uint64_t duration = 0;
r = nestegg_duration(mContext, &duration);
if (!r) {
mInfo.mVideo.mDuration = media::TimeUnit::FromNanoseconds(duration).ToMicroseconds();
}
+ mInfo.mVideo.mCrypto = GetTrackCrypto(track);
} else if (type == NESTEGG_TRACK_AUDIO && !mHasAudio) {
nestegg_audio_params params;
r = nestegg_track_audio_params(mContext, track, ¶ms);
if (r == -1) {
return NS_ERROR_FAILURE;
}
mAudioTrack = track;
@@ -421,16 +422,17 @@ WebMDemuxer::ReadMetadata()
mInfo.mAudio.mCodecSpecificConfig->AppendElements(headers[0],
headerLens[0]);
}
uint64_t duration = 0;
r = nestegg_duration(mContext, &duration);
if (!r) {
mInfo.mAudio.mDuration = media::TimeUnit::FromNanoseconds(duration).ToMicroseconds();
}
+ mInfo.mAudio.mCrypto = GetTrackCrypto(track);
}
}
return NS_OK;
}
bool
WebMDemuxer::IsSeekable() const
{
@@ -481,19 +483,72 @@ WebMDemuxer::NotifyDataRemoved()
mBufferedState->NotifyDataArrived(mInitData->Elements(), mInitData->Length(), 0);
}
mNeedReIndex = true;
}
UniquePtr<EncryptionInfo>
WebMDemuxer::GetCrypto()
{
+ unsigned int ntracks = 0;
+ bool has_encrypted_track = false;
+
+ int r = nestegg_track_count(mContext, &ntracks);
+
+ if (r == -1) {
+ WEBM_DEBUG("nestegg_track_count failed r=%d", r);
+ return nullptr;
+ }
+
+ auto crypto = MakeUnique<EncryptionInfo>();
+ for (unsigned int track = 0; track < ntracks; ++track) {
+ // For every track if we have valid crypto info add the key ID to the
+ // overall crypto information returned for this demuxer
+ CryptoTrack trackCrypto = GetTrackCrypto(track);
+ if(trackCrypto.mValid) {
+ has_encrypted_track = true;
+ crypto->AddInitData(NS_LITERAL_STRING("webm"), Move(trackCrypto.mKeyId));
+ }
+ }
+
+ if (has_encrypted_track) {
+ return crypto;
+ }
return nullptr;
}
+CryptoTrack
+WebMDemuxer::GetTrackCrypto(size_t aTrackNumber) {
+ const int WEBM_IV_SIZE = 16;
+ const unsigned char * content_enc_key_id;
+ size_t content_enc_key_id_length;
+ CryptoTrack crypto;
+
+ int r = nestegg_track_content_enc_key_id(mContext, aTrackNumber, &content_enc_key_id, &content_enc_key_id_length);
+ if (r == -1) {
+ WEBM_DEBUG("nestegg_track_content_enc_key_id failed r=%d", r);
+ return crypto;
+ }
+
+ uint32_t i;
+ nsTArray<uint8_t> initData;
+ for (i = 0; i < content_enc_key_id_length; i++) {
+ initData.AppendElement(content_enc_key_id[i]);
+ }
+
+ if (!initData.IsEmpty()) {
+ crypto.mValid = true;
+ // crypto.mMode is not used for WebMs
+ crypto.mIVSize = WEBM_IV_SIZE;
+ crypto.mKeyId = Move(initData);
+ }
+
+ return crypto;
+}
+
bool
WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples)
{
if (mIsMediaSource) {
// To ensure mLastWebMBlockOffset is properly up to date.
EnsureUpToDateIndex();
}
@@ -551,51 +606,58 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
if (mIsMediaSource && next_tstamp == INT64_MIN) {
return false;
}
int64_t discardPadding = 0;
(void) nestegg_packet_discard_padding(holder->Packet(), &discardPadding);
+ int packet_encryption = nestegg_packet_encryption(holder->Packet());
+
for (uint32_t i = 0; i < count; ++i) {
unsigned char* data;
size_t length;
r = nestegg_packet_data(holder->Packet(), i, &data, &length);
if (r == -1) {
WEBM_DEBUG("nestegg_packet_data failed r=%d", r);
return false;
}
bool isKeyframe = false;
if (aType == TrackInfo::kAudioTrack) {
isKeyframe = true;
} else if (aType == TrackInfo::kVideoTrack) {
- vpx_codec_stream_info_t si;
- PodZero(&si);
- si.sz = sizeof(si);
- switch (mVideoCodec) {
+ if (packet_encryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED) {
+ // Packet is encrypted, can't peek, use packet info
+ isKeyframe = nestegg_packet_has_keyframe(holder->Packet()) == NESTEGG_PACKET_HAS_KEYFRAME_TRUE;
+ } else {
+ vpx_codec_stream_info_t si;
+ PodZero(&si);
+ si.sz = sizeof(si);
+ switch (mVideoCodec) {
case NESTEGG_CODEC_VP8:
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
break;
case NESTEGG_CODEC_VP9:
vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si);
break;
- }
- isKeyframe = si.is_kf;
- if (isKeyframe) {
- // We only look for resolution changes on keyframes for both VP8 and
- // VP9. Other resolution changes are invalid.
- if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() &&
+ }
+ isKeyframe = si.is_kf;
+ if (isKeyframe) {
+ // We only look for resolution changes on keyframes for both VP8 and
+ // VP9. Other resolution changes are invalid.
+ if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() &&
(si.w != mLastSeenFrameWidth.value() ||
- si.h != mLastSeenFrameHeight.value())) {
- mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h);
- mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID);
+ si.h != mLastSeenFrameHeight.value())) {
+ mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h);
+ mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID);
+ }
+ mLastSeenFrameWidth = Some(si.w);
+ mLastSeenFrameHeight = Some(si.h);
}
- mLastSeenFrameWidth = Some(si.w);
- mLastSeenFrameHeight = Some(si.h);
}
}
WEBM_DEBUG("push sample tstamp: %ld next_tstamp: %ld length: %ld kf: %d",
tstamp, next_tstamp, length, isKeyframe);
RefPtr<MediaRawData> sample = new MediaRawData(data, length);
sample->mTimecode = tstamp;
sample->mTime = tstamp;
@@ -603,16 +665,40 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
sample->mOffset = holder->Offset();
sample->mKeyframe = isKeyframe;
if (discardPadding && i == count - 1) {
uint8_t c[8];
BigEndian::writeInt64(&c[0], discardPadding);
sample->mExtraData = new MediaByteBuffer;
sample->mExtraData->AppendElements(&c[0], 8);
}
+
+ if (packet_encryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED ||
+ packet_encryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED) {
+ nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
+ unsigned char const* iv;
+ size_t ivLength;
+ nestegg_packet_iv(holder->Packet(), &iv, &ivLength);
+ writer->mCrypto.mValid = true;
+ writer->mCrypto.mIVSize = ivLength;
+ if (ivLength == 0) {
+ // Frame is not encrypted
+ writer->mCrypto.mPlainSizes.AppendElement(length);
+ writer->mCrypto.mEncryptedSizes.AppendElement(0);
+ } else {
+ // Frame is encrypted
+ writer->mCrypto.mIV.AppendElements(iv, 8);
+ // Iv from samples is 64 bits, must be padded with 64 bits more 0s in compliance with spec
+ for (uint32_t i = 0; i < 8; i++) {
+ writer->mCrypto.mIV.AppendElement(0);
+ }
+ writer->mCrypto.mPlainSizes.AppendElement(0);
+ writer->mCrypto.mEncryptedSizes.AppendElement(length);
+ }
+ }
if (aType == TrackInfo::kVideoTrack) {
sample->mTrackInfo = mSharedVideoTrackInfo;
}
aSamples->Push(sample);
}
return true;
}
@@ -969,16 +1055,25 @@ WebMTrackDemuxer::Reset()
} else {
mNextKeyframeTime.reset();
}
}
void
WebMTrackDemuxer::UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples)
{
+ for (size_t i = 0; i < aSamples.Length(); i++) {
+ MediaRawData* sample = aSamples[i];
+ if (sample->mCrypto.mValid) {
+ nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
+ writer->mCrypto.mMode = mInfo->mCrypto.mMode;
+ writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
+ writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
+ }
+ }
if (mNextKeyframeTime.isNothing() ||
aSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) {
SetNextKeyFrameTime();
}
}
nsresult
WebMTrackDemuxer::GetNextRandomAccessPoint(media::TimeUnit* aTime)
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -138,16 +138,17 @@ private:
void Cleanup();
void InitBufferedState();
nsresult ReadMetadata();
void NotifyDataArrived() override;
void NotifyDataRemoved() override;
void EnsureUpToDateIndex();
media::TimeIntervals GetBuffered();
nsresult SeekInternal(const media::TimeUnit& aTarget);
+ CryptoTrack GetTrackCrypto(size_t aTrackNumber);
// Read a packet from the nestegg file. Returns nullptr if all packets for
// the particular track have been read. Pass TrackInfo::kVideoTrack or
// TrackInfo::kVideoTrack to indicate the type of the packet we want to read.
RefPtr<NesteggPacketHolder> NextPacket(TrackInfo::TrackType aType);
// Internal method that demuxes the next packet from the stream. The caller
// is responsible for making sure it doesn't get lost.