Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "mp4_demuxer/Adts.h"
6 : #include "mp4_demuxer/AnnexB.h"
7 : #include "mp4_demuxer/ByteReader.h"
8 : #include "mp4_demuxer/DecoderData.h"
9 : #include <media/stagefright/foundation/ABitReader.h>
10 : #include "media/stagefright/MetaData.h"
11 : #include "media/stagefright/MediaDefs.h"
12 : #include "media/stagefright/Utils.h"
13 : #include "mozilla/ArrayUtils.h"
14 : #include "include/ESDS.h"
15 :
16 : // OpusDecoder header is really needed only by MP4 in rust
17 : #include "OpusDecoder.h"
18 : #include "mp4parse.h"
19 :
20 : using namespace stagefright;
21 : using mozilla::media::TimeUnit;
22 :
23 : namespace mp4_demuxer
24 : {
25 :
26 : static int32_t
27 0 : FindInt32(const MetaData* mMetaData, uint32_t mKey)
28 : {
29 : int32_t value;
30 0 : if (!mMetaData->findInt32(mKey, &value))
31 0 : return 0;
32 0 : return value;
33 : }
34 :
35 : static int64_t
36 0 : FindInt64(const MetaData* mMetaData, uint32_t mKey)
37 : {
38 : int64_t value;
39 0 : if (!mMetaData->findInt64(mKey, &value))
40 0 : return 0;
41 0 : return value;
42 : }
43 :
44 : template <typename T, size_t N>
45 : static bool
46 : FindData(const MetaData* aMetaData, uint32_t aKey, mozilla::Vector<T, N>* aDest)
47 : {
48 : const void* data;
49 : size_t size;
50 : uint32_t type;
51 :
52 : aDest->clear();
53 : // There's no point in checking that the type matches anything because it
54 : // isn't set consistently in the MPEG4Extractor.
55 : if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
56 : return false;
57 : }
58 :
59 : aDest->append(reinterpret_cast<const T*>(data), size / sizeof(T));
60 : return true;
61 : }
62 :
63 : template <typename T>
64 : static bool
65 0 : FindData(const MetaData* aMetaData, uint32_t aKey, nsTArray<T>* aDest)
66 : {
67 : const void* data;
68 : size_t size;
69 : uint32_t type;
70 :
71 0 : aDest->Clear();
72 : // There's no point in checking that the type matches anything because it
73 : // isn't set consistently in the MPEG4Extractor.
74 0 : if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
75 0 : return false;
76 : }
77 :
78 0 : aDest->AppendElements(reinterpret_cast<const T*>(data), size / sizeof(T));
79 0 : return true;
80 : }
81 :
82 : static bool
83 0 : FindData(const MetaData* aMetaData, uint32_t aKey, mozilla::MediaByteBuffer* aDest)
84 : {
85 0 : return FindData(aMetaData, aKey, static_cast<nsTArray<uint8_t>*>(aDest));
86 : }
87 :
88 : bool
89 0 : CryptoFile::DoUpdate(const uint8_t* aData, size_t aLength)
90 : {
91 0 : ByteReader reader(aData, aLength);
92 0 : while (reader.Remaining()) {
93 0 : PsshInfo psshInfo;
94 0 : if (!reader.ReadArray(psshInfo.uuid, 16)) {
95 0 : return false;
96 : }
97 :
98 0 : if (!reader.CanReadType<uint32_t>()) {
99 0 : return false;
100 : }
101 0 : auto length = reader.ReadType<uint32_t>();
102 :
103 0 : if (!reader.ReadArray(psshInfo.data, length)) {
104 0 : return false;
105 : }
106 0 : pssh.AppendElement(psshInfo);
107 : }
108 0 : return true;
109 : }
110 :
111 : static void
112 0 : UpdateTrackInfo(mozilla::TrackInfo& aConfig,
113 : const MetaData* aMetaData,
114 : const char* aMimeType)
115 : {
116 0 : mozilla::CryptoTrack& crypto = aConfig.mCrypto;
117 0 : aConfig.mMimeType = aMimeType;
118 : aConfig.mDuration = TimeUnit::FromMicroseconds(
119 0 : FindInt64(aMetaData, kKeyDuration));
120 : aConfig.mMediaTime = TimeUnit::FromMicroseconds(
121 0 : FindInt64(aMetaData, kKeyMediaTime));
122 0 : aConfig.mTrackId = FindInt32(aMetaData, kKeyTrackID);
123 0 : aConfig.mCrypto.mValid = aMetaData->findInt32(kKeyCryptoMode, &crypto.mMode) &&
124 0 : aMetaData->findInt32(kKeyCryptoDefaultIVSize, &crypto.mIVSize) &&
125 0 : FindData(aMetaData, kKeyCryptoKey, &crypto.mKeyId);
126 0 : }
127 :
128 : void
129 0 : MP4AudioInfo::Update(const MetaData* aMetaData,
130 : const char* aMimeType)
131 : {
132 0 : UpdateTrackInfo(*this, aMetaData, aMimeType);
133 0 : mChannels = FindInt32(aMetaData, kKeyChannelCount);
134 0 : mBitDepth = FindInt32(aMetaData, kKeySampleSize);
135 0 : mRate = FindInt32(aMetaData, kKeySampleRate);
136 0 : mProfile = FindInt32(aMetaData, kKeyAACProfile);
137 :
138 0 : if (FindData(aMetaData, kKeyESDS, mExtraData)) {
139 0 : ESDS esds(mExtraData->Elements(), mExtraData->Length());
140 :
141 : const void* data;
142 : size_t size;
143 0 : if (esds.getCodecSpecificInfo(&data, &size) == OK) {
144 0 : const uint8_t* cdata = reinterpret_cast<const uint8_t*>(data);
145 0 : mCodecSpecificConfig->AppendElements(cdata, size);
146 0 : if (size > 1) {
147 0 : ABitReader br(cdata, size);
148 0 : mExtendedProfile = br.getBits(5);
149 :
150 0 : if (mExtendedProfile == 31) { // AAC-ELD => additional 6 bits
151 0 : mExtendedProfile = 32 + br.getBits(6);
152 : }
153 : }
154 : }
155 : }
156 0 : }
157 :
158 : bool
159 0 : MP4AudioInfo::IsValid() const
160 : {
161 0 : return mChannels > 0 && mRate > 0 &&
162 : // Accept any mime type here, but if it's aac, validate the profile.
163 0 : (!mMimeType.Equals(MEDIA_MIMETYPE_AUDIO_AAC) ||
164 0 : mProfile > 0 || mExtendedProfile > 0);
165 : }
166 :
167 : void
168 0 : MP4VideoInfo::Update(const MetaData* aMetaData, const char* aMimeType)
169 : {
170 0 : UpdateTrackInfo(*this, aMetaData, aMimeType);
171 0 : mDisplay.width = FindInt32(aMetaData, kKeyDisplayWidth);
172 0 : mDisplay.height = FindInt32(aMetaData, kKeyDisplayHeight);
173 0 : mImage.width = FindInt32(aMetaData, kKeyWidth);
174 0 : mImage.height = FindInt32(aMetaData, kKeyHeight);
175 0 : mRotation = VideoInfo::ToSupportedRotation(FindInt32(aMetaData, kKeyRotation));
176 :
177 0 : FindData(aMetaData, kKeyAVCC, mExtraData);
178 0 : }
179 :
180 : static void
181 0 : UpdateTrackProtectedInfo(mozilla::TrackInfo& aConfig,
182 : const mp4parse_sinf_info& aSinf)
183 : {
184 0 : if (aSinf.is_encrypted != 0) {
185 0 : aConfig.mCrypto.mValid = true;
186 0 : aConfig.mCrypto.mMode = aSinf.is_encrypted;
187 0 : aConfig.mCrypto.mIVSize = aSinf.iv_size;
188 0 : aConfig.mCrypto.mKeyId.AppendElements(aSinf.kid.data, aSinf.kid.length);
189 : }
190 0 : }
191 :
192 : void
193 0 : MP4AudioInfo::Update(const mp4parse_track_info* track,
194 : const mp4parse_track_audio_info* audio)
195 : {
196 0 : UpdateTrackProtectedInfo(*this, audio->protected_data);
197 :
198 0 : if (track->codec == mp4parse_codec_OPUS) {
199 0 : mMimeType = NS_LITERAL_CSTRING("audio/opus");
200 : // The Opus decoder expects the container's codec delay or
201 : // pre-skip value, in microseconds, as a 64-bit int at the
202 : // start of the codec-specific config blob.
203 0 : MOZ_ASSERT(audio->extra_data.data);
204 0 : MOZ_ASSERT(audio->extra_data.length >= 12);
205 : uint16_t preskip =
206 0 : LittleEndian::readUint16(audio->extra_data.data + 10);
207 0 : OpusDataDecoder::AppendCodecDelay(mCodecSpecificConfig,
208 0 : mozilla::FramesToUsecs(preskip, 48000).value());
209 0 : } else if (track->codec == mp4parse_codec_AAC) {
210 0 : mMimeType = MEDIA_MIMETYPE_AUDIO_AAC;
211 0 : } else if (track->codec == mp4parse_codec_FLAC) {
212 0 : mMimeType = MEDIA_MIMETYPE_AUDIO_FLAC;
213 0 : } else if (track->codec == mp4parse_codec_MP3) {
214 0 : mMimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
215 : }
216 :
217 0 : mRate = audio->sample_rate;
218 0 : mChannels = audio->channels;
219 0 : mBitDepth = audio->bit_depth;
220 0 : mExtendedProfile = audio->profile;
221 0 : mDuration = TimeUnit::FromMicroseconds(track->duration);
222 0 : mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
223 0 : mTrackId = track->track_id;
224 :
225 : // In stagefright, mProfile is kKeyAACProfile, mExtendedProfile is kKeyAACAOT.
226 : // Both are from audioObjectType in AudioSpecificConfig.
227 0 : if (audio->profile <= 4) {
228 0 : mProfile = audio->profile;
229 : }
230 :
231 0 : if (audio->extra_data.length > 0) {
232 0 : mExtraData->AppendElements(audio->extra_data.data,
233 0 : audio->extra_data.length);
234 : }
235 :
236 0 : if (audio->codec_specific_config.length > 0) {
237 0 : mCodecSpecificConfig->AppendElements(audio->codec_specific_config.data,
238 0 : audio->codec_specific_config.length);
239 : }
240 0 : }
241 :
242 : void
243 0 : MP4VideoInfo::Update(const mp4parse_track_info* track,
244 : const mp4parse_track_video_info* video)
245 : {
246 0 : UpdateTrackProtectedInfo(*this, video->protected_data);
247 0 : if (track->codec == mp4parse_codec_AVC) {
248 0 : mMimeType = MEDIA_MIMETYPE_VIDEO_AVC;
249 0 : } else if (track->codec == mp4parse_codec_VP9) {
250 0 : mMimeType = NS_LITERAL_CSTRING("video/vp9");
251 0 : } else if (track->codec == mp4parse_codec_MP4V) {
252 0 : mMimeType = MEDIA_MIMETYPE_VIDEO_MPEG4;
253 : }
254 0 : mTrackId = track->track_id;
255 0 : mDuration = TimeUnit::FromMicroseconds(track->duration);
256 0 : mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
257 0 : mDisplay.width = video->display_width;
258 0 : mDisplay.height = video->display_height;
259 0 : mImage.width = video->image_width;
260 0 : mImage.height = video->image_height;
261 0 : mRotation = ToSupportedRotation(video->rotation);
262 0 : if (video->extra_data.data) {
263 0 : mExtraData->AppendElements(video->extra_data.data, video->extra_data.length);
264 : }
265 0 : }
266 :
267 : bool
268 0 : MP4VideoInfo::IsValid() const
269 : {
270 0 : return (mDisplay.width > 0 && mDisplay.height > 0) ||
271 0 : (mImage.width > 0 && mImage.height > 0);
272 : }
273 :
274 : }
|