直播【95秀】JNI 基本实现 简洁
基本架构
1、使用SurfaceView在UI层面展示视频2、通过JNI调用C代码控制视频的播放、停止![]()
基本功能
1、从服务器获取正在直播的主播的列表信息2、进入直播界面3、可获取的主播信息
Activity_主列表界面
public class MainActivity extends Activity {public static final String SERVER_URL = "api.95xiu.com";//"tapi.95xiu.com"public static final String RQ_LIVE = "/show/anchor_list_v3.php";private List<LiveBean> mList;private GridView gridView;private MyBaseAdapter adapter;private DisplayImageOptions options;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);//取消标题栏ImageLoader.getInstance().init(new ImageLoaderConfiguration.Builder(this).build());options = new DisplayImageOptions.Builder().cacheInMemory(true).cacheOnDisk(true)//将图片缓存到内存和硬盘中.showImageOnLoading(R.drawable.live_icon_default).showImageOnFail(R.drawable.live_icon_default)//加载中、加载错误时显示的图片.bitmapConfig(Bitmap.Config.RGB_565).build();setContentView(R.layout.layout_main);mList = new ArrayList<LiveBean>();loadingData();gridView = (GridView) findViewById(R.id.gv);adapter = new MyBaseAdapter();gridView.setAdapter(adapter);}private void loadingData() {RequestParams requestParams = new RequestParams();requestParams.put("page_index", "0");//非必须requestParams.put("version", "1");//非必须AsyncHttpHelper.get(SERVER_URL,RQ_LIVE, requestParams, new OnHttpListener<JSONObject>() {//http://api.95xiu.com/show/anchor_list_v3.php@Overridepublic void onHttpListener(boolean httpSuccessed, JSONObject obj) {if (httpSuccessed) {Log.i("bqt", obj.toString());if (obj.optInt("result") == 1) {JSONArray arr = obj.optJSONArray("user_info");if (arr != null && arr.length() > 0) {for (int i = 0; i < arr.length(); i++) {JSONObject jObject = arr.optJSONObject(i);mList.add(new LiveBean(jObject.optString("anchor_image"), jObject.optString("nickname"), jObject.optString("live_num")//, jObject.optString("uid")));}Log.i("bqt", "数据个数:" + mList.size());}adapter.notifyDataSetChanged();}}}});}public class MyBaseAdapter extends BaseAdapter {private ViewHolder mViewHolder;@Overridepublic int getCount() {return mList == null ? 0 : mList.size();}@Overridepublic Object getItem(int position) {return mList == null ? null : mList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {if (convertView != null) mViewHolder = (ViewHolder) convertView.getTag();else {convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);mViewHolder = new ViewHolder();mViewHolder.iv_head = (ImageView) convertView.findViewById(R.id.iv_anchor_img);mViewHolder.tv_name = (TextView) convertView.findViewById(R.id.tv_anchor_name);mViewHolder.tv_audience_num = (TextView) convertView.findViewById(R.id.tv_audience_num);mViewHolder.iv_rankingLev = (ImageView) convertView.findViewById(R.id.iv_rankingLev);mViewHolder.iv_moods = (ImageView) convertView.findViewById(R.id.iv_moods);mViewHolder.iv_coverage = (ImageView) convertView.findViewById(R.id.iv_coverage);convertView.setTag(mViewHolder);}if (mList != null) {ImageLoader.getInstance().displayImage(mList.get(position).anchor_image, mViewHolder.iv_head, options);mViewHolder.tv_name.setText(mList.get(position).nickname);mViewHolder.tv_audience_num.setText(mList.get(position).live_num);if (position == 0) mViewHolder.iv_rankingLev.setVisibility(View.VISIBLE);else mViewHolder.iv_rankingLev.setVisibility(View.INVISIBLE);if (position == 0 || position == 1 || position == 3 || position == 6) mViewHolder.iv_moods.setVisibility(View.VISIBLE);else mViewHolder.iv_moods.setVisibility(View.INVISIBLE);mViewHolder.iv_coverage.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, LiveActivity.class);intent.putExtra("anchorId", mList.get(position).anchorId);Log.i("bqt", "主播ID:" + mList.get(position).anchorId);startActivity(intent);}});}return convertView;}}public static class ViewHolder {public ImageView iv_head;//主播头像public TextView tv_name;//主播名字public TextView tv_audience_num;//直播间人数public ImageView iv_rankingLev;//排名public ImageView iv_moods;//人气等标签public ImageView iv_coverage;//背景框}}class LiveBean {public String anchor_image;public String nickname;public String live_num;public String anchorId;public LiveBean(String anchor_image, String nickname, String live_num, String anchorId) {super();this.anchor_image = anchor_image;this.nickname = nickname;this.live_num = live_num;this.anchorId = anchorId;}}
两个布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:baselineAligned="false"android:background="#fff"android:orientation="horizontal" ><GridViewandroid:id="@+id/gv"android:layout_width="match_parent"android:layout_height="wrap_content"android:cacheColorHint="#00000000"android:listSelector="#00000000"android:verticalSpacing="5dp"android:horizontalSpacing="5dp"android:descendantFocusability ="beforeDescendants"android:numColumns="2" /></LinearLayout><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rl_item"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#fbf7ed" ><ImageViewandroid:id="@+id/iv_anchor_img"android:layout_width="match_parent"android:layout_height="130dp"android:layout_alignParentTop="true"android:scaleType="fitXY"android:src="@drawable/live_icon_default" /><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignBottom="@id/iv_anchor_img"android:background="@drawable/main_live_head_bg" /><TextViewandroid:id="@+id/tv_audience_num"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@id/iv_anchor_img"android:layout_alignParentLeft="true"android:layout_marginBottom="4dp"android:drawableLeft="@drawable/living_true"android:drawablePadding="4dp"android:ellipsize="end"android:gravity="center"android:paddingLeft="8dp"android:singleLine="true"android:text="111"android:textColor="#00f"android:textSize="12sp" /><TextViewandroid:id="@+id/tv_anchor_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignBottom="@id/tv_audience_num"android:layout_alignParentRight="true"android:layout_marginLeft="5dp"android:layout_toRightOf="@id/tv_audience_num"android:ellipsize="end"android:gravity="right"android:paddingRight="8dp"android:singleLine="true"android:text="这是主播主播主播"android:textColor="#fff"android:textSize="12sp" /><ImageViewandroid:id="@+id/iv_rankingLev"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:layout_marginLeft="4dp"android:layout_marginTop="8dp"android:src="@drawable/live_ranking1" /><ImageViewandroid:id="@+id/iv_moods"android:layout_width="40dp"android:layout_height="17dp"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:layout_marginTop="8dp"android:src="@drawable/live_moods" /><ImageViewandroid:id="@+id/iv_coverage"android:layout_width="match_parent"android:layout_height="130dp"android:background="@drawable/live_main_item_bg"android:clickable="true"android:focusable="true" /></RelativeLayout>
Activity_直播界面
public class LiveActivity extends Activity {private ViEAndroidGLES20 mSurfaceView;private LinearLayout root;private String mVideoUrl;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);//取消标题栏initViews();setContentView(root);}private void initViews() {// 视频比率 4:3DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);int width = displayMetrics.widthPixels;int h = width * 3 / 4;if (h % 2 != 0) h += 1;root = new LinearLayout(this);root.setOrientation(LinearLayout.VERTICAL);mSurfaceView = ViERenderer.CreateRenderer(this, true, null);mSurfaceView.setLayoutParams(new FrameLayout.LayoutParams(width, h));//具有父控件的View设置setLayoutParams才有效!root.addView(mSurfaceView);TextView textView = new TextView(this);root.addView(textView);Intent intent = getIntent();if (intent != null && intent.getStringExtra("anchorId") != null) {mVideoUrl = String.format("app/%s?k=1092dc67c9402014144fc19181974172&t=540fb568", intent.getStringExtra("anchorId"));textView.setText("视频地址:" + mVideoUrl);//livestream.setPlayerStateHandler(mHandler);livestream.init(mVideoUrl, mSurfaceView);startVideo();}}public void startVideo() {try {Log.v("vvvv", "startPlay");livestream.setVideoPath(mVideoUrl);livestream.setSurfaceView(mSurfaceView);livestream.playVideo();} catch (Exception e) {e.printStackTrace();}}public void stopVideo(boolean isFreeHandler) {try {Log.v("vvvv", "stopPlay");livestream.stopVideo();if (isFreeHandler) {livestream.setPlayerStateHandler(null);}} catch (Exception e) {e.printStackTrace();}}public static void freeVideo() {try {livestream.setPlayerStateHandler(null);livestream.free();} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onPause() {super.onPause();}@Overridepublic void onDestroy() {super.onDestroy();if (mSurfaceView != null) mSurfaceView.onPause();stopVideo(true);}}
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.bqt.test"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="16"android:targetSdkVersion="21" /><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name" ><activity android:name=".MainActivity" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".LiveActivity" ></activity></application></manifest>
附件列表
直播【95秀】JNI 基本实现 简洁的更多相关文章
- 95秀-自定义对话框 dialog 合集
普通的确认对话框 NormalDialog.java import android.app.Dialog; import android.content.Context; import android ...
- 95秀-ViewPager 使用实例
Activity的样式 <style name="under_live_indicator" parent="android:Theme.NoTitleBa ...
- 95秀-异步http请求完整过程
最终调用时的代码 private void ansyClearApplyInfor() { RequestParams params = new RequestParams() ...
- 95秀-dialog 进度对话框 实用工具
工具Util public class DialogUtil { public static ProgressDialogView progressDialog; /** * ...
- 95秀-PullToRefreshListView 示例
正在加载.暂无数据页面 public class RefreshGuideTool { private RelativeLayout rl_loading_guide;//整个View ...
- 95秀-弹窗+listview+动画 示例
Dialog布局 dialog.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLay ...
- 做一款仿映客的直播App
投稿文章,作者:JIAAIR(GitHub) 一.直播现状简介 1.技术实现层面 技术相对都比较成熟,设备也都支持硬编码.iOS还提供现成的Video ToolBox框架,可以对摄像头和流媒体数据结构 ...
- 做一款仿映客的直播App?看我就够了
来源:JIAAIR 链接:http://www.jianshu.com/p/5b1341e97757 一.直播现状简介 1.技术实现层面: 技术相对都比较成熟,设备也都支持硬编码.IOS还提供现成 ...
- 开发一款直播APP系统软件应该有哪些功能,如何开发?
1.技术实现层面: 技术相对都比较成熟,设备也都支持硬编码.IOS还提供现成的 Video ToolBox框架,可以对摄像头和流媒体数据结构进行处理,但Video ToolBox框架只兼容8.0以上版 ...
随机推荐
- CodeForces 140C New Year Snowmen(堆)
题面 CodeForces 题解 因为要保证两两不同,所以不能单纯的开堆来维护,堆维护一个二元组,个数为第一关键字,编号为第二关键字,对于一个相同的颜色,统计一下这个颜色的个数再用堆来维护就好了. # ...
- Category 特性在 iOS 组件化中的应用与管控
背景 iOS Category功能简介 Category 是 Objective-C 2.0之后添加的语言特性. Category 就是对装饰模式的一种具体实现.它的主要作用是在不改变原有类的前提下, ...
- ubuntu16.04(64位)建立交叉编译环境,并配置编译内核
安装步骤 1.准备工具安装目录 将压缩包gcc-linaro-arm-linux-bnueabihf-4.9-2014.07_linux.tar存放在一个目录下,这个目录就是你等会解压缩的目录,以后这 ...
- 你的跑步姿势正确吗? 教你正确跑步姿势 & 常识
转载!!!!!搞IT必须运动一下 前言: 最近两年跑步的人越来越多,跑步在大部分人的观念中都是毫无技术含量,只要迈开腿就行了,其实这也是造成大多数跑步人士伤病的根源.对跑步的认知不足,跑步是一项看起来 ...
- ARM 寄存器
ARM总共有37个寄存器 ARM寄存器物理分类 通用寄存器:1:不分组寄存器(R0--R7) 2:分组寄存器(R8-R14) 3:程序计数器(R15)(注意:又名pc指针) 程序状态寄存器:1:CPS ...
- 错误:SSL peer shut down incorrectly
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 打开这个界面 ,修改一下.对照自己以前的没问题的项目.我的是3.3. 错误:Failed ...
- JavaSE基础之封装
JavaSE基础之封装 一.Java中的封装 1.字面意思: 包装: 2.专业含义: 面向对象的三大特征之一: 指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所 ...
- [BZOJ1758][WC2010]重建计划(点分治+单调队列)
点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...
- Codeforces Round #353 (Div. 2) E. Trains and Statistic dp 贪心
E. Trains and Statistic 题目连接: http://www.codeforces.com/contest/675/problem/E Description Vasya comm ...
- ZeptoLab Code Rush 2015 A. King of Thieves 暴力
A. King of Thieves Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/526/pr ...



