2013-06-04 18 views
5

Ho un video di registrazione MediaRecorder e sono molto confuso dall'effetto di setCaptureRate().MediaRecorder Android setCaptureRate() e velocità di riproduzione video

In particolare, mi preparo il mio MediaRecorder come segue:

mMediaRecorder = new MediaRecorder(); 
mCamera.stopPreview(); 
mCamera.unlock(); 
mMediaRecorder.setCamera(mCamera); 
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 
mMediaRecorder.setProfile(CamcorderProfile.QUALITY_TIME_LAPSE_480P); 
mMediaRecorder.setCaptureRate(30f); 
mMediaRecorder.setOrientationHint(270); 
mMediaRecorder.setOutputFile(...); 
mMediaRecorder.setPreviewDisplay(...); 
mMediaRecorder.prepare(); 

I record per cinque secondi (con un CountDownTimer, ma questo è irrilevante), e questo è il file che viene generato:

$ ffmpeg -i ~/CaptureRate30fps.mp4 
... 
Seems stream 0 codec frame rate differs from container frame rate: 180000.00 (180000/1) -> 30.00 (30/1) 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/mspitz/CaptureRate30fps.mp4': 
    Metadata: 
    major_brand  : isom 
    minor_version : 0 
    compatible_brands: isom3gp4 
    creation_time : 2013-06-04 00:52:00 
    Duration: 00:00:02.59, start: 0.000000, bitrate: 5238 kb/s 
    Stream #0.0(eng): Video: h264 (Baseline), yuv420p, 720x480, 5235 kb/s, PAR 65536:65536 DAR 3:2, 30 fps, 30 tbr, 90k tbn, 180k tbc 
    Metadata: 
     creation_time : 2013-06-04 00:52:00 

Si noti che la durata è di circa 3 secondi. Il video funziona anche molto più velocemente, come se fossero 5 secondi di video stipati in 3.

Ora, se registro preparando il mio mediaRecorder esattamente come sopra, ma sottraendo la linea setCaptureRate (30f), ottengo un file come this:

$ ffmpeg -i ~/NoSetCaptureRate.mp4 
... 
Seems stream 0 codec frame rate differs from container frame rate: 180000.00 (180000/1) -> 90000.00 (180000/2) 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/mspitz/NoSetCaptureRate.mp4': 
    Metadata: 
    major_brand  : isom 
    minor_version : 0 
    compatible_brands: isom3gp4 
    creation_time : 2013-06-04 00:50:41 
    Duration: 00:00:04.87, start: 0.000000, bitrate: 2803 kb/s 
    Stream #0.0(eng): Video: h264 (Baseline), yuv420p, 720x480, 2801 kb/s, PAR 65536:65536 DAR 3:2, 16.01 fps, 90k tbr, 90k tbn, 180k tbc 
    Metadata: 
     creation_time : 2013-06-04 00:50:41 

Si noti che la Durata è come previsto, circa 5 secondi. Anche il video viene riprodotto a una velocità normale.

Sto usando setCaptureRate (30f) perché 30 fotogrammi al secondo è il valore del mio CamcorderProfile's videoFrameRate. Sul mio Galaxy Nexus S2 (4.2.1), omettendo setCaptureRate() va bene, ma quando ho provato su un Galaxy Nexus S3 (4.1.1), omettendo setCaptureRate() si ottiene l'utile errore "start failed -22" quando ho chiamato mMediaRecorder.start().

Quindi, cosa mi manca? Ho pensato che la velocità di acquisizione e il frame rate del video fossero indipendenti, ma è chiaro che non lo sono. C'è un modo per determinare a livello di codice ciò di cui ho bisogno per impostare la velocità di acquisizione al fine di determinare che il mio video riproduce a velocità 1x?

+0

Perché 'QUALITY_TIME_LAPSE_480P' e non' QUALITY_480P'? Il tempo trascorso non è intrinsecamente una velocità di riproduzione 1x. –

+0

Hai anche esaminato 'MediaRecorder.setVideoFrameRate'? –

+0

@RomanNurik Grazie per il tuo commento! In realtà non voglio registrare il suono, e l'unico modo per farlo sembra essere usando un video time lapse. Re: setVideoFrameRate, viene chiamato quando chiamo setProfile(): https://github.com/android/platform_frameworks_base/blob/master/media/java/android/media/MediaRecorder.java#L329 Infatti, guardando la fonte è ciò che mi ha dato la mancia per aver bisogno di chiamare setCaptureRate() in primo luogo. https://github.com/android/platform_frameworks_base/blob/master/media/java/android/media/MediaRecorder.java#L337 Altrimenti, ho ottenuto un -22. – spitzanator

risposta

1

(Questa è una sintesi della risoluzione dai commenti sulla domanda iniziale)

Il problema può essere che direttamente utilizzando i tassi di riproduzione QUALITY_TIME_LAPSE_480P profilo influenze, dal momento che decade di tempo non sono implicitamente un 1x velocità di riproduzione.

Inoltre, se il motivo si sta utilizzando quel profilo è quello di evitare l'audio vengano registrati quando si utilizza QUALITY_480P (dal time-lapse non registrano l'audio), si consiglia di chiamare invece CamcorderProfile.get(QUALITY_480P) e parametri video impostati sulla MediaRecorder manualmente in base al profilo, senza chiamare direttamente MediaRecorder.setProfile. Un MediaRecorder che non ha parametri audio impostati non dovrebbe teoricamente registrare alcun audio.

0

Secondo la documentazione, setCaptureRate(double fps) viene utilizzato per impostare la registrazione a intervalli di tempo, con audio ignorato. È molto utile se vuoi meno fps di quelli che il sistema può effettivamente fornire. Voi chiedete più fps rispetto al sistema in grado di fornire, qui è una citazione da developer.android.com/reference:

Nota che il registratore non può garantire che i frame verranno catturate al tasso determinato a causa di limitazioni/encoder della macchina fotografica. Tuttavia prova per essere il più vicino possibile.

Ciò che il tuo codice non chiama, è setVideoFrameRate(int rate). Credo che usando questa funzione, la tua registrazione sarà corretta.

+0

Sfortunatamente, non è corretto. Dai un'occhiata all'origine di MediaRecorder: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/MediaRecorder.java setProfile (profilo CamcorderProfile) non chiama setVideoFrameRate (profile.videoFrameRate); Il commento qui è quello che mi ha fatto provare setCaptureRate() in primo luogo per farlo funzionare su un Galaxy Nexus S3. – spitzanator

0

Hai ragione. Ti darò la risposta corretta. Ho affrontato la stessa situazione. Avvio non riuscito-22 appartiene alla frequenza di frame rate.hence che stai dando non è nel range del dispositivo. utilizza getSupportedPreviewFpsRange() per determinare l'intervallo di fps del dispositivo e quindi imposta di conseguenza. Puoi utilizzare PREVIEW_FPS_MAX_INDEX e PREVIEW_FPS_MIN_INDEX per fFps massimo e minimo.

uso seguente codice darà risultato moltiplicato per 1000 ie se frame rate è 5, ritornerà 5000.

Camera.Parameters camParameter = camera.getParameters(); 
    List<int[]> frame = camParameter.getSupportedPreviewFpsRange(); 
     Iterator<int[]> supportedPreviewFpsIterator = frame.iterator(); 
     while (supportedPreviewFpsIterator.hasNext()) { 
      int[] tmpRate = supportedPreviewFpsIterator.next(); 
      StringBuffer sb = new StringBuffer(); 
      sb.append("supportedPreviewRate: "); 
      for (int i = tmpRate.length, j = 0; j < i; j++) { 
       sb.append(tmpRate[j] + ", "); 
      } 
      Log.d(VTAG, sb.toString()); 
     } 
    } 

ulteriore controllo qui: http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewFpsRange()

EDIT: in Android documento dello sviluppatore.È stato detto che setCaptureRate() imposta la velocità di acquisizione del fotogramma video. Questo può essere usato per impostare una diversa velocità di acquisizione del fotogramma video rispetto alla velocità di riproduzione del video registrato. Questo metodo imposta anche la modalità di registrazione su time lapse. Dal momento che imposta anche la modalità di registrazione su intervallo di tempo, controlla il video dopo aver rimosso il profilo di qualità QUALITY_TIME_LAPSE_480P su qualsiasi altro profilo normale supportato come QUALITY_480P o imposta le impostazioni del media multimediale personalizzato impostando la dimensione del video e altro.Può aiutarti.

+0

Grazie per la tua risposta! Devi infatti verificare la presenza di framerate supportati, ma ho verificato che 30 fps è ben all'interno dei limiti accettabili sul Galaxy Nexus S3, quindi non è questo il problema. – spitzanator

Problemi correlati