Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / mediasource / SourceBuffer.cpp
index 04eb7d5..2211b11 100644 (file)
@@ -72,11 +72,11 @@ static bool throwExceptionIfRemovedOrUpdating(bool isRemoved, bool isUpdating, E
 
 } // namespace
 
-PassRefPtrWillBeRawPtr<SourceBuffer> SourceBuffer::create(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSource* source, GenericEventQueue* asyncEventQueue)
+SourceBuffer* SourceBuffer::create(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSource* source, GenericEventQueue* asyncEventQueue)
 {
-    RefPtrWillBeRawPtr<SourceBuffer> sourceBuffer(adoptRefWillBeRefCountedGarbageCollected(new SourceBuffer(webSourceBuffer, source, asyncEventQueue)));
+    SourceBuffer* sourceBuffer(adoptRefCountedGarbageCollected(new SourceBuffer(webSourceBuffer, source, asyncEventQueue)));
     sourceBuffer->suspendIfNeeded();
-    return sourceBuffer.release();
+    return sourceBuffer;
 }
 
 SourceBuffer::SourceBuffer(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSource* source, GenericEventQueue* asyncEventQueue)
@@ -89,6 +89,7 @@ SourceBuffer::SourceBuffer(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSou
     , m_timestampOffset(0)
     , m_appendWindowStart(0)
     , m_appendWindowEnd(std::numeric_limits<double>::infinity())
+    , m_pendingAppendDataOffset(0)
     , m_appendBufferAsyncPartRunner(this, &SourceBuffer::appendBufferAsyncPart)
     , m_pendingRemoveStart(-1)
     , m_pendingRemoveEnd(-1)
@@ -125,23 +126,19 @@ void SourceBuffer::setMode(const AtomicString& newMode, ExceptionState& exceptio
 {
     // Section 3.1 On setting mode attribute steps.
     // 1. Let new mode equal the new value being assigned to this attribute.
-    // 2. If new mode does not equal "segments" or "sequence", then throw an INVALID_ACCESS_ERR exception and abort
-    //    these steps.
-    //    Step 2 is unnecessary: IDL enforcement prevents this case and should just return immediately to script
-    //    without calling this method in this case.
-    // 3. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw
+    // 2. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw
     //    an INVALID_STATE_ERR exception and abort these steps.
-    // 4. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
+    // 3. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
     if (throwExceptionIfRemovedOrUpdating(isRemoved(), m_updating, exceptionState))
         return;
 
-    // 5. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
-    // 5.1 Set the readyState attribute of the parent media source to "open"
-    // 5.2 Queue a task to fire a simple event named sourceopen at the parent media source.
+    // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
+    // 4.1 Set the readyState attribute of the parent media source to "open"
+    // 4.2 Queue a task to fire a simple event named sourceopen at the parent media source.
     m_source->openIfInEndedState();
 
-    // 6. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
-    // 7. If the new mode equals "sequence", then set the group start timestamp to the highest presentation end timestamp.
+    // 5. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
+    // 6. If the new mode equals "sequence", then set the group start timestamp to the highest presentation end timestamp.
     WebSourceBuffer::AppendMode appendMode = WebSourceBuffer::AppendModeSegments;
     if (newMode == sequenceKeyword())
         appendMode = WebSourceBuffer::AppendModeSequence;
@@ -150,7 +147,7 @@ void SourceBuffer::setMode(const AtomicString& newMode, ExceptionState& exceptio
         return;
     }
 
-    // 8. Update the attribute to new mode.
+    // 7. Update the attribute to new mode.
     m_mode = newMode;
 }
 
@@ -175,13 +172,8 @@ double SourceBuffer::timestampOffset() const
 
 void SourceBuffer::setTimestampOffset(double offset, ExceptionState& exceptionState)
 {
-    // Enforce throwing an exception on restricted double values.
-    if (!std::isfinite(offset)) {
-        exceptionState.throwTypeError(ExceptionMessages::notAFiniteNumber(offset));
-        return;
-    }
-
     // Section 3.1 timestampOffset attribute setter steps.
+    // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-SourceBuffer-timestampOffset
     // 1. Let new timestamp offset equal the new value being assigned to this attribute.
     // 2. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw an
     //    InvalidStateError exception and abort these steps.
@@ -212,13 +204,8 @@ double SourceBuffer::appendWindowStart() const
 
 void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionState)
 {
-    // Enforce throwing an exception on restricted double values.
-    if (!std::isfinite(start)) {
-        exceptionState.throwTypeError(ExceptionMessages::notAFiniteNumber(start));
-        return;
-    }
-
     // Section 3.1 appendWindowStart attribute setter steps.
+    // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-SourceBuffer-appendWindowStart
     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
     //    InvalidStateError exception and abort these steps.
     // 2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
@@ -246,6 +233,7 @@ double SourceBuffer::appendWindowEnd() const
 void SourceBuffer::setAppendWindowEnd(double end, ExceptionState& exceptionState)
 {
     // Section 3.1 appendWindowEnd attribute setter steps.
+    // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-SourceBuffer-appendWindowEnd
     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
     //    InvalidStateError exception and abort these steps.
     // 2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
@@ -253,12 +241,12 @@ void SourceBuffer::setAppendWindowEnd(double end, ExceptionState& exceptionState
         return;
 
     // 3. If the new value equals NaN, then throw an InvalidAccessError and abort these steps.
-    // 4. If the new value is less than or equal to appendWindowStart then throw an InvalidAccessError
-    //    exception and abort these steps.
     if (std::isnan(end)) {
         exceptionState.throwDOMException(InvalidAccessError, ExceptionMessages::notAFiniteNumber(end));
         return;
     }
+    // 4. If the new value is less than or equal to appendWindowStart then throw an InvalidAccessError
+    //    exception and abort these steps.
     if (end <= m_appendWindowStart) {
         // FIXME: Use ExceptionState::indexExceedsMinimumBound() once it lands.
         exceptionState.throwDOMException(InvalidAccessError, "The value provided ('" + String::number(end) + "') is less than or equal to the minimum value (" + String::number(m_appendWindowStart) + ").");
@@ -275,12 +263,6 @@ void SourceBuffer::appendBuffer(PassRefPtr<ArrayBuffer> data, ExceptionState& ex
 {
     // Section 3.2 appendBuffer()
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
-    // 1. If data is null then throw an InvalidAccessError exception and abort these steps.
-    if (!data) {
-        exceptionState.throwDOMException(InvalidAccessError, "The ArrayBuffer provided is invalid.");
-        return;
-    }
-
     appendBufferInternal(static_cast<const unsigned char*>(data->data()), data->byteLength(), exceptionState);
 }
 
@@ -288,12 +270,6 @@ void SourceBuffer::appendBuffer(PassRefPtr<ArrayBufferView> data, ExceptionState
 {
     // Section 3.2 appendBuffer()
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
-    // 1. If data is null then throw an InvalidAccessError exception and abort these steps.
-    if (!data) {
-        exceptionState.throwDOMException(InvalidAccessError, "The ArrayBuffer provided is invalid.");
-        return;
-    }
-
     appendBufferInternal(static_cast<const unsigned char*>(data->baseAddress()), data->byteLength(), exceptionState);
 }
 
@@ -403,6 +379,7 @@ void SourceBuffer::abortIfUpdating()
     // 3.1. Abort the buffer append and stream append loop algorithms if they are running.
     m_appendBufferAsyncPartRunner.stop();
     m_pendingAppendData.clear();
+    m_pendingAppendDataOffset = 0;
 
     m_removeAsyncPartRunner.stop();
     m_pendingRemoveStart = -1;
@@ -481,7 +458,7 @@ void SourceBuffer::scheduleEvent(const AtomicString& eventName)
 {
     ASSERT(m_asyncEventQueue);
 
-    RefPtr<Event> event = Event::create(eventName);
+    RefPtrWillBeRawPtr<Event> event = Event::create(eventName);
     event->setTarget(this);
 
     m_asyncEventQueue->enqueueEvent(event.release());
@@ -492,57 +469,83 @@ void SourceBuffer::appendBufferInternal(const unsigned char* data, unsigned size
     // Section 3.2 appendBuffer()
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
 
-    // Step 1 is enforced by the caller.
-    // 2. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps.
-    // 3. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
+    // 1. Run the prepare append algorithm.
+    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-prepare-append
+    //  1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps.
+    //  2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
     if (throwExceptionIfRemovedOrUpdating(isRemoved(), m_updating, exceptionState))
         return;
 
-    TRACE_EVENT_ASYNC_BEGIN0("media", "SourceBuffer::appendBuffer", this);
+    TRACE_EVENT_ASYNC_BEGIN1("media", "SourceBuffer::appendBuffer", this, "size", size);
 
-    // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: ...
+    //  3. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: ...
     m_source->openIfInEndedState();
 
-    // Steps 5-6
+    //  Steps 4-5 - end "prepare append" algorithm.
 
-    // 7. Add data to the end of the input buffer.
-    m_pendingAppendData.append(data, size);
+    // 2. Add data to the end of the input buffer.
+    ASSERT(data || size == 0);
+    if (data)
+        m_pendingAppendData.append(data, size);
+    m_pendingAppendDataOffset = 0;
 
-    // 8. Set the updating attribute to true.
+    // 3. Set the updating attribute to true.
     m_updating = true;
 
-    // 9. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
+    // 4. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
     scheduleEvent(EventTypeNames::updatestart);
 
-    // 10. Asynchronously run the buffer append algorithm.
+    // 5. Asynchronously run the buffer append algorithm.
     m_appendBufferAsyncPartRunner.runAsync();
 
-    TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "waiting");
+    TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "initialDelay");
 }
 
 void SourceBuffer::appendBufferAsyncPart()
 {
     ASSERT(m_updating);
 
-    TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "appending");
-
     // Section 3.5.4 Buffer Append Algorithm
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
 
     // 1. Run the segment parser loop algorithm.
     // Step 2 doesn't apply since we run Step 1 synchronously here.
-    size_t appendSize = m_pendingAppendData.size();
-    if (!appendSize) {
-        // Resize buffer for 0 byte appends so we always have a valid pointer.
-        // We need to convey all appends, even 0 byte ones to |m_webSourceBuffer|
-        // so that it can clear its end of stream state if necessary.
-        m_pendingAppendData.resize(1);
+    ASSERT(m_pendingAppendData.size() >= m_pendingAppendDataOffset);
+    size_t appendSize = m_pendingAppendData.size() - m_pendingAppendDataOffset;
+
+    // Impose an arbitrary max size for a single append() call so that an append
+    // doesn't block the renderer event loop very long. This value was selected
+    // by looking at YouTube SourceBuffer usage across a variety of bitrates.
+    // This value allows relatively large appends while keeping append() call
+    // duration in the  ~5-15ms range.
+    const size_t MaxAppendSize = 128 * 1024;
+    if (appendSize > MaxAppendSize)
+        appendSize = MaxAppendSize;
+
+    TRACE_EVENT_ASYNC_STEP_INTO1("media", "SourceBuffer::appendBuffer", this, "appending", "appendSize", static_cast<unsigned>(appendSize));
+
+    // |zero| is used for 0 byte appends so we always have a valid pointer.
+    // We need to convey all appends, even 0 byte ones to |m_webSourceBuffer|
+    // so that it can clear its end of stream state if necessary.
+    unsigned char zero = 0;
+    unsigned char* appendData = &zero;
+    if (appendSize)
+        appendData = m_pendingAppendData.data() + m_pendingAppendDataOffset;
+
+    m_webSourceBuffer->append(appendData, appendSize, &m_timestampOffset);
+
+    m_pendingAppendDataOffset += appendSize;
+
+    if (m_pendingAppendDataOffset < m_pendingAppendData.size()) {
+        m_appendBufferAsyncPartRunner.runAsync();
+        TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "nextPieceDelay");
+        return;
     }
-    m_webSourceBuffer->append(m_pendingAppendData.data(), appendSize, &m_timestampOffset);
 
     // 3. Set the updating attribute to false.
     m_updating = false;
     m_pendingAppendData.clear();
+    m_pendingAppendDataOffset = 0;
 
     // 4. Queue a task to fire a simple event named update at this SourceBuffer object.
     scheduleEvent(EventTypeNames::update);
@@ -580,13 +583,13 @@ void SourceBuffer::appendStreamInternal(PassRefPtrWillBeRawPtr<Stream> stream, E
 {
     // Section 3.2 appendStream()
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendStream-void-Stream-stream-unsigned-long-long-maxSize
-    // 1. If stream is null then throw an InvalidAccessError exception and abort these steps.
-    if (!stream || stream->isNeutered()) {
-        exceptionState.throwDOMException(InvalidAccessError, stream ? "The stream provided has been neutered." : "The stream provided is invalid.");
+    // (0. If the stream has been neutered, then throw an InvalidAccessError exception and abort these steps.)
+    if (stream->isNeutered()) {
+        exceptionState.throwDOMException(InvalidAccessError, "The stream provided has been neutered.");
         return;
     }
 
-    // 2. Run the prepare append algorithm.
+    // 1. Run the prepare append algorithm.
     //  Section 3.5.4 Prepare Append Algorithm.
     //  https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-prepare-append
     //  1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps.
@@ -601,13 +604,13 @@ void SourceBuffer::appendStreamInternal(PassRefPtrWillBeRawPtr<Stream> stream, E
 
     // Steps 4-5 of the prepare append algorithm are handled by m_webSourceBuffer.
 
-    // 3. Set the updating attribute to true.
+    // 2. Set the updating attribute to true.
     m_updating = true;
 
-    // 4. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
+    // 3. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
     scheduleEvent(EventTypeNames::updatestart);
 
-    // 5. Asynchronously run the stream append loop algorithm with stream and maxSize.
+    // 4. Asynchronously run the stream append loop algorithm with stream and maxSize.
 
     stream->neuter();
     m_loader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadByClient, this));