`
iaiai
  • 浏览: 2204939 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

[转]将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;
        }
 
    }
分享到:
评论

相关推荐

    spydroid-ipcamera这个项目能够将Android设备变成一个漂亮的网络摄像机.rar

    "Spydroid-IPCamera"项目正是这样一个创新性的尝试,它能够将普通的Android设备转变为功能强大的网络摄像机,使得监控、远程视频传输等应用变得更加便捷和实用。下面我们将深入探讨该项目的核心技术和应用场景。 一...

    spydroid-ipcamera-master.zip

    本文将深入探讨一个名为"spydroid-ipcamera-master"的开源项目,该项目专注于H264 RTP流媒体的开发,对于Android平台的流媒体应用开发者来说,这是一个极具价值的资源。 首先,让我们理解项目的名称"spydroid-...

    spydroid-ipcamera-master

    "spydroid-ipcamera-master"是一个针对Android平台的开源项目,它的核心功能是将Android智能手机转变为一个网络摄像机(IPC,Internet Protocol Camera),允许用户通过电脑或其他设备实时监控手机摄像头的画面。...

    spydroid-ipcamera最新版源码

    `spydroid-ipcamera`的核心功能是将Android设备转化为网络摄像头,允许用户通过网络实时传输视频流。这个项目的源码不仅展示了如何利用Android的多媒体框架捕获和处理视频流,还特别强调了对H264硬件编码的支持。H...

    spydroid-ipcamera-master.zip_Spydroid_ipcamera_java vlc_spydro

    spydroid-ipcamera是一个开源的andoird源码,运行在android手机上,可将手机的摄像头当做ipc camera,电脑可采用vlc实时监控手机的摄像头。

    spydroid-ipcamera 8.0

    8.0版本的发布,旨在解决从Google获取源码时可能遇到的不便,提供了一个更加便捷的下载途径。 1.2 功能特性:此应用的核心功能包括实时视频流传输、照片拍摄、录制视频、多设备连接等。这些功能的实现,离不开...

    spydroid-ipcamera 实现Android视频实时上传到服务器,服务器可以实时浏览

    vlc_2.2.4.0.exe是服务器的执行程序,安装时需要选择允许浏览器插件的选项,默认的就可以。spydroid-ipcamera是开源的项目,导入工程可以直接使用,运行后进入setting页面,需要勾选http port和Rtsp port二个选项。

    spydroid-ipCamera-ICamera AS导入不报错版本能运行版本

    解决AndroidStudio导入报错的各种问题,spydroid-ipCamera-ICamera,官方的 代码下载下来后,导入进AS IDE各种报错,弄了半天,各种库版本,不兼容问题。于是乎,自己新建了一个类似项目改版了代码,不会导入报错了。...

    spydroid实时视频监控(实测可用)

    spydroid-ipcamera这个项目能够将Android设备变成一个漂亮的网络摄像机 ip camera。Spydroid是一个很小的app,能够将手机的摄像头和麦克风streams至你的浏览器或VLC。它是市场上最强大的工具,一种方法用来从智能...

    Android应用源码之ipcamera-for- 手机变成IP Camera.zip

    本篇将深入探讨一款名为"ipcamera-for-"的Android应用源码,该应用能够将手机转变为一个网络摄像头,即IP Camera。通过学习此源码,开发者可以了解Android多媒体处理、网络通信以及设备硬件接口调用等关键技术。 一...

    spydroid-ipcamera

    Spydroid 是一个小应用程序。 将手机的摄像头和麦克风流式传输到浏览器或 VLC! 这是一个有趣的恶作剧应用程序:您可以远程触发手机上的有趣声音或切换其闪光灯。 开发人员,首先,了解如何在 Spydroid 中实现...

    Quantum6-Android-IPCamera-ONVIF-main.zip

    首先,我们来看标题中的"Quantum6-Android-IPCamera-ONVIF-main.zip",这是一个包含JAVA版Android IP Camera ONVIF实现的压缩包。这个项目的核心目标是在Android设备上构建一个能够与ONVIF兼容的IP Camera客户端,...

    网络摄像机中文说明书-iPcamera网络视频服务器网络.docx

    - 当网络摄像机的IP地址可能会发生变化(如ADSL用户),需要使用DDNS服务(如3322.org提供的免费服务)来绑定一个固定的域名,确保无论IP如何变化,都可以通过同一域名访问到摄像机。 - 需要有电子邮件地址来接收...

    spydroid最新版8.0.2

    在Eclipse中,开发者需要先创建一个新的Android项目,然后将下载的"spydroid-ipcamera"文件夹导入到项目中,作为项目的源代码库。接着,配置项目依赖,包括Android SDK版本、库引用等,确保所有必要的组件都能正常...

    安卓开发-ipcamera-for-android 手机变成IP Camera.zip

    这个项目标题揭示了我们正在探讨的主题,即如何将Android手机转变为一个IP摄像头。在IT领域,IP摄像头(网络摄像头)是一种可以通过网络进行视频传输的设备。在这个特定的安卓开发项目中,开发者将创建一个应用程序...

    ipcamera-for-android

    "ipcamera-for-android"正是这样一个应用,它让我们的Android设备摇身一变,成为一台可远程访问的网络摄像头。 首先,我们来理解一下IP Camera的基本概念。IP Camera是一种通过网络传输视频信号的摄像头,它不再...

    安卓Android源码——ipcamera-for-android 手机变成IP Camera.zip

    "安卓Android源码——ipcamera-for-android 手机变成IP Camera" 这个标题揭示了我们正在探讨一个特殊的Android项目,它的主要功能是将Android智能手机转化为网络摄像头,即IP Camera。IP Camera是指能够通过网络进行...

Global site tag (gtag.js) - Google Analytics