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. | |
esprehn
2016/01/21 04:00:47
yay comments, thanks :)
mcasas
2016/01/21 18:42:46
Acknowledged.
| |
52 void AllocateVideoAndAudioBitrates(ExceptionState& exceptionState, ExecutionCont ext* context, const MediaRecorderOptions& options, bool useAudio, bool useVideo, int32_t* audioBitsPerSecond, int32_t* videoBitsPerSecond) | |
esprehn
2016/01/21 04:00:47
take the stream for fewer bools. :)
mcasas
2016/01/21 18:42:46
Done.
| |
53 { | |
54 // Throw if any value would overflow an int32_t. | |
55 const unsigned long kInt32MaxValueAsULong = std::numeric_limits<int32_t>::ma x(); | |
miu
2016/01/21 00:51:05
Please use uint32_t instead of unsigned long.
mcasas
2016/01/21 18:42:46
Done.
| |
56 if (options.bitsPerSecond() >= kInt32MaxValueAsULong) { | |
57 exceptionState.throwDOMException(NotSupportedError, "Overall bit rate to o large " + String::number(options.bitsPerSecond()) + "bps)"); | |
58 return; | |
59 } | |
60 if (options.bitsPerSecond() == 0) { | |
61 if (options.videoBitsPerSecond() >= kInt32MaxValueAsULong) { | |
62 exceptionState.throwDOMException(NotSupportedError, "Video bit rate too large " + String::number(options.videoBitsPerSecond()) + "bps)"); | |
63 return; | |
64 } | |
65 if (options.audioBitsPerSecond() >= kInt32MaxValueAsULong) { | |
66 exceptionState.throwDOMException(NotSupportedError, "Audio bit rate too large " + String::number(options.audioBitsPerSecond()) + "bps)"); | |
67 return; | |
68 } | |
69 } | |
70 | |
71 int32_t videoBps = options.videoBitsPerSecond(); | |
72 int32_t audioBps = options.audioBitsPerSecond(); | |
73 if (useAudio) { | |
74 // |options.bitsPerSecond()| overrides the specific audio and video bit rates. | |
75 if (options.bitsPerSecond()) { | |
76 if (useVideo) | |
77 audioBps = options.bitsPerSecond() / 10; | |
78 else | |
79 audioBps = options.bitsPerSecond(); | |
80 } | |
81 // Limit audio bitrate values if set explicitly or calculated. | |
82 if (audioBps) { | |
83 if (audioBps > kLargestAutoAllocatedOpusBitRate) { | |
84 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc e, WarningMessageLevel, "Clamping calculated audio bitrate (" + String::number(a udioBps) + "bps) to the maximum (" + String::number(kLargestAutoAllocatedOpusBit Rate) + "bps)")); | |
85 audioBps = kLargestAutoAllocatedOpusBitRate; | |
86 } | |
87 | |
88 if (audioBps < kSmallestPossibleOpusBitRate) { | |
89 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc e, WarningMessageLevel, "Clamping calculated audio bitrate (" + String::number(a udioBps) + "bps) to the minimum (" + String::number(kSmallestPossibleOpusBitRate ) + "bps)")); | |
90 audioBps = kSmallestPossibleOpusBitRate; | |
91 } | |
92 } | |
93 } else { | |
94 audioBps = 0; | |
95 } | |
96 if (useVideo) { | |
97 // Allocate the remaining overall |options.bitsPerSecond()|, if any, to video. | |
98 if (options.bitsPerSecond()) | |
99 videoBps = options.bitsPerSecond() - audioBps; | |
100 // Clamp the video bit rate if the user has set explicitly the video bit rate or has used the overall bitrate. | |
101 if ((options.videoBitsPerSecond() > 0 || options.bitsPerSecond() > 0) && (videoBps < kSmallestPossibleVpxBitRate)) { | |
102 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, W arningMessageLevel, "Clamping calculated video bitrate (" + String::number(video Bps) + "bps) to the minimum (" + String::number(kSmallestPossibleVpxBitRate) + " bps)")); | |
103 videoBps = kSmallestPossibleVpxBitRate; | |
104 } | |
105 } else { | |
106 videoBps = 0; | |
107 } | |
108 | |
109 *videoBitsPerSecond = videoBps; | |
110 *audioBitsPerSecond = audioBps; | |
111 return; | |
112 } | |
113 | |
37 } // namespace | 114 } // namespace |
38 | 115 |
39 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState) | 116 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState) |
40 { | 117 { |
41 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp tions(), exceptionState); | 118 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp tions(), exceptionState); |
42 recorder->suspendIfNeeded(); | 119 recorder->suspendIfNeeded(); |
43 | 120 |
44 return recorder; | 121 return recorder; |
45 } | 122 } |
46 | 123 |
(...skipping 13 matching lines...) Expand all Loading... | |
60 , m_stopped(true) | 137 , m_stopped(true) |
61 , m_ignoreMutedMedia(true) | 138 , m_ignoreMutedMedia(true) |
62 , m_state(State::Inactive) | 139 , m_state(State::Inactive) |
63 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) | 140 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) |
64 { | 141 { |
65 ASSERT(m_stream->getTracks().size()); | 142 ASSERT(m_stream->getTracks().size()); |
66 | 143 |
67 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); | 144 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); |
68 ASSERT(m_recorderHandler); | 145 ASSERT(m_recorderHandler); |
69 | 146 |
70 // We deviate from the spec by not returning |UnsupportedOption|, see https: //github.com/w3c/mediacapture-record/issues/18 | |
71 if (!m_recorderHandler) { | 147 if (!m_recorderHandler) { |
72 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); | 148 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); |
73 return; | 149 return; |
74 } | 150 } |
75 ContentType contentType(m_mimeType); | 151 |
76 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"))) { | 152 const bool useVideo = stream->getVideoTracks().size() > 0; |
esprehn
2016/01/21 04:00:47
remove these, we also don't usually const local bo
mcasas
2016/01/21 18:42:46
Done.
| |
77 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder, the type provided " + m_mimeType + "is unsupported." ); | 153 const bool useAudio = stream->getAudioTracks().size() > 0; |
154 int32_t audioBitsPerSecond = 0; | |
155 int32_t videoBitsPerSecond = 0; | |
156 | |
157 AllocateVideoAndAudioBitrates(exceptionState, context, options, useAudio, us eVideo, &audioBitsPerSecond, &videoBitsPerSecond); | |
esprehn
2016/01/21 04:00:47
pass the stream into this instead of the two bools
mcasas
2016/01/21 18:42:46
Done.
| |
158 | |
159 const ContentType contentType(m_mimeType); | |
160 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"), audioBitsPerSecond, videoBitsPerSecond)) { | |
161 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder the type provided (" + m_mimeType + ") is not supported." ); | |
78 return; | 162 return; |
79 } | 163 } |
80 m_stopped = false; | 164 m_stopped = false; |
81 } | 165 } |
82 | 166 |
83 String MediaRecorder::state() const | 167 String MediaRecorder::state() const |
84 { | 168 { |
85 return stateToString(m_state); | 169 return stateToString(m_state); |
86 } | 170 } |
87 | 171 |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 DEFINE_TRACE(MediaRecorder) | 352 DEFINE_TRACE(MediaRecorder) |
269 { | 353 { |
270 visitor->trace(m_stream); | 354 visitor->trace(m_stream); |
271 visitor->trace(m_dispatchScheduledEventRunner); | 355 visitor->trace(m_dispatchScheduledEventRunner); |
272 visitor->trace(m_scheduledEvents); | 356 visitor->trace(m_scheduledEvents); |
273 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); | 357 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); |
274 ActiveDOMObject::trace(visitor); | 358 ActiveDOMObject::trace(visitor); |
275 } | 359 } |
276 | 360 |
277 } // namespace blink | 361 } // namespace blink |
OLD | NEW |