Libstreaming是一个开源的流媒体框架,它可以让手机变成一台流媒体服务器,直接在PC端查看手机摄像头的实时画面。值得一提的是它的作者也是spydroid的作者。按照作者的说法,spydroid是利用该库完成流媒体传输的,但据笔者的分析观察,此说法并不十分确切。Libstreaming是spydroid的抽象与升华,RTSP服务器的实现方式也有很大的不同。
巧妇难为无米之炊,我们先把Libstreaming的源代码下载下来。地址:https://github.com/fyhertz/libstreaming 下载完毕后导入eclipse,并新建工程引用该库。这里要颇为注意,新建的工程必须和Libstreaming在同一个盘符下,否则可能出现引用失败的问题。
接下来看看官方文档中给出的创建RTSP服务器的步骤:
<service android:name="net.majorkernelpanic.streaming.rtsp.RtspServer"/>
把RtspServer这个服务在androidManifest文件中进行注册。在libstreaming库中,rtsp服务器是作为service组建实现的,这与spydroid的实现方式完全不一样。
Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putString(RtspServer.KEY_PORT, String.valueOf(1234));
editor.commit();
The port is indeed stored as a String in the preferences, there is a good reason to that. The EditTextPreference object saves its input as a String and cannot easily (one would need to override it) be configured to store it as an Integer.
可以改变rtsp服务器的端口,当然,这是非必需的。默认端口是8086。若想改变端口,必须通过sharedPreference完成。先获取一个指向本activity的sharedPreference的editor对象,再将指定的端口号put进去。至于为什么用String类型而不是用整形存储端口号,主要是考虑到EditTextPreference对象的保存类型是string。
3、Configure its behavior with the SessionBuilder:
SessionBuilder.getInstance()
.setSurfaceHolder(mSurfaceView.getHolder())
.setContext(getApplicationContext())
.setAudioEncoder(SessionBuilder.AUDIO_AAC)
.setVideoEncoder(SessionBuilder.VIDEO_H264);
5、Start and stop the server like this:
// Starts the RTSP server
context.startService(new Intent(this,RtspServer.class));
// Stops the RTSP server
context.stopService(new Intent(this,RtspServer.class));
完整的示例:
1、布局文件——activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <SurfaceView android:id="@+id/surface" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
package com.dyc.spydroidrtspserver; import net.majorkernelpanic.streaming.SessionBuilder; import net.majorkernelpanic.streaming.rtsp.RtspServer; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.preference.PreferenceManager; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences.Editor; import android.view.Menu; import android.view.SurfaceView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { SurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//加载布局 surfaceView=(SurfaceView)findViewById(R.id.surface); Editor editor=PreferenceManager.getDefaultSharedPreferences(this).edit();//获取sharedPreference的editor对象 editor.putString(RtspServer.KEY_PORT, "1234");//将新的端口号put进去 editor.commit();//提交更改 SessionBuilder.getInstance() .setAudioEncoder(SessionBuilder.AUDIO_AMRNB) .setVideoEncoder(SessionBuilder.VIDEO_H264). setContext(getApplicationContext()). setSurfaceHolder(surfaceView.getHolder());//配置sessionBuilder对象 this.startService(new Intent(this, RtspServer.class));//启动服务 displayIpAddress();//显示地址 } private void displayIpAddress() { WifiManager wifiManager=(WifiManager)getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo=wifiManager.getConnectionInfo(); int address=wifiInfo.getIpAddress();//获取IP地址,注意获取的结果是整数 Toast.makeText(this, "rtsp://"+intToIp(address)+":1234", Toast.LENGTH_LONG).show();//用toast打印地址 } private String intToIp(int i) {//整形转IP return (i & 0xFF)+ "." + ((i >> 8 ) & 0xFF)+ "." + ((i >> 16 ) & 0xFF) +"."+((i >> 24 ) & 0xFF ); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.dyc.spydroidrtspserver" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.dyc.spydroidrtspserver.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="net.majorkernelpanic.streaming.rtsp.RtspServer" /> </application> </manifest>