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

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 + update Created 4 years, 8 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
« no previous file with comments | « third_party/WebKit/Source/modules/mediasource/SourceBuffer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 484 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 { 495 {
496 // According to MSE specification (https://w3c.github.io/media-source/#sourc ebuffer-init-segment-received) step 3.1: 496 // According to MSE specification (https://w3c.github.io/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. 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 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
499 // track of the given type is the same one that we had in previous init segm ents. 499 // track of the given type is the same one that we had in previous init segm ents.
500 if (trackList.length() == 1) 500 if (trackList.length() == 1)
501 return trackList.anonymousIndexedGetter(0); 501 return trackList.anonymousIndexedGetter(0);
502 return trackList.getTrackById(id); 502 return trackList.getTrackById(id);
503 } 503 }
504 504
505 const TrackDefault* SourceBuffer::getTrackDefaultHelper(const AtomicString& trac kType, const AtomicString& byteStreamTrackID) const
philipj_slow 2016/04/25 13:03:42 Maybe just getTrackDefault as the name?
servolk 2016/04/25 20:29:07 Done.
506 {
507 // This is a helper for implementation of default track label and default tr ack language algorithms.
508 // defaultTrackLabel spec: https://w3c.github.io/media-source/#sourcebuffer- default-track-label
509 // defaultTrackLanguage spec: https://w3c.github.io/media-source/#sourcebuff er-default-track-language
510
511 // 1. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackID attribute equal to byteStreamTrackID,
512 // then return the value of the label/language attribute on this matching ob ject and abort these steps.
513 for (unsigned i = 0; i < m_trackDefaults->length(); ++i) {
514 const auto* trackDefault = m_trackDefaults->item(i);
philipj_slow 2016/04/25 13:03:42 From http://chromium-cpp.appspot.com and https://g
servolk 2016/04/25 20:29:08 Done.
515 ASSERT(trackDefault);
philipj_slow 2016/04/25 13:03:42 Not sure if there's a document rule here, but in h
servolk 2016/04/25 20:29:08 Done.
516 if (trackDefault->type() == trackType && trackDefault->byteStreamTrackID () == byteStreamTrackID)
517 return trackDefault;
518 }
519
520 // 2. If trackDefaults contains a TrackDefault object with a type attribute equal to type and a byteStreamTrackID attribute equal to an empty string,
521 // then return the value of the label/language attribute on this matching ob ject and abort these steps.
522 for (unsigned i = 0; i < m_trackDefaults->length(); ++i) {
523 const auto* trackDefault = m_trackDefaults->item(i);
524 ASSERT(trackDefault);
525 if (trackDefault->type() == trackType && trackDefault->byteStreamTrackID () == "")
philipj_slow 2016/04/25 13:03:42 In the first loop you could maintain two variables
servolk 2016/04/25 20:29:08 Done.
526 return trackDefault;
527 }
528
529 // 3. Return an empty string to the caller
530 return nullptr;
531 }
532
533 AtomicString SourceBuffer::defaultTrackLabel(const AtomicString& trackType, cons t AtomicString& byteStreamTrackID) const
534 {
535 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-labe l
536 const TrackDefault* trackDefault = getTrackDefaultHelper(trackType, byteStre amTrackID);
537 return trackDefault ? AtomicString(trackDefault->label()) : "";
538 }
539
540 AtomicString SourceBuffer::defaultTrackLanguage(const AtomicString& trackType, c onst AtomicString& byteStreamTrackID) const
541 {
542 // Spec: https://w3c.github.io/media-source/#sourcebuffer-default-track-lang uage
543 const TrackDefault* trackDefault = getTrackDefaultHelper(trackType, byteStre amTrackID);
544 return trackDefault ? AtomicString(trackDefault->language()) : "";
545 }
546
505 WebVector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(c onst WebVector<MediaTrackInfo>& newTracks) 547 WebVector<WebMediaPlayer::TrackId> SourceBuffer::initializationSegmentReceived(c onst WebVector<MediaTrackInfo>& newTracks)
506 { 548 {
507 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p tracks=%zu", this, newTracks.size()); 549 WTF_LOG(Media, "SourceBuffer::initializationSegmentReceived %p tracks=%zu", this, newTracks.size());
508 ASSERT(m_source); 550 ASSERT(m_source);
509 ASSERT(m_source->mediaElement()); 551 ASSERT(m_source->mediaElement());
510 ASSERT(m_updating); 552 ASSERT(m_updating);
511 553
512 // TODO(servolk): Implement proper 'initialization segment received' algorit hm according to MSE spec: 554 WebVector<WebMediaPlayer::TrackId> assignedTrackIds(newTracks.size());
555
556 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) {
557 for (size_t i = 0; i < newTracks.size(); ++i) {
558 static WebMediaPlayer::TrackId nextTrackId = 0;
559 assignedTrackIds[i] = ++nextTrackId;
560 }
561 if (!m_firstInitializationSegmentReceived) {
562 m_source->setSourceBufferActive(this);
563 m_firstInitializationSegmentReceived = true;
564 }
565 return assignedTrackIds;
566 }
567
568
569 // Implementation of Initialization Segment Received, see 3.5.8 at
513 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received 570 // https://w3c.github.io/media-source/#sourcebuffer-init-segment-received
514 WebVector<WebMediaPlayer::TrackId> result(newTracks.size()); 571
572 // Sort newTracks into audio and video tracks to facilitate implementation
573 // of subsequent steps of this algorithm.
574 std::vector<MediaTrackInfo> newAudioTracks;
philipj_slow 2016/04/25 13:03:42 Vector<>
servolk 2016/04/25 20:29:08 Done.
575 std::vector<MediaTrackInfo> newVideoTracks;
515 unsigned resultIdx = 0; 576 unsigned resultIdx = 0;
philipj_slow 2016/04/25 13:03:42 size_t to match WebVector.h and the new usage abov
servolk 2016/04/25 20:29:08 Done.
516 for (const auto& trackInfo : newTracks) { 577 for (const auto& trackInfo : newTracks) {
517 if (!RuntimeEnabledFeatures::audioVideoTracksEnabled()) { 578 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) {
518 static WebMediaPlayer::TrackId nextTrackId = 0; 579 newAudioTracks.push_back(trackInfo);
519 result[resultIdx++] = ++nextTrackId; 580 if (m_firstInitializationSegmentReceived) {
520 continue; 581 AudioTrack* audioTrack = findExistingTrackById(audioTracks(), tr ackInfo.byteStreamTrackId);
582 ASSERT(audioTrack);
philipj_slow 2016/04/25 13:03:42 It seems a bit odd to assume the tracks are all th
servolk 2016/04/25 20:29:07 Yeah, I guess strictly speaking it's better to han
583 assignedTrackIds[resultIdx++] = audioTrack->trackId();
584 }
585 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) {
586 newVideoTracks.push_back(trackInfo);
587 if (m_firstInitializationSegmentReceived) {
588 VideoTrack* videoTrack = findExistingTrackById(videoTracks(), tr ackInfo.byteStreamTrackId);
589 ASSERT(videoTrack);
590 assignedTrackIds[resultIdx++] = videoTrack->trackId();
591 }
592 } else {
593 // TODO(servolk): Add handling of text tracks.
594 ASSERT_NOT_REACHED();
philipj_slow 2016/04/25 13:03:42 NOTREACHED() is the new ASSERT_NOT_REACHED()
servolk 2016/04/25 20:29:08 Done.
595 }
596 }
597
598 // 1. Update the duration attribute if it currently equals NaN:
599 // TODO(servolk): Pass also stream duration into initSegmentReceived.
600
601 // 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.
602 if (newTracks.size() == 0) {
603 WTF_LOG(Media, "SourceBuffer(%p)::initializationSegmentReceived failed, no tracks found in the init segment.", this);
604 appendError(true);
605 return assignedTrackIds;
606 }
607
608 // 3. If the first initialization segment received flag is true, then run th e following steps:
609 if (m_firstInitializationSegmentReceived) {
610 // 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.
611 bool tracksMatchFirstInitSegment = true;
612 // - The number of audio, video, and text tracks match what was in the f irst initialization segment.
613 if (newAudioTracks.size() != audioTracks().length() || newVideoTracks.si ze() != videoTracks().length()) {
614 tracksMatchFirstInitSegment = false;
615 }
616 // - The codecs for each track, match what was specified in the first in itialization segment.
philipj_slow 2016/04/25 13:03:42 Is this also in MediaSourceState::OnNewConfigs? If
servolk 2016/04/25 20:29:08 Done.
617 // - 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.
618 if (tracksMatchFirstInitSegment && newAudioTracks.size() > 1) {
619 for (size_t i = 0; i < newAudioTracks.size(); ++i) {
620 const String& newTrackId = newVideoTracks[i].byteStreamTrackId;
621 if (newTrackId != audioTracks().anonymousIndexedGetter(i)->id())
622 tracksMatchFirstInitSegment = false;
philipj_slow 2016/04/25 13:03:42 Also break?
servolk 2016/04/25 20:29:08 Done.
623 }
521 } 624 }
522 625
523 const TrackBase* trackBase = nullptr; 626 if (tracksMatchFirstInitSegment && newVideoTracks.size() > 1) {
524 if (trackInfo.trackType == WebMediaPlayer::AudioTrack) { 627 for (size_t i = 0; i < newVideoTracks.size(); ++i) {
525 AudioTrack* audioTrack = nullptr; 628 const String& newTrackId = newVideoTracks[i].byteStreamTrackId;
526 if (!m_firstInitializationSegmentReceived) { 629 if (newTrackId != videoTracks().anonymousIndexedGetter(i)->id())
527 audioTrack = AudioTrack::create(trackInfo.byteStreamTrackId, tra ckInfo.kind, trackInfo.label, trackInfo.language, false); 630 tracksMatchFirstInitSegment = false;
philipj_slow 2016/04/25 13:03:42 Ditto.
servolk 2016/04/25 20:29:08 Done.
528 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, th is);
529 audioTracks().add(audioTrack);
530 m_source->mediaElement()->audioTracks().add(audioTrack);
531 } else {
532 audioTrack = findExistingTrackById(audioTracks(), trackInfo.byte StreamTrackId);
533 ASSERT(audioTrack);
534 } 631 }
535 trackBase = audioTrack;
536 result[resultIdx++] = audioTrack->trackId();
537 } else if (trackInfo.trackType == WebMediaPlayer::VideoTrack) {
538 VideoTrack* videoTrack = nullptr;
539 if (!m_firstInitializationSegmentReceived) {
540 videoTrack = VideoTrack::create(trackInfo.byteStreamTrackId, tra ckInfo.kind, trackInfo.label, trackInfo.language, false);
541 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, th is);
542 videoTracks().add(videoTrack);
543 m_source->mediaElement()->videoTracks().add(videoTrack);
544 } else {
545 videoTrack = findExistingTrackById(videoTracks(), trackInfo.byte StreamTrackId);
546 ASSERT(videoTrack);
547 }
548 trackBase = videoTrack;
549 result[resultIdx++] = videoTrack->trackId();
550 } else {
551 NOTREACHED();
552 } 632 }
553 (void)trackBase; 633
554 #if !LOG_DISABLED 634 if (!tracksMatchFirstInitSegment) {
555 const char* logActionStr = m_firstInitializationSegmentReceived ? "using existing" : "added"; 635 WTF_LOG(Media, "SourceBuffer(%p)::initializationSegmentReceived fail ed: tracks mismatch the first init segment.", this);
556 const char* logTrackTypeStr = (trackInfo.trackType == WebMediaPlayer::Au dioTrack) ? "audio" : "video"; 636 appendError(true);
557 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()); 637 return assignedTrackIds;
558 #endif 638 }
639
640 // 3.2 Add the appropriate track descriptions from this initialization s egment to each of the track buffers.
641 // This is done in Chromium code in stream parsers and demuxer implement ations.
642
643 // 3.3 Set the need random access point flag on all track buffers to tru e.
644 // This is done in Chromium code, see MediaSourceState::OnNewConfigs.
559 } 645 }
560 646
647 // 4. Let active track flag equal false.
648 m_activeTrack = false;
649
650 // 5. If the first initialization segment received flag is false, then run t he following steps:
561 if (!m_firstInitializationSegmentReceived) { 651 if (!m_firstInitializationSegmentReceived) {
562 // 5. If active track flag equals true, then run the following steps: 652 // 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.
563 // 5.1. Add this SourceBuffer to activeSourceBuffers. 653 // This is done in Chromium code, see MediaSourceState::OnNewConfigs.
564 // 5.2. Queue a task to fire a simple event named addsourcebuffer at 654
655 // 5.2 For each audio track in the initialization segment, run following steps:
656 for (const auto& trackInfo : newAudioTracks) {
philipj_slow 2016/04/25 13:03:42 s/auto/MediaTrackInfo/
servolk 2016/04/25 20:29:08 Done.
657 // 5.2.1 Let audio byte stream track ID be the Track ID for the curr ent track being processed.
658 const auto& byteStreamTrackId = trackInfo.byteStreamTrackId;
philipj_slow 2016/04/25 13:03:42 s/auto/WebString/ and I think you could just use c
servolk 2016/04/25 20:29:08 Done (using WebString). We can't use const referen
659 // 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.
660 AtomicString language = trackInfo.language;
661 // 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
662 // audio byte stream track ID and type set to "audio" and assign the value returned by the algorithm to audio language.
663 if (language == "" || language == "und")
philipj_slow 2016/04/25 13:03:42 language.isEmpty() would also cover the case where
servolk 2016/04/25 20:29:08 Done.
664 language = defaultTrackLanguage("audio", byteStreamTrackId);
philipj_slow 2016/04/25 13:03:42 Can you expose audioKeyword() from TrackDefault.cp
servolk 2016/04/25 20:29:08 Done.
665 // 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.
666 AtomicString label = trackInfo.label;
667 // 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
668 // type set to "audio" and assign the value returned by the algorith m to audio label.
669 if (label == "")
670 label = defaultTrackLabel("audio", byteStreamTrackId);
671 // 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.
672 const auto& kind = trackInfo.kind;
673 // 5.2.8.2 Let new audio track be a new AudioTrack object.
674 AudioTrack* audioTrack = AudioTrack::create(byteStreamTrackId, kind, label, language, false);
675 SourceBufferTrackBaseSupplement::setSourceBuffer(*audioTrack, this);
676 assignedTrackIds[resultIdx++] = audioTrack->trackId();
677 // 5.2.8.7 If audioTracks.length equals 0, then run the following st eps:
678 if (audioTracks().length() == 0) {
679 // 5.2.8.7.1 Set the enabled property on new audio track to true .
680 audioTrack->setEnabled(true);
681 // 5.2.8.7.2 Set active track flag to true.
682 m_activeTrack = true;
683 }
684 // 5.2.8.8 Add new audio track to the audioTracks attribute on this SourceBuffer object.
685 // 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.
686 audioTracks().add(audioTrack);
687 // 5.2.8.10 Add new audio track to the audioTracks attribute on the HTMLMediaElement.
688 // 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.
689 m_source->mediaElement()->audioTracks().add(audioTrack);
690 }
691
692 // 5.3. For each video track in the initialization segment, run followin g steps:
693 for (const auto& trackInfo : newVideoTracks) {
694 // 5.3.1 Let video byte stream track ID be the Track ID for the curr ent track being processed.
695 const auto& byteStreamTrackId = trackInfo.byteStreamTrackId;
696 // 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.
697 AtomicString language = trackInfo.language;
698 // 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
699 // video byte stream track ID and type set to "video" and assign the value returned by the algorithm to video language.
700 if (language == "" || language == "und")
701 language = defaultTrackLanguage("video", byteStreamTrackId);
702 // 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.
703 AtomicString label = trackInfo.label;
704 // 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
705 // type set to "video" and assign the value returned by the algorith m to video label.
706 if (label == "")
707 label = defaultTrackLabel("video", byteStreamTrackId);
708 // 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.
709 const auto& kind = trackInfo.kind;
710 // 5.3.8.2 Let new video track be a new VideoTrack object.
711 VideoTrack* videoTrack = VideoTrack::create(byteStreamTrackId, kind, label, language, false);
712 SourceBufferTrackBaseSupplement::setSourceBuffer(*videoTrack, this);
713 assignedTrackIds[resultIdx++] = videoTrack->trackId();
714 // 5.3.8.7 If videoTracks.length equals 0, then run the following st eps:
715 if (videoTracks().length() == 0) {
716 // 5.3.8.7.1 Set the selected property on new audio track to tru e.
717 videoTrack->setSelected(true);
718 // 5.3.8.7.2 Set active track flag to true.
719 m_activeTrack = true;
720 }
721 // 5.3.8.8 Add new video track to the videoTracks attribute on this SourceBuffer object.
722 // 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.
723 videoTracks().add(videoTrack);
724 // 5.3.8.10 Add new video track to the videoTracks attribute on the HTMLMediaElement.
725 // 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.
726 m_source->mediaElement()->videoTracks().add(videoTrack);
727 }
728
729 // 5.4 TODO(servolk): Add text track processing here.
730
731 // 5.5 If active track flag equals true, then run the following steps:
565 // activesourcebuffers. 732 // activesourcebuffers.
566 m_source->setSourceBufferActive(this); 733 if (m_activeTrack) {
734 // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
735 // 5.5.2 Queue a task to fire a simple event named addsourcebuffer a t activeSourceBuffers
736 m_source->setSourceBufferActive(this);
737 }
567 738
568 // 6. Set first initialization segment received flag to true. 739 // 5.6. Set first initialization segment received flag to true.
569 m_firstInitializationSegmentReceived = true; 740 m_firstInitializationSegmentReceived = true;
570 } 741 }
571 742
572 return result; 743 return assignedTrackIds;
573 } 744 }
574 745
575 bool SourceBuffer::hasPendingActivity() const 746 bool SourceBuffer::hasPendingActivity() const
576 { 747 {
577 return m_source; 748 return m_source;
578 } 749 }
579 750
580 void SourceBuffer::suspend() 751 void SourceBuffer::suspend()
581 { 752 {
582 m_appendBufferAsyncPartRunner->suspend(); 753 m_appendBufferAsyncPartRunner->suspend();
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 visitor->trace(m_removeAsyncPartRunner); 1121 visitor->trace(m_removeAsyncPartRunner);
951 visitor->trace(m_appendStreamAsyncPartRunner); 1122 visitor->trace(m_appendStreamAsyncPartRunner);
952 visitor->trace(m_stream); 1123 visitor->trace(m_stream);
953 visitor->trace(m_audioTracks); 1124 visitor->trace(m_audioTracks);
954 visitor->trace(m_videoTracks); 1125 visitor->trace(m_videoTracks);
955 EventTargetWithInlineData::trace(visitor); 1126 EventTargetWithInlineData::trace(visitor);
956 ActiveDOMObject::trace(visitor); 1127 ActiveDOMObject::trace(visitor);
957 } 1128 }
958 1129
959 } // namespace blink 1130 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/modules/mediasource/SourceBuffer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698