Android - 在 SurfaceTexture 上绘制 YouTube 视频

Posted

技术标签:

【中文标题】Android - 在 SurfaceTexture 上绘制 YouTube 视频【英文标题】:Android - draw YouTube video on SurfaceTexture 【发布时间】:2013-10-16 21:28:57 【问题描述】:

我正在尝试在 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"
 ...

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

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);
   

当尝试在使用上述 hack 渲染的 webview 上播放 YouTube 视频时,视频矩形是黑色的(但是可以听到声音)。 我怀疑硬件加速不适用于表面纹理。

所以问题是: 有没有办法在 OpenGL 纹理上播放 youtube 视频?

【问题讨论】:

这里有一个有趣的问题。 WebView 将使用 SurfaceView 播放视频,但您不知道在应该显示 SurfaceView 的纹理中的哪个位置切割一个洞。除非您的纹理是全屏的,否则视频无论如何都不会出现在正确的位置。这可能是不可能的。 视频(整个网页)在正确的位置。我通过使 SurfaceTexture 的缓冲区大小适合 web 视图(全屏)的所有像素来实现这一点。 实际上,视频应该在的地方有一个黑色矩形,对吧?视频本身正在视图层次结构窗口后面的单独窗口上播放。 SurfaceView 最重要的工作通常是在视图层次结构窗口中切出一个洞,以便您可以看到另一个窗口。照原样渲染事物,没有什么可以切开那个洞。如果你能看到它,视频将是 WebView 最初放置的位置,因为没有在纹理上渲染的概念。 谢谢,我误解了你的第一条评论。您可能希望将其转换为答案。 我实际上已经再次查看了一些 Android 源代码,试图想出一种方法来做到这一点。不幸的是,我没有想出太多,但我会发布一个答案...... 【参考方案1】:

问题是这样的:视频被绘制到视图层次结构窗口后面的单独窗口中,并且不容易在SurfaceTexture 上绘制。更复杂的是,WebView 将定位和调整视频窗口的大小,而不考虑将其自身绘制到屏幕上显示的Canvas 之外。此外,视频是以本机代码呈现的,无论如何您都无法以足够快的速度绘制到 Canvas 以跟上(这就是为视频提供单独窗口背后的全部想法)。

任何令人满意的解决方案几乎都需要使用私有 API 来访问本机代码中的视频窗口。根据您计划如何使用SurfaceTexture,您可能会想出一个解决方法,包括拦截WebViewClient 中的URL,在渲染之前剥离任何视频标签,并将视频放在SurfaceViewTextureView在你的控制之下。然后,您可以将它放在与您绘制SurfaceTexture 的位置相关的位置,但这会将SurfaceTexture 的使用限制为广告牌。不过,这种 hack 很快就会变得非常丑陋。

简而言之,我没有看到一个干净的方法来做到这一点。这是个好主意,但它不适用于公共 API。

【讨论】:

看来这是可行的。我找到了一个名为FullDive 的Android 应用程序。它基于 Cardboard 并成功地将 Youtube 视频渲染到 opengl 纹理上。 VRTube 也一样。知道他们是怎么做到的吗? 我尝试使用这个问题***.com/q/19669984 找到那个窗口(使用 PixelCopy API 将其复制到位图),但它实际上并没有出现!而且,正如 WebView 开发人员在此处 groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/… 所述,WebView 使用硬件合成(尽管 idk 它是什么),这是无法复制的......【参考方案2】:

尝试使用在 API 级别 23 中添加的lockHardwareCanvas。

【讨论】:

以上是关于Android - 在 SurfaceTexture 上绘制 YouTube 视频的主要内容,如果未能解决你的问题,请参考以下文章

如何在Android中启动JAVA程序

android中怎么设置组件在LinearLayout中居中

如何在android源代码中打印出日志

求教怎么在android的Logcat中输出日志

如何在Android中取得当前进程名

skia项目运行在Android.4.2,Android 4.2和Android 2.2有区别吗?