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 |