|
12 | 12 |
|
13 | 13 | import com.twilio.video.I420Frame; |
14 | 14 | import com.twilio.video.VideoRenderer; |
15 | | -import com.twilio.video.VideoView; |
| 15 | +import com.twilio.video.VideoTextureView; |
16 | 16 |
|
17 | 17 | import java.io.ByteArrayOutputStream; |
| 18 | +import java.lang.reflect.Field; |
18 | 19 | import java.nio.ByteBuffer; |
19 | 20 | import java.util.concurrent.atomic.AtomicBoolean; |
20 | 21 |
|
21 | 22 | import io.alterac.blurkit.BlurKit; |
| 23 | +import tvi.webrtc.EglRenderer; |
22 | 24 | import tvi.webrtc.RendererCommon; |
23 | 25 | import tvi.webrtc.YuvConverter; |
24 | 26 |
|
|
29 | 31 | * last frame rendered and will update the provided image view any time {@link #takeSnapshot()} is |
30 | 32 | * invoked. |
31 | 33 | */ |
32 | | -public class SnapshotVideoRenderer extends VideoView { |
| 34 | +public class SnapshotVideoRenderer extends VideoTextureView { |
33 | 35 | private final ImageView imageView; |
34 | 36 | private int blurValue; |
35 | 37 | private final AtomicBoolean snapshotRequsted = new AtomicBoolean(false); |
36 | 38 | private final Handler handler = new Handler(Looper.getMainLooper()); |
| 39 | + private Handler eglRendererHandler = null; |
| 40 | + private final VideoTextureView videoTextureView; |
37 | 41 |
|
38 | | - public SnapshotVideoRenderer(Context context, ImageView imageView, int blurValue) { |
| 42 | + public SnapshotVideoRenderer(Context context, ImageView imageView, int blurValue, VideoTextureView videoTextureView) { |
39 | 43 | super(context); |
40 | 44 | this.imageView = imageView; |
41 | 45 | this.blurValue = blurValue; |
| 46 | + this.videoTextureView = videoTextureView; |
42 | 47 | } |
43 | 48 |
|
44 | 49 | @Override |
45 | 50 | public void renderFrame(final I420Frame i420Frame) { |
46 | 51 |
|
47 | 52 | // Capture bitmap and post to main thread |
48 | 53 | if (snapshotRequsted.compareAndSet(true, false)) { |
49 | | - /* |
50 | | - * I420Frame can be represented as texture or an in-memory buffer. yuvPlanes is not |
51 | | - * null and textureId is zero when frame is represented in memory and yuvPlanes is |
52 | | - * null textureId is a non zero value when the frame is represented as a texture. |
53 | | - */ |
54 | | - final Bitmap bitmap = i420Frame.yuvPlanes == null ? |
55 | | - captureBitmapFromTexture(i420Frame) : |
56 | | - captureBitmapFromYuvFrame(i420Frame); |
57 | | - handler.post(() -> { |
58 | | - |
59 | | - // Update the bitmap of image view |
60 | | - BlurKit.getInstance().blur(bitmap, blurValue); |
61 | | - imageView.setImageBitmap(bitmap); |
62 | | - |
63 | | - // Frames must be released after rendering to free the native memory |
64 | | - i420Frame.release(); |
65 | | - }); |
| 54 | + if (eglRendererHandler == null) { |
| 55 | + eglRendererHandler = getEglHandler(); |
| 56 | + } |
| 57 | + if (eglRendererHandler != null) { |
| 58 | + eglRendererHandler.post(() -> { |
| 59 | + final Bitmap bitmap = i420Frame.yuvPlanes == null ? |
| 60 | + captureBitmapFromTexture(i420Frame) : |
| 61 | + captureBitmapFromYuvFrame(i420Frame); |
| 62 | + |
| 63 | + // Update the bitmap of image view |
| 64 | + BlurKit.getInstance().blur(bitmap, blurValue); |
| 65 | + |
| 66 | + handler.post(() -> { |
| 67 | + imageView.setImageBitmap(bitmap); |
| 68 | + |
| 69 | + // Frames must be released after rendering to free the native memory |
| 70 | + i420Frame.release(); |
| 71 | + }); |
| 72 | + }); |
| 73 | + } |
66 | 74 | } else { |
67 | 75 | i420Frame.release(); |
68 | 76 | } |
69 | 77 | } |
70 | 78 |
|
| 79 | + private Handler getEglHandler() { |
| 80 | + try { |
| 81 | + Field eglRendererField = videoTextureView.getClass().getDeclaredField("eglRenderer"); |
| 82 | + eglRendererField.setAccessible(true); |
| 83 | + EglRenderer eglRenderer = (EglRenderer) eglRendererField.get(videoTextureView); |
| 84 | + Field renderThreadHandlerField = eglRenderer.getClass().getDeclaredField("renderThreadHandler"); |
| 85 | + renderThreadHandlerField.setAccessible(true); |
| 86 | + Handler eglHandler = (Handler) renderThreadHandlerField.get(eglRenderer); |
| 87 | + |
| 88 | + return eglHandler; |
| 89 | + } catch (NoSuchFieldException e) { |
| 90 | + e.printStackTrace(); |
| 91 | + } catch (IllegalAccessException e) { |
| 92 | + e.printStackTrace(); |
| 93 | + } |
| 94 | + |
| 95 | + return null; |
| 96 | + } |
| 97 | + |
71 | 98 | /** |
72 | 99 | * Request a snapshot on the rendering thread. |
73 | 100 | */ |
|
0 commit comments