| Index: third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp
|
| diff --git a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp
|
| index d8b8e8a59271ae800fca7006260dc6a950d2dfc7..7f11656eb32160c68b85310ad8767ec0b3b95548 100644
|
| --- a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp
|
| +++ b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp
|
| @@ -42,6 +42,10 @@
|
| #include "core/html/HTMLMediaElement.h"
|
| #include "core/html/MediaError.h"
|
| #include "core/html/TimeRanges.h"
|
| +#include "core/html/track/AudioTrack.h"
|
| +#include "core/html/track/AudioTrackList.h"
|
| +#include "core/html/track/VideoTrack.h"
|
| +#include "core/html/track/VideoTrackList.h"
|
| #include "core/streams/Stream.h"
|
| #include "modules/mediasource/MediaSource.h"
|
| #include "platform/Logging.h"
|
| @@ -122,6 +126,9 @@ SourceBuffer::SourceBuffer(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSou
|
| {
|
| ASSERT(m_webSourceBuffer);
|
| ASSERT(m_source);
|
| + ASSERT(m_source->mediaElement());
|
| + m_audioTracks = AudioTrackList::create(*m_source->mediaElement());
|
| + m_videoTracks = VideoTrackList::create(*m_source->mediaElement());
|
| m_webSourceBuffer->setClient(this);
|
| }
|
|
|
| @@ -131,6 +138,8 @@ SourceBuffer::~SourceBuffer()
|
| // explicitly removed first, hence the asserts below will not
|
| // hold.
|
| #if !ENABLE(OILPAN)
|
| + m_audioTracks->shutdown();
|
| + m_videoTracks->shutdown();
|
| ASSERT(isRemoved());
|
| ASSERT(!m_loader);
|
| ASSERT(!m_stream);
|
| @@ -228,6 +237,18 @@ void SourceBuffer::setTimestampOffset(double offset, ExceptionState& exceptionSt
|
| m_timestampOffset = offset;
|
| }
|
|
|
| +AudioTrackList& SourceBuffer::audioTracks()
|
| +{
|
| + ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled());
|
| + return *m_audioTracks;
|
| +}
|
| +
|
| +VideoTrackList& SourceBuffer::videoTracks()
|
| +{
|
| + ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled());
|
| + return *m_videoTracks;
|
| +}
|
| +
|
| double SourceBuffer::appendWindowStart() const
|
| {
|
| return m_appendWindowStart;
|
| @@ -471,17 +492,76 @@ void SourceBuffer::removedFromMediaSource()
|
| m_asyncEventQueue = nullptr;
|
| }
|
|
|
| -void SourceBuffer::initializationSegmentReceived()
|
| +template<class T>
|
| +T* findExistingTrackById(const TrackListBase<T>& trackList, const String& id)
|
| +{
|
| + // According to MSE specification (https://w3c.github.io/media-source/#sourcebuffer-init-segment-received) step 3.1:
|
| + // > If more than one track for a single type are present (ie 2 audio tracks), then the Track IDs match the ones in the first initialization segment.
|
| + // I.e. we only need to search by TrackID if there is more than one track, otherwise we can assume that the only
|
| + // track of the given type is the same one that we had in previous init segments.
|
| + if (trackList.length() == 1)
|
| + return trackList.anonymousIndexedGetter(0);
|
| + return trackList.getTrackById(id);
|
| +}
|
| +
|
| +std::vector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(const std::vector<MediaTrackInfo>& newTracks)
|
| {
|
| - WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p", this);
|
| + WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p tracks=%zu", this, newTracks.size());
|
| ASSERT(m_source);
|
| + ASSERT(m_source->mediaElement());
|
| ASSERT(m_updating);
|
|
|
| - // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebuffer-init-segment-received
|
| - // FIXME: Make steps 1-7 synchronous with this call.
|
| - // FIXME: Augment the interface to this method to implement compliant steps 4-7 here.
|
| - // Step 3 (if the first initialization segment received flag is true) is
|
| - // implemented by caller.
|
| + // TODO(servolk): Implement proper 'initialization segment received' algorithm according to MSE spec:
|
| + // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received
|
| + std::vector<WebMediaPlayer::TrackId> result;
|
| + for (const auto& trackInfo : newTracks) {
|
| + const auto& trackType = std::get<0>(trackInfo);
|
| + const auto& id = std::get<1>(trackInfo);
|
| + const auto& kind = std::get<2>(trackInfo);
|
| + const auto& label = std::get<3>(trackInfo);
|
| + const auto& language = std::get<4>(trackInfo);
|
| +
|
| + if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) {
|
| + static WebMediaPlayer::TrackId nextTrackId = 0;
|
| + result.push_back(++nextTrackId);
|
| + continue;
|
| + }
|
| +
|
| + const TrackBase* trackBase = nullptr;
|
| + if (trackType == WebMediaPlayer::AudioTrack) {
|
| + AudioTrack* audioTrack = nullptr;
|
| + if (!m_firstInitializationSegmentReceived) {
|
| + audioTrack = AudioTrack::create(id, kind, label, language, false);
|
| + audioTracks().add(audioTrack);
|
| + m_source->mediaElement()->audioTracks().add(audioTrack);
|
| + } else {
|
| + audioTrack = findExistingTrackById(audioTracks(), id);
|
| + ASSERT(audioTrack);
|
| + }
|
| + trackBase = audioTrack;
|
| + result.push_back(audioTrack->trackId());
|
| + } else if (trackType == WebMediaPlayer::VideoTrack) {
|
| + VideoTrack* videoTrack = nullptr;
|
| + if (!m_firstInitializationSegmentReceived) {
|
| + videoTrack = VideoTrack::create(id, kind, label, language, false);
|
| + videoTracks().add(videoTrack);
|
| + m_source->mediaElement()->videoTracks().add(videoTrack);
|
| + } else {
|
| + videoTrack = findExistingTrackById(videoTracks(), id);
|
| + ASSERT(videoTrack);
|
| + }
|
| + trackBase = videoTrack;
|
| + result.push_back(videoTrack->trackId());
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| + (void)trackBase;
|
| +#if !LOG_DISABLED
|
| + const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added";
|
| + const char* logTrackTypeStr = (trackType == WebMediaPlayer::AudioTrack) ? "audio" : "video";
|
| + WTF_LOG(Media, "Tracks (sb=%p): %s %sTrack %p trackId=%d id=%s label=%s lang=%s", this, logActionStr, logTrackTypeStr, trackBase, trackBase->trackId(), trackBase->id().utf8().data(), trackBase->label().utf8().data(), trackBase->language().utf8().data());
|
| +#endif
|
| + }
|
|
|
| if (!m_firstInitializationSegmentReceived) {
|
| // 5. If active track flag equals true, then run the following steps:
|
| @@ -493,6 +573,8 @@ void SourceBuffer::initializationSegmentReceived()
|
| // 6. Set first initialization segment received flag to true.
|
| m_firstInitializationSegmentReceived = true;
|
| }
|
| +
|
| + return result;
|
| }
|
|
|
| bool SourceBuffer::hasPendingActivity() const
|
| @@ -873,6 +955,8 @@ DEFINE_TRACE(SourceBuffer)
|
| visitor->trace(m_removeAsyncPartRunner);
|
| visitor->trace(m_appendStreamAsyncPartRunner);
|
| visitor->trace(m_stream);
|
| + visitor->trace(m_audioTracks);
|
| + visitor->trace(m_videoTracks);
|
| RefCountedGarbageCollectedEventTargetWithInlineData<SourceBuffer>::trace(visitor);
|
| ActiveDOMObject::trace(visitor);
|
| }
|
|
|