| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chrome/renderer/media/cast_rtp_stream.h" | 5 #include "chrome/renderer/media/cast_rtp_stream.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
| 15 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/macros.h" | 18 #include "base/macros.h" |
| 19 #include "base/memory/ref_counted.h" | 19 #include "base/memory/ref_counted.h" |
| 20 #include "base/memory/weak_ptr.h" | 20 #include "base/memory/weak_ptr.h" |
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 22 #include "base/sys_info.h" | |
| 23 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
| 24 #include "base/timer/timer.h" | 23 #include "base/timer/timer.h" |
| 25 #include "base/trace_event/trace_event.h" | 24 #include "base/trace_event/trace_event.h" |
| 26 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
| 27 #include "chrome/renderer/media/cast_session.h" | 26 #include "chrome/renderer/media/cast_session.h" |
| 28 #include "chrome/renderer/media/cast_udp_transport.h" | 27 #include "chrome/renderer/media/cast_udp_transport.h" |
| 29 #include "content/public/renderer/media_stream_audio_sink.h" | 28 #include "content/public/renderer/media_stream_audio_sink.h" |
| 30 #include "content/public/renderer/media_stream_utils.h" | 29 #include "content/public/renderer/media_stream_utils.h" |
| 31 #include "content/public/renderer/media_stream_video_sink.h" | 30 #include "content/public/renderer/media_stream_video_sink.h" |
| 32 #include "content/public/renderer/render_thread.h" | 31 #include "content/public/renderer/render_thread.h" |
| 33 #include "content/public/renderer/video_encode_accelerator.h" | 32 #include "content/public/renderer/video_encode_accelerator.h" |
| 34 #include "media/base/audio_bus.h" | 33 #include "media/base/audio_bus.h" |
| 35 #include "media/base/audio_converter.h" | 34 #include "media/base/audio_converter.h" |
| 36 #include "media/base/audio_parameters.h" | 35 #include "media/base/audio_parameters.h" |
| 37 #include "media/base/bind_to_current_loop.h" | 36 #include "media/base/bind_to_current_loop.h" |
| 38 #include "media/base/limits.h" | 37 #include "media/base/limits.h" |
| 39 #include "media/base/video_frame.h" | 38 #include "media/base/video_frame.h" |
| 40 #include "media/base/video_util.h" | 39 #include "media/base/video_util.h" |
| 41 #include "media/cast/cast_config.h" | 40 #include "media/cast/cast_config.h" |
| 42 #include "media/cast/cast_sender.h" | 41 #include "media/cast/cast_sender.h" |
| 43 #include "media/cast/net/cast_transport_config.h" | 42 #include "media/cast/net/cast_transport_config.h" |
| 44 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" | 43 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
| 45 #include "ui/gfx/geometry/size.h" | 44 #include "ui/gfx/geometry/size.h" |
| 46 | 45 |
| 47 using media::cast::AudioSenderConfig; | 46 using media::cast::FrameSenderConfig; |
| 48 using media::cast::VideoSenderConfig; | |
| 49 | 47 |
| 50 namespace { | 48 namespace { |
| 51 | 49 |
| 52 const char kCodecNameOpus[] = "OPUS"; | |
| 53 const char kCodecNameVp8[] = "VP8"; | |
| 54 const char kCodecNameH264[] = "H264"; | |
| 55 | |
| 56 // To convert from kilobits per second to bits to per second. | |
| 57 const int kBitrateMultiplier = 1000; | |
| 58 | |
| 59 // The maximum number of milliseconds that should elapse since the last video | 50 // The maximum number of milliseconds that should elapse since the last video |
| 60 // frame was received from the video source, before requesting refresh frames. | 51 // frame was received from the video source, before requesting refresh frames. |
| 61 const int kRefreshIntervalMilliseconds = 250; | 52 const int kRefreshIntervalMilliseconds = 250; |
| 62 | 53 |
| 63 // The maximum number of refresh video frames to request/receive. After this | 54 // The maximum number of refresh video frames to request/receive. After this |
| 64 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made. | 55 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made. |
| 65 const int kMaxConsecutiveRefreshFrames = 60; | 56 const int kMaxConsecutiveRefreshFrames = 60; |
| 66 | 57 |
| 67 CastRtpPayloadParams DefaultOpusPayload() { | 58 FrameSenderConfig DefaultOpusConfig() { |
| 68 CastRtpPayloadParams payload; | 59 FrameSenderConfig config; |
| 69 payload.payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; | 60 config.rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; |
| 70 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 61 config.sender_ssrc = 1; |
| 71 payload.ssrc = 1; | 62 config.receiver_ssrc = 2; |
| 72 payload.feedback_ssrc = 2; | 63 config.rtp_timebase = media::cast::kDefaultAudioSamplingRate; |
| 73 payload.clock_rate = media::cast::kDefaultAudioSamplingRate; | 64 config.channels = 2; |
| 74 // The value is 0 which means VBR. | 65 // The value is 0 which means VBR. |
| 75 payload.min_bitrate = payload.max_bitrate = | 66 config.min_bitrate = config.max_bitrate = config.start_bitrate = |
| 76 media::cast::kDefaultAudioEncoderBitrate; | 67 media::cast::kDefaultAudioEncoderBitrate; |
| 77 payload.channels = 2; | 68 config.max_frame_rate = 100; // 10 ms audio frames |
| 78 payload.max_frame_rate = 100; // 10 ms audio frames | 69 config.codec = media::cast::CODEC_AUDIO_OPUS; |
| 79 payload.codec_name = kCodecNameOpus; | 70 return config; |
| 80 return payload; | |
| 81 } | 71 } |
| 82 | 72 |
| 83 CastRtpPayloadParams DefaultVp8Payload() { | 73 FrameSenderConfig DefaultVp8Config() { |
| 84 CastRtpPayloadParams payload; | 74 FrameSenderConfig config; |
| 85 payload.payload_type = media::cast::RtpPayloadType::VIDEO_VP8; | 75 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; |
| 86 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 76 config.sender_ssrc = 11; |
| 87 payload.ssrc = 11; | 77 config.receiver_ssrc = 12; |
| 88 payload.feedback_ssrc = 12; | 78 config.rtp_timebase = media::cast::kVideoFrequency; |
| 89 payload.clock_rate = media::cast::kVideoFrequency; | 79 config.channels = 1; |
| 90 payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 80 config.max_bitrate = media::cast::kDefaultMaxVideoBitrate; |
| 91 payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 81 config.min_bitrate = media::cast::kDefaultMinVideoBitrate; |
| 92 payload.channels = 1; | 82 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; |
| 93 payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 83 config.codec = media::cast::CODEC_VIDEO_VP8; |
| 94 payload.codec_name = kCodecNameVp8; | 84 return config; |
| 95 return payload; | |
| 96 } | 85 } |
| 97 | 86 |
| 98 CastRtpPayloadParams DefaultH264Payload() { | 87 FrameSenderConfig DefaultH264Config() { |
| 99 CastRtpPayloadParams payload; | 88 FrameSenderConfig config; |
| 100 payload.payload_type = media::cast::RtpPayloadType::VIDEO_H264; | 89 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; |
| 101 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 90 config.sender_ssrc = 11; |
| 102 payload.ssrc = 11; | 91 config.receiver_ssrc = 12; |
| 103 payload.feedback_ssrc = 12; | 92 config.rtp_timebase = media::cast::kVideoFrequency; |
| 104 payload.clock_rate = media::cast::kVideoFrequency; | 93 config.channels = 1; |
| 105 payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 94 config.max_bitrate = media::cast::kDefaultMaxVideoBitrate; |
| 106 payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 95 config.min_bitrate = media::cast::kDefaultMinVideoBitrate; |
| 107 payload.channels = 1; | 96 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; |
| 108 payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 97 config.codec = media::cast::CODEC_VIDEO_H264; |
| 109 payload.codec_name = kCodecNameH264; | 98 return config; |
| 110 return payload; | |
| 111 } | 99 } |
| 112 | 100 |
| 113 bool IsHardwareVP8EncodingSupported() { | 101 std::vector<FrameSenderConfig> SupportedAudioConfigs() { |
| 114 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 102 // TODO(hclam): Fill in more codecs here. |
| 115 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 103 return std::vector<FrameSenderConfig>(1, DefaultOpusConfig()); |
| 116 DVLOG(1) << "Disabled hardware VP8 support for Cast Streaming."; | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 // Query for hardware VP8 encoder support. | |
| 121 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | |
| 122 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | |
| 123 for (const auto& vea_profile : vea_profiles) { | |
| 124 if (vea_profile.profile >= media::VP8PROFILE_MIN && | |
| 125 vea_profile.profile <= media::VP8PROFILE_MAX) { | |
| 126 return true; | |
| 127 } | |
| 128 } | |
| 129 return false; | |
| 130 } | 104 } |
| 131 | 105 |
| 132 bool IsHardwareH264EncodingSupported() { | 106 std::vector<FrameSenderConfig> SupportedVideoConfigs() { |
| 133 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 107 std::vector<FrameSenderConfig> supported_configs; |
| 134 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | |
| 135 DVLOG(1) << "Disabled hardware h264 support for Cast Streaming."; | |
| 136 return false; | |
| 137 } | |
| 138 | |
| 139 // Query for hardware H.264 encoder support. | |
| 140 // | |
| 141 // TODO(miu): Look into why H.264 hardware encoder on MacOS is broken. | |
| 142 // http://crbug.com/596674 | |
| 143 #if !defined(OS_MACOSX) | |
| 144 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | |
| 145 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | |
| 146 for (const auto& vea_profile : vea_profiles) { | |
| 147 if (vea_profile.profile >= media::H264PROFILE_MIN && | |
| 148 vea_profile.profile <= media::H264PROFILE_MAX) { | |
| 149 return true; | |
| 150 } | |
| 151 } | |
| 152 #endif // !defined(OS_MACOSX) | |
| 153 return false; | |
| 154 } | |
| 155 | |
| 156 int NumberOfEncodeThreads() { | |
| 157 // Do not saturate CPU utilization just for encoding. On a lower-end system | |
| 158 // with only 1 or 2 cores, use only one thread for encoding. On systems with | |
| 159 // more cores, allow half of the cores to be used for encoding. | |
| 160 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); | |
| 161 } | |
| 162 | |
| 163 std::vector<CastRtpParams> SupportedAudioParams() { | |
| 164 // TODO(hclam): Fill in more codecs here. | |
| 165 return std::vector<CastRtpParams>(1, CastRtpParams(DefaultOpusPayload())); | |
| 166 } | |
| 167 | |
| 168 std::vector<CastRtpParams> SupportedVideoParams() { | |
| 169 std::vector<CastRtpParams> supported_params; | |
| 170 | 108 |
| 171 // Prefer VP8 over H.264 for hardware encoder. | 109 // Prefer VP8 over H.264 for hardware encoder. |
| 172 if (IsHardwareVP8EncodingSupported()) | 110 if (CastRtpStream::IsHardwareVP8EncodingSupported()) |
| 173 supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 111 supported_configs.push_back(DefaultVp8Config()); |
| 174 if (IsHardwareH264EncodingSupported()) | 112 if (CastRtpStream::IsHardwareH264EncodingSupported()) |
| 175 supported_params.push_back(CastRtpParams(DefaultH264Payload())); | 113 supported_configs.push_back(DefaultH264Config()); |
| 176 | 114 |
| 177 // Propose the default software VP8 encoder, if no hardware encoders are | 115 // Propose the default software VP8 encoder, if no hardware encoders are |
| 178 // available. | 116 // available. |
| 179 if (supported_params.empty()) | 117 if (supported_configs.empty()) |
| 180 supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 118 supported_configs.push_back(DefaultVp8Config()); |
| 181 | 119 |
| 182 return supported_params; | 120 return supported_configs; |
| 183 } | |
| 184 | |
| 185 bool ToAudioSenderConfig(const CastRtpParams& params, | |
| 186 AudioSenderConfig* config) { | |
| 187 config->ssrc = params.payload.ssrc; | |
| 188 config->receiver_ssrc = params.payload.feedback_ssrc; | |
| 189 if (config->ssrc == config->receiver_ssrc) { | |
| 190 DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc"; | |
| 191 return false; | |
| 192 } | |
| 193 config->min_playout_delay = base::TimeDelta::FromMilliseconds( | |
| 194 params.payload.min_latency_ms ? | |
| 195 params.payload.min_latency_ms : | |
| 196 params.payload.max_latency_ms); | |
| 197 config->max_playout_delay = | |
| 198 base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms); | |
| 199 config->animated_playout_delay = base::TimeDelta::FromMilliseconds( | |
| 200 params.payload.animated_latency_ms ? params.payload.animated_latency_ms | |
| 201 : params.payload.max_latency_ms); | |
| 202 if (config->min_playout_delay <= base::TimeDelta()) { | |
| 203 DVLOG(1) << "min_playout_delay " << config->min_playout_delay | |
| 204 << " is too small"; | |
| 205 return false; | |
| 206 } | |
| 207 if (config->min_playout_delay > config->max_playout_delay) { | |
| 208 DVLOG(1) << "min_playout_delay " << config->min_playout_delay | |
| 209 << " is too big"; | |
| 210 return false; | |
| 211 } | |
| 212 if (config->animated_playout_delay < config->min_playout_delay || | |
| 213 config->animated_playout_delay > config->max_playout_delay) { | |
| 214 DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay | |
| 215 << " is out of range"; | |
| 216 return false; | |
| 217 } | |
| 218 config->rtp_payload_type = params.payload.payload_type; | |
| 219 config->use_external_encoder = false; | |
| 220 config->frequency = params.payload.clock_rate; | |
| 221 // Sampling rate must be one of the Opus-supported values. | |
| 222 switch (config->frequency) { | |
| 223 case 48000: | |
| 224 case 24000: | |
| 225 case 16000: | |
| 226 case 12000: | |
| 227 case 8000: | |
| 228 break; | |
| 229 default: | |
| 230 DVLOG(1) << "frequency " << config->frequency << " is invalid"; | |
| 231 return false; | |
| 232 } | |
| 233 config->channels = params.payload.channels; | |
| 234 if (config->channels < 1) { | |
| 235 DVLOG(1) << "channels " << config->channels << " is invalid"; | |
| 236 return false; | |
| 237 } | |
| 238 config->bitrate = params.payload.max_bitrate * kBitrateMultiplier; | |
| 239 if (params.payload.codec_name == kCodecNameOpus) { | |
| 240 config->codec = media::cast::CODEC_AUDIO_OPUS; | |
| 241 } else { | |
| 242 DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid"; | |
| 243 return false; | |
| 244 } | |
| 245 config->aes_key = params.payload.aes_key; | |
| 246 config->aes_iv_mask = params.payload.aes_iv_mask; | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 bool ToVideoSenderConfig(const CastRtpParams& params, | |
| 251 VideoSenderConfig* config) { | |
| 252 config->ssrc = params.payload.ssrc; | |
| 253 config->receiver_ssrc = params.payload.feedback_ssrc; | |
| 254 if (config->ssrc == config->receiver_ssrc) { | |
| 255 DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc"; | |
| 256 return false; | |
| 257 } | |
| 258 config->min_playout_delay = base::TimeDelta::FromMilliseconds( | |
| 259 params.payload.min_latency_ms ? | |
| 260 params.payload.min_latency_ms : | |
| 261 params.payload.max_latency_ms); | |
| 262 config->max_playout_delay = | |
| 263 base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms); | |
| 264 config->animated_playout_delay = base::TimeDelta::FromMilliseconds( | |
| 265 params.payload.animated_latency_ms ? params.payload.animated_latency_ms | |
| 266 : params.payload.max_latency_ms); | |
| 267 if (config->min_playout_delay <= base::TimeDelta()) { | |
| 268 DVLOG(1) << "min_playout_delay " << config->min_playout_delay | |
| 269 << " is too small"; | |
| 270 return false; | |
| 271 } | |
| 272 if (config->min_playout_delay > config->max_playout_delay) { | |
| 273 DVLOG(1) << "min_playout_delay " << config->min_playout_delay | |
| 274 << " is too big"; | |
| 275 return false; | |
| 276 } | |
| 277 if (config->animated_playout_delay < config->min_playout_delay || | |
| 278 config->animated_playout_delay > config->max_playout_delay) { | |
| 279 DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay | |
| 280 << " is out of range"; | |
| 281 return false; | |
| 282 } | |
| 283 config->rtp_payload_type = params.payload.payload_type; | |
| 284 config->min_bitrate = config->start_bitrate = | |
| 285 params.payload.min_bitrate * kBitrateMultiplier; | |
| 286 config->max_bitrate = params.payload.max_bitrate * kBitrateMultiplier; | |
| 287 if (config->min_bitrate > config->max_bitrate) { | |
| 288 DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than " | |
| 289 << "max_bitrate " << config->max_bitrate; | |
| 290 return false; | |
| 291 } | |
| 292 config->start_bitrate = config->min_bitrate; | |
| 293 config->max_frame_rate = static_cast<int>( | |
| 294 std::max(1.0, params.payload.max_frame_rate) + 0.5); | |
| 295 if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) { | |
| 296 DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid"; | |
| 297 return false; | |
| 298 } | |
| 299 if (params.payload.codec_name == kCodecNameVp8) { | |
| 300 config->use_external_encoder = IsHardwareVP8EncodingSupported(); | |
| 301 config->codec = media::cast::CODEC_VIDEO_VP8; | |
| 302 } else if (params.payload.codec_name == kCodecNameH264) { | |
| 303 config->use_external_encoder = IsHardwareH264EncodingSupported(); | |
| 304 config->codec = media::cast::CODEC_VIDEO_H264; | |
| 305 } else { | |
| 306 DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid"; | |
| 307 return false; | |
| 308 } | |
| 309 if (!config->use_external_encoder) | |
| 310 config->number_of_encode_threads = NumberOfEncodeThreads(); | |
| 311 config->aes_key = params.payload.aes_key; | |
| 312 config->aes_iv_mask = params.payload.aes_iv_mask; | |
| 313 return true; | |
| 314 } | 121 } |
| 315 | 122 |
| 316 } // namespace | 123 } // namespace |
| 317 | 124 |
| 318 // This class receives MediaStreamTrack events and video frames from a | 125 // This class receives MediaStreamTrack events and video frames from a |
| 319 // MediaStreamVideoTrack. It also includes a timer to request refresh frames | 126 // MediaStreamVideoTrack. It also includes a timer to request refresh frames |
| 320 // when the capturer halts (e.g., a screen capturer stops delivering frames | 127 // when the capturer halts (e.g., a screen capturer stops delivering frames |
| 321 // because the screen is not being updated). When a halt is detected, refresh | 128 // because the screen is not being updated). When a halt is detected, refresh |
| 322 // frames will be requested at regular intervals for a short period of time. | 129 // frames will be requested at regular intervals for a short period of time. |
| 323 // This provides the video encoder, downstream, several copies of the last frame | 130 // This provides the video encoder, downstream, several copies of the last frame |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 // These members are accessed on the real-time audio time only. | 395 // These members are accessed on the real-time audio time only. |
| 589 media::AudioParameters input_params_; | 396 media::AudioParameters input_params_; |
| 590 std::unique_ptr<media::AudioConverter> converter_; | 397 std::unique_ptr<media::AudioConverter> converter_; |
| 591 const media::AudioBus* current_input_bus_; | 398 const media::AudioBus* current_input_bus_; |
| 592 int64_t sample_frames_in_; | 399 int64_t sample_frames_in_; |
| 593 int64_t sample_frames_out_; | 400 int64_t sample_frames_out_; |
| 594 | 401 |
| 595 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 402 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); |
| 596 }; | 403 }; |
| 597 | 404 |
| 598 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 405 bool CastRtpStream::IsHardwareVP8EncodingSupported() { |
| 599 : payload(payload_params) {} | 406 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 407 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { |
| 408 DVLOG(1) << "Disabled hardware VP8 support for Cast Streaming."; |
| 409 return false; |
| 410 } |
| 600 | 411 |
| 601 CastCodecSpecificParams::CastCodecSpecificParams() {} | 412 // Query for hardware VP8 encoder support. |
| 413 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
| 414 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); |
| 415 for (const auto& vea_profile : vea_profiles) { |
| 416 if (vea_profile.profile >= media::VP8PROFILE_MIN && |
| 417 vea_profile.profile <= media::VP8PROFILE_MAX) { |
| 418 return true; |
| 419 } |
| 420 } |
| 421 return false; |
| 422 } |
| 602 | 423 |
| 603 CastCodecSpecificParams::~CastCodecSpecificParams() {} | 424 bool CastRtpStream::IsHardwareH264EncodingSupported() { |
| 425 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 426 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { |
| 427 DVLOG(1) << "Disabled hardware h264 support for Cast Streaming."; |
| 428 return false; |
| 429 } |
| 604 | 430 |
| 605 CastRtpPayloadParams::CastRtpPayloadParams() | 431 // Query for hardware H.264 encoder support. |
| 606 : payload_type(media::cast::RtpPayloadType::UNKNOWN), | 432 // |
| 607 max_latency_ms(0), | 433 // TODO(miu): Look into why H.264 hardware encoder on MacOS is broken. |
| 608 min_latency_ms(0), | 434 // http://crbug.com/596674 |
| 609 ssrc(0), | 435 #if !defined(OS_MACOSX) |
| 610 feedback_ssrc(0), | 436 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
| 611 clock_rate(0), | 437 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); |
| 612 max_bitrate(0), | 438 for (const auto& vea_profile : vea_profiles) { |
| 613 min_bitrate(0), | 439 if (vea_profile.profile >= media::H264PROFILE_MIN && |
| 614 channels(0), | 440 vea_profile.profile <= media::H264PROFILE_MAX) { |
| 615 max_frame_rate(0.0) {} | 441 return true; |
| 616 | 442 } |
| 617 CastRtpPayloadParams::CastRtpPayloadParams(const CastRtpPayloadParams& other) = | 443 } |
| 618 default; | 444 #endif // !defined(OS_MACOSX) |
| 619 | 445 return false; |
| 620 CastRtpPayloadParams::~CastRtpPayloadParams() {} | 446 } |
| 621 | |
| 622 CastRtpParams::CastRtpParams() {} | |
| 623 | |
| 624 CastRtpParams::CastRtpParams(const CastRtpParams& other) = default; | |
| 625 | |
| 626 CastRtpParams::~CastRtpParams() {} | |
| 627 | 447 |
| 628 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, | 448 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, |
| 629 const scoped_refptr<CastSession>& session) | 449 const scoped_refptr<CastSession>& session) |
| 630 : track_(track), cast_session_(session), weak_factory_(this) {} | 450 : track_(track), cast_session_(session), weak_factory_(this) {} |
| 631 | 451 |
| 632 CastRtpStream::~CastRtpStream() { | 452 CastRtpStream::~CastRtpStream() { |
| 633 Stop(); | 453 Stop(); |
| 634 } | 454 } |
| 635 | 455 |
| 636 std::vector<CastRtpParams> CastRtpStream::GetSupportedParams() { | 456 std::vector<FrameSenderConfig> CastRtpStream::GetSupportedConfigs() { |
| 637 if (IsAudio()) | 457 if (IsAudio()) |
| 638 return SupportedAudioParams(); | 458 return SupportedAudioConfigs(); |
| 639 else | 459 else |
| 640 return SupportedVideoParams(); | 460 return SupportedVideoConfigs(); |
| 641 } | 461 } |
| 642 | 462 |
| 643 CastRtpParams CastRtpStream::GetParams() { return params_; } | 463 void CastRtpStream::Start(const FrameSenderConfig& config, |
| 644 | |
| 645 void CastRtpStream::Start(const CastRtpParams& params, | |
| 646 const base::Closure& start_callback, | 464 const base::Closure& start_callback, |
| 647 const base::Closure& stop_callback, | 465 const base::Closure& stop_callback, |
| 648 const ErrorCallback& error_callback) { | 466 const ErrorCallback& error_callback) { |
| 649 DCHECK(!start_callback.is_null()); | 467 DCHECK(!start_callback.is_null()); |
| 650 DCHECK(!stop_callback.is_null()); | 468 DCHECK(!stop_callback.is_null()); |
| 651 DCHECK(!error_callback.is_null()); | 469 DCHECK(!error_callback.is_null()); |
| 652 | 470 |
| 653 DVLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video"); | 471 DVLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video"); |
| 654 stop_callback_ = stop_callback; | 472 stop_callback_ = stop_callback; |
| 655 error_callback_ = error_callback; | 473 error_callback_ = error_callback; |
| 656 | 474 |
| 657 if (IsAudio()) { | 475 if (IsAudio()) { |
| 658 AudioSenderConfig config; | |
| 659 if (!ToAudioSenderConfig(params, &config)) { | |
| 660 DidEncounterError("Invalid parameters for audio."); | |
| 661 return; | |
| 662 } | |
| 663 | |
| 664 // In case of error we have to go through DidEncounterError() to stop | 476 // In case of error we have to go through DidEncounterError() to stop |
| 665 // the streaming after reporting the error. | 477 // the streaming after reporting the error. |
| 666 audio_sink_.reset(new CastAudioSink( | 478 audio_sink_.reset( |
| 667 track_, | 479 new CastAudioSink(track_, config.channels, config.rtp_timebase)); |
| 668 params.payload.channels, | |
| 669 params.payload.clock_rate)); | |
| 670 cast_session_->StartAudio( | 480 cast_session_->StartAudio( |
| 671 config, | 481 config, |
| 672 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), | 482 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), |
| 673 base::Bind(&CastRtpStream::DidEncounterError, | 483 base::Bind(&CastRtpStream::DidEncounterError, |
| 674 weak_factory_.GetWeakPtr())); | 484 weak_factory_.GetWeakPtr())); |
| 675 start_callback.Run(); | 485 start_callback.Run(); |
| 676 } else { | 486 } else { |
| 677 VideoSenderConfig config; | |
| 678 if (!ToVideoSenderConfig(params, &config)) { | |
| 679 DidEncounterError("Invalid parameters for video."); | |
| 680 return; | |
| 681 } | |
| 682 // See the code for audio above for explanation of callbacks. | 487 // See the code for audio above for explanation of callbacks. |
| 683 video_sink_.reset(new CastVideoSink( | 488 video_sink_.reset(new CastVideoSink( |
| 684 track_, | 489 track_, |
| 685 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 490 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
| 686 weak_factory_.GetWeakPtr())))); | 491 weak_factory_.GetWeakPtr())))); |
| 687 cast_session_->StartVideo( | 492 cast_session_->StartVideo( |
| 688 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), | 493 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), |
| 689 !params.payload.aes_key.empty()), | 494 !config.aes_key.empty()), |
| 690 base::Bind(&CastRtpStream::DidEncounterError, | 495 base::Bind(&CastRtpStream::DidEncounterError, |
| 691 weak_factory_.GetWeakPtr())); | 496 weak_factory_.GetWeakPtr())); |
| 692 start_callback.Run(); | 497 start_callback.Run(); |
| 693 } | 498 } |
| 694 } | 499 } |
| 695 | 500 |
| 696 void CastRtpStream::Stop() { | 501 void CastRtpStream::Stop() { |
| 697 DVLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video"); | 502 DVLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video"); |
| 698 if (stop_callback_.is_null()) | 503 if (stop_callback_.is_null()) |
| 699 return; // Already stopped. | 504 return; // Already stopped. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 DCHECK(content::RenderThread::Get()); | 539 DCHECK(content::RenderThread::Get()); |
| 735 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " | 540 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " |
| 736 << (IsAudio() ? "audio" : "video"); | 541 << (IsAudio() ? "audio" : "video"); |
| 737 // Save the WeakPtr first because the error callback might delete this object. | 542 // Save the WeakPtr first because the error callback might delete this object. |
| 738 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); | 543 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); |
| 739 error_callback_.Run(message); | 544 error_callback_.Run(message); |
| 740 base::ThreadTaskRunnerHandle::Get()->PostTask( | 545 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 741 FROM_HERE, | 546 FROM_HERE, |
| 742 base::Bind(&CastRtpStream::Stop, ptr)); | 547 base::Bind(&CastRtpStream::Stop, ptr)); |
| 743 } | 548 } |
| OLD | NEW |