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 "modules/mediarecorder/MediaRecorder.h" | 5 #include "modules/mediarecorder/MediaRecorder.h" |
6 | 6 |
7 #include "bindings/core/v8/Dictionary.h" | 7 #include "bindings/core/v8/Dictionary.h" |
8 #include "core/events/Event.h" | 8 #include "core/events/Event.h" |
9 #include "core/fileapi/Blob.h" | 9 #include "core/fileapi/Blob.h" |
| 10 #include "core/inspector/ConsoleMessage.h" |
10 #include "modules/EventTargetModules.h" | 11 #include "modules/EventTargetModules.h" |
11 #include "modules/mediarecorder/BlobEvent.h" | 12 #include "modules/mediarecorder/BlobEvent.h" |
12 #include "platform/ContentType.h" | 13 #include "platform/ContentType.h" |
13 #include "platform/NotImplemented.h" | 14 #include "platform/NotImplemented.h" |
14 #include "platform/blob/BlobData.h" | 15 #include "platform/blob/BlobData.h" |
15 #include "public/platform/Platform.h" | 16 #include "public/platform/Platform.h" |
16 #include "public/platform/WebMediaStream.h" | 17 #include "public/platform/WebMediaStream.h" |
17 | 18 |
18 namespace blink { | 19 namespace blink { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
| 23 // Boundaries of Opus bitrate from https://www.opus-codec.org/. |
| 24 const int kSmallestPossibleOpusBitRate = 6000; |
| 25 const int kLargestAutoAllocatedOpusBitRate = 128000; |
| 26 |
| 27 // Smallest Vpx bitrate that can be requested. |
| 28 const int kSmallestPossibleVpxBitRate = 100000; |
| 29 |
22 String stateToString(MediaRecorder::State state) | 30 String stateToString(MediaRecorder::State state) |
23 { | 31 { |
24 switch (state) { | 32 switch (state) { |
25 case MediaRecorder::State::Inactive: | 33 case MediaRecorder::State::Inactive: |
26 return "inactive"; | 34 return "inactive"; |
27 case MediaRecorder::State::Recording: | 35 case MediaRecorder::State::Recording: |
28 return "recording"; | 36 return "recording"; |
29 case MediaRecorder::State::Paused: | 37 case MediaRecorder::State::Paused: |
30 return "paused"; | 38 return "paused"; |
31 } | 39 } |
32 | 40 |
33 ASSERT_NOT_REACHED(); | 41 ASSERT_NOT_REACHED(); |
34 return String(); | 42 return String(); |
35 } | 43 } |
36 | 44 |
| 45 // Allocates the requested bit rates from |bitrateOptions| into the respective |
| 46 // |{audio,video}BitsPerSecond| (where a value of zero indicates Platform to use |
| 47 // whatever it sees fit). If |options.bitsPerSecond()| is specified, it |
| 48 // overrides any specific bitrate, and the UA is free to allocate as desired: |
| 49 // here a 90%/10% video/audio is used. In all cases where a value is explicited |
| 50 // or calculated, values are clamped in sane ranges. |
| 51 // This method throws NotSupportedError. |
| 52 void AllocateVideoAndAudioBitrates(ExceptionState& exceptionState, ExecutionCont
ext* context, const MediaRecorderOptions& options, MediaStream* stream, int32_t*
audioBitsPerSecond, int32_t* videoBitsPerSecond) |
| 53 { |
| 54 // Throw if any value would overflow an int32_t. |
| 55 // TODO(mcasas): This section would no be needed if the bit rates are signed
, see https://github.com/w3c/mediacapture-record/issues/48. |
| 56 const uint32_t kInt32MaxValueAsULong = std::numeric_limits<int32_t>::max(); |
| 57 if (options.bitsPerSecond() >= kInt32MaxValueAsULong) { |
| 58 exceptionState.throwDOMException(NotSupportedError, "Overall bit rate to
o large " + String::number(options.bitsPerSecond()) + "bps)"); |
| 59 return; |
| 60 } |
| 61 if (options.bitsPerSecond() == 0) { |
| 62 if (options.videoBitsPerSecond() >= kInt32MaxValueAsULong) { |
| 63 exceptionState.throwDOMException(NotSupportedError, "Video bit rate
too large " + String::number(options.videoBitsPerSecond()) + "bps)"); |
| 64 return; |
| 65 } |
| 66 if (options.audioBitsPerSecond() >= kInt32MaxValueAsULong) { |
| 67 exceptionState.throwDOMException(NotSupportedError, "Audio bit rate
too large " + String::number(options.audioBitsPerSecond()) + "bps)"); |
| 68 return; |
| 69 } |
| 70 } |
| 71 |
| 72 int32_t videoBps = options.videoBitsPerSecond(); |
| 73 int32_t audioBps = options.audioBitsPerSecond(); |
| 74 bool useVideo = stream->getVideoTracks().size() > 0; |
| 75 bool useAudio = stream->getAudioTracks().size() > 0; |
| 76 |
| 77 if (useAudio) { |
| 78 // |options.bitsPerSecond()| overrides the specific audio and video bit
rates. |
| 79 if (options.bitsPerSecond()) { |
| 80 if (useVideo) |
| 81 audioBps = options.bitsPerSecond() / 10; |
| 82 else |
| 83 audioBps = options.bitsPerSecond(); |
| 84 } |
| 85 // Limit audio bitrate values if set explicitly or calculated. |
| 86 if (audioBps) { |
| 87 if (audioBps > kLargestAutoAllocatedOpusBitRate) { |
| 88 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc
e, WarningMessageLevel, "Clamping calculated audio bitrate (" + String::number(a
udioBps) + "bps) to the maximum (" + String::number(kLargestAutoAllocatedOpusBit
Rate) + "bps)")); |
| 89 audioBps = kLargestAutoAllocatedOpusBitRate; |
| 90 } |
| 91 |
| 92 if (audioBps < kSmallestPossibleOpusBitRate) { |
| 93 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc
e, WarningMessageLevel, "Clamping calculated audio bitrate (" + String::number(a
udioBps) + "bps) to the minimum (" + String::number(kSmallestPossibleOpusBitRate
) + "bps)")); |
| 94 audioBps = kSmallestPossibleOpusBitRate; |
| 95 } |
| 96 } |
| 97 } else { |
| 98 audioBps = 0; |
| 99 } |
| 100 if (useVideo) { |
| 101 // Allocate the remaining overall |options.bitsPerSecond()|, if any, to
video. |
| 102 if (options.bitsPerSecond()) |
| 103 videoBps = options.bitsPerSecond() - audioBps; |
| 104 // Clamp the video bit rate if the user has set explicitly the video bit
rate or has used the overall bitrate. |
| 105 if ((options.videoBitsPerSecond() > 0 || options.bitsPerSecond() > 0) &&
(videoBps < kSmallestPossibleVpxBitRate)) { |
| 106 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, W
arningMessageLevel, "Clamping calculated video bitrate (" + String::number(video
Bps) + "bps) to the minimum (" + String::number(kSmallestPossibleVpxBitRate) + "
bps)")); |
| 107 videoBps = kSmallestPossibleVpxBitRate; |
| 108 } |
| 109 } else { |
| 110 videoBps = 0; |
| 111 } |
| 112 |
| 113 *videoBitsPerSecond = videoBps; |
| 114 *audioBitsPerSecond = audioBps; |
| 115 return; |
| 116 } |
| 117 |
37 } // namespace | 118 } // namespace |
38 | 119 |
39 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str
eam, ExceptionState& exceptionState) | 120 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str
eam, ExceptionState& exceptionState) |
40 { | 121 { |
41 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp
tions(), exceptionState); | 122 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp
tions(), exceptionState); |
42 recorder->suspendIfNeeded(); | 123 recorder->suspendIfNeeded(); |
43 | 124 |
44 return recorder; | 125 return recorder; |
45 } | 126 } |
46 | 127 |
(...skipping 13 matching lines...) Expand all Loading... |
60 , m_stopped(true) | 141 , m_stopped(true) |
61 , m_ignoreMutedMedia(true) | 142 , m_ignoreMutedMedia(true) |
62 , m_state(State::Inactive) | 143 , m_state(State::Inactive) |
63 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th
is, &MediaRecorder::dispatchScheduledEvent)) | 144 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th
is, &MediaRecorder::dispatchScheduledEvent)) |
64 { | 145 { |
65 ASSERT(m_stream->getTracks().size()); | 146 ASSERT(m_stream->getTracks().size()); |
66 | 147 |
67 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler
()); | 148 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler
()); |
68 ASSERT(m_recorderHandler); | 149 ASSERT(m_recorderHandler); |
69 | 150 |
70 // We deviate from the spec by not returning |UnsupportedOption|, see https:
//github.com/w3c/mediacapture-record/issues/18 | |
71 if (!m_recorderHandler) { | 151 if (!m_recorderHandler) { |
72 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha
ndler can be created."); | 152 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha
ndler can be created."); |
73 return; | 153 return; |
74 } | 154 } |
75 ContentType contentType(m_mimeType); | 155 |
76 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t
ype(), contentType.parameter("codecs"))) { | 156 int32_t audioBitsPerSecond = 0; |
77 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ
e native MediaRecorder, the type provided " + m_mimeType + "is unsupported." ); | 157 int32_t videoBitsPerSecond = 0; |
| 158 AllocateVideoAndAudioBitrates(exceptionState, context, options, stream, &aud
ioBitsPerSecond, &videoBitsPerSecond); |
| 159 |
| 160 const ContentType contentType(m_mimeType); |
| 161 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t
ype(), contentType.parameter("codecs"), audioBitsPerSecond, videoBitsPerSecond))
{ |
| 162 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ
e native MediaRecorder the type provided (" + m_mimeType + ") is not supported."
); |
78 return; | 163 return; |
79 } | 164 } |
80 m_stopped = false; | 165 m_stopped = false; |
81 } | 166 } |
82 | 167 |
83 String MediaRecorder::state() const | 168 String MediaRecorder::state() const |
84 { | 169 { |
85 return stateToString(m_state); | 170 return stateToString(m_state); |
86 } | 171 } |
87 | 172 |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 DEFINE_TRACE(MediaRecorder) | 353 DEFINE_TRACE(MediaRecorder) |
269 { | 354 { |
270 visitor->trace(m_stream); | 355 visitor->trace(m_stream); |
271 visitor->trace(m_dispatchScheduledEventRunner); | 356 visitor->trace(m_dispatchScheduledEventRunner); |
272 visitor->trace(m_scheduledEvents); | 357 visitor->trace(m_scheduledEvents); |
273 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi
sitor); | 358 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi
sitor); |
274 ActiveDOMObject::trace(visitor); | 359 ActiveDOMObject::trace(visitor); |
275 } | 360 } |
276 | 361 |
277 } // namespace blink | 362 } // namespace blink |
OLD | NEW |