2012-05-09 162 views
4

我正在將照片/視頻捕獲集成到我的應用中,並且遇到了視頻捕獲問題。無論何時錄像開始,屏幕閃爍,我會暫停一段時間,然後開始錄像。但是,使用手機的相機應用程序,根本沒有閃爍/暫停。開始錄製視頻時屏幕閃爍並調整大小

而且,我的相機預覽顯示會在調用recorder.start()後立即調整大小。我不明白這是爲什麼。它會使預覽失真(一切看起來都會變得更加寬廣)。

我的問題:如何防止開始錄像時的閃爍/暫停?如何防止recorder.start()調整我的預覽顯示?

每當啓用「視頻模式」時,立即調用initRecording()。一旦用戶按下按鈕,startRecording()被調用。最後,當再次按下按鈕時,調用stopRecording()。不太重要的是,當切換回「圖片模式」時,destroyRecorder()被調用。

@Override 
public void onResume() { 

    super.onResume(); 

    Camera camera = null; 
    try { 
     camera = Camera.open(); 
    } 
    catch (Exception e) { 
     // Camera isn't available 
     Toast.makeText(getActivity(), "Camera is not available at this time.", Toast.LENGTH_SHORT).show(); 
     getActivity().finish(); 
     return; 
    } 

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { 
     setCameraDisplayOrientation(camera); 
    } 
    else { 
     camera.setDisplayOrientation(90); 
    } 

    setCamera(camera); 
    setCameraZoomDisplay(camera); 

    if (getSurfaceHolder() != null) { 
     startPreview(); 

     if (getMode() == MODE_VIDEO) { 
      initRecording(); 
     } 
    } 
} 

private void setCameraDisplayOrientation(Camera camera) { 

    CameraInfo info = new CameraInfo(); 
    Camera.getCameraInfo(0, info); 

    int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation(); 
    int degrees = 0; 
    switch (rotation) { 
     case Surface.ROTATION_0: 
      degrees = 0; 
      break; 
     case Surface.ROTATION_90: 
      degrees = 90; 
      break; 
     case Surface.ROTATION_180: 
      degrees = 180; 
      break; 
     case Surface.ROTATION_270: 
      degrees = 270; 
      break; 
    } 

    int result = (info.orientation - degrees + 360) % 360; 
    camera.setDisplayOrientation(result); 
} 

private void initRecording() { 

    MediaRecorder recorder = new MediaRecorder(); 
    setRecorder(recorder); 

    Camera camera = getCamera(); 
    camera.unlock(); 
    recorder.setCamera(camera); 

    recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 

    CamcorderProfile cp = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); 
    recorder.setProfile(cp); 

    String extension; 
    switch (cp.fileFormat) { 
     case MediaRecorder.OutputFormat.MPEG_4: 
      extension = "mp4"; 
      break; 
     case MediaRecorder.OutputFormat.THREE_GPP: 
      extension = "3gp"; 
      break; 
     default: 
      extension = "tmp"; 
    } 

    setVideoMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)); 

    File toFile = new File(getActivity().getCacheDir(), "tempvideo.tmp"); 
    if (toFile.exists()) { 
     toFile.delete(); 
    } 
    setTempFile(toFile); 

    recorder.setOutputFile(toFile.getPath()); 
    recorder.setPreviewDisplay(getSurfaceHolder().getSurface()); 

    try { 
     recorder.prepare(); 
     setRecorderInitialized(true); 
    } 
    catch (IllegalStateException e) { 
     e.printStackTrace(); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private boolean startRecording() { 

    try { 
     getRecorder().start(); 
     setRecording(true); 

     ImageView actionImageView = getActionImageView(); 
     actionImageView.setImageResource(R.drawable.record_red); 
    } 
    catch (Exception e) { 
     getCamera().lock(); 
    } 

    return true; 
} 

private void stopRecording() { 

    MediaRecorder recorder = getRecorder(); 
    if (recorder != null && isRecording()) { 
     recorder.stop(); 
     setRecording(false); 
     setRecorderInitialized(false); 

     try { 
      insertVideo(); 
     } 
     catch (IOException e) { 
      e.printStackTrace(); 
     } 

     initRecording(); 

     ImageView actionImageView = getActionImageView(); 
     actionImageView.setImageResource(R.drawable.record_green); 
    } 
} 

private void destroyRecorder() { 

    MediaRecorder recorder = getRecorder(); 
    recorder.release(); 
    setRecorder(null); 
    getCamera().lock(); 
} 
+0

你有沒有想過是什麼導致閃爍和調整大小?我正在處理與我正在進行的項目相同的問題。 – MattDavis

+0

@MattDavis抱歉,遺憾的是沒有。 –

回答

7

原因時MediaRecorder.start()被調用略有放大是由於相機調整其大小,預覽匹配的正在錄製的視頻分辨率。通過設置預覽和視頻解析可以解決此問題。我想我也找到了一種方法來阻止閃爍,儘管我發現在使用Camera和MediaRecorder時,一些滯後或閃爍可能來自任何地方,這可能是有點難以追查。 The Android documentation for setting up a camera/video recorder是開始確保主要部分設置正確的好地方,但我發現有必要深入研究一些api類文檔以進行調試並使體驗真正流暢。

Camera.Parameters班是保持流暢錄像體驗的關鍵。一旦你有一個Camera對象,你可以使用Camera.getParameters()來獲取當前參數來修改它們。然後可以使用Camera.setParameters(Camera.Parameters)來觸發已經做出的任何更改。

爲防止視頻調整大小,我們需要確保參數的預覽大小與要錄製的視頻分辨率一致。要獲得支持的視頻/預覽尺寸列表,我們可以在我們當前的參數對象上使用Camera.Parameters.getSupportedPreviewSizes(),它將返回一個Camera.Size對象列表。這些對象中的每一個都具有寬度和高度屬性,可通過Camera.Size.widthCamera.Size.height直接訪問(無getter方法)。 getSupportedPreviewSizes()方法是guaranteed to return at least one result,,好像結果是從最高分辨率到最低分。

(對於API級別> 11還有一個getSupportedVideoSizes()方法,但它似乎只有在設備的某些視頻尺寸與預覽尺寸不同時纔會顯示,否則返回null。這個方法,所以我會堅持使用PreviewSizes,因爲它可以保證返回一個大小適合視頻和預覽,但它是要知道前進的東西。)

一旦我們有Camera.Size對應於視頻分辨率,我們可以使用Camera.Parameters.setPreviewSize(width, height).設置此大小此外,爲了幫助閃爍,我使用了Camera.Parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO).採取了一個這些步驟,使用Camera.setParameters()來通知攝像機您的更改。我已經成功地在獲取相機後設置這些參數,因爲在用戶與此Activity進行交互時設置參數導致了一些滯後。如果您使用相同的活動進行視頻和圖片捕獲,您也可以在此處設置圖片參數,Camera對象將使用適合每個模式的參數進行處理。

幾乎完成!現在預覽已經完成,剩下的就是確保MediaRecorder使用與預覽相同的分辨率。在準備媒體記錄器時,在撥打MediaRecorder.setProfile()(或設置編碼器,API級別< 8)和MediaRecorder.setOutputFile()之間,請撥打MediaRecorder.setVideoSize(width, height),使用與預覽相同的值。現在,使用MediaRecorder.start()從預覽到記錄的轉換應該是無縫的,因爲它們都使用相同的分辨率。

我這裏還有一些簡單的代碼片段,所以你可以看到在行動的一切:

獲取和設置PARAMS:

Camera.Parameters params = camera.getParameters(); 

params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 

//myVideoSize is an instance of Camera.Size 
List<Camera.Size> previewSizes = params.getSupportedPreviewSizes(); 
myVideoSize = previewSizes.get(0); 
params.setPreviewSize(myVideoSize.width, myVideoSize.height); 

camera.setParameters(params); 

然後設置在媒體記錄尺寸:

//After setting the profile.... 
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 

//Use myVideoSize from above 
mediaRecorder.setVideoSize(myVideoSize.width, myVideoSize.height); 

//Before setting the output file 
mediaRecorder.setOutputFile(myFile); 
+1

偉大的職位,感謝您解釋整個過程。我遵循這些步驟,但我仍然得到預覽和閃爍的大小調整。我將相機預覽尺寸和「MediaRecorder」的視頻尺寸設置爲相同的值(640x480)。 – Cat

+0

當我使用這條線。 mediaRecorder.setVideoSize(myVideoSize.width,myVideoSize.height);視頻不在android中錄製。 – Shankar