Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/MediaInfo.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
#if !defined(MediaInfo_h)
7
#define MediaInfo_h
8
9
#include "mozilla/UniquePtr.h"
10
#include "mozilla/RefPtr.h"
11
#include "nsDataHashtable.h"
12
#include "nsString.h"
13
#include "nsTArray.h"
14
#include "AudioConfig.h"
15
#include "ImageTypes.h"
16
#include "MediaData.h"
17
#include "TrackID.h" // for TrackID
18
#include "TimeUnits.h"
19
#include "mozilla/gfx/Point.h" // for gfx::IntSize
20
#include "mozilla/gfx/Rect.h"  // for gfx::IntRect
21
22
namespace mozilla {
23
24
class AudioInfo;
25
class VideoInfo;
26
class TextInfo;
27
28
class MetadataTag
29
{
30
public:
31
  MetadataTag(const nsACString& aKey,
32
              const nsACString& aValue)
33
    : mKey(aKey)
34
    , mValue(aValue)
35
  {
36
  }
37
  nsCString mKey;
38
  nsCString mValue;
39
};
40
41
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
42
43
class TrackInfo
44
{
45
public:
46
  enum TrackType
47
  {
48
    kUndefinedTrack,
49
    kAudioTrack,
50
    kVideoTrack,
51
    kTextTrack
52
  };
53
  TrackInfo(TrackType aType,
54
            const nsAString& aId,
55
            const nsAString& aKind,
56
            const nsAString& aLabel,
57
            const nsAString& aLanguage,
58
            bool aEnabled,
59
            TrackID aTrackId)
60
    : mId(aId)
61
    , mKind(aKind)
62
    , mLabel(aLabel)
63
    , mLanguage(aLanguage)
64
    , mEnabled(aEnabled)
65
    , mTrackId(aTrackId)
66
    , mIsRenderedExternally(false)
67
    , mType(aType)
68
  {
69
    MOZ_COUNT_CTOR(TrackInfo);
70
  }
71
72
  // Only used for backward compatibility. Do not use in new code.
73
  void Init(const nsAString& aId,
74
            const nsAString& aKind,
75
            const nsAString& aLabel,
76
            const nsAString& aLanguage,
77
            bool aEnabled)
78
  {
79
    mId = aId;
80
    mKind = aKind;
81
    mLabel = aLabel;
82
    mLanguage = aLanguage;
83
    mEnabled = aEnabled;
84
  }
85
86
  // Fields common with MediaTrack object.
87
  nsString mId;
88
  nsString mKind;
89
  nsString mLabel;
90
  nsString mLanguage;
91
  bool mEnabled;
92
93
  TrackID mTrackId;
94
95
  nsCString mMimeType;
96
  media::TimeUnit mDuration;
97
  media::TimeUnit mMediaTime;
98
  CryptoTrack mCrypto;
99
100
  nsTArray<MetadataTag> mTags;
101
102
  // True if the track is gonna be (decrypted)/decoded and
103
  // rendered directly by non-gecko components.
104
  bool mIsRenderedExternally;
105
106
  virtual AudioInfo* GetAsAudioInfo()
107
  {
108
    return nullptr;
109
  }
110
  virtual VideoInfo* GetAsVideoInfo()
111
  {
112
    return nullptr;
113
  }
114
  virtual TextInfo* GetAsTextInfo()
115
  {
116
    return nullptr;
117
  }
118
  virtual const AudioInfo* GetAsAudioInfo() const
119
  {
120
    return nullptr;
121
  }
122
  virtual const VideoInfo* GetAsVideoInfo() const
123
  {
124
    return nullptr;
125
  }
126
  virtual const TextInfo* GetAsTextInfo() const
127
  {
128
    return nullptr;
129
  }
130
131
  bool IsAudio() const
132
  {
133
    return !!GetAsAudioInfo();
134
  }
135
  bool IsVideo() const
136
  {
137
    return !!GetAsVideoInfo();
138
  }
139
  bool IsText() const
140
  {
141
    return !!GetAsTextInfo();
142
  }
143
  TrackType GetType() const
144
  {
145
    return mType;
146
  }
147
148
  bool virtual IsValid() const = 0;
149
150
  virtual UniquePtr<TrackInfo> Clone() const = 0;
151
152
  virtual ~TrackInfo()
153
  {
154
    MOZ_COUNT_DTOR(TrackInfo);
155
  }
156
157
protected:
158
  TrackInfo(const TrackInfo& aOther)
159
  {
160
    mId = aOther.mId;
161
    mKind = aOther.mKind;
162
    mLabel = aOther.mLabel;
163
    mLanguage = aOther.mLanguage;
164
    mEnabled = aOther.mEnabled;
165
    mTrackId = aOther.mTrackId;
166
    mMimeType = aOther.mMimeType;
167
    mDuration = aOther.mDuration;
168
    mMediaTime = aOther.mMediaTime;
169
    mCrypto = aOther.mCrypto;
170
    mIsRenderedExternally = aOther.mIsRenderedExternally;
171
    mType = aOther.mType;
172
    mTags = aOther.mTags;
173
    MOZ_COUNT_CTOR(TrackInfo);
174
  }
175
176
private:
177
  TrackType mType;
178
};
179
180
// String version of track type.
181
const char* TrackTypeToStr(TrackInfo::TrackType aTrack);
182
183
// Stores info relevant to presenting media frames.
184
class VideoInfo : public TrackInfo
185
{
186
public:
187
  enum Rotation
188
  {
189
    kDegree_0 = 0,
190
    kDegree_90 = 90,
191
    kDegree_180 = 180,
192
    kDegree_270 = 270,
193
  };
194
  VideoInfo()
195
    : VideoInfo(-1, -1)
196
  {
197
  }
198
199
  explicit VideoInfo(int32_t aWidth, int32_t aHeight)
200
    : VideoInfo(gfx::IntSize(aWidth, aHeight))
201
  {
202
  }
203
204
  explicit VideoInfo(const gfx::IntSize& aSize)
205
    : TrackInfo(kVideoTrack,
206
                NS_LITERAL_STRING("2"),
207
                NS_LITERAL_STRING("main"),
208
                EmptyString(),
209
                EmptyString(),
210
                true,
211
                2)
212
    , mDisplay(aSize)
213
    , mStereoMode(StereoMode::MONO)
214
    , mImage(aSize)
215
    , mCodecSpecificConfig(new MediaByteBuffer)
216
    , mExtraData(new MediaByteBuffer)
217
    , mRotation(kDegree_0)
218
    , mImageRect(gfx::IntRect(gfx::IntPoint(), aSize))
219
  {
220
  }
221
222
  VideoInfo(const VideoInfo& aOther)
223
    : TrackInfo(aOther)
224
    , mDisplay(aOther.mDisplay)
225
    , mStereoMode(aOther.mStereoMode)
226
    , mImage(aOther.mImage)
227
    , mCodecSpecificConfig(aOther.mCodecSpecificConfig)
228
    , mExtraData(aOther.mExtraData)
229
    , mRotation(aOther.mRotation)
230
    , mBitDepth(aOther.mBitDepth)
231
    , mImageRect(aOther.mImageRect)
232
    , mAlphaPresent(aOther.mAlphaPresent)
233
  {
234
  }
235
236
  bool IsValid() const override
237
  {
238
    return mDisplay.width > 0 && mDisplay.height > 0;
239
  }
240
241
  VideoInfo* GetAsVideoInfo() override
242
  {
243
    return this;
244
  }
245
246
  const VideoInfo* GetAsVideoInfo() const override
247
  {
248
    return this;
249
  }
250
251
  UniquePtr<TrackInfo> Clone() const override
252
  {
253
    return MakeUnique<VideoInfo>(*this);
254
  }
255
256
  void SetAlpha(bool aAlphaPresent)
257
  {
258
    mAlphaPresent = aAlphaPresent;
259
  }
260
261
  bool HasAlpha() const
262
  {
263
    return mAlphaPresent;
264
  }
265
266
  gfx::IntRect ImageRect() const
267
  {
268
    if (mImageRect.Width() < 0 || mImageRect.Height() < 0) {
269
      return gfx::IntRect(0, 0, mImage.width, mImage.height);
270
    }
271
    return mImageRect;
272
  }
273
274
  void SetImageRect(const gfx::IntRect& aRect) { mImageRect = aRect; }
275
276
  // Returned the crop rectangle scaled to aWidth/aHeight size relative to
277
  // mImage size.
278
  // If aWidth and aHeight are identical to the original mImage.width/mImage.height
279
  // then the scaling ratio will be 1.
280
  // This is used for when the frame size is different from what the container
281
  // reports. This is legal in WebM, and we will preserve the ratio of the crop
282
  // rectangle as it was reported relative to the picture size reported by the
283
  // container.
284
  gfx::IntRect ScaledImageRect(int64_t aWidth, int64_t aHeight) const
285
  {
286
    if ((aWidth == mImage.width && aHeight == mImage.height) ||
287
        !mImage.width ||
288
        !mImage.height) {
289
      return ImageRect();
290
    }
291
292
    gfx::IntRect imageRect = ImageRect();
293
    int64_t w = (aWidth * imageRect.Width()) / mImage.width;
294
    int64_t h = (aHeight * imageRect.Height()) / mImage.height;
295
    if (!w || !h) {
296
      return imageRect;
297
    }
298
299
    imageRect.x = (imageRect.x * aWidth) / mImage.width;
300
    imageRect.y = (imageRect.y * aHeight) / mImage.height;
301
    imageRect.SetWidth(w);
302
    imageRect.SetHeight(h);
303
    return imageRect;
304
  }
305
306
  Rotation ToSupportedRotation(int32_t aDegree) const
307
  {
308
    switch (aDegree) {
309
      case 90:
310
        return kDegree_90;
311
      case 180:
312
        return kDegree_180;
313
      case 270:
314
        return kDegree_270;
315
      default:
316
        NS_WARNING_ASSERTION(aDegree == 0, "Invalid rotation degree, ignored");
317
        return kDegree_0;
318
    }
319
  }
320
321
  // Size in pixels at which the video is rendered. This is after it has
322
  // been scaled by its aspect ratio.
323
  gfx::IntSize mDisplay;
324
325
  // Indicates the frame layout for single track stereo videos.
326
  StereoMode mStereoMode;
327
328
  // Size of the decoded video's image.
329
  gfx::IntSize mImage;
330
331
  RefPtr<MediaByteBuffer> mCodecSpecificConfig;
332
  RefPtr<MediaByteBuffer> mExtraData;
333
334
  // Describing how many degrees video frames should be rotated in clock-wise to
335
  // get correct view.
336
  Rotation mRotation;
337
338
  // Should be 8, 10 or 12. Default value is 8.
339
  uint8_t mBitDepth = 8;
340
341
private:
342
  // mImage may be cropped; currently only used with the WebM container.
343
  // A negative width or height indicate that no cropping is to occur.
344
  gfx::IntRect mImageRect;
345
346
  // Indicates whether or not frames may contain alpha information.
347
  bool mAlphaPresent = false;
348
};
349
350
class AudioInfo : public TrackInfo
351
{
352
public:
353
  AudioInfo()
354
    : TrackInfo(kAudioTrack, NS_LITERAL_STRING("1"), NS_LITERAL_STRING("main"),
355
                EmptyString(), EmptyString(), true, 1)
356
    , mRate(0)
357
    , mChannels(0)
358
    , mChannelMap(AudioConfig::ChannelLayout::UNKNOWN_MAP)
359
    , mBitDepth(0)
360
    , mProfile(0)
361
    , mExtendedProfile(0)
362
    , mCodecSpecificConfig(new MediaByteBuffer)
363
    , mExtraData(new MediaByteBuffer)
364
  {
365
  }
366
367
  AudioInfo(const AudioInfo& aOther)
368
    : TrackInfo(aOther)
369
    , mRate(aOther.mRate)
370
    , mChannels(aOther.mChannels)
371
    , mChannelMap(aOther.mChannelMap)
372
    , mBitDepth(aOther.mBitDepth)
373
    , mProfile(aOther.mProfile)
374
    , mExtendedProfile(aOther.mExtendedProfile)
375
    , mCodecSpecificConfig(aOther.mCodecSpecificConfig)
376
    , mExtraData(aOther.mExtraData)
377
  {
378
  }
379
380
  static const uint32_t MAX_RATE = 640000;
381
382
  bool IsValid() const override
383
  {
384
    return mChannels > 0 && mRate > 0 && mRate <= MAX_RATE;
385
  }
386
387
  AudioInfo* GetAsAudioInfo() override
388
  {
389
    return this;
390
  }
391
392
  const AudioInfo* GetAsAudioInfo() const override
393
  {
394
    return this;
395
  }
396
397
  UniquePtr<TrackInfo> Clone() const override
398
  {
399
    return MakeUnique<AudioInfo>(*this);
400
  }
401
402
  // Sample rate.
403
  uint32_t mRate;
404
405
  // Number of audio channels.
406
  uint32_t mChannels;
407
  // The AudioConfig::ChannelLayout map. Channels are ordered as per SMPTE
408
  // definition. A value of UNKNOWN_MAP indicates unknown layout.
409
  // ChannelMap is an unsigned bitmap compatible with Windows' WAVE and FFmpeg
410
  // channel map.
411
  AudioConfig::ChannelLayout::ChannelMap mChannelMap;
412
413
  // Bits per sample.
414
  uint32_t mBitDepth;
415
416
  // Codec profile.
417
  int8_t mProfile;
418
419
  // Extended codec profile.
420
  int8_t mExtendedProfile;
421
422
  RefPtr<MediaByteBuffer> mCodecSpecificConfig;
423
  RefPtr<MediaByteBuffer> mExtraData;
424
};
425
426
class EncryptionInfo
427
{
428
public:
429
  EncryptionInfo()
430
    : mEncrypted(false)
431
  {
432
  }
433
434
  struct InitData
435
  {
436
    template<typename AInitDatas>
437
    InitData(const nsAString& aType, AInitDatas&& aInitData)
438
      : mType(aType)
439
      , mInitData(std::forward<AInitDatas>(aInitData))
440
    {
441
    }
442
443
    // Encryption type to be passed to JS. Usually `cenc'.
444
    nsString mType;
445
446
    // Encryption data.
447
    nsTArray<uint8_t> mInitData;
448
  };
449
  typedef nsTArray<InitData> InitDatas;
450
451
  // True if the stream has encryption metadata
452
  bool IsEncrypted() const
453
  {
454
    return mEncrypted;
455
  }
456
457
  void Reset()
458
  {
459
    mEncrypted = false;
460
    mInitDatas.Clear();
461
  }
462
463
  template<typename AInitDatas>
464
  void AddInitData(const nsAString& aType, AInitDatas&& aInitData)
465
  {
466
    mInitDatas.AppendElement(InitData(aType, std::forward<AInitDatas>(aInitData)));
467
    mEncrypted = true;
468
  }
469
470
  void AddInitData(const EncryptionInfo& aInfo)
471
  {
472
    mInitDatas.AppendElements(aInfo.mInitDatas);
473
    mEncrypted = !!mInitDatas.Length();
474
  }
475
476
  // One 'InitData' per encrypted buffer.
477
  InitDatas mInitDatas;
478
private:
479
  bool mEncrypted;
480
};
481
482
class MediaInfo
483
{
484
public:
485
  bool HasVideo() const
486
  {
487
    return mVideo.IsValid();
488
  }
489
490
  void EnableVideo()
491
  {
492
    if (HasVideo()) {
493
      return;
494
    }
495
    // Set dummy values so that HasVideo() will return true;
496
    // See VideoInfo::IsValid()
497
    mVideo.mDisplay = gfx::IntSize(1, 1);
498
  }
499
500
  bool HasAudio() const
501
  {
502
    return mAudio.IsValid();
503
  }
504
505
  void EnableAudio()
506
  {
507
    if (HasAudio()) {
508
      return;
509
    }
510
    // Set dummy values so that HasAudio() will return true;
511
    // See AudioInfo::IsValid()
512
    mAudio.mChannels = 2;
513
    mAudio.mRate = 44100;
514
  }
515
516
  bool IsEncrypted() const
517
  {
518
    return (HasAudio() && mAudio.mCrypto.mValid) ||
519
           (HasVideo() && mVideo.mCrypto.mValid);
520
  }
521
522
  bool HasValidMedia() const
523
  {
524
    return HasVideo() || HasAudio();
525
  }
526
527
  void AssertValid() const
528
  {
529
    NS_ASSERTION(!HasAudio() || mAudio.mTrackId != TRACK_INVALID,
530
                 "Audio track ID must be valid");
531
    NS_ASSERTION(!HasVideo() || mVideo.mTrackId != TRACK_INVALID,
532
                 "Audio track ID must be valid");
533
    NS_ASSERTION(!HasAudio() || !HasVideo() ||
534
                 mAudio.mTrackId != mVideo.mTrackId,
535
                 "Duplicate track IDs");
536
  }
537
538
  // TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
539
  VideoInfo mVideo;
540
  AudioInfo mAudio;
541
542
  // If the metadata includes a duration, we store it here.
543
  media::NullableTimeUnit mMetadataDuration;
544
545
  // The Ogg reader tries to kinda-sorta compute the duration by seeking to the
546
  // end and determining the timestamp of the last frame. This isn't useful as
547
  // a duration until we know the start time, so we need to track it separately.
548
  media::NullableTimeUnit mUnadjustedMetadataEndTime;
549
550
  // True if the media is seekable (i.e. supports random access).
551
  bool mMediaSeekable = true;
552
553
  // True if the media is only seekable within its buffered ranges.
554
  bool mMediaSeekableOnlyInBufferedRanges = false;
555
556
  EncryptionInfo mCrypto;
557
558
  // The minimum of start times of audio and video tracks.
559
  // Use to map the zero time on the media timeline to the first frame.
560
  media::TimeUnit mStartTime;
561
};
562
563
class TrackInfoSharedPtr
564
{
565
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackInfoSharedPtr)
566
public:
567
  TrackInfoSharedPtr(const TrackInfo& aOriginal, uint32_t aStreamID)
568
    : mInfo(aOriginal.Clone())
569
    , mStreamSourceID(aStreamID)
570
    , mMimeType(mInfo->mMimeType)
571
  {
572
  }
573
574
  uint32_t GetID() const
575
0
  {
576
0
    return mStreamSourceID;
577
0
  }
578
579
  operator const TrackInfo*() const
580
0
  {
581
0
    return mInfo.get();
582
0
  }
583
584
  const TrackInfo* operator*() const
585
  {
586
    return mInfo.get();
587
  }
588
589
  const TrackInfo* operator->() const
590
0
  {
591
0
    MOZ_ASSERT(mInfo.get(), "dereferencing a UniquePtr containing nullptr");
592
0
    return mInfo.get();
593
0
  }
594
595
  const AudioInfo* GetAsAudioInfo() const
596
  {
597
    return mInfo ? mInfo->GetAsAudioInfo() : nullptr;
598
  }
599
600
  const VideoInfo* GetAsVideoInfo() const
601
  {
602
    return mInfo ? mInfo->GetAsVideoInfo() : nullptr;
603
  }
604
605
  const TextInfo* GetAsTextInfo() const
606
  {
607
    return mInfo ? mInfo->GetAsTextInfo() : nullptr;
608
  }
609
610
private:
611
  ~TrackInfoSharedPtr() { }
612
  UniquePtr<TrackInfo> mInfo;
613
  // A unique ID, guaranteed to change when changing streams.
614
  uint32_t mStreamSourceID;
615
616
public:
617
  const nsCString& mMimeType;
618
};
619
620
} // namespace mozilla
621
622
#endif // MediaInfo_h