“社畜”的手机视频体验
作为一名社畜,白天要把时间献给代码,晚上要把时间献给家庭,真正属于自己的时间,算来算去也只有每天搭乘公共交通的通勤时间能够*支配。不过,因为身处车厢哪也去不了,这种*也仅限于掏出手机刷哪部剧,看哪个直播而已。
但即便是这仅有的一点休闲,我们也只能看超低分辨率、超卡顿的视频。原因无他,地铁信号实在、实在太差了!
就拿我现在都没看全的几个奥运大项决赛来说,在信号不好的公交或地铁上看比赛,开低分辨率是保持流畅的唯一方法。但在低分辨率下看比赛,你既看不见球在哪,也分不清谁是谁;基本等于看了个寂寞。
如果分辨率太低,在乒乓球、网球这样的小球比赛里,两个运动员就像在隔空做广播体操,完全看不见球在哪;在足球、排球、网球这样的团队竞技中,也完全看不出来同一个队里谁是谁;而在跳水这样的项目中,每个人入水都没什么水花,都是9.5水平……
那么,面对此起彼伏的视频内容风口,除了指望运营商能多建几个基站之外,作为开发者,我们有什么能做的吗?
答案很简单,视频超分辨率!
超分辨率,过去很复杂,现在很简单
在GitHub上随手一搜,我们就能看到数千个与超分辨率相关的项目,其中还有不少经常维护的技术合集,可以说是百花齐放。不过真到了实践阶段,你就会发现,这些开源项目不仅需要很多DL方面的框架知识,集成到项目中也是非常麻烦的事情。缺少相关技术大牛的小团队想要搞定视频超分,别说赶眼前的内容风口了,能赶下半年的内容风口就不错了。
不过最近,华为HMS Core 6.0全球上线,其新推出的多媒体管线服务(AV Pipeline Kit,简称AV Pipeline)中,提供了视频超分插件。开发者只需将AV Pipeline的SDK集成到自己的视频播放器应用中并完成UI的适配便可实现视频超分功能。
AV Pipeline框架支持在播放过程中进行视频的逐帧超分。而除视频播放Pipeline的插件外,还包含视频超分插件CVFilter。编排关系如上图所示。
话不多说,我们来实战:
1 开发准备
1.1 新建Android Studio工程,修改工程级build.gradle文件,在“allprojects > repositories”里面增加华为的Maven仓地址。
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
1.2 打开项目中应用级的“build.gradle”文件。在dependencies中添加编译依赖。
dependencies {
...
implementation 'com.huawei.hms:avpipelinesdk:6.0.0.302'
implementation 'com.huawei.hms:avpipeline-aidl:6.0.0.302'
implementation 'com.huawei.hms:avpipeline-fallback-base:6.0.0.302'
implementation 'com.huawei.hms:avpipeline-fallback-cvfoundry:6.0.0.302'
}
1.3 在完成以上的配置后,点击工具栏中的gradle同步图标,完成“build.gradle”文件的
同步,将相关依赖下载到本地。
2 开发步骤
2.1 动态申请存储权限
private void handlePermission() {
String[] permissionLists = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE
};
int requestPermissionCode = 1;
for (String permission : permissionLists) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissionLists, requestPermissionCode);
}
}
}
2.2 初始化AV Pipeline框架。
private void initFwk() {
if (AVPLoader.isInit()) {
Log.d(TAG, "avp framework already inited");
return;
}
boolean ret = AVPLoader.initFwk(getApplicationContext());
if (ret) {
makeToastAndRecordLog(Log.INFO, "avp framework load succ");
} else {
makeToastAndRecordLog(Log.ERROR, "avp framework load failed");
}
}
2.3 创建MediaPlayer实例。播放过程的控制由该实例来完成。
//创建MediaPlayer实例
mPlayer = MediaPlayer.create(MediaPlayer.PLAYER_TYPE_AV);
2.4 设置graph配置文件。AV Pipeline框架依赖于该配置文件来编排各个插件。此外还需要将MEDIA_ENABLE_CV的值设置为1,激活视频超分插件。
protected void setGraph() {
String path = getExternalFilesDir(null).getPath() + "/PlayerGraphCV.xml";
MediaMeta meta = new MediaMeta();
meta.setString(MediaMeta.MEDIA_GRAPH_PATH, path);
meta.setInt32(MediaMeta.MEDIA_ENABLE_CV, 1);
mPlayer.setParameter(meta);
}
2.5 以下为视频超分Pipeline的graph配置文件PlayerGraphCV.xml。
<?xml version="1.0"?>
<Nodes>
<node id="0" name="AVDemuxer" mime="media/demuxer" type="source">
<!-- 数据流从这里开始分两路,一路到视频解码节点node 1,一路到音频解码节点node 2 -->
<next id="1"/>
<next id="2"/>
</node>
<!-- 视频解码节点将解码后的图像送到下一个节点,即next id号对应的3号CVFilter节点 -->
<node id="1" name="MediaCodecDecoder" mime="video/avc" type="filter">
<next id="3"/>
</node>
<!-- 音频解码节点将解码后的音频送到下一个节点,即next id号对应的4号AudioSinkOpenSL节点 -->
<node id="2" name="FFmpegNode" mime="audio/aac" type="filter">
<next id="4"/>
</node>
<!-- node的name、mime、type参考示例中的定义。node id应当唯一,建议为上一个node id加1即可 -->
<node id="3" name="CVFilter" mime="video/cv-filter" type="filter">
<!-- next id为视频流从本节点出去后需要到达的下一个节点,本示例中为送显节点 -->
<next id="5" />
</node>
<node id="4" name="AudioSinkOpenSL" mime="audio/sink" type="sink">
</node>
<node id="5" name="VideoSinkBasic" mime="video/sink" type="sink">
</node>
</Nodes>
2.6 设置以下参数后调用prepare接口,启动MediaPlayer准备工作。
//创建MediaPlayer实例
mPlayer = MediaPlayer.create(MediaPlayer.PLAYER_TYPE_AV);
if (mPlayer == null) {
return;
}
//设置graph配置文件
setGraph();
if (getPlayerType() == MediaPlayer.PLAYER_TYPE_AV) {
// 设置视频渲染的surface
SurfaceView mSurfaceVideo = findViewById(R.id.surfaceViewup);
SurfaceHolder mVideoHolder = mSurfaceVideo.getHolder();
int ret = mPlayer.setVideoDisplay(mVideoHolder.getSurface());
if (ret != 0) {
makeToastAndRecordLog(Log.ERROR, "setVideoDisplay failed, ret=" + ret);
return;
}
}
// 设置待播放媒体文件的路径
int ret = mPlayer.setDataSource(mFilePath);
if (ret != 0) {
makeToastAndRecordLog(Log.ERROR, "setDataSource failed, ret=" + ret);
return;
}
//启动MediaPlayer准备工作
mPlayer.prepare();
2.7 调用start开始播放
mPlayer.start();
2.8 停止播放和销毁播放器
mPlayer.stop();
mPlayer.reset();
mPlayer.release();
mPlayer = null;
视频超分辨率效果对比
在AV Pipeline的demo中我们可以看到,在开启超分辨率后,画质、色彩和亮度均获得了不同程度的提升,观看体验提升还是比较明显的。而最重要的是,相对于其他超分辨率实现手段,通过调用HMS Core的方法实现超分非常简单。这相当于以很低的开发成本给你的视频应用带来体验的大幅升级;何乐而不为?
HMS Core与未来
HMS Core是华为软硬件开放能力的合集,其目的在于帮助应用开发者简化开发流程,让APP能够以更简单、更高效、更低成本的方式完成功能开发,为尽可能多的最终用户提供优秀且一致的应用体验。
从最初的帐号、支付、推送服务一路走来,目前的HMS Core 6.0已经能够提供应用服务、AI、媒体、智能设备连接、图形、安全和连接通信等七大类、几十种开放能力和数百种功能。从用户登录、广告推送,到图形渲染、机器学习、音视频编辑,再到5G、网络聚合、NFC……HMS Core用庞大的代码库为开发者提供了构建APP所需的各类功能模块。利用HMS Core,开发者要做的便是展开想象力,用无数块“积木”搭建出属于自己的App城堡并开始运营。可以说HMS Core不仅降低了移动App开发的门槛,也提升了开发的敏捷性和上限。
华为不仅维护了全球数百万开发者参与的社区,更在gitee、GitHub上有海量的代码库和demo可供参考。无论大团队、小团队还是个人都可以通过调用HMS Core获得开发上的便利。
另一方面,面向手机、智能终端和物联网设备的HarmonyOS在上线后的短短一个多月时间内便迅速在全球迅速积累了数千万用户和设备,并拥有数十家重量级设备合作伙伴。在这一全新OS生态中的布局是App提供新体验、获得新用户的重要途径。而HMS生态是运行在操作系统之上的应用和服务生态,可运行在HarmonyOS上。现有Android应用已经使用了HMS Core的能力可在HarmonyOS可以继续使用,这很大降低了开发者进入HarmonyOS生态的门槛,并让多版本App的维护变得异常简单。
更简便的开发、更全面的功能、更好的体验,外加更庞大的生态……