1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/omx/MediaOmxDecoder.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,244 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "MediaOmxDecoder.h" 1.11 +#include "MediaOmxReader.h" 1.12 +#include "MediaDecoderStateMachine.h" 1.13 + 1.14 +#include "OmxDecoder.h" 1.15 + 1.16 +#ifdef MOZ_AUDIO_OFFLOAD 1.17 +#include "AudioOffloadPlayer.h" 1.18 +#endif 1.19 + 1.20 +using namespace android; 1.21 + 1.22 +namespace mozilla { 1.23 + 1.24 +#ifdef PR_LOGGING 1.25 +extern PRLogModuleInfo* gMediaDecoderLog; 1.26 +#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) 1.27 +#else 1.28 +#define DECODER_LOG(type, msg) 1.29 +#endif 1.30 + 1.31 +MediaOmxDecoder::MediaOmxDecoder() : 1.32 + MediaDecoder(), 1.33 + mCanOffloadAudio(false), 1.34 + mFallbackToStateMachine(false) 1.35 +{ 1.36 +#ifdef PR_LOGGING 1.37 + if (!gMediaDecoderLog) { 1.38 + gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); 1.39 + } 1.40 +#endif 1.41 +} 1.42 + 1.43 +MediaDecoder* MediaOmxDecoder::Clone() 1.44 +{ 1.45 + return new MediaOmxDecoder(); 1.46 +} 1.47 + 1.48 +MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine() 1.49 +{ 1.50 + mReader = new MediaOmxReader(this); 1.51 + mReader->SetAudioChannel(GetAudioChannel()); 1.52 + return new MediaDecoderStateMachine(this, mReader); 1.53 +} 1.54 + 1.55 +void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio) 1.56 +{ 1.57 + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); 1.58 + mCanOffloadAudio = aCanOffloadAudio; 1.59 +} 1.60 + 1.61 +void MediaOmxDecoder::MetadataLoaded(int aChannels, 1.62 + int aRate, 1.63 + bool aHasAudio, 1.64 + bool aHasVideo, 1.65 + MetadataTags* aTags) 1.66 +{ 1.67 + MOZ_ASSERT(NS_IsMainThread()); 1.68 + MediaDecoder::MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags); 1.69 + 1.70 + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); 1.71 + if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() || 1.72 + mInitialPlaybackRate != 1.0) { 1.73 + DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed", 1.74 + __PRETTY_FUNCTION__)); 1.75 + return; 1.76 + } 1.77 + 1.78 +#ifdef MOZ_AUDIO_OFFLOAD 1.79 + mAudioOffloadPlayer = new AudioOffloadPlayer(this); 1.80 +#endif 1.81 + mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack()); 1.82 + status_t err = mAudioOffloadPlayer->Start(false); 1.83 + if (err == OK) { 1.84 + PauseStateMachine(); 1.85 + // Call ChangeState() to run AudioOffloadPlayer since offload state enabled 1.86 + ChangeState(mPlayState); 1.87 + return; 1.88 + } 1.89 + 1.90 + mAudioOffloadPlayer = nullptr; 1.91 + DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d." 1.92 + "Switching to normal mode", __PRETTY_FUNCTION__, err)); 1.93 +} 1.94 + 1.95 +void MediaOmxDecoder::PauseStateMachine() 1.96 +{ 1.97 + MOZ_ASSERT(NS_IsMainThread()); 1.98 + GetReentrantMonitor().AssertCurrentThreadIn(); 1.99 + DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); 1.100 + if (!mDecoderStateMachine) { 1.101 + return; 1.102 + } 1.103 + StopProgress(); 1.104 + mDecoderStateMachine->SetDormant(true); 1.105 +} 1.106 + 1.107 +void MediaOmxDecoder::ResumeStateMachine() 1.108 +{ 1.109 + MOZ_ASSERT(NS_IsMainThread()); 1.110 + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); 1.111 + DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__, 1.112 + mCurrentTime)); 1.113 + 1.114 + if (!mDecoderStateMachine) { 1.115 + return; 1.116 + } 1.117 + 1.118 + mFallbackToStateMachine = true; 1.119 + mAudioOffloadPlayer = nullptr; 1.120 + mRequestedSeekTarget = SeekTarget(mCurrentTime, SeekTarget::Accurate); 1.121 + 1.122 + mNextState = mPlayState; 1.123 + ChangeState(PLAY_STATE_LOADING); 1.124 + mDecoderStateMachine->SetDormant(false); 1.125 +} 1.126 + 1.127 +void MediaOmxDecoder::AudioOffloadTearDown() 1.128 +{ 1.129 + MOZ_ASSERT(NS_IsMainThread()); 1.130 + PlaybackPositionChanged(); 1.131 + DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__)); 1.132 + { 1.133 + // Audio offload player sent tear down event. Fallback to state machine 1.134 + ResumeStateMachine(); 1.135 + } 1.136 +} 1.137 + 1.138 +void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream, 1.139 + bool aFinishWhenEnded) 1.140 +{ 1.141 + MOZ_ASSERT(NS_IsMainThread()); 1.142 + PlaybackPositionChanged(); 1.143 + 1.144 + if (mAudioOffloadPlayer) { 1.145 + // Offload player cannot handle MediaStream. Fallback 1.146 + ResumeStateMachine(); 1.147 + } 1.148 + 1.149 + MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded); 1.150 +} 1.151 + 1.152 +void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate) 1.153 +{ 1.154 + MOZ_ASSERT(NS_IsMainThread()); 1.155 + PlaybackPositionChanged(); 1.156 + 1.157 + if (mAudioOffloadPlayer && 1.158 + ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) { 1.159 + // Offload player cannot handle playback rate other than 1/0. Fallback 1.160 + ResumeStateMachine(); 1.161 + } 1.162 + 1.163 + MediaDecoder::SetPlaybackRate(aPlaybackRate); 1.164 +} 1.165 + 1.166 +void MediaOmxDecoder::ChangeState(PlayState aState) 1.167 +{ 1.168 + MOZ_ASSERT(NS_IsMainThread()); 1.169 + // Keep MediaDecoder state in sync with MediaElement irrespective of offload 1.170 + // playback so it will continue to work in normal mode when offloading fails 1.171 + // in between 1.172 + MediaDecoder::ChangeState(aState); 1.173 + 1.174 + if (mAudioOffloadPlayer) { 1.175 + status_t err = mAudioOffloadPlayer->ChangeState(aState); 1.176 + if (err != OK) { 1.177 + ResumeStateMachine(); 1.178 + } 1.179 + } 1.180 +} 1.181 + 1.182 +void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState) 1.183 +{ 1.184 + MOZ_ASSERT(NS_IsMainThread()); 1.185 + // During offload playback, state machine should be in dormant state. 1.186 + // ApplyStateToStateMachine() can change state machine state to 1.187 + // something else or reset the seek time. So don't call this when audio is 1.188 + // offloaded 1.189 + if (!mAudioOffloadPlayer) { 1.190 + MediaDecoder::ApplyStateToStateMachine(aState); 1.191 + } 1.192 +} 1.193 + 1.194 +void MediaOmxDecoder::PlaybackPositionChanged() 1.195 +{ 1.196 + MOZ_ASSERT(NS_IsMainThread()); 1.197 + if (!mAudioOffloadPlayer) { 1.198 + MediaDecoder::PlaybackPositionChanged(); 1.199 + return; 1.200 + } 1.201 + 1.202 + if (!mOwner || mShuttingDown) { 1.203 + return; 1.204 + } 1.205 + 1.206 + double lastTime = mCurrentTime; 1.207 + { 1.208 + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); 1.209 + mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs(); 1.210 + } 1.211 + if (mOwner && lastTime != mCurrentTime) { 1.212 + FireTimeUpdate(); 1.213 + } 1.214 +} 1.215 + 1.216 +void MediaOmxDecoder::SetElementVisibility(bool aIsVisible) 1.217 +{ 1.218 + MOZ_ASSERT(NS_IsMainThread()); 1.219 + if (mAudioOffloadPlayer) { 1.220 + mAudioOffloadPlayer->SetElementVisibility(aIsVisible); 1.221 + } 1.222 +} 1.223 + 1.224 +void MediaOmxDecoder::UpdateReadyStateForData() 1.225 +{ 1.226 + MOZ_ASSERT(NS_IsMainThread()); 1.227 + if (!mAudioOffloadPlayer) { 1.228 + MediaDecoder::UpdateReadyStateForData(); 1.229 + return; 1.230 + } 1.231 + 1.232 + if (!mOwner || mShuttingDown) 1.233 + return; 1.234 + mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus()); 1.235 +} 1.236 + 1.237 +void MediaOmxDecoder::SetVolume(double aVolume) 1.238 +{ 1.239 + MOZ_ASSERT(NS_IsMainThread()); 1.240 + if (!mAudioOffloadPlayer) { 1.241 + MediaDecoder::SetVolume(aVolume); 1.242 + return; 1.243 + } 1.244 + mAudioOffloadPlayer->SetVolume(aVolume); 1.245 +} 1.246 + 1.247 +} // namespace mozilla