0%

takeSnapshotWithConfiguration 截图白屏的问题

问题描述

想基于wkwebview做个webgl的游戏录屏方案;
但使用takeSnapshotWithConfiguration无法截取webgl渲染的内容;
通过查看源码,确认wkwebview无法截取硬件加速的内容;只能选择其它替代方案;

canvas 接口验证

验证canvas.toDataURL、canvas.toBlob、canvas.captureStream这几个接口,效果如下:

机型 接口名 平均帧率
iphone xs max canvas.toDataURL 35.5
iphone xs max canvas.toBlob 37
iphone xs max canvas.captureStream 37

canvas 的几个接口,开启截图后,游戏帧率下降非常严重,不适合做游戏录屏;

webgl 的 glReadPixel 方案验证

注入js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

- (void)loadJsBase:(NSMutableString*)jsStr {
[jsStr appendString:@"var console = {};"];
[jsStr appendString:@"console.log = function(msg) {window.webkit.messageHandlers.Logger.postMessage(msg)};"];
[jsStr appendString:@"var starting = true;"];
}

- (void)loadJsSendData:(NSMutableString*)jsStr {
[jsStr appendString:@"function sendSnapData(data) {"];
[jsStr appendString:@"var request = new XMLHttpRequest();"];
[jsStr appendString:@"request.onloadstart = function(e) {console.log('onloadstart');};"];
[jsStr appendString:@"request.onprogress = function(e) {console.log('onprogress');};"];
[jsStr appendString:@"request.onabort = function(e) {console.log('onabort');};"];
[jsStr appendString:@"request.onerror = function(e) {console.log('onerror');};"];
// [jsStr appendString:@"request.onload = function(e) {console.log('onload: ' + request.status);};"];
[jsStr appendString:@"request.ontimeout = function(e) {console.log('ontimeout');};"];
// [jsStr appendString:@"request.onloadend = function(e) {console.log('onloadend');};"];
[jsStr appendFormat:@"request.open('POST', 'hilive://upload/%u', false);", ++ requestId];
[jsStr appendString:@"request.setRequestHeader('content-type', 'application/arraybuffer');"];
[jsStr appendString:@"request.send(data);"];
[jsStr appendString:@"request.end();"];
[jsStr appendString:@"}"];
}

- (void)loadJsSnapShot:(NSMutableString*)jsStr {
[jsStr appendString:@"var pixelBuffer = new Uint8Array(1);"];
[jsStr appendString:@"function snapShot() {"];
[jsStr appendString:@"if (!starting) { return;}"];
[jsStr appendString:@"var drawSize = gl.drawingBufferWidth * gl.drawingBufferHeight * 4;"];
[jsStr appendString:@"if (pixelBuffer.length != drawSize) {"];
[jsStr appendString:@"pixelBuffer = new Uint8Array(drawSize);"];
[jsStr appendString:@"console.log('pixelBuffer init');"];
[jsStr appendString:@"}"];
[jsStr appendString:@"gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixelBuffer);"];
// [jsStr appendString:@"sendSnapData(pixelBuffer);"];
[jsStr appendString:@"}"];
}

- (void)loadJsTakeSnap:(NSMutableString*)jsStr {
[jsStr appendString:@"function takeSnap() {"];
[jsStr appendString:@"snapShot();"];//59.7fps
// [jsStr appendString:@"canvas.toDataURL('image/jpeg');"];//35.5fps
// [jsStr appendString:@"canvas.toBlob(function(blob) {}, 'image/jpeg');"];//37fps
[jsStr appendString:@"window.webkit.messageHandlers.Animate.postMessage('');"];
[jsStr appendString:@"}"];
}

- (void)loadBridge {
NSMutableString* jsStr = [[NSMutableString alloc] init];

[self loadJsBase:jsStr];
[self loadJsSendData:jsStr];
[self loadJsSnapShot:jsStr];
[self loadJsTakeSnap:jsStr];

[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable data, NSError * _Nullable error) {
NSLog(@"loadBridge, error: %@", error);
}];
}

机型 接口名 平均帧率
iphone xs max canvas.toDataURL 35.5
iphone xs max canvas.toBlob 37
iphone xs max canvas.captureStream 37
iphone xs max gl.readPixels 59.7

使用glReadPixel,游戏帧率能保持60fps左右,能够满足游戏录屏的需要;

代码路径

https://github.com/hilive/samples/tree/master/apple/WKSnapshot

用户的需求就是我的追求!