Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/remoting/remoting_renderer_controller.h" | 5 #include "media/remoting/remoting_renderer_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/threading/thread_checker.h" | 9 #include "base/threading/thread_checker.h" |
| 10 #include "media/base/video_util.h" | |
| 10 #include "media/remoting/remoting_cdm_context.h" | 11 #include "media/remoting/remoting_cdm_context.h" |
| 11 | 12 |
| 12 namespace media { | 13 namespace media { |
| 13 | 14 |
| 15 namespace { | |
| 16 | |
| 17 gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) { | |
| 18 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270) | |
| 19 return gfx::Size(natural_size.height(), natural_size.width()); | |
| 20 return natural_size; | |
| 21 } | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 14 RemotingRendererController::RemotingRendererController( | 25 RemotingRendererController::RemotingRendererController( |
| 15 scoped_refptr<RemotingSourceImpl> remoting_source) | 26 scoped_refptr<RemotingSourceImpl> remoting_source) |
| 16 : remoting_source_(remoting_source), weak_factory_(this) { | 27 : remoting_source_(remoting_source), weak_factory_(this) { |
| 17 remoting_source_->AddClient(this); | 28 remoting_source_->AddClient(this); |
| 18 } | 29 } |
| 19 | 30 |
| 20 RemotingRendererController::~RemotingRendererController() { | 31 RemotingRendererController::~RemotingRendererController() { |
| 21 DCHECK(thread_checker_.CalledOnValidThread()); | 32 DCHECK(thread_checker_.CalledOnValidThread()); |
| 22 remoting_source_->RemoveClient(this); | 33 remoting_source_->RemoveClient(this); |
| 23 } | 34 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 36 } else { | 47 } else { |
| 37 VLOG(1) << "Failed to start remoting."; | 48 VLOG(1) << "Failed to start remoting."; |
| 38 remote_rendering_started_ = false; | 49 remote_rendering_started_ = false; |
| 39 } | 50 } |
| 40 } | 51 } |
| 41 | 52 |
| 42 void RemotingRendererController::OnSessionStateChanged() { | 53 void RemotingRendererController::OnSessionStateChanged() { |
| 43 DCHECK(thread_checker_.CalledOnValidThread()); | 54 DCHECK(thread_checker_.CalledOnValidThread()); |
| 44 | 55 |
| 45 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state(); | 56 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state(); |
| 57 | |
| 58 UpdateInterstitial(); | |
| 46 UpdateAndMaybeSwitch(); | 59 UpdateAndMaybeSwitch(); |
| 47 } | 60 } |
| 48 | 61 |
| 49 void RemotingRendererController::OnEnteredFullscreen() { | 62 void RemotingRendererController::OnEnteredFullscreen() { |
| 50 DCHECK(thread_checker_.CalledOnValidThread()); | 63 DCHECK(thread_checker_.CalledOnValidThread()); |
| 51 | 64 |
| 52 is_fullscreen_ = true; | 65 is_fullscreen_ = true; |
| 53 UpdateAndMaybeSwitch(); | 66 UpdateAndMaybeSwitch(); |
| 54 } | 67 } |
| 55 | 68 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 DCHECK(thread_checker_.CalledOnValidThread()); | 109 DCHECK(thread_checker_.CalledOnValidThread()); |
| 97 | 110 |
| 98 remoting_source_->StartDataPipe(std::move(audio_data_pipe), | 111 remoting_source_->StartDataPipe(std::move(audio_data_pipe), |
| 99 std::move(video_data_pipe), done_callback); | 112 std::move(video_data_pipe), done_callback); |
| 100 } | 113 } |
| 101 | 114 |
| 102 void RemotingRendererController::OnMetadataChanged( | 115 void RemotingRendererController::OnMetadataChanged( |
| 103 const PipelineMetadata& metadata) { | 116 const PipelineMetadata& metadata) { |
| 104 DCHECK(thread_checker_.CalledOnValidThread()); | 117 DCHECK(thread_checker_.CalledOnValidThread()); |
| 105 | 118 |
| 119 const gfx::Size old_size = pipeline_metadata_.natural_size; | |
| 106 pipeline_metadata_ = metadata; | 120 pipeline_metadata_ = metadata; |
| 107 | 121 |
| 108 is_encrypted_ = false; | 122 is_encrypted_ = false; |
| 109 if (has_video()) { | 123 if (has_video()) { |
| 110 video_decoder_config_ = metadata.video_decoder_config; | 124 is_encrypted_ |= metadata.video_decoder_config.is_encrypted(); |
| 111 is_encrypted_ |= video_decoder_config_.is_encrypted(); | 125 pipeline_metadata_.natural_size = GetRotatedVideoSize( |
| 126 pipeline_metadata_.video_rotation, pipeline_metadata_.natural_size); | |
| 112 } | 127 } |
| 113 if (has_audio()) { | 128 if (has_audio()) { |
| 114 audio_decoder_config_ = metadata.audio_decoder_config; | 129 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted(); |
| 115 is_encrypted_ |= audio_decoder_config_.is_encrypted(); | |
| 116 } | 130 } |
| 131 | |
| 132 if (pipeline_metadata_.natural_size != old_size) | |
| 133 UpdateInterstitial(); | |
| 134 | |
| 117 UpdateAndMaybeSwitch(); | 135 UpdateAndMaybeSwitch(); |
| 118 } | 136 } |
| 119 | 137 |
| 120 bool RemotingRendererController::IsVideoCodecSupported() { | 138 bool RemotingRendererController::IsVideoCodecSupported() { |
| 121 DCHECK(thread_checker_.CalledOnValidThread()); | 139 DCHECK(thread_checker_.CalledOnValidThread()); |
| 122 DCHECK(has_video()); | 140 DCHECK(has_video()); |
| 123 | 141 |
| 124 switch (video_decoder_config_.codec()) { | 142 switch (pipeline_metadata_.video_decoder_config.codec()) { |
| 125 case VideoCodec::kCodecH264: | 143 case VideoCodec::kCodecH264: |
| 126 case VideoCodec::kCodecVP8: | 144 case VideoCodec::kCodecVP8: |
| 127 return true; | 145 return true; |
| 128 default: | 146 default: |
| 129 VLOG(2) << "Remoting does not support video codec: " | 147 VLOG(2) << "Remoting does not support video codec: " |
| 130 << video_decoder_config_.codec(); | 148 << pipeline_metadata_.video_decoder_config.codec(); |
| 131 return false; | 149 return false; |
| 132 } | 150 } |
| 133 } | 151 } |
| 134 | 152 |
| 135 bool RemotingRendererController::IsAudioCodecSupported() { | 153 bool RemotingRendererController::IsAudioCodecSupported() { |
| 136 DCHECK(thread_checker_.CalledOnValidThread()); | 154 DCHECK(thread_checker_.CalledOnValidThread()); |
| 137 DCHECK(has_audio()); | 155 DCHECK(has_audio()); |
| 138 | 156 |
| 139 switch (audio_decoder_config_.codec()) { | 157 switch (pipeline_metadata_.audio_decoder_config.codec()) { |
| 140 case AudioCodec::kCodecAAC: | 158 case AudioCodec::kCodecAAC: |
| 141 case AudioCodec::kCodecMP3: | 159 case AudioCodec::kCodecMP3: |
| 142 case AudioCodec::kCodecPCM: | 160 case AudioCodec::kCodecPCM: |
| 143 case AudioCodec::kCodecVorbis: | 161 case AudioCodec::kCodecVorbis: |
| 144 case AudioCodec::kCodecFLAC: | 162 case AudioCodec::kCodecFLAC: |
| 145 case AudioCodec::kCodecAMR_NB: | 163 case AudioCodec::kCodecAMR_NB: |
| 146 case AudioCodec::kCodecAMR_WB: | 164 case AudioCodec::kCodecAMR_WB: |
| 147 case AudioCodec::kCodecPCM_MULAW: | 165 case AudioCodec::kCodecPCM_MULAW: |
| 148 case AudioCodec::kCodecGSM_MS: | 166 case AudioCodec::kCodecGSM_MS: |
| 149 case AudioCodec::kCodecPCM_S16BE: | 167 case AudioCodec::kCodecPCM_S16BE: |
| 150 case AudioCodec::kCodecPCM_S24BE: | 168 case AudioCodec::kCodecPCM_S24BE: |
| 151 case AudioCodec::kCodecOpus: | 169 case AudioCodec::kCodecOpus: |
| 152 case AudioCodec::kCodecEAC3: | 170 case AudioCodec::kCodecEAC3: |
| 153 case AudioCodec::kCodecPCM_ALAW: | 171 case AudioCodec::kCodecPCM_ALAW: |
| 154 case AudioCodec::kCodecALAC: | 172 case AudioCodec::kCodecALAC: |
| 155 case AudioCodec::kCodecAC3: | 173 case AudioCodec::kCodecAC3: |
| 156 return true; | 174 return true; |
| 157 default: | 175 default: |
| 158 VLOG(2) << "Remoting does not support audio codec: " | 176 VLOG(2) << "Remoting does not support audio codec: " |
| 159 << audio_decoder_config_.codec(); | 177 << pipeline_metadata_.audio_decoder_config.codec(); |
| 160 return false; | 178 return false; |
| 161 } | 179 } |
| 162 } | 180 } |
| 163 | 181 |
| 164 bool RemotingRendererController::ShouldBeRemoting() { | 182 bool RemotingRendererController::ShouldBeRemoting() { |
| 165 DCHECK(thread_checker_.CalledOnValidThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
| 166 | 184 |
| 167 if (switch_renderer_cb_.is_null()) | 185 if (switch_renderer_cb_.is_null()) |
| 168 return false; // No way to switch to a RemotingRenderImpl. | 186 return false; // No way to switch to a RemotingRenderImpl. |
| 169 | 187 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 // For encrypted content, it's only valid to switch to remoting renderer, | 254 // For encrypted content, it's only valid to switch to remoting renderer, |
| 237 // and never back to the local renderer. The RemotingCdmController will | 255 // and never back to the local renderer. The RemotingCdmController will |
| 238 // force-stop the session when remoting has ended; so no need to call | 256 // force-stop the session when remoting has ended; so no need to call |
| 239 // StopRemoting() from here. | 257 // StopRemoting() from here. |
| 240 DCHECK(!is_encrypted_); | 258 DCHECK(!is_encrypted_); |
| 241 switch_renderer_cb_.Run(); | 259 switch_renderer_cb_.Run(); |
| 242 remoting_source_->StopRemoting(this); | 260 remoting_source_->StopRemoting(this); |
| 243 } | 261 } |
| 244 } | 262 } |
| 245 | 263 |
| 264 void RemotingRendererController::SetShowInterstitialCallback( | |
| 265 const ShowInterstitialCallback& cb) { | |
| 266 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 267 show_interstitial_cb_ = cb; | |
| 268 UpdateInterstitial(); | |
| 269 } | |
| 270 | |
| 271 void RemotingRendererController::UpdateInterstitial() { | |
| 272 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 273 if (!remote_rendering_started_ || show_interstitial_cb_.is_null() || | |
| 274 pipeline_metadata_.natural_size.IsEmpty()) | |
| 275 return; | |
| 276 | |
| 277 RemotingInterstitialType type = RemotingInterstitialType::BETWEEN_SESSIONS; | |
| 278 switch (remoting_source_->state()) { | |
| 279 case SESSION_STARTED: | |
| 280 type = RemotingInterstitialType::IN_SESSION; | |
| 281 break; | |
| 282 case SESSION_PERMANENTLY_STOPPED: | |
| 283 type = RemotingInterstitialType::ENCRYPTED_MEDIA_FATAL_ERROR; | |
| 284 break; | |
| 285 case SESSION_UNAVAILABLE: | |
| 286 case SESSION_CAN_START: | |
| 287 case SESSION_STARTING: | |
|
miu
2016/12/20 21:21:04
IMHO, we should show the "IN_SESSION" interstitial
xjz
2016/12/20 22:15:37
Why? We only need (and can only) show interstitial
miu
2016/12/20 23:15:49
tl;dr: Don't bake assumptions into your code when
xjz
2016/12/20 23:54:54
Thanks for the explanation. Learned a lot from you
| |
| 288 case SESSION_STOPPING: | |
| 289 return; | |
|
miu
2016/12/20 21:21:04
I think you meant "break" instead of "return" here
xjz
2016/12/20 22:15:37
I mean "return" because we don't need to paint int
miu
2016/12/20 23:15:49
This is another flavor of the prior comment: Don't
xjz
2016/12/20 23:54:54
Done. Thanks for the explanation.
| |
| 290 } | |
| 291 | |
| 292 // TODO(xjz): Download poster image when available. | |
| 293 show_interstitial_cb_.Run(SkBitmap(), pipeline_metadata_.natural_size, type); | |
| 294 } | |
| 295 | |
| 246 } // namespace media | 296 } // namespace media |
| OLD | NEW |