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()); | |
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
| |
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) |
134 ASSERT(isRemoved()); | 141 ASSERT(isRemoved()); |
(...skipping 86 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. | 228 // 6. If the mode attribute equals "sequence", then set the group start time stamp to new timestamp offset. |
222 if (!m_webSourceBuffer->setTimestampOffset(offset)) { | 229 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'."); | 230 MediaSource::logAndThrowDOMException(exceptionState, InvalidStateError, "The timestamp offset may not be set while the SourceBuffer's append state is 'P ARSING_MEDIA_SEGMENT'."); |
224 return; | 231 return; |
225 } | 232 } |
226 | 233 |
227 // 7. Update the attribute to new timestamp offset. | 234 // 7. Update the attribute to new timestamp offset. |
228 m_timestampOffset = offset; | 235 m_timestampOffset = offset; |
229 } | 236 } |
230 | 237 |
238 AudioTrackList& SourceBuffer::audioTracks() | |
239 { | |
240 ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled()); | |
241 return *m_audioTracks; | |
242 } | |
243 | |
244 VideoTrackList& SourceBuffer::videoTracks() | |
245 { | |
246 ASSERT(RuntimeEnabledFeatures::audioVideoTracksEnabled()); | |
247 return *m_videoTracks; | |
248 } | |
249 | |
231 double SourceBuffer::appendWindowStart() const | 250 double SourceBuffer::appendWindowStart() const |
232 { | 251 { |
233 return m_appendWindowStart; | 252 return m_appendWindowStart; |
234 } | 253 } |
235 | 254 |
236 void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionS tate) | 255 void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionS tate) |
237 { | 256 { |
238 WTF_LOG(Media, "SourceBuffer::setAppendWindowStart %p start=%f", this, start ); | 257 WTF_LOG(Media, "SourceBuffer::setAppendWindowStart %p start=%f", this, start ); |
239 // Section 3.1 appendWindowStart attribute setter steps. | 258 // 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 | 259 // 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 | 483 |
465 WTF_LOG(Media, "SourceBuffer(%p)::removedFromMediaSource", this); | 484 WTF_LOG(Media, "SourceBuffer(%p)::removedFromMediaSource", this); |
466 abortIfUpdating(); | 485 abortIfUpdating(); |
467 | 486 |
468 m_webSourceBuffer->removedFromMediaSource(); | 487 m_webSourceBuffer->removedFromMediaSource(); |
469 m_webSourceBuffer.clear(); | 488 m_webSourceBuffer.clear(); |
470 m_source = nullptr; | 489 m_source = nullptr; |
471 m_asyncEventQueue = nullptr; | 490 m_asyncEventQueue = nullptr; |
472 } | 491 } |
473 | 492 |
474 void SourceBuffer::initializationSegmentReceived() | 493 template<class T> |
494 T* findTrackById(const TrackListBase<T>& trackList, const WebString& id) | |
475 { | 495 { |
476 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p", this); | 496 // According to MSE specification (https://www.w3.org/TR/media-source/#sourc ebuffer-init-segment-received) step 3.1: |
497 // > 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. | |
498 // I.e. we only need to search by TrackID if there is more than one track, o therwise 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
| |
499 // track of the given type is the same one that we had in previous init segm ents. | |
500 if (trackList.length() == 1) | |
501 return trackList.anonymousIndexedGetter(0); | |
502 return trackList.getTrackById(id); | |
503 } | |
504 | |
505 std::vector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived (const std::vector<MediaTrackInfo>& newTracks) | |
506 { | |
507 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived2 %p tracks=%zu", this, newTracks.size()); | |
477 ASSERT(m_source); | 508 ASSERT(m_source); |
509 ASSERT(m_source->mediaElement()); | |
478 ASSERT(m_updating); | 510 ASSERT(m_updating); |
479 | 511 |
480 // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source. html#sourcebuffer-init-segment-received | 512 // TODO(servolk): Implement proper 'initialization segment received' algorit hm according to MSE spec: |
481 // FIXME: Make steps 1-7 synchronous with this call. | 513 // 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.
| |
482 // FIXME: Augment the interface to this method to implement compliant steps 4-7 here. | 514 std::vector<WebMediaPlayer::TrackId> result; |
483 // Step 3 (if the first initialization segment received flag is true) is | 515 for (const auto& trackInfo : newTracks) { |
484 // implemented by caller. | 516 const auto& trackType = std::get<0>(trackInfo); |
517 const auto& id = std::get<1>(trackInfo); | |
518 const auto& kind = std::get<2>(trackInfo); | |
519 const auto& label = std::get<3>(trackInfo); | |
520 const auto& language = std::get<4>(trackInfo); | |
521 | |
522 const TrackBase* trackBase = nullptr; | |
523 if (trackType == WebMediaPlayer::AudioTrack) { | |
524 AudioTrack* audioTrack = nullptr; | |
525 if (!m_firstInitializationSegmentReceived) { | |
526 audioTrack = AudioTrack::create(id, kind, label, language, false ); | |
527 audioTracks().add(audioTrack); | |
528 m_source->mediaElement()->audioTracks().add(audioTrack); | |
529 } else { | |
530 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
| |
531 ASSERT(audioTrack); | |
532 } | |
533 trackBase = audioTrack; | |
534 result.push_back(audioTrack->trackId()); | |
535 } else if (trackType == WebMediaPlayer::VideoTrack) { | |
536 VideoTrack* videoTrack = nullptr; | |
537 if (!m_firstInitializationSegmentReceived) { | |
538 videoTrack = VideoTrack::create(id, kind, label, language, false ); | |
539 videoTracks().add(videoTrack); | |
540 m_source->mediaElement()->videoTracks().add(videoTrack); | |
541 } else { | |
542 videoTrack = findTrackById(videoTracks(), id); | |
543 ASSERT(videoTrack); | |
544 } | |
545 trackBase = videoTrack; | |
546 result.push_back(videoTrack->trackId()); | |
547 } else { | |
548 NOTREACHED(); | |
549 } | |
550 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
| |
551 const char* logTrackTypeStr = (trackType == WebMediaPlayer::AudioTrack) ? "audio" : "video"; | |
552 (void)logActionStr; | |
553 (void)logTrackTypeStr; | |
554 (void)trackBase; | |
555 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()); | |
556 } | |
485 | 557 |
486 if (!m_firstInitializationSegmentReceived) { | 558 if (!m_firstInitializationSegmentReceived) { |
487 // 5. If active track flag equals true, then run the following steps: | 559 // 5. If active track flag equals true, then run the following steps: |
488 // 5.1. Add this SourceBuffer to activeSourceBuffers. | 560 // 5.1. Add this SourceBuffer to activeSourceBuffers. |
489 // 5.2. Queue a task to fire a simple event named addsourcebuffer at | 561 // 5.2. Queue a task to fire a simple event named addsourcebuffer at |
490 // activesourcebuffers. | 562 // activesourcebuffers. |
491 m_source->setSourceBufferActive(this); | 563 m_source->setSourceBufferActive(this); |
492 | 564 |
493 // 6. Set first initialization segment received flag to true. | 565 // 6. Set first initialization segment received flag to true. |
494 m_firstInitializationSegmentReceived = true; | 566 m_firstInitializationSegmentReceived = true; |
495 } | 567 } |
568 | |
569 return result; | |
496 } | 570 } |
497 | 571 |
498 bool SourceBuffer::hasPendingActivity() const | 572 bool SourceBuffer::hasPendingActivity() const |
499 { | 573 { |
500 return m_source; | 574 return m_source; |
501 } | 575 } |
502 | 576 |
503 void SourceBuffer::suspend() | 577 void SourceBuffer::suspend() |
504 { | 578 { |
505 m_appendBufferAsyncPartRunner->suspend(); | 579 m_appendBufferAsyncPartRunner->suspend(); |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
866 | 940 |
867 DEFINE_TRACE(SourceBuffer) | 941 DEFINE_TRACE(SourceBuffer) |
868 { | 942 { |
869 visitor->trace(m_source); | 943 visitor->trace(m_source); |
870 visitor->trace(m_trackDefaults); | 944 visitor->trace(m_trackDefaults); |
871 visitor->trace(m_asyncEventQueue); | 945 visitor->trace(m_asyncEventQueue); |
872 visitor->trace(m_appendBufferAsyncPartRunner); | 946 visitor->trace(m_appendBufferAsyncPartRunner); |
873 visitor->trace(m_removeAsyncPartRunner); | 947 visitor->trace(m_removeAsyncPartRunner); |
874 visitor->trace(m_appendStreamAsyncPartRunner); | 948 visitor->trace(m_appendStreamAsyncPartRunner); |
875 visitor->trace(m_stream); | 949 visitor->trace(m_stream); |
950 visitor->trace(m_audioTracks); | |
951 visitor->trace(m_videoTracks); | |
876 RefCountedGarbageCollectedEventTargetWithInlineData<SourceBuffer>::trace(vis itor); | 952 RefCountedGarbageCollectedEventTargetWithInlineData<SourceBuffer>::trace(vis itor); |
877 ActiveDOMObject::trace(visitor); | 953 ActiveDOMObject::trace(visitor); |
878 } | 954 } |
879 | 955 |
880 } // namespace blink | 956 } // namespace blink |
OLD | NEW |