@granite-js/video 1.0.0

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/GraniteVideo.podspec +72 -0
  3. package/android/README.md +232 -0
  4. package/android/build.gradle +117 -0
  5. package/android/gradle.properties +8 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/run/granite/video/GraniteVideoModule.kt +70 -0
  8. package/android/src/main/java/run/granite/video/GraniteVideoPackage.kt +43 -0
  9. package/android/src/main/java/run/granite/video/GraniteVideoView.kt +384 -0
  10. package/android/src/main/java/run/granite/video/GraniteVideoViewManager.kt +318 -0
  11. package/android/src/main/java/run/granite/video/event/GraniteVideoEvents.kt +273 -0
  12. package/android/src/main/java/run/granite/video/event/VideoEventDispatcher.kt +66 -0
  13. package/android/src/main/java/run/granite/video/event/VideoEventListenerAdapter.kt +157 -0
  14. package/android/src/main/java/run/granite/video/provider/GraniteVideoProvider.kt +346 -0
  15. package/android/src/media3/AndroidManifest.xml +9 -0
  16. package/android/src/media3/java/run/granite/video/provider/media3/ExoPlayerProvider.kt +386 -0
  17. package/android/src/media3/java/run/granite/video/provider/media3/Media3ContentProvider.kt +29 -0
  18. package/android/src/media3/java/run/granite/video/provider/media3/Media3Initializer.kt +25 -0
  19. package/android/src/media3/java/run/granite/video/provider/media3/factory/ExoPlayerFactory.kt +32 -0
  20. package/android/src/media3/java/run/granite/video/provider/media3/factory/MediaSourceFactory.kt +61 -0
  21. package/android/src/media3/java/run/granite/video/provider/media3/factory/TrackSelectorFactory.kt +26 -0
  22. package/android/src/media3/java/run/granite/video/provider/media3/factory/VideoSurfaceFactory.kt +62 -0
  23. package/android/src/media3/java/run/granite/video/provider/media3/listener/ExoPlayerEventListener.kt +104 -0
  24. package/android/src/media3/java/run/granite/video/provider/media3/scheduler/ProgressScheduler.kt +56 -0
  25. package/android/src/test/java/run/granite/video/GraniteVideoViewRobolectricTest.kt +598 -0
  26. package/android/src/test/java/run/granite/video/event/VideoEventListenerAdapterTest.kt +319 -0
  27. package/android/src/test/java/run/granite/video/helpers/FakeGraniteVideoProvider.kt +161 -0
  28. package/android/src/test/java/run/granite/video/helpers/TestProgressScheduler.kt +42 -0
  29. package/android/src/test/java/run/granite/video/provider/GraniteVideoRegistryTest.kt +232 -0
  30. package/android/src/test/java/run/granite/video/provider/ProviderContractTest.kt +174 -0
  31. package/android/src/test/java/run/granite/video/provider/media3/listener/ExoPlayerEventListenerTest.kt +243 -0
  32. package/android/src/test/resources/kotest.properties +2 -0
  33. package/dist/module/GraniteVideo.js +458 -0
  34. package/dist/module/GraniteVideo.js.map +1 -0
  35. package/dist/module/GraniteVideoNativeComponent.ts +265 -0
  36. package/dist/module/index.js +7 -0
  37. package/dist/module/index.js.map +1 -0
  38. package/dist/module/package.json +1 -0
  39. package/dist/module/types.js +4 -0
  40. package/dist/module/types.js.map +1 -0
  41. package/dist/typescript/GraniteVideo.d.ts +12 -0
  42. package/dist/typescript/GraniteVideoNativeComponent.d.ts +189 -0
  43. package/dist/typescript/index.d.ts +5 -0
  44. package/dist/typescript/types.d.ts +328 -0
  45. package/ios/GraniteVideoComponentsProvider.h +10 -0
  46. package/ios/GraniteVideoProvider.swift +280 -0
  47. package/ios/GraniteVideoView.h +15 -0
  48. package/ios/GraniteVideoView.mm +661 -0
  49. package/ios/Providers/AVPlayerProvider.swift +541 -0
  50. package/package.json +106 -0
  51. package/src/GraniteVideo.tsx +575 -0
  52. package/src/GraniteVideoNativeComponent.ts +265 -0
  53. package/src/index.ts +8 -0
  54. package/src/types.ts +464 -0
package/src/types.ts ADDED
@@ -0,0 +1,464 @@
1
+ import type { StyleProp, ViewStyle, ImageSourcePropType } from 'react-native';
2
+ import type {
3
+ OnVideoLoadStartEvent,
4
+ OnVideoLoadEvent,
5
+ OnVideoProgressEvent,
6
+ OnVideoSeekEvent,
7
+ OnVideoBufferEvent,
8
+ OnVideoBandwidthUpdateEvent,
9
+ OnVideoPlaybackStateChangedEvent,
10
+ OnVideoPlaybackRateChangeEvent,
11
+ OnVideoVolumeChangeEvent,
12
+ OnVideoAudioFocusChangedEvent,
13
+ OnVideoPictureInPictureStatusChangedEvent,
14
+ OnVideoControlsVisibilityChangeEvent,
15
+ OnVideoExternalPlaybackChangeEvent,
16
+ OnVideoAspectRatioEvent,
17
+ OnVideoErrorEvent,
18
+ } from './GraniteVideoNativeComponent';
19
+
20
+ // ============================================================
21
+ // Source Types
22
+ // ============================================================
23
+
24
+ export interface VideoSourceHeaders {
25
+ [key: string]: string;
26
+ }
27
+
28
+ export interface DrmConfig {
29
+ type: 'widevine' | 'playready' | 'clearkey' | 'fairplay';
30
+ licenseServer?: string;
31
+ headers?: VideoSourceHeaders;
32
+ contentId?: string;
33
+ certificateUrl?: string;
34
+ base64Certificate?: boolean;
35
+ multiDrm?: boolean;
36
+ }
37
+
38
+ export interface TextTrack {
39
+ title: string;
40
+ language: string;
41
+ type: 'application/x-subrip' | 'text/vtt' | 'application/ttml+xml';
42
+ uri: string;
43
+ }
44
+
45
+ export interface BufferConfig {
46
+ minBufferMs?: number;
47
+ maxBufferMs?: number;
48
+ bufferForPlaybackMs?: number;
49
+ bufferForPlaybackAfterRebufferMs?: number;
50
+ backBufferDurationMs?: number;
51
+ cacheSizeMB?: number;
52
+ live?: {
53
+ maxPlaybackSpeed?: number;
54
+ minPlaybackSpeed?: number;
55
+ maxOffsetMs?: number;
56
+ minOffsetMs?: number;
57
+ targetOffsetMs?: number;
58
+ };
59
+ }
60
+
61
+ export interface VideoSource {
62
+ uri?: string;
63
+ type?: string;
64
+ mainVer?: number;
65
+ patchVer?: number;
66
+ headers?: VideoSourceHeaders;
67
+ startPosition?: number;
68
+ cropStart?: number;
69
+ cropEnd?: number;
70
+ drm?: DrmConfig;
71
+ textTracks?: TextTrack[];
72
+ metadata?: VideoMetadata;
73
+ }
74
+
75
+ export interface VideoMetadata {
76
+ title?: string;
77
+ subtitle?: string;
78
+ description?: string;
79
+ artist?: string;
80
+ imageUri?: string;
81
+ }
82
+
83
+ // ============================================================
84
+ // Track Selection Types
85
+ // ============================================================
86
+
87
+ export type SelectedTrackType = 'system' | 'disabled' | 'title' | 'language' | 'index';
88
+ export type SelectedVideoTrackType = 'auto' | 'disabled' | 'resolution' | 'index';
89
+
90
+ export interface SelectedTrack {
91
+ type: SelectedTrackType;
92
+ value?: string | number;
93
+ }
94
+
95
+ export interface SelectedVideoTrack {
96
+ type: SelectedVideoTrackType;
97
+ value?: number;
98
+ }
99
+
100
+ // ============================================================
101
+ // Resize Mode
102
+ // ============================================================
103
+
104
+ export type ResizeMode = 'contain' | 'cover' | 'stretch' | 'none';
105
+
106
+ // ============================================================
107
+ // View Type (Android)
108
+ // ============================================================
109
+
110
+ export type ViewType = 'surface' | 'texture';
111
+
112
+ // ============================================================
113
+ // Poster Source
114
+ // ============================================================
115
+
116
+ export interface PosterSource {
117
+ uri?: string;
118
+ }
119
+
120
+ export type Poster = ImageSourcePropType | PosterSource;
121
+
122
+ // ============================================================
123
+ // Event Data Types
124
+ // ============================================================
125
+
126
+ export type OnLoadData = OnVideoLoadEvent & {
127
+ naturalSize: OnVideoLoadEvent['naturalSize'] & {
128
+ orientation: 'portrait' | 'landscape';
129
+ };
130
+ audioTracks: AudioTrack[];
131
+ textTracks: TextTrackInfo[];
132
+ videoTracks: VideoTrackInfo[];
133
+ };
134
+
135
+ export interface AudioTrack {
136
+ index: number;
137
+ title?: string;
138
+ language?: string;
139
+ bitrate?: number;
140
+ type?: string;
141
+ selected?: boolean;
142
+ }
143
+
144
+ export interface TextTrackInfo {
145
+ index: number;
146
+ title?: string;
147
+ language?: string;
148
+ type?: string;
149
+ selected?: boolean;
150
+ }
151
+
152
+ export interface VideoTrackInfo {
153
+ index: number;
154
+ trackId?: string;
155
+ codecs?: string;
156
+ width?: number;
157
+ height?: number;
158
+ bitrate?: number;
159
+ selected?: boolean;
160
+ }
161
+
162
+ export type OnSeekData = OnVideoSeekEvent & {
163
+ target?: number;
164
+ };
165
+
166
+ export interface OnTimedMetadataData {
167
+ metadata: Array<{
168
+ value: string;
169
+ identifier: string;
170
+ }>;
171
+ }
172
+
173
+ export interface OnAudioTracksData {
174
+ audioTracks: AudioTrack[];
175
+ }
176
+
177
+ export interface OnTextTracksData {
178
+ textTracks: TextTrackInfo[];
179
+ }
180
+
181
+ export interface OnTextTrackDataChangedData {
182
+ subtitleTracks: string;
183
+ }
184
+
185
+ export interface OnVideoTracksData {
186
+ videoTracks: VideoTrackInfo[];
187
+ }
188
+
189
+ export interface OnReceiveAdEventData {
190
+ event: string;
191
+ data?: {
192
+ [key: string]: string | number | boolean;
193
+ };
194
+ }
195
+
196
+ export interface OnTransferEndData {
197
+ uri: string;
198
+ bytesTransferred: number;
199
+ }
200
+
201
+ // ============================================================
202
+ // Ref Methods
203
+ // ============================================================
204
+
205
+ export interface VideoRef {
206
+ seek: (time: number, tolerance?: number) => void;
207
+ pause: () => void;
208
+ resume: () => void;
209
+ setVolume: (volume: number) => void;
210
+ setFullScreen: (fullscreen: boolean) => void;
211
+ presentFullscreenPlayer: () => void;
212
+ dismissFullscreenPlayer: () => void;
213
+ enterPictureInPicture: () => void;
214
+ exitPictureInPicture: () => void;
215
+ setSource: (source: VideoSource) => void;
216
+ getCurrentPosition: () => Promise<number>;
217
+ save: (options?: { type?: string }) => Promise<{ uri: string }>;
218
+ restoreUserInterfaceForPictureInPictureStopCompleted: (restored: boolean) => void;
219
+ }
220
+
221
+ // ============================================================
222
+ // Component Props
223
+ // ============================================================
224
+
225
+ export interface VideoProps {
226
+ // Test ID
227
+ testID?: string;
228
+
229
+ // Style
230
+ style?: StyleProp<ViewStyle>;
231
+
232
+ // Progress
233
+ progressUpdateInterval?: number;
234
+
235
+ // Source
236
+ source: VideoSource | number;
237
+
238
+ /**
239
+ * **NOTE**
240
+ *
241
+ * Value: string with a URL for the poster is deprecated, use poster as an object instead.
242
+ */
243
+ poster?: Poster | string;
244
+ posterResizeMode?: ResizeMode;
245
+
246
+ // Playback Control
247
+ paused?: boolean;
248
+ muted?: boolean;
249
+ volume?: number;
250
+ rate?: number;
251
+ repeat?: boolean;
252
+ playInBackground?: boolean;
253
+ playWhenInactive?: boolean;
254
+ automaticallyWaitsToMinimizeStalling?: boolean;
255
+ shutterColor?: string;
256
+
257
+ // Display
258
+ resizeMode?: ResizeMode;
259
+ viewType?: ViewType;
260
+ useTextureView?: boolean;
261
+ useSecureView?: boolean;
262
+
263
+ // Buffering
264
+ bufferConfig?: BufferConfig;
265
+ minLoadRetryCount?: number;
266
+ maxBitRate?: number;
267
+ preferredForwardBufferDuration?: number;
268
+
269
+ // Track Selection
270
+ selectedAudioTrack?: SelectedTrack;
271
+ selectedTextTrack?: SelectedTrack;
272
+ selectedVideoTrack?: SelectedVideoTrack;
273
+ textTracks?: TextTrack[];
274
+
275
+ // DRM
276
+ drm?: DrmConfig;
277
+ localSourceEncryptionKeyScheme?: string;
278
+
279
+ // Ads (Android/iOS)
280
+ adTagUrl?: string;
281
+ adLanguage?: string;
282
+
283
+ // Controls
284
+ controls?: boolean;
285
+ showNotificationControls?: boolean;
286
+ disableFocus?: boolean;
287
+ disableDisconnectError?: boolean;
288
+ focusable?: boolean;
289
+ hideShutterView?: boolean;
290
+ preventsDisplaySleepDuringVideoPlayback?: boolean;
291
+
292
+ // Fullscreen
293
+ fullscreen?: boolean;
294
+ fullscreenAutorotate?: boolean;
295
+ fullscreenOrientation?: 'all' | 'landscape' | 'portrait';
296
+
297
+ // Picture in Picture
298
+ pictureInPicture?: boolean;
299
+
300
+ // Content
301
+ contentStartTime?: number;
302
+ allowsExternalPlayback?: boolean;
303
+ audioOutput?: 'speaker' | 'earpiece';
304
+ ignoreSilentSwitch?: 'inherit' | 'ignore' | 'obey';
305
+ mixWithOthers?: 'inherit' | 'mix' | 'duck';
306
+
307
+ // Debug
308
+ debug?: {
309
+ enable?: boolean;
310
+ thread?: boolean;
311
+ };
312
+
313
+ // === Events ===
314
+
315
+ /**
316
+ * Callback when video starts loading
317
+ */
318
+ onLoadStart?: (data: OnVideoLoadStartEvent) => void;
319
+
320
+ /**
321
+ * Callback when video is loaded
322
+ */
323
+ onLoad?: (data: OnLoadData) => void;
324
+
325
+ /**
326
+ * Callback when video fails to load
327
+ */
328
+ onError?: (data: OnVideoErrorEvent) => void;
329
+
330
+ /**
331
+ * Callback during video playback progress
332
+ */
333
+ onProgress?: (data: OnVideoProgressEvent) => void;
334
+
335
+ /**
336
+ * Callback when video seek completes
337
+ */
338
+ onSeek?: (data: OnSeekData) => void;
339
+
340
+ /**
341
+ * Callback when video ends
342
+ */
343
+ onEnd?: () => void;
344
+
345
+ /**
346
+ * Callback when video buffering state changes
347
+ */
348
+ onBuffer?: (data: OnVideoBufferEvent) => void;
349
+
350
+ /**
351
+ * Callback when video bandwidth updates
352
+ */
353
+ onBandwidthUpdate?: (data: OnVideoBandwidthUpdateEvent) => void;
354
+
355
+ /**
356
+ * Callback when playback state changes
357
+ */
358
+ onPlaybackStateChanged?: (data: OnVideoPlaybackStateChangedEvent) => void;
359
+
360
+ /**
361
+ * Callback when playback rate changes
362
+ */
363
+ onPlaybackRateChange?: (data: OnVideoPlaybackRateChangeEvent) => void;
364
+
365
+ /**
366
+ * Callback when volume changes
367
+ */
368
+ onVolumeChange?: (data: OnVideoVolumeChangeEvent) => void;
369
+
370
+ /**
371
+ * Callback when video becomes idle
372
+ */
373
+ onIdle?: () => void;
374
+
375
+ /**
376
+ * Callback when video is ready for display
377
+ */
378
+ onReadyForDisplay?: () => void;
379
+ onPlaybackResume?: () => void;
380
+ onPlaybackStalled?: () => void;
381
+
382
+ // Track Events
383
+ onAudioTracks?: (data: OnAudioTracksData) => void;
384
+ onTextTracks?: (data: OnTextTracksData) => void;
385
+ onTextTrackDataChanged?: (data: OnTextTrackDataChangedData) => void;
386
+ onVideoTracks?: (data: OnVideoTracksData) => void;
387
+ onTimedMetadata?: (data: OnTimedMetadataData) => void;
388
+
389
+ /**
390
+ * Callback when video aspect ratio changes
391
+ */
392
+ onAspectRatio?: (data: OnVideoAspectRatioEvent) => void;
393
+
394
+ /**
395
+ * Callback when audio focus changes
396
+ */
397
+ onAudioFocusChanged?: (data: OnVideoAudioFocusChangedEvent) => void;
398
+
399
+ /**
400
+ * Callback when audio becomes noisy
401
+ */
402
+ onAudioBecomingNoisy?: () => void;
403
+
404
+ /**
405
+ * Callback before fullscreen player presents
406
+ */
407
+ onFullscreenPlayerWillPresent?: () => void;
408
+
409
+ /**
410
+ * Callback after fullscreen player presents
411
+ */
412
+ onFullscreenPlayerDidPresent?: () => void;
413
+
414
+ /**
415
+ * Callback before fullscreen player dismisses
416
+ */
417
+ onFullscreenPlayerWillDismiss?: () => void;
418
+
419
+ /**
420
+ * Callback after fullscreen player dismisses
421
+ */
422
+ onFullscreenPlayerDidDismiss?: () => void;
423
+
424
+ /**
425
+ * Callback when picture-in-picture status changes
426
+ */
427
+ onPictureInPictureStatusChanged?: (data: OnVideoPictureInPictureStatusChangedEvent) => void;
428
+
429
+ /**
430
+ * Callback to restore user interface for picture-in-picture stop
431
+ */
432
+ onRestoreUserInterfaceForPictureInPictureStop?: () => void;
433
+
434
+ /**
435
+ * Callback when controls visibility changes
436
+ */
437
+ onControlsVisibilityChange?: (data: OnVideoControlsVisibilityChangeEvent) => void;
438
+
439
+ /**
440
+ * Callback when external playback changes
441
+ */
442
+ onExternalPlaybackChange?: (data: OnVideoExternalPlaybackChangeEvent) => void;
443
+
444
+ /**
445
+ * Callback when receive ad event occurs
446
+ */
447
+ onReceiveAdEvent?: (data: OnReceiveAdEventData) => void;
448
+
449
+ /**
450
+ * Callback when transfer end event occurs
451
+ */
452
+ onTransferEnd?: (data: OnTransferEndData) => void;
453
+ }
454
+
455
+ // ============================================================
456
+ // Static Methods
457
+ // ============================================================
458
+
459
+ export interface VideoStatic {
460
+ clearCache: () => Promise<void>;
461
+ getWidevineLevel: () => Promise<number>;
462
+ isCodecSupported: (mimeType: string, width: number, height: number) => Promise<boolean>;
463
+ isHEVCSupported: () => Promise<boolean>;
464
+ }