直播技術(shù)筆記(2)——視頻采集+音頻采集

按: 最近做了一個(gè)直播的預(yù)研項(xiàng)目, 因此記錄下直播的技術(shù)的實(shí)現(xiàn),在這過程中一些問題解決的思路,以android平臺的實(shí)現(xiàn)說明。

項(xiàng)目結(jié)構(gòu)

  • unity紋理插件和視頻采集(視頻源)
    VideoSourceCamera
  • 麥克風(fēng)采集(音頻源)
    AudioSourceMIC
  • 視頻編碼
    VideoEncoder
  • 音頻編碼
    AudioEncoder
  • FLV編碼(混合)
    MuxerFLV
  • http流上傳(上傳源)
    PublisherHttp
  • 流視頻播放(回放)
    play
  • OpenGL圖形圖象處理

從本篇文章開始將會介紹這幾個(gè)組件的實(shí)現(xiàn)細(xì)節(jié),相互依賴關(guān)系的處理方式。

(2) —— 視頻采集+麥克風(fēng)采集

在過去,視頻和音頻采集都需要專有的設(shè)備,如今,已經(jīng)成為標(biāo)準(zhǔn)的智能手機(jī)組件。

  • 抽象采集過程,定義接口類.
    采集最終是為了后續(xù)處理過程提供視頻源和音頻源,在android的標(biāo)準(zhǔn)處理中,分別是將視頻刷在紋理上,音頻輸出字節(jié)流。
    此外,還需要得到采集一刻的顯示時(shí)間戳信息(PTS-Presentation TimeStamp)

      //視頻源
      interface IHippoVideoSource extends IHippoSwitcher {
          //向其它gl surface刷新圖像信息, PTS在接口調(diào)用時(shí)發(fā)生
          void onFeedVideo(GLEnv env);
      }
      //音頻源
      interface IHippoAudioSource extends IHippoSwitcher {
          void onFeedEncoder(ByteBuffer inputBuffer, Ref ptsRet); //音頻字節(jié)流輸出
      }
    
  • 相機(jī)預(yù)覽實(shí)現(xiàn)
    涉及android組件:import android.hardware.Camera;
    選擇前置/后置相機(jī), 分辨率,刷新率。
    //選擇相機(jī)
    Camera.CameraInfo info = new Camera.CameraInfo();
    int numCameras = Camera.getNumberOfCameras();
    foreach camera in camera
    Camera.getCameraInfo(i, info);
    if(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)//前置
    ...
    else if(info.facing == Camera.CameraInfo.CAMERA_FACING_BACK)//后置
    分辨率,刷新率,都是通過通過設(shè)置 CameraParameter來完成
    mParms = mCamera.getParameters();
    //設(shè)置...
    mCamera.setParameters(mParms);

  • 準(zhǔn)備相機(jī)渲染
    注意,這里是兩張貼圖,一個(gè)是Camera組件所需要的GL_TEXTURE_EXTERNAL_OES 類型,另一個(gè)是unity為我們準(zhǔn)備好的貼圖(wrap)
    mCameraGLTexture = new GLTexture(width, height, GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_RGBA);
    mSurfaceTexture = new SurfaceTexture(mCameraGLTexture.getTextureID());//CameraRender.getInstance().getTextureId());

    //在系列(1)已說過,我們需要一個(gè)render to texture所需的rendertexture
    mTextureCanvas = new GLRenderTexture(mGLTexture)
    ...
    void renderCamera2Texture()
    {
    mTextureCanvas.begin();
    cameraDrawObject.draw();
    mTextureCanvas.end();
    }

  • 繪制輸出
    很不幸,實(shí)時(shí)采集和實(shí)時(shí)繪制發(fā)生不同線程,所以采集完成,需要推送消息到渲染線程。

     //相機(jī)采集回調(diào)
     public void onFrameAvailable(final SurfaceTexture surfaceTexture)
     {
         getProcessor().append (new Task() {
         @Override
         public void run() {
             if (state != EHippoState.e_started) return;
             surfaceTexture.updateTexImage();
         }
     });
     
     //實(shí)時(shí)渲染
     Task renderCameraTask = new Task() {
         @Override
         public void run() throws Exception {
             if(state != EHippoState.e_started) return;
             renderCamera2Texture();
    
             if(!HippoRuntime.isUnityMode())
             {
                 renderCurrent();
             }
         }
     };
    

    至此,任務(wù)完成!在這步驟里,你可以做點(diǎn)“美顏”什么的,不再贅述.

  • 音頻采集
    • 準(zhǔn)備音頻
      android 提供了AudioRecord組件,需要設(shè)置音頻輸出格式(PCM), 采樣率,還有采集緩沖大小。

        int minBufferSize = AudioRecord.getMinBufferSize(mSampleRate, HippoConfig.AUDIO_CHANNEL_COUNT, HippoConfig.AUDIO_FORMAT);
        bufferSize = mSampleRate * 10;
        if (bufferSize < minBufferSize)
            bufferSize = ((minBufferSize / mSampleRate) + 1) * mSampleRate * 2;
      
        mAudioRecord = new AudioRecord(
                MediaRecorder.AudioSource.MIC,       // source
                mSampleRate,                         // sample rate, hz
                HippoConfig.AUDIO_CHANNEL_COUNT,
                HippoConfig.AUDIO_FORMAT,
                bufferSize);
        mAudioRecord.startRecording();
      
    • 音頻采集輸出
      void onFeedEncoder(ByteBuffer inputBuffer, Ref ptsRet) {
      inputBuffer.clear();
      int inputLength = mAudioRecord.read(inputBuffer, inputBuffer.capacity() );
      if (HippoConfig.log_level >= HippoConfig.LOG_DEBUG)
      Log.i(HippoConfig.TAG, "onFeedEncoder inputLength of:"+inputLength);
      inputBuffer.limit(inputLength);
      long pts = HippoUtil.getPresentTimeUs() - (((inputLength/2) / mSampleRate)/1000000000); ;//assumbly 16bit
      ptsRet.set(pts);
      需要注意的是,AudioRecord提供了一個(gè)采集buffer, 你必須在保證它未被寫滿前,處理已有的音頻樣本,如果優(yōu)先級不高導(dǎo)致,緩沖被覆蓋,聲音會有明顯的毛刺,記得 onFeedEncoder 有較高優(yōu)先級!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,641評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,604評論 2 380

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