spydroid-ipcamera源碼分析(二):MediaStream流媒體基類分析

MediaStream類

MediaStream作為流媒體的基類,實(shí)現(xiàn)了Stream接口惫叛,封裝了對Srteam對象的基本操作亩鬼。同時(shí)它又作為一個抽象類饥脑,抽象出更為細(xì)分的操作動作讓子類進(jìn)行實(shí)現(xiàn)。

static {
        // We determine wether or not the MediaCodec API should be used
        try {
            Class.forName("android.media.MediaCodec");
            // Will be set to MODE_MEDIACODEC_API at some point...
            sSuggestedMode = MODE_MEDIACODEC_API;
            Log.i(TAG,"Phone supports the MediaCoded API");
        } catch (ClassNotFoundException e) {
            sSuggestedMode = MODE_MEDIARECORDER_API;
            Log.i(TAG,"Phone does not support the MediaCodec API");
        }
    }

MediaStream在靜態(tài)塊中確定流媒體使用的編解碼器晴圾。默認(rèn)優(yōu)先選擇MediaCodec颂砸,若不支持MediaCodec才選擇MediaRecorder。

在傳輸流媒體的過程中,為了節(jié)約帶寬和傳輸效率人乓,一般都會對流媒體數(shù)據(jù)進(jìn)行編解碼操作勤篮。在這里編解碼又分為軟編解碼和硬編解碼。

以視頻編碼舉例,軟編碼就是使用CPU進(jìn)行編碼,實(shí)現(xiàn)直接色罚、簡單碰缔,參數(shù)調(diào)整方便,但CPU負(fù)載重戳护,性能較硬編碼低金抡;硬編碼就是使用非CP(顯卡GPU、專用編解碼芯片等)進(jìn)行編碼腌且,這種方式性能更高梗肝,但不便于移植。在Android平臺上的效果切蟋,主流配置設(shè)配在使用軟編碼運(yùn)行幾分鐘后便會出現(xiàn)發(fā)燙统捶、掉幀等問題,而硬編碼出現(xiàn)上述問題的程度要輕微得多柄粹。所以在spydroid-ipcamera項(xiàng)目這種需要長時(shí)間運(yùn)行流媒體編碼的場景下喘鸟,顯然硬編碼更合適一些。

Android系統(tǒng)內(nèi)部提供了兩種視頻編碼方式:MediaCodec和MediaRecorder驻右。他們都可以對視頻進(jìn)行編碼什黑,但是唯一不同的是MediaCodec更偏向原生,而MediaRecorder偏向的上層封裝堪夭。MediaCodec類處理視頻的時(shí)候可以接觸到視頻流數(shù)據(jù)愕把,比如一些特殊需求:視頻的疊加技術(shù),添加字幕等就可以在這里處理森爽。而MediaRecorder類相對于MediaCodec簡單恨豁,且封裝得更好,直接用幾個接口就可以完成對視頻的錄入和編碼爬迟,用法簡單橘蜜,但就是不能接觸到視頻流數(shù)據(jù),處理不了原生的視頻數(shù)據(jù)付呕。

    /** Starts the stream. */
    public synchronized void start() throws IllegalStateException, IOException {
        
        if (mDestination==null)
            throw new IllegalStateException("No destination ip address set for the stream !");

        if (mRtpPort<=0 || mRtcpPort<=0)
            throw new IllegalStateException("No destination ports set for the stream !");

        mPacketizer.setTimeToLive(mTTL);
        
        if (mMode != MODE_MEDIARECORDER_API) {
            encodeWithMediaCodec();
        } else {
            encodeWithMediaRecorder();
        }

    }

    /** Stops the stream. */
    @SuppressLint("NewApi") 
    public synchronized  void stop() {
        if (mStreaming) {
            try {
                if (mMode==MODE_MEDIARECORDER_API) {
                    mMediaRecorder.stop();
                    mMediaRecorder.release();
                    mMediaRecorder = null;
                    closeSockets();
                    mPacketizer.stop();
                } else {
                    mPacketizer.stop();
                    mMediaCodec.stop();
                    mMediaCodec.release();
                    mMediaCodec = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }   
            mStreaming = false;
        }
    }

實(shí)現(xiàn)Stream接口中start()和stop()的實(shí)現(xiàn)计福。start()需要子類去實(shí)現(xiàn)encodeWithMediaRecorder()和encodeWithMediaCodec()方法。stop()主要是釋放多媒體編碼類對象徽职。

    protected abstract void encodeWithMediaRecorder() throws IOException;

    protected abstract void encodeWithMediaCodec() throws IOException;

MediaStream類中兩個核心抽象方法象颖,就是使用MediaCodec和MediaRecorder兩種編碼方式的進(jìn)行實(shí)現(xiàn)。好比同一個目的地姆钉,兩條不同的路说订。

    protected void createSockets() throws IOException {

        final String LOCAL_ADDR = "net.majorkernelpanic.streaming-";

        for (int i=0;i<10;i++) {
            try {
                mSocketId = new Random().nextInt();
                mLss = new LocalServerSocket(LOCAL_ADDR+mSocketId);
                break;
            } catch (IOException e1) {}
        }

        mReceiver = new LocalSocket();
        mReceiver.connect( new LocalSocketAddress(LOCAL_ADDR+mSocketId));
        mReceiver.setReceiveBufferSize(500000);
        mReceiver.setSoTimeout(3000);
        mSender = mLss.accept();
        mSender.setSendBufferSize(500000);
    }

    protected void closeSockets() {
        try {
            mReceiver.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            mSender.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            mLss.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mLss = null;
        mSender = null;
        mReceiver = null;
    }

如果是通過MediaRecoder采集視頻抄瓦,需要再將視頻流映射到LocalSocket上來實(shí)現(xiàn)收發(fā)。所以當(dāng)使用MediaRecorder方式實(shí)現(xiàn)時(shí)克蚂,start()和stop()需要使用到createSockets()和closeSockets()闺鲸。具體細(xì)節(jié)在后面的文章會詳細(xì)分析。

到這里我們大致了解了MediaStream埃叭,主要采用了Android的MediaCodec和MediaRecorder兩種方式實(shí)現(xiàn)流媒體的采集和編解碼摸恍,下一步我們將詳細(xì)分析音頻流AudioStream和它的子類,了解音頻流采集和編碼的主要過程赤屋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末立镶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子类早,更是在濱河造成了極大的恐慌媚媒,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涩僻,死亡現(xiàn)場離奇詭異缭召,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)逆日,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門嵌巷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人室抽,你說我怎么就攤上這事搪哪。” “怎么了坪圾?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵晓折,是天一觀的道長。 經(jīng)常有香客問我兽泄,道長漓概,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任病梢,我火速辦了婚禮垛耳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘飘千。我一直安慰自己,他們只是感情好栈雳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布护奈。 她就那樣靜靜地躺著,像睡著了一般哥纫。 火紅的嫁衣襯著肌膚如雪霉旗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機(jī)與錄音厌秒,去河邊找鬼读拆。 笑死,一個胖子當(dāng)著我的面吹牛鸵闪,可吹牛的內(nèi)容都是我干的檐晕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蚌讼,長吁一口氣:“原來是場噩夢啊……” “哼辟灰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起篡石,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芥喇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凰萨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體继控,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年胖眷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了武通。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡瘦材,死狀恐怖厅须,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情食棕,我是刑警寧澤朗和,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站簿晓,受9級特大地震影響眶拉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜憔儿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一忆植、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谒臼,春花似錦朝刊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至底哥,卻和暖如春咙鞍,著一層夾襖步出監(jiān)牢的瞬間房官,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工续滋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翰守,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓疲酌,卻偏偏與公主長得像蜡峰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子徐勃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容