Chromium Code Reviews| 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..cb424ba56c12eb5ba816beb9aa60fc4f7a55d5cf 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()); |
|
philipj_slow
2016/03/29 11:59:21
Looks like you could put this in the initializer l
servolk
2016/03/29 17:30:34
Yeah, I wanted to check (via ASSERT) that we have
|
| + m_videoTracks = VideoTrackList::create(*m_source->mediaElement()); |
| m_webSourceBuffer->setClient(this); |
| } |
| @@ -228,6 +235,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 +490,70 @@ void SourceBuffer::removedFromMediaSource() |
| m_asyncEventQueue = nullptr; |
| } |
| -void SourceBuffer::initializationSegmentReceived() |
| +template<class T> |
| +T* findTrackById(const TrackListBase<T>& trackList, const WebString& id) |
| { |
| - WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p", this); |
| + // According to MSE specification (https://www.w3.org/TR/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 |
|
philipj_slow
2016/03/29 11:59:21
Is this an optimization, or is it expected to ever
servolk
2016/03/29 17:30:34
wolenetz@ mentioned that MSE spec allows bytestrea
|
| + // 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::initializationSegmentReceived2 %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://www.w3.org/TR/media-source/#sourcebuffer-init-segment-received |
|
philipj_slow
2016/03/29 11:59:21
https://w3c.github.io/media-source/#sourcebuffer-i
servolk
2016/03/29 17:30:34
Done.
|
| + 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); |
| + |
| + 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 = findTrackById(audioTracks(), id); |
|
philipj_slow
2016/03/29 11:59:21
How about making it part of the API that if(m_firs
servolk
2016/03/29 17:30:34
No, see the comments above for findExistingTrackBy
|
| + 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 = findTrackById(videoTracks(), id); |
| + ASSERT(videoTrack); |
| + } |
| + trackBase = videoTrack; |
| + result.push_back(videoTrack->trackId()); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added"; |
|
philipj_slow
2016/03/29 11:59:21
The trackBase variable is only for logging it seem
servolk
2016/03/29 17:30:34
Well, actually one important thing that we want to
|
| + const char* logTrackTypeStr = (trackType == WebMediaPlayer::AudioTrack) ? "audio" : "video"; |
| + (void)logActionStr; |
| + (void)logTrackTypeStr; |
| + (void)trackBase; |
| + 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()); |
| + } |
| if (!m_firstInitializationSegmentReceived) { |
| // 5. If active track flag equals true, then run the following steps: |
| @@ -493,6 +565,8 @@ void SourceBuffer::initializationSegmentReceived() |
| // 6. Set first initialization segment received flag to true. |
| m_firstInitializationSegmentReceived = true; |
| } |
| + |
| + return result; |
| } |
| bool SourceBuffer::hasPendingActivity() const |
| @@ -873,6 +947,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); |
| } |