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(GonkMediaDataDecoder_h_)
8 #define GonkMediaDataDecoder_h_
9 #include "PlatformDecoderModule.h"
10 #include <stagefright/foundation/AHandler.h>
11 
12 namespace android {
13 struct ALooper;
14 class MediaBuffer;
15 class MediaCodecProxy;
16 } // namespace android
17 
18 namespace mozilla {
19 class MediaRawData;
20 
21 // Manage the data flow from inputting encoded data and outputting decode data.
22 class GonkDecoderManager : public android::AHandler {
23 public:
24   typedef TrackInfo::TrackType TrackType;
25   typedef MediaDataDecoder::InitPromise InitPromise;
26 
~GonkDecoderManager()27   virtual ~GonkDecoderManager() {}
28 
29   virtual RefPtr<InitPromise> Init() = 0;
30   virtual const char* GetDescriptionName() const = 0;
31 
32   // Asynchronously send sample into mDecoder. If out of input buffer, aSample
33   // will be queued for later re-send.
34   nsresult Input(MediaRawData* aSample);
35 
36   // Flush the queued samples and signal decoder to throw all pending input/output away.
37   nsresult Flush();
38 
39   // Shutdown decoder and rejects the init promise.
40   virtual nsresult Shutdown();
41 
42   // How many samples are waiting for processing.
43   size_t NumQueuedSamples();
44 
45   // Set callback for decoder events, such as requesting more input,
46   // returning output, or reporting error.
SetDecodeCallback(MediaDataDecoderCallback * aCallback)47   void SetDecodeCallback(MediaDataDecoderCallback* aCallback)
48   {
49     mDecodeCallback = aCallback;
50   }
51 
52 protected:
GonkDecoderManager()53   GonkDecoderManager()
54     : mMutex("GonkDecoderManager")
55     , mLastTime(INT64_MIN)
56     , mFlushMonitor("GonkDecoderManager::Flush")
57     , mIsFlushing(false)
58     , mDecodeCallback(nullptr)
59   {}
60 
61   bool InitLoopers(MediaData::Type aType);
62 
63   void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
64 
65   // Produces decoded output. It returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
66   // when output is not produced yet.
67   // If this returns a failure code other than NS_ERROR_NOT_AVAILABLE, an error
68   // will be reported through mDecodeCallback.
69   virtual nsresult Output(int64_t aStreamOffset,
70                           RefPtr<MediaData>& aOutput) = 0;
71 
72   // Send queued samples to OMX. It returns how many samples are still in
73   // queue after processing, or negative error code if failed.
74   int32_t ProcessQueuedSamples();
75 
76   void ProcessInput(bool aEndOfStream);
77   virtual void ProcessFlush();
78   void ProcessToDo(bool aEndOfStream);
79   virtual void ResetEOS();
80 
81   RefPtr<MediaByteBuffer> mCodecSpecificData;
82 
83   nsAutoCString mMimeType;
84 
85   // MediaCodedc's wrapper that performs the decoding.
86   android::sp<android::MediaCodecProxy> mDecoder;
87   // Looper for mDecoder to run on.
88   android::sp<android::ALooper> mDecodeLooper;
89   // Looper to run decode tasks such as processing input, output, flush, and
90   // recycling output buffers.
91   android::sp<android::ALooper> mTaskLooper;
92   // Message codes for tasks running on mTaskLooper.
93   enum {
94     // Decoder will send this to indicate internal state change such as input or
95     // output buffers availability. Used to run pending input & output tasks.
96     kNotifyDecoderActivity = 'nda ',
97     // Signal the decoder to flush.
98     kNotifyProcessFlush = 'npf ',
99     // Used to process queued samples when there is new input.
100     kNotifyProcessInput = 'npi ',
101 #ifdef DEBUG
102     kNotifyFindLooperId = 'nfli',
103 #endif
104   };
105 
106   MozPromiseHolder<InitPromise> mInitPromise;
107 
108   Mutex mMutex; // Protects mQueuedSamples.
109   // A queue that stores the samples waiting to be sent to mDecoder.
110   // Empty element means EOS and there shouldn't be any sample be queued after it.
111   // Samples are queued in caller's thread and dequeued in mTaskLooper.
112   nsTArray<RefPtr<MediaRawData>> mQueuedSamples;
113 
114   // The last decoded frame presentation time. Only accessed on mTaskLooper.
115   int64_t mLastTime;
116 
117   Monitor mFlushMonitor; // Waits for flushing to complete.
118   bool mIsFlushing; // Protected by mFlushMonitor.
119 
120   // Remembers the notification that is currently waiting for the decoder event
121   // to avoid requesting more than one notification at the time, which is
122   // forbidden by mDecoder.
123   android::sp<android::AMessage> mToDo;
124 
125   // Stores sample info for output buffer processing later.
126   struct WaitOutputInfo {
WaitOutputInfoWaitOutputInfo127     WaitOutputInfo(int64_t aOffset, int64_t aTimestamp, bool aEOS)
128       : mOffset(aOffset)
129       , mTimestamp(aTimestamp)
130       , mEOS(aEOS)
131     {}
132     const int64_t mOffset;
133     const int64_t mTimestamp;
134     const bool mEOS;
135   };
136 
137   nsTArray<WaitOutputInfo> mWaitOutput;
138 
139   MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error.
140 
141 private:
142   void UpdateWaitingList(int64_t aForgetUpTo);
143 
144 #ifdef DEBUG
145   typedef void* LooperId;
146 
147   bool OnTaskLooper();
148   LooperId mTaskLooperId;
149 #endif
150 };
151 
152 class AutoReleaseMediaBuffer
153 {
154 public:
AutoReleaseMediaBuffer(android::MediaBuffer * aBuffer,android::MediaCodecProxy * aCodec)155   AutoReleaseMediaBuffer(android::MediaBuffer* aBuffer, android::MediaCodecProxy* aCodec)
156     : mBuffer(aBuffer)
157     , mCodec(aCodec)
158   {}
159 
~AutoReleaseMediaBuffer()160   ~AutoReleaseMediaBuffer()
161   {
162     MOZ_ASSERT(mCodec.get());
163     if (mBuffer) {
164       mCodec->ReleaseMediaBuffer(mBuffer);
165     }
166   }
167 
forget()168   android::MediaBuffer* forget()
169   {
170     android::MediaBuffer* tmp = mBuffer;
171     mBuffer = nullptr;
172     return tmp;
173   }
174 
175 private:
176   android::MediaBuffer* mBuffer;
177   android::sp<android::MediaCodecProxy> mCodec;
178 };
179 
180 // Samples are decoded using the GonkDecoder (MediaCodec)
181 // created by the GonkDecoderManager. This class implements
182 // the higher-level logic that drives mapping the Gonk to the async
183 // MediaDataDecoder interface. The specifics of decoding the exact stream
184 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
185 class GonkMediaDataDecoder : public MediaDataDecoder {
186 public:
187   GonkMediaDataDecoder(GonkDecoderManager* aDecoderManager,
188                        MediaDataDecoderCallback* aCallback);
189 
190   ~GonkMediaDataDecoder();
191 
192   RefPtr<InitPromise> Init() override;
193 
194   void Input(MediaRawData* aSample) override;
195 
196   void Flush() override;
197 
198   void Drain() override;
199 
200   void Shutdown() override;
201 
GetDescriptionName()202   const char* GetDescriptionName() const override
203   {
204     return "gonk decoder";
205   }
206 
207 private:
208 
209   android::sp<GonkDecoderManager> mManager;
210 };
211 
212 } // namespace mozilla
213 
214 #endif // GonkMediaDataDecoder_h_
215