summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/apple/AppleVTDecoder.h
blob: 140a33562847ea0f56738c277d3a63262ec8ea67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */

#ifndef mozilla_AppleVTDecoder_h
#define mozilla_AppleVTDecoder_h

#include <CoreFoundation/CFDictionary.h>  // For CFDictionaryRef
#include <CoreMedia/CoreMedia.h>          // For CMVideoFormatDescriptionRef
#include <VideoToolbox/VideoToolbox.h>    // For VTDecompressionSessionRef

#include "AppleDecoderModule.h"
#include "PerformanceRecorder.h"
#include "PlatformDecoderModule.h"
#include "ReorderQueue.h"
#include "TimeUnits.h"
#include "mozilla/Atomics.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ProfilerUtils.h"

namespace mozilla {

DDLoggedTypeDeclNameAndBase(AppleVTDecoder, MediaDataDecoder);

class AppleVTDecoder final : public MediaDataDecoder,
                             public DecoderDoctorLifeLogger<AppleVTDecoder> {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AppleVTDecoder, final);

  AppleVTDecoder(const VideoInfo& aConfig,
                 layers::ImageContainer* aImageContainer,
                 CreateDecoderParams::OptionSet aOptions,
                 layers::KnowsCompositor* aKnowsCompositor,
                 Maybe<TrackingId> aTrackingId);

  class AppleFrameRef {
   public:
    media::TimeUnit decode_timestamp;
    media::TimeUnit composition_timestamp;
    media::TimeUnit duration;
    int64_t byte_offset;
    bool is_sync_point;

    explicit AppleFrameRef(const MediaRawData& aSample)
        : decode_timestamp(aSample.mTimecode),
          composition_timestamp(aSample.mTime),
          duration(aSample.mDuration),
          byte_offset(aSample.mOffset),
          is_sync_point(aSample.mKeyframe) {}
  };

  RefPtr<InitPromise> Init() override;
  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
  RefPtr<DecodePromise> Drain() override;
  RefPtr<FlushPromise> Flush() override;
  RefPtr<ShutdownPromise> Shutdown() override;
  void SetSeekThreshold(const media::TimeUnit& aTime) override;

  bool IsHardwareAccelerated(nsACString& aFailureReason) const override {
    return mIsHardwareAccelerated;
  }

  nsCString GetDescriptionName() const override {
    return mIsHardwareAccelerated ? "apple hardware VT decoder"_ns
                                  : "apple software VT decoder"_ns;
  }

  nsCString GetCodecName() const override;

  ConversionRequired NeedsConversion() const override {
    return ConversionRequired::kNeedAVCC;
  }

  // Access from the taskqueue and the decoder's thread.
  // OutputFrame is thread-safe.
  void OutputFrame(CVPixelBufferRef aImage, AppleFrameRef aFrameRef);
  void OnDecodeError(OSStatus aError);

 private:
  friend class AppleDecoderModule;  // To access InitializeSession.
  virtual ~AppleVTDecoder();
  RefPtr<FlushPromise> ProcessFlush();
  RefPtr<DecodePromise> ProcessDrain();
  void ProcessShutdown();
  void ProcessDecode(MediaRawData* aSample);
  void MaybeResolveBufferedFrames();

  void MaybeRegisterCallbackThread();

  void AssertOnTaskQueue() { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); }

  AppleFrameRef* CreateAppleFrameRef(const MediaRawData* aSample);
  CFDictionaryRef CreateOutputConfiguration();

  const RefPtr<MediaByteBuffer> mExtraData;
  const uint32_t mPictureWidth;
  const uint32_t mPictureHeight;
  const uint32_t mDisplayWidth;
  const uint32_t mDisplayHeight;
  const gfx::YUVColorSpace mColorSpace;
  const gfx::ColorSpace2 mColorPrimaries;
  const gfx::TransferFunction mTransferFunction;
  const gfx::ColorRange mColorRange;
  const gfx::ColorDepth mColorDepth;

  // Method to set up the decompression session.
  MediaResult InitializeSession();
  nsresult WaitForAsynchronousFrames();
  CFDictionaryRef CreateDecoderSpecification();
  CFDictionaryRef CreateDecoderExtensions();

  enum class StreamType { Unknown, H264, VP9 };
  const StreamType mStreamType;
  const RefPtr<TaskQueue> mTaskQueue;
  const uint32_t mMaxRefFrames;
  const RefPtr<layers::ImageContainer> mImageContainer;
  const RefPtr<layers::KnowsCompositor> mKnowsCompositor;
  const bool mUseSoftwareImages;
  const Maybe<TrackingId> mTrackingId;

  // Set on reader/decode thread calling Flush() to indicate that output is
  // not required and so input samples on mTaskQueue need not be processed.
  Atomic<bool> mIsFlushing;
  std::atomic<ProfilerThreadId> mCallbackThreadId;
  // Protects mReorderQueue and mPromise.
  Monitor mMonitor MOZ_UNANNOTATED;
  ReorderQueue mReorderQueue;
  MozMonitoredPromiseHolder<DecodePromise> mPromise;

  // Decoded frame will be dropped if its pts is smaller than this
  // value. It shold be initialized before Input() or after Flush(). So it is
  // safe to access it in OutputFrame without protecting.
  Maybe<media::TimeUnit> mSeekTargetThreshold;

  CMVideoFormatDescriptionRef mFormat;
  VTDecompressionSessionRef mSession;
  Atomic<bool> mIsHardwareAccelerated;
  PerformanceRecorderMulti<DecodeStage> mPerformanceRecorder;
};

}  // namespace mozilla

#endif  // mozilla_AppleVTDecoder_h