在之前的项目中使用原生VideoView,存在一个加载非常慢的问题,为了提升加载速度,在项目中使用ExoPlayer来替换原视频方案.
ExoPlayer是Google提供的开源视频库,提供了功能更强大的媒体播放功能,支持多种格式
https://github.com/google/ExoPlayer
我这里只需要能播最普通的Mp4即可,参考官方Demo,删减一下,就能得到一个简单的视频播放器,然后移植到原项目即可。
然而在移植过程中遇见了很大问题。
由于我们项目是使用Android.mk文件完成编译的,没法通过Gradle导入依赖,于是首先想到去找jar包,然而官方并没有提供,网上提供的下载源码,编译jar包的方法,
./gradlew jarRelease
只适合2.0.1以下的版本,以后的版本删除了这个task。
于是想到在gradle缓存目录中查找自动下载的jar包,在
~/.gradle/caches/modules-2/files-2.1/com.google.android.exoplayer
找到了自动下载的jar包,除了有jar的包之外,还有aar的包,然后将jar包导入工程后,结果失败,提示缺少资源文件。后来才知道,主角应该是那个aar的包。
后来问了下同事,了解到aar包中除了包含类之外,还包含了资源文件,而ExoPlayer工程中包含了许多资源文件,不能舍弃。于是现在主要需要解决的是将aar文件使用Android.mk文件导入
LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages com.google.android.exoplayer2.ui
LOCAL_STATIC_JAVA_AAR_LIBRARIES :=exoplayer_core exoplayer_ui
....
省略
...
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := exoplayer_ui:libs/library-ui-release.aar \
exoplayer_core:libs/library-core-release.aar \
include $(BUILD_MULTI_PREBUILT)
https://stackoverflow.com/questions/31205856/aar-support-in-android-mk
上边是网上搜到的Android.mk引入aar的方法
LOCAL_AAPT_FLAGS那块的作用是为ExoPlayer单独生成一个R文件,避免找不到相关资源
然后编译工程,结果提示targetSdk不符,我的工程targetSdk需要23,而ExoPlayer的aar文件targetSdk为25。本来这是个大问题,不过之前尝试下源码编jar包的时候,碰巧找到了这个问题的解决方法。
进入ExoPlayer 源码目录,
./gradlew task
可以列出所支持的所有任务,然后compileReleaseSources这个任务吸引了我的注意,尝试执行了下
./gradlew compileReleaseSources
然后在ExoPlayer-release-v2/library/core/buildout/outputs/aar
目录下生成了编译出的aar包,放到Android Studio里试验了下,果然好使。
这样我们修改源码根目录下的build.gradle文件中的targetSdkVersion,改为23,就可以了,
不过实际还有问题,网上搜了下,结果发现,还需要降低gradle的版本,修改如下
classpath 'com.android.tools.build:gradle:2.2.3'
这样再编译出的aar文件,就符合要求了,导入工程再次尝试,结果还是出现问题
提示,
com.google.android.exoplayer2.decoder.CryptoInfo文件有问题
其中有个v24的方法找不到所需的class,这个可能跟我们修改了Android源码有关,进去看了下源码,发现这个v24方法可以砍掉,现在体会到了代码开源的好处,遇到特殊问题,可以自己修改然后编译。
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.decoder;
import android.annotation.TargetApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Util;
/**
* Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}.
*/
public final class CryptoInfo {
/**
* @see android.media.MediaCodec.CryptoInfo#iv
*/
public byte[] iv;
/**
* @see android.media.MediaCodec.CryptoInfo#key
*/
public byte[] key;
/**
* @see android.media.MediaCodec.CryptoInfo#mode
*/
@C.CryptoMode
public int mode;
/**
* @see android.media.MediaCodec.CryptoInfo#numBytesOfClearData
*/
public int[] numBytesOfClearData;
/**
* @see android.media.MediaCodec.CryptoInfo#numBytesOfEncryptedData
*/
public int[] numBytesOfEncryptedData;
/**
* @see android.media.MediaCodec.CryptoInfo#numSubSamples
*/
public int numSubSamples;
/**
* @see android.media.MediaCodec.CryptoInfo.Pattern
*/
public int patternBlocksToEncrypt;
/**
* @see android.media.MediaCodec.CryptoInfo.Pattern
*/
public int patternBlocksToSkip;
private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo;
public CryptoInfo() {
frameworkCryptoInfo = Util.SDK_INT >= 16 ? newFrameworkCryptoInfoV16() : null;
}
/**
* @see android.media.MediaCodec.CryptoInfo#set(int, int[], int[], byte[], byte[], int)
*/
public void set(int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
byte[] key, byte[] iv, @C.CryptoMode int mode) {
this.numSubSamples = numSubSamples;
this.numBytesOfClearData = numBytesOfClearData;
this.numBytesOfEncryptedData = numBytesOfEncryptedData;
this.key = key;
this.iv = iv;
this.mode = mode;
patternBlocksToEncrypt = 0;
patternBlocksToSkip = 0;
if (Util.SDK_INT >= 16) {
updateFrameworkCryptoInfoV16();
}
}
public void setPattern(int patternBlocksToEncrypt, int patternBlocksToSkip) {
this.patternBlocksToEncrypt = patternBlocksToEncrypt;
this.patternBlocksToSkip = patternBlocksToSkip;
}
/**
* Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance.
* <p>
* Successive calls to this method on a single {@link CryptoInfo} will return the same instance.
* Changes to the {@link CryptoInfo} will be reflected in the returned object. The return object
* should not be modified directly.
*
* @return The equivalent {@link android.media.MediaCodec.CryptoInfo} instance.
*/
@TargetApi(16)
public android.media.MediaCodec.CryptoInfo getFrameworkCryptoInfoV16() {
return frameworkCryptoInfo;
}
@TargetApi(16)
private android.media.MediaCodec.CryptoInfo newFrameworkCryptoInfoV16() {
return new android.media.MediaCodec.CryptoInfo();
}
@TargetApi(16)
private void updateFrameworkCryptoInfoV16() {
// Update fields directly because the framework's CryptoInfo.set performs an unnecessary object
// allocation on Android N.
frameworkCryptoInfo.numSubSamples = numSubSamples;
frameworkCryptoInfo.numBytesOfClearData = numBytesOfClearData;
frameworkCryptoInfo.numBytesOfEncryptedData = numBytesOfEncryptedData;
frameworkCryptoInfo.key = key;
frameworkCryptoInfo.iv = iv;
frameworkCryptoInfo.mode = mode;
}
}
修改之后再编译,然后导入工程中,通过了,完美~
做了这个项目,ExoPlayer没了解太多,结果把gradle和Android.mk了解了不少,收货颇丰。
参考连接
http://blog.csdn.net/xiaowan0404/article/details/52166969