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); |
} |