前言
Ijkplayer是B站开源的一款多媒体播放引擎,其基于ffmpeg开并支持很多的在线媒体播放格式。本文实现了在安卓TV上播放各大电视台的直播,其格式是.m3u8。当然了只要是编译的Ijkplayer支持的格式这款播放器自然可以播放。
首先上界面:
播放器界面非常简单,因为是用电视遥控器操作,所以布局和操作力求简单易用。布局分为播放区域和左侧菜单,按遥控器的确定按钮调出菜单,可以选择界面确认后进入播放界面。下面开始讲如何实现:
播放器主界面布局文件activity_play_rel.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
复制代码
|
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <RelativeLayout android:id="@+id/fl_videoview" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorBlack"> <com.gxf.liveplay.ijkplayer.media.IjkVideoView android:id="@+id/videoview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:background="@color/colorBlack"></com.gxf.liveplay.ijkplayer.media.IjkVideoView> <RelativeLayout android:id="@+id/rl_loading" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#de262a3b"> <TextView android:id="@+id/tv_load_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/pb_loading" android:layout_centerInParent="true" android:layout_marginTop="6dp" android:textColor="#ffffff" android:textSize="16sp" /> <ProgressBar android:id="@+id/pb_loading" android:layout_width="60dp" android:layout_height="60dp" android:layout_centerInParent="true" android:layout_marginTop="60dp" android:indeterminate="false" android:indeterminateDrawable="@drawable/video_loading" android:padding="5dp" /> </RelativeLayout> <!-- <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/player_panel_background_color"> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="60dp" android:textSize="24dp" android:text="" android:layout_centerVertical="true" android:layout_marginTop="18dp" android:textColor="@color/white"/> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="60dp" android:textSize="20dp" android:layout_toRightOf="@id/tv_title" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:layout_marginTop="20dp" android:textColor="@color/white"/> </LinearLayout>--> </RelativeLayout> </LinearLayout> <include layout="@layout/layout_menu" />
</RelativeLayout>
复制代码
|
整体分为两部分:上边为播放器实现的界面布局,下边为左侧菜单布局。这里没有采用滑动调出左侧菜单的效果,只是采用相对布局通过设定菜单的宽带直接覆盖在播放器布局之上。IjkVidoView下边的是播放器的控制器布局,可以扩展实现进度音量等控制,本文尚未实现。
接下来看左侧菜单布局文件layout_menu.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
复制代码
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="360dp" android:layout_height="match_parent" android:id="@+id/leftMenuCtrl" android:layout_gravity="left" android:visibility="gone" android:background="@drawable/dark_no_shadow" android:orientation="vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" android:layout_gravity="center" android:orientation="horizontal"> <ImageButton android:id="@+id/turnLeft" android:layout_width="30px" android:layout_height="40px" android:layout_gravity="center" android:adjustViewBounds="false" android:background="@drawable/tv_switch_bg_left" android:onClick="turnLeft" /> <TextView android:id="@+id/tvGroupTitle" android:layout_width="300px" android:layout_height="100px" android:layout_gravity="center" android:gravity="center" android:text="我的频道" android:textColor="@color/white" android:textSize="24sp" android:textStyle="bold" /> <ImageButton android:id="@+id/turnRight" android:layout_width="30px" android:layout_height="40px" android:layout_gravity="center" android:adjustViewBounds="false" android:background="@drawable/tv_switch_bg_right" android:onClick="turnRight" /> </LinearLayout> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="9" android:layout_gravity="center" android:listSelector="@color/colorPrimaryDark"/>
</LinearLayout>
复制代码
|
上边的LinearLayout用于切换节目组,下边是ListView显示每个分组下的节目列表。这次布局就实现了,这是相当简单的。
二,实现播放
LiveActivityRel实现了播放功能,启动该Activity的时候传入媒体资源的地址mVideoUrl,然后启动Ijkplayer的播放功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
复制代码
|
public void initVideo() { // init player` IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin("libijkplayer.so"); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); mVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() { @Override public void onPrepared(IMediaPlayer mp) { mp.setVolume(100, 100); mVideoView.start(); } }); mVideoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() { @Override public boolean onInfo(IMediaPlayer mp, int what, int extra) { switch (what) { case IjkMediaPlayer.MEDIA_INFO_BUFFERING_START: mLoadingLayout.setVisibility(View.VISIBLE); break; case IjkMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: case IjkMediaPlayer.MEDIA_INFO_BUFFERING_END: mLoadingLayout.setVisibility(View.GONE); break; } return false; } }); mVideoView.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() { @Override public void onCompletion(IMediaPlayer mp) { mLoadingLayout.setVisibility(View.VISIBLE); mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); } }); mVideoView.setOnErrorListener(new IMediaPlayer.OnErrorListener() { @Override public boolean onError(IMediaPlayer mp, int what, int extra) { if (++mRetryTimes > CONNECTION_TIMES) { new AlertDialog.Builder(LiveActivityRel.this) .setMessage("该频道媒体资源出现错误,节目暂时不能播放...") .setPositiveButton(R.string.VideoView_error_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); //LiveActivityRel.this.finish(); } }) .setCancelable(false) .show(); } else { mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); } return false; } }); }
复制代码
|
这里也是很简答的,首先进行库的加载和初始化,绑定各种事件,然后在setOnPreparedListener中启动播放。其余的功能主要是涉及到UI和数据解析。节目列表是一个JSON结构,在原来的项目是有API进行登录和节目列表获取的。为了方便本文直接把节目列表写死,同时启动的Activity设置为MainActivityOffline。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
复制代码
|
package com.gxf.liveplay; import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast; /** * splash * 启动登录检测 */
public class MainActivityOffline extends Activity { private final int SPLASH_DISPLAY_LENGHT = 1000; // 两秒后进入系统 private boolean isUpdateChecked = false; public void checkLogin(){ SharedPreferences userSettings = getSharedPreferences("auth", Context.MODE_PRIVATE); final String lastVedioUrl = userSettings.getString("lastVedioUrl", "none"); final Toast toast = Toast.makeText(MainActivityOffline.this, "系统初始化失败...", Toast.LENGTH_SHORT); // 开启一个子线程,进行网络操作,等待有返回结果,使用handler通知UI new Thread(new Runnable() { @Override public void run() { try { PlayListCache.initPlayInfo(null,null); String url = lastVedioUrl; if (url.equals("none")) url = PlayListCache.playListMap.get(PlayListCache.playListMap.keySet().iterator().next()); LiveActivityRel.activityStart(MainActivityOffline.this, url); MainActivityOffline.this.finish(); } catch (Exception e) { toast.show(); e.printStackTrace(); } } }).start(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkLogin(); }
}
复制代码
|
启动App在一个线程里去获取节目列表并缓存起来放在PlayListCache中,然后调用LiveActivityRel并传入一个默认的播放地址(首次启动)或者上次播放的地址。至于登录和HttpUtils中的代码(主要用于节目列表和登录控制)就不在赘述了,因为不属于本文的重点。
三,项目的代码
github.com/gongxufan/T…
THE END
PS:本项目中的播放源地址可能会失效,如需测试需要更改可用的播放源。
具体代码在com.gxf.liveplay.HttpUtils#getOfflinePlayList,数据格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
复制代码
|
[ { "group": "省内频道", "list": [ { "湖南都市": "http://220.248.175.231:6610/001/2/ch00000090990000001049/index.m3u8?virtualDomain=001.live_hls.zte.com" }, { "湖南经视": "http://220.248.175.230:6610/001/2/ch00000090990000001052/index.m3u8?virtualDomain=001.live_hls.zte.com" } ] }, { "group": "其他频道", "list": [ { "安徽卫视": "http://220.248.175.230:6610/001/2/ch00000090990000001024/index.m3u8?virtualDomain=001.live_hls.zte.com" }, { "北京卫视": "http://220.248.175.230:6610/001/2/ch00000090990000001025/index.m3u8?virtualDomain=001.live_hls.zte.com" } ] }, { "group": "高清频道", "list": [ { "CCTV1综合HD": "http://220.248.175.230:6610/001/2/ch00000090990000001075/index.m3u8?virtualDomain=001.live_hls.zte.com" }, { "湖南经视HD": "http://220.248.175.230:6610/001/2/ch00000090990000001080/index.m3u8?virtualDomain=001.live_hls.zte.com" } ] }, { "group": "央视频道", "list": [ { "CCTV1综合": "http://220.248.175.230:6610/001/2/ch00000090990000001075/index.m3u8?virtualDomain=001.live_hls.zte.com" }, { "CCTV证券": "http://220.248.175.230:6610/001/2/ch00000090990000001133/index.m3u8?virtualDomain=001.live_hls.zte.com" } ] }
]
复制代码
|
【基于Ijkplayer】安卓机顶盒电视播放器开发相关推荐
- android 基于ijkplayer项目进行的播放器
jjdxm_ijkplayer 项目地址:jjdxm_ijkplayer 简介:基于 ijkplayer 简单的 UI 界面 当前项目是基于 ijkplayer 项目进行的播放器界面 UI 封装. 是 ...
- 【基于Python+tkinter的音乐播放器开发-哔哩哔哩】 https://b23.tv/eG2TwOL
[基于Python+tkinter的音乐播放器开发-哔哩哔哩] https://b23.tv/eG2TwOL https://b23.tv/eG2TwOL
- 基于android系统的音乐播放器,基于Android系统的音乐播放器软件设计与实现.doc
基于Android平台的音乐播放器 The Development of Mobile Music Player Based on Android platform system 学生学号: 学生姓名 ...
- 智能android电视更换播放器,GitHub - qfwc258/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- 智能android电视更换播放器,GitHub - kaigeLove/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- 智能android电视更换播放器,GitHub - xioxu/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- 异地过年,我要用它看春晚!- Qt趣味开发之基于QtAV的电视播放器
今年过年因为疫情的关系,在工作地点过年.家里穷的连个电视都没有,春晚都看不了,怎么办??!! QtAV是一个开源的音视频播放器,支持播放本地文件和网络流媒体.并集成了多种视频渲染方式,使用它的简单的A ...
- 张利国,龚海平,王植萌.android移动开发入门与进阶,开题报告-基于Android的手机音乐播放器的设计与实现.doc...
盐城师范学院 毕业设计开题报告 题 目: 基于android的手机音乐播放器 的设计与实现 姓 名: 二级学院: 信息工程学院 专 业: 软件工程 班 级: 12(1) 学 号: 指导教师: 职称: ...
- 基于VLC的播放器开发
VLC的C++封装 因为工作需要,研究了一段时间的播放器开发,如果从头开始做,可以学习下FFmpeg(http://www.ffmpeg.org/),很多播放器都是基于FFmpeg开发的,但是这样工作 ...
最新文章
- .NET判断字符串是否是数值型或xxx型
- 网页中PNG透明背景图片的完美应用
- HDU 4614 Vases and Flowers 【线段树】+【二分】
- Python编程基础:第五十五节 map函数Map
- Hadoop的学习前奏(二)——Hadoop集群的配置
- Ruby实例方法和类方法的简写
- layui怎样将响应数据展示在页面_layui怎么对弹出层显示数据
- 【深度学习理论】一文搞透pytorch中的tensor、autograd、反向传播和计算图
- 技术项目 - MySQL多从系统的主库选择
- html5用户注册页面代码,HTML5注册页面示例代码_html5教程技巧
- 安丘妇幼保健院智能照明监控系统的设计与应用-安科瑞耿敏花
- select2 使用详解
- 应用统计学与计算机论文,浅谈统计学在生活中的应用
- java excel 导入试题
- python项目实战:天眼查询你所需的公司信息
- Git分支图解理解其概念HEAD,git branch name,git checkout name,git log --oneline --decorate
- 中年危机也许只是个幻觉
- windows11应用商店错误:0x800704cf
- 全键盘 linux 手机,当年青葱的岁月:10佳全键盘智能手机盘点
- 米思齐Mixly图形化编程---遥控灯
热门文章
- Sketch for mac(矢量绘图UI设计)
- 工业计算机刷游戏,我的世界电脑版工业2教程 带你深入了解游戏
- 部署城市级室外无线局域网的成功战略
- 国内外几大浏览器性能比较
- 数据中心现场施工管理难点案例分析
- 滑雪游戏中,有俩种障碍物,合并障碍物的作用是什么
- 10月31日到12月04日学习总结
- python淘宝秒杀_Python 实现淘宝秒杀的示例代码
- 机械专业应具备什么计算机能力
- 中兴交换机stp mstp 配置实例 原理