安卓 - 在SurfaceTexture上绘制YouTube视频

12
我正在尝试在 SurfaceTexture 上绘制 WebView,以便可以在 OpenGL 中呈现它。到目前为止,我已成功地以标准方式在 WebView 中播放了 YouTube 视频。
  ...
  webView.getSettings().setJavaScriptEnabled(true);

  if (Build.VERSION.SDK_INT < 8) 
  {
     webView.getSettings().setPluginsEnabled(true);
  } 
  else 
  {
     webView.getSettings().setPluginState(WebSettings.PluginState.ON);
  }
  webView.setWebChromeClient(new WebChromeClient() { });
  webView.setWebViewClient(new WebViewClient());
  ...

同时硬件加速已开启:

 <application
        android:hardwareAccelerated="true"
 ...

并且我也成功地根据这篇教程: http://anuraagsridhar.wordpress.com/2013/03/13/rendering-an-android-webview-or-for-that-matter-any-android-view-directly-to-opengl/,在OpenGL中渲染了 WebView(除了播放视频)。

WebView的额外初始化(使其始终处于“纵向”并适合于纹理):

 Point p = new Point();
 activity.getWindow().getWindowManager().getDefaultDisplay().getSize(p);
 webView.setLayoutParams(new ViewGroup.LayoutParams(p.x, p.y));
 surfaceTexture.setDefaultBufferSize(p.x, p.y);

WebView的onDraw方法被重写:

@Override
public void onDraw(Canvas c)
{
   try
   {
      Point p = new Point();
      activity.getWindow().getWindowManager().getDefaultDisplay().getSize(p);
      Canvas canvas = surfaceTexture.lockCanvas(new Rect(0,0,p.x,p.y));
      canvas.save();
      canvas.translate(-scrollL, -scrollT);
      super.onDraw(canvas);
      canvas.restore();
      surfaceTexture.unlockCanvasAndPost(canvas);
   }
   catch (Surface.OutOfResourcesException e)
   {
      throw new RuntimeException(e);
   }
}

尝试使用上述技巧在Webview中播放YouTube视频时,视频矩形是黑色的(但可以听到声音)。 我怀疑硬件加速在表面纹理上无法正常工作。

因此问题是: 有没有办法在OpenGL纹理上播放YouTube视频?


1
你面临一个有趣的问题。WebView将使用SurfaceView播放视频,但你不知道在纹理中应该在哪里切一个洞来显示SurfaceView。除非你的纹理是全屏的,否则视频也不会在正确的位置。这可能是不可能的。 - Dave
视频(整个网页)已经放置在正确的位置。我通过使SurfaceTexture的缓冲区大小适合全屏的webview中的所有像素来实现这一点。 - Piotr Trzpil
2
实际上,您有一个黑色矩形,视频应该在其中,对吗? 视频本身正在另一个窗口上播放,该窗口位于视图层次结构窗口后面。 SurfaceView的最重要任务通常是在视图层次结构窗口中切割一个孔,以便您可以看到其他窗口。 您目前的渲染方式无法切割那个孔。 如果您能看到它,视频将位于WebView最初放置的位置,因为它没有被呈现为纹理。 - Dave
谢谢,我误解了你的第一条评论。你可能想把它转换成答案。 - Piotr Trzpil
我已经再次查看了一些Android源代码,试图想出一种方法来实现这个。不幸的是,我没有想出太多,但我会发布一个答案... - Dave
显示剩余3条评论
2个回答

7
问题在于视频被绘制到一个独立的窗口中,该窗口位于视图层次结构窗口后面,不容易访问,并且无法直接绘制到你的SurfaceTexture上。更为复杂的是,WebView将会定位和调整视频窗口的大小,而不考虑自身是否被绘制到与屏幕上显示的Canvas不同的Canvas上。此外,视频是在本地代码中渲染的,你也无法快速地在Canvas上进行绘制(这就是给视频单独窗口的全部想法背后的原因)。
任何令人满意的解决方案几乎都需要使用私有API来在本地代码中访问视频窗口。根据你计划如何使用你的SurfaceTexture,你可能会想出一个解决方法,其中涉及拦截WebViewClient中的URL,渲染之前删除任何视频标签,并将视频放置在你控制下的SurfaceViewTextureView中。然后,你可以将其放置在与你绘制的SurfaceTexture相关的位置,但这限制了你对SurfaceTexture的使用。这种hack方法很快就会变得非常丑陋。
简而言之,我没有看到一种干净的方法来解决这个问题。这是一个好主意,但使用公共API无法实现。

2
看起来这是可行的。我找到了一个名为FullDive的Android应用程序。它基于Cardboard,并成功地将Youtube视频呈现为OpenGL纹理。 - user2060386
2
同样适用于VRTube。你知道他们是怎么做到的吗? - Ayyappa
我尝试使用这个问题 https://dev59.com/Y2Ik5IYBdhLWcg3wBZ_7 找到那个窗口(使用PixelCopy API将其复制到位图中),但它实际上没有出现!而且,正如WebView开发人员在这里 https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/3wrULcul8lw 中所述,WebView使用硬件合成(虽然我不知道它是什么),这是不可能复制的... - Lev Leontev

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接