Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add ios support for accessing WebVTT Subtitle Content #3541

Merged

Conversation

coofzilla
Copy link
Contributor

📝 Summary

This PR adds the capability to access and expose the content of subtitles within RN; but, currently only implements the ios portion. The core of this functionality leverages AVFoundation framework's AVPlayerItemLegibleOutput, enabling the app to intercept subtitle data as attributed strings during video playback. This data is subsequently passed to do the RN layer through the newly introduced event, onSubtitleTracks; thus, allowing components to reactively update based on this subtitle content.

Motivation

Our motivation for integrating the onSubtitleTracks event handler with react-native-video is to enhance user engagement with HLS VODs of sports content. Utilizing WebVTT tracks, we aim to dynamically display game information like scores as overlays on the video, based on the playback position. This feature ensures viewers have access to contextual sports data as they navigate through the video, significantly improving their viewing experience by making it more informative and interactive. This implementation aligns with the capabilities of the WebVTT API, optimizing our app's use of text tracks for an enriched sports viewing experience.

The primary purpose of WebVTT files is to add text overlays to a <video>

source

Changes

📲 iOS Implementation:

  • RCTPlayerObserver class implements AVPlayerItemLegibleOutputPushDelegate to observe and handle subtitle tracks.
  • Configured legibleOutput on the player item and set the current class as the delegate to manage legible output.
  • Implemented the legibleOutput delegate method to capture subtitle data, processing it via the handleLegibleOutput method to extract and utilize subtitle strings.

🌉 RN Bridge:

  • Added an @objc property onSubtitleTracks to facilitate event emission, enabling the RN layer to receive subtitle data.
  • Implemented method handleLegibleOutput to handle attributed strings from subtitles, triggering the onSubtitleTracks event with the subtitle text for consumption within RN components.

🥳 RN Layer

  • Exposed the onSubtitleTracks property.

Example:

const App = () => {
  const handleSubtitleTracks = useCallback((e: OnSubtitleTracksData) => {
    console.log('Subtitles:', e.subtitleTracks);
  }, []);

  return (
    <Video
      source={{ uri: 'video-url.mp4' }} // Replace 'video-url.mp4' with your video source
      onSubtitleTracks={handleSubtitleTracks} // new event handler
      // Other props for the Video component
    />
  );
};

📄 Docs

  • updated events.md to include a description aligned with current standards.

Test plan

✅ Tested in example app with uri included in this PR

Set the tracks you want to use, for my demo I used the below; however, SelectedTrackType.LANGUAGE also works. For my actual use-case, we'll be using TITLE so I wanted to make sure that worked.

  • Apply following changes to test in example app:
// VideoPlayer.tsx

    // selectedTextTrack={this.state.selectedTextTrack}
    selectedTextTrack={{
      type: SelectedTrackType.TITLE,
      value: 'English',
    }}

Comment out this line; due to textTracks being undefined, I believe it has to do with how data.textTracks is being set; but, I didn't want to address that on this PR as its a separate issue.

// VideoPlayer.tsx
  {/* {this.state.textTracks.map(track => (
    <Picker.Item
      label={track.language}
      value={track.language}
      key={track.language}
    />
  ))} */}

Comment out this line for the app to build( I believe this is a known issue):

// metro.config.js

// /(.*\/react-native-video\/node_modules\/.*)$/,

Demo of how it works:

demo.mp4

Push the parsing/formatting to the consumer side.
…Tracks

added optional chaining for `return x?.selected` because tracks that don't have a track selected either by default or manually will return undefined and this can cause an error.
@coofzilla coofzilla changed the title Feat/subtitle event handler Feat: Add ios support for accessing WebVTT Subtitle Content Feb 23, 2024
@freeboub
Copy link
Collaborator

few comments, but looks good !
on android I think the code shall be in onCue function if you want to implement it.

docs/pages/component/events.md Outdated Show resolved Hide resolved
docs/pages/component/events.md Outdated Show resolved Hide resolved
docs/pages/component/events.md Show resolved Hide resolved
examples/basic/src/VideoPlayer.tsx Outdated Show resolved Hide resolved
examples/basic/src/VideoPlayer.tsx Show resolved Hide resolved
@coofzilla
Copy link
Contributor Author

few comments, but looks good ! on android I think the code shall be in onCue function if you want to implement it.

Thank you for the feedback 🙏🏽! I'll take a look at the android implementation once I get this merged 😄 I'm going to apply the requested changes here shortly

Renamed the onSubtitleTracks event to onTextTrackDataChanged across the codebase to clearly indicate the callback's purpose: being called when the text track's data changes. This change is reflected in the events documentation, example usage in VideoPlayer.tsx, and the relevant iOS implementation files for consistency and clarity, in line with PR feedback.
@coofzilla
Copy link
Contributor Author

All feedback has been addressed :)

I've also tested it again in the sample app.
image

src/Video.tsx Outdated Show resolved Hide resolved
Copy link
Member

@KrzysztofMoch KrzysztofMoch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thank you very much 👍
Let's wait for @freeboub review (this may take some time, for what I know he's busy lately)

target could be confusing for users so we have removed it. using the delete operator instead of using {target,...eventData} as that would give an eslint error about unused vars.
@coofzilla
Copy link
Contributor Author

LGTM, Thank you very much 👍 Let's wait for @freeboub review (this may take some time, for what I know he's busy lately)

Awesome, happy to help! Excited to get this merged in 😊

@coofzilla
Copy link
Contributor Author

@KrzysztofMoch any other blockers I need to take care of to get this merged? 😅

@KrzysztofMoch KrzysztofMoch merged commit 253ffb5 into TheWidlarzGroup:master Feb 29, 2024
8 checks passed
@KrzysztofMoch
Copy link
Member

No 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants