static int textTrackSelectionScore(const TextTrack& track) { if (track.kind() != TextTrack::captionsKeyword() && track.kind() != TextTrack::subtitlesKeyword()) return 0; return textTrackLanguageSelectionScore(track); }
void AutomaticTrackSelection::perform(TextTrackList& textTracks) { TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles); TrackGroup descriptionTracks(TrackGroup::Description); TrackGroup chapterTracks(TrackGroup::Chapter); TrackGroup metadataTracks(TrackGroup::Metadata); for (size_t i = 0; i < textTracks.length(); ++i) { TextTrack* textTrack = textTracks.item(i); if (!textTrack) continue; String kind = textTrack->kind(); TrackGroup* currentGroup; if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) { currentGroup = &captionAndSubtitleTracks; } else if (kind == TextTrack::descriptionsKeyword()) { currentGroup = &descriptionTracks; } else if (kind == TextTrack::chaptersKeyword()) { currentGroup = &chapterTracks; } else { ASSERT(kind == TextTrack::metadataKeyword()); currentGroup = &metadataTracks; } if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::showingKeyword()) currentGroup->visibleTrack = textTrack; if (!currentGroup->defaultTrack && textTrack->isDefault()) currentGroup->defaultTrack = textTrack; // Do not add this track to the group if it has already been automatically configured // as we only want to perform selection once per track so that adding another track // after the initial configuration doesn't reconfigure every track - only those that // should be changed by the new addition. For example all metadata tracks are // disabled by default, and we don't want a track that has been enabled by script // to be disabled automatically when a new metadata track is added later. if (textTrack->hasBeenConfigured()) continue; if (textTrack->language().length()) currentGroup->hasSrcLang = true; currentGroup->tracks.append(textTrack); } if (captionAndSubtitleTracks.tracks.size()) performAutomaticTextTrackSelection(captionAndSubtitleTracks); if (descriptionTracks.tracks.size()) performAutomaticTextTrackSelection(descriptionTracks); if (chapterTracks.tracks.size()) performAutomaticTextTrackSelection(chapterTracks); if (metadataTracks.tracks.size()) enableDefaultMetadataTextTracks(metadataTracks); }
Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTrackList* trackList) { ASSERT(trackList); Vector<RefPtr<TextTrack>> tracksForMenu; for (unsigned i = 0, length = trackList->length(); i < length; ++i) { TextTrack* track = trackList->item(i); const AtomicString& kind = track->kind(); if (kind == TextTrack::captionsKeyword() || kind == TextTrack::descriptionsKeyword() || kind == TextTrack::subtitlesKeyword()) tracksForMenu.append(track); } std::sort(tracksForMenu.begin(), tracksForMenu.end(), [](const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b) { return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0; }); tracksForMenu.insert(0, TextTrack::captionMenuOffItem()); tracksForMenu.insert(1, TextTrack::captionMenuAutomaticItem()); return tracksForMenu; }
void AutomaticTrackSelection::performAutomaticTextTrackSelection(const TrackGroup& group) { ASSERT(group.tracks.size()); // First, find the track in the group that should be enabled (if any). HeapVector<Member<TextTrack>> currentlyEnabledTracks; TextTrack* trackToEnable = nullptr; TextTrack* defaultTrack = nullptr; TextTrack* preferredTrack = nullptr; TextTrack* fallbackTrack = nullptr; int highestTrackScore = 0; for (size_t i = 0; i < group.tracks.size(); ++i) { TextTrack* textTrack = group.tracks[i]; if (m_configuration.disableCurrentlyEnabledTracks && textTrack->mode() == TextTrack::showingKeyword()) currentlyEnabledTracks.append(textTrack); int trackScore = textTrackSelectionScore(*textTrack); if (textTrack->kind() == preferredTrackKind()) trackScore += 1; if (trackScore) { // * If the text track kind is subtitles or captions and the user has indicated an interest in having a // track with this text track kind, text track language, and text track label enabled, and there is no // other text track in the media element's list of text tracks with a text track kind of either subtitles // or captions whose text track mode is showing // Let the text track mode be showing. if (trackScore > highestTrackScore) { preferredTrack = textTrack; highestTrackScore = trackScore; } if (!defaultTrack && textTrack->isDefault()) defaultTrack = textTrack; if (!fallbackTrack) fallbackTrack = textTrack; } else if (!group.visibleTrack && !defaultTrack && textTrack->isDefault()) { // * If the track element has a default attribute specified, and there is no other text track in the media // element's list of text tracks whose text track mode is showing or showing by default // Let the text track mode be showing by default. defaultTrack = textTrack; } } if (m_configuration.textTrackKindUserPreference != TextTrackKindUserPreference::Default) trackToEnable = preferredTrack; if (!trackToEnable && defaultTrack) trackToEnable = defaultTrack; if (!trackToEnable && m_configuration.forceEnableSubtitleOrCaptionTrack && group.kind == TrackGroup::CaptionsAndSubtitles) { if (fallbackTrack) trackToEnable = fallbackTrack; else trackToEnable = group.tracks[0]; } if (currentlyEnabledTracks.size()) { for (size_t i = 0; i < currentlyEnabledTracks.size(); ++i) { TextTrack* textTrack = currentlyEnabledTracks[i]; if (textTrack != trackToEnable) textTrack->setMode(TextTrack::disabledKeyword()); } } if (trackToEnable) trackToEnable->setMode(TextTrack::showingKeyword()); }
static v8::Handle<v8::Value> kindAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { TextTrack* imp = V8TextTrack::toNative(info.Holder()); return v8String(imp->kind(), info.GetIsolate()); }
void MediaControlClosedCaptionsTrackListElement::rebuildTrackListMenu() { #if ENABLE(VIDEO_TRACK) // Remove any existing content. removeChildren(); m_menuItems.clear(); m_trackListHasChanged = false; if (!mediaController()->hasClosedCaptions()) return; HTMLMediaElement* mediaElement = toParentMediaElement(this); if (!mediaElement) return; TextTrackList* trackList = mediaElement->textTracks(); if (!trackList || !trackList->length()) return; Document* doc = document(); RefPtr<Element> captionsSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION); RefPtr<Element> captionsHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION); captionsHeader->appendChild(doc->createTextNode(textTrackClosedCaptionsText())); captionsSection->appendChild(captionsHeader); RefPtr<Element> captionsMenuList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION); RefPtr<Element> subtitlesSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION); RefPtr<Element> subtitlesHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION); subtitlesHeader->appendChild(doc->createTextNode(textTrackSubtitlesText())); subtitlesSection->appendChild(subtitlesHeader); RefPtr<Element> subtitlesMenuList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION); RefPtr<Element> trackItem; trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION); trackItem->appendChild(doc->createTextNode(textTrackOffText())); trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION); captionsMenuList->appendChild(trackItem); m_menuItems.append(trackItem); trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION); trackItem->appendChild(doc->createTextNode(textTrackOffText())); trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION); subtitlesMenuList->appendChild(trackItem); m_menuItems.append(trackItem); bool hasCaptions = false; bool hasSubtitles = false; for (unsigned i = 0, length = trackList->length(); i < length; ++i) { TextTrack* track = trackList->item(i); trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION); // Add a custom attribute to the <li> element which will allow // us to easily associate the user tapping here with the // track. Since this list is rebuilt if the tracks change, we // should always be in sync. trackItem->setAttribute(trackIndexAttributeName(), String::number(i), ASSERT_NO_EXCEPTION); AtomicString labelText = track->label(); if (labelText.isNull() || labelText.isEmpty()) labelText = displayNameForLanguageLocale(track->language()); if (labelText.isNull() || labelText.isEmpty()) labelText = textTrackNoLabelText(); trackItem->appendChild(doc->createTextNode(labelText)); if (track->kind() == track->captionsKeyword()) { hasCaptions = true; insertTextTrackMenuItemIntoSortedContainer(trackItem, captionsMenuList); } if (track->kind() == track->subtitlesKeyword()) { hasSubtitles = true; insertTextTrackMenuItemIntoSortedContainer(trackItem, subtitlesMenuList); } m_menuItems.append(trackItem); } captionsSection->appendChild(captionsMenuList); subtitlesSection->appendChild(subtitlesMenuList); if (hasCaptions) appendChild(captionsSection); if (hasSubtitles) appendChild(subtitlesSection); updateDisplay(); #endif }