You can use intelligent production to preview the timeline of an online editing project. To preview the timeline, integrate the preview component by adding the corresponding file to the HTML document. This topic describes how to integrate the preview component that is provided in the video editing SDK for web.
Usage notes
In this topic, the video editing SDK for web V5.2.2 is used. Before you use the video editing SDK for web V5.0.0 or later, you must apply for a license. For information about the latest version of the video editing SDK for web, see the note on the Video Editing Projects tab in the Intelligent Media Services (IMS) console.
Procedure
Integrate the preview component.
Import the CSS file of the preview component under the
<head>tag in the HTML document of the project.<head> <link rel="stylesheet" href="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/player.css"> </head>Under the
<body>tag, add a<div>node that is used to mount the preview window, import the JavaScript file of the video editing SDK for web, and then add a<script>node that is used to call the video editing SDK for web.<body> <div id="player-wrapper" style="height:500px"></div> // Change the height of the container based on your business requirements. <script src="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/player.js"></script> <script> // Place the code that is used to call the video editing SDK for web here. </script> </body>Initialize the preview component.
const player = new window.AliyunTimelinePlayer({ container: document.querySelector('#player-wrapper'), licenseConfig: { rootDomain: "", // The root domain name used by the license. Example: abc.com. licenseKey: "", // The applied license key. If a license key is not configured, watermarks appear when you preview a video under the localhost domain name. }, timeline: { // Optional. VideoTracks: [], // Specify video tracks. AudioTracks: [], // Specify audio tracks. AspectRatio: '16:9', }, getMediaInfo: (mediaId) => { return Promise.resolve('https://example.com/url/for/this/media.mp4'); }, });The following section describes the parameters that you need to configure in
PlayerInitConfigwhen you callnew window.AliyunTimelinePlayer(PlayerInitConfig)to initialize the preview component:interface PlayerInitConfig { licenseConfig?: { rootDomain?: string; licenseKey?: string; }; // The license configurations. getTimelineMaterials?: (params: TimelineMaterial[]) => Promise<InputMedia[]>; // The media asset material in the timeline. mode?: 'component' | 'player'; // The style of the player component. The component is a pure component. componentClass?: string; container: Element; // The container of the preview component. The value is an HTML element. locale?: Locales; // The language of the user interface (UI). Valid values: zh-CN and en-US. Default value: zh-CN. controls?: boolean; // Specifies whether to display the control bar at the bottom of the view. Default value: true. timeline?: AliyunTimeline; // The timeline object generated by the video editing SDK for web. The timeline is different from the timeline that is generated by calling an API operation. playbackRate?: number; // The playback speed after the preview component is initialized. Default value: 1. The value range of this parameter varies based on the playbackRate configuration of the browser. aspectRatio?: string; // The aspect ratio of the video after the preview component is initialized. Default value: 16:9. You can specify a custom aspect ratio in the width:height format. We recommend that you use the aspect ratio that you specified for AliyunTimeline. minWidth?: number | string; // The minimum width of the player. customFontList?: CustomFontItem[]; // The custom fonts. getMediaInfo?: ( mediaId: string, mediaType: MediaType, mediaOrigin?: MediaOrigin | undefined, inputUrl?: string | undefined, ) => Promise<string | DynamicSrcObj>; }// Similar to the getDynamicSrc method that is used when you integrate the video editing SDK for web, you can obtain the signed playback URL from mediaId. For more information about the getDynamicSrc method, see the "Integrate the video editing SDK for web" topic.The following section describes the methods that are defined in the
AliyunTimelinePlayerclass:class AliyunTimelinePlayer { static getSubtitleEffectColorStyles(): Array<{ key: string; cover: string; }>; // Obtain the list of word art effects. static getSubtitleBubbles(): Array<{ key: string; cover: string; }>;// Obtain the list of bubble effects. static setDefaultLocale(locale?: Locales): void; // Specify the default language. static getDefaultFontList(): CustomFontItem[]; // Obtain the list of default fonts. static getVideoEffects(): Array<{ subType: string; cover: string; name: string; title: string; category: string | undefined; }>; // Obtain the list of special effects. static getVideoFilters(): Array<{ subType: string; cover: string; name: string; title: string; category: string | undefined; }>;// Obtain the list of filters. static getVideoTransitions(): Array<{ subType: string; cover: string; name: string; title: string; category: string | undefined; }>;// Obtain the list of transitions. static parseTimeline( timeline: string | IServerTimeline, // Specify the size of the canvas. In most cases, the Width and Height values of the FECanvas field in the timeline are used. options: { outputWidth: number; outputHeight: number } = { outputWidth: 800, outputHeight: 450 }, ):ParsedResult; // Convert the timeline in the backend to a timeline in the frontend for preview. constructor(config: PlayerInitConfig); play(): void; // js Start playback. pause(): void; // js Pause playback. destroy(): void; // Destroy the instance. on(eventName: string, callback: Function): any; // Listen to events. once(eventName: string, callback: Function): any; // Listen to an event only once. off(eventName: string): any; // Stop listening to events. get event$(): IObservable<EventData<any>>; // Query the event stream. You can obtain all events by subscribing to the event stream. For more information, see RxJS subscription logic. get version(): string | undefined; // Query the version. get duration(): number;// Query the duration. get timeline(): any;// Query the current timeline. set timeline(timeline: any); // Configure the current timeline. // Query the width of the scene, which can be used to calculate the absolute values of the x-coordinate and y-coordinate. This method works only for the video editing SDK for web V5.2.2 and later. get stageWidth(): number; // Query the height of the scene, which can be used to calculate the absolute values of the x-coordinate and y-coordinate. This method works only for the video editing SDK for web V5.2.2 and later. get stageHeight(): number; // Configure automatic parsing of the timeline. This method works only for the video editing SDK for web V5.2.2 and later. setTimeline(timeline: any, autoParse?: boolean): Promise<void>; get currentTime(): number;// Query the playback progress. set currentTime(currentTime: number); // Set the playback progress. get controls(): boolean; // Query the display state of the current control. set controls(show: boolean); // Hide the current control. get aspectRatio(): string; // Query the aspect ratio of the current component. set aspectRatio(ratio: string); // Specify the aspect ratio of the current component, such as 16:9. get playbackRate(): number; // Query the playback speed. set playbackRate(speed: number); // Set the playback speed. setFontList(value: CustomFontItem[]): Promise<void>; // Configure custom fonts. // Monitor track data changes. This method works only for the video editing SDK for web V5.2.2 and later. watchTrack(handler?: (tracks: ExportTrack[]) => void): () => void; // Deletes the current track. This method works only for the video editing SDK for web V5.2.2 and later. removeTrack(id: number): void; // Configure track attributes. This method works only for the video editing SDK for web V5.2.2 and later. setTrack(id: number, options: { visible?: boolean; mainTrack?: boolean; }): void; // Add a track. This method works only for the video editing SDK for web V5.2.2 and later. addTrack(track: {id: number;type: TrackType; clips: ExportClip[];visible: boolean;mainTrack?: boolean;} ): void; // Delete a material in the track. This method works only for the video editing SDK for web V5.2.2 and later. removeClip(id: number): void; // Query the detailed configurations of a material in the track. This method works only for the video editing SDK for web V5.2.2 and later. getClip(id: number): ServerClip; // Add a material in the track. This method works only for the video editing SDK for web V5.2.2 and later. addClip(clip: ServerClip): void; // Set the start point of a material. This method works only for the video editing SDK for web V5.2.2 and later. setClipTimelineIn(id: number, timelineIn: number): void; // Set the end point of a material. This method works only for the video editing SDK for web V5.2.2 and later. setClipTimelineOut(id: number, timelineOut: number): void; // Update a material. This method works only for the video editing SDK for web V5.2.2 and later. updateClip(id: number, handle: (clip: ServerClip) => ServerClip): void; // Monitor material changes. This method works only for the video editing SDK for web V5.2.2 and later. watchClip(id: number, handle: (clip: ServerClip | null) => void): () => void; // Convert to a timeline in the backend. This method works only for the video editing SDK for web V5.2.2 and later. toBackendTimeline(): { duration: number; timeline: any; }; // Query tracks. This method works only for the video editing SDK for web V5.2.2 and later. queryTracks(handler: (track: ExportTrack) => boolean): ExportTrack[]; // Query materials. This method works only for the video editing SDK for web V5.2.2 and later. queryClips(handler: (clip: ExportClip, track: ExportTrack) => boolean): ExportClip[]; // Highlight a material so that the material can move freely. This method works only for the video editing SDK for web V5.2.2 and later. focusClip(id: number, autoSeek?: boolean): void; // Cancel the highlighting of the material. This method works only for the video editing SDK for web V5.2.2 and later. blurClip(): void; } // The clip material exported from the watchTrack method. You can call the getClip method to query the attributes of the clip material. interface ExportClip { id: number; type: MaterialType; timelineIn: number; timelineOut: number; } // The track exported from the watchTrack method. interface ExportTrack { id: number; type: TrackType; clips: ExportClip[]; visible: boolean; mainTrack?: boolean; } // A custom font. interface CustomFontItem { key: string; // The unique identifier of the font. name?: string; // The display name of the font. url: string; // The URL of the font. urlType?: 'dynamic' | 'static'; // If the font URL needs to be dynamically obtained by calling the getMedinfo method, set this parameter to dynamic. Otherwise, set this parameter to static. } // The player status. enum PLAYER_STATE { PLAYING = 0, PAUSED = 1, STALLED = 2, ENDED = 3, BROKEN = 4 } // The parsing result of the timeline in the frontend. interface ParsedResult { success: boolean; // Indicates whether the parsing is successful. logs: any[]; timeline: IServerTimeline; // The timeline parsing result. toBackendTimeline: (fTimeline: IServerTimeline) => IServerTimeline; // Convert the timeline in the frontend to a timeline in the server. mediaMap: ParsedMediaMap; output: { width: number; height: number; }; fontList: Array<{ key: string; url: string }>; } type ParsedMediaMap = { [key: string]: { mediaType: string; mediaId: string; mediaUrl?: string; width?: number; height?: number; duration: number; }; } type InputMedia = (InputVideo | InputAudio | InputImage); interface InputVideo { mediaId: string; mediaIdType?: MediaIdType; mediaType: 'video'; video: { duration: number; }; } interface InputAudio { mediaId: string; mediaIdType?: MediaIdType; mediaType: 'audio'; audio: { duration: number; }; } interface InputImage { mediaId: string; mediaIdType?: MediaIdType; mediaType: 'image'; image: { coverUrl?: string; }; } type MediaIdType = 'mediaId' | 'mediaURL';
Destroy the instance.
Call the
destroymethod to destroy the instance. After the instance is destroyed, the container parameter is empty.player.destroy();
Sample code
The following sample code provides an example on how to create a timeline-based preview player with custom fonts, transitions, and effects, in which you can edit subtitles.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/player.css"
/>
<script src="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/player.js"></script>
<title>Online editing preview player</title>
</head>
<body>
<div id="root" style="width: 820px;margin: 30px auto;" >
<div id="player" style="width: 800px; height: 450px"></div>
<div style="margin-top: 16px">
<div>
<label>ID</label> <br/>
<input id="subtitle" value="123" />
<br/>
<label>Content</label> <br/>
<textarea id="content" rows="4" >Custom subtitles</textarea>
</div>
<button id="addSubtitle">Add subtitles</button>
<button id="updateSubtitle">Modify subtitles</button>
<button id="moveSubtitle">Move subtitles</button>
<button id="removeSubtitle">Delete subtitles</button>
</div>
</div>
<script type="text/javascript">
const timelineDemo = {
Version: 1,
SdkVersion: "4.12.2",
VideoTracks: [
{
// The video track.
Id: 1,
Type: "Video",
Visible: true,
Disabled: false,
Count: 1,
VideoTrackClips: [
{
// The image.
Id: 3,
TrackId: 1,
Type: "Image",
MediaURL:
"https://img.alicdn.com/imgextra/i4/O1CN01TDN7Gw1SCgVv61T4s_!!6000000002211-0-tps-1920-1046.jpg",
Title: "test.png",
X: 0,
Y: 0,
Width: 1,
Height: 1,
TimelineIn: 0,
TimelineOut: 5,
Duration: 5,
VirginDuration: 5,
},
{
// The video.
Id: 4,
TrackId: 1,
Type: "Video",
MediaURL:
"https://ice-pub-media.myalicdn.com/vod-demo/%E6%9C%80%E7%BE%8E%E4%B8%AD%E5%9B%BD%E7%BA%AA%E5%BD%95%E7%89%87-%E6%99%BA%E8%83%BD%E5%AD%97%E5%B9%95.mp4",
X: 0,
Y: 0,
Width: 1,
Height: 1,
TimelineIn: 4, // The start point of the transition must be before the end point of the previous material.
TimelineOut: 9,
Duration: 5,
VirginDuration: 5,
Effects: [
{
// The transition.
Type: "Transition",
Id: 13,
Name: "transitions.directional",
SubType: "directional",
Duration: 1, // Duration of the transition = End point of the previous material - Start point of the current material
From: 3, // The ID of the previous material.
},
],
},
],
},
{
// The effect track.
Id: 2,
Type: "Effect",
Visible: true,
Disabled: false,
Count: 1,
VideoTrackClips: [
{
Type: "VFX",
Id: 2,
TrackId: 1,
SubType: "heartfireworks",
TimelineIn: 0,
TimelineOut: 5,
Duration: 5,
X: 0,
Y: 0,
Width: 0,
Height: 0,
},
],
},
],
AudioTracks: [],
SubtitleTracks: [
{
Id: 2,
Type: "Text",
Visible: true,
Disabled: false,
Count: 1,
SubtitleTrackClips: [
{
Id: 1,
TrackId: 2,
Type: "Text",
X: 0,
Y: 0,
TimelineIn: 0,
TimelineOut: 2,
Duration: 2,
VirginDuration: 2,
FontSize: 30,
FontColor: "#333333",
FontColorOpacity: 1,
Content: "Text with the custom font specified by the FontUrl parameter",
Alignment: "BottomCenter",
// The custom font.
FontUrl:
"https://ice-pub-media.myalicdn.com/mts-fonts/%E7%AB%99%E9%85%B7%E6%96%87%E8%89%BA%E4%BD%93.ttf",
},
],
},
],
AspectRatio: "16:9",
From: "websdk",
FECanvas: {
Width: 800,
Height: 450,
},
FEConfig: {
AutoProportion: "681:383",
},
};
const player = new window.AliyunTimelinePlayer({
container: document.getElementById("player"),
getMediaInfo: async (mediaId, mediaType, mediaOri) => {
console.log(">>>", mediaId, mediaType, mediaOri);
// If the URL is specified by the mediaUrl parameter of the timeline, which can be accessed over the Internet, you can directly return the URL.
return mediaId;
/**
If you need to dynamically request URLs, refer to the following sample code:
* if (mediaType === "font") {
params.InputURL = InputURL;
delete params.MediaId;
}
if (mediaOrigin === "mediaURL") {
params.InputURL = mediaId;
delete params.MediaId;
}
const apiName =
mediaOrigin === "public" ? "GetPublicMediaInfo" : "GetMediaInfo";
return request(apiName, {
// https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-getmediainfo
MediaId: mediaId,
})
.then((res) => {
// The following sample code is provided only for reference. We recommend that you configure the error logic. For example, you can configure the error message that is returned if FileInfoList is an empty array.
const fileInfoList = get(res, "data.MediaInfo.FileInfoList", []);
let mediaUrl, maskUrl;
let sourceFile = fileInfoList.find((item) => {
return item?.FileBasicInfo?.FileType === "source_file";
});
if (!sourceFile) {
sourceFile = fileInfoList[0];
}
const maskFile = fileInfoList.find((item) => {
return (
item.FileBasicInfo &&
item.FileBasicInfo.FileUrl &&
item.FileBasicInfo.FileUrl.indexOf("_mask") > 0
);
});
if (maskFile) {
maskUrl = get(maskFile, "FileBasicInfo.FileUrl");
}
mediaUrl = get(sourceFile, "FileBasicInfo.FileUrl");
const codec = get(sourceFile, "VideoStreamInfoList[0].CodecName");
return {
url: mediaUrl,
codec,
maskUrl,
};
})
.catch((ex) => {
// The error logic for external URLs.
if (mediaOrigin === "mediaURL") {
return mediaId;
}
});
*
* **/
},
});
// When you preview the timeline in the frontend, calling the setTimeline method automatically parses the MediaUrl parameter and font files.
player.setTimeline(timelineDemo);
// You can convert the timeline in the frontend to a timeline in the backend by using toBackendTimeline.
console.log("toBackendTimeline", player.toBackendTimeline());
document.getElementById("addSubtitle").addEventListener("click", () => {
player.addClip({
Id: Number(document.getElementById('subtitle').value),
TrackId: 2,
Type: "Text",
X: 0,
Y: 0,
TimelineIn: player.currentTime,
TimelineOut: player.currentTime+2,
Duration: 2,
VirginDuration: 2,
FontSize: 30,
FontColor: "#333333",
FontColorOpacity: 1,
Content: document.getElementById('content').value,
Alignment: "TopCenter",
// The custom font.
FontUrl:
"https://ice-pub-media.myalicdn.com/mts-fonts/%E7%AB%99%E9%85%B7%E6%96%87%E8%89%BA%E4%BD%93.ttf",
});
});
document.getElementById("updateSubtitle").addEventListener("click", () => {
player.updateClip(Number(document.getElementById('subtitle').value),(item)=>{
return Object.assign({},item,{Content: document.getElementById('content').value})
});
});
document.getElementById("moveSubtitle").addEventListener("click", () => {
player.focusClip( Number(document.getElementById('subtitle').value));
});
document.getElementById("removeSubtitle").addEventListener("click", () => {
player.blurClip();
player.removeClip( Number(document.getElementById('subtitle').value));
});
// Monitor track changes.
player.watchTrack((tracks)=>{
console.log('Timeline change:');
console.log(JSON.stringify(tracks,null,4));
});
</script>
</body>
</html>
For more information about how to perform complicated operations on the preview component, such as configuring tracks, subtitles, video effects, transitions, positions, and width and height and customizing the player UI, see the Open source demo. For information about how to run the demo, see Run the video editing demo for web.
FAQ
How do I update a timeline?
After an instance of AliyunTimelinePlayer is created, update a timeline by assigning a value to the timeline.
player.timeline = {....}If an issue occurs due to the cache, assign a null value to the timeline, clear the timeline content, and then assign another value to the timeline.
player.timeline = {} // Assign a null value to the timeline and clear the timeline content.The font size of a previewed video is inconsistent with the font size of the output video. Why?
If the font size of the output video becomes smaller, make sure that the timeline contains the FECanvas field. The FECanvas field specifies the resolution of the preview player. During video production, the server scales the font based on the resolutions of the preview player and the output video. The following sample code shows the regular resolutions of the preview player:
//16:9
FECanvas: {Width: 800, Height: 450}
//9:16
FECanvas: {Width: 253.125, Height: 450}How do I obtain the built-in materials of the preview player?
// Obtain the list of fonts.
AliyunTimelinePlayer.getDefaultFontList();
// Obtain the list of word art effects.
AliyunTimelinePlayer.getSubtitleEffectColorStyles();
// Obtain the list of bubble effects.
AliyunTimelinePlayer.getSubtitleBubbles();
// Obtain the list of special effects.
AliyunTimelinePlayer.getVideoEffects();
// Obtain the list of filters.
AliyunTimelinePlayer.getVideoFilters();
// Obtain the list of transitions.
AliyunTimelinePlayer.getVideoTransitions();When you specify parameters, you must retain spaces. Example: "Font":"Alibaba PuHuiTi",.
Are multiple instances of the preview player supported?
No. Due to restrictions of internal implementation, only a single instance of the preview player is supported.
What do I do if the following error message appears: player.js:27 TypeError: Cannot read properties of undefined (reading 'GLctx')?
This error message appears when hardware acceleration is disabled for your browser. Make sure that the kernel version of the browser is Chrome, the version number of the browser is greater than 80, and hardware acceleration is enabled for the browser.
The video editing SDK for web supports Chrome only.