Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1029)

Side by Side Diff: third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp

Issue 1678523003: Implement InitSegmentReceived algorithm in blink (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blink-sb-audiotrack
Patch Set: rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 557 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 { 568 {
569 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1: 569 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1:
570 // > 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. 570 // > 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.
571 // I.e. we only need to search by TrackID if there is more than one track, o therwise we can assume that the only 571 // I.e. we only need to search by TrackID if there is more than one track, o therwise we can assume that the only
572 // track of the given type is the same one that we had in previous init segm ents. 572 // track of the given type is the same one that we had in previous init segm ents.
573 if (trackList.length() == 1) 573 if (trackList.length() == 1)
574 return trackList.anonymousIndexedGetter(0); 574 return trackList.anonymousIndexedGetter(0);
575 return trackList.getTrackById(id); 575 return trackList.getTrackById(id);
576 } 576 }
577 577
578 const TrackDefault* SourceBuffer::getTrackDefault(const AtomicString& trackType, const AtomicString& byteStreamTrackId) const
579 {
580 // This is a helper for implementation of default track label and default tr ack language algorithms.
581 // defaultTrackLabel spec: https://w3c.github.io/media-source/#sourcebuffer- default-track-label
582 // defaultTrackLanguage spec: https://w3c.github.io/media-source/#sourcebuff er-default-track-language
583
584 // 1. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackId attribute equal to byteStreamTrackId,
585 // then return the value of the label/language attribute on this matching ob ject and abort these steps.
586 // 2. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackId attribute equal to an empty string,
587 // then return the value of the label/language attribute on this matching ob ject and abort these steps.
588 // 3. Return an empty string to the caller
589 const TrackDefault* trackDefaultWithEmptyBytestreamId = nullptr;
590 for (unsigned i = 0; i < m_trackDefaults->length(); ++i) {
591 const TrackDefault* trackDefault = m_trackDefaults->item(i);
592 if (trackDefault->type() != trackType)
593 continue;
594 if (trackDefault->byteStreamTrackID() == byteStreamTrackId)
595 return trackDefault;
596 if (!trackDefaultWithEmptyBytestreamId && trackDefault->byteStreamTrackI D() == "") {
597 trackDefaultWithEmptyBytestreamId = trackDefault;
598 }
599 }
600 return trackDefaultWithEmptyBytestreamId;
601 }
602
603 AtomicString SourceBuffer::defaultTrackLabel(const AtomicString& trackType, cons t AtomicString& byteStreamTrackId) const
604 {
605 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-labe l
606 const TrackDefault* trackDefault = getTrackDefault(trackType, byteStreamTrac kId);
607 return trackDefault ? AtomicString(trackDefault->label()) : "";
608 }
609
610 AtomicString SourceBuffer::defaultTrackLanguage(const AtomicString& trackType, c onst AtomicString& byteStreamTrackId) const
611 {
612 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-lang uage
613 const TrackDefault* trackDefault = getTrackDefault(trackType, byteStreamTrac kId);
614 return trackDefault ? AtomicString(trackDefault->language()) : "";
615 }
616
578 WebVector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(c onst WebVector<MediaTrackInfo>& newTracks) 617 WebVector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(c onst WebVector<MediaTrackInfo>& newTracks)
579 { 618 {
580 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p tracks=%zu", this, newTracks.size()); 619 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p tracks=%zu", this, newTracks.size());
581 ASSERT(m_source); 620 ASSERT(m_source);
582 ASSERT(m_source->mediaElement()); 621 ASSERT(m_source->mediaElement());
583 ASSERT(m_updating); 622 ASSERT(m_updating);
584 623
585 // TODO(servolk): Implement proper 'initialization segment received' algorit hm according to MSE spec: 624 WebVector<WebMediaPlayer::TrackId> assignedTrackIds(newTracks.size());
625
626 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) {
627 for (size_t i = 0; i < newTracks.size(); ++i) {
628 static WebMediaPlayer::TrackId nextTrackId = 0;
629 assignedTrackIds[i] = ++nextTrackId;
630 }
631 if (!m_firstInitializationSegmentReceived) {
632 m_source->setSourceBufferActive(this);
633 m_firstInitializationSegmentReceived = true;
634 }
635 return assignedTrackIds;
636 }
637
638
639 // Implementation of Initialization Segment Received, see 3.5.8 at
586 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received 640 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received
587 WebVector<WebMediaPlayer::TrackId> result(newTracks.size()); 641
588 unsigned resultIdx = 0; 642 // Sort newTracks into audio and video tracks to facilitate implementation
589 for (const auto& trackInfo : newTracks) { 643 // of subsequent steps of this algorithm.
590 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) { 644 Vector<MediaTrackInfo> newAudioTracks;
591 static WebMediaPlayer::TrackId nextTrackId = 0; 645 Vector<MediaTrackInfo> newVideoTracks;
592 result[resultIdx++] = ++nextTrackId; 646 size_t resultIdx = 0;
593 continue; 647 for (const MediaTrackInfo& trackInfo : newTracks) {
594 } 648 const TrackBase* track = nullptr;
595
596 const TrackBase* trackBase = nullptr;
597 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) { 649 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) {
598 AudioTrack* audioTrack = nullptr; 650 newAudioTracks.append(trackInfo);
599 if (!m_firstInitializationSegmentReceived) { 651 if (m_firstInitializationSegmentReceived)
600 audioTrack = AudioTrack::create(trackInfo.byteStreamTrackId, tra ckInfo.kind, trackInfo.label, trackInfo.language, false); 652 track = findExistingTrackById(audioTracks(), trackInfo.byteStrea mTrackId);
601 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, th is);
602 audioTracks().add(audioTrack);
603 m_source->mediaElement()->audioTracks().add(audioTrack);
604 } else {
605 audioTrack = findExistingTrackById(audioTracks(), trackInfo.byte StreamTrackId);
606 ASSERT(audioTrack);
607 }
608 trackBase = audioTrack;
609 result[resultIdx++] = audioTrack->trackId();
610 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) { 653 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) {
611 VideoTrack* videoTrack = nullptr; 654 newVideoTracks.append(trackInfo);
612 if (!m_firstInitializationSegmentReceived) { 655 if (m_firstInitializationSegmentReceived)
613 videoTrack = VideoTrack::create(trackInfo.byteStreamTrackId, tra ckInfo.kind, trackInfo.label, trackInfo.language, false); 656 track = findExistingTrackById(videoTracks(), trackInfo.byteStrea mTrackId);
614 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, th is);
615 videoTracks().add(videoTrack);
616 m_source->mediaElement()->videoTracks().add(videoTrack);
617 } else {
618 videoTrack = findExistingTrackById(videoTracks(), trackInfo.byte StreamTrackId);
619 ASSERT(videoTrack);
620 }
621 trackBase = videoTrack;
622 result[resultIdx++] = videoTrack->trackId();
623 } else { 657 } else {
658 // TODO(servolk): Add handling of text tracks.
624 NOTREACHED(); 659 NOTREACHED();
625 } 660 }
626 (void)trackBase; 661
627 #if !LOG_DISABLED 662 if (m_firstInitializationSegmentReceived) {
628 const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added"; 663 if (!track) {
629 const char* logTrackTypeStr = (trackInfo.trackType == WebMediaPlayer::Au dioTrack) ? "audio" : "video"; 664 WTF_LOG(Media, "SourceBuffer(%p)::initializationSegmentReceived failed: tracks mismatch the first init segment.", this);
630 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()); 665 appendError(true);
631 #endif 666 return assignedTrackIds;
632 } 667 }
633 668 assignedTrackIds[resultIdx++] = track->trackId();
669 }
670 }
671
672 // 1. Update the duration attribute if it currently equals NaN:
673 // TODO(servolk): Pass also stream duration into initSegmentReceived.
674
675 // 2. If the initialization segment has no audio, video, or text tracks, the n run the append error algorithm with the decode error parameter set to true and abort these steps.
676 if (newTracks.size() == 0) {
677 WTF_LOG(Media, "SourceBuffer(%p)::initializationSegmentReceived failed, no tracks found in the init segment.", this);
678 appendError(true);
679 return assignedTrackIds;
680 }
681
682 // 3. If the first initialization segment received flag is true, then run th e following steps:
683 if (m_firstInitializationSegmentReceived) {
684 // 3.1 Verify the following properties. If any of the checks fail then r un the append error algorithm with the decode error parameter set to true and ab ort these steps.
685 bool tracksMatchFirstInitSegment = true;
686 // - The number of audio, video, and text tracks match what was in the f irst initialization segment.
687 if (newAudioTracks.size() != audioTracks().length() || newVideoTracks.si ze() != videoTracks().length()) {
688 tracksMatchFirstInitSegment = false;
689 }
690 // - The codecs for each track, match what was specified in the first in itialization segment.
691 // This is currently done in MediaSourceState::OnNewConfigs.
692 // - If more than one track for a single type are present (ie 2 audio tr acks), then the Track IDs match the ones in the first initialization segment.
693 if (tracksMatchFirstInitSegment && newAudioTracks.size() > 1) {
694 for (size_t i = 0; i < newAudioTracks.size(); ++i) {
695 const String& newTrackId = newVideoTracks[i].byteStreamTrackId;
696 if (newTrackId != audioTracks().anonymousIndexedGetter(i)->id()) {
697 tracksMatchFirstInitSegment = false;
698 break;
699 }
700 }
701 }
702
703 if (tracksMatchFirstInitSegment && newVideoTracks.size() > 1) {
704 for (size_t i = 0; i < newVideoTracks.size(); ++i) {
705 const String& newTrackId = newVideoTracks[i].byteStreamTrackId;
706 if (newTrackId != videoTracks().anonymousIndexedGetter(i)->id()) {
707 tracksMatchFirstInitSegment = false;
708 break;
709 }
710 }
711 }
712
713 if (!tracksMatchFirstInitSegment) {
714 WTF_LOG(Media, "SourceBuffer(%p)::initializationSegmentReceived fail ed: tracks mismatch the first init segment.", this);
715 appendError(true);
716 return assignedTrackIds;
717 }
718
719 // 3.2 Add the appropriate track descriptions from this initialization s egment to each of the track buffers.
720 // This is done in Chromium code in stream parsers and demuxer implement ations.
721
722 // 3.3 Set the need random access point flag on all track buffers to tru e.
723 // This is done in Chromium code, see MediaSourceState::OnNewConfigs.
724 }
725
726 // 4. Let active track flag equal false.
727 m_activeTrack = false;
728
729 // 5. If the first initialization segment received flag is false, then run t he following steps:
634 if (!m_firstInitializationSegmentReceived) { 730 if (!m_firstInitializationSegmentReceived) {
635 // 5. If active track flag equals true, then run the following steps: 731 // 5.1 If the initialization segment contains tracks with codecs the use r agent does not support, then run the append error algorithm with the decode er ror parameter set to true and abort these steps.
636 // 5.1. Add this SourceBuffer to activeSourceBuffers. 732 // This is done in Chromium code, see MediaSourceState::OnNewConfigs.
637 // 5.2. Queue a task to fire a simple event named addsourcebuffer at 733
734 // 5.2 For each audio track in the initialization segment, run following steps:
735 for (const MediaTrackInfo& trackInfo : newAudioTracks) {
736 // 5.2.1 Let audio byte stream track ID be the Track ID for the curr ent track being processed.
737 const auto& byteStreamTrackId = trackInfo.byteStreamTrackId;
738 // 5.2.2 Let audio language be a BCP 47 language tag for the languag e specified in the initialization segment for this track or an empty string if n o language info is present.
739 WebString language = trackInfo.language;
740 // 5.2.3 If audio language equals an empty string or the 'und' BCP 4 7 value, then run the default track language algorithm with byteStreamTrackId se t to
741 // audio byte stream track ID and type set to "audio" and assign the value returned by the algorithm to audio language.
742 if (language.isEmpty() || language == "und")
743 language = defaultTrackLanguage(TrackDefault::audioKeyword(), by teStreamTrackId);
744 // 5.2.4 Let audio label be a label specified in the initialization segment for this track or an empty string if no label info is present.
745 WebString label = trackInfo.label;
746 // 5.3.5 If audio label equals an empty string, then run the default track label algorithm with byteStreamTrackId set to audio byte stream track ID and
747 // type set to "audio" and assign the value returned by the algorith m to audio label.
748 if (label.isEmpty())
749 label = defaultTrackLabel(TrackDefault::audioKeyword(), byteStre amTrackId);
750 // 5.2.6 Let audio kinds be an array of kind strings specified in th e initialization segment for this track or an empty array if no kind information is provided.
751 const auto& kind = trackInfo.kind;
752 // 5.2.7 TODO(servolk): Implement track kind processing.
753 // 5.2.8.2 Let new audio track be a new AudioTrack object.
754 AudioTrack* audioTrack = AudioTrack::create(byteStreamTrackId, kind, label, language, false);
755 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, this);
756 assignedTrackIds[resultIdx++] = audioTrack->trackId();
757 // 5.2.8.7 If audioTracks.length equals 0, then run the following st eps:
758 if (audioTracks().length() == 0) {
759 // 5.2.8.7.1 Set the enabled property on new audio track to true .
760 audioTrack->setEnabled(true);
761 // 5.2.8.7.2 Set active track flag to true.
762 m_activeTrack = true;
763 }
764 // 5.2.8.8 Add new audio track to the audioTracks attribute on this SourceBuffer object.
765 // 5.2.8.9 Queue a task to fire a trusted event named addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object referenced by the audioTracks attribute on this Sou rceBuffer object.
766 audioTracks().add(audioTrack);
767 // 5.2.8.10 Add new audio track to the audioTracks attribute on the HTMLMediaElement.
768 // 5.2.8.11 Queue a task to fire a trusted event named addtrack, tha t does not bubble and is not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object referenced by the audioTracks attribute on the HTM LMediaElement.
769 m_source->mediaElement()->audioTracks().add(audioTrack);
770 }
771
772 // 5.3. For each video track in the initialization segment, run followin g steps:
773 for (const MediaTrackInfo& trackInfo : newVideoTracks) {
774 // 5.3.1 Let video byte stream track ID be the Track ID for the curr ent track being processed.
775 const auto& byteStreamTrackId = trackInfo.byteStreamTrackId;
776 // 5.3.2 Let video language be a BCP 47 language tag for the languag e specified in the initialization segment for this track or an empty string if n o language info is present.
777 WebString language = trackInfo.language;
778 // 5.3.3 If video language equals an empty string or the 'und' BCP 4 7 value, then run the default track language algorithm with byteStreamTrackId se t to
779 // video byte stream track ID and type set to "video" and assign the value returned by the algorithm to video language.
780 if (language.isEmpty() || language == "und")
781 language = defaultTrackLanguage(TrackDefault::videoKeyword(), by teStreamTrackId);
782 // 5.3.4 Let video label be a label specified in the initialization segment for this track or an empty string if no label info is present.
783 WebString label = trackInfo.label;
784 // 5.3.5 If video label equals an empty string, then run the default track label algorithm with byteStreamTrackId set to video byte stream track ID and
785 // type set to "video" and assign the value returned by the algorith m to video label.
786 if (label.isEmpty())
787 label = defaultTrackLabel(TrackDefault::videoKeyword(), byteStre amTrackId);
788 // 5.3.6 Let video kinds be an array of kind strings specified in th e initialization segment for this track or an empty array if no kind information is provided.
789 const auto& kind = trackInfo.kind;
790 // 5.3.7 TODO(servolk): Implement track kind processing.
791 // 5.3.8.2 Let new video track be a new VideoTrack object.
792 VideoTrack* videoTrack = VideoTrack::create(byteStreamTrackId, kind, label, language, false);
793 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, this);
794 assignedTrackIds[resultIdx++] = videoTrack->trackId();
795 // 5.3.8.7 If videoTracks.length equals 0, then run the following st eps:
796 if (videoTracks().length() == 0) {
797 // 5.3.8.7.1 Set the selected property on new audio track to tru e.
798 videoTrack->setSelected(true);
799 // 5.3.8.7.2 Set active track flag to true.
800 m_activeTrack = true;
801 }
802 // 5.3.8.8 Add new video track to the videoTracks attribute on this SourceBuffer object.
803 // 5.3.8.9 Queue a task to fire a trusted event named addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object referenced by the videoTracks attribute on this Sou rceBuffer object.
804 videoTracks().add(videoTrack);
805 // 5.3.8.10 Add new video track to the videoTracks attribute on the HTMLMediaElement.
806 // 5.3.8.11 Queue a task to fire a trusted event named addtrack, tha t does not bubble and is not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object referenced by the videoTracks attribute on the HTM LMediaElement.
807 m_source->mediaElement()->videoTracks().add(videoTrack);
808 }
809
810 // 5.4 TODO(servolk): Add text track processing here.
811
812 // 5.5 If active track flag equals true, then run the following steps:
638 // activesourcebuffers. 813 // activesourcebuffers.
639 m_source->setSourceBufferActive(this); 814 if (m_activeTrack) {
640 815 // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
641 // 6. Set first initialization segment received flag to true. 816 // 5.5.2 Queue a task to fire a simple event named addsourcebuffer a t activeSourceBuffers
817 m_source->setSourceBufferActive(this);
818 }
819
820 // 5.6. Set first initialization segment received flag to true.
642 m_firstInitializationSegmentReceived = true; 821 m_firstInitializationSegmentReceived = true;
643 } 822 }
644 823
645 return result; 824 return assignedTrackIds;
646 } 825 }
647 826
648 bool SourceBuffer::hasPendingActivity() const 827 bool SourceBuffer::hasPendingActivity() const
649 { 828 {
650 return m_source; 829 return m_source;
651 } 830 }
652 831
653 void SourceBuffer::suspend() 832 void SourceBuffer::suspend()
654 { 833 {
655 m_appendBufferAsyncPartRunner->suspend(); 834 m_appendBufferAsyncPartRunner->suspend();
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
1023 visitor->trace(m_removeAsyncPartRunner); 1202 visitor->trace(m_removeAsyncPartRunner);
1024 visitor->trace(m_appendStreamAsyncPartRunner); 1203 visitor->trace(m_appendStreamAsyncPartRunner);
1025 visitor->trace(m_stream); 1204 visitor->trace(m_stream);
1026 visitor->trace(m_audioTracks); 1205 visitor->trace(m_audioTracks);
1027 visitor->trace(m_videoTracks); 1206 visitor->trace(m_videoTracks);
1028 EventTargetWithInlineData::trace(visitor); 1207 EventTargetWithInlineData::trace(visitor);
1029 ActiveDOMObject::trace(visitor); 1208 ActiveDOMObject::trace(visitor);
1030 } 1209 }
1031 1210
1032 } // namespace blink 1211 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698