EGLContext: eglMakeCurrent详解

2023-05-16

1. 前言

在完成EGL的初始化之后,需要通过eglMakeCurrent()函数来将当前的上下文切换,这样opengl的函数才能启动作用。

boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context)

该接口将申请到的display,draw(surface)和 context进行了绑定。也就是说,在context下的OpenGLAPI指令将draw(surface)作为其渲染最终目的地。而display作为draw(surface)的前端显示。调用后,当前线程使用的EGLContex为context。

那么为什么调用了该函数之后,OpenGL ES的api函数就可以用了呢?
因为我们没有GPU驱动的代码,所以,我们可以从libagl中看出一点端倪。
查看这部分代码,建议将如下几部分的sourcecode导入到sourceinsight中。

frameworks/native/opengl/libagl
frameworks/base/cmds/bootanimation

2.libGLES_android

在Android的架构设计中,使用模拟GPU的话,加载的库应该为libGLES_android.so。而从Android的编译脚本中,可以知道libGLES_android.so的sourcecode的路径为:

N5_5.1/frameworks/native/opengl/libagl。

Pixelflinger是Android系统中为OpenGL ES引擎提供的一套软件渲染器(renderer)。Pixelflinger作为软件渲染器,为OpenGL ES引擎提供了一系列基础绘图功能。这些功能包括定义各种颜色格式像素位置、画点画线、绘制矩形及三角形、填充纹理等等。由于OpenGL ES相当于一个状态机,配置OpenGL ES状态的函数也均由Pixelflinger提供。

Pixelflinger的源代码位于system/core/libpixelflinger。
头文件位于system/core/include/libpixelflinger和system/core/include/private/pixelflinger。

3.egl_context

Context是什么东西呢?我们先来看看下面的几个结构体。

egl_context_t

egl_context_t类定义在frameworks/native/opengl/libs/egl/egl_object.h中。

egl_context_t

ogles_context_t

先看看ogles_context_t结构体,定义在frameworks/native/opengl/libagl/context.h中。
ogles_context_t

context_t

context_t结构体定义在system/core/include/private/pixelflinger/ggl_context.h中。
context_t

context_t结构体,用来存储OpenGL ES状态及数据上下文。context_t结构体中包含GGLContext、state_t、shade_t、iterators_t、generated_vars_t等结构体。
GGLContext结构体中包含了Pixelflinger库可提供给上层调用的一些函数接口,包括画点画线、绘制多边形、配置OpenGL ES状态机等函数接口。
state_t结构体用来描述OpenGL ES状态机的状态,包含多个子结构体,每个子结构体均负责处理一部分OpenGL ES功能。包括存储贴图及纹理、裁剪操作、光栅操作、混合操作、景深操作、雾化操作等功能。

这几个结构体之间的关系如图:
context_t

4. eglCreateContext

eglCreateContext实现在framework/native/opengl/libagl/egl.cpp中。该函数主要完成对egl_context_t结构体的初始化。同时调用ogles_init完成对应ogles_context_t结构体的初始化。

EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
                            EGLContext /*share_list*/, const EGLint* /*attrib_list*/)
{
    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
    ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
    
    egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
    c->flags = egl_context_t::NEVER_CURRENT;
    c->dpy = dpy;
    c->config = config;
    c->read = 0;
    c->draw = 0;
    return (EGLContext)gl;
}

ogles_context_t *ogles_init(size_t extra)
{
    // 申请空间,空间大小为egl_context_t & ogles_context_t + 32,为了32位对齐。
    void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
    if (!base) return 0;

    // 将指针C指向ogles_context_t,32位对齐
    ogles_context_t *c =
            (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
memset(c, 0, sizeof(ogles_context_t));
   // 调用ggl_init_context初始化context_t
    ggl_init_context(&(c->rasterizer));

    // XXX: this should be passed as an argument
    sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
    c->surfaceManager = smgr.get();
    c->surfaceManager->incStrong(c);

    sp<EGLBufferObjectManager> bomgr(new EGLBufferObjectManager());
    c->bufferObjectManager = bomgr.get();
    c->bufferObjectManager->incStrong(c);

    ogles_init_array(c);
    ogles_init_matrix(c);
    ogles_init_vertex(c);
    ogles_init_light(c);
    ogles_init_texture(c); // 初始化纹理相关的状态。
    
    c->rasterizer.base = base;
    c->point.size = TRI_ONE;
    c->line.width = TRI_ONE;

    // in OpenGL, writing to the depth buffer is enabled by default.
    c->rasterizer.procs.depthMask(c, 1);

    // OpenGL enables dithering by default
    c->rasterizer.procs.enable(c, GL_DITHER);
    return c;
}


void ggl_init_context(context_t* c)
{
    memset(c, 0, sizeof(context_t));
    ggl_init_procs(c);// 将state_t结构体的函数指针与Pixelflinger.cpp中的函数挂钩。
    ggl_init_trap(c);// 配置OpenGL ES状态机的状态。
    ggl_init_scanline(c); // 主要将scanline函数与context_t的接口挂钩。
    ggl_init_texture(c); // 初始化纹理相关的状态。
    ggl_init_picker(c); // 空函数。
    ggl_init_raster(c); // 将Raster.cpp中的函数与state_t结构体的函数指针挂钩。
    c->formats = gglGetPixelFormatTable();
    c->state.blend.src = GGL_ONE;
    c->state.blend.dst = GGL_ZERO;
    c->state.blend.src_alpha = GGL_ONE;
    c->state.blend.dst_alpha = GGL_ZERO;
    c->state.mask.color = 0xF;
    c->state.mask.depth = 0;
    c->state.mask.stencil = 0xFFFFFFFF;
    c->state.logic_op.opcode = GGL_COPY;
    c->state.alpha_test.func = GGL_ALWAYS;
    c->state.depth_test.func = GGL_LESS;
    c->state.depth_test.clearValue = FIXED_ONE;
    c->shade.w0 = FIXED_ONE;
    memcpy(c->ditherMatrix, gDitherMatrix, sizeof(gDitherMatrix));
}

在eglCreateContext函数中,首先会调用ogles_init为ogles_context_t & egl_context_t申请地址空间,并完成结构体中成员的赋值,然后将ogles_context_t->rasterizer->base指向elg_context_t。最后,返回执行ogles_context_t结构体的指针gl。

执行完成eglCreateContext之后,结构图如下:

5. eglMakeCurrent

eglMakeCurrent将申请到的display,draw(surface)和 context进行了绑定。也就是说,在context下的OpenGLAPI指令将draw(surface)作为其渲染最终目的地。而display作为draw(surface)的前端显示。调用后,当前线程使用的EGLContex为context。

先看看在bootanimation.cpp中对于eglMakeCurrent的调用:

   if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
        return NO_INIT;

接下来在libagl中看看glMakeCurrent的实现。

EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                            EGLSurface read, EGLContext ctx)
{
    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
    if (draw) {
        egl_surface_t* s = (egl_surface_t*)draw;
        if (!s->isValid())
            return setError(EGL_BAD_SURFACE, EGL_FALSE);
        if (s->dpy != dpy)
            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
        // TODO: check that draw is compatible with the context
    }
    if (read && read!=draw) {
        egl_surface_t* s = (egl_surface_t*)read;
        if (!s->isValid())
            return setError(EGL_BAD_SURFACE, EGL_FALSE);
        if (s->dpy != dpy)
            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
        // TODO: check that read is compatible with the context
    }
    EGLContext current_ctx = EGL_NO_CONTEXT;
    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
        return setError(EGL_BAD_MATCH, EGL_FALSE);

    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
        return setError(EGL_BAD_MATCH, EGL_FALSE);

    if (ctx == EGL_NO_CONTEXT) {
        // if we're detaching, we need the current context
        current_ctx = (EGLContext)getGlThreadSpecific();
    } else {
        egl_context_t* c = egl_context_t::context(ctx);
        egl_surface_t* d = (egl_surface_t*)draw;
        egl_surface_t* r = (egl_surface_t*)read;
        if ((d && d->ctx && d->ctx != ctx) ||
            (r && r->ctx && r->ctx != ctx)) {
            // one of the surface is bound to a context in another thread
            return setError(EGL_BAD_ACCESS, EGL_FALSE);
        }
    }
// 调用makeCurrent,将gl和当前的进程进行绑定。
    ogles_context_t* gl = (ogles_context_t*)ctx;
    if (makeCurrent(gl) == 0) {
        if (ctx) {
            egl_context_t* c = egl_context_t::context(ctx);
            egl_surface_t* d = (egl_surface_t*)draw;
            egl_surface_t* r = (egl_surface_t*)read;

            if (c->draw) {// 断开当前draw surface的绑定
                egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
                s->disconnect();
                s->ctx = EGL_NO_CONTEXT;
                if (s->zombie)
                    delete s;
            }
            if (c->read) {
                // FIXME: unlock/disconnect the read surface too 
            }
            // 将draw & read 绑定到当前的上下文。
            c->draw = draw;
            c->read = read;

            if (c->flags & egl_context_t::NEVER_CURRENT) {
                c->flags &= ~egl_context_t::NEVER_CURRENT;
                GLint w = 0;
                GLint h = 0;
                if (draw) {
                    w = d->getWidth();
                    h = d->getHeight();
                }
                ogles_surfaceport(gl, 0, 0);
                ogles_viewport(gl, 0, 0, w, h);
                ogles_scissor(gl, 0, 0, w, h);
            }
            if (d) {
                if (d->connect() == EGL_FALSE) {
                    return EGL_FALSE;
                }
                d->ctx = ctx;
                d->bindDrawSurface(gl);
            }
            if (r) {
                // FIXME: lock/connect the read surface too 
                r->ctx = ctx;
                r->bindReadSurface(gl);
            }
        } else {//取消绑定
            // if surfaces were bound to the context bound to this thread
            // mark then as unbound.
            if (current_ctx) {
                egl_context_t* c = egl_context_t::context(current_ctx);
                egl_surface_t* d = (egl_surface_t*)c->draw;
                egl_surface_t* r = (egl_surface_t*)c->read;
                if (d) {
                    c->draw = 0;
                    d->disconnect();
                    d->ctx = EGL_NO_CONTEXT;
                    if (d->zombie)
                        delete d;
                }
                if (r) {
                    c->read = 0;
                    r->ctx = EGL_NO_CONTEXT;
                    // FIXME: unlock/disconnect the read surface too 
                }
            }
        }
        return EGL_TRUE;
    }
    return setError(EGL_BAD_ACCESS, EGL_FALSE);
}

这里面将gl和当前的进程绑定是通过函数makecurrent来实现的。

static int makeCurrent(ogles_context_t* gl)
{
// 取得当前GlThread的context信息。
    ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
    if (gl) {
        egl_context_t* c = egl_context_t::context(gl);
        if (c->flags & egl_context_t::IS_CURRENT) { // 标记是当前的context,但实际却不是,出错。
            if (current != gl) {
                // it is an error to set a context current, if it's already
                // current to another thread
                return -1;
            }
        } else { // 执行glFlush,然后将当前的context标记为非当前context
            if (current) {
                // mark the current context as not current, and flus
                glFlush();
                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
            }
        }
        if (!(c->flags & egl_context_t::IS_CURRENT)) { // 然后将context和thread进行绑定,同时将context flag设置为curren
            // The context is not current, make it current!
            setGlThreadSpecific(gl);
            c->flags |= egl_context_t::IS_CURRENT;
        }
    } else { // gl为空,就将当前context flags设置为非当前,然后将当前thread的context设置为0
        if (current) 
            // mark the current context as not current, and flush
            glFlush();
            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
        }
        // this thread has no context attached to it
        setGlThreadSpecific(0);
    }
    return 0;
}

我们来看看context和GlThread的设置及取得操作实现。这两个函数是内联函数,定义在context.h中。

#ifdef HAVE_ANDROID_OS
    // We have a dedicated TLS slot in bionic
    inline void setGlThreadSpecific(ogles_context_t *value) {
        __get_tls()[TLS_SLOT_OPENGL] = value;
    }
    inline ogles_context_t* getGlThreadSpecific() {
        return static_cast<ogles_context_t*>(__get_tls()[TLS_SLOT_OPENGL]);
    }
#else
    extern pthread_key_t gGLKey;
    inline void setGlThreadSpecific(ogles_context_t *value) {
        pthread_setspecific(gGLKey, value);
    }
    inline ogles_context_t* getGlThreadSpecific() {
        return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey));
    }
#endif

从上面的代码分析可以知道,eglMakeCurrent会将第四个参数context设置到GLThread的__get_tls()[TLS_SLOT_OPENGL]中,从而实现context和GLThread之间的联系,同时,会将第二个参数draw & 第三个参数read赋值给context的成员变量,实现了context 和surface的绑定。经过了eglMakeCurrent之后,整个结构关系如下:

6.glclear

接下来,我们来看一下一个简单的opengl es的api实现。比如glclear

void glClear(GLbitfield mask) {

    ogles_context_t* c = ogles_context_t::get();

    c->rasterizer.procs.clear(c, mask);

}

可以在ogles_context_t结构体中看到get()函数的实现。

    static inline ogles_context_t* get() {

        return getGlThreadSpecific();

    }

明白了,当glclear别调用的时候,首先通过getGlThreadSpecific()获取到当前GlThread的context信息。而这个context就是在eglMakeCurrent的时候和GLThread绑定的context。

所以,GLThread可以看成是一个中间媒介,实现context的传递。

这样就回到了为什么调用eglMakeCurrent完成GlThread上下文的设置之后,opengl es的api就可以起作用咯。


作者:happy19850920
来源:CSDN
原文:https://blog.csdn.net/happy19850920/article/details/50673005
版权声明:本文为博主原创文章,转载请附上博文链接!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

EGLContext: eglMakeCurrent详解 的相关文章

  • 电脑知识:Win10系统把系统盘的软件移到D盘的简单方法

    作者主页 xff1a IT技术分享社区 作者简介 xff1a 大家好 我是IT技术分享社区的博主 xff0c 从事C Java开发九年 xff0c 对数据库 C Java 前端 运维 电脑技巧等经验丰富 个人荣誉 xff1a 数据库领域优质
  • 操作系统:Win10的沙盒是什么,如何使用,看完你就懂了

    Win10操作系统新增的windows沙盒是一种安全机制 xff0c 为执行中的程式提供的隔离环境 通常是作为一些来源不可信 具有破坏力或无法判定程序意图的应用程序提供实验之用 很多网友想要通过沙盒运行一些未知的程序 xff0c 但是不知道
  • 收集一些程序员励志经典名言

    1 作为一个真正的程序员 xff0c 首先应该尊重编程 xff0c 热爱你所写下的程序 xff0c 他是你的伙伴 xff0c 而不是工具 2 程序员可以让步 xff0c 却不可以退缩 xff0c 可以羞涩 xff0c 却不可以软弱 xff0
  • 夸克浏览器网页版入口网址分享

    夸克浏览器是一款简约 无广告的浏览器软件 xff0c 致力于带给用户最流畅舒适的使用体验 但是有用户问小编夸克浏览器的网页版入口地址在哪 xff1f 那么小编这里就给大家分享一下夸克浏览器网页版入口 夸克浏览器网页版入口地址分享 夸克浏览器
  • 由于找不到iutils.dll无法继续执行代码?

    电脑缺少某个dll文件是非常常见的系统错误 xff0c 但是如果遇到由于找不到iutils dll无法继续执行代码的问题 xff0c 那就不是简单的缺少文件问题了 xff0c 是中了流氓软件的问题 方法一 xff1a 1 这个问题是由于中了
  • excel制作表格的详细步骤

    excel是办公软件Microsoft office的组件之一 xff0c 很多用户都会使用excel来制作表格 xff0c 快捷方便 xff0c 但是还有不少用户不清楚怎么使用excel制作表格 xff1f 下面就一起来瞧瞧吧 xff01
  • ms-gamingoverlay一直跳出来怎么解决?

    最近有Win11玩家发现自己在玩游戏的时候经常弹出ms gamingoverlay的弹窗 xff0c 非常影响自己的游戏体验感 xff0c 那有什么办法可以解决这一问题吗 xff1f 大家可以按照以下的解决办法操作 xff0c 希望可以帮到
  • 联想电脑黑屏但电源键亮着的解决办法

    最近有联想电脑用户跟小编反应 xff0c 自己的笔记本屏幕黑屏了但是电源键还是亮着的 xff0c 这是怎么回事 xff1f 很多用户遇到这种情况往往不知所措 xff0c 不知道如何处理 xff0c 那么小编这里就给大家分享一下联想电脑黑屏电
  • 【XR】VR手柄设计之LED光点布局

    1 如何设计一台VR手柄 xff08 设计一台VR手柄需要考虑以下几个方面 xff1a xff09 功能 xff1a VR手柄需要具备一定的交互功能 xff0c 例如触摸板 按键 扳机等 xff0c 以及能够感知手部动作和姿态的传感器 舒适
  • Win11怎么彻底卸载Xbox Game Bar?

    Xbox Game Bar是常用于捕捉 记录屏幕并与其他游戏玩家朋友聊天的工具 xff0c 缺点就是运行过程中会占用大量的空间 xff0c 有什么办法可以卸载Xbox Game Bar xff0c 释放空间吗 xff1f 下面就来看看详细的
  • Win11打开本地组策略编辑器的两种方法

    Win11是新推出的操作系统 xff0c 但是用户对很多操作都不熟悉 xff0c 想要通过本地组策略编辑器修改一些配置 xff0c 都找不到本地组策略编辑器 xff0c 那么Win11怎么打开本地组策略编辑器呢 xff1f 一起来看看具体的
  • 介绍一下115sha1链接使用方法

    收到一个115 开头的网盘链接 xff0c 要如何下载呢 xff1f 单纯复制这个链接是没有办法直接下载的 xff0c 复制进去还会显示链接地址错误 xff0c 那么小编这里就给大家分享一下正确的使用方法 xff0c 希望可以帮到你 115
  • 夸克网盘的文件怎么保存到百度网盘?

    我们经常将自己的文件 视频等等都传到网盘上储存 xff0c 大大减少电脑和手机的占用 xff0c 其中百度网盘和夸克网盘是非常受欢迎的两款软件 xff0c 拥有超大的云储存空间 xff0c 用户想存什么就存什么 那夸克网盘的文件能存到百度网
  • Furmark如何进行正确的烤机?

    Furmark是一款非常不错的显卡性能以及稳定度测试软件 xff0c 通过这款软件可以快速测试出显卡的性能以及显卡是否稳定 xff0c 下面小编就来教教大家Furmark如何进行正确的烤机吧 1 打开Furmark xff0c 可以看到如图
  • WinRAR一直自动关闭怎么回事

    很多用户都习惯使用WinRAR来压缩解压文件 xff0c 但是有小伙伴跟小编反映自己的WinRAR老是一直闪退 xff0c 这是怎么回事 xff1f 下面就来看看WinRAR软件闪退的解决办法吧 Win10纯净版 Win10 64位纯净版
  • win11共享文件夹需要用户名和密码?

    在共享文件夹时提示需要用户名和密码 xff0c 这是怎么回事 xff1f 不少win11用户跟小编反映了这个问题 xff0c 我们要如何解决呢 xff1f 下面就来看看具体的win11共享文件夹需要用户名和密码的解决办法吧 win11共享文
  • win11桌面文件在哪个文件夹?

    很多win10系统用户应该都知道 xff0c 桌面文件默认存储在C xff1a Users Username Desktop文件夹中 xff0c 那升级win11之后 xff0c 桌面文件在哪个文件夹呢 xff1f 有没有改动呢 xff1f
  • win7时间总是不对怎么办?

    一般用户的主机中的主板会有一个电池 xff0c 这个电池可以给主板供电 xff0c 但是主板电池没电了的话就会将原本的时间设置清空 xff0c 因此这个时候时间就是不对的 xff0c 下面就是关于win7时间总是不对的解决方法 xff0c

随机推荐

  • Win10无法连接打印机怎么办?不能使用打印机的解决方法

    在我们平常的办公中 xff0c 经常会需要使用到打印机打印文件 想要使用打印机是需要先将电脑与打印机连接的 xff0c 但是有部分Win10用户遇到了无法连接打印机的情况 xff0c 对于这种情况应该如何解决呢 xff1f 下面来看看详细的
  • 【python】6DOF analyse tool

    1 result show 1 1 note 图1为3D位置 xff0c 图2 xff0c 3 xff0c 4分别表示yaw pitch xff0c roll角随着时间的变化的波动 2 code span class token comme
  • Spring入门预备知识(上)

    Spring入门主要使用了下面几个技术 xff1a 工厂模式 单例模式 动态代理模式 面向接口编程 xff0c 下面分几部分详细分析 一 xff09 工厂模式 1 定义 xff1a 定义一个用于创建对象的接口 xff0c 让子类决定实例化哪
  • 电脑丢失dll文件能一键修复吗,哪种修复方法靠谱?

    Dll文件的丢失其实是一件挺常见的事情的 xff0c 最近就有网友问小编 xff0c 关于dll文件丢失的相关问题 xff0c 他问电脑丢失dll文件能一键修复吗 xff1f 这里小编告诉你 xff0c 有方法一键修复 xff0c 但是需要
  • vcruntime140_1.dll无法继续执行代码,怎么解决这种问题?

    经常使用电脑的人 xff0c 可能对于这个弹出框应该不陌生 xff0c vcruntime140 1 dll无法继续执行代码 xff0c 其实会出现这种情况 xff0c 主要是因为缺少一个动态链接库 DLL 文件导致的 这个文件是 Visu
  • 这可能是最简单又有效的自监督学习方法了

    文 王珣 64 知乎 本文已获作者授权 xff0c 禁止二次转载 从Kaiming的MoCo和Hinton组Chen Ting的SimCLR开始 xff0c 自监督学习 xff08 SSL xff09 成了计算机视觉的热潮显学 凡是大佬大组
  • idea 2022.1 创建maven卡死解决

    1 关闭项目 2 新建maven项目 创建成功
  • FFmpeg 命令常见操作

    1 转码 ffmpeg i source mp4 ss 20 t 10 c copy my mp4 ffmpeg ss 10 t 15 accurate seek i test mp4 c a copy c v copy tt mp4 i
  • FFprobe查看&统计视频信息

    1 查看音视频信息 1 1 查看基本信息 ffprobe span class token number 1280 span x720 h264 8mbps 30fps span class token punctuation span m
  • Linux 查看文件夹大小,磁盘剩余空间(du/df)

    1 简介 du查看目录大小 xff0c df查看磁盘使用情况 2 du disk usage xff08 1 xff09 基本功能 递归查看文件夹下所有文件的大小 xff08 2 xff09 常用参数 xff1a h human reada
  • Python matplotlib高级绘图详解

    1 前言 前面我们介绍了使用matplotlib简单的绘图方法 xff08 见 xff1a Python应用matplotlib绘图简介 xff09 但是想要完全控制你的图形 xff0c 以及更高级的用法 xff0c 就需要使用 pyplo
  • ffmpeg视频精准剪切

    1 导言 ffmepg剪切视频 xff0c 很方便 xff0c 但是也有很大缺陷 xff1a xff08 1 xff09 剪切时间点不精确 xff08 2 xff09 有时剪切的视频开头有黑屏 造成这些问题的原因是ffmpeg无法seek到
  • 【python】6DOF analyse tool2

    result show 1 1 note 图1为3D X Y Z combination位置 xff0c 图4 xff0c 5 xff0c 6分别表示yaw pitch xff0c roll角随着时间的变化的波动 span class to
  • AudioChannelManipulation

    Manipulating audio channels with ffmpeg Contents stereo mono streamstereo 2 mono filesstereo 2 mono streamsmono stereo2
  • 音频节奏检测(Onset Detection)

    1 前言 最近市场上出现一些多个视频拼接而成MV xff0c 其原理是根据音频的节拍变换切换视频 我在这里讲述下如何进行音频节拍检测 2 音频检测一般流程 3 3 1 原始音频频谱 以1024为窗口 xff08 即每次读取1024个采样点
  • 金融时间序列分析:6. AR模型实例(R语言)

    0 目录 金融时间序列分析 xff1a 9 ARMA自回归移动平均模型 金融时间序列分析 xff1a 8 MA模型实例 xff08 Python xff09 金融时间序列分析 xff1a 7 MA滑动平均模型 金融时间序列分析 xff1a
  • 比特率,帧率,分辨率对视频画质的影响

    0 前言 前几天和别人讨论视频编码参数对视频清晰度影响 xff0c 今日查查文献在此记录总结下 对最终用户而言 xff0c 其只关心视频的文件大小和画面质量 其中画面质量包括 xff1a 分辨率 xff0c 清晰度和流畅度 流畅度 xff1
  • 搭建Android Camera项目工程

    0 前言 这块内容非常简单 xff0c 需要注意的有两个 xff1a 需要申请相机权限需要一个Surface用来预览 1 申请相机权限 1 1 申请Camera权限 span class hljs tag lt span class hlj
  • 获取webshell权限的45种方法

    1 到GoogLe 搜索一些关键字 edit asp 韩国肉鸡为多 多数为MSSQL数据库 2 到Google site cq cn inurl asp 3 利用挖掘鸡和一个ASP木马 文件名是login asp 路径组是 manage 关
  • EGLContext: eglMakeCurrent详解

    1 前言 在完成EGL的初始化之后 xff0c 需要通过eglMakeCurrent 函数来将当前的上下文切换 xff0c 这样opengl的函数才能启动作用 boolean eglMakeCurrent EGLDisplay displa