分析ijkplayer

ijkplayerは、より優れたオープンソースのAndroid / IOSクロスプラットフォームのプレーヤー、ベースffplay、容易な統合、カスタマイズ可能なコンパイル済みのボリュームコントロールのためのAPIです。

ベースの0.8.8バージョンijkplayerを、それは異なるプラットフォームの下にパッケージまたはインタフェースを扱うことになると、そのソースを分析しているAndroidの例。

ijkplayerアンドロイドは達成するために3人の選手を統合します。

  • AndroidMediaPlayer:すなわちアンドリュースプレーヤーが来るのMediaPlayer、ベースMediaCodec、AudioTrack他のAndroid APIを。
  • IjkExoMediaPlayer:Googleの新しいことExoPlayer、また、AndroidのAPIとしてMediaCodec、AudioTrackをベースにしていますが、MediaPlayerのに比べてはそうでサポートDASH、シニアHLS、カスタム拡張としています。
  • IjkMediaPlayer:なFFmpegに基づいてffplay、MediaCodecは、OpenGLのようなレンダリング、ハードウェアデコーダを統合しました。

一般に、ijkplayerが参照IjkMediaPlayerを、この分析の目的は、IjkMediaPlayerあります。

ディレクトリ構造

1 
2
3
4
5
6
7
8
9
ijkplayer(プロジェクトフォルダ)
├──tools -初期化スクリプトプロジェクト
├──config - ffmpegののコンパイルに使用する設定ファイル
├──extraを-などのffmpeg、opensslの、その他など必要な依存ijkplayerコンパイラは、ソースファイル、
├──ijkmedia -コアコード
├──ijkplayer -プレイヤーデータダウンロードおよびデコード関連
├──ijksdl -オーディオおよびビデオデータに関連するレンダリング
インターネットのAndroidプラットフォーム上で上位インタフェースパッケージおよび関連する方法- ├──androidを
├──ios - iOSの上位インタフェースパッケージやインターネット関連の方法

機能の違いを達成するためのプラットフォーム

IOSとAndroidプラットフォームの違いは主で

  • ビデオのハードウェアデコード
  • オーディオレンダリング
  • ビデオレンダリング
プラットフォーム ハードウェアコーデック ビデオのレンダリング 音声出力
アンドロイド MediaCodec OpenGL ES、MediaCodec OpenSL ES、AudioTrack
iOS版 VideoToolBox OpenGL ES AudioQueue

IjkMediaPlayerとネイティブの相互作用

再生制御に関連するstart、pause、stopそのような方法は、対応するネイティブ呼び出し

(そのような状況基礎となるコールバック演奏など)のステータスレポート情報の下の関連はpostEventFromNative、これらの方法は、(でボトムを呼び出すためのイニシアチブをとる@CalledByNativeコメント)

初期化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class  extends AbstractMediaPlayer {
private void initPlayer(IjkLibLoader libLoader) {
loadLibrariesOnce(libLoader);
initNativeOnce();

Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}


* Native setup requires a weak reference to our object. It's easier to
* create it here than in C++.
*/
native_setup(new WeakReference<IjkMediaPlayer>(this));
}
}

initPlayer 方法,共做了四件事:

  • 加载 so 库
  • 静态初始化底层,底层其实什么都没做
  • 初始化 Message Handler,处理底层状态信息的上报
  • 初始化底层,这部分做的工作最多

初始化底层

c代码

ijkplayer/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ijkmedia/ijkplayer/android/

主要逻辑位于

ijkpalyer_android.cijkmp_android_create 方法

1
2
3
4
5
6
7
8
// 创建底层播放器对象,设置消息处理函数
IjkMediaPlayer *mp = ijkmp_create(msg_loop, saveMode, hard_mux);

// 创建图像渲染对象
mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface();

// 初始化视频解码器(软/硬)、音频输出设备(opensles/audioTrack)
mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);

软硬解码选择

跟踪 pipeline/ffpipeline_android.cffpipeline_create_from_android 方法

发现是 用函数指针记录 类 IjkMediaPlayer.setOption() 设置的属性

配置

初始化后 IjkMediaPlayer 后,可以对其进行一系列配置,例如:

1
2
3
4
5
// 设置硬解码
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);

// 设置 opensles 方式输出音频
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);

setOption() 会调用到底层 ff_ffplay.c 的 ffp_set_option() 方法

播放

播放器必然是通过多线程同时进行解封装、解码、视频渲染等工作的,对于 Ijkplayer 来说,开辟的线程如下:

当对播放器设置视频源路径、解码方式、输出模式等播放选项后,就可以开始播放了, 播放入口方法为 ffp_prepare_async_l,此方法中调用了比较重要的两个方法:

1
2
3
4
5
// 打开音频输出设备
ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);
...
// 创建音/视频数据解码前/后队列, 创建解封装和视频渲染线程
VideoState *is = stream_open(ffp, file_name, NULL);

stream_open 方法则相当重要了,梳理一下该方法中涉及到的关键方法:

音视频同步

对于播放器来说,音视频同步是一个关键点,同时也是一个难点,同步效果的好坏,直接决定着播放器的质量。

通常音视频同步的解决方案就是选择一个参考时钟,播放时读取音视频帧上的时间戳,同时参考当前时钟参考时钟上的时间来安排播放。如下图所示:

如果音视频帧的播放时间大于当前参考时钟上的时间,则不急于播放该帧,直到参考时钟达到该帧的时间戳;如果音视频帧的时间戳小于当前参考时钟上的时间,则需要“尽快”播放该帧或丢弃,以便播放进度追上参考时钟。

参考时钟的选择

有多种方式:

  • 选取视频时间戳作为参考时钟源
  • 选取音频时间戳作为参考时钟源
  • 选取外部时间作为参考时钟源

考虑人对视频、和音频的敏感度,在存在音频的情况下,优先选择音频作为主时钟源。

ijkplayer デフォルト用いた場合であるオーディオを基準源として

イベント処理

再生中は、レンダリングを開始、そのような完全な準備などの特定の行動を、変更または完全な、上位層は、特定のビジネスプロセスを作成するように、イベントの外形を通知する必要があります。

外部に通知され、プレイヤーが実際にあるときに、イベントを報告する基礎となるメッセージは、メッセージキューに送信すると、別のスレッドがキューからメッセージを取得していきます

リファレンス&拡張

オリジナル:ビッグボックス  ijkplayer分析


おすすめ

転載: www.cnblogs.com/dajunjun/p/11641093.html
おすすめ