"本文转载自:[wangxiuwen12]的Android集成ijkplayer做自己的播放器"
1.简介
继上一篇文档《Ubuntu20.04编译android平台ijkplayer源码》ijkplayer编译成功后,在android/ijkplayer路径下会生成一些重要的文件夹:
build.gradle gradlew ijkplayer-armv5 ijkplayer-exo ijkplayer-x86_64 tools
gradle gradlew.bat ijkplayer-armv7a ijkplayer-java local.properties
gradle.properties ijkplayer-arm64 ijkplayer-example ijkplayer-x86 settings.gradl
其中ijkplayer-arm*和ijkplayer-x86*对应不同ABI平台的工程,其中包含了编译出来的so库。在实际开发过程中,只需要根据自己的andorid设备的cpu架构选择其中一个就可以,不用将所有的都加入进去。
ijkplayer-example和ijkplayer-exo是官方给的封装好的播放器;ijkplayer-java这个moudle,顾名思义这个就是对于so库的native接口,我们直接调用里面的 IjkMediaPlayer类就可以了,用法和MediaPlayer一样。
所以AS项目中引用ijkplayer的基本思路是:
(1)导入对应平台的so库;
(2)导入ijkplayer-java;
(3)调用ijkplayer-java模块里面IjkMediaPlayer类播放。
2.导入so库
通过下面的命令确定android设备cpu的架构:
adb shell getprop ro.product.cpu.abi
结果:
armeabi-v7a
根据android设备将整个armeabi-v7a文件夹(里面包含三个so库)拷贝到Android Studio项目中,对应路径:app/libs。
3.导入ijkplayer-java
在Android Studio项目中选择File -> New -> Import Moudle,然后选择ijkplayer-java,就会导入。然后需要改的就是Moudle里面的build.gradle 设置里面的SDK version,要和你当前的工程SDK版本一样,可能之前在Ubuntu上面编译的SDK不一样。还有一处会报错,那就是:
apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle");
这个明显就是没有找到tools这个文件夹,所以我们把tools文件夹复制到工程里面,这样就不会报错了。
4.配置参数
在项目的 build.gradle 文件中,添加 ijkplayer 的依赖库。具体代码如下:
(1)ijkplayer-java/build.gradle
由于ijkplayer-java是在ubuntu中编译出来,所以它的SDK的版本和当前AS项目的SDK不一样,需要修改成AS项目一致。
- 需要修改的参数:
compileSdkVersion 33
buildToolsVersion "31.0.0"
minSdkVersion 27
targetSdkVersion 33
implementation fileTree(dir: 'libs', include: ['*.jar'])
- 修改后完整的文件
apply plugin: 'com.android.library'
android {
// http://tools.android.com/tech-docs/new-build-system/tips
//noinspection GroovyAssignabilityCheck
compileSdkVersion 33
//noinspection GroovyAssignabilityCheck
buildToolsVersion "31.0.0"
lintOptions {
abortOnError false
}
defaultConfig {
minSdkVersion 27
targetSdkVersion 33
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {{
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle");
(2)app/build.gradle
- 需要修改的参数:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
--------------
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':ijkplayer-java')
- 修改后完整的文件
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.myijkplayer'
compileSdk 33
defaultConfig {
applicationId "com.example.myijkplayer"
minSdk 27
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':ijkplayer-java')
}
(3)setting.gradle
如果使用Import Moudle时会自动添加,如果是复制进项目的需要手动添加。
include ':ijkplayer-java'
5.demo
(1)AndroidMenifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
(2)activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<SurfaceView
android:layout_width="720dp"
android:layout_height="500dp"
android:id="@+id/video_test"/>
<Button
android:layout_width="100dp"
android:layout_height="80dp"
android:text="开始"
android:id="@+id/start_view"/>
<Button
android:layout_width="100dp"
android:layout_height="80dp"
android:text="停止"
android:id="@+id/stop_view"/>
</LinearLayout>
(3)MainActivity.java
package com.example.myijkplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.content.res.AssetFileDescriptor;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.IOException;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
public class MainActivity extends AppCompatActivity {
private SurfaceView surfaceView;
private Button start_bofang;
private Button stop_bofang;
private IjkMediaPlayer ijkMediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_bofang = (Button)findViewById(R.id.start_view);
stop_bofang = (Button)findViewById(R.id.stop_view);
surfaceView =(SurfaceView)findViewById(R.id.video_test);
surfaceView.getHolder().addCallback(callback);
new newInit().start();
start_bofang.setOnClickListener(onClickListener);
stop_bofang.setOnClickListener(onClickListener);
}
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.start_view:
new myThread().start();
break;
case R.id.stop_view:
ijkMediaPlayer.stop();
break;
default:
break;
}
}
};
private void InitIjk(){
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin("libijkplayer.so");
IjkMediaPlayer.native_profileBegin("libijkffmpeg.so");
IjkMediaPlayer.native_profileBegin("libijksdl.so");
ijkMediaPlayer = new IjkMediaPlayer();
}
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
ijkMediaPlayer.setDisplay(surfaceHolder);
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
};
private class newInit extends Thread{
@Override
public void run() {
InitIjk();
super.run();
}
}
private class myThread extends Thread{
@Override
public void run() {
try {
ijkMediaPlayer.setDataSource("/sdcard/h264.mp4");
} catch (IOException e) {
e.printStackTrace();
}
ijkMediaPlayer.prepareAsync();
ijkMediaPlayer.setDisplay(surfaceView.getHolder()); //将视频画面输出到surface上
ijkMediaPlayer.start(); //开始播放
super.run();
}
}
}
注:其中视频文件h264.mp4需要将其拷贝到android设备的/sdcard路径下。