赞
踩
上一节讲解了 编辑SDK 的架构,这一节在来基于图7讲讲 编辑SDK 的运行机制。
上一章大概的讲了讲整个 编辑SDK 的整体架构和运行机制,但其实整个 编辑SDK 内部的每一个部分的细节都非常多,所以这一章我会先讲解 VideoDecodeService 的内部细节。其他各个部分则放在后面几篇文章中讲解。与此同时,WsVideoEditor 中的代码也会随着讲解的进行而不断更新。最终形成一个可用的 编辑SDK。
-----代码块1----- VideoDecodeService.java
private native long newNative(int bufferCapacity);
private native void releaseNative(long nativeAddress);
private native void setProjectNative(long nativeAddress, double startTime, byte[] projectData);
private native void startNative(long nativeAddress);
private native String getRenderFrameNative(long nativeAddress, double renderTime);
private native void updateProjectNative(long nativeAddress, byte[] projectData);
private native void seekNative(long nativeAddress, double seekTime);
private native void stopNative(long nativeAddress);
private native boolean endedNative(long nativeAddress);
private native boolean stoppedNative(long nativeAddress);
private native int getBufferedFrameCountNative(long nativeAddress);
如代码块1所示,我们先来讲讲 VideoDecodeService 的 API
newNative
:由前面几章的讲解我们知道,VideoDecoderService 内部有一个先进先出的阻塞队列,这个方法的入参 bufferCapacity
就是用于设置这个阻塞队列的长度。这个方法调用之后 Native 层会创建一个与 Java 层同名的 VideoDecodeService.cpp 对象。然后返回一个 long
表示这个 Cpp 对象的地址。我们会将其记录在 Java 层,后续要调用其他方法时需要通过这个地址找到相应的对象。releaseNative
:因为 Cpp 没有垃圾回收机制,所以 Cpp 对象都是需要手动释放的,所以这个方法就是用于释放 VideoDecodeService.cpp 对象。setProjectNative
:因为 Protobuf 是高效的跨平台通信协议,所以 Java 与 Cpp 层的通信方式使用的就是 Protobuf,我们可以看 ws_video_editor_sdk.proto 这个文件,里面定义的 EditorProject 就是两端一起使用的数据结构。这个方法的入参 nativeAddress
就是我们在 1 中获取到的对象地址。入参 startTime
表示起始的解码点,单位是秒。入参 projectData
就是 EditorProject 序列化之后的字节流。startNative
:这个方法表示开始解码。getRenderFrameNative
:这个方法表示获取 renderTime
这一时刻的帧数据,目前返回到 Java 层的是一个 String
,在 Cpp 层后续我们主要就是使用这个方法获取到的帧数据使用 OpenGL 绘制到屏幕上。updateProjectNative
:这个方法和 setProjectNative
类似,用于更新 EditorProject。seekNative
:我们在看视频的时候,将进度条拖动到某一时刻的操作被称为 seek,在 VideoDecodeService 中的体现就是这个方法,这个方法会将当前的解码时间点设置为 seekTime
。stopNative
:这个方法表示暂停解码。endedNative
:返回一个 boolean
表示视频的解码点是否到达了视频的结尾。stoppedNative
:返回了一个 boolean
表示当前是否暂停了解码。getBufferedFrameCountNative
:返回一个 int
,表示当前阻塞队列中有多少个帧,最大不会超过我们在 1 中设置的 bufferCapacity
。这一小节中,我使用一个完整的例子来分析 VideoDecodeService 的源码
initButton
中进行了下面这些操作newNative
方法。这个方法最终会进入到 video_decode_service.h 中调用 VideoDecodeService.cpp 的构造方法,构造方法则会创建一个 BlockingQueue.cpp 对象 decoded_unit_queue_
,这就是我们一直说的 先进先出阻塞队列/sdcard/test.mp4
stringBuilder
和 times
是用来记录测试数据的就不说了setProject
方法,进过一系列调用链后会通过 jni 进入到代码块3buffer
反序列化成 EditorProject.cpp 对象。address
强转 VideoDecodeService.cpp 对象。LoadProject
方法解析出一些数据,例如视频的帧率、宽高等等。有兴趣的读者可以跟进入看看。SetProject
给 VideoDecodeService.cpp 设置 EditorProject.cpp。start
最终也是到代码块3中,调用 Start
方法。我们继续进入 Start
方法中,发现其中是启动了一个线程然后调用 VideoDecodeService::DecodeThreadMain
,这个方法内部则是一个 while
循环,每当使用 FFMPEG 解码出一个视频帧的时候就会将这一帧放到 decoded_unit_queue_
中。当外部没有消费者时,decoded_unit_queue_
的帧数量将会很快达到阈值(我们设置的是10),此时这个线程就会被阻塞。直到外部消费后,帧数量减少了,本线程将会继续开始解码视频帧,如此往复。-----代码块3----- com_whensunset_wsvideoeditorsdk_inner_VideoDecoderService.cc
JNIEXPORT void JNICALL
Java_com_whensunset_wsvideoeditorsdk_inner_VideoDecodeService_setProjectNative
(JNIEnv *env, jobject, jlong address, jdouble render_pos, jbyteArray buffer) {
VideoDecodeService *native_decode_service = reinterpret_cast<VideoDecodeService *>(address);
model::EditorProject project;
jbyte *buffer_elements = env->GetByteArrayElements(buffer, 0);
project.ParseFromArray(buffer_elements, env->GetArrayLength(buffer));
env->ReleaseByteArrayElements(buffer, buffer_elements, 0);
LoadProject(&project);
native_decode_service->SetProject(project, render_pos);
}
JNIEXPORT void JNICALL Java_com_whensunset_wsvideoeditorsdk_inner_VideoDecodeService_startNative
(JNIEnv *, jobject, jlong address) {
VideoDecodeService *native_decode_service = reinterpret_cast<VideoDecodeService *>(address);
native_decode_service->Start();
}
getRenderFrame
方法来从 VideoDecodeService 中消费一个视频帧。然后把帧的信息打印到 TextView 上面。其实这里的代码可以类比为视频的播放,VideoDecodeService 不断地在后台线程进行解码按顺序将视频帧放入到队列中,本线程则不断的从队列中取出一帧进行消费,就像视频帧被渲染到屏幕上一样。自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
进阶学习视频
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。