android 使用 IJKPlayer 播放視頻流的實(shí)現(xiàn)代碼
最近在做音視頻相關(guān)的內(nèi)容,這就無(wú)法避開視屏采集和播放的問題了,然后播放器使用的是 ijkplayer,這個(gè)東西使用 url 播放倒是沒啥問題,只是我們的方案是接收 flv 的視頻流進(jìn)行播放,這需要借助 IAndroidIO 這個(gè)接口,也可以用于播放本地文件。
實(shí)現(xiàn) IAndroidIO 接口
播放類的實(shí)現(xiàn)
class ReadByteIO private constructor(): IAndroidIO {
companion object {
private var instance: ReadByteIO? = null
var URL_SUFFIX = "recv_data_online"
@Synchronized
fun getInstance(): ReadByteIO { // 單例
instance?.let {
return it
}
instance = ReadByteIO()
return instance!!
}
}
private var TAG = ReadByteIO::class.java.simpleName
private var flvData = LinkedBlockingDeque<Byte>() // 內(nèi)存隊(duì)列,用于緩存獲取到的流數(shù)據(jù),要實(shí)現(xiàn)追幀效果,只需要根據(jù)策略丟棄本地緩存的內(nèi)容即可
private fun takeFirstWithLen(len : Int): ByteArray { // 取 byte 數(shù)據(jù)用于界面渲染
var byteList = ByteArray(len)
for (i in 0 until len) {
byteList[i] = flvData.take()
}
return byteList
}
@Synchronized
fun addLast(bytes: ByteArray): Boolean {
var tmpList:List<Byte> = bytes.toList()
Log.e(TAG, "tmpList size " + tmpList.size)
return flvData.addAll(tmpList)
}
// 如果是播放本地文件,可在此處打開文件流,后續(xù)讀取文件流即可
override fun open(url: String?): Int {
if (url == URL_SUFFIX) {
return 1 // 打開播放流成功
}
return -1 // 打開播放流失敗
}
override fun read(buffer: ByteArray?, size: Int): Int {
var tmpBytes = takeFirstWithLen(size) // 阻塞式讀取,沒有數(shù)據(jù)不渲染畫面
System.arraycopy(tmpBytes, 0, buffer, 0, size)
return size
}
override fun seek(offset: Long, whence: Int): Long {
return 0
}
override fun close(): Int {
return 0
}
}
調(diào)用播放類
接下來(lái),就看看如何調(diào)用播放實(shí)例了。注意:我們還是需要傳入一個(gè) url,只是這個(gè) url 是我們自定義的
public class RecordVideoActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
private String TAG = RecordVideoActivity.class.getSimpleName();
private IjkMediaPlayer player;
private Surface surface;
private TextureView playView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record_video);
playView = findViewById(R.id.v_play);
playView.setSurfaceTextureListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (player != null) {
player.stop();
}
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
if (surface != null) {
this.surface = new Surface(surface);
play(); // 存在 surface 實(shí)例再做播放
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { }
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false; }
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
private void play() {
player = new IjkMediaPlayer();
player.reset();
player.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 100);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 25 * 1024);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "threads", 1);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "sync-av-start", 0);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec",1);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
player.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "ijkio,crypto,file,http,https,tcp,tls,udp"); // 屬性設(shè)置支持,轉(zhuǎn)入我們自定義的播放類
player.setSurface(this.surface);
player.setAndroidIOCallback(ReadByteIO.Companion.getInstance());
Uri uri = Uri.parse("ijkio:androidio:" + ReadByteIO.Companion.getURL_SUFFIX()); // 設(shè)定我們自定義的 url
try {
player.setDataSource(uri.toString());
} catch (IOException e) {
e.printStackTrace();
}
player.prepareAsync();
player.start();
}
}
到此這篇關(guān)于android 使用 IJKPlayer 播放視頻流的文章就介紹到這了,更多相關(guān)android 播放視頻流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Flutter實(shí)現(xiàn)頁(yè)面路由及404路由攔截
這篇文章介紹了Flutter實(shí)現(xiàn)頁(yè)面路由及404路由攔截的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-11-11
Android動(dòng)態(tài)添加menu菜單的簡(jiǎn)單方法
Android動(dòng)態(tài)添加menu菜單的簡(jiǎn)單方法,需要的朋友可以參考一下2013-06-06
Android Studio實(shí)現(xiàn)仿微信APP門戶界面詳解及源碼
這篇文章帶你通過(guò)Android studio來(lái)實(shí)現(xiàn)微信APP的門戶界面,主要說(shuō)明框架的各部分功能與實(shí)現(xiàn)過(guò)程,下文包含了整個(gè)開發(fā)過(guò)程,以及解決問題的思路并再末尾提供了源碼鏈接2021-10-10
Android開發(fā)中父組件調(diào)用子組件方法demo
這篇文章主要為大家介紹了Android開發(fā)中父組件調(diào)用子組件方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android UI設(shè)計(jì)系列之自定義ListView仿QQ空間阻尼下拉刷新和漸變菜單欄效果(8)
這篇文章主要介紹了Android UI設(shè)計(jì)系列之自定義ListView仿QQ空間阻尼下拉刷新和漸變菜單欄效果,具有一定的實(shí)用性和參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
Android自定義照相機(jī)Camera出現(xiàn)黑屏的解決方法
這篇文章主要介紹了Android自定義照相機(jī)Camera出現(xiàn)黑屏的解決方法,分析了黑屏出現(xiàn)的原因及參考解決方法,需要的朋友可以參考下2016-08-08

