2011-10-12 16 views
28

Sto provando a utilizzare l'encoder H264 su Android per creare video dalla videocamera e utilizzare FFmpeg in mux in audio (tutto sul telefono Android stesso)Decodifica feed telecamera H264 codificata hardware di Android utilizzando ffmpeg in tempo reale

Quello che ho compiuto finora è il packetizing del video H264 nei pacchetti rtsp e la decodifica tramite VLC (oltre UDP), quindi so che il video è almeno correttamente formattato. Tuttavia, sto riscontrando problemi nel trasferire i dati video a ffmpeg in un formato comprensibile.

Ho provato l'invio degli stessi rtsp pacchetti a una porta 5006 su localhost (su UDP), quindi fornendo ffmpeg con il file sdp che gli dice che porta locale il flusso video è in arrivo su e su come decodificare il video , se capisco lo streaming rtsp correttamente. Tuttavia, questo non funziona e sto riscontrando dei problemi nel diagnosticare il perché, poiché ffmpeg si trova lì in attesa di input.

Per motivi di latenza e scalabilità, non posso semplicemente inviare il video e l'audio al server e metterlo da parte, deve essere fatto al telefono, nel modo più leggero possibile.

Quello che penso che sto cercando sono suggerimenti su come questo può essere realizzato. La soluzione ottimale sarebbe inviare il video H264 a ffmpeg a un pipe, ma non è possibile inviare i parametri di file del file sdp necessari per decodificare il video.

Posso fornire ulteriori informazioni su richiesta, ad esempio come ffmpeg è compilato per Android ma dubito che sia necessario.

Oh, e il modo in cui inizio ffmpeg è tramite la riga di comando, vorrei davvero evitare di chiacchierare con Jni se è possibile.

E l'aiuto sarebbe molto apprezzato, grazie.

+3

perché stai decodifica usando ffmpeg? utilizzare l'oggetto MediaPlayer incorporato –

+0

Hai provato a utilizzare live555 per trasmettere l'output di ffmpeg tramite RTSP? Inoltre, ffmpeg non dovrebbe sondare il flusso e trovare informazioni sul flusso stesso? – Shark

+0

Penso che Aviad abbia la verità. Come fai a sapere quale formato video produce la fotocamera? –

risposta

1

Hai provato a utilizzare java.lang.Runtime?

String[] parameters = {"ffmpeg", "other", "args"}; 
Program program Runtime.getRuntime().exec(parameters); 

InputStream in = program.getInputStream(); 
OutputStream out = program.getOutputStream(); 
InputStream err = program.getErrorStream(); 

Poi si scrive sullo standard output e leggere da stdin e stderr. Non è un pipe, ma dovrebbe essere migliore di usare un'interfaccia di rete.

+0

OP qui, non sto più lavorando a questo problema (ho rinunciato), ma dovrei aggiungere che ho tentato esattamente questo. Non ricordo tutti i dettagli, ma ho provato ad usare sia l'InputStream, sia più pipe FIFO usando il sistema operativo (una pipe per il video, una per l'audio). Tuttavia, il problema con questo metodo era che non ero in grado di fornire ffmpeg informazioni sufficienti per comprendere e decodificare i pacchetti video generati dal feed della telecamera. La vera ragione per cui volevo usare rtsp era che, teoricamente, avrebbe fornito a FFmpeg informazioni sufficienti per decodificare il live streaming. – joebobfrank

1

Un po 'in ritardo, ma penso che questa sia una buona domanda e non ha ancora una buona risposta.

Se si desidera trasmettere in streaming telecamera e microfono da un dispositivo Android, esistono due alternative principali: implementazioni Java o NDK.

  1. Implementazione Java.

    Sto solo citando l'idea, ma fondamentalmente è implementare un server RTSP e protocollo RTP in Java sulla base di questi standard Real-Time Streaming Protocol Version 2.0 e RTP Payload Format for H.264 Video. Questo compito sarà molto lungo e difficile. Ma se stai facendo il tuo PhP potrebbe essere bello avere una buona lib di Java RTSP per Android.

  2. Implementazione NDK.

    Questa è un'alternativa comprende varie soluzioni. L'idea principale è usare una libreria C o C++ di potenza nella nostra applicazione Android. Per questa istanza, FFmpeg.Questa libreria può essere compilata per Android e può supportare varie architetture. Il problema di questo approccio è che potrebbe essere necessario conoscere l'NDK di Android, C e C++ per realizzare questo.

    Ma c'è un'alternativa. Puoi racchiudere la libreria c e usare FFmpeg. Ma come?

    Ad esempio, utilizzando FFmpeg Android, che è stato compilato con x264, libass, fontconfig, freetype e fribidi e supporta varie architetture. Ma è ancora difficile programmare se si desidera eseguire lo streaming in tempo reale è necessario gestire i descrittori di file e i flussi in/out.

    L'alternativa migliore, dal punto di vista della programmazione Java, è l'utilizzo di JavaCV. JavaCV utilizza involucri da librerie comunemente usati di computer vision che comprende: (OpenCV, FFmpeg, ecc, e fornisce classi di utilità per rendere la loro funzionalità più facile da utilizzare sulla piattaforma Java, tra cui (ovviamente) Android

    JavaCV viene inoltre fornito. con visualizzazione hardware a schermo intero accelerato (CanvasFrame e GLCanvasFrame), metodi facili da usare per eseguire codice in parallelo su più core (Parallel), calibrazione geometrica e cromatica facile da usare di videocamere e proiettori (GeometricCalibrator, ProCamGeometricCalibrator, ProCamColorCalibrator) , rilevamento e corrispondenza dei punti funzione (ObjectFinder), un insieme di classi che implementano l'allineamento diretto dell'immagine dei sistemi di videoproiettori (principalmente GNImageAligner, ProjectiveTransformer, ProjectiveColorTransformer, ProCamTransformer e ReflectanceInitializer), un pacchetto di analisi BLOB (Blobs) e varie funzionalità nella classe JavaCV. Alcune di queste classi hanno anche un omologo OpenCL e OpenGL, i loro nomi che terminano con CL o che iniziano con GL, cioè .: JavaCVCL, GLCanvasFrame, ecc

Ma come possiamo usare questa soluzione?

Qui abbiamo un'implementazione di base per lo streaming utilizzando UDP.

String streamURL = "udp://ip_destination:port"; 
recorder = new FFmpegFrameRecorder(streamURL, frameWidth, frameHeight, 1); 
recorder.setInterleaved(false); 
// video options // 
recorder.setFormat("mpegts"); 
recorder.setVideoOption("tune", "zerolatency"); 
recorder.setVideoOption("preset", "ultrafast"); 
recorder.setVideoBitrate(5 * 1024 * 1024); 
recorder.setFrameRate(30); 
recorder.setSampleRate(AUDIO_SAMPLE_RATE); 
recorder.setVideoCodec(AV_CODEC_ID_H264); 
recorder.setAudioCodec(AV_CODEC_ID_AAC); 

Questa parte del codice mostra come inizializzare l'oggetto FFmpegFrameRecorder chiamato registratore. Questo oggetto catturerà e codificherà i fotogrammi ottenuti dalla fotocamera e i campioni ottenuti dal microfono.

Se si desidera acquisire un'anteprima nella stessa app Android, è necessario implementare una classe CameraPreview questa classe convertirà i dati grezzi forniti dalla fotocamera e creerà l'anteprima e il fotogramma per FFmpegFrameRecorder.

Ricordarsi di sostituire ip_destination con l'ip del pc o del dispositivo in cui si desidera inviare lo streaming. La porta può essere 8080 come esempio.

@Override 
public Mat onCameraFrame(Mat mat) 
{ 
    if (audioRecordRunnable == null) { 
     startTime = System.currentTimeMillis(); 
     return mat; 
    } 
    if (recording && mat != null) { 
     synchronized (semaphore) { 
      try { 
       Frame frame = converterToMat.convert(mat); 
       long t = 1000 * (System.currentTimeMillis() - startTime); 
       if (t > recorder.getTimestamp()) { 
        recorder.setTimestamp(t); 
       } 
       recorder.record(frame); 
      } catch (FFmpegFrameRecorder.Exception e) { 
       LogHelper.i(TAG, e.getMessage()); 
       e.printStackTrace(); 
      } 
     } 
    } 
    return mat; 
} 

Questo metodo mostra l'implementazione del metodo onCameraFrame che supporta l'Mat (foto) dalla fotocamera e viene convertito in frame e registrati dall'oggetto FFmpegFrameRecorder.

@Override 
public void onSampleReady(ShortBuffer audioData) 
{ 
    if (recorder == null) return; 
    if (recording && audioData == null) return; 

    try { 
     long t = 1000 * (System.currentTimeMillis() - startTime); 
     if (t > recorder.getTimestamp()) { 
      recorder.setTimestamp(t); 
     } 
     LogHelper.e(TAG, "audioData: " + audioData); 
     recorder.recordSamples(audioData); 
    } catch (FFmpegFrameRecorder.Exception e) { 
     LogHelper.v(TAG, e.getMessage()); 
     e.printStackTrace(); 
    } 
} 

stessa con l'audio audioData è un oggetto ShortBuffer che sarà registratore dal FFmpegFrameRecorder.

Nella destinazione del PC o del dispositivo è possibile eseguire il seguente comando per ottenere lo streaming.

ffplay udp://ip_source:port 

Il ip_source è l'IP dello smartphone che è in streaming la fotocamera e microfono torrente. La porta deve essere la stessa 8080.

Ho creato una soluzione nel mio repository github qui: UDPAVStreamer.

Buona fortuna