as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持
跳转到主要内容
With Vega, you can render up to four video streams concurrently in a single app. Multi-stream playback supports the following use cases:
  • Sports multi-camera views
  • Security camera dashboards
  • Picture-in-picture (PIP) layouts
  • Side-by-side video comparison

Prerequisites

Set up your app to use the W3C Media Player. For more information, see Media Player Setup.

Surface and player

Video playback on Vega uses two parts of the W3C Media API, both exported from @amazon-devices/react-native-w3cmedia:
  • KeplerVideoSurfaceView: A React Native component that creates a rendering surface. It doesn’t manage playback.
  • VideoPlayer: An imperative class that handles initialization, source loading, and playback control. You connect it to the surface with a handle.

Architecture

The player and the rendering surface are independent objects. You create both separately, then connect them with a surface handle after the surface is ready.

Add the dependency

Open the package.json file in your app. In the dependencies section, add the following entry.

Configure the manifest

Video playback requires declaring media service dependencies and privileges in your manifest.toml file. Without these, the media pipeline doesn’t initialize, and surfaces render black.

Layout examples

Render a single video stream

The following example defines a VideoPane component that renders one video stream.

Side-by-side layout

The following example renders two streams of equal width.

Grid layout with four streams

The following example renders four concurrent streams in a two-by-two grid.

Picture-in-picture layout

The following example renders a smaller stream over a full-screen stream.

Playback controls

The following example adds play, pause, and seek controls to a single pane.

Complete side-by-side example

The following example is a complete App.tsx file that renders two video streams side by side.

Limitations and best practices

Supported content

  • Clear content without digital rights management (DRM): up to four concurrent streams
  • DRM content: one stream at a time, because Fire TV devices based on Vega provide a single secure video decoder instance

Performance considerations

  • Each stream consumes GPU memory and decode resources
  • Vega Virtual Device supports four concurrent non-DRM streams using software decoding

Best practices

  • Stagger stream initialization to prevent resource contention.
  • Handle errors for each stream separately, so that one failed stream doesn’t crash the entire layout.
  • Use a distinct URL for each stream, rather than decoding the same source four times.
  • Call clearSurfaceHandle('') and pause() in the useEffect() cleanup function to release resources when the component unmounts.
  • Wait for onSurfaceViewCreated() before you call setSurfaceHandle().

Stagger stream initialization

Calling initialize() on all four players at the same time causes resource contention. The following example adds an initDelay prop to VideoPane and staggers initialization by 500 milliseconds.

Troubleshooting

The following table describes common multi-stream playback problems and their solutions.

Test on Vega Virtual Device

You can validate multi-stream playback on Vega Virtual Device. Vega Virtual Device supports four concurrent non-DRM streams with VideoPlayer and KeplerVideoSurfaceView.

Build and run from the command line

  1. At the command prompt, build the app.
  2. Run the app on the connected Vega Virtual Device. The following example targets a Mac M-series machine. Replace the architecture in the path with the one that matches your development machine, and replace the app ID with the one from your manifest.toml file.
    For more information about build output paths and architecture-specific commands, see Run Your App.

Build and run from Vega Studio

  • To build and run your app, choose Run in Vega Studio.

Proposed sample changes for review

The examples in the body of this page are unchanged from the versions supplied by the media player team. The following items are proposed changes and open questions raised during the documentation review. Each one needs testing and confirmation before it goes into the page.

Question 1 — Is clearSurfaceHandle('') correct?

Every cleanup function in this page calls clearSurfaceHandle('') with an empty string. The API reference for clearSurfaceHandle documents the parameter as “The surface handle returned by onSurfaceViewCreated event emitted by KeplerVideoSurfaceView component” — not an empty string. The client-side ad insertion documentation passes the cached handle instead. For details, see Implement client-side ad insertion with the JS approach.
Questions for the team:
  1. Does clearSurfaceHandle('') release the surface, or is it a no-op?
  2. If it’s a no-op, does the surface leak until the VideoPlayer instance is garbage collected?
  3. Could this explain the “Only two streams render, and the others are black” symptom in the Troubleshooting table?
If passing the real handle is required, each example needs to cache the handle from onSurfaceViewCreated so the cleanup function can pass it. The following example shows the proposed change to VideoPane.

Question 2 — Should the examples call deinitialize()?

The cleanup functions call pause() but never deinitialize(). General requirements for media apps states that apps must release media resources, and that releasing happens by deinitializing VideoPlayer. The appstore certification requirements depend on this. Questions for the team:
  1. Should each pane call await player.deinitialize() on unmount?
  2. Because deinitialize() returns a Promise<void> and a useEffect() cleanup function can’t await, is deinitializeSync(timeoutInMs) the correct call in this position? What timeout value do you recommend?
  3. With four concurrent players, does deinitializing them at the same time cause the same resource contention that initialization does?

Question 3 — The playback controls example exposes nothing

In the Playback controls example, play, pause, and seek are declared but never returned or called. As written, the component renders a surface and the three controls are unreachable from any parent component. TypeScript also reports them as unused locals. The following example is a proposed replacement that exposes the controls with forwardRef() and useImperativeHandle(). This pattern already appears in Vega Carousel.
Questions for the team:
  1. Is useImperativeHandle() the pattern you want to recommend, or would you rather the example show on-screen controls with D-pad focus handling?
  2. Is currentTime += seconds the correct way to seek, or is there a seek API that handles clamping at the start and end of the stream?

Question 4 — Is KeplerVideoSurfaceView the right component?

The API reference describes KeplerVideoSurfaceView and KeplerShareableSurfaceView with identical text: “Use this component only when operating in pre-buffering mode using the VideoPlayer component, where more than one player can be pre-buffered simultaneously with different contents.” Questions for the team:
  1. What’s the difference between KeplerVideoSurfaceView and KeplerShareableSurfaceView, and which one should multi-stream apps use?
  2. The reference says to use these components “only when operating in pre-buffering mode.” Do the examples in this page operate in pre-buffering mode? If pre-buffering is a precondition, the page needs to say so and show how to enable it.

Question 5 — What are the real concurrent stream limits?

The page states four concurrent streams in three places. Every source found for that number describes Vega Virtual Device with software decoding. Questions for the team:
  1. How many concurrent clear streams do Fire TV Stick devices based on Vega support? Is it four, or is four specific to the virtual device?
  2. General requirements for media apps states that the first Fire TV based on Vega supports only one secure video decoder instance. The DRM warning at the top of this page is based on that. Is that still accurate for the current hardware?
  3. Does the four-stream limit vary by resolution? For example, is four streams at 1080p equivalent to one at 4K?

Question 6 — Confirm the staggered initialization delay

The Stagger stream initialization example uses 500 millisecond increments, for a total of 1.5 seconds before the fourth stream starts initializing. Questions for the team:
  1. Is 500 milliseconds a measured value or a placeholder?
  2. Is there a deterministic alternative, such as awaiting each initialize() in sequence, that avoids a fixed delay?

Question 7 — Build and run commands need validation

The changes below are a best guess from the surrounding documentation, and the team needs to confirm or correct them against the actual toolchain. The content as supplied told developers to run npx react-native build-kepler --build-type Release --target aarch64 in the Troubleshooting table and vega run-app build/aarch64-release/<your-app-name>_aarch64.vpkg in the Test on Vega Virtual Device steps. What was changed, and why:
  1. build-kepler changed to build-vega. build-kepler is the legacy command name. Vega CLI tools documents npx react-native build-vega for React Native Vega apps, and the build-kepler occurrences elsewhere in the 0.24 documentation describe the name rather than instruct it, such as Vega Studio console output and a troubleshooting entry titled “Unrecognized command build-kepler.”
  2. --target aarch64 was dropped. The flag appears with build-vega nowhere in the 0.24 documentation. The documented flags are --build-type, --build-version, and --build-number. Build Your App shows a single build producing aarch64-release, x86_64-release, and armv7-release output folders, so a target flag doesn’t appear to be needed.
  3. The run command gained an app ID and -d VirtualDevice. Vega CLI tools gives the signature as vega run-app <Vpkg path> <App ID> -d <device>, and every other 0.24 example supplies both. As supplied, the command omitted both.
Why this still needs validation: the 0.24 documentation doesn’t agree with itself about how a React Native app is built, and the three forms aren’t reconciled anywhere:
  • Vega CLI tools says to use npx react-native build-vega directly, and notes that vega build exists but isn’t for React Native apps.
  • Build Your App — the primary build page — gives npm run build:app in its Vega CLI path and never mentions build-vega. About Vega Headless Tasks and Services shows build:app resolving to build-vega --build-type Release and --build-type Debug, so the npm script is presumably a wrapper. That indirection is never stated on the build page.
  • Step 1: Dependency Updates says @amazon-devices/kepler-cli-platform registers the vega build command, and that removing @react-native-community/cli makes npm run build:release fail with “Unrecognized command vega build” — which implies the React Native npm scripts invoke vega build, contradicting the Vega CLI tools page.
Questions for the team:
  1. What is the current, correct way to build a React Native for Vega app from the command line: npx react-native build-vega, npm run build:app, or vega build? Are build-vega and vega build the same command under two names, or two different commands?
  2. Should this page instruct a raw build-vega invocation at all, or should it match Build Your App and use npm run build:app, which is what a developer following the getting-started path will already have?
  3. Does build-vega accept a --target flag? If it does, is a target needed here, or does one build produce every architecture?
  4. Confirm the vega run-app invocation, including whether the app ID pattern com.amazondeveloper.<your-app-name>.main matches the manifest.toml file that ships with the sample.
  5. Does the “App crashes on launch” entry describe a real, reproducible failure? The original wording attributed vega build to native C++ and Rust development. That claim was removed because no native development path is documented for Vega, and Rust appears nowhere else in this documentation set. The entry now says only that vega build isn’t supported for React Native and produces an incomplete package. Confirm that this is accurate and that an incomplete package is what causes the crash. Note that this entry’s premise depends on the first question in this list: if the npm scripts invoke vega build under the hood, then “you used vega build” can’t be the cause of the crash.
Note: the samples on this page were presumably built and tested with build-kepler. Whichever command is correct, they need a rebuild against it before this page publishes.
最后修改于 2026年7月31日