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 "core/inspector/ConsoleMessage.h" |
| 11 #include "modules/EventTargetModules.h" | 11 #include "modules/EventTargetModules.h" |
| 12 #include "modules/mediarecorder/BlobEvent.h" | 12 #include "modules/mediarecorder/BlobEvent.h" |
| 13 #include "platform/ContentType.h" | 13 #include "platform/ContentType.h" |
| 14 #include "platform/NotImplemented.h" | 14 #include "platform/NotImplemented.h" |
| 15 #include "platform/blob/BlobData.h" | 15 #include "platform/blob/BlobData.h" |
| 16 #include "public/platform/Platform.h" | 16 #include "public/platform/Platform.h" |
| 17 #include "public/platform/WebMediaStream.h" | 17 #include "public/platform/WebMediaStream.h" |
| 18 #include <algorithm> | |
| 18 | 19 |
| 19 namespace blink { | 20 namespace blink { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Boundaries of Opus bitrate from https://www.opus-codec.org/. | 24 // Boundaries of Opus bitrate from https://www.opus-codec.org/. |
| 24 const int kSmallestPossibleOpusBitRate = 6000; | 25 const int kSmallestPossibleOpusBitRate = 6000; |
| 25 const int kLargestAutoAllocatedOpusBitRate = 128000; | 26 const int kLargestAutoAllocatedOpusBitRate = 128000; |
| 26 | 27 |
| 27 // Smallest Vpx bitrate that can be requested. | 28 // Smallest Vpx bitrate that can be requested. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 42 return String(); | 43 return String(); |
| 43 } | 44 } |
| 44 | 45 |
| 45 // Allocates the requested bit rates from |bitrateOptions| into the respective | 46 // Allocates the requested bit rates from |bitrateOptions| into the respective |
| 46 // |{audio,video}BitsPerSecond| (where a value of zero indicates Platform to use | 47 // |{audio,video}BitsPerSecond| (where a value of zero indicates Platform to use |
| 47 // whatever it sees fit). If |options.bitsPerSecond()| is specified, it | 48 // 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 // 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 // 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 // or calculated, values are clamped in sane ranges. |
| 51 // This method throws NotSupportedError. | 52 // This method throws NotSupportedError. |
| 52 void AllocateVideoAndAudioBitrates(ExceptionState& exceptionState, ExecutionCont ext* context, const MediaRecorderOptions& options, MediaStream* stream, int32_t* audioBitsPerSecond, int32_t* videoBitsPerSecond) | 53 void AllocateVideoAndAudioBitrates(ExceptionState& exceptionState, ExecutionCont ext* context, const MediaRecorderOptions& options, MediaStream* stream, int* aud ioBitsPerSecond, int* videoBitsPerSecond) |
| 53 { | 54 { |
| 54 // Throw if any value would overflow an int32_t. | 55 // Clamp incoming values to a signed integer's maximum. |
| 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 // TODO(mcasas): This section would no be needed if the bit rates are signed , see https://github.com/w3c/mediacapture-record/issues/48. |
|
philipj_slow
2016/02/04 03:03:10
I like https://github.com/w3c/mediacapture-record/
mcasas
2016/02/05 02:39:14
I do! Will follow up with Gecko and hopefully deal
philipj_slow
2016/02/05 07:48:49
Sounds good.
| |
| 56 const uint32_t kInt32MaxValueAsULong = std::numeric_limits<int32_t>::max(); | 57 const unsigned kMaxIntAsUnsigned = std::numeric_limits<int>::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 | 58 |
| 72 int32_t videoBps = options.videoBitsPerSecond(); | 59 ASSERT(options.bitsPerSecond() < kMaxIntAsUnsigned); |
|
philipj_slow
2016/02/04 03:03:10
Actually you can't assert this, a script can hit t
mcasas
2016/02/05 02:39:14
Done.
| |
| 73 int32_t audioBps = options.audioBitsPerSecond(); | 60 const int overallBps = std::min(options.bitsPerSecond(), kMaxIntAsUnsigned); |
| 74 bool useVideo = stream->getVideoTracks().size() > 0; | 61 |
| 75 bool useAudio = stream->getAudioTracks().size() > 0; | 62 ASSERT(overallBps != 0 || options.videoBitsPerSecond() < kMaxIntAsUnsigned); |
|
philipj_slow
2016/02/04 03:03:10
These asserts would have to go too.
mcasas
2016/02/05 02:39:14
Done, I think.
| |
| 63 int videoBps = std::min(options.videoBitsPerSecond(), kMaxIntAsUnsigned); | |
| 64 | |
| 65 ASSERT(overallBps != 0 || options.audioBitsPerSecond() < kMaxIntAsUnsigned); | |
| 66 int audioBps = std::min(options.audioBitsPerSecond(), kMaxIntAsUnsigned); | |
| 67 | |
| 68 const bool useVideo = stream->getVideoTracks().size() > 0; | |
| 69 const bool useAudio = stream->getAudioTracks().size() > 0; | |
| 76 | 70 |
| 77 if (useAudio) { | 71 if (useAudio) { |
| 78 // |options.bitsPerSecond()| overrides the specific audio and video bit rates. | 72 // |overallBps| overrides the specific audio and video bit rates. |
| 79 if (options.bitsPerSecond()) { | 73 if (overallBps) { |
| 80 if (useVideo) | 74 if (useVideo) |
| 81 audioBps = options.bitsPerSecond() / 10; | 75 audioBps = overallBps / 10; |
| 82 else | 76 else |
| 83 audioBps = options.bitsPerSecond(); | 77 audioBps = overallBps; |
| 84 } | 78 } |
| 85 // Limit audio bitrate values if set explicitly or calculated. | 79 // Limit audio bitrate values if set explicitly or calculated. |
| 86 if (audioBps) { | 80 if (audioBps) { |
| 87 if (audioBps > kLargestAutoAllocatedOpusBitRate) { | 81 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)")); | 82 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; | 83 audioBps = kLargestAutoAllocatedOpusBitRate; |
| 90 } | 84 } |
| 91 | 85 |
| 92 if (audioBps < kSmallestPossibleOpusBitRate) { | 86 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)")); | 87 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; | 88 audioBps = kSmallestPossibleOpusBitRate; |
| 95 } | 89 } |
| 96 } | 90 } |
| 97 } else { | 91 } else { |
| 98 audioBps = 0; | 92 audioBps = 0; |
| 99 } | 93 } |
| 100 if (useVideo) { | 94 if (useVideo) { |
| 101 // Allocate the remaining overall |options.bitsPerSecond()|, if any, to video. | 95 // Allocate the remaining overall |overallBps|, if any, to video. |
|
philipj_slow
2016/02/04 03:03:10
Can drop "overall" now.
mcasas
2016/02/05 02:39:14
Done.
| |
| 102 if (options.bitsPerSecond()) | 96 if (overallBps) |
| 103 videoBps = options.bitsPerSecond() - audioBps; | 97 videoBps = overallBps - audioBps; |
| 104 // Clamp the video bit rate if the user has set explicitly the video bit rate or has used the overall bitrate. | 98 // 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)) { | 99 if ((options.videoBitsPerSecond() > 0 || overallBps > 0) && (videoBps < kSmallestPossibleVpxBitRate)) { |
|
philipj_slow
2016/02/04 03:03:10
Look at videoBps here instead? It'd be nice to dea
mcasas
2016/02/05 02:39:14
In this case the idea is to check if the original
philipj_slow
2016/02/05 07:48:49
Oh, I see. If the IDL matched the spec and didn't
mcasas
2016/02/06 00:26:25
Using hasVideoBitsPerSecond().
philipj_slow
2016/02/08 09:39:44
This bit is still using options.videoBitsPerSecond
mcasas
2016/02/08 21:54:40
Darn, something was missing indeed.
What I (think
| |
| 106 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, W arningMessageLevel, "Clamping calculated video bitrate (" + String::number(video Bps) + "bps) to the minimum (" + String::number(kSmallestPossibleVpxBitRate) + " bps)")); | 100 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; | 101 videoBps = kSmallestPossibleVpxBitRate; |
| 108 } | 102 } |
| 109 } else { | 103 } else { |
| 110 videoBps = 0; | 104 videoBps = 0; |
| 111 } | 105 } |
| 112 | 106 |
| 113 *videoBitsPerSecond = videoBps; | 107 *videoBitsPerSecond = videoBps; |
| 114 *audioBitsPerSecond = audioBps; | 108 *audioBitsPerSecond = audioBps; |
| 115 return; | 109 return; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 133 return recorder; | 127 return recorder; |
| 134 } | 128 } |
| 135 | 129 |
| 136 MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, con st MediaRecorderOptions& options, ExceptionState& exceptionState) | 130 MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, con st MediaRecorderOptions& options, ExceptionState& exceptionState) |
| 137 : ActiveDOMObject(context) | 131 : ActiveDOMObject(context) |
| 138 , m_stream(stream) | 132 , m_stream(stream) |
| 139 , m_streamAmountOfTracks(stream->getTracks().size()) | 133 , m_streamAmountOfTracks(stream->getTracks().size()) |
| 140 , m_mimeType(options.mimeType()) | 134 , m_mimeType(options.mimeType()) |
| 141 , m_stopped(true) | 135 , m_stopped(true) |
| 142 , m_ignoreMutedMedia(true) | 136 , m_ignoreMutedMedia(true) |
| 137 , m_audioBitsPerSecond(0) | |
| 138 , m_videoBitsPerSecond(0) | |
| 143 , m_state(State::Inactive) | 139 , m_state(State::Inactive) |
| 144 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) | 140 , m_dispatchScheduledEventRunner(AsyncMethodRunner<MediaRecorder>::create(th is, &MediaRecorder::dispatchScheduledEvent)) |
| 145 { | 141 { |
| 146 ASSERT(m_stream->getTracks().size()); | 142 ASSERT(m_stream->getTracks().size()); |
| 147 | 143 |
| 148 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); | 144 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ()); |
| 149 ASSERT(m_recorderHandler); | 145 ASSERT(m_recorderHandler); |
| 150 | 146 |
| 151 if (!m_recorderHandler) { | 147 if (!m_recorderHandler) { |
| 152 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); | 148 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created."); |
| 153 return; | 149 return; |
| 154 } | 150 } |
| 155 | 151 |
| 156 int32_t audioBitsPerSecond = 0; | 152 AllocateVideoAndAudioBitrates(exceptionState, context, options, stream, &m_a udioBitsPerSecond, &m_videoBitsPerSecond); |
| 157 int32_t videoBitsPerSecond = 0; | |
| 158 AllocateVideoAndAudioBitrates(exceptionState, context, options, stream, &aud ioBitsPerSecond, &videoBitsPerSecond); | |
| 159 | 153 |
| 160 const ContentType contentType(m_mimeType); | 154 const ContentType contentType(m_mimeType); |
| 161 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"), audioBitsPerSecond, videoBitsPerSecond)) { | 155 if (!m_recorderHandler->initialize(this, stream->descriptor(), contentType.t ype(), contentType.parameter("codecs"), m_audioBitsPerSecond, m_videoBitsPerSeco nd)) { |
| 162 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder the type provided (" + m_mimeType + ") is not supported." ); | 156 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder the type provided (" + m_mimeType + ") is not supported." ); |
| 163 return; | 157 return; |
| 164 } | 158 } |
| 165 m_stopped = false; | 159 m_stopped = false; |
| 166 } | 160 } |
| 167 | 161 |
| 168 String MediaRecorder::state() const | 162 String MediaRecorder::state() const |
| 169 { | 163 { |
| 170 return stateToString(m_state); | 164 return stateToString(m_state); |
| 171 } | 165 } |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 353 DEFINE_TRACE(MediaRecorder) | 347 DEFINE_TRACE(MediaRecorder) |
| 354 { | 348 { |
| 355 visitor->trace(m_stream); | 349 visitor->trace(m_stream); |
| 356 visitor->trace(m_dispatchScheduledEventRunner); | 350 visitor->trace(m_dispatchScheduledEventRunner); |
| 357 visitor->trace(m_scheduledEvents); | 351 visitor->trace(m_scheduledEvents); |
| 358 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); | 352 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor); |
| 359 ActiveDOMObject::trace(visitor); | 353 ActiveDOMObject::trace(visitor); |
| 360 } | 354 } |
| 361 | 355 |
| 362 } // namespace blink | 356 } // namespace blink |
| OLD | NEW |