2014-05-22 06:42:39 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2017-11-16 10:05:17 +03:00
|
|
|
#include "Adts.h"
|
|
|
|
#include "AnnexB.h"
|
2017-11-16 10:57:15 +03:00
|
|
|
#include "BufferReader.h"
|
2017-11-16 11:24:22 +03:00
|
|
|
#include "DecoderData.h"
|
2014-05-22 06:42:39 +04:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2017-10-05 16:53:07 +03:00
|
|
|
#include "mozilla/EndianUtils.h"
|
2017-10-04 21:57:11 +03:00
|
|
|
#include "VideoUtils.h"
|
2014-05-22 06:42:39 +04:00
|
|
|
|
2016-12-12 11:00:24 +03:00
|
|
|
// OpusDecoder header is really needed only by MP4 in rust
|
|
|
|
#include "OpusDecoder.h"
|
2016-04-02 01:44:00 +03:00
|
|
|
#include "mp4parse.h"
|
|
|
|
|
2017-04-12 11:41:36 +03:00
|
|
|
using mozilla::media::TimeUnit;
|
2014-05-22 06:42:39 +04:00
|
|
|
|
2017-11-17 04:42:02 +03:00
|
|
|
namespace mozilla
|
2014-05-22 06:42:39 +04:00
|
|
|
{
|
|
|
|
|
2017-11-07 02:57:34 +03:00
|
|
|
mozilla::Result<mozilla::Ok, nsresult>
|
2015-04-07 13:33:18 +03:00
|
|
|
CryptoFile::DoUpdate(const uint8_t* aData, size_t aLength)
|
2014-07-18 07:36:04 +04:00
|
|
|
{
|
2017-10-25 10:40:24 +03:00
|
|
|
BufferReader reader(aData, aLength);
|
2014-07-18 07:36:04 +04:00
|
|
|
while (reader.Remaining()) {
|
|
|
|
PsshInfo psshInfo;
|
|
|
|
if (!reader.ReadArray(psshInfo.uuid, 16)) {
|
2017-11-07 02:57:34 +03:00
|
|
|
return mozilla::Err(NS_ERROR_FAILURE);
|
2014-07-18 07:36:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!reader.CanReadType<uint32_t>()) {
|
2017-11-07 02:57:34 +03:00
|
|
|
return mozilla::Err(NS_ERROR_FAILURE);
|
2014-07-18 07:36:04 +04:00
|
|
|
}
|
|
|
|
auto length = reader.ReadType<uint32_t>();
|
|
|
|
|
|
|
|
if (!reader.ReadArray(psshInfo.data, length)) {
|
2017-11-07 02:57:34 +03:00
|
|
|
return mozilla::Err(NS_ERROR_FAILURE);
|
2014-07-18 07:36:04 +04:00
|
|
|
}
|
|
|
|
pssh.AppendElement(psshInfo);
|
|
|
|
}
|
2017-11-07 02:57:34 +03:00
|
|
|
return mozilla::Ok();
|
2014-07-18 07:36:04 +04:00
|
|
|
}
|
|
|
|
|
2014-05-22 06:42:39 +04:00
|
|
|
bool
|
2015-04-14 08:16:32 +03:00
|
|
|
MP4AudioInfo::IsValid() const
|
2014-05-22 06:42:39 +04:00
|
|
|
{
|
2015-04-14 08:16:32 +03:00
|
|
|
return mChannels > 0 && mRate > 0 &&
|
2016-05-12 03:18:07 +03:00
|
|
|
// Accept any mime type here, but if it's aac, validate the profile.
|
2017-11-10 11:02:06 +03:00
|
|
|
(!mMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
2015-04-14 08:16:32 +03:00
|
|
|
mProfile > 0 || mExtendedProfile > 0);
|
2014-05-22 06:42:39 +04:00
|
|
|
}
|
|
|
|
|
2016-12-12 11:00:24 +03:00
|
|
|
static void
|
|
|
|
UpdateTrackProtectedInfo(mozilla::TrackInfo& aConfig,
|
2017-11-22 05:15:51 +03:00
|
|
|
const Mp4parseSinfInfo& aSinf)
|
2016-12-12 11:00:24 +03:00
|
|
|
{
|
|
|
|
if (aSinf.is_encrypted != 0) {
|
|
|
|
aConfig.mCrypto.mValid = true;
|
|
|
|
aConfig.mCrypto.mMode = aSinf.is_encrypted;
|
|
|
|
aConfig.mCrypto.mIVSize = aSinf.iv_size;
|
|
|
|
aConfig.mCrypto.mKeyId.AppendElements(aSinf.kid.data, aSinf.kid.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-11-22 05:15:51 +03:00
|
|
|
MP4AudioInfo::Update(const Mp4parseTrackInfo* track,
|
|
|
|
const Mp4parseTrackAudioInfo* audio)
|
2016-12-12 11:00:24 +03:00
|
|
|
{
|
|
|
|
UpdateTrackProtectedInfo(*this, audio->protected_data);
|
|
|
|
|
2017-11-22 05:15:51 +03:00
|
|
|
if (track->codec == MP4PARSE_CODEC_OPUS) {
|
2016-12-12 11:00:24 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("audio/opus");
|
|
|
|
// The Opus decoder expects the container's codec delay or
|
|
|
|
// pre-skip value, in microseconds, as a 64-bit int at the
|
|
|
|
// start of the codec-specific config blob.
|
2017-04-20 09:30:28 +03:00
|
|
|
MOZ_ASSERT(audio->extra_data.data);
|
|
|
|
MOZ_ASSERT(audio->extra_data.length >= 12);
|
2016-12-12 11:00:24 +03:00
|
|
|
uint16_t preskip =
|
2017-10-05 16:53:07 +03:00
|
|
|
mozilla::LittleEndian::readUint16(audio->extra_data.data + 10);
|
|
|
|
mozilla::OpusDataDecoder::AppendCodecDelay(mCodecSpecificConfig,
|
2016-12-12 11:00:24 +03:00
|
|
|
mozilla::FramesToUsecs(preskip, 48000).value());
|
2017-11-22 05:15:51 +03:00
|
|
|
} else if (track->codec == MP4PARSE_CODEC_AAC) {
|
2017-10-18 09:12:51 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("audio/mp4a-latm");
|
2017-11-22 05:15:51 +03:00
|
|
|
} else if (track->codec == MP4PARSE_CODEC_FLAC) {
|
2017-10-18 09:12:51 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("audio/flac");
|
2017-11-22 05:15:51 +03:00
|
|
|
} else if (track->codec == MP4PARSE_CODEC_MP3) {
|
2017-10-18 09:12:51 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("audio/mpeg");
|
2016-12-12 11:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mRate = audio->sample_rate;
|
|
|
|
mChannels = audio->channels;
|
|
|
|
mBitDepth = audio->bit_depth;
|
2016-12-14 11:01:43 +03:00
|
|
|
mExtendedProfile = audio->profile;
|
2017-04-12 11:41:36 +03:00
|
|
|
mDuration = TimeUnit::FromMicroseconds(track->duration);
|
2017-04-12 11:53:09 +03:00
|
|
|
mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
|
2016-12-12 11:00:24 +03:00
|
|
|
mTrackId = track->track_id;
|
|
|
|
|
2016-12-14 11:01:43 +03:00
|
|
|
// In stagefright, mProfile is kKeyAACProfile, mExtendedProfile is kKeyAACAOT.
|
|
|
|
// Both are from audioObjectType in AudioSpecificConfig.
|
|
|
|
if (audio->profile <= 4) {
|
|
|
|
mProfile = audio->profile;
|
|
|
|
}
|
2016-12-12 11:00:24 +03:00
|
|
|
|
2017-04-20 09:30:28 +03:00
|
|
|
if (audio->extra_data.length > 0) {
|
|
|
|
mExtraData->AppendElements(audio->extra_data.data,
|
|
|
|
audio->extra_data.length);
|
2017-03-16 11:06:28 +03:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:30:28 +03:00
|
|
|
if (audio->codec_specific_config.length > 0) {
|
|
|
|
mCodecSpecificConfig->AppendElements(audio->codec_specific_config.data,
|
|
|
|
audio->codec_specific_config.length);
|
2016-12-12 11:00:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-02 01:44:00 +03:00
|
|
|
void
|
2017-11-22 05:15:51 +03:00
|
|
|
MP4VideoInfo::Update(const Mp4parseTrackInfo* track,
|
|
|
|
const Mp4parseTrackVideoInfo* video)
|
2016-04-02 01:44:00 +03:00
|
|
|
{
|
2016-12-12 11:00:24 +03:00
|
|
|
UpdateTrackProtectedInfo(*this, video->protected_data);
|
2017-11-22 05:15:51 +03:00
|
|
|
if (track->codec == MP4PARSE_CODEC_AVC) {
|
2017-10-18 09:12:51 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("video/avc");
|
2017-11-22 05:15:51 +03:00
|
|
|
} else if (track->codec == MP4PARSE_CODEC_VP9) {
|
2016-04-02 01:44:00 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("video/vp9");
|
2017-11-22 05:15:51 +03:00
|
|
|
} else if (track->codec == MP4PARSE_CODEC_MP4V) {
|
2017-10-18 09:12:51 +03:00
|
|
|
mMimeType = NS_LITERAL_CSTRING("video/mp4v-es");
|
2016-04-02 01:44:00 +03:00
|
|
|
}
|
|
|
|
mTrackId = track->track_id;
|
2017-04-12 11:41:36 +03:00
|
|
|
mDuration = TimeUnit::FromMicroseconds(track->duration);
|
2017-04-12 11:53:09 +03:00
|
|
|
mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
|
2016-04-02 01:44:00 +03:00
|
|
|
mDisplay.width = video->display_width;
|
|
|
|
mDisplay.height = video->display_height;
|
|
|
|
mImage.width = video->image_width;
|
|
|
|
mImage.height = video->image_height;
|
2017-03-21 11:01:14 +03:00
|
|
|
mRotation = ToSupportedRotation(video->rotation);
|
2016-11-24 11:36:08 +03:00
|
|
|
if (video->extra_data.data) {
|
|
|
|
mExtraData->AppendElements(video->extra_data.data, video->extra_data.length);
|
|
|
|
}
|
2016-04-02 01:44:00 +03:00
|
|
|
}
|
|
|
|
|
2014-05-22 06:42:39 +04:00
|
|
|
bool
|
2015-04-14 08:16:32 +03:00
|
|
|
MP4VideoInfo::IsValid() const
|
2014-05-22 06:42:39 +04:00
|
|
|
{
|
2016-08-21 23:39:41 +03:00
|
|
|
return (mDisplay.width > 0 && mDisplay.height > 0) ||
|
|
|
|
(mImage.width > 0 && mImage.height > 0);
|
2014-05-22 06:42:39 +04:00
|
|
|
}
|
2015-04-14 08:16:32 +03:00
|
|
|
|
2014-05-22 06:42:39 +04:00
|
|
|
}
|