Chromium Code Reviews| 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::kDefaultRtpAudioPayloadType; | 60 config.rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; |
| 70 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 61 config.max_playout_delay = |
| 71 payload.ssrc = 1; | 62 base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); |
| 72 payload.feedback_ssrc = 2; | 63 config.sender_ssrc = 1; |
| 73 payload.clock_rate = media::cast::kDefaultAudioSamplingRate; | 64 config.receiver_ssrc = 2; |
| 65 config.frequency = media::cast::kDefaultAudioSamplingRate; | |
| 74 // The value is 0 which means VBR. | 66 // The value is 0 which means VBR. |
| 75 payload.min_bitrate = payload.max_bitrate = | 67 config.min_bitrate = config.max_bitrate = |
|
miu
2016/06/30 21:59:43
and start_bitrate (per comment in cast_config.h)
xjz
2016/07/01 23:52:09
Done.
| |
| 76 media::cast::kDefaultAudioEncoderBitrate; | 68 media::cast::kDefaultAudioEncoderBitrate; |
| 77 payload.channels = 2; | 69 config.channels = 2; |
| 78 payload.max_frame_rate = 100; // 10 ms audio frames | 70 config.max_frame_rate = 100; // 10 ms audio frames |
| 79 payload.codec_name = kCodecNameOpus; | 71 config.codec = media::cast::CODEC_AUDIO_OPUS; |
| 80 return payload; | 72 return config; |
| 81 } | 73 } |
| 82 | 74 |
| 83 CastRtpPayloadParams DefaultVp8Payload() { | 75 FrameSenderConfig DefaultVp8Config() { |
| 84 CastRtpPayloadParams payload; | 76 FrameSenderConfig config; |
| 85 payload.payload_type = media::cast::kDefaultRtpVideoPayloadType; | 77 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; |
| 86 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 78 config.max_playout_delay = |
|
miu
2016/06/30 21:59:42
You could omit this, since we set this default in
xjz
2016/07/01 23:52:09
Done.
| |
| 87 payload.ssrc = 11; | 79 base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); |
| 88 payload.feedback_ssrc = 12; | 80 config.sender_ssrc = 11; |
| 89 payload.clock_rate = media::cast::kVideoFrequency; | 81 config.receiver_ssrc = 12; |
| 90 payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 82 config.frequency = media::cast::kVideoFrequency; |
| 91 payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 83 config.max_bitrate = media::cast::kDefaultMaxVideoKbps; |
| 92 payload.channels = 1; | 84 config.min_bitrate = media::cast::kDefaultMinVideoKbps; |
| 93 payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 85 config.channels = 1; |
|
miu
2016/06/30 21:59:43
nit: Can you move this to be just before max_bitra
xjz
2016/07/01 23:52:09
Done.
| |
| 94 payload.codec_name = kCodecNameVp8; | 86 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; |
| 95 return payload; | 87 config.codec = media::cast::CODEC_VIDEO_VP8; |
| 88 return config; | |
| 96 } | 89 } |
| 97 | 90 |
| 98 CastRtpPayloadParams DefaultH264Payload() { | 91 FrameSenderConfig DefaultH264Config() { |
| 99 CastRtpPayloadParams payload; | 92 FrameSenderConfig config; |
| 100 payload.payload_type = 96; | 93 config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; |
| 101 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 94 config.max_playout_delay = |
| 102 payload.ssrc = 11; | 95 base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); |
| 103 payload.feedback_ssrc = 12; | 96 config.sender_ssrc = 11; |
| 104 payload.clock_rate = media::cast::kVideoFrequency; | 97 config.receiver_ssrc = 12; |
| 105 payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 98 config.frequency = media::cast::kVideoFrequency; |
| 106 payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 99 config.max_bitrate = media::cast::kDefaultMaxVideoKbps; |
| 107 payload.channels = 1; | 100 config.min_bitrate = media::cast::kDefaultMinVideoKbps; |
| 108 payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 101 config.channels = 1; |
| 109 payload.codec_name = kCodecNameH264; | 102 config.max_frame_rate = media::cast::kDefaultMaxFrameRate; |
| 110 return payload; | 103 config.codec = media::cast::CODEC_VIDEO_H264; |
| 104 return config; | |
| 111 } | 105 } |
| 112 | 106 |
| 113 bool IsHardwareVP8EncodingSupported() { | 107 std::vector<FrameSenderConfig> SupportedAudioConfigs() { |
| 114 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 108 // TODO(hclam): Fill in more codecs here. |
| 115 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 109 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 } | 110 } |
| 131 | 111 |
| 132 bool IsHardwareH264EncodingSupported() { | 112 std::vector<FrameSenderConfig> SupportedVideoConfigs() { |
| 133 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 113 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 | 114 |
| 171 // Prefer VP8 over H.264 for hardware encoder. | 115 // Prefer VP8 over H.264 for hardware encoder. |
| 172 if (IsHardwareVP8EncodingSupported()) | 116 if (CastRtpStream::IsHardwareVP8EncodingSupported()) |
| 173 supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 117 supported_configs.push_back(DefaultVp8Config()); |
| 174 if (IsHardwareH264EncodingSupported()) | 118 if (CastRtpStream::IsHardwareH264EncodingSupported()) |
| 175 supported_params.push_back(CastRtpParams(DefaultH264Payload())); | 119 supported_configs.push_back(DefaultH264Config()); |
| 176 | 120 |
| 177 // Propose the default software VP8 encoder, if no hardware encoders are | 121 // Propose the default software VP8 encoder, if no hardware encoders are |
| 178 // available. | 122 // available. |
| 179 if (supported_params.empty()) | 123 if (supported_configs.empty()) |
| 180 supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 124 supported_configs.push_back(DefaultVp8Config()); |
| 181 | 125 |
| 182 return supported_params; | 126 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 } | 127 } |
| 315 | 128 |
| 316 } // namespace | 129 } // namespace |
| 317 | 130 |
| 318 // This class receives MediaStreamTrack events and video frames from a | 131 // This class receives MediaStreamTrack events and video frames from a |
| 319 // MediaStreamVideoTrack. It also includes a timer to request refresh frames | 132 // MediaStreamVideoTrack. It also includes a timer to request refresh frames |
| 320 // when the capturer halts (e.g., a screen capturer stops delivering frames | 133 // 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 | 134 // 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. | 135 // 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 | 136 // 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. | 401 // These members are accessed on the real-time audio time only. |
| 589 media::AudioParameters input_params_; | 402 media::AudioParameters input_params_; |
| 590 std::unique_ptr<media::AudioConverter> converter_; | 403 std::unique_ptr<media::AudioConverter> converter_; |
| 591 const media::AudioBus* current_input_bus_; | 404 const media::AudioBus* current_input_bus_; |
| 592 int64_t sample_frames_in_; | 405 int64_t sample_frames_in_; |
| 593 int64_t sample_frames_out_; | 406 int64_t sample_frames_out_; |
| 594 | 407 |
| 595 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 408 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); |
| 596 }; | 409 }; |
| 597 | 410 |
| 598 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 411 bool CastRtpStream::IsHardwareVP8EncodingSupported() { |
| 599 : payload(payload_params) {} | 412 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 413 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | |
| 414 DVLOG(1) << "Disabled hardware VP8 support for Cast Streaming."; | |
| 415 return false; | |
| 416 } | |
| 600 | 417 |
| 601 CastCodecSpecificParams::CastCodecSpecificParams() {} | 418 // Query for hardware VP8 encoder support. |
| 602 | 419 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
| 603 CastCodecSpecificParams::~CastCodecSpecificParams() {} | 420 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); |
| 604 | 421 for (const auto& vea_profile : vea_profiles) { |
| 605 CastRtpPayloadParams::CastRtpPayloadParams() | 422 if (vea_profile.profile >= media::VP8PROFILE_MIN && |
| 606 : payload_type(0), | 423 vea_profile.profile <= media::VP8PROFILE_MAX) { |
| 607 max_latency_ms(0), | 424 return true; |
| 608 min_latency_ms(0), | 425 } |
| 609 ssrc(0), | 426 } |
| 610 feedback_ssrc(0), | 427 return false; |
| 611 clock_rate(0), | |
| 612 max_bitrate(0), | |
| 613 min_bitrate(0), | |
| 614 channels(0), | |
| 615 max_frame_rate(0.0) { | |
| 616 } | 428 } |
| 617 | 429 |
| 618 CastRtpPayloadParams::CastRtpPayloadParams(const CastRtpPayloadParams& other) = | 430 bool CastRtpStream::IsHardwareH264EncodingSupported() { |
| 619 default; | 431 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 432 if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | |
| 433 DVLOG(1) << "Disabled hardware h264 support for Cast Streaming."; | |
| 434 return false; | |
| 435 } | |
| 620 | 436 |
| 621 CastRtpPayloadParams::~CastRtpPayloadParams() {} | 437 // Query for hardware H.264 encoder support. |
| 622 | 438 // |
| 623 CastRtpParams::CastRtpParams() {} | 439 // TODO(miu): Look into why H.264 hardware encoder on MacOS is broken. |
| 624 | 440 // http://crbug.com/596674 |
| 625 CastRtpParams::CastRtpParams(const CastRtpParams& other) = default; | 441 #if !defined(OS_MACOSX) |
| 626 | 442 const std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
| 627 CastRtpParams::~CastRtpParams() {} | 443 vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); |
| 444 for (const auto& vea_profile : vea_profiles) { | |
| 445 if (vea_profile.profile >= media::H264PROFILE_MIN && | |
| 446 vea_profile.profile <= media::H264PROFILE_MAX) { | |
| 447 return true; | |
| 448 } | |
| 449 } | |
| 450 #endif // !defined(OS_MACOSX) | |
| 451 return false; | |
| 452 } | |
| 628 | 453 |
| 629 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, | 454 CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, |
| 630 const scoped_refptr<CastSession>& session) | 455 const scoped_refptr<CastSession>& session) |
| 631 : track_(track), cast_session_(session), weak_factory_(this) {} | 456 : track_(track), cast_session_(session), weak_factory_(this) {} |
| 632 | 457 |
| 633 CastRtpStream::~CastRtpStream() { | 458 CastRtpStream::~CastRtpStream() { |
| 634 Stop(); | 459 Stop(); |
| 635 } | 460 } |
| 636 | 461 |
| 637 std::vector<CastRtpParams> CastRtpStream::GetSupportedParams() { | 462 std::vector<FrameSenderConfig> CastRtpStream::GetSupportedConfigs() { |
| 638 if (IsAudio()) | 463 if (IsAudio()) |
| 639 return SupportedAudioParams(); | 464 return SupportedAudioConfigs(); |
| 640 else | 465 else |
| 641 return SupportedVideoParams(); | 466 return SupportedVideoConfigs(); |
| 642 } | 467 } |
| 643 | 468 |
| 644 CastRtpParams CastRtpStream::GetParams() { return params_; } | 469 void CastRtpStream::Start(const FrameSenderConfig& config, |
| 645 | |
| 646 void CastRtpStream::Start(const CastRtpParams& params, | |
| 647 const base::Closure& start_callback, | 470 const base::Closure& start_callback, |
| 648 const base::Closure& stop_callback, | 471 const base::Closure& stop_callback, |
| 649 const ErrorCallback& error_callback) { | 472 const ErrorCallback& error_callback) { |
| 650 DCHECK(!start_callback.is_null()); | 473 DCHECK(!start_callback.is_null()); |
| 651 DCHECK(!stop_callback.is_null()); | 474 DCHECK(!stop_callback.is_null()); |
| 652 DCHECK(!error_callback.is_null()); | 475 DCHECK(!error_callback.is_null()); |
| 653 | 476 |
| 654 DVLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video"); | 477 DVLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video"); |
| 655 stop_callback_ = stop_callback; | 478 stop_callback_ = stop_callback; |
| 656 error_callback_ = error_callback; | 479 error_callback_ = error_callback; |
| 657 | 480 |
| 658 if (IsAudio()) { | 481 if (IsAudio()) { |
| 659 AudioSenderConfig config; | |
| 660 if (!ToAudioSenderConfig(params, &config)) { | |
| 661 DidEncounterError("Invalid parameters for audio."); | |
| 662 return; | |
| 663 } | |
| 664 | |
| 665 // In case of error we have to go through DidEncounterError() to stop | 482 // In case of error we have to go through DidEncounterError() to stop |
| 666 // the streaming after reporting the error. | 483 // the streaming after reporting the error. |
| 667 audio_sink_.reset(new CastAudioSink( | 484 audio_sink_.reset( |
| 668 track_, | 485 new CastAudioSink(track_, config.channels, config.frequency)); |
| 669 params.payload.channels, | |
| 670 params.payload.clock_rate)); | |
| 671 cast_session_->StartAudio( | 486 cast_session_->StartAudio( |
| 672 config, | 487 config, |
| 673 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), | 488 base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), |
| 674 base::Bind(&CastRtpStream::DidEncounterError, | 489 base::Bind(&CastRtpStream::DidEncounterError, |
| 675 weak_factory_.GetWeakPtr())); | 490 weak_factory_.GetWeakPtr())); |
| 676 start_callback.Run(); | 491 start_callback.Run(); |
| 677 } else { | 492 } else { |
| 678 VideoSenderConfig config; | |
| 679 if (!ToVideoSenderConfig(params, &config)) { | |
| 680 DidEncounterError("Invalid parameters for video."); | |
| 681 return; | |
| 682 } | |
| 683 // See the code for audio above for explanation of callbacks. | 493 // See the code for audio above for explanation of callbacks. |
| 684 video_sink_.reset(new CastVideoSink( | 494 video_sink_.reset(new CastVideoSink( |
| 685 track_, | 495 track_, |
| 686 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 496 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
| 687 weak_factory_.GetWeakPtr())))); | 497 weak_factory_.GetWeakPtr())))); |
| 688 cast_session_->StartVideo( | 498 cast_session_->StartVideo( |
| 689 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), | 499 config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), |
| 690 !params.payload.aes_key.empty()), | 500 !config.aes_key.empty()), |
| 691 base::Bind(&CastRtpStream::DidEncounterError, | 501 base::Bind(&CastRtpStream::DidEncounterError, |
| 692 weak_factory_.GetWeakPtr())); | 502 weak_factory_.GetWeakPtr())); |
| 693 start_callback.Run(); | 503 start_callback.Run(); |
| 694 } | 504 } |
| 695 } | 505 } |
| 696 | 506 |
| 697 void CastRtpStream::Stop() { | 507 void CastRtpStream::Stop() { |
| 698 DVLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video"); | 508 DVLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video"); |
| 699 if (stop_callback_.is_null()) | 509 if (stop_callback_.is_null()) |
| 700 return; // Already stopped. | 510 return; // Already stopped. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 735 DCHECK(content::RenderThread::Get()); | 545 DCHECK(content::RenderThread::Get()); |
| 736 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " | 546 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " |
| 737 << (IsAudio() ? "audio" : "video"); | 547 << (IsAudio() ? "audio" : "video"); |
| 738 // Save the WeakPtr first because the error callback might delete this object. | 548 // Save the WeakPtr first because the error callback might delete this object. |
| 739 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); | 549 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); |
| 740 error_callback_.Run(message); | 550 error_callback_.Run(message); |
| 741 base::ThreadTaskRunnerHandle::Get()->PostTask( | 551 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 742 FROM_HERE, | 552 FROM_HERE, |
| 743 base::Bind(&CastRtpStream::Stop, ptr)); | 553 base::Bind(&CastRtpStream::Stop, ptr)); |
| 744 } | 554 } |
| OLD | NEW |