1/* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "modules/mediasource/WebKitMediaSource.h" 33 34#include "bindings/v8/ExceptionState.h" 35#include "bindings/v8/ExceptionStatePlaceholder.h" 36#include "core/dom/ExceptionCode.h" 37#include "core/html/TimeRanges.h" 38#include "core/platform/ContentType.h" 39#include "core/platform/MIMETypeRegistry.h" 40#include "core/platform/graphics/SourceBufferPrivate.h" 41#include "modules/mediasource/MediaSourceRegistry.h" 42#include "wtf/Uint8Array.h" 43 44namespace WebCore { 45 46PassRefPtr<WebKitMediaSource> WebKitMediaSource::create(ScriptExecutionContext* context) 47{ 48 RefPtr<WebKitMediaSource> mediaSource(adoptRef(new WebKitMediaSource(context))); 49 mediaSource->suspendIfNeeded(); 50 return mediaSource.release(); 51} 52 53WebKitMediaSource::WebKitMediaSource(ScriptExecutionContext* context) 54 : MediaSourceBase(context) 55{ 56 ScriptWrappable::init(this); 57 m_sourceBuffers = WebKitSourceBufferList::create(scriptExecutionContext(), asyncEventQueue()); 58 m_activeSourceBuffers = WebKitSourceBufferList::create(scriptExecutionContext(), asyncEventQueue()); 59} 60 61WebKitSourceBufferList* WebKitMediaSource::sourceBuffers() 62{ 63 return m_sourceBuffers.get(); 64} 65 66WebKitSourceBufferList* WebKitMediaSource::activeSourceBuffers() 67{ 68 // FIXME(91649): support track selection 69 return m_activeSourceBuffers.get(); 70} 71 72WebKitSourceBuffer* WebKitMediaSource::addSourceBuffer(const String& type, ExceptionState& es) 73{ 74 // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-addsourcebuffer 75 // 1. If type is null or an empty then throw an InvalidAccessError exception and 76 // abort these steps. 77 if (type.isNull() || type.isEmpty()) { 78 es.throwDOMException(InvalidAccessError); 79 return 0; 80 } 81 82 // 2. If type contains a MIME type that is not supported ..., then throw a 83 // NotSupportedError exception and abort these steps. 84 if (!isTypeSupported(type)) { 85 es.throwDOMException(NotSupportedError); 86 return 0; 87 } 88 89 // 4. If the readyState attribute is not in the "open" state then throw an 90 // InvalidStateError exception and abort these steps. 91 if (!isOpen()) { 92 es.throwDOMException(InvalidStateError); 93 return 0; 94 } 95 96 // 5. Create a new SourceBuffer object and associated resources. 97 ContentType contentType(type); 98 Vector<String> codecs = contentType.codecs(); 99 OwnPtr<SourceBufferPrivate> sourceBufferPrivate = createSourceBufferPrivate(contentType.type(), codecs, es); 100 if (!sourceBufferPrivate) 101 return 0; 102 103 RefPtr<WebKitSourceBuffer> buffer = WebKitSourceBuffer::create(sourceBufferPrivate.release(), this); 104 // 6. Add the new object to sourceBuffers and fire a addsourcebuffer on that object. 105 m_sourceBuffers->add(buffer); 106 m_activeSourceBuffers->add(buffer); 107 // 7. Return the new object to the caller. 108 return buffer.get(); 109} 110 111void WebKitMediaSource::removeSourceBuffer(WebKitSourceBuffer* buffer, ExceptionState& es) 112{ 113 // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-removesourcebuffer 114 // 1. If sourceBuffer is null then throw an InvalidAccessError exception and 115 // abort these steps. 116 if (!buffer) { 117 es.throwDOMException(InvalidAccessError); 118 return; 119 } 120 121 // 2. If sourceBuffers is empty then throw an InvalidStateError exception and 122 // abort these steps. 123 if (isClosed() || !m_sourceBuffers->length()) { 124 es.throwDOMException(InvalidStateError); 125 return; 126 } 127 128 // 3. If sourceBuffer specifies an object that is not in sourceBuffers then 129 // throw a NotFoundError exception and abort these steps. 130 // 6. Remove sourceBuffer from sourceBuffers and fire a removesourcebuffer event 131 // on that object. 132 if (!m_sourceBuffers->remove(buffer)) { 133 es.throwDOMException(NotFoundError); 134 return; 135 } 136 137 // 7. Destroy all resources for sourceBuffer. 138 m_activeSourceBuffers->remove(buffer); 139 140 // 4. Remove track information from audioTracks, videoTracks, and textTracks for all tracks 141 // associated with sourceBuffer and fire a simple event named change on the modified lists. 142 // FIXME(91649): support track selection 143 144 // 5. If sourceBuffer is in activeSourceBuffers, then remove it from that list and fire a 145 // removesourcebuffer event on that object. 146 // FIXME(91649): support track selection 147} 148 149void WebKitMediaSource::onReadyStateChange(const AtomicString& oldState, const AtomicString& newState) 150{ 151 if (isClosed()) { 152 m_sourceBuffers->clear(); 153 m_activeSourceBuffers->clear(); 154 scheduleEvent(eventNames().webkitsourcecloseEvent); 155 return; 156 } 157 158 if (oldState == openKeyword() && newState == endedKeyword()) { 159 scheduleEvent(eventNames().webkitsourceendedEvent); 160 return; 161 } 162 163 if (isOpen()) { 164 scheduleEvent(eventNames().webkitsourceopenEvent); 165 return; 166 } 167} 168 169Vector<RefPtr<TimeRanges> > WebKitMediaSource::activeRanges() const 170{ 171 Vector<RefPtr<TimeRanges> > activeRanges(m_activeSourceBuffers->length()); 172 for (size_t i = 0; i < m_activeSourceBuffers->length(); ++i) 173 activeRanges[i] = m_activeSourceBuffers->item(i)->buffered(ASSERT_NO_EXCEPTION); 174 175 return activeRanges; 176} 177 178bool WebKitMediaSource::isTypeSupported(const String& type) 179{ 180 // Section 2.1 isTypeSupported() method steps. 181 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-MediaSource-isTypeSupported-boolean-DOMString-type 182 // 1. If type is an empty string, then return false. 183 if (type.isNull() || type.isEmpty()) 184 return false; 185 186 ContentType contentType(type); 187 String codecs = contentType.parameter("codecs"); 188 189 // 2. If type does not contain a valid MIME type string, then return false. 190 if (contentType.type().isEmpty() || codecs.isEmpty()) 191 return false; 192 193 // 3. If type contains a media type or media subtype that the MediaSource does not support, then return false. 194 // 4. If type contains at a codec that the MediaSource does not support, then return false. 195 // 5. If the MediaSource does not support the specified combination of media type, media subtype, and codecs then return false. 196 // 6. Return true. 197 return MIMETypeRegistry::isSupportedMediaSourceMIMEType(contentType.type(), codecs); 198} 199 200const AtomicString& WebKitMediaSource::interfaceName() const 201{ 202 return eventNames().interfaceForWebKitMediaSource; 203} 204 205} // namespace WebCore 206