Chromium Code Reviews| 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|, calculating and clamping if needed. | |
|
Peter Beverloo
2016/01/20 18:35:35
nit: A comment here explaining *why* certain ratio
mcasas
2016/01/20 21:13:22
Commented.
| |
| 47 bool AllocateVideoAndAudioBitrates(ExecutionContext* context, const MediaRecorde rOptions& options, bool useAudio, bool useVideo, int32_t* audioBitsPerSecond, in t32_t* videoBitsPerSecond) | |
| 48 { | |
| 49 // Check that |options| don't overflow an int32_t. | |
| 50 const unsigned long kInt32MaxValueAsULong = std::numeric_limits<int32_t>::ma x(); | |
| 51 if (options.bitsPerSecond() >= kInt32MaxValueAsULong || (options.bitsPerSeco nd() == 0 && (options.videoBitsPerSecond() >= kInt32MaxValueAsULong || options.a udioBitsPerSecond() >= kInt32MaxValueAsULong))) { | |
| 52 const String message = "bitrates too large (audio: " + String::number(op tions.audioBitsPerSecond()) + "bps, video: " + String::number(options.videoBitsP erSecond()) + "bps, overall: " + String::number(options.bitsPerSecond()) + "bps) "; | |
| 53 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, Error MessageLevel, message)); | |
| 54 return false; | |
| 55 } | |
| 56 | |
|
Peter Beverloo
2016/01/20 18:35:35
[Comment applies to lines 49-55.]
I think this is
mcasas
2016/01/20 21:13:22
I'd love to but Gecko had it as ulong beforehand,
Peter Beverloo
2016/01/21 11:04:36
It is unfortunate that we can't rely on the standa
mcasas
2016/01/21 18:42:46
I filed https://github.com/w3c/mediacapture-record
| |
| 57 *videoBitsPerSecond = options.videoBitsPerSecond(); | |
| 58 *audioBitsPerSecond = options.audioBitsPerSecond(); | |
|
Peter Beverloo
2016/01/20 18:35:35
nit: There's a lot of stars in the code. Might be
mcasas
2016/01/20 21:13:22
Done.
| |
| 59 | |
| 60 // |options.bitsPerSecond()| overrides the specific audio and video bit | |
| 61 // rates, and we are free to allocate as desired. | |
| 62 if (useAudio) { | |
| 63 if (options.bitsPerSecond()) { | |
| 64 if (useVideo) | |
| 65 *audioBitsPerSecond = options.bitsPerSecond() / 10; | |
| 66 else | |
| 67 *audioBitsPerSecond = options.bitsPerSecond(); | |
| 68 } | |
| 69 // Limit audio bitrate values if they are too large or too small. | |
| 70 if (*audioBitsPerSecond) { | |
| 71 if (*audioBitsPerSecond > kLargestAutoAllocatedOpusBitRate) { | |
| 72 const String message = "clamping calculated audio bitrate (" + S tring::number(*audioBitsPerSecond) + "bps) to the maximum (" + String::number(kL argestAutoAllocatedOpusBitRate) + "bps)"; | |
|
Peter Beverloo
2016/01/20 18:35:35
nit: s/clamping/Clamping/. These are sentences.
mcasas
2016/01/20 21:13:22
Done.
| |
| 73 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc e, WarningMessageLevel, message)); | |
| 74 *audioBitsPerSecond = kLargestAutoAllocatedOpusBitRate; | |
| 75 } | |
| 76 | |
| 77 if (*audioBitsPerSecond < kSmallestPossibleOpusBitRate) { | |
| 78 const String message = "clamping calculated audio bitrate (" + S tring::number(*audioBitsPerSecond) + "bps) to the minimum (" + String::number(kS mallestPossibleOpusBitRate) + "bps)"; | |
| 79 context->addConsoleMessage(ConsoleMessage::create(JSMessageSourc e, WarningMessageLevel, message)); | |
| 80 *audioBitsPerSecond = kSmallestPossibleOpusBitRate; | |
| 81 } | |
| 82 } | |
| 83 } else { | |
| 84 *audioBitsPerSecond = 0; | |
| 85 } | |
| 86 // If there is video bit rate allocated it should be larger than a minimum. | |
| 87 if (useVideo) { | |
| 88 if (options.bitsPerSecond()) | |
| 89 *videoBitsPerSecond = options.bitsPerSecond() - *audioBitsPerSecond; | |
| 90 // Clamp the video bit rate if there is any configured (explicitly or | |
|
Peter Beverloo
2016/01/20 18:35:35
nit: it's a bit odd to break this comment given th
mcasas
2016/01/20 21:13:22
Yup, sorry, came from Cr side 80-char limit. Done.
| |
| 91 // implicitly via |options.bitsPerSecond()|). | |
| 92 if ((*videoBitsPerSecond || options.bitsPerSecond()) && (*videoBitsPerSe cond < kSmallestPossibleVpxBitRate)) { | |
|
Peter Beverloo
2016/01/20 18:35:35
In which situation is the "(*videoBitsPerSecond ||
mcasas
2016/01/20 21:13:22
It's a peculiar case indeed, as miu@ detailed:
- t
| |
| 93 const String message = "clamping calculated video bitrate (" + Strin g::number(*videoBitsPerSecond) + "bps) to the minimum (" + String::number(kSmall estPossibleVpxBitRate) + "bps)"; | |
| 94 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, W arningMessageLevel, message)); | |
| 95 *videoBitsPerSecond = kSmallestPossibleVpxBitRate; | |
| 96 } | |
| 97 } else { | |
| 98 *videoBitsPerSecond = 0; | |
| 99 } | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 37 } // namespace | 103 } // namespace |
| 38 | 104 |
| 39 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState) | 105 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState) |
| 40 { | 106 { |
| 41 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp tions(), exceptionState); | 107 MediaRecorder* recorder = new MediaRecorder(context, stream, MediaRecorderOp tions(), exceptionState); |
| 42 recorder->suspendIfNeeded(); | 108 recorder->suspendIfNeeded(); |
| 43 | 109 |
| 44 return recorder; | 110 return recorder; |
| 45 } | 111 } |
| 46 | 112 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 60 , m_stopped(true) | 126 , m_stopped(true) |
| 61 , m_ignoreMutedMedia(true) | 127 , m_ignoreMutedMedia(true) |
| 62 , m_state(State::Inactive) | 128 , m_state(State::Inactive) |
| 63 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) | 129 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) |
| 64 { | 130 { |
| 65 ASSERT(m_stream->getTracks().size()); | 131 ASSERT(m_stream->getTracks().size()); |
| 66 | 132 |
| 67 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); | 133 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); |
| 68 ASSERT(m_recorderHandler); | 134 ASSERT(m_recorderHandler); |
| 69 | 135 |
| 70 // We deviate from the spec by not returning |UnsupportedOption|, see https: //github.com/w3c/mediacapture-record/issues/18 | |
| 71 if (!m_recorderHandler) { | 136 if (!m_recorderHandler) { |
| 72 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); | 137 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); |
| 73 return; | 138 return; |
| 74 } | 139 } |
| 75 ContentType contentType(m_mimeType); | 140 |
| 76 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"))) { | 141 const ContentType contentType(m_mimeType); |
| 77 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder, the type provided " + m_mimeType + "is unsupported." ); | 142 const bool useVideo = stream->getVideoTracks().size() > 0; |
| 143 const bool useAudio = stream->getAudioTracks().size() > 0; | |
| 144 int32_t audioBitsPerSecond = 0; | |
| 145 int32_t videoBitsPerSecond = 0; | |
| 146 // If bit rate calculation fails, throw an exception but allow continuing wi th defaults. | |
|
Peter Beverloo
2016/01/20 18:35:35
This could do with a few more blank lines for read
mcasas
2016/01/20 21:13:22
cleaned up.
| |
| 147 if (!AllocateVideoAndAudioBitrates(context, options, useAudio, useVideo, &au dioBitsPerSecond, &videoBitsPerSecond)) { | |
| 148 const String message = "target bitrates too large (audio: " + String::nu mber(options.audioBitsPerSecond()) + "bps, video: " + String::number(options.vid eoBitsPerSecond()) + "bps, overall: " + String::number(options.bitsPerSecond()) + "bps)"; | |
| 149 exceptionState.throwDOMException(NotSupportedError, message); | |
| 150 } | |
| 151 | |
| 152 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"), audioBitsPerSecond, videoBitsPerSecond)) { | |
| 153 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder, the bitrates supplied, or the type provided (" + m_mimeT ype + ") are unsupported."); | |
| 78 return; | 154 return; |
| 79 } | 155 } |
| 80 m_stopped = false; | 156 m_stopped = false; |
| 81 } | 157 } |
| 82 | 158 |
| 83 String MediaRecorder::state() const | 159 String MediaRecorder::state() const |
| 84 { | 160 { |
| 85 return stateToString(m_state); | 161 return stateToString(m_state); |
| 86 } | 162 } |
| 87 | 163 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 DEFINE_TRACE(MediaRecorder) | 344 DEFINE_TRACE(MediaRecorder) |
| 269 { | 345 { |
| 270 visitor->trace(m_stream); | 346 visitor->trace(m_stream); |
| 271 visitor->trace(m_dispatchScheduledEventRunner); | 347 visitor->trace(m_dispatchScheduledEventRunner); |
| 272 visitor->trace(m_scheduledEvents); | 348 visitor->trace(m_scheduledEvents); |
| 273 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); | 349 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); |
| 274 ActiveDOMObject::trace(visitor); | 350 ActiveDOMObject::trace(visitor); |
| 275 } | 351 } |
| 276 | 352 |
| 277 } // namespace blink | 353 } // namespace blink |
| OLD | NEW |