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 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
570 { | 570 { |
571 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1: | 571 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1: |
572 // > 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. | 572 // > 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. |
573 // I.e. we only need to search by TrackID if there is more than one track, o therwise we can assume that the only | 573 // I.e. we only need to search by TrackID if there is more than one track, o therwise we can assume that the only |
574 // track of the given type is the same one that we had in previous init segm ents. | 574 // track of the given type is the same one that we had in previous init segm ents. |
575 if (trackList.length() == 1) | 575 if (trackList.length() == 1) |
576 return trackList.anonymousIndexedGetter(0); | 576 return trackList.anonymousIndexedGetter(0); |
577 return trackList.getTrackById(id); | 577 return trackList.getTrackById(id); |
578 } | 578 } |
579 | 579 |
580 WebVector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(c onst WebVector<MediaTrackInfo>& newTracks) | 580 const TrackDefault* SourceBuffer::getTrackDefault(const AtomicString& trackType, const AtomicString& byteStreamTrackID) const |
581 { | |
582 // This is a helper for implementation of default track label and default tr ack language algorithms. | |
583 // defaultTrackLabel spec: https://w3c.github.io/media-source/#sourcebuffer- default-track-label | |
584 // defaultTrackLanguage spec: https://w3c.github.io/media-source/#sourcebuff er-default-track-language | |
585 | |
586 // 1. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackID attribute equal to byteStreamTrackID, | |
587 // then return the value of the label/language attribute on this matching ob ject and abort these steps. | |
588 // 2. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackID attribute equal to an empty string, | |
589 // then return the value of the label/language attribute on this matching ob ject and abort these steps. | |
590 // 3. Return an empty string to the caller | |
591 const TrackDefault* trackDefaultWithEmptyBytestreamId = nullptr; | |
592 for (unsigned i = 0; i < m_trackDefaults->length(); ++i) { | |
593 const TrackDefault* trackDefault = m_trackDefaults->item(i); | |
594 if (trackDefault->type() != trackType) | |
595 continue; | |
596 if (trackDefault->byteStreamTrackID() == byteStreamTrackID) | |
597 return trackDefault; | |
598 if (!trackDefaultWithEmptyBytestreamId && trackDefault->byteStreamTrackI D() == "") { | |
wolenetz
2016/06/16 22:15:33
nit: {} inconsistency within this method. Why usin
servolk
2016/06/21 17:44:52
Done.
| |
599 trackDefaultWithEmptyBytestreamId = trackDefault; | |
600 } | |
601 } | |
602 return trackDefaultWithEmptyBytestreamId; | |
603 } | |
604 | |
605 AtomicString SourceBuffer::defaultTrackLabel(const AtomicString& trackType, cons t AtomicString& byteStreamTrackID) const | |
606 { | |
607 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-labe l | |
608 const TrackDefault* trackDefault = getTrackDefault(trackType, byteStreamTrac kID); | |
609 return trackDefault ? AtomicString(trackDefault->label()) : ""; | |
610 } | |
611 | |
612 AtomicString SourceBuffer::defaultTrackLanguage(const AtomicString& trackType, c onst AtomicString& byteStreamTrackID) const | |
613 { | |
614 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-lang uage | |
615 const TrackDefault* trackDefault = getTrackDefault(trackType, byteStreamTrac kID); | |
616 return trackDefault ? AtomicString(trackDefault->language()) : ""; | |
617 } | |
618 | |
619 bool SourceBuffer::initializationSegmentReceived(const WebVector<MediaTrackInfo> & newTracks) | |
581 { | 620 { |
582 SBLOG << __FUNCTION__ << " this=" << this << " tracks=" << newTracks.size(); | 621 SBLOG << __FUNCTION__ << " this=" << this << " tracks=" << newTracks.size(); |
583 DCHECK(m_source); | 622 DCHECK(m_source); |
584 DCHECK(m_source->mediaElement()); | 623 DCHECK(m_source->mediaElement()); |
585 DCHECK(m_updating); | 624 DCHECK(m_updating); |
586 | 625 |
587 // TODO(servolk): Implement proper 'initialization segment received' algorit hm according to MSE spec: | 626 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) { |
627 if (!m_firstInitializationSegmentReceived) { | |
628 m_source->setSourceBufferActive(this); | |
629 m_firstInitializationSegmentReceived = true; | |
630 } | |
631 return true; | |
632 } | |
633 | |
634 // Implementation of Initialization Segment Received, see 3.5.8 at | |
wolenetz
2016/06/16 22:15:33
nit: s/3.5.8 at//
servolk
2016/06/21 17:44:52
Done.
| |
588 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received | 635 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received |
589 WebVector<WebMediaPlayer::TrackId> result(newTracks.size()); | 636 |
590 unsigned resultIdx = 0; | 637 // Sort newTracks into audio and video tracks to facilitate implementation |
591 for (const auto& trackInfo : newTracks) { | 638 // of subsequent steps of this algorithm. |
592 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) { | 639 Vector<MediaTrackInfo> newAudioTracks; |
593 static unsigned nextTrackId = 0; | 640 Vector<MediaTrackInfo> newVideoTracks; |
594 StringBuilder stringBuilder; | 641 for (const MediaTrackInfo& trackInfo : newTracks) { |
595 stringBuilder.appendNumber(++nextTrackId); | 642 const TrackBase* track = nullptr; |
596 result[resultIdx++] = stringBuilder.toString(); | |
597 continue; | |
598 } | |
599 | |
600 const TrackBase* trackBase = nullptr; | |
601 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) { | 643 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) { |
602 AudioTrack* audioTrack = nullptr; | 644 newAudioTracks.append(trackInfo); |
603 if (!m_firstInitializationSegmentReceived) { | 645 if (m_firstInitializationSegmentReceived) |
604 audioTrack = AudioTrack::create(trackInfo.id, trackInfo.kind, tr ackInfo.label, trackInfo.language, false); | 646 track = findExistingTrackById(audioTracks(), trackInfo.id); |
605 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, th is); | |
606 audioTracks().add(audioTrack); | |
607 m_source->mediaElement()->audioTracks().add(audioTrack); | |
608 } else { | |
609 audioTrack = findExistingTrackById(audioTracks(), trackInfo.id); | |
610 DCHECK(audioTrack); | |
611 } | |
612 trackBase = audioTrack; | |
613 result[resultIdx++] = audioTrack->id(); | |
614 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) { | 647 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) { |
615 VideoTrack* videoTrack = nullptr; | 648 newVideoTracks.append(trackInfo); |
616 if (!m_firstInitializationSegmentReceived) { | 649 if (m_firstInitializationSegmentReceived) |
617 videoTrack = VideoTrack::create(trackInfo.id, trackInfo.kind, tr ackInfo.label, trackInfo.language, false); | 650 track = findExistingTrackById(videoTracks(), trackInfo.id); |
618 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, th is); | |
619 videoTracks().add(videoTrack); | |
620 m_source->mediaElement()->videoTracks().add(videoTrack); | |
621 } else { | |
622 videoTrack = findExistingTrackById(videoTracks(), trackInfo.id); | |
623 DCHECK(videoTrack); | |
624 } | |
625 trackBase = videoTrack; | |
626 result[resultIdx++] = videoTrack->id(); | |
627 } else { | 651 } else { |
652 SBLOG << __FUNCTION__ << " this=" << this << " failed: unsupported t rack type " << trackInfo.trackType; | |
653 // TODO(servolk): Add handling of text tracks. | |
628 NOTREACHED(); | 654 NOTREACHED(); |
629 } | 655 } |
630 (void)trackBase; | 656 if (m_firstInitializationSegmentReceived && !track) { |
657 SBLOG << __FUNCTION__ << " this=" << this << " failed: tracks mismat ch the first init segment."; | |
658 appendError(true); | |
wolenetz
2016/06/16 22:15:33
Hmm. While I think this will probably work, our er
servolk
2016/06/21 17:44:52
Acknowledged. Ok, yes, I think reporting this erro
| |
659 return false; | |
660 } | |
631 #if !LOG_DISABLED | 661 #if !LOG_DISABLED |
632 const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added"; | |
633 const char* logTrackTypeStr = (trackInfo.trackType == WebMediaPlayer::Au dioTrack) ? "audio" : "video"; | 662 const char* logTrackTypeStr = (trackInfo.trackType == WebMediaPlayer::Au dioTrack) ? "audio" : "video"; |
634 SBLOG << __FUNCTION__ << "(" << this << ") " << logActionStr << " " | 663 SBLOG << __FUNCTION__ << " this=" << this << " : " << logTrackTypeStr << " track " |
635 << logTrackTypeStr << " Track " << trackBase << " id=" << String(tra ckBase->id()) | 664 << " id=" << String(trackInfo.id) << " byteStreamTrackID=" << String (trackInfo.byteStreamTrackID) |
636 << " label=" << trackBase->label() << " lang=" << trackBase->languag e(); | 665 << " kind=" << String(trackInfo.kind) << " label=" << String(trackIn fo.label) << " language=" << String(trackInfo.language); |
637 #endif | 666 #endif |
638 } | 667 } |
639 | 668 |
669 // 1. Update the duration attribute if it currently equals NaN: | |
670 // TODO(servolk): Pass also stream duration into initSegmentReceived. | |
671 | |
672 // 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. | |
673 if (newTracks.size() == 0) { | |
674 SBLOG << __FUNCTION__ << " this=" << this << " failed: no tracks found i n the init segment."; | |
675 appendError(true); | |
676 return false; | |
677 } | |
678 | |
679 // 3. If the first initialization segment received flag is true, then run th e following steps: | |
680 if (m_firstInitializationSegmentReceived) { | |
681 // 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. | |
682 bool tracksMatchFirstInitSegment = true; | |
683 // - The number of audio, video, and text tracks match what was in the f irst initialization segment. | |
684 if (newAudioTracks.size() != audioTracks().length() || newVideoTracks.si ze() != videoTracks().length()) { | |
685 tracksMatchFirstInitSegment = false; | |
686 } | |
687 // - The codecs for each track, match what was specified in the first in itialization segment. | |
688 // This is currently done in MediaSourceState::OnNewConfigs. | |
689 // - 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. | |
690 if (tracksMatchFirstInitSegment && newAudioTracks.size() > 1) { | |
691 for (size_t i = 0; i < newAudioTracks.size(); ++i) { | |
692 const String& newTrackId = newVideoTracks[i].id; | |
693 if (newTrackId != String(audioTracks().anonymousIndexedGetter(i) ->id())) { | |
694 tracksMatchFirstInitSegment = false; | |
695 break; | |
696 } | |
697 } | |
698 } | |
699 | |
700 if (tracksMatchFirstInitSegment && newVideoTracks.size() > 1) { | |
701 for (size_t i = 0; i < newVideoTracks.size(); ++i) { | |
702 const String& newTrackId = newVideoTracks[i].id; | |
703 if (newTrackId != String(videoTracks().anonymousIndexedGetter(i) ->id())) { | |
704 tracksMatchFirstInitSegment = false; | |
705 break; | |
706 } | |
707 } | |
708 } | |
709 | |
710 if (!tracksMatchFirstInitSegment) { | |
711 SBLOG << __FUNCTION__ << " this=" << this << " failed: tracks mismat ch the first init segment."; | |
712 appendError(true); | |
713 return false; | |
714 } | |
715 | |
716 // 3.2 Add the appropriate track descriptions from this initialization s egment to each of the track buffers. | |
717 // This is done in Chromium code in stream parsers and demuxer implement ations. | |
718 | |
719 // 3.3 Set the need random access point flag on all track buffers to tru e. | |
720 // This is done in Chromium code, see MediaSourceState::OnNewConfigs. | |
721 } | |
722 | |
723 // 4. Let active track flag equal false. | |
724 m_activeTrack = false; | |
725 | |
726 // 5. If the first initialization segment received flag is false, then run t he following steps: | |
640 if (!m_firstInitializationSegmentReceived) { | 727 if (!m_firstInitializationSegmentReceived) { |
641 // 5. If active track flag equals true, then run the following steps: | 728 // 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. |
642 // 5.1. Add this SourceBuffer to activeSourceBuffers. | 729 // This is done in Chromium code, see MediaSourceState::OnNewConfigs. |
643 // 5.2. Queue a task to fire a simple event named addsourcebuffer at | 730 |
731 // 5.2 For each audio track in the initialization segment, run following steps: | |
732 for (const MediaTrackInfo& trackInfo : newAudioTracks) { | |
733 // 5.2.1 Let audio byte stream track ID be the Track ID for the curr ent track being processed. | |
734 const auto& byteStreamTrackID = trackInfo.byteStreamTrackID; | |
735 // 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. | |
736 WebString language = trackInfo.language; | |
737 // 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 | |
738 // audio byte stream track ID and type set to "audio" and assign the value returned by the algorithm to audio language. | |
739 if (language.isEmpty() || language == "und") | |
740 language = defaultTrackLanguage(TrackDefault::audioKeyword(), by teStreamTrackID); | |
741 // 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. | |
742 WebString label = trackInfo.label; | |
743 // 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 | |
744 // type set to "audio" and assign the value returned by the algorith m to audio label. | |
745 if (label.isEmpty()) | |
746 label = defaultTrackLabel(TrackDefault::audioKeyword(), byteStre amTrackID); | |
747 // 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. | |
748 const auto& kind = trackInfo.kind; | |
749 // 5.2.7 TODO(servolk): Implement track kind processing. | |
750 // 5.2.8.2 Let new audio track be a new AudioTrack object. | |
751 AudioTrack* audioTrack = AudioTrack::create(byteStreamTrackID, kind, label, language, false); | |
752 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, this); | |
753 // 5.2.8.7 If audioTracks.length equals 0, then run the following st eps: | |
754 if (audioTracks().length() == 0) { | |
755 // 5.2.8.7.1 Set the enabled property on new audio track to true . | |
756 audioTrack->setEnabled(true); | |
757 // 5.2.8.7.2 Set active track flag to true. | |
758 m_activeTrack = true; | |
759 } | |
760 // 5.2.8.8 Add new audio track to the audioTracks attribute on this SourceBuffer object. | |
761 // 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. | |
762 audioTracks().add(audioTrack); | |
763 // 5.2.8.10 Add new audio track to the audioTracks attribute on the HTMLMediaElement. | |
764 // 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. | |
765 m_source->mediaElement()->audioTracks().add(audioTrack); | |
766 } | |
767 | |
768 // 5.3. For each video track in the initialization segment, run followin g steps: | |
769 for (const MediaTrackInfo& trackInfo : newVideoTracks) { | |
770 // 5.3.1 Let video byte stream track ID be the Track ID for the curr ent track being processed. | |
771 const auto& byteStreamTrackID = trackInfo.byteStreamTrackID; | |
772 // 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. | |
773 WebString language = trackInfo.language; | |
774 // 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 | |
775 // video byte stream track ID and type set to "video" and assign the value returned by the algorithm to video language. | |
776 if (language.isEmpty() || language == "und") | |
777 language = defaultTrackLanguage(TrackDefault::videoKeyword(), by teStreamTrackID); | |
778 // 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. | |
779 WebString label = trackInfo.label; | |
780 // 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 | |
781 // type set to "video" and assign the value returned by the algorith m to video label. | |
782 if (label.isEmpty()) | |
783 label = defaultTrackLabel(TrackDefault::videoKeyword(), byteStre amTrackID); | |
784 // 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. | |
785 const auto& kind = trackInfo.kind; | |
786 // 5.3.7 TODO(servolk): Implement track kind processing. | |
787 // 5.3.8.2 Let new video track be a new VideoTrack object. | |
788 VideoTrack* videoTrack = VideoTrack::create(byteStreamTrackID, kind, label, language, false); | |
789 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, this); | |
790 // 5.3.8.7 If videoTracks.length equals 0, then run the following st eps: | |
791 if (videoTracks().length() == 0) { | |
792 // 5.3.8.7.1 Set the selected property on new audio track to tru e. | |
793 videoTrack->setSelected(true); | |
794 // 5.3.8.7.2 Set active track flag to true. | |
795 m_activeTrack = true; | |
796 } | |
797 // 5.3.8.8 Add new video track to the videoTracks attribute on this SourceBuffer object. | |
798 // 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. | |
799 videoTracks().add(videoTrack); | |
800 // 5.3.8.10 Add new video track to the videoTracks attribute on the HTMLMediaElement. | |
801 // 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. | |
802 m_source->mediaElement()->videoTracks().add(videoTrack); | |
803 } | |
804 | |
805 // 5.4 TODO(servolk): Add text track processing here. | |
806 | |
807 // 5.5 If active track flag equals true, then run the following steps: | |
644 // activesourcebuffers. | 808 // activesourcebuffers. |
645 m_source->setSourceBufferActive(this); | 809 if (m_activeTrack) { |
646 | 810 // 5.5.1 Add this SourceBuffer to activeSourceBuffers. |
647 // 6. Set first initialization segment received flag to true. | 811 // 5.5.2 Queue a task to fire a simple event named addsourcebuffer a t activeSourceBuffers |
812 m_source->setSourceBufferActive(this); | |
813 } | |
814 | |
815 // 5.6. Set first initialization segment received flag to true. | |
648 m_firstInitializationSegmentReceived = true; | 816 m_firstInitializationSegmentReceived = true; |
649 } | 817 } |
650 | 818 |
651 return result; | 819 return true; |
652 } | 820 } |
653 | 821 |
654 bool SourceBuffer::hasPendingActivity() const | 822 bool SourceBuffer::hasPendingActivity() const |
655 { | 823 { |
656 return m_source; | 824 return m_source; |
657 } | 825 } |
658 | 826 |
659 void SourceBuffer::suspend() | 827 void SourceBuffer::suspend() |
660 { | 828 { |
661 m_appendBufferAsyncPartRunner->suspend(); | 829 m_appendBufferAsyncPartRunner->suspend(); |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1030 visitor->trace(m_removeAsyncPartRunner); | 1198 visitor->trace(m_removeAsyncPartRunner); |
1031 visitor->trace(m_appendStreamAsyncPartRunner); | 1199 visitor->trace(m_appendStreamAsyncPartRunner); |
1032 visitor->trace(m_stream); | 1200 visitor->trace(m_stream); |
1033 visitor->trace(m_audioTracks); | 1201 visitor->trace(m_audioTracks); |
1034 visitor->trace(m_videoTracks); | 1202 visitor->trace(m_videoTracks); |
1035 EventTargetWithInlineData::trace(visitor); | 1203 EventTargetWithInlineData::trace(visitor); |
1036 ActiveDOMObject::trace(visitor); | 1204 ActiveDOMObject::trace(visitor); |
1037 } | 1205 } |
1038 | 1206 |
1039 } // namespace blink | 1207 } // namespace blink |
OLD | NEW |