Dopo diversi giorni di ricerche su SO e Google, sto iniziando a rinunciare, quindi ho pensato che avrei potuto postare anche qui.Android: streaming della fotocamera come mjpeg
Sto creando un'app per Android che dovrebbe offrire qualche tipo di chat video. Dato che questo dovrebbe essere il più vicino possibile al tempo reale, ho letto su vari protocolli e ho deciso di provare MJPEG per i principianti (per ora non riguarda l'audio).
In questo momento lo streaming dei dati mi sta facendo impazzire. La connessione viene stabilita, l'app inizia a scrivere i frame di anteprima della videocamera nello stream, ma né VLC né mplayer iniziano a riprodurre video. Il monitoraggio della connessione rivela che i dati stanno arrivando.
Collegamento Questo codice viene eseguito da un compito asincrona, un ascoltatore viene notificato in caso di successo:
try
{
ServerSocket server = new ServerSocket(8080);
socket = server.accept();
server.close();
Log.i(TAG, "New connection to :" + socket.getInetAddress());
stream = new DataOutputStream(socket.getOutputStream());
prepared = true;
}
catch (IOException e)
{
Log.e(TAG, e.getMessage();
}
Sul mio PC eseguo 'mplayer http://tabletIP:8080
' e la tavoletta registra una connessione (e quindi inizia il mio streamer e l'anteprima della fotocamera). Funziona anche con VLC.
Streaming Questo scrive l'intestazione al flusso:
if (stream != null)
{
try
{
// send the header
stream.write(("HTTP/1.0 200 OK\r\n" +
"Server: iRecon\r\n" +
"Connection: close\r\n" +
"Max-Age: 0\r\n" +
"Expires: 0\r\n" +
"Cache-Control: no-cache, private\r\n" +
"Pragma: no-cache\r\n" +
"Content-Type: multipart/x-mixed-replace; " +
"boundary=--" + boundary +
"\r\n\r\n").getBytes());
stream.flush();
streaming = true;
}
catch (IOException e)
{
notifyOnEncoderError(this, "Error while writing header: " + e.getMessage());
stop();
}
}
Successivamente streaming è attivato attraverso la richiamata Camera.onPreviewFrame():
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
frame = data;
if (streaming)
mHandler.post(this);
}
@Override
public void run()
{
// TODO: cache not filling?
try
{
// buffer is a ByteArrayOutputStream
buffer.reset();
switch (imageFormat)
{
case ImageFormat.JPEG:
// nothing to do, leave it that way
buffer.write(frame);
break;
case ImageFormat.NV16:
case ImageFormat.NV21:
case ImageFormat.YUY2:
case ImageFormat.YV12:
new YuvImage(frame, imageFormat, w, h, null).compressToJpeg(area, 100, buffer);
break;
default:
throw new IOException("Error while encoding: unsupported image format");
}
buffer.flush();
// write the content header
stream.write(("--" + boundary + "\r\n" +
"Content-type: image/jpg\r\n" +
"Content-Length: " + buffer.size() +
"\r\n\r\n").getBytes());
// Should omit the array copy
buffer.writeTo(stream);
stream.write("\r\n\r\n".getBytes());
stream.flush();
}
catch (IOException e)
{
stop();
notifyOnEncoderError(this, e.getMessage());
}
}
Non c'è eccezione generata. L'mHandler gira nel proprio HandlerThread. Solo per essere sicuro di aver provato ad usare un AsyncTask, senza alcun risultato (btw, è meglio?).
I frame codificati vanno bene sul lato Android, li ho salvati in file jpg e li ho potuto aprire.
La mia ipotesi è che devo raggruppare i dati in qualche modo o dover impostare alcune opzioni per il socket o qualcosa del genere, ma .... beh, sono bloccato.
tl; dr: VLC non giocare flusso, mplayer dice 'cache non riempire', problema probabilmente ultimo segmento di codice, hanno bisogno di aiuto ~ :)
Grazie gentilmente!
Potrebbe inviare il codice per ottenere MJPEG dalla fotocamera. – Sourav301
@Sourav La classe deve implementare Camera.PreviewCallback. Dopo aver inizializzato la videocamera, chiama camera.setPreviewCallback (...). Il resto per il recupero di JPEGS è già nella mia domanda. – Managarm
Per coloro che si chiedono quale limite dovrebbe essere, può essere qualsiasi stringa java (composta da alfabeti, non sono sicuro che i numeri e caratteri speciali funzioneranno). –