|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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 |
|
7 #if !defined(PlatformDecoderModule_h_) |
|
8 #define PlatformDecoderModule_h_ |
|
9 |
|
10 #include "MediaDecoderReader.h" |
|
11 #include "mozilla/layers/LayersTypes.h" |
|
12 #include "nsTArray.h" |
|
13 #include "mozilla/RefPtr.h" |
|
14 #include <queue> |
|
15 |
|
16 namespace mp4_demuxer { |
|
17 class VideoDecoderConfig; |
|
18 class AudioDecoderConfig; |
|
19 struct MP4Sample; |
|
20 } |
|
21 |
|
22 class nsIThreadPool; |
|
23 |
|
24 namespace mozilla { |
|
25 |
|
26 namespace layers { |
|
27 class ImageContainer; |
|
28 } |
|
29 |
|
30 class MediaDataDecoder; |
|
31 class MediaDataDecoderCallback; |
|
32 class MediaInputQueue; |
|
33 class MediaTaskQueue; |
|
34 typedef int64_t Microseconds; |
|
35 |
|
36 // The PlatformDecoderModule interface is used by the MP4Reader to abstract |
|
37 // access to the H264 and AAC decoders provided by various platforms. It |
|
38 // may be extended to support other codecs in future. Each platform (Windows, |
|
39 // MacOSX, Linux, B2G etc) must implement a PlatformDecoderModule to provide |
|
40 // access to its decoders in order to get decompressed H.264/AAC from the |
|
41 // MP4Reader. |
|
42 // |
|
43 // Video decoding is asynchronous, and should be performed on the task queue |
|
44 // provided if the underlying platform isn't already exposing an async API. |
|
45 // |
|
46 // Platforms that don't have a corresponding PlatformDecoderModule won't be |
|
47 // able to play the H.264/AAC data output by the MP4Reader. In practice this |
|
48 // means that we won't have fragmented MP4 supported in Media Source |
|
49 // Extensions. |
|
50 // |
|
51 // A cross-platform decoder module that discards input and produces "blank" |
|
52 // output samples exists for testing, and is created when the pref |
|
53 // "media.fragmented-mp4.use-blank-decoder" is true. |
|
54 class PlatformDecoderModule { |
|
55 public: |
|
56 // Call on the main thread to initialize the static state |
|
57 // needed by Create(). |
|
58 static void Init(); |
|
59 |
|
60 // Factory method that creates the appropriate PlatformDecoderModule for |
|
61 // the platform we're running on. Caller is responsible for deleting this |
|
62 // instance. It's expected that there will be multiple |
|
63 // PlatformDecoderModules alive at the same time. There is one |
|
64 // PlatformDecoderModule created per MP4Reader. |
|
65 // This is called on the decode thread. |
|
66 static PlatformDecoderModule* Create(); |
|
67 |
|
68 // Called to shutdown the decoder module and cleanup state. This should |
|
69 // block until shutdown is complete. This is called after Shutdown() has |
|
70 // been called on all MediaDataDecoders created from this |
|
71 // PlatformDecoderModule. |
|
72 // Called on the main thread only. |
|
73 virtual nsresult Shutdown() = 0; |
|
74 |
|
75 // Creates an H.264 decoder. The layers backend is passed in so that |
|
76 // decoders can determine whether hardware accelerated decoding can be used. |
|
77 // Asynchronous decoding of video should be done in runnables dispatched |
|
78 // to aVideoTaskQueue. If the task queue isn't needed, the decoder should |
|
79 // not hold a reference to it. |
|
80 // Output and errors should be returned to the reader via aCallback. |
|
81 // On Windows the task queue's threads in have MSCOM initialized with |
|
82 // COINIT_MULTITHREADED. |
|
83 // Returns nullptr if the decoder can't be created. |
|
84 // It is safe to store a reference to aConfig. |
|
85 // Called on decode thread. |
|
86 virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig, |
|
87 layers::LayersBackend aLayersBackend, |
|
88 layers::ImageContainer* aImageContainer, |
|
89 MediaTaskQueue* aVideoTaskQueue, |
|
90 MediaDataDecoderCallback* aCallback) = 0; |
|
91 |
|
92 // Creates an AAC decoder with the specified properties. |
|
93 // Asynchronous decoding of audio should be done in runnables dispatched to |
|
94 // aAudioTaskQueue. If the task queue isn't needed, the decoder should |
|
95 // not hold a reference to it. |
|
96 // Output and errors should be returned to the reader via aCallback. |
|
97 // Returns nullptr if the decoder can't be created. |
|
98 // On Windows the task queue's threads in have MSCOM initialized with |
|
99 // COINIT_MULTITHREADED. |
|
100 // It is safe to store a reference to aConfig. |
|
101 // Called on decode thread. |
|
102 virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, |
|
103 MediaTaskQueue* aAudioTaskQueue, |
|
104 MediaDataDecoderCallback* aCallback) = 0; |
|
105 |
|
106 virtual ~PlatformDecoderModule() {} |
|
107 |
|
108 protected: |
|
109 PlatformDecoderModule() {} |
|
110 // Caches pref media.fragmented-mp4.use-blank-decoder |
|
111 static bool sUseBlankDecoder; |
|
112 static bool sFFmpegDecoderEnabled; |
|
113 }; |
|
114 |
|
115 // A callback used by MediaDataDecoder to return output/errors to the |
|
116 // MP4Reader. Implementation is threadsafe, and can be called on any thread. |
|
117 class MediaDataDecoderCallback { |
|
118 public: |
|
119 virtual ~MediaDataDecoderCallback() {} |
|
120 |
|
121 // Called by MediaDataDecoder when a sample has been decoded. Callee is |
|
122 // responsibile for deleting aData. |
|
123 virtual void Output(MediaData* aData) = 0; |
|
124 |
|
125 // Denotes an error in the decoding process. The reader will stop calling |
|
126 // the decoder. |
|
127 virtual void Error() = 0; |
|
128 |
|
129 // Denotes that the last input sample has been inserted into the decoder, |
|
130 // and no more output can be produced unless more input is sent. |
|
131 virtual void InputExhausted() = 0; |
|
132 }; |
|
133 |
|
134 // MediaDataDecoder is the interface exposed by decoders created by the |
|
135 // PlatformDecoderModule's Create*Decoder() functions. The type of |
|
136 // media data that the decoder accepts as valid input and produces as |
|
137 // output is determined when the MediaDataDecoder is created. |
|
138 // |
|
139 // All functions must be threadsafe, and be able to be called on an |
|
140 // arbitrary thread. |
|
141 // |
|
142 // Decoding is done asynchronously. Any async work can be done on the |
|
143 // MediaTaskQueue passed into the PlatformDecoderModules's Create*Decoder() |
|
144 // function. This may not be necessary for platforms with async APIs |
|
145 // for decoding. |
|
146 class MediaDataDecoder { |
|
147 protected: |
|
148 virtual ~MediaDataDecoder() {}; |
|
149 |
|
150 public: |
|
151 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataDecoder) |
|
152 |
|
153 // Initialize the decoder. The decoder should be ready to decode after |
|
154 // this returns. The decoder should do any initialization here, rather |
|
155 // than in its constructor or PlatformDecoderModule::Create*Decoder(), |
|
156 // so that if the MP4Reader needs to shutdown during initialization, |
|
157 // it can call Shutdown() to cancel this operation. Any initialization |
|
158 // that requires blocking the calling thread in this function *must* |
|
159 // be done here so that it can be canceled by calling Shutdown()! |
|
160 virtual nsresult Init() = 0; |
|
161 |
|
162 // Inserts a sample into the decoder's decode pipeline. The decoder must |
|
163 // delete the sample once its been decoded. If Input() returns an error, |
|
164 // aSample will be deleted by the caller. |
|
165 virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0; |
|
166 |
|
167 // Causes all samples in the decoding pipeline to be discarded. When |
|
168 // this function returns, the decoder must be ready to accept new input |
|
169 // for decoding. This function is called when the demuxer seeks, before |
|
170 // decoding resumes after the seek. |
|
171 // While the reader calls Flush(), it ignores all output sent to it; |
|
172 // it is safe (but pointless) to send output while Flush is called. |
|
173 // The MP4Reader will not call Input() while it's calling Flush(). |
|
174 virtual nsresult Flush() = 0; |
|
175 |
|
176 // Causes all complete samples in the pipeline that can be decoded to be |
|
177 // output. If the decoder can't produce samples from the current output, |
|
178 // it drops the input samples. The decoder may be holding onto samples |
|
179 // that are required to decode samples that it expects to get in future. |
|
180 // This is called when the demuxer reaches end of stream. |
|
181 // The MP4Reader will not call Input() while it's calling Drain(). |
|
182 virtual nsresult Drain() = 0; |
|
183 |
|
184 // Cancels all init/input/drain operations, and shuts down the |
|
185 // decoder. The platform decoder should clean up any resources it's using |
|
186 // and release memory etc. Shutdown() must block until the decoder has |
|
187 // completed shutdown. The reader calls Flush() before calling Shutdown(). |
|
188 // The reader will delete the decoder once Shutdown() returns. |
|
189 // The MediaDataDecoderCallback *must* not be called after Shutdown() has |
|
190 // returned. |
|
191 virtual nsresult Shutdown() = 0; |
|
192 |
|
193 }; |
|
194 |
|
195 } // namespace mozilla |
|
196 |
|
197 #endif |