libpag 4.5.4 → 4.5.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -46,4 +46,5 @@ export const binding = (module: PAG) => {
46
46
  module.RenderCanvas = RenderCanvas;
47
47
  setMixin(module);
48
48
  module.currentPlayer = null;
49
+ module._useSoftwareDecoder = false;
49
50
  };
@@ -114,7 +114,7 @@ export class PAGView extends NativePAGView {
114
114
  this.flushingNextFrame = false;
115
115
  } catch (e: any) {
116
116
  this.flushingNextFrame = false;
117
- throw e;
117
+ console.error(e);
118
118
  }
119
119
  }
120
120
 
@@ -141,6 +141,11 @@ export class PAGView extends NativePAGView {
141
141
  }
142
142
  this.player.setProgress((this.playTime % duration) / duration);
143
143
  const res = await this.flush();
144
+ if (this.needResetStartTime()) {
145
+ // The WeChat Mini Program decoder takes a long time to start decoding,
146
+ // Decoding BMP takes too much time and makes the video reader seek repeatedly.
147
+ this.startTime = this.getNowTime() * 1000 - this.playTime;
148
+ }
144
149
  this.playFrame = playFrame;
145
150
  this.repeatedTimes = count;
146
151
  return res;
@@ -3,6 +3,9 @@ import { removeFile, touchDirectory, writeFile } from './file-utils';
3
3
  import { ArrayBufferImage, FrameData } from '@tgfx/wechat/array-buffer-image';
4
4
 
5
5
  import type { FrameDataOptions, VideoDecoder, wx } from './interfaces';
6
+ import {PAGModule} from "../pag-module";
7
+ import type {PAGPlayer} from "../pag-player";
8
+ import {destroyVerify} from "../utils/decorators";
6
9
 
7
10
  declare const wx: wx;
8
11
  declare const setInterval: (callback: () => void, delay: number) => number;
@@ -27,19 +30,22 @@ export interface TimeRange {
27
30
  end: number;
28
31
  }
29
32
 
33
+ @destroyVerify
30
34
  export class VideoReader {
31
35
  public static async create(
32
- mp4Data: Uint8Array,
33
- width: number,
34
- height: number,
35
- frameRate: number,
36
- staticTimeRanges: TimeRange[],
36
+ mp4Data: Uint8Array,
37
+ width: number,
38
+ height: number,
39
+ frameRate: number,
40
+ staticTimeRanges: TimeRange[],
37
41
  ): Promise<VideoReader> {
38
42
  return new VideoReader(mp4Data, width, height, frameRate, staticTimeRanges);
39
43
  }
40
44
 
41
45
  public isSought = false; // Web SDK use this property to check if video is seeked
42
46
  public isPlaying = false; // Web SDK use this property to check if video is playing
47
+ public isDestroyed = false;
48
+ private player: PAGPlayer | null = null;
43
49
 
44
50
  private readonly frameRate: number;
45
51
  private currentFrame: number;
@@ -55,11 +61,11 @@ export class VideoReader {
55
61
  private arrayBufferImage = new ArrayBufferImage(new ArrayBuffer(0), 0, 0);
56
62
 
57
63
  public constructor(
58
- mp4Data: Uint8Array,
59
- width: number,
60
- height: number,
61
- frameRate: number,
62
- staticTimeRanges: TimeRange[],
64
+ mp4Data: Uint8Array,
65
+ width: number,
66
+ height: number,
67
+ frameRate: number,
68
+ staticTimeRanges: TimeRange[],
63
69
  ) {
64
70
  this.frameRate = frameRate;
65
71
  this.currentFrame = -1;
@@ -75,10 +81,12 @@ export class VideoReader {
75
81
  this.videoDecoderPromise = this.videoDecoder.start({ source: this.mp4Path, mode: 1 }).then(() => {
76
82
  this.startGetFrameDataLoop();
77
83
  });
84
+ this.linkPlayer(PAGModule.currentPlayer);
78
85
  }
79
86
 
80
87
  public async prepare(targetFrame: number) {
81
88
  if (targetFrame === this.currentFrame) return;
89
+ this.isSought = false;
82
90
  // Wait for videoDecoder ready
83
91
  await this.videoDecoderPromise;
84
92
  if (this.frameDataBuffers.length > 0) {
@@ -94,6 +102,8 @@ export class VideoReader {
94
102
 
95
103
  if (targetFrame !== this.bufferIndex) {
96
104
  this.seeking = true;
105
+ this.isSought = true;
106
+ this.bufferIndex = targetFrame;
97
107
  await this.videoDecoder.seek(Math.floor((targetFrame / this.frameRate) * 1000));
98
108
  this.seeking = false;
99
109
  }
@@ -106,6 +116,10 @@ export class VideoReader {
106
116
  return this.arrayBufferImage;
107
117
  }
108
118
 
119
+ public getCurrentFrame(): number {
120
+ return this.currentFrame;
121
+ }
122
+
109
123
  public async play() {
110
124
  // Web SDK use this function to play video.
111
125
  }
@@ -124,11 +138,16 @@ export class VideoReader {
124
138
  }
125
139
 
126
140
  public onDestroy() {
141
+ if (this.player) {
142
+ this.player.unlinkVideoReader(this);
143
+ this.player = null;
144
+ }
127
145
  this.clearFrameDataLoop();
128
146
  this.videoDecoder.remove();
129
147
  if (this.mp4Path) {
130
148
  removeFile(this.mp4Path);
131
149
  }
150
+ this.isDestroyed = true;
132
151
  }
133
152
 
134
153
  private getFrameData() {
@@ -186,4 +205,11 @@ export class VideoReader {
186
205
  }
187
206
  this.getFrameDataLooping = false;
188
207
  }
189
- }
208
+
209
+ private linkPlayer(player: PAGPlayer | null) {
210
+ this.player = player;
211
+ if (player) {
212
+ player.linkVideoReader(this);
213
+ }
214
+ }
215
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * VideoDecode wait frame num.
3
3
  */
4
- export declare const VIDEO_DECODE_WAIT_FRAME = 3;
4
+ export declare const VIDEO_DECODE_WAIT_FRAME = 1;
5
5
  /**
6
6
  * VideoDecode seek timeout frame num.
7
7
  */
@@ -1,9 +1,10 @@
1
1
  import type { TimeRange, VideoReader as VideoReaderInterfaces } from '../interfaces';
2
2
  export declare class VideoReader {
3
- static create(source: Uint8Array | HTMLVideoElement, width: number, height: number, frameRate: number, staticTimeRanges: TimeRange[]): VideoReaderInterfaces;
3
+ static create(source: Uint8Array | HTMLVideoElement, width: number, height: number, frameRate: number, staticTimeRanges: TimeRange[]): Promise<VideoReaderInterfaces>;
4
4
  isSought: boolean;
5
5
  isPlaying: boolean;
6
6
  bitmap: ImageBitmap | null;
7
+ isDestroyed: boolean;
7
8
  private videoEl;
8
9
  private frameRate;
9
10
  private canplay;
@@ -16,6 +17,7 @@ export declare class VideoReader {
16
17
  private bitmapCanvas;
17
18
  private bitmapCtx;
18
19
  private currentFrame;
20
+ private targetFrame;
19
21
  constructor(source: Uint8Array | HTMLVideoElement, width: number, height: number, frameRate: number, staticTimeRanges: TimeRange[]);
20
22
  prepare(targetFrame: number, playbackRate: number): Promise<void>;
21
23
  getCurrentFrame(): number;
@@ -13,7 +13,13 @@ export interface VideoReader {
13
13
  pause: () => void;
14
14
  stop: () => void;
15
15
  }
16
- export type VideoDecoderConstructor = new (mp4Data: Uint8Array, width: number, height: number, frameRate: number, staticTimeRanges: TimeRange[]) => VideoReader;
16
+ export interface VideoReaderManager {
17
+ getVideoReaderByID: (id: number) => VideoReader | undefined;
18
+ destroy: () => void;
19
+ }
20
+ export interface VideoDecoderConstructor {
21
+ create: (mp4Data: Uint8Array, width: number, height: number, frameRate: number, staticTimeRanges: TimeRange[]) => Promise<VideoReader>;
22
+ }
17
23
  export interface FontMetrics {
18
24
  ascent: number;
19
25
  descent: number;
@@ -2,13 +2,16 @@ import { PAGSurface } from './pag-surface';
2
2
  import { Matrix } from './core/matrix';
3
3
  import { PAGComposition } from './pag-composition';
4
4
  import type { PAGLayer } from './pag-layer';
5
- import { PAGScaleMode, Rect, VecArray } from './types';
5
+ import { type PAGScaleMode, type Rect, VecArray } from './types';
6
6
  import type { VideoReader } from './interfaces';
7
+ import { VideoReaderManager } from "./video-reader-manager";
7
8
  export declare class PAGPlayer {
8
9
  static create(): PAGPlayer;
9
10
  wasmIns: any;
10
11
  isDestroyed: boolean;
11
12
  videoReaders: VideoReader[];
13
+ protected pagComposition: PAGComposition | null;
14
+ protected videoReaderManager: VideoReaderManager | null;
12
15
  constructor(wasmIns: any);
13
16
  /**
14
17
  * Set the progress of play position, the value is from 0.0 to 1.0.
@@ -182,4 +185,12 @@ export declare class PAGPlayer {
182
185
  * Unlink VideoReader from PAGPlayer.
183
186
  */
184
187
  unlinkVideoReader(videoReader: VideoReader): void;
188
+ /**
189
+ * Prepares the video frame for the current composition before rendering.
190
+ */
191
+ private prepareVideoFrame;
192
+ /**
193
+ * Destroys the video reader manager and releases all associated resources.
194
+ */
195
+ destroyVideoReaderManager(): void;
185
196
  }
@@ -207,6 +207,6 @@ export declare class PAGView {
207
207
  protected setTimer(): void;
208
208
  protected clearTimer(): void;
209
209
  protected resetSize(useScale?: boolean): void;
210
+ protected needResetStartTime(): boolean;
210
211
  private updateFPS;
211
- private needResetStartTime;
212
212
  }
@@ -15,6 +15,7 @@ import { PAGImageLayer } from './pag-image-layer';
15
15
  import { PAGSolidLayer } from './pag-solid-layer';
16
16
  import { Matrix as ClassMatrix } from './core/matrix';
17
17
  import { RenderCanvas } from './core/render-canvas';
18
+ import { VideoReaderManager } from "./interfaces";
18
19
  import type { ScalerContextConstructor, VideoDecoderConstructor } from './interfaces';
19
20
  import type { ArrayBufferImage } from '../../third_party/tgfx/web/src/wechat/array-buffer-image';
20
21
  import type { TGFXPathFillType, TGFXLineCap, TGFXLineJoin, EmscriptenGL, ctor, Point, Vector, Rect } from '../../third_party/tgfx/web/src/types';
@@ -94,6 +95,12 @@ export interface PAG extends EmscriptenModule {
94
95
  registerSoftwareDecoderFactory: (factory: SoftwareDecoderFactory | null) => void;
95
96
  SDKVersion: () => string;
96
97
  currentPlayer: PAGPlayer | null;
98
+ videoReaderManager: VideoReaderManager | null;
99
+ _videoInfoManager: {
100
+ _Make: (pagFile: any) => any;
101
+ _HasVideo: (pagFile: any) => any;
102
+ };
103
+ _useSoftwareDecoder: boolean;
97
104
  [key: string]: any;
98
105
  }
99
106
  /**
@@ -0,0 +1,60 @@
1
+ import type { VideoReader } from "./interfaces";
2
+ /**
3
+ * VideoReaderManager is responsible for managing multiple VideoReader instances.
4
+ * It handles video decoder initialization, frame preparation, and lifecycle management.
5
+ */
6
+ export declare class VideoReaderManager {
7
+ /**
8
+ * Checks whether the given PAG composition contains any video content.
9
+ * @param wasmIns - The WebAssembly instance to check
10
+ * @returns True if the composition contains video, false otherwise
11
+ */
12
+ static HasVideo(wasmIns: any): boolean;
13
+ /**
14
+ * Factory method to create and initialize a VideoReaderManager instance.
15
+ * @param wasmIns - The WebAssembly instance containing video information
16
+ * @returns A promise that resolves to a fully initialized VideoReaderManager instance
17
+ */
18
+ static make(wasmIns: any): Promise<VideoReaderManager>;
19
+ /** WebAssembly instance for video information management */
20
+ wasmIns: any;
21
+ /** Array of video IDs managed by this instance */
22
+ videoIDs: Array<number>;
23
+ /** Flag indicating whether this instance has been destroyed */
24
+ isDestroyed: boolean;
25
+ /** Map storing VideoReader instances indexed by video ID */
26
+ private videoReaderMap;
27
+ /**
28
+ * Constructor for VideoReaderManager.
29
+ * Initializes the WASM instance and retrieves all video IDs.
30
+ * @param wasmIns - The WebAssembly instance
31
+ * @throws Error if VideoReaderManager creation fails
32
+ */
33
+ constructor(wasmIns: any);
34
+ /**
35
+ * Creates VideoReader instances for all videos in the PAG file.
36
+ * For each video ID, retrieves MP4 data and initializes the corresponding VideoReader.
37
+ * Also prepares the first frame with the initial playback rate.
38
+ */
39
+ createVideoReader(): Promise<void>;
40
+ /**
41
+ * Retrieves a VideoReader instance by video ID.
42
+ * Marks the video as using hardware decoding (software decode disabled).
43
+ * @param id - The video ID
44
+ * @returns The VideoReader instance or undefined if not found
45
+ * @throws Error if VideoReader is not found for the given ID
46
+ */
47
+ getVideoReaderByID(id: number): VideoReader | undefined;
48
+ /**
49
+ * Prepares target frames for all videos based on current playback position.
50
+ * This method is called during rendering to ensure the correct frames are decoded.
51
+ * It handles both hardware and software decoding modes.
52
+ */
53
+ prepareTargetFrame(): Promise<void>;
54
+ /**
55
+ * Destroys the VideoReaderManager instance and cleans up all resources.
56
+ * This includes destroying the WASM instance, all VideoReader instances,
57
+ * and clearing internal maps.
58
+ */
59
+ destroy(): void;
60
+ }