OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 24 matching lines...) Expand all Loading... | |
35 #include "core/dom/DOMArrayBuffer.h" | 35 #include "core/dom/DOMArrayBuffer.h" |
36 #include "core/dom/DOMArrayBufferView.h" | 36 #include "core/dom/DOMArrayBufferView.h" |
37 #include "core/dom/ExceptionCode.h" | 37 #include "core/dom/ExceptionCode.h" |
38 #include "core/dom/ExecutionContext.h" | 38 #include "core/dom/ExecutionContext.h" |
39 #include "core/events/Event.h" | 39 #include "core/events/Event.h" |
40 #include "core/events/GenericEventQueue.h" | 40 #include "core/events/GenericEventQueue.h" |
41 #include "core/fileapi/FileReaderLoader.h" | 41 #include "core/fileapi/FileReaderLoader.h" |
42 #include "core/html/HTMLMediaElement.h" | 42 #include "core/html/HTMLMediaElement.h" |
43 #include "core/html/MediaError.h" | 43 #include "core/html/MediaError.h" |
44 #include "core/html/TimeRanges.h" | 44 #include "core/html/TimeRanges.h" |
45 #include "core/html/track/AudioTrack.h" | |
46 #include "core/html/track/AudioTrackList.h" | |
47 #include "core/html/track/VideoTrack.h" | |
48 #include "core/html/track/VideoTrackList.h" | |
45 #include "core/streams/Stream.h" | 49 #include "core/streams/Stream.h" |
46 #include "modules/mediasource/MediaSource.h" | 50 #include "modules/mediasource/MediaSource.h" |
47 #include "platform/Logging.h" | 51 #include "platform/Logging.h" |
48 #include "platform/TraceEvent.h" | 52 #include "platform/TraceEvent.h" |
49 #include "public/platform/WebSourceBuffer.h" | 53 #include "public/platform/WebSourceBuffer.h" |
50 #include "wtf/MathExtras.h" | 54 #include "wtf/MathExtras.h" |
51 | 55 |
52 #include <limits> | 56 #include <limits> |
53 #include <sstream> | 57 #include <sstream> |
54 | 58 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
115 , m_appendBufferAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this , &SourceBuffer::appendBufferAsyncPart)) | 119 , m_appendBufferAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this , &SourceBuffer::appendBufferAsyncPart)) |
116 , m_pendingRemoveStart(-1) | 120 , m_pendingRemoveStart(-1) |
117 , m_pendingRemoveEnd(-1) | 121 , m_pendingRemoveEnd(-1) |
118 , m_removeAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this, &Sou rceBuffer::removeAsyncPart)) | 122 , m_removeAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this, &Sou rceBuffer::removeAsyncPart)) |
119 , m_streamMaxSizeValid(false) | 123 , m_streamMaxSizeValid(false) |
120 , m_streamMaxSize(0) | 124 , m_streamMaxSize(0) |
121 , m_appendStreamAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this , &SourceBuffer::appendStreamAsyncPart)) | 125 , m_appendStreamAsyncPartRunner(AsyncMethodRunner<SourceBuffer>::create(this , &SourceBuffer::appendStreamAsyncPart)) |
122 { | 126 { |
123 ASSERT(m_webSourceBuffer); | 127 ASSERT(m_webSourceBuffer); |
124 ASSERT(m_source); | 128 ASSERT(m_source); |
129 ASSERT(m_source->mediaElement()); | |
130 m_audioTracks = AudioTrackList::create(*m_source->mediaElement()); | |
131 m_videoTracks = VideoTrackList::create(*m_source->mediaElement()); | |
125 m_webSourceBuffer->setClient(this); | 132 m_webSourceBuffer->setClient(this); |
126 } | 133 } |
127 | 134 |
128 SourceBuffer::~SourceBuffer() | 135 SourceBuffer::~SourceBuffer() |
129 { | 136 { |
130 // Oilpan: a SourceBuffer might be finalized without having been | 137 // Oilpan: a SourceBuffer might be finalized without having been |
131 // explicitly removed first, hence the asserts below will not | 138 // explicitly removed first, hence the asserts below will not |
132 // hold. | 139 // hold. |
133 #if !ENABLE(OILPAN) | 140 #if !ENABLE(OILPAN) |
141 m_audioTracks->shutdown(); | |
142 m_videoTracks->shutdown(); | |
134 ASSERT(isRemoved()); | 143 ASSERT(isRemoved()); |
135 ASSERT(!m_loader); | 144 ASSERT(!m_loader); |
136 ASSERT(!m_stream); | 145 ASSERT(!m_stream); |
137 ASSERT(!m_webSourceBuffer); | 146 ASSERT(!m_webSourceBuffer); |
138 #endif | 147 #endif |
139 WTF_LOG(Media, "SourceBuffer(%p)::~SourceBuffer", this); | 148 WTF_LOG(Media, "SourceBuffer(%p)::~SourceBuffer", this); |
140 } | 149 } |
141 | 150 |
142 const AtomicString& SourceBuffer::segmentsKeyword() | 151 const AtomicString& SourceBuffer::segmentsKeyword() |
143 { | 152 { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 // 6. If the mode attribute equals "sequence", then set the group start time stamp to new timestamp offset. | 230 // 6. If the mode attribute equals "sequence", then set the group start time stamp to new timestamp offset. |
222 if (!m_webSourceBuffer->setTimestampOffset(offset)) { | 231 if (!m_webSourceBuffer->setTimestampOffset(offset)) { |
223 MediaSource::logAndThrowDOMException(exceptionState, InvalidStateError, "The timestamp offset may not be set while the SourceBuffer's append state is 'P ARSING_MEDIA_SEGMENT'."); | 232 MediaSource::logAndThrowDOMException(exceptionState, InvalidStateError, "The timestamp offset may not be set while the SourceBuffer's append state is 'P ARSING_MEDIA_SEGMENT'."); |
224 return; | 233 return; |
225 } | 234 } |
226 | 235 |
227 // 7. Update the attribute to new timestamp offset. | 236 // 7. Update the attribute to new timestamp offset. |
228 m_timestampOffset = offset; | 237 m_timestampOffset = offset; |
229 } | 238 } |
230 | 239 |
240 AudioTrackList& SourceBuffer::audioTracks() | |
241 { | |
242 ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled()); | |
243 return *m_audioTracks; | |
244 } | |
245 | |
246 VideoTrackList& SourceBuffer::videoTracks() | |
247 { | |
248 ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled()); | |
249 return *m_videoTracks; | |
250 } | |
251 | |
231 double SourceBuffer::appendWindowStart() const | 252 double SourceBuffer::appendWindowStart() const |
232 { | 253 { |
233 return m_appendWindowStart; | 254 return m_appendWindowStart; |
234 } | 255 } |
235 | 256 |
236 void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionS tate) | 257 void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionS tate) |
237 { | 258 { |
238 WTF_LOG(Media, "SourceBuffer::setAppendWindowStart %p start=%f", this, start ); | 259 WTF_LOG(Media, "SourceBuffer::setAppendWindowStart %p start=%f", this, start ); |
239 // Section 3.1 appendWindowStart attribute setter steps. | 260 // Section 3.1 appendWindowStart attribute setter steps. |
240 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source. html#widl-SourceBuffer-appendWindowStart | 261 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source. html#widl-SourceBuffer-appendWindowStart |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 | 485 |
465 WTF_LOG(Media, "SourceBuffer(%p)::removedFromMediaSource", this); | 486 WTF_LOG(Media, "SourceBuffer(%p)::removedFromMediaSource", this); |
466 abortIfUpdating(); | 487 abortIfUpdating(); |
467 | 488 |
468 m_webSourceBuffer->removedFromMediaSource(); | 489 m_webSourceBuffer->removedFromMediaSource(); |
469 m_webSourceBuffer.clear(); | 490 m_webSourceBuffer.clear(); |
470 m_source = nullptr; | 491 m_source = nullptr; |
471 m_asyncEventQueue = nullptr; | 492 m_asyncEventQueue = nullptr; |
472 } | 493 } |
473 | 494 |
474 void SourceBuffer::initializationSegmentReceived() | 495 template<class T> |
496 T* findExistingTrackById(const TrackListBase<T>& trackList, const String& id) | |
475 { | 497 { |
476 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p", this); | 498 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1: |
499 // > 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. | |
500 // I.e. we only need to search by TrackID if there is more than one track, o therwise we can assume that the only | |
501 // track of the given type is the same one that we had in previous init segm ents. | |
502 if (trackList.length() == 1) | |
503 return trackList.anonymousIndexedGetter(0); | |
504 return trackList.getTrackById(id); | |
505 } | |
506 | |
507 std::vector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived (const std::vector<MediaTrackInfo>& newTracks) | |
508 { | |
509 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived2 %p tracks=%zu", this, newTracks.size()); | |
wolenetz
2016/03/30 01:06:15
nit: s/2//?
servolk
2016/03/30 01:10:37
Done.
| |
477 ASSERT(m_source); | 510 ASSERT(m_source); |
511 ASSERT(m_source->mediaElement()); | |
478 ASSERT(m_updating); | 512 ASSERT(m_updating); |
479 | 513 |
480 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source. html#sourcebuffer-init-segment-received | 514 // TODO(servolk): Implement proper 'initialization segment received' algorit hm according to MSE spec: |
481 // FIXME: Make steps 1-7 synchronous with this call. | 515 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received |
482 // FIXME: Augment the interface to this method to implement compliant steps 4-7 here. | 516 std::vector<WebMediaPlayer::TrackId> result; |
483 // Step 3 (if the first initialization segment received flag is true) is | 517 for (const auto& trackInfo : newTracks) { |
484 // implemented by caller. | 518 const auto& trackType = std::get<0>(trackInfo); |
519 const auto& id = std::get<1>(trackInfo); | |
520 const auto& kind = std::get<2>(trackInfo); | |
521 const auto& label = std::get<3>(trackInfo); | |
522 const auto& language = std::get<4>(trackInfo); | |
523 | |
524 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) { | |
525 static WebMediaPlayer::TrackId nextTrackId = 0; | |
526 result.push_back(++nextTrackId); | |
527 continue; | |
528 } | |
529 | |
530 const TrackBase* trackBase = nullptr; | |
531 if (trackType == WebMediaPlayer::AudioTrack) { | |
532 AudioTrack* audioTrack = nullptr; | |
533 if (!m_firstInitializationSegmentReceived) { | |
534 audioTrack = AudioTrack::create(id, kind, label, language, false ); | |
535 audioTracks().add(audioTrack); | |
536 m_source->mediaElement()->audioTracks().add(audioTrack); | |
537 } else { | |
538 audioTrack = findExistingTrackById(audioTracks(), id); | |
wolenetz
2016/03/30 01:06:15
Indeed this is an improvement over rebuilding the
servolk
2016/03/30 01:10:37
Acknowledged.
| |
539 ASSERT(audioTrack); | |
540 } | |
541 trackBase = audioTrack; | |
542 result.push_back(audioTrack->trackId()); | |
543 } else if (trackType == WebMediaPlayer::VideoTrack) { | |
544 VideoTrack* videoTrack = nullptr; | |
545 if (!m_firstInitializationSegmentReceived) { | |
546 videoTrack = VideoTrack::create(id, kind, label, language, false ); | |
547 videoTracks().add(videoTrack); | |
548 m_source->mediaElement()->videoTracks().add(videoTrack); | |
549 } else { | |
550 videoTrack = findExistingTrackById(videoTracks(), id); | |
551 ASSERT(videoTrack); | |
552 } | |
553 trackBase = videoTrack; | |
554 result.push_back(videoTrack->trackId()); | |
555 } else { | |
556 NOTREACHED(); | |
557 } | |
558 (void)trackBase; | |
559 #if !LOG_DISABLED | |
560 const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added"; | |
561 const char* logTrackTypeStr = (trackType == WebMediaPlayer::AudioTrack) ? "audio" : "video"; | |
562 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->lang uage().utf8().data()); | |
563 #endif | |
564 } | |
485 | 565 |
486 if (!m_firstInitializationSegmentReceived) { | 566 if (!m_firstInitializationSegmentReceived) { |
487 // 5. If active track flag equals true, then run the following steps: | 567 // 5. If active track flag equals true, then run the following steps: |
488 // 5.1. Add this SourceBuffer to activeSourceBuffers. | 568 // 5.1. Add this SourceBuffer to activeSourceBuffers. |
489 // 5.2. Queue a task to fire a simple event named addsourcebuffer at | 569 // 5.2. Queue a task to fire a simple event named addsourcebuffer at |
490 // activesourcebuffers. | 570 // activesourcebuffers. |
491 m_source->setSourceBufferActive(this); | 571 m_source->setSourceBufferActive(this); |
492 | 572 |
493 // 6. Set first initialization segment received flag to true. | 573 // 6. Set first initialization segment received flag to true. |
494 m_firstInitializationSegmentReceived = true; | 574 m_firstInitializationSegmentReceived = true; |
495 } | 575 } |
576 | |
577 return result; | |
496 } | 578 } |
497 | 579 |
498 bool SourceBuffer::hasPendingActivity() const | 580 bool SourceBuffer::hasPendingActivity() const |
499 { | 581 { |
500 return m_source; | 582 return m_source; |
501 } | 583 } |
502 | 584 |
503 void SourceBuffer::suspend() | 585 void SourceBuffer::suspend() |
504 { | 586 { |
505 m_appendBufferAsyncPartRunner->suspend(); | 587 m_appendBufferAsyncPartRunner->suspend(); |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
866 | 948 |
867 DEFINE_TRACE(SourceBuffer) | 949 DEFINE_TRACE(SourceBuffer) |
868 { | 950 { |
869 visitor->trace(m_source); | 951 visitor->trace(m_source); |
870 visitor->trace(m_trackDefaults); | 952 visitor->trace(m_trackDefaults); |
871 visitor->trace(m_asyncEventQueue); | 953 visitor->trace(m_asyncEventQueue); |
872 visitor->trace(m_appendBufferAsyncPartRunner); | 954 visitor->trace(m_appendBufferAsyncPartRunner); |
873 visitor->trace(m_removeAsyncPartRunner); | 955 visitor->trace(m_removeAsyncPartRunner); |
874 visitor->trace(m_appendStreamAsyncPartRunner); | 956 visitor->trace(m_appendStreamAsyncPartRunner); |
875 visitor->trace(m_stream); | 957 visitor->trace(m_stream); |
958 visitor->trace(m_audioTracks); | |
959 visitor->trace(m_videoTracks); | |
876 RefCountedGarbageCollectedEventTargetWithInlineData<SourceBuffer>::trace(vis itor); | 960 RefCountedGarbageCollectedEventTargetWithInlineData<SourceBuffer>::trace(vis itor); |
877 ActiveDOMObject::trace(visitor); | 961 ActiveDOMObject::trace(visitor); |
878 } | 962 } |
879 | 963 |
880 } // namespace blink | 964 } // namespace blink |
OLD | NEW |