|
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 file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "MediaOmxDecoder.h" |
|
8 #include "MediaOmxReader.h" |
|
9 #include "MediaDecoderStateMachine.h" |
|
10 |
|
11 #include "OmxDecoder.h" |
|
12 |
|
13 #ifdef MOZ_AUDIO_OFFLOAD |
|
14 #include "AudioOffloadPlayer.h" |
|
15 #endif |
|
16 |
|
17 using namespace android; |
|
18 |
|
19 namespace mozilla { |
|
20 |
|
21 #ifdef PR_LOGGING |
|
22 extern PRLogModuleInfo* gMediaDecoderLog; |
|
23 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) |
|
24 #else |
|
25 #define DECODER_LOG(type, msg) |
|
26 #endif |
|
27 |
|
28 MediaOmxDecoder::MediaOmxDecoder() : |
|
29 MediaDecoder(), |
|
30 mCanOffloadAudio(false), |
|
31 mFallbackToStateMachine(false) |
|
32 { |
|
33 #ifdef PR_LOGGING |
|
34 if (!gMediaDecoderLog) { |
|
35 gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); |
|
36 } |
|
37 #endif |
|
38 } |
|
39 |
|
40 MediaDecoder* MediaOmxDecoder::Clone() |
|
41 { |
|
42 return new MediaOmxDecoder(); |
|
43 } |
|
44 |
|
45 MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine() |
|
46 { |
|
47 mReader = new MediaOmxReader(this); |
|
48 mReader->SetAudioChannel(GetAudioChannel()); |
|
49 return new MediaDecoderStateMachine(this, mReader); |
|
50 } |
|
51 |
|
52 void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio) |
|
53 { |
|
54 ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); |
|
55 mCanOffloadAudio = aCanOffloadAudio; |
|
56 } |
|
57 |
|
58 void MediaOmxDecoder::MetadataLoaded(int aChannels, |
|
59 int aRate, |
|
60 bool aHasAudio, |
|
61 bool aHasVideo, |
|
62 MetadataTags* aTags) |
|
63 { |
|
64 MOZ_ASSERT(NS_IsMainThread()); |
|
65 MediaDecoder::MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags); |
|
66 |
|
67 ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); |
|
68 if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() || |
|
69 mInitialPlaybackRate != 1.0) { |
|
70 DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed", |
|
71 __PRETTY_FUNCTION__)); |
|
72 return; |
|
73 } |
|
74 |
|
75 #ifdef MOZ_AUDIO_OFFLOAD |
|
76 mAudioOffloadPlayer = new AudioOffloadPlayer(this); |
|
77 #endif |
|
78 mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack()); |
|
79 status_t err = mAudioOffloadPlayer->Start(false); |
|
80 if (err == OK) { |
|
81 PauseStateMachine(); |
|
82 // Call ChangeState() to run AudioOffloadPlayer since offload state enabled |
|
83 ChangeState(mPlayState); |
|
84 return; |
|
85 } |
|
86 |
|
87 mAudioOffloadPlayer = nullptr; |
|
88 DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d." |
|
89 "Switching to normal mode", __PRETTY_FUNCTION__, err)); |
|
90 } |
|
91 |
|
92 void MediaOmxDecoder::PauseStateMachine() |
|
93 { |
|
94 MOZ_ASSERT(NS_IsMainThread()); |
|
95 GetReentrantMonitor().AssertCurrentThreadIn(); |
|
96 DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); |
|
97 if (!mDecoderStateMachine) { |
|
98 return; |
|
99 } |
|
100 StopProgress(); |
|
101 mDecoderStateMachine->SetDormant(true); |
|
102 } |
|
103 |
|
104 void MediaOmxDecoder::ResumeStateMachine() |
|
105 { |
|
106 MOZ_ASSERT(NS_IsMainThread()); |
|
107 ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); |
|
108 DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__, |
|
109 mCurrentTime)); |
|
110 |
|
111 if (!mDecoderStateMachine) { |
|
112 return; |
|
113 } |
|
114 |
|
115 mFallbackToStateMachine = true; |
|
116 mAudioOffloadPlayer = nullptr; |
|
117 mRequestedSeekTarget = SeekTarget(mCurrentTime, SeekTarget::Accurate); |
|
118 |
|
119 mNextState = mPlayState; |
|
120 ChangeState(PLAY_STATE_LOADING); |
|
121 mDecoderStateMachine->SetDormant(false); |
|
122 } |
|
123 |
|
124 void MediaOmxDecoder::AudioOffloadTearDown() |
|
125 { |
|
126 MOZ_ASSERT(NS_IsMainThread()); |
|
127 PlaybackPositionChanged(); |
|
128 DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); |
|
129 { |
|
130 // Audio offload player sent tear down event. Fallback to state machine |
|
131 ResumeStateMachine(); |
|
132 } |
|
133 } |
|
134 |
|
135 void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream, |
|
136 bool aFinishWhenEnded) |
|
137 { |
|
138 MOZ_ASSERT(NS_IsMainThread()); |
|
139 PlaybackPositionChanged(); |
|
140 |
|
141 if (mAudioOffloadPlayer) { |
|
142 // Offload player cannot handle MediaStream. Fallback |
|
143 ResumeStateMachine(); |
|
144 } |
|
145 |
|
146 MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded); |
|
147 } |
|
148 |
|
149 void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate) |
|
150 { |
|
151 MOZ_ASSERT(NS_IsMainThread()); |
|
152 PlaybackPositionChanged(); |
|
153 |
|
154 if (mAudioOffloadPlayer && |
|
155 ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) { |
|
156 // Offload player cannot handle playback rate other than 1/0. Fallback |
|
157 ResumeStateMachine(); |
|
158 } |
|
159 |
|
160 MediaDecoder::SetPlaybackRate(aPlaybackRate); |
|
161 } |
|
162 |
|
163 void MediaOmxDecoder::ChangeState(PlayState aState) |
|
164 { |
|
165 MOZ_ASSERT(NS_IsMainThread()); |
|
166 // Keep MediaDecoder state in sync with MediaElement irrespective of offload |
|
167 // playback so it will continue to work in normal mode when offloading fails |
|
168 // in between |
|
169 MediaDecoder::ChangeState(aState); |
|
170 |
|
171 if (mAudioOffloadPlayer) { |
|
172 status_t err = mAudioOffloadPlayer->ChangeState(aState); |
|
173 if (err != OK) { |
|
174 ResumeStateMachine(); |
|
175 } |
|
176 } |
|
177 } |
|
178 |
|
179 void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState) |
|
180 { |
|
181 MOZ_ASSERT(NS_IsMainThread()); |
|
182 // During offload playback, state machine should be in dormant state. |
|
183 // ApplyStateToStateMachine() can change state machine state to |
|
184 // something else or reset the seek time. So don't call this when audio is |
|
185 // offloaded |
|
186 if (!mAudioOffloadPlayer) { |
|
187 MediaDecoder::ApplyStateToStateMachine(aState); |
|
188 } |
|
189 } |
|
190 |
|
191 void MediaOmxDecoder::PlaybackPositionChanged() |
|
192 { |
|
193 MOZ_ASSERT(NS_IsMainThread()); |
|
194 if (!mAudioOffloadPlayer) { |
|
195 MediaDecoder::PlaybackPositionChanged(); |
|
196 return; |
|
197 } |
|
198 |
|
199 if (!mOwner || mShuttingDown) { |
|
200 return; |
|
201 } |
|
202 |
|
203 double lastTime = mCurrentTime; |
|
204 { |
|
205 ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); |
|
206 mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs(); |
|
207 } |
|
208 if (mOwner && lastTime != mCurrentTime) { |
|
209 FireTimeUpdate(); |
|
210 } |
|
211 } |
|
212 |
|
213 void MediaOmxDecoder::SetElementVisibility(bool aIsVisible) |
|
214 { |
|
215 MOZ_ASSERT(NS_IsMainThread()); |
|
216 if (mAudioOffloadPlayer) { |
|
217 mAudioOffloadPlayer->SetElementVisibility(aIsVisible); |
|
218 } |
|
219 } |
|
220 |
|
221 void MediaOmxDecoder::UpdateReadyStateForData() |
|
222 { |
|
223 MOZ_ASSERT(NS_IsMainThread()); |
|
224 if (!mAudioOffloadPlayer) { |
|
225 MediaDecoder::UpdateReadyStateForData(); |
|
226 return; |
|
227 } |
|
228 |
|
229 if (!mOwner || mShuttingDown) |
|
230 return; |
|
231 mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus()); |
|
232 } |
|
233 |
|
234 void MediaOmxDecoder::SetVolume(double aVolume) |
|
235 { |
|
236 MOZ_ASSERT(NS_IsMainThread()); |
|
237 if (!mAudioOffloadPlayer) { |
|
238 MediaDecoder::SetVolume(aVolume); |
|
239 return; |
|
240 } |
|
241 mAudioOffloadPlayer->SetVolume(aVolume); |
|
242 } |
|
243 |
|
244 } // namespace mozilla |