После нескольких дней поиска SO и google я начинаю сдаваться, поэтому я подумал, что могу также опубликовать здесь.Android: потоковая передача камеры как mjpeg
Я создаю приложение для Android, которое должно предложить какой-то видеочат. Поскольку это должно быть как можно ближе к реальному времени, я читал о различных протоколах и решил попробовать MJPEG для стартеров (не относящихся к аудио на данный момент).
Прямо сейчас передача данных приводит меня в бешенство. Соединение устанавливается, приложение начинает записывать кадры предварительного просмотра камеры в поток, но ни VLC, ни mplayer не начинают воспроизводить видео. Мониторинг подключения показывает, что данные поступают.
Подключение Этот код выполняется с помощью задачи асинхронным, слушатель получает уведомление об успехе:
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();
}
На моем компьютере я исполню «MPlayer http://tabletIP:8080
» и планшет регистрирует соединение (и, таким образом, начинается мой стример и предварительный просмотр камеры). Это также работает с VLC.
Streaming Об этом пишет заголовок потока:
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();
}
}
После потоковая срабатывает через 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());
}
}
Там не исключение брошено. MHandler работает в собственном HandlerThread. Просто чтобы убедиться, что я попытался использовать AsyncTask, безрезультатно (кстати, это лучше?).
Закодированные фреймы на стороне андроида, я сохранил их в jpg-файлах и мог их открыть.
Я предполагаю, что мне нужно как-то скопировать данные или установить некоторые параметры для сокета или что-то в этом роде, но ... ну, я застрял.
TL; др: VLC не играет поток, MPlayer говорит: «кэш не заполнение», проблема, вероятно, в последнем сегменте кода, нужна помощь ~ :)
Спасибо любезно!
Не могли бы вы выслать код для получения MJPEG с камеры. – Sourav301
@Sourav Ваш класс должен реализовать Camera.PreviewCallback. После инициализации камеры вызовите camera.setPreviewCallback (...). Остальное для получения JPEGS уже в моем вопросе. – Managarm
Для тех, кто задается вопросом, какая граница должна быть, это может быть любая строка java (состоящая из алфавитов, не уверена, будут ли номера и специальные символы работать). –