Skip to content

Commit d3fc555

Browse files
committed
feat(android): add video texture support
1 parent 4f382f9 commit d3fc555

File tree

19 files changed

+767
-325
lines changed

19 files changed

+767
-325
lines changed

packages/canvas-media/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nativescript/canvas-media",
3-
"version": "0.4.0",
3+
"version": "0.5.0",
44
"description": "Canvas media",
55
"main": "index",
66
"typings": "index.d.ts",

packages/canvas-media/video/index.android.ts

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ export class Video extends VideoBase {
2222
#playerView: com.google.android.exoplayer2.ui.PlayerView;
2323
#player: com.google.android.exoplayer2.SimpleExoPlayer;
2424
#playerListener: com.google.android.exoplayer2.Player.EventListener;
25+
#videoListener: com.google.android.exoplayer2.video.VideoListener;
2526
#src: string;
2627
#autoplay: boolean;
2728
#loop: boolean;
2829
#textureView: android.view.TextureView;
29-
3030
_isCustom: boolean = false;
3131
_playing: boolean = false;
3232
_timer: any;
@@ -37,9 +37,12 @@ export class Video extends VideoBase {
3737
_canvas: any;
3838
_frameTimer: any;
3939
_readyState: number = 0;
40+
_videoWidth = 0;
41+
_videoHeight = 0;
4042
constructor() {
4143
super();
4244
java.lang.System.loadLibrary('canvasnative');
45+
//@ts-ignore
4346
const builder = new com.google.android.exoplayer2.SimpleExoPlayer.Builder(Utils.ad.getApplicationContext());
4447
this.#player = builder.build();
4548
const ref = new WeakRef(this);
@@ -102,6 +105,17 @@ export class Video extends VideoBase {
102105
onTimelineChanged(timeline: com.google.android.exoplayer2.Timeline, manifest: any, reason: number) {},
103106
onTracksChanged: function (trackGroups, trackSelections) {},
104107
});
108+
this.#videoListener = new com.google.android.exoplayer2.video.VideoListener({
109+
onRenderedFirstFrame() {},
110+
onVideoSizeChanged(width: number, height: number, unappliedRotationDegrees: number, pixelWidthHeightRatio: number) {
111+
const owner = ref.get();
112+
if (owner) {
113+
owner._videoWidth = width;
114+
owner._videoHeight = height;
115+
}
116+
},
117+
onSurfaceSizeChanged(width: number, height: number) {},
118+
});
105119
const activity: androidx.appcompat.app.AppCompatActivity = Application.android.foregroundActivity || Application.android.startActivity;
106120
const inflator = activity.getLayoutInflater();
107121
const layout = Video.getResourceId(Application.android.foregroundActivity || Application.android.startActivity, 'player');
@@ -111,9 +125,8 @@ export class Video extends VideoBase {
111125
const params = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.MATCH_PARENT);
112126
this.#textureView = new android.view.TextureView(Application.android.foregroundActivity || Application.android.startActivity);
113127
this.#container.addView(this.#textureView as any, params);
114-
//this.#playerView.setPlayer(this.#player);
115-
//this.#player.setVideoTextureView(this.#textureView);
116128
this.setNativeView(this.#container);
129+
this.#player.addVideoListener(this.#videoListener);
117130
}
118131

119132
get readyState() {
@@ -139,7 +152,6 @@ export class Video extends VideoBase {
139152
}
140153
static st_count = 0;
141154
static createCustomView() {
142-
const canvas = require('@nativescript/canvas');
143155
const video = new Video();
144156
video._isCustom = true;
145157
video.width = 300;
@@ -164,40 +176,48 @@ export class Video extends VideoBase {
164176

165177
_hasFrame = false;
166178
getCurrentFrame(context?: WebGLRenderingContext) {
167-
const surfaceView = this.#playerView.getVideoSurfaceView();
168-
if (surfaceView instanceof android.view.TextureView) {
169-
if (!this._st) {
170-
// @ts-ignore
171-
const result = com.github.triniwiz.canvas.Utils.createSurfaceTexture(context);
172-
this._st = result[0];
173-
const ref = new WeakRef(this);
174-
this._frameListener = new android.graphics.SurfaceTexture.OnFrameAvailableListener({
175-
onFrameAvailable(param0: android.graphics.SurfaceTexture) {
176-
const owner = ref.get();
177-
if (owner) {
178-
owner._hasFrame = true;
179-
owner._notifyVideoFrameCallbacks();
180-
}
181-
},
182-
});
183-
this._st.setOnFrameAvailableListener(this._frameListener);
184-
185-
//this.#textureView.setSurfaceTexture(this._st);
186-
this._surface = new android.view.Surface(this._st);
187-
this.#player.setVideoSurface(this._surface);
188-
this._render = result[1];
179+
if (this.isLoaded) {
180+
const surfaceView = this.#playerView.getVideoSurfaceView();
181+
if (surfaceView instanceof android.view.TextureView) {
182+
const st = surfaceView.getSurfaceTexture();
183+
if (st) {
184+
// @ts-ignore
185+
this._render = com.github.triniwiz.canvas.Utils.createRenderAndAttachToGLContext(context, st);
186+
this._st = st;
187+
}
189188
}
189+
}
190190

191-
if (this._st) {
192-
if (!this._hasFrame) {
193-
return;
194-
}
191+
if (!this._st) {
192+
// @ts-ignore
193+
const result = com.github.triniwiz.canvas.Utils.createSurfaceTexture(context);
194+
this._st = result[0];
195+
const ref = new WeakRef(this);
196+
this._frameListener = new android.graphics.SurfaceTexture.OnFrameAvailableListener({
197+
onFrameAvailable(param0: android.graphics.SurfaceTexture) {
198+
const owner = ref.get();
199+
if (owner) {
200+
owner._hasFrame = true;
201+
owner._notifyVideoFrameCallbacks();
202+
}
203+
},
204+
});
195205

196-
// @ts-ignore
197-
com.github.triniwiz.canvas.Utils.updateTexImage(context, this._st, this._render);
206+
this._st.setOnFrameAvailableListener(this._frameListener);
198207

199-
this._hasFrame = false;
208+
this._surface = new android.view.Surface(this._st);
209+
this.#player.setVideoSurface(this._surface);
210+
this._render = result[1];
211+
}
212+
213+
if (this._st) {
214+
if (!this._hasFrame) {
215+
return;
200216
}
217+
// @ts-ignore
218+
com.github.triniwiz.canvas.Utils.updateTexImage(context, this._st, this._render, this._videoWidth, this._videoHeight, arguments[4], arguments[5]);
219+
220+
this._hasFrame = false;
201221
}
202222
}
203223

@@ -274,6 +294,7 @@ export class Video extends VideoBase {
274294
if (!this.#playerView) {
275295
this.#playerView = new com.google.android.exoplayer2.ui.PlayerView(this._context);
276296
}
297+
this.#playerView.setPlayer(this.#player);
277298
return this.#playerView;
278299
}
279300

packages/canvas/Canvas/common.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {CSSType, PercentLength, View, Screen, GestureStateTypes, Utils, Application} from '@nativescript/core';
22
import {CanvasRenderingContext, TouchList} from '../common';
3-
import {Pointer} from '@nativescript/core/ui/gestures';
3+
import {PinchGestureEventData, Pointer} from '@nativescript/core/ui/gestures';
44

55
export interface ICanvasBase {
66
on(eventName: 'ready', callback: (data: any) => void, thisArg?: any): void;
@@ -92,6 +92,7 @@ export abstract class CanvasBase extends View implements ICanvasBase {
9292

9393
__touchStart?: Pointer;
9494

95+
_isPinching = false;
9596
_touchEventsFN(event: any) {
9697
if (event.eventName === 'touch') {
9798
switch (event.action) {
@@ -114,8 +115,15 @@ export abstract class CanvasBase extends View implements ICanvasBase {
114115
break;
115116
}
116117
} else if (event.eventName === 'pinch') {
118+
this._isPinching = true;
117119
this._emitEvent('touchmove:pinch', event);
120+
if(event.state === GestureStateTypes.ended || event.state === GestureStateTypes.cancelled){
121+
this._isPinching = false;
122+
}
118123
} else if (event.eventName === 'pan') {
124+
if(this._isPinching){
125+
return;
126+
}
119127
if (event.state === GestureStateTypes.began || event.state === GestureStateTypes.changed) {
120128
this._emitEvent('touchmove', event);
121129
}
@@ -205,20 +213,21 @@ export abstract class CanvasBase extends View implements ICanvasBase {
205213
};
206214

207215
pointers.push({
208-
clientX: this.__touchStart.getX(),
209-
clientY: this.__touchStart.getY(),
216+
clientX: this.__touchStart?.getX() ?? 0,
217+
clientY: this.__touchStart?.getY() ?? 0,
210218
force: 0.0,
211219
identifier: 0,
212-
pageX: this.__touchStart.getX(),
213-
pageY: this.__touchStart.getY(),
220+
pageX: this.__touchStart?.getX() ?? 0,
221+
pageY: this.__touchStart?.getY() ?? 0,
214222
radiusX: 0,
215223
radiusY: 0,
216224
rotationAngle: 0,
217-
screenX: this.__touchStart.getX(),
218-
screenY: this.__touchStart.getY(),
225+
screenX: this.__touchStart?.getX() ?? 0,
226+
screenY: this.__touchStart?.getY() ?? 0,
219227
target,
220228
});
221229

230+
222231
pointers.push({
223232
clientX: x,
224233
clientY: y,
@@ -233,6 +242,7 @@ export abstract class CanvasBase extends View implements ICanvasBase {
233242
screenY: y,
234243
target,
235244
});
245+
236246
} else {
237247
const count = event.getAllPointers().length;
238248
const point = event.getActivePointers()[0];

packages/canvas/WebGL/WebGLRenderingContext/index.android.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,20 @@ export class WebGLRenderingContext extends WebGLRenderingContextBase {
133133
this.context.bindRenderbuffer(target, value);
134134
}
135135

136+
_lastTexture : {
137+
target: number,
138+
texture: number
139+
} = {target: 0, texture: 0}
136140
bindTexture(target: number, texture: WebGLTexture): void {
137141
this._glCheckError('bindTexture');
138142
this._checkArgs('bindTexture', arguments);
139143
const value = texture ? texture.native : 0;
144+
if(value > 0){
145+
this._lastTexture = {
146+
target, texture: value
147+
};
148+
}
149+
140150
this.context.bindTexture(target, value);
141151
}
142152

@@ -1026,9 +1036,9 @@ export class WebGLRenderingContext extends WebGLRenderingContextBase {
10261036
}
10271037
} else if (arguments.length === 6) {
10281038
if (border && typeof border.tagName === 'string' && (border.tagName === 'VID' || border.tagName === 'VIDEO') && typeof border._video.getCurrentFrame === 'function') {
1029-
border._video.getCurrentFrame(this.context);
1039+
border._video.getCurrentFrame(this.context, this, target, level, internalformat, width, height);
10301040
} else if (border && typeof border.getCurrentFrame === 'function') {
1031-
border.getCurrentFrame(this.context);
1041+
border.getCurrentFrame(this.context, this, target, level, internalformat, width, height);
10321042
} else if (border instanceof ImageAsset) {
10331043
this.context.texImage2D(target, level, internalformat, width, height, border.native);
10341044
} else if (border instanceof android.graphics.Bitmap) {

packages/canvas/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nativescript/canvas",
3-
"version": "0.9.10",
3+
"version": "0.9.12",
44
"description": "DOM Canvas API for NativeScript",
55
"main": "index",
66
"typings": "index.d.ts",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
dependencies {
2-
implementation 'com.github.triniwiz:canvas:0.9.10'
2+
implementation 'com.github.triniwiz:canvas:0.9.11'
33
}

packages/canvas/src-native/canvas-android/.idea/dictionaries/triniwiz.xml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/canvas/src-native/canvas-android/app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ dependencies {
3636
androidTestImplementation 'androidx.test:runner:1.2.0'
3737
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
3838
implementation project(path: ':canvas')
39+
implementation 'com.google.android.exoplayer:exoplayer:2.13.2'
40+
implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.2'
3941
}

0 commit comments

Comments
 (0)