最近在做一個項目,簡單說一下需求吧:
android手機做前端視頻采集入口,能捕獲實時的視頻流並傳到服務器並且分發到pc客戶端實時的進行視頻的觀看。
就這個看似簡單的需求,由於我之前對流媒體全無了解,也因為接入了XX平台進行數據中轉,導致開發過程一再受阻。
但就目前已基本將該項目流程走通,所以必須在這里來作個小結。
在這里有幾個關鍵點:
a、視頻數據如何獲取。
b、獲取到的數據如何重新編碼,以何種形式編碼。
c、以什么協議進行傳輸。
d、視頻最后的解碼播放。
android充當攝像頭,進行流媒體傳輸的開源項目有spydroid。這個項目是研究android流媒體處理目前來說最好的切入點。網上也有很多對該項目源碼解析的文章,這里不再多說。我就上面提到的幾個關鍵點簡單說一下做法。
a獲取視頻數據
用android來實現還算是簡單。畢竟有豐富的sdk封裝。那么就會用到MediaRecorder。跟它相關的幾個類還有Camera、SurfaceHolder。
MediaRecorder用於錄像,相關設置如下:
if (mMediaRecorder == null) {
mMediaRecorder = new MediaRecorder(); } else { mMediaRecorder.reset(); } camera = getCamera();
camera.startPreview();
camera.unlock();
mMediaRecorder.setCamera(camera); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); <!--以上和以下順序不能顛倒,否則出錯> mMediaRecorder.setVideoSize(reX, reY); mMediaRecorder.setVideoFrameRate(fr); mMediaRecorder.setMaxDuration(0); mMediaRecorder.setMaxFileSize(Integer.MAX_VALUE); mMediaRecorder.setVideoEncodingBitRate(bit * 1000); mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); mMediaRecorder.setOrientationHint(90);//豎屏播放,但貌似只有在android手機上播放有效,在pc上播放無效。 mMediaRecorder.setOutputFile(sender.getFileDescriptor());//設置輸出為本地socket
然后就是Camera的獲取和設置:
1 public Camera getCamera(){ 2 if(camera==null){ 3 try{ 4 camera = Camera.open(); 5 Parameters paramters = camera.getParameters(); 6 paramters.setPreviewSize(Integer.parseInt(getPreferences().resolution.split("×")[0]),Integer.parseInt(getPreferences().resolutio n.split("×")[1])); 7 }catch(Exception e){ 8 e.printStackTrace(); 9 try { 10 if(camera!=null){ 11 camera.reconnect(); 12 }else{ 13 Toast.makeText(this, "連接攝像頭服務失敗!請重啟手機后再試。", Toast.LENGTH_SHORT).show(); 14 } 15 } catch (IOException e1) { 16 e1.printStackTrace(); 17 } 18 } 19 if (camera!=null) { 20 camera.setDisplayOrientation(90);
camera.setPreviewDisplay(mSurfaceHolder); 21 } 22 } 23 return camera; 24 }
負責預覽的SurfaceView和SurfaceHolder:
/** * 初始化surfaceView */ private void InitSurfaceView() { mSurfaceView = (SurfaceView) this.findViewById(R.id.surface_camera); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.setKeepScreenOn(true); mSurfaceHolder.addCallback(this); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//兼容低版本 }
打開錄像:
try { mMediaRecorder.prepare(); mMediaRecorder.start(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); releaseMediaRecorder(); }
到這里,已經可以在本地socket中拿到攝像頭獲取的流了。當然根據我的參數設置,獲得的流是系統MP4、h264編碼后的碼流。