Android: la diffusion de la caméra comme mjpeg
Après plusieurs jours de recherche, DONC google et je commence à m'abandonner, j'ai donc pensé que je pourrais aussi bien de poster ici.
Je crée une application android qui devrait offrir une sorte de chat vidéo. Comme ce doit être aussi proche que possible de en temps réel, j'ai lu sur différents protocoles et a décidé d'essayer MJPEG pour les débutants (ne concernant pas avec de l'audio pour l'instant).
Dès maintenant en streaming les données sont me rend fou. La connexion sera établie, l'application commence à écrire l'appareil photo les images de prévisualisation de la rivière, mais ni VLC ni mplayer démarrer la lecture de la vidéo. La surveillance de la connexion révèle que les données arrivent.
Connexion
Ce code est exécuté par un async task, un auditeur est notifié à succès:
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();
}
Sur mon PC, j'execute 'mplayer http://tabletIP:8080
" et la tablette enregistre une connexion (et commence donc mon streamer et l'aperçu de la caméra). Cela fonctionne aussi avec VLC.
Streaming Ceci écrit l'en-tête du flux:
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();
}
}
Après la diffusion est déclenchée par la Caméra.onPreviewFrame() Rappel:
@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());
}
}
Il n'y a aucune exception n'est levée. Le mHandler s'exécute dans son propre HandlerThread. Juste pour être sûr, j'ai essayé d'utiliser un AsyncTask, en vain (btw, est-ce mieux?).
De l'encodage des cadres sont beaux sur l'android côté, je enregistrés dans des fichiers jpg et pourrait ouvrir de leur.
Ma conjecture est que j'ai à regrouper les données d'une manière ou d'avoir à définir des options pour la prise ou quelque chose, mais....eh bien, je suis coincé.
tl;dr: VLC ne pas jouer stream, mplayer dit "cache pas remplir", le problème est probablement dans le dernier segment de code, besoin d'aide~ 🙂
Merci de bien vouloir!
OriginalL'auteur Managarm | 2013-02-11
Vous devez vous connecter pour publier un commentaire.
Je l'ai eu. Semble, comme mon http-/contenu des en-têtes ont été foiré. Le bon en-têtes doivent être:
et
Bien sûr, l'endroit où placer la limite est votre propre choix. Aussi il y a probablement certains champs sont facultatifs (par exemple, la plupart en Cache-Control), mais cela fonctionne, et jusqu'à maintenant j'ai été trop paresseux pour les démonter. L'important est de se rappeler les retours à la ligne ((
\r\n
des bidules)...Votre classe doit implémenter l'Appareil photo.PreviewCallback. Après l'initialisation de votre appareil photo caméra d'appel.setPreviewCallback(...). Le reste pour la récupération des fichiers JPEG est déjà dans ma question.
Pour ceux qui se demandent ce que la limite devrait être, il peut être tout java string (composé de l'alphabet, ne sais pas si les chiffres et les caractères spéciaux de travail).
J'ai utilisé le protocole rtsp pour de vrai streamming android appareil photo, mais j'ai eu environ 2 secondes de retard au récepteur . j'ai changé le protocole à utiliser mjpeg streamming mais la vidéo n'avait pas commencer à jouer au récepteur alors que la connexion est établie , de la même à votre problème . voulez-vous me dire comment vous avez résolu ce problème ?
désolé, c'était il y a quelques temps et nous avons fini par utiliser RTSP (MJPEG était à l'origine de la mise en œuvre qui nous en débarrasser). Tout ce que je pouvais vous dire au niveau du code est dans ma question et la réponse que j'ai trouvé. Assurez-vous de tester sur un réseau local avec une connexion directe à éviter NAT problèmes. Ah, et quoi que vous fassiez, UDP, à moins que vous ne le pouvez pas. Outre que je n'attends pas de MJPEG pour avoir une latence plus faible, il devrait être plus élevé, car chaque image est fondamentalement une image clé. Si vous le pouvez, essayez moderne codec comme h264. Cheers!
OriginalL'auteur Managarm