spydroid源碼閱讀筆記

本文主要記錄對spydroid源碼的閱讀筆記

源代碼:https://github.com/fyhertz/spydroid-ipcamera

使用步驟 局域網用手機實現視頻監控

1.下載運行測試 apk :https://fir.im/qnhb
2.設置裏把 HTTP server 和 RTSP server 都打開


3.下載vlc (播放rtsp流) ,填入地址,地址爲手機首頁顯示的局域網地址



4.右擊 播放 就可以啦

一個問題:由於手機攝像投角度的問題,VLC 直接播放的是沒有旋轉處理的畫面,即攝像頭原始數據
notes:

1.廣告(增加收入?) :https://www.google.com/admob/
2.sdk 23以上不再支持org.apache.http,非要用高版本sdk,則 spydroid/build.gradle 添加
     android {
         useLibrary 'org.apache.http.legacy'
     }
3.電池狀態監聽  net.majorkernelpanic.spydroid.SpydroidApplication.mBatteryInfoReceiver
registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
4.指定跳到系統桌面
    Intent setIntent = new Intent(Intent.ACTION_MAIN);//指定跳到系統桌面
    setIntent.addCategory(Intent.CATEGORY_HOME);
    setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    //setIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //清除上一步緩存
    startActivity(setIntent);
5.保持屏幕常亮 新姿勢
    需要電源管理的權限 <uses-permission android:name="android.permission.WAKE_LOCK"/>
    PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
            | PowerManager.ON_AFTER_RELEASE, "WAKE_LOCK");
    wakeLock.acquire();
    // onStop()
    // A WakeLock should only be released when isHeld() is true !
    if (mWakeLock.isHeld()) mWakeLock.release();
    附:關於int flags 各種鎖的類型對CPU 、屏幕、鍵盤的影響:
      PARTIAL_WAKE_LOCK:        保持CPU 運轉,屏幕和鍵盤燈有可能是關閉的。
      SCREEN_DIM_WAKE_LOCK:   保持CPU 運轉,允許保持屏幕顯示但有可能是灰的,允許關閉鍵盤燈
      SCREEN_BRIGHT_WAKE_LOCK:保持CPU 運轉,允許保持屏幕高亮顯示,允許關閉鍵盤燈
      FULL_WAKE_LOCK:          保持CPU 運轉,保持屏幕高亮顯示,鍵盤燈也保持亮度
      ACQUIRE_CAUSES_WAKEUP:  正常喚醒鎖實際上並不打開照明。相反,一旦打開他們會一直仍然保持(例如來世user的activity)。
      當獲得wakelock,這個標誌會使屏幕或/和鍵盤立即打開。一個典型的使用就是可以立即看到那些對用戶重要的通知。
      ON_AFTER_RELEASE:        設置了這個標誌,當wakelock釋放時用戶activity計時器會被重置,
      導致照明持續一段時間。如果你在wacklock條件中循環,這個可以用來減少閃爍
6. Notification & PendingIntent
    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);
7. PreferenceActivity 設置
    以 Notification 的打開關閉爲例:
    佈局 : xml/preferences.xml:91  android:key="notification_enabled"
    改變的監聽 :net/majorkernelpanic/spydroid/SpydroidApplication.java:150   if (key.equals("notification_enabled"))
8.ViewPager 的 title  android.support.v4.view.PagerTitleStrip
    layout use in layout/spydroid.xml:27
    FragmentPagerAdapter only needs @Override  public CharSequence getPageTitle(int position)
9.bindService()  切記 需要 unbindService(conn);
    bindService(new Intent(xxx.this,Service.class),conn,flag)-->Service:onCreate()-->Service:onBind()-->conn:onServiceConnected()
    如果多次調用 bindService ,onBind()方法只會執行一次
    Google API:https://developer.android.com/guide/components/bound-services.html
10.Intent.FLAG_ACTIVITY_NO_HISTORY   net/majorkernelpanic/spydroid/ui/AboutFragment.java:62
    用這個FLAG啓動的Activity,一旦退出,它不會存在於棧中,比方說!原來是A,B,C這個時候再C中以這個FLAG啓動D的,D再啓動E,這個時候棧中情況爲A,B,C,E。
    以web 打開網頁或者應用商店
    Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("https://code.google.com/p/spydroid-ipcamera/"));
    // Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id="+appPackageName));
    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    startActivity(intent);
11.程序運行時,進入net.majorkernelpanic.spydroid.ui.SpydroidActivity,該activity 運行時候,開啓http server ,rtsp server
12.rtsp server: net.majorkernelpanic.streaming.rtsp.RtspServer.start
      start 裏 開啓一個線程負責監聽客戶端的請求(VLC) mListenerThread = new RequestListener();
      當有客戶端請求時,開啓一個WorkerThread 線程 new WorkerThread(mServer.accept()).start();一個線程session代表一個請求
      其實就是服務器的主線程負責接收客戶的連接, 每次接收到一個客戶連接, 就會創建一個工作線程, 由它負責與客戶的通信.
13.http server:net.majorkernelpanic.http.TinyHttpServer.start
    開啓一個線程負責監聽 mHttpRequestListener = new HttpRequestListener(mHttpPort);
14. 12 和 13 裏面都使用的通信方式 : ServerSocket
    這兩部分的代碼邏輯類似,只是使用的協議不同,都是充當服務器使用
    在客戶/服務器通信模式中, 服務器端需要創建監聽端口的 ServerSocket, ServerSocket 負責接收客戶連接請求
    Socket socket = serverSocket.accept();//從連接隊列中取出一個連接,如果沒有則等待
15. 目前只測試了rtsp協議是OK的,所以先重點分享 rtsp
    目前爲止已經大概搞清楚了數據傳輸方式,使用ServerSocket,接下來看看如何把數據傳輸出去
    net.majorkernelpanic.streaming.rtsp.RtspServer.Response 這個是作爲結果返回回去的,有個很重要的處理接收的方法
    net.majorkernelpanic.streaming.rtsp.RtspServer.WorkerThread.processRequest,裏面使用了Session類
    net.majorkernelpanic.streaming.Session 這個類用來包裝音頻或者視頻,
    然後可以找到 H264Stream extends VideoStream ,AACStream extends AudioStream
    在 net.majorkernelpanic.streaming.rtsp.RtspServer.WorkerThread.processRequest #428
    裏調用了handleRequest #437 調用net.majorkernelpanic.streaming.rtsp.UriParser.parse 配置session,
    Session 中含有 AudioStream VideoStream  ,在方法 net.majorkernelpanic.streaming.Session.getSessionDescription
    中獲取 描述信息,而後被賦值給 response.content;
    感覺獲取到的音頻或者視頻幀數據就在 getSessionDescription()裏被處理的
16. audio : AACStream --> AACStream.encodeWithMediaCodec --> 開啓一個線程AudioRecord獲取音頻數據送個MediaCodec編碼
           解碼過程和解碼數據封裝爲 MediaCodecInputStream ,處理數據的過程封裝爲 AbstractPacketizer 這樣一個抽象類
           這個類裏包含了一個 net.majorkernelpanic.streaming.rtp.RtpSocket 這樣一個維護 一個先進先出的隊列的一個線程,
           這個RtpSocket 負責將數據處理爲 rtsp 數據,SenderReport 負責處理待發送的數據 SenderReport類包含着處理好的待發送出去的數據
           等待着serverSocket發送數據
           看來傳播數據的部分在這裏 request.method.equalsIgnoreCase("SETUP")
17. video :H264Stream --> VideoStream.encodeWithMediaCodec --> VideoStream.encodeWithMediaCodecMethod1 與
    音頻的處理類似,也是封裝爲 MediaCodecInputStream ,只是 AbstractPacketizer的實現類變爲 H264Packetizer
    大致的過程就是這個樣子,MediaCodec處理攝像頭獲取的數據,編碼後的output數據經 MediaCodecInputStream 處理後包裝成 H264Packetizer
    進一步包裝爲 Session ,然後就可以作爲 response 數據響應客戶端的請求




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章