| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/renderer/media_recorder/media_recorder_handler.h" | 5 #include "content/renderer/media_recorder/media_recorder_handler.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/strings/string_tokenizer.h" | 13 #include "base/strings/string_tokenizer.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/sys_info.h" |
| 15 #include "content/child/scoped_web_callbacks.h" | 16 #include "content/child/scoped_web_callbacks.h" |
| 16 #include "content/renderer/media/media_stream_audio_track.h" | 17 #include "content/renderer/media/media_stream_audio_track.h" |
| 17 #include "content/renderer/media/media_stream_track.h" | 18 #include "content/renderer/media/media_stream_track.h" |
| 18 #include "content/renderer/media/webrtc_uma_histograms.h" | 19 #include "content/renderer/media/webrtc_uma_histograms.h" |
| 19 #include "content/renderer/media_recorder/audio_track_recorder.h" | 20 #include "content/renderer/media_recorder/audio_track_recorder.h" |
| 20 #include "media/base/audio_bus.h" | 21 #include "media/base/audio_bus.h" |
| 21 #include "media/base/audio_parameters.h" | 22 #include "media/base/audio_parameters.h" |
| 22 #include "media/base/bind_to_current_loop.h" | 23 #include "media/base/bind_to_current_loop.h" |
| 23 #include "media/base/mime_util.h" | 24 #include "media/base/mime_util.h" |
| 24 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
| 25 #include "media/muxers/webm_muxer.h" | 26 #include "media/muxers/webm_muxer.h" |
| 26 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" | 27 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h" |
| 27 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" | 28 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
| 28 #include "third_party/WebKit/public/platform/WebString.h" | 29 #include "third_party/WebKit/public/platform/WebString.h" |
| 29 #include "third_party/WebKit/public/platform/modules/media_capabilities/WebMedia
Configuration.h" | 30 #include "third_party/WebKit/public/platform/modules/media_capabilities/WebMedia
Configuration.h" |
| 30 | 31 |
| 31 using base::TimeDelta; | 32 using base::TimeDelta; |
| 32 using base::TimeTicks; | 33 using base::TimeTicks; |
| 33 using base::ToLowerASCII; | 34 using base::ToLowerASCII; |
| 34 | 35 |
| 35 namespace content { | 36 namespace content { |
| 36 | 37 |
| 37 using blink::WebMediaCapabilitiesQueryCallbacks; | 38 using blink::WebMediaCapabilitiesQueryCallbacks; |
| 38 | 39 |
| 39 namespace { | 40 namespace { |
| 40 | 41 |
| 42 // Encoding smoothness depends on a number of parameters, namely: frame rate, |
| 43 // resolution, hardware support availability, platform and IsLowEndDevice(); to |
| 44 // simplify calculations we compare the amount of pixels per second (i.e. |
| 45 // resolution times frame rate). Software based encoding on Desktop can run |
| 46 // fine up and until HD resolution at 30fps, whereas if IsLowEndDevice() we set |
| 47 // the cut at VGA at 30fps (~27Mpps and ~9Mpps respectively). |
| 48 // TODO(mcasas): The influence of the frame rate is not exactly linear, so this |
| 49 // threshold might be oversimplified, https://crbug.com/709181. |
| 50 const float kNumPixelsPerSecondSmoothnessThresholdLow = 640 * 480 * 30.0; |
| 51 const float kNumPixelsPerSecondSmoothnessThresholdHigh = 1280 * 720 * 30.0; |
| 52 |
| 41 media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) { | 53 media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) { |
| 42 switch (id) { | 54 switch (id) { |
| 43 case VideoTrackRecorder::CodecId::VP8: | 55 case VideoTrackRecorder::CodecId::VP8: |
| 44 return media::kCodecVP8; | 56 return media::kCodecVP8; |
| 45 case VideoTrackRecorder::CodecId::VP9: | 57 case VideoTrackRecorder::CodecId::VP9: |
| 46 return media::kCodecVP9; | 58 return media::kCodecVP9; |
| 47 #if BUILDFLAG(RTC_USE_H264) | 59 #if BUILDFLAG(RTC_USE_H264) |
| 48 case VideoTrackRecorder::CodecId::H264: | 60 case VideoTrackRecorder::CodecId::H264: |
| 49 return media::kCodecH264; | 61 return media::kCodecH264; |
| 50 #endif | 62 #endif |
| 51 case VideoTrackRecorder::CodecId::LAST: | 63 case VideoTrackRecorder::CodecId::LAST: |
| 52 return media::kUnknownVideoCodec; | 64 return media::kUnknownVideoCodec; |
| 53 } | 65 } |
| 54 NOTREACHED() << "Unsupported codec"; | 66 NOTREACHED() << "Unsupported codec"; |
| 55 return media::kUnknownVideoCodec; | 67 return media::kUnknownVideoCodec; |
| 56 } | 68 } |
| 57 | 69 |
| 70 // Extracts the first recognised CodecId of |codecs| or CodecId::LAST if none |
| 71 // of them is known. |
| 72 VideoTrackRecorder::CodecId StringToCodecId(const blink::WebString& codecs) { |
| 73 const std::string& codecs_str = ToLowerASCII(codecs.Utf8()); |
| 74 |
| 75 if (codecs_str.find("vp8") != std::string::npos) |
| 76 return VideoTrackRecorder::CodecId::VP8; |
| 77 else if (codecs_str.find("vp9") != std::string::npos) |
| 78 return VideoTrackRecorder::CodecId::VP9; |
| 79 #if BUILDFLAG(RTC_USE_H264) |
| 80 else if (codecs_str.find("h264") != std::string::npos || |
| 81 codecs_str.find("avc1") != std::string::npos) |
| 82 return VideoTrackRecorder::CodecId::H264; |
| 83 #endif |
| 84 return VideoTrackRecorder::CodecId::LAST; |
| 85 } |
| 86 |
| 58 void OnEncodingInfoError( | 87 void OnEncodingInfoError( |
| 59 std::unique_ptr<WebMediaCapabilitiesQueryCallbacks> callbacks) { | 88 std::unique_ptr<WebMediaCapabilitiesQueryCallbacks> callbacks) { |
| 60 callbacks->OnError(); | 89 callbacks->OnError(); |
| 61 } | 90 } |
| 62 | 91 |
| 63 } // anonymous namespace | 92 } // anonymous namespace |
| 64 | 93 |
| 65 MediaRecorderHandler::MediaRecorderHandler() | 94 MediaRecorderHandler::MediaRecorderHandler() |
| 66 : video_bits_per_second_(0), | 95 : video_bits_per_second_(0), |
| 67 audio_bits_per_second_(0), | 96 audio_bits_per_second_(0), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 // Save histogram data so we can see how much MediaStream Recorder is used. | 159 // Save histogram data so we can see how much MediaStream Recorder is used. |
| 131 // The histogram counts the number of calls to the JS API. | 160 // The histogram counts the number of calls to the JS API. |
| 132 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER); | 161 UpdateWebRTCMethodCount(WEBKIT_MEDIA_STREAM_RECORDER); |
| 133 | 162 |
| 134 if (!CanSupportMimeType(type, codecs)) { | 163 if (!CanSupportMimeType(type, codecs)) { |
| 135 DLOG(ERROR) << "Unsupported " << type.Utf8() << ";codecs=" << codecs.Utf8(); | 164 DLOG(ERROR) << "Unsupported " << type.Utf8() << ";codecs=" << codecs.Utf8(); |
| 136 return false; | 165 return false; |
| 137 } | 166 } |
| 138 | 167 |
| 139 // Once established that we support the codec(s), hunt then individually. | 168 // Once established that we support the codec(s), hunt then individually. |
| 140 const std::string& codecs_str = ToLowerASCII(codecs.Utf8()); | 169 const VideoTrackRecorder::CodecId codec_id = StringToCodecId(codecs); |
| 141 if (codecs_str.find("vp8") != std::string::npos) | 170 codec_id_ = (codec_id != VideoTrackRecorder::CodecId::LAST) |
| 142 codec_id_ = VideoTrackRecorder::CodecId::VP8; | 171 ? codec_id |
| 143 else if (codecs_str.find("vp9") != std::string::npos) | 172 : VideoTrackRecorder::GetPreferredCodecId(); |
| 144 codec_id_ = VideoTrackRecorder::CodecId::VP9; | |
| 145 #if BUILDFLAG(RTC_USE_H264) | |
| 146 else if (codecs_str.find("h264") != std::string::npos) | |
| 147 codec_id_ = VideoTrackRecorder::CodecId::H264; | |
| 148 else if (codecs_str.find("avc1") != std::string::npos) | |
| 149 codec_id_ = VideoTrackRecorder::CodecId::H264; | |
| 150 #endif | |
| 151 else | |
| 152 codec_id_ = VideoTrackRecorder::GetPreferredCodecId(); | |
| 153 | 173 |
| 154 DVLOG_IF(1, codecs_str.empty()) << "Falling back to preferred codec id " | 174 DVLOG_IF(1, codec_id == VideoTrackRecorder::CodecId::LAST) |
| 155 << static_cast<int>(codec_id_); | 175 << "Falling back to preferred codec id " << static_cast<int>(codec_id_); |
| 156 | 176 |
| 157 media_stream_ = media_stream; | 177 media_stream_ = media_stream; |
| 158 DCHECK(client); | 178 DCHECK(client); |
| 159 client_ = client; | 179 client_ = client; |
| 160 | 180 |
| 161 audio_bits_per_second_ = audio_bits_per_second; | 181 audio_bits_per_second_ = audio_bits_per_second; |
| 162 video_bits_per_second_ = video_bits_per_second; | 182 video_bits_per_second_ = video_bits_per_second; |
| 163 return true; | 183 return true; |
| 164 } | 184 } |
| 165 | 185 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 blink::WebString mime_type; | 315 blink::WebString mime_type; |
| 296 blink::WebString codec; | 316 blink::WebString codec; |
| 297 if (configuration.video_configuration) { | 317 if (configuration.video_configuration) { |
| 298 mime_type = configuration.video_configuration->mime_type; | 318 mime_type = configuration.video_configuration->mime_type; |
| 299 codec = configuration.video_configuration->codec; | 319 codec = configuration.video_configuration->codec; |
| 300 } else { | 320 } else { |
| 301 mime_type = configuration.audio_configuration->mime_type; | 321 mime_type = configuration.audio_configuration->mime_type; |
| 302 codec = configuration.audio_configuration->codec; | 322 codec = configuration.audio_configuration->codec; |
| 303 } | 323 } |
| 304 | 324 |
| 305 // See RFC 2231. https://tools.ietf.org/html/rfc2231 | |
| 306 info->supported = CanSupportMimeType(mime_type, codec); | 325 info->supported = CanSupportMimeType(mime_type, codec); |
| 307 DVLOG(1) << "type: " << mime_type.Ascii() << ", codec:" << codec.Ascii() | 326 |
| 308 << " is" << (info->supported ? " supported" : " NOT supported"); | 327 if (configuration.video_configuration && info->supported) { |
| 328 const bool is_likely_accelerated = |
| 329 VideoTrackRecorder::CanUseAcceleratedEncoder( |
| 330 StringToCodecId(codec), configuration.video_configuration->width, |
| 331 configuration.video_configuration->height); |
| 332 |
| 333 const float pixels_per_second = |
| 334 configuration.video_configuration->width * |
| 335 configuration.video_configuration->height * |
| 336 configuration.video_configuration->framerate; |
| 337 // Encoding is considered |smooth| up and until the pixels per second |
| 338 // threshold or if it's likely to be accelerated. |
| 339 const float threshold = base::SysInfo::IsLowEndDevice() |
| 340 ? kNumPixelsPerSecondSmoothnessThresholdLow |
| 341 : kNumPixelsPerSecondSmoothnessThresholdHigh; |
| 342 info->smooth = is_likely_accelerated || pixels_per_second <= threshold; |
| 343 |
| 344 // TODO(mcasas): revisit what |power_efficient| means |
| 345 // https://crbug.com/709181. |
| 346 info->power_efficient = info->smooth; |
| 347 } |
| 348 DVLOG(1) << "type: " << mime_type.Ascii() << ", params:" << codec.Ascii() |
| 349 << " is" << (info->supported ? " supported" : " NOT supported") |
| 350 << " and" << (info->smooth ? " smooth" : " NOT smooth"); |
| 309 | 351 |
| 310 scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info)); | 352 scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info)); |
| 311 } | 353 } |
| 312 | 354 |
| 313 void MediaRecorderHandler::OnEncodedVideo( | 355 void MediaRecorderHandler::OnEncodedVideo( |
| 314 const media::WebmMuxer::VideoParameters& params, | 356 const media::WebmMuxer::VideoParameters& params, |
| 315 std::unique_ptr<std::string> encoded_data, | 357 std::unique_ptr<std::string> encoded_data, |
| 316 std::unique_ptr<std::string> encoded_alpha, | 358 std::unique_ptr<std::string> encoded_alpha, |
| 317 TimeTicks timestamp, | 359 TimeTicks timestamp, |
| 318 bool is_key_frame) { | 360 bool is_key_frame) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 recorder->OnData(audio_bus, timestamp); | 460 recorder->OnData(audio_bus, timestamp); |
| 419 } | 461 } |
| 420 | 462 |
| 421 void MediaRecorderHandler::SetAudioFormatForTesting( | 463 void MediaRecorderHandler::SetAudioFormatForTesting( |
| 422 const media::AudioParameters& params) { | 464 const media::AudioParameters& params) { |
| 423 for (const auto& recorder : audio_recorders_) | 465 for (const auto& recorder : audio_recorders_) |
| 424 recorder->OnSetFormat(params); | 466 recorder->OnSetFormat(params); |
| 425 } | 467 } |
| 426 | 468 |
| 427 } // namespace content | 469 } // namespace content |
| OLD | NEW |