Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >小窗播放视频的原理和实现(上)

小窗播放视频的原理和实现(上)

作者头像
QQ音乐技术团队
发布于 2018-02-01 07:03:21
发布于 2018-02-01 07:03:21
11K20
代码可运行
举报
运行总次数:0
代码可运行

本文对小窗视频播放进行了详细的研究,针对几种实现方案进行了深入的对比分析,进而给出实现小窗视频播放的最优解。其中通过对系统源码的分析,详细探究了如何完美地实现移动、缩放等效果,很有技术深度。文中几种方案的对比,以及SurfaceViewGLSurfaceViewTextureView相关知识点的讲解,非常实用,值得收藏。 — 责任编辑 junyihan

由于文章篇幅较长,将分为上、下两篇。上篇主要介绍小窗播放视频的原理,下篇主要介绍小窗播放视频的实现。

一、简介

目前很多视频类App都有小窗播放功能,比如Youtube(如图1)、Facebook(如图2)等,不过它们的实现方式却不同。Youtube 是将视频播放View内嵌到应用内,优点是交互好;Facebook则是通过WindowManager添加视频播放View,同时支持应用内部和外部播放。

小窗播放视频功能在小窗和大屏之间切换时,视频类App通常一边执行交互动作一边播放视频。交互动作包括移动、缩放或者动画;这些App在播放时期望给用户平滑的过渡体验,流畅加载视频,不能有明显的卡顿。

(图1 Youtube小窗播放视频)
(图1 Youtube小窗播放视频)
(图2 Facebook小窗播放视频)
(图2 Facebook小窗播放视频)

二、SurfaceView 和 GLSurfaceView

Android 中使用 MediaPlayer 播放视频时,一般采用SurfaceViewGLSurfaceViewTextureView。Youtube、Facebook用不同技术方案实现了小窗播放视频功能,它们共同点是都可以使用SurfaceViewGLSurfaceViewTextureView来播放视频。接下来分析三个视图用于小窗播放视频的原理。

SurfaceView继承自类View,但与其他View的子类不同的是它有独立的Surface,如下源码可以看出它包含一个Surface属性,即它不与宿主窗口共享同一个绘图表面。因此SurfaceView的UI可以在一个独立的线程中进行绘制。由于不会占用主线程资源,因此SurfaceView可以实现复杂而高效的UI。GLSurfaceView继承SurfaceView,作为SurfaceView的补充,加入了EGL的管理,并自带了渲染线程。它用于小窗播放时效果和SurfaceView类似。本文以下内容以SurfaceView为例分析独立的Surface对小窗播放会有什么影响。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SurfaceView extends View {        final Surface mSurface = new Surface();  
}

2.1、什么是Surface

Handle onto a raw buffer that is being managed by the screen compositor.[1]

通过Surface的类注释可以知道,Surface处理一块由Screen compositor管理的Raw buffer。而Screen compositor其实就是SurfaceFlinger服务。Surface字面意思就是绘图表面,可以理解为是UI的画布。

Android应用程序窗口需要请求SurfaceFlinger服务创建绘图表面(也就是Surface对象),同时窗口还需要被WindowManagerService管理;所以实际上窗口的绘图表面是通过两个Surface对象来描述,一个是应用程序进程创建的,另一个是由WindowManagerService创建的,这两个Surface对象对应于SurfaceFlinger服务的同一个Layer对象。

在应用程序进程这一侧,每一个应用程序窗口,如Activity,都有一个Surface对象,就是在ViewRootImpl对象的mSurface属性,这个Surface用来绘制应用程序窗口的UI,如下ViewRootImpl源码所示。当界面需要刷新时,窗口调用draw方法,向Surface请求canvas,执行绘画操作后再次提交给Surface完成屏幕显示。

在WindowManagerService服务这一侧,每一个窗口,都有一个对应的WindowState对象。其有一个属性mSurface,它负责设置窗口的位置、大小属性。例如,一个窗口的Z轴坐标大小要考虑到它的窗口类型,以及它与系统中的其它窗口的关系[2]。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class ViewRootImpl {
    private final Surface mSurface = new Surface();
    private void draw(boolean fullRedrawNeeded) {
        if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
        }
    }
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo,……) {
        inal Canvas canvas;
        canvas = mSurface.lockCanvas(dirty);
        surface.unlockCanvasAndPost(canvas);
    }
}

SurfaceView有独立的绘图表面,那么SurfaceView又是怎么绘制在宿主窗口的呢?

2.2、SurfaceView的Surface的创建过程

上面说到每一个窗口在SurfaceFlinger服务中都对应有一个Layer,用来描述它的绘图表面。同时每一个SurfaceView在SurfaceFlinger服务中还对应有一个独立的Layer或者LayerBuffer,用来单独描述它的绘图表面,以区别于它的宿主窗口的绘图表面[3]。

(图3 SurfaceView的Surface的创建过程)

接下来了解Surface创建过程,如图3的时序图所示,每当一个窗口需要刷新UI时,就会调用ViewRootImpl类的performTraversals方法。如果当前窗口的Surface还没有创建,或者已经失效,SurfaceView就会请求WindowManagerService服务创建一个新的Surface,它最终会调用updateWindow来完成Surface的创建。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SurfaceView extends View {
    final Surface mSurface = new Surface();
    MyWindow mWindow;
    int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;

    private void updateWindow(boolean force, boolean redrawNeeded) {
        if (mWindow == null) {
            mSession.addWithoutInputChannel(mWindow, mLayout,……);
        }
        ……
        mSurfaceLock.lock();
        try {
            ……
            final int relayoutResult = mSession.relayout(mWindow, mLayout,……, mSurface);
            ……
        } finally {
            mSurfaceLock.unlock();
    }
}

如SurfaceView源码所示,它有一个mSurface属性,相比之下TextView或者Button等普通View会共用ViewRootImpl的Surface。

SurfaceView类的属性mWindowType描述的是SurfaceView的窗口类型,它的默认值等于TYPE_APPLICATION_MEDIA,用来显示多媒体的,如视频。SurfaceView还有另外一个类型TYPE_APPLICATION_MEDIA_OVERLAY,它是在视频上面显示Overlay的,它可以显示视字幕等信息。宿主窗口会遮挡这两个类型的SurfaceView,如果窗口嵌入这两类SurfaceView,那么它们的Z轴位置会低于该窗口的Z轴位置,显示在该窗口下面。如果mWindow等于null的话,那么就说明该SurfaceView还没有添加到WindowManagerService服务中去,然后调用addWithoutInputChannel添加到WindowManagerService服务中。

mSession.relayout()请求WindowManagerService服务对SurfaceView的UI进行布局。如果宿主窗口的绘制表面还未创建,或者需要重新创建,那么就会请求SurfaceFlinger服务为它创建一个新的Surface。由于这一步可能会修改SurfaceView的Surface,所以添加了mSurfaceLock锁,避免其它线程同时修改该Surface的内容。

执行完成上述步骤之后,SurfaceView的Surface的创建完成了。但是mWindowType为TYPE_APPLICATION_MEDIATYPE_APPLICATION_MEDIA_OVERLAY的SurfaceView会被宿主窗口挡住,如何解决这个问题,这就要了解SurfaceView“挖洞”原理。

2.3、SurfaceView“挖洞”原理

当SurfaceView附加宿主窗口时,它的onAttachedToWindow会被调用。这个方法调用requestTransparentRegion请求在宿主窗口上设置透明区域,即请求在宿主窗口上挖洞,其实就是设置ViewRootImpl中Surface的透明度。而每当其宿主窗口刷新自己的UI的时候,就会调用ViewGroup的gatherTransparentRegion将所有嵌入在它里面的SurfaceView所设置的透明区域收集起来。然后再通知WindowManagerService为SurfaceView的gatherTransparentRegion方法设置一个总的透明区域。这就是SurfaceViewd的“挖洞”原理,如图4时序图所示。

(图4 SurfaceView“挖洞”原理)

接下来结合ViewRootImpl类的requestTransparentRegion源码,来分析请求在宿主窗口上设置透明区域的过程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class ViewRootImpl implements ……{        public void requestTransparentRegion(View child) {            if (mView == child) {
            mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
            mWindowAttributesChanged = true;
            requestLayout();
        }
    }
}

当mView等于子View时,将mPrivateFlags的View.REQUEST_TRANSPARENT_REGIONS位设置为1,表示该窗口被设置了一块透明区域。当一个窗口被请求设置了一块透明区域之后,它的窗口属性就发生了变化,这时候除了要将与它所关联的ViewRootImpl对象的mWindowAttributesChanged值设置为true之外,还要调用该ViewRootImpl对象的requestLayout方法对窗口的UI进行重新布局和绘制。requestLayout最终会调用到另外一个方法performTraversals来实际执行刷新窗口UI的操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class ViewRootImpl implements ……{
    private void performTraversals() {
        final View host = mView;
        if (didLayout) {
            host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
            if (……);
                host.gatherTransparentRegion(mTransparentRegion);
                if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                    mPreviousTransparentRegion.set(mTransparentRegion);
                    try {
                        sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
                    } catch (RemoteException e) {
                    }
                }
            }
        }
        boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
        if (!cancelDraw && !newSurface) {
            draw(fullRedrawNeeded);
        } 
    }
}

ViewRootImpl类的方法performTraversals是用来收集嵌入在它里面的SurfaceView所设置的透明区域的。它处于窗口的UI布局完成之后,窗口的UI绘制之前。这是因为窗口的UI布局完成之后,各个子视图的大小和位置才能确定下来,进而才能确定SurfaceView的透明区域的位置和大小。从顶层视图开始,从上到下收集每一个子视图所要设置的区域,最终收集到的总透明区域并保存在ViewRootImpl类的成员变量mTransparentRegion中。其中host是DecorView,它的gatherTransparentRegion方法重载了父类ViewGroup的gatherTransparentRegion方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class ViewGroup extends View …… {
    @Override
    public boolean gatherTransparentRegion(Region region) {
        //检测mPrivateFlags的REQUEST_TRANSPARENT_REGIONS位是否为1,因为如果当前视图不透明,子视图都不可能设置有透明区域。
        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
        if (meOpaque && region == null) {
            return true;
        }
        super.gatherTransparentRegion(region);
        ……
        boolean noneOfTheChildrenAreTransparent = true;
        for (int i = 0; i < count; i++) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK)==VISIBLE||child.getAnimation() != null){
                if (!child.gatherTransparentRegion(region)) {
                    noneOfTheChildrenAreTransparent = false;
                }
            }
        }
        return meOpaque || noneOfTheChildrenAreTransparent;
    }
}

ViewGroup的gatherTransparentRegion方法中,检测到有透明区域时,调用父类View的方法gatherTransparentRegion来检查当前视图容器是否需要绘制。如果需要绘制,说明当前视图的前景需要绘制,就会将它所占据的区域从参数region所占据的区域移除,以便可以显示当前视图的前景。然后调用每一个子视图的成员函数gatherTransparentRegion来继续往下收集透明区域。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SurfaceView extends View {
    @Override
    public boolean gatherTransparentRegion(Region region) {
        if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
            return super.gatherTransparentRegion(region);
        }
        boolean opaque = true;
        if ((mPrivateFlags & SKIP_DRAW) == 0) {
            // this view draws, remove it from the transparent region
            opaque = super.gatherTransparentRegion(region);
        } else if (region != null) {
            int w = getWidth();
            int h = getHeight();
            if (w>0 && h>0) {
                getLocationInWindow(mLocation);
                int l = mLocation[0];
                int t = mLocation[1];
                region.op(l, t, l+w, t+h, Region.Op.UNION);
            }
        }
        if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
            opaque = false;
        }
        return opaque;
    }
    ……
}

SurfaceView类的方法gatherTransparentRegion中,先检测是否用作窗口面板以及mPrivateFlags的SKIP_DRAW位是不是1。如果都是,将它所占据的区域从参数region所描述的区域移除,region中剩下的就是透明区域。最后判断Surface的像素格式是否设置有透明值。如果有,返回false给ViewRootImpl,然后ViewRootImpl调用sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);设置窗口为透明。这样就能看到SurfaceView了。

2.4、SurfaceView的绘制

SurfaceView虽然具有独立的Surface,不过它仍然是宿主窗口的视图结构中的一个结点,因此,它仍然是可以参与到宿主窗口的绘制流程中去的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SurfaceView extends View {
    @Override
    public void draw(Canvas canvas) {
        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
            // draw() is not called when SKIP_DRAW is set
            if ((mPrivateFlags & SKIP_DRAW) == 0) {
                // punch a whole in the view-hierarchy below us
                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            }
        }
        super.draw(canvas);
    }
    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
            // if SKIP_DRAW is cleared, draw() has already punched a hole
            if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
                // punch a whole in the view-hierarchy below us
                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            }
        }
        // reposition ourselves where the surface is 
        mHaveFrame = true;
        updateWindow(false, false);
        super.dispatchDraw(canvas);
    }
}

在SurfaceView的draw和dispatchDraw方法中,参数canvas是建立在宿主窗口的Surface上的画布,因此在这块画布上绘制任何UI都是出现在宿主窗口的Surface上的。但如果当前正在处理的SurfaceView不是用作宿主窗口面板的时候,即属性mWindowType的值不等于TYPE_APPLICATION_PANEL的时候,SurfaceView的这两个方法只是简单地将它所占据的区域绘制为黑色。另外dispatchDraw还会调用另外一个方法updateWindow更新的UI,绘制自己的Sueface。

2.5、小结SurfaceView的分析

通过了解SurfaceView的创建过程、“挖洞”原理和绘制过程,可以了解到Surface对小窗播放视频的影响如下:

1)SurfaceView在宿主窗口下面,通过“挖洞”原理显示Surface。SurfaceView在做旋转时,画面不会跟随SurfaceView旋转。

2)同理,设置透明度或者执行透明值动画时,SurfaceView显示有问题。

3)SurfaceView绘制时会先绘制黑边,所以在移动或者缩放过程,在更新不及时时会看到黑边。

4)SurfaceView具有独立的Surface,它的UI绘制可以在独立的线程中进行,可以进行复杂的UI绘制。

三、Android N上SurfaceView新特性

Note: Starting in platform version N, SurfaceView’s window position is updated synchronously with other View rendering. This means that translating and scaling a SurfaceView on screen will not cause rendering artifacts. Such artifacts may occur on previous versions of the platform when its window is positioned asynchronously.[4]

由于SurfaceView不在View hierarchy中,View的一些缩放,透明度变化等方法无法使用。要实现这些功能就得使用TextureView,但TextureView有个缺点就是性能低耗电高。Android N对SurfaceView进行了更改,它对SurfaceView自身和它的内容改变做了同步处理,播放视频时不会出现之前难看的黑色条。SurfaceView因这个新特性不会出现黑色条,但它旋转时画面仍然不会跟随旋转,仍然不支持透明度。

四、TextureView

如下源码所示,TextureView继承于View,并重载了View的draw()方法,它与其它的View一样在View hierarchy中管理与绘制。draw()方法中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView有新数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class TextureView extends View {
    private HardwareLayer mLayer;
    private SurfaceTexture mSurface;
    private SurfaceTextureListener mListener;
    private Canvas mCanvas;
    private long mNativeWindow;
      //……
      public final void draw(Canvas canvas) {
        // NOTE: Maintain this carefully (see View.java)
        mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
        applyUpdate();
        applyTransformMatrix();
    }
    private void applyUpdate() {
        if (mLayer == null) {
            return;
        }
        synchronized (mLock) {
            if (mUpdateLayer) {
                mUpdateLayer = false;
            } else {
                return;
            }
        }
        mLayer.prepare(getWidth(), getHeight(), mOpaque);
        mLayer.updateSurfaceTexture();
        if (mListener != null) {
            mListener.onSurfaceTextureUpdated(mSurface);
        }
    }
}

根据以上信息,可以知道TextureView不同于SurfaceView,没有单独创建Surface,而是作为View hierarchy中的一个普通View,来进行移动,旋转,缩放,动画等,没有SurfaceView执行旋转、缩放时的缺点。值得注意的是TextureView必须在硬件加速的窗口中,通过HardwareLayer更新视图。它需要硬件加速层,这使得TextureView比SurfaceView更耗性能。 Android N上SurfaceView新特性的说明上,官方也推荐在不执行旋转、透明度、缩放时使用SurfaceView。

五、结论

SurfaceView有独立的Surface,通过“挖洞”原理显示它。以致它在执行旋转时,画面不会跟随旋转;同时设置透明度或者执行透明值动画时,显示有问题。Android N以上的SurfaceView在视频进行缩放旋转时会同步变化,不会看到黑色边,官方推荐使用SurfaceView。TextureView作为普通View在View hierarchy中管理与绘制,更适用于小窗播放视频功能。但TextureView需要硬件加速层,使得TextureView比SurfaceView和GLSurfaceView更耗性能。

六、引用

[1]、Surface(https://developer.android.com/reference/android/view/Surface.html)

[2]、Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析 (http://blog.csdn.net/luoshengyang/article/details/8303098)

[3]、Android视图SurfaceView的实现原理分析(http://blog.csdn.net/luoshengyang/article/details/8661317)

[4]、SurfaceView(https://developer.android.com/reference/android/view/SurfaceView.html)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 QQ音乐技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
2 条评论
热度
最新
感谢分享
感谢分享
回复回复点赞举报
绝佳好文,谢谢分享?
绝佳好文,谢谢分享?
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
android SurfaceView绘制实现原理解析
在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制。又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。在本文中,我们就详细分析SurfaceView的实现原理。         在前面Android控件TextView的实现原理分析一文中提到,普通的Android控件
xiangzhihong
2018/02/01
5.9K0
android SurfaceView绘制实现原理解析
小窗播放视频的原理和实现(下)
本文对小窗视频播放进行了详细的研究,针对几种实现方案进行了深入的对比分析,进而给出实现小窗视频播放的最优解。其中通过对系统源码的分析,详细探究了如何完美地实现移动、缩放等效果,很有技术深度。文中几种方案的对比,以及SurfaceView、GLSurfaceView和TextureView相关知识点的讲解,非常实用,值得收藏。 — 责任编辑 junyihan 回顾上篇小窗播放视频的原理和实现(上),SurfaceView在它所在的位置上创建一个新的Window,Window创建一个独立的Surface,显示内
QQ音乐技术团队
2018/03/01
4.6K2
小窗播放视频的原理和实现(下)
SurfaceView 与 TextureView 详解
Surface 就是“表面”的意思,可以简单理解为内存中的一段绘图缓冲区。在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原生缓冲器的句柄”, 这句话包括下面两个意思:
字节流动
2021/01/12
13.9K0
聊聊SurfaceView和TextureView
播放视频或者渲染其他的动画的时候,有两个View组件可供选择,SurfaceView和TextureView,GLSurfaceView是SurfaceView是子类,这儿还是归类到SurfaceView中吧。
马上就说
2020/11/11
4.5K0
播放视频时如何在视频帧上添加水印
之前的一篇文章中我们介绍了播放视频的时候调整音频的音量,我们能否在播放视频的时候在视频画面上加上水印?
马上就说
2020/11/11
3.2K0
剖析Activity、Window、ViewRootImpl和View之间的关系
作者 | 豆沙包67 地址 | https://www.jianshu.com/p/a7596afb1aa1 声明 | 本文是 豆沙包67 原创,已获授权发布,未经原作者允许请勿转载 概念定义 ContextImpl:Context实现类。 PhoneWindow:Window唯一实现类。Window是一个抽象概念,是添加到WindowManager的根容器。 ViewRootImpl:ViewRootImpl是View的根,它控制了View的测量和绘制,同时持有WindowSession通过Binder
用户1269200
2018/02/01
1.6K0
剖析Activity、Window、ViewRootImpl和View之间的关系
什么是 SurfaceView?
SurfaceView就是在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显式在 SurfaceView之上,你也可以添加一些层在SurfaceView之上。
对话、
2022/02/22
1.2K0
什么是 SurfaceView?
理解Android硬件加速原理的小白文
硬件加速,直观上说就是依赖GPU实现图形绘制加速,软硬件加速的区别主要是图形的绘制究竟是GPU来处理还是CPU,如果是GPU,就认为是硬件加速绘制,反之,软件绘制。在Android中也是如此,不过相对于普通的软件绘制,硬件加速还做了其他方面优化,不仅仅限定在绘制方面,绘制之前,在如何构建绘制区域上,硬件加速也做出了很大优化,因此硬件加速特性可以从下面两部分来分析:
看书的小蜗牛
2018/06/29
2K0
理解Android硬件加速原理的小白文
OpenGL ES 与 GLSurfaceView 渲染视频帧
大家好,本文是 iOS/Android 音视频专题 的第六篇,该专题中 AVPlayer 项目代码将在 Github 进行托管,你可在微信公众号(GeekDev)后台回复 资料 获取项目地址。
100001509164
2022/01/20
2.6K0
Android 绘制原理浅析【干货】
对于Android开发,在面试的时候,经常会被问到,说一说View的绘制流程?我也经常问面试者,View的绘制流程.
Rouse
2019/08/06
1.5K1
史上最全Android渲染机制讲解(长文源码深度剖析)
渲染机制是Android操作系统很重要的一环,本系列通过介绍应用从启动到渲染的流程,揭秘Android渲染原理。
Android技术干货分享
2020/05/20
3.5K1
史上最全Android渲染机制讲解(长文源码深度剖析)
Android播放端绘制-SurfaceView还是GLSurfaceView
Surface的官方介绍:Handle onto a raw buffer that is being managed by the screen compositor,Surface是一个raw buffer的句柄,通过它在raw buffer上进行绘制,可以通过Surface获得一个Canvas。
音视频牛哥
2021/03/24
1.6K0
android之surfaceview画图
在前文中,我们分析了应用程序窗口连接到WindowManagerService服务的过程。在这个过程中,WindowManagerService服务会为应用程序窗口创建过一个到SurfaceFlinger服务的连接。有了这个连接之后,WindowManagerService服务就可以为应用程序窗口创建绘图表面了,以便可以用来渲染窗口的UI。在本文中,我们就详细分析应用程序窗口的绘图表面的创建过程。         从前面Android应用程序与SurfaceFlinger服务的关系概述和学习计划和Andro
xiangzhihong
2018/01/26
2K0
Android中如何使用OpenGL播放视频
视频播放主要经历这么几个步骤:解协议 -> 解封装 -> 解码音视频 -> 音视频同步,流程如下图:
雪月清
2020/06/23
2.4K0
音视频直播技术--视频的渲染与展示
今天给大家介绍一下在Android系统下视频如何渲染与展示。 我们都知道一个直播客户端对音视频的处理主要由以下几大部分组成:1. 数据采集; 2. 编码; 3. 传输; 4. 解码;5.渲染与展示。 今天讲的就是渲染与展示。
音视频_李超
2020/04/02
1.4K0
Android 图形架构
要理解Android的图形架构,我们需要先理解window的概念。维基百科中给window的定义是:Window是图形用户界面(GUI)系统中显示器上一个单独的视图区域(可以想象你电脑桌面上一个个窗口)。
字节流动
2022/09/26
2.4K0
软件绘制 &amp; 硬件加速绘制 【DisplayList &amp; RenderNode】
两者都是从SF获取一块内存,绘制都是在APP端,绘制好后都是通知SF去进行合成图层
小柔
2022/10/09
1.4K0
软件绘制 &amp; 硬件加速绘制 【DisplayList &amp; RenderNode】
从零开始仿写一个抖音App——Android绘制机制以及Surface家族源码全解析
本文首发于微信公众号——世界上有意思的事,搬运转载请注明出处,否则将追究版权责任。微信号:a1018998632,交流qq群:859640274
何时夕
2019/03/04
3.1K0
从零开始仿写一个抖音App——Android绘制机制以及Surface家族源码全解析
软件绘制 & 硬件加速绘制 【DisplayList & RenderNode】
两者都是从SF获取一块内存,绘制都是在APP端,绘制好后都是通知SF去进行合成图层
北洋
2023/09/18
6470
为播放器外接一套渲染框架
在一堆VideoEditor的技术文章中插入一篇播放器的文章,稍微有点违和,但是本文还是有必要讲讲的,因为它能给我们一点启示:原来播放器不是被动接收数据,还能主动进攻。我做播放器也很久了,今天不想谈播放器的性能优化和内部原理,谈谈播放器的渲染框架。
马上就说
2023/03/05
5550
为播放器外接一套渲染框架
推荐阅读
相关推荐
android SurfaceView绘制实现原理解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档