示例#1
0
void MediaSource::setReadyState(const String& state)
{
    ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());
    if (m_readyState == state)
        return;

    String oldState = m_readyState;
    m_readyState = state;

    if (m_readyState == closedKeyword()) {
        m_sourceBuffers->clear();
        m_activeSourceBuffers->clear();
        m_player = 0;
        scheduleEvent(eventNames().webkitsourcecloseEvent);
        return;
    }

    if (oldState == openKeyword() && m_readyState == endedKeyword()) {
        scheduleEvent(eventNames().webkitsourceendedEvent);
        return;
    }

    if (m_readyState == openKeyword()) {
        scheduleEvent(eventNames().webkitsourceopenEvent);
        return;
    }
}
示例#2
0
void MediaSource::endOfStream(const String& error, ExceptionCode& ec)
{
    // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-endofstream
    // 1. If the readyState attribute is not in the "open" state then throw an
    // INVALID_STATE_ERR exception and abort these steps.
    if (!m_player || m_readyState != openKeyword()) {
        ec = INVALID_STATE_ERR;
        return;
    }

    MediaPlayer::EndOfStreamStatus eosStatus = MediaPlayer::EosNoError;

    if (error.isNull() || error.isEmpty())
        eosStatus = MediaPlayer::EosNoError;
    else if (error == "network")
        eosStatus = MediaPlayer::EosNetworkError;
    else if (error == "decode")
        eosStatus = MediaPlayer::EosDecodeError;
    else {
        ec = INVALID_ACCESS_ERR;
        return;
    }

    // 2. Change the readyState attribute value to "ended".
    setReadyState(endedKeyword());
    m_player->sourceEndOfStream(eosStatus);
}
示例#3
0
void MediaSourceBase::endOfStream(const AtomicString& error, ExceptionCode& ec)
{
    DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
    DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));

    // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-endofstream
    // 1. If the readyState attribute is not in the "open" state then throw an
    // INVALID_STATE_ERR exception and abort these steps.
    if (!isOpen()) {
        ec = INVALID_STATE_ERR;
        return;
    }

    MediaSourcePrivate::EndOfStreamStatus eosStatus = MediaSourcePrivate::EosNoError;

    if (error.isNull() || error.isEmpty())
        eosStatus = MediaSourcePrivate::EosNoError;
    else if (error == network)
        eosStatus = MediaSourcePrivate::EosNetworkError;
    else if (error == decode)
        eosStatus = MediaSourcePrivate::EosDecodeError;
    else {
        ec = INVALID_ACCESS_ERR;
        return;
    }

    // 2. Change the readyState attribute value to "ended".
    setReadyState(endedKeyword());
    m_private->markEndOfStream(eosStatus);
}
示例#4
0
void MediaSource::streamEndedWithError(const AtomicString& error, ExceptionCode& ec)
{
    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));

    // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm
    // 1. Change the readyState attribute value to "ended".
    // 2. Queue a task to fire a simple event named sourceended at the MediaSource.
    setReadyState(endedKeyword());

    // 3.
    if (error.isEmpty()) {
        // ↳ If error is not set, is null, or is an empty string
        // 1. Run the duration change algorithm with new duration set to the highest end timestamp
        // across all SourceBuffer objects in sourceBuffers.
        MediaTime maxEndTimestamp;
        for (auto it = m_sourceBuffers->begin(), end = m_sourceBuffers->end(); it != end; ++it)
            maxEndTimestamp = std::max((*it)->highestPresentationEndTimestamp(), maxEndTimestamp);
        m_private->setDuration(maxEndTimestamp);

        // 2. Notify the media element that it now has all of the media data.
        m_private->markEndOfStream(MediaSourcePrivate::EosNoError);
    } else if (error == network) {
        // ↳ If error is set to "network"
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data cannot be fetched at all, due to network errors, causing
            //    the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the "If the connection is interrupted after some media data has been received, causing the
            //    user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError);
        }
    } else if (error == decode) {
        // ↳ If error is set to "decode"
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data can be fetched but is found by inspection to be in an unsupported
            //    format, or can otherwise not be rendered at all" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the media data is corrupted steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError);
        }
    } else {
        // ↳ Otherwise
        //   Throw an INVALID_ACCESS_ERR exception.
        ec = INVALID_ACCESS_ERR;
    }
}
示例#5
0
void MediaSource::openIfInEndedState()
{
    if (m_readyState != endedKeyword())
        return;

    setReadyState(openKeyword());
    m_private->unmarkEndOfStream();
}
示例#6
0
void MediaSource::streamEndedWithError(Optional<EndOfStreamError> error)
{
    LOG(MediaSource, "MediaSource::streamEndedWithError(%p)", this);

    // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm

    // 1. Change the readyState attribute value to "ended".
    // 2. Queue a task to fire a simple event named sourceended at the MediaSource.
    setReadyState(endedKeyword());

    // 3.
    if (!error) {
        // ↳ If error is not set, is null, or is an empty string
        // 1. Run the duration change algorithm with new duration set to the highest end time reported by
        // the buffered attribute across all SourceBuffer objects in sourceBuffers.
        MediaTime maxEndTime;
        for (auto& sourceBuffer : *m_sourceBuffers) {
            if (auto length = sourceBuffer->buffered()->length())
                maxEndTime = std::max(sourceBuffer->buffered()->ranges().end(length - 1), maxEndTime);
        }
        setDurationInternal(maxEndTime);

        // 2. Notify the media element that it now has all of the media data.
        m_private->markEndOfStream(MediaSourcePrivate::EosNoError);
    } else if (error == EndOfStreamError::Network) {
        // ↳ If error is set to "network"
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data cannot be fetched at all, due to network errors, causing
            //    the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the "If the connection is interrupted after some media data has been received, causing the
            //    user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError);
        }
    } else {
        // ↳ If error is set to "decode"
        ASSERT(error == EndOfStreamError::Decode);
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data can be fetched but is found by inspection to be in an unsupported
            //    format, or can otherwise not be rendered at all" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the media data is corrupted steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError);
        }
    }
}
示例#7
0
std::unique_ptr<PlatformTimeRanges> MediaSource::buffered() const
{
    if (m_buffered && m_activeSourceBuffers->length() && std::all_of(m_activeSourceBuffers->begin(), m_activeSourceBuffers->end(), [] (RefPtr<SourceBuffer>& buffer) { return !buffer->isBufferedDirty(); }))
        return std::make_unique<PlatformTimeRanges>(*m_buffered);

    m_buffered = std::make_unique<PlatformTimeRanges>();
    for (auto& sourceBuffer : *m_activeSourceBuffers)
        sourceBuffer->setBufferedDirty(false);

    // Implements MediaSource algorithm for HTMLMediaElement.buffered.
    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
    Vector<PlatformTimeRanges> activeRanges = this->activeRanges();

    // 1. If activeSourceBuffers.length equals 0 then return an empty TimeRanges object and abort these steps.
    if (activeRanges.isEmpty())
        return std::make_unique<PlatformTimeRanges>(*m_buffered);

    // 2. Let active ranges be the ranges returned by buffered for each SourceBuffer object in activeSourceBuffers.
    // 3. Let highest end time be the largest range end time in the active ranges.
    MediaTime highestEndTime = MediaTime::zeroTime();
    for (auto& ranges : activeRanges) {
        unsigned length = ranges.length();
        if (length)
            highestEndTime = std::max(highestEndTime, ranges.end(length - 1));
    }

    // Return an empty range if all ranges are empty.
    if (!highestEndTime)
        return std::make_unique<PlatformTimeRanges>(*m_buffered);

    // 4. Let intersection ranges equal a TimeRange object containing a single range from 0 to highest end time.
    m_buffered->add(MediaTime::zeroTime(), highestEndTime);

    // 5. For each SourceBuffer object in activeSourceBuffers run the following steps:
    bool ended = readyState() == endedKeyword();
    for (auto& sourceRanges : activeRanges) {
        // 5.1 Let source ranges equal the ranges returned by the buffered attribute on the current SourceBuffer.
        // 5.2 If readyState is "ended", then set the end time on the last range in source ranges to highest end time.
        if (ended && sourceRanges.length())
            sourceRanges.add(sourceRanges.start(sourceRanges.length() - 1), highestEndTime);

        // 5.3 Let new intersection ranges equal the the intersection between the intersection ranges and the source ranges.
        // 5.4 Replace the ranges in intersection ranges with the new intersection ranges.
        m_buffered->intersectWith(sourceRanges);
    }

    return std::make_unique<PlatformTimeRanges>(*m_buffered);
}
示例#8
0
void MediaSource::setReadyState(const AtomicString& state)
{
    ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());

    AtomicString oldState = readyState();
    LOG(Media, "MediaSource::setReadyState() %p : %s -> %s", this, oldState.string().ascii().data(), state.string().ascii().data());

    if (state == closedKeyword()) {
        m_private.clear();
        m_mediaElement = 0;
    }

    if (oldState == state)
        return;

    m_readyState = state;

    onReadyStateChange(oldState, state);
}
示例#9
0
std::unique_ptr<PlatformTimeRanges> MediaSource::buffered() const
{
    // Implements MediaSource algorithm for HTMLMediaElement.buffered.
    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
    Vector<RefPtr<TimeRanges>> ranges = activeRanges();

    // 1. If activeSourceBuffers.length equals 0 then return an empty TimeRanges object and abort these steps.
    if (ranges.isEmpty())
        return PlatformTimeRanges::create();

    // 2. Let active ranges be the ranges returned by buffered for each SourceBuffer object in activeSourceBuffers.
    // 3. Let highest end time be the largest range end time in the active ranges.
    double highestEndTime = -1;
    for (size_t i = 0; i < ranges.size(); ++i) {
        unsigned length = ranges[i]->length();
        if (length)
            highestEndTime = std::max(highestEndTime, ranges[i]->end(length - 1, ASSERT_NO_EXCEPTION));
    }

    // Return an empty range if all ranges are empty.
    if (highestEndTime < 0)
        return PlatformTimeRanges::create();

    // 4. Let intersection ranges equal a TimeRange object containing a single range from 0 to highest end time.
    RefPtr<TimeRanges> intersectionRanges = TimeRanges::create(0, highestEndTime);

    // 5. For each SourceBuffer object in activeSourceBuffers run the following steps:
    bool ended = readyState() == endedKeyword();
    for (size_t i = 0; i < ranges.size(); ++i) {
        // 5.1 Let source ranges equal the ranges returned by the buffered attribute on the current SourceBuffer.
        TimeRanges* sourceRanges = ranges[i].get();

        // 5.2 If readyState is "ended", then set the end time on the last range in source ranges to highest end time.
        if (ended && sourceRanges->length())
            sourceRanges->add(sourceRanges->start(sourceRanges->length() - 1, ASSERT_NO_EXCEPTION), highestEndTime);

        // 5.3 Let new intersection ranges equal the the intersection between the intersection ranges and the source ranges.
        // 5.4 Replace the ranges in intersection ranges with the new intersection ranges.
        intersectionRanges->intersectWith(*sourceRanges);
    }

    return PlatformTimeRanges::create(intersectionRanges->ranges());
}
示例#10
0
void WebKitMediaSource::onReadyStateChange(const AtomicString& oldState, const AtomicString& newState)
{
    if (isClosed()) {
        m_sourceBuffers->clear();
        m_activeSourceBuffers->clear();
        scheduleEvent(eventNames().webkitsourcecloseEvent);
        return;
    }

    if (oldState == openKeyword() && newState == endedKeyword()) {
        scheduleEvent(eventNames().webkitsourceendedEvent);
        return;
    }

    if (isOpen()) {
        scheduleEvent(eventNames().webkitsourceopenEvent);
        return;
    }
}
示例#11
0
void MediaSource::setReadyState(const AtomicString& state)
{
    ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());

    AtomicString oldState = readyState();
    LOG(MediaSource, "MediaSource::setReadyState(%p) : %s -> %s", this, oldState.string().ascii().data(), state.string().ascii().data());

    if (state == closedKeyword()) {
        m_private = nullptr;
        m_mediaElement = nullptr;
        m_duration = MediaTime::invalidTime();
    }

    if (oldState == state)
        return;

    m_readyState = state;

    onReadyStateChange(oldState, state);
}
示例#12
0
void MediaSource::append(const String& id, PassRefPtr<Uint8Array> data, ExceptionCode& ec)
{
    if (!data.get()) {
        ec = INVALID_ACCESS_ERR;
        return;
    }

    if (!m_player || m_readyState == closedKeyword()) {
        ec = INVALID_STATE_ERR;
        return;
    }

    if (m_readyState == endedKeyword())
        setReadyState(openKeyword());

    if (!m_player->sourceAppend(id, data->data(), data->length())) {
        ec = SYNTAX_ERR;
        return;
    }
}
示例#13
0
void MediaSource::onReadyStateChange(const AtomicString& oldState, const AtomicString& newState)
{
    if (isOpen()) {
        scheduleEvent(eventNames().sourceopenEvent);
        return;
    }

    if (oldState == openKeyword() && newState == endedKeyword()) {
        scheduleEvent(eventNames().sourceendedEvent);
        return;
    }

    ASSERT(isClosed());

    m_activeSourceBuffers->clear();

    // Clear SourceBuffer references to this object.
    for (auto& buffer : *m_sourceBuffers)
        buffer->removedFromMediaSource();
    m_sourceBuffers->clear();
    
    scheduleEvent(eventNames().sourcecloseEvent);
}
示例#14
0
void MediaSource::onReadyStateChange(const AtomicString& oldState, const AtomicString& newState)
{
    if (isOpen()) {
        scheduleEvent(eventNames().sourceopenEvent);
        return;
    }

    if (oldState == openKeyword() && newState == endedKeyword()) {
        scheduleEvent(eventNames().sourceendedEvent);
        return;
    }

    ASSERT(isClosed());

    m_activeSourceBuffers->clear();

    // Clear SourceBuffer references to this object.
    for (unsigned long i = 0, length =  m_sourceBuffers->length(); i < length; ++i)
        m_sourceBuffers->item(i)->removedFromMediaSource();
    m_sourceBuffers->clear();
    
    scheduleEvent(eventNames().sourcecloseEvent);
}
示例#15
0
bool MediaSource::isEnded() const
{
    return readyState() == endedKeyword();
}
void MediaSource::streamEndedWithError(const AtomicString& error, ExceptionCode& ec)
{
    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));

    LOG(MediaSource, "MediaSource::streamEndedWithError(%p) : %s", this, error.string().ascii().data());

    // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm

    // 3.
    if (error.isEmpty()) {
        // ↳ If error is not set, is null, or is an empty string
        // 1. Run the duration change algorithm with new duration set to the highest end time reported by
        // the buffered attribute across all SourceBuffer objects in sourceBuffers.
        MediaTime maxEndTime;
        for (auto& sourceBuffer : *m_sourceBuffers) {
            if (auto length = sourceBuffer->buffered()->length())
                maxEndTime = std::max(sourceBuffer->buffered()->ranges().end(length - 1), maxEndTime);
        }
        setDurationInternal(maxEndTime);

        // 2. Notify the media element that it now has all of the media data.
        m_private->markEndOfStream(MediaSourcePrivate::EosNoError);
    }

    // NOTE: Do steps 1 & 2 after step 3 (with an empty error) to avoid the MediaSource's readyState being re-opened by a
    // remove() operation resulting from a duration change.
    // FIXME: Re-number or update this section once <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26316> is resolved.
    // 1. Change the readyState attribute value to "ended".
    // 2. Queue a task to fire a simple event named sourceended at the MediaSource.
    setReadyState(endedKeyword());

    if (error == network) {
        // ↳ If error is set to "network"
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data cannot be fetched at all, due to network errors, causing
            //    the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the "If the connection is interrupted after some media data has been received, causing the
            //    user agent to give up trying to fetch the resource" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError);
        }
    } else if (error == decode) {
        // ↳ If error is set to "decode"
        ASSERT(m_mediaElement);
        if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) {
            //  ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING
            //    Run the "If the media data can be fetched but is found by inspection to be in an unsupported
            //    format, or can otherwise not be rendered at all" steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed().
            m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError);
        } else {
            //  ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING
            //    Run the media data is corrupted steps of the resource fetch algorithm.
            //    NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally().
            m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError);
        }
    } else if (!error.isEmpty()) {
        // ↳ Otherwise
        //   Throw an INVALID_ACCESS_ERR exception.
        ec = INVALID_ACCESS_ERR;
    }
}