[转]将Android变成一个网络摄像机:spydroid-ipcamera;能实时传输,几乎没有延迟...
spydroid-ipcamera这个项目能够将Android设备变成一个漂亮的网络摄像机 ip camera。Spydroid是一个很小的app,能够将手机的摄像头和麦克风streams至你的浏览器或VLC。它是市场上最强大的工具,一种方法用来从智能手机传输音频/视频到您的电脑。H.264支持分辨率高达1080p和在手机上运行ICS或JB就能够支持AAC格式。
需要注意的是,此解决方案仅限于局域网,要想在公网环境下实现视频监控,则需要STUN协议的支持。
源码片段
public class SpydroidActivity extends FragmentActivity {
static final public String TAG = "SpydroidActivity";
public final int HANDSET = 0x01; public final int TABLET = 0x02;
// We assume that the device is a phone public int device = HANDSET;
private ViewPager mViewPager; private PowerManager.WakeLock mWakeLock; private SectionsPagerAdapter mAdapter; private SurfaceView mSurfaceView; private SpydroidApplication mApplication; private CustomHttpServer mHttpServer; private RtspServer mRtspServer;
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
mApplication = (SpydroidApplication) getApplication();
setContentView(R.layout.spydroid);
if (findViewById(R.id.handset_pager) != null) {
// Handset detected ! mAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); mViewPager = (ViewPager) findViewById(R.id.handset_pager); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mSurfaceView = (SurfaceView)findViewById(R.id.handset_camera_view); SessionBuilder.getInstance().setSurfaceView(mSurfaceView); SessionBuilder.getInstance().setPreviewOrientation(90);
} else {
// Tablet detected ! device = TABLET; mAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); mViewPager = (ViewPager) findViewById(R.id.tablet_pager); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); SessionBuilder.getInstance().setPreviewOrientation(0);
}
mViewPager.setAdapter(mAdapter);
// Remove the ads if this is the donate version of the app. if (mApplication.DONATE_VERSION) { ((LinearLayout)findViewById(R.id.adcontainer)).removeAllViews(); }
// Prevents the phone from going to sleep mode PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "net.majorkernelpanic.spydroid.wakelock");
// Starts the service of the HTTP server this.startService(new Intent(this,CustomHttpServer.class));
// Starts the service of the RTSP server this.startService(new Intent(this,CustomRtspServer.class));
}
public void onStart() { super.onStart();
// Lock screen mWakeLock.acquire();
// Did the user disabled the notification ? if (mApplication.notificationEnabled) { Intent notificationIntent = new Intent(this, SpydroidActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this); Notification notification = builder.setContentIntent(pendingIntent) .setWhen(System.currentTimeMillis()) .setTicker(getText(R.string.notification_title)) .setSmallIcon(R.drawable.icon) .setContentTitle(getText(R.string.notification_title)) .setContentText(getText(R.string.notification_content)).build(); notification.flags |= Notification.FLAG_ONGOING_EVENT; ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(0,notification); } else { removeNotification(); }
bindService(new Intent(this,CustomHttpServer.class), mHttpServiceConnection, Context.BIND_AUTO_CREATE); bindService(new Intent(this,CustomRtspServer.class), mRtspServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override public void onStop() { super.onStop(); // A WakeLock should only be released when isHeld() is true ! if (mWakeLock.isHeld()) mWakeLock.release(); if (mHttpServer != null) mHttpServer.removeCallbackListener(mHttpCallbackListener); unbindService(mHttpServiceConnection); if (mRtspServer != null) mRtspServer.removeCallbackListener(mRtspCallbackListener); unbindService(mRtspServiceConnection); }
@Override public void onResume() { super.onResume(); mApplication.applicationForeground = true; }
@Override public void onPause() { super.onPause(); mApplication.applicationForeground = false; }
@Override public void onDestroy() { Log.d(TAG,"SpydroidActivity destroyed"); super.onDestroy(); }
@Override public void onBackPressed() { Intent setIntent = new Intent(Intent.ACTION_MAIN); setIntent.addCategory(Intent.CATEGORY_HOME); setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(setIntent); }
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); MenuItemCompat.setShowAsAction(menu.findItem(R.id.quit), 1); MenuItemCompat.setShowAsAction(menu.findItem(R.id.options), 1); return true; }
@Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent;
switch (item.getItemId()) { case R.id.options: // Starts QualityListActivity where user can change the streaming quality intent = new Intent(this.getBaseContext(),OptionsActivity.class); startActivityForResult(intent, 0); return true; case R.id.quit: quitSpydroid(); return true; default: return super.onOptionsItemSelected(item); } }
private void quitSpydroid() { // Removes notification if (mApplication.notificationEnabled) removeNotification(); // Kills HTTP server this.stopService(new Intent(this,CustomHttpServer.class)); // Kills RTSP server this.stopService(new Intent(this,CustomRtspServer.class)); // Returns to home menu finish(); }
private ServiceConnection mRtspServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) { mRtspServer = (CustomRtspServer) ((RtspServer.LocalBinder)service).getService(); mRtspServer.addCallbackListener(mRtspCallbackListener); mRtspServer.start(); }
@Override public void onServiceDisconnected(ComponentName name) {}
};
private RtspServer.CallbackListener mRtspCallbackListener = new RtspServer.CallbackListener() {
@Override public void onError(RtspServer server, Exception e, int error) { // We alert the user that the port is already used by another app. if (error == RtspServer.ERROR_BIND_FAILED) { new AlertDialog.Builder(SpydroidActivity.this) .setTitle(R.string.port_used) .setMessage(getString(R.string.bind_failed, "RTSP")) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { startActivityForResult(new Intent(SpydroidActivity.this, OptionsActivity.class),0); } }) .show(); } }
@Override public void onMessage(RtspServer server, int message) { if (message==RtspServer.MESSAGE_STREAMING_STARTED) { if (mAdapter != null && mAdapter.getHandsetFragment() != null) mAdapter.getHandsetFragment().update(); } else if (message==RtspServer.MESSAGE_STREAMING_STOPPED) { if (mAdapter != null && mAdapter.getHandsetFragment() != null) mAdapter.getHandsetFragment().update(); } }
};
private ServiceConnection mHttpServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) { mHttpServer = (CustomHttpServer) ((TinyHttpServer.LocalBinder)service).getService(); mHttpServer.addCallbackListener(mHttpCallbackListener); mHttpServer.start(); }
@Override public void onServiceDisconnected(ComponentName name) {}
};
private TinyHttpServer.CallbackListener mHttpCallbackListener = new TinyHttpServer.CallbackListener() {
@Override public void onError(TinyHttpServer server, Exception e, int error) { // We alert the user that the port is already used by another app. if (error == TinyHttpServer.ERROR_HTTP_BIND_FAILED || error == TinyHttpServer.ERROR_HTTPS_BIND_FAILED) { String str = error==TinyHttpServer.ERROR_HTTP_BIND_FAILED?"HTTP":"HTTPS"; new AlertDialog.Builder(SpydroidActivity.this) .setTitle(R.string.port_used) .setMessage(getString(R.string.bind_failed, str)) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { startActivityForResult(new Intent(SpydroidActivity.this, OptionsActivity.class),0); } }) .show(); } }
@Override public void onMessage(TinyHttpServer server, int message) { if (message==CustomHttpServer.MESSAGE_STREAMING_STARTED) { if (mAdapter != null && mAdapter.getHandsetFragment() != null) mAdapter.getHandsetFragment().update(); if (mAdapter != null && mAdapter.getPreviewFragment() != null) mAdapter.getPreviewFragment().update(); } else if (message==CustomHttpServer.MESSAGE_STREAMING_STOPPED) { if (mAdapter != null && mAdapter.getHandsetFragment() != null) mAdapter.getHandsetFragment().update(); if (mAdapter != null && mAdapter.getPreviewFragment() != null) mAdapter.getPreviewFragment().update(); } }
};
private void removeNotification() { ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).cancel(0); }
public void log(String s) { Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); }
class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) { super(fm); }
@Override public Fragment getItem(int i) { if (device == HANDSET) { switch (i) { case 0: return new HandsetFragment(); case 1: return new PreviewFragment(); case 2: return new AboutFragment(); } } else { switch (i) { case 0: return new TabletFragment(); case 1: return new AboutFragment(); } } return null; }
@Override public int getCount() { return device==HANDSET ? 3 : 2; }
public HandsetFragment getHandsetFragment() { if (device == HANDSET) { return (HandsetFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:"+R.id.handset_pager+":0"); } else { return (HandsetFragment) getSupportFragmentManager().findFragmentById(R.id.handset); } }
public PreviewFragment getPreviewFragment() { if (device == HANDSET) { return (PreviewFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:"+R.id.handset_pager+":1"); } else { return (PreviewFragment) getSupportFragmentManager().findFragmentById(R.id.preview); } }
@Override public CharSequence getPageTitle(int position) { if (device == HANDSET) { switch (position) { case 0: return getString(R.string.page0); case 1: return getString(R.string.page1); case 2: return getString(R.string.page2); } } else { switch (position) { case 0: return getString(R.string.page0); case 1: return getString(R.string.page2); } } return null; }
}
[转]将Android变成一个网络摄像机:spydroid-ipcamera;能实时传输,几乎没有延迟...相关推荐
- 基于Android的MJPEG网络摄像机设计
1 系统硬件组成与网络架构 摄像机硬件核心采用三星公司推出的基于ARM9架构的S3C2440A芯片,该处理器主频达到400 MHz可以满足实时压缩,MJPEG视频流可以达到320×240分辨率25 f ...
- android通过数组,流播放声音的方法,音频实时传输
AudioRecord和AudioTrack类是Android获取和播放音频流的重要类,放置在android.media包中.与该包中 的MediaRecorder和MediaPlayer类不同,Au ...
- 通识1——网络摄像机简介
以下内容源于网络资源的学习与整理,如有侵权请告知删除. 一.网络摄像机定义 (1)网络摄像机,也叫IP摄像机,即IPCamera,简称IPC,近几年得益于网络带宽,芯片技术,算法技术,存储技术的进不而 ...
- 网络摄像机产品介绍以及学习
网络摄像机定义 网络摄像机,也叫IP摄像机,即IPCamera,简称IPC,近几年得益于网络带宽,芯片技术,算法技术,存储技术的进不而得到大力发展.IPC的特点主要体现在"IP"上 ...
- 凯聪网络摄像机SIP1201系列使用说明 说明书 设置教程
本说明包含产品所有设置功能: 为了更方便查找:请使用 ctrl+f 搜索 查找答案. 苹果系统 请使用 command+f 1201网络摄像机软件下载: 电脑/PC搜索软件(windows):http ...
- 网络摄像机编码标准及传输协议简析
视频监控系统从第一代模拟系统(VCR)到第二代部分数字化系统(DVR/NVR),再到第三代完全数字化系统(网络摄像机,网络视频服务器),三个阶段的发展演变预示着全数字化视频监控系统不久将成为安防市场的 ...
- 网络摄像机与传统模拟摄像机的差别
监控摄像机是用在安防方面的准摄像机,它的像素和分辨率比电脑的视频头要高,比专业的数码相机或dv低.监控摄像机大多只是单一的视频捕捉设备,很少具备数据保存功能. 监控摄像机从外型上主要区分为枪式.半球. ...
- 基于Android的3G手机网络摄像机客户端软件设计
深入研究了MJPEG视频压缩算法,阐述了算法实现过程,并设计出基于Android操作系统的3G手机网络摄像机客户端软件.本系统通过实地安装与测试达到了预期效果,突破了传统网络摄像机客户端固定地域的限制 ...
- Android:面试官死亡问答,如何优化一个网络请求?大牛多个网络优化方案帮你解决!
面试官:小萧啊,我好想你啊,你都好久没来找我面试了呀. 小萧:emmmmmmm,这不是怕被你打击吗. 面试官:ok,看来是有备而来,那么我们今天聊聊网络优化咋做吧. 小萧:我大意了,没有闪.老头子,你 ...
最新文章
- push_heap算法 (即满足max-heap条件,最大值在根节点)
- python sklearn 归一化_第3章 Sklearn概述
- Android AIDL使用介绍(2)自定义数据类型的传递
- 2019年嵌入式开发系统详细分析告诉你是否还值得去学习
- 当飞猪遇上 Serverless | 云原生 Talk
- jQuery 实现菜单
- 四川的软考成绩终于出来了
- linux下MySQL安装及设置
- Unity3D物理渲染算法研究【PBR】
- ECTOUCH广告图片轮播间隔调整 ECTOUCH教程
- codeforces1359E Modular Stability
- 《触动人心设计优秀iphone应用》读后感
- excel表格公式出现#REF是什么意思
- lemonldap java_Java LDAP操作
- 深度学习图像算法在内容安全领域的应用
- Extjs中利用combobox实现全国省市级联
- 命名实体识别的一点经验
- 论文阅读:In the Eye of the Beholder: A Survey of Models for Eyes and Gaze
- NEIL: Extracting Visual Knowledge from Web Data 论文笔记
- 学习HCIA第八天 VLAN原理和配置
热门文章
- Lycn 2013 with SQL AlwaysOn 「二」偷梁换柱装Lync
- 带通滤波器中心频率计算公式中R是哪个值_三个零件组成矿石收音机,LC电路谐振频率换算及零件选购是关键...
- fullCalendar改造计划之带农历节气节假日的万年历
- 质量管理、质量保证、质量控制的区别
- “最牛愤青教授”郑强叫板当代教育
- Redis 知识收集
- 致所有初学者--助力所有ERP初学者!!!
- 用史上最牛学习法自学编程,不香吗?
- 2021年平均工资出炉,IT行业不出所料
- Supermap iDesktop处理导入CAD文件存在线型风格显示缺失问题