Веб-поток Android JavaCV FFmpeg на локальный статический веб-сайт

Для моего интегрированного теста я работаю над приложением, которое должно обеспечивать прямую трансляцию на локальном веб-сайте. Я уже создал рабочий сайт, работающий на nanohttpd. Это приложение выполняет также специальную обработку изображений. Поэтому я использую JavaCV. Библиотека работает отлично, и все привязки cpp тоже работают.

Мой вопрос: как настроить прямую трансляцию, которую можно будет напрямую воспроизводить на статическом сайте, размещенном на nanohttpd? - Я на правильном пути?

Мой код:

в этом:

private void initLiveStream() throws FrameRecorder.Exception {
    /* ~~~ https://github.com/bytedeco/javacv/issues/598 ~~~ */
    frameRecorder = new FFmpegFrameRecorder("http://localhost:9090", imageWidth, imageHeight, 0);
    frameRecorder.setVideoOption("preset", "ultrafast");
    frameRecorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
    frameRecorder.setAudioCodec(0);
    frameRecorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
    frameRecorder.setFormat("webm");
    frameRecorder.setGopSize(10);
    frameRecorder.setFrameRate(frameRate);
    frameRecorder.setVideoBitrate(5000);
    frameRecorder.setOption("content_type","video/webm");
    frameRecorder.setOption("listen", "1");
    frameRecorder.start();
}

В моем CameraView:

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    Camera.Size size = camera.getParameters().getPreviewSize();
    Frame frame = new AndroidFrameConverter().convert(data, size.width, size.height);
    try {
         if(frameRecorder!=null){
             frameRecorder.record(frame);
         }
     } catch (FrameRecorder.Exception e) {
         e.printStackTrace();
     }
 }

Вот одна из трассировок стека, которые часто появлялись в моем поиске решения:

org.bytedeco.javacv.FrameRecorder$Exception: avio_open error() error -111: Could not open 'http://localhost:9090'

Я не смог найти какой-либо другой темы, посвященной этой конкретной проблеме.

заранее спасибо

РЕДАКТИРОВАТЬ

Благодаря Честеру Кобусу, вот мой используемый код:

Веб-сокет:

//Constructor
AsyncHttpServer serverStream = new AsyncHttpServer();
List<WebSocket> sockets = new ArrayList<>();

//http://stackoverflow.com/a/33021907/5500092
//I'm planning to use more sockets. This is the only uniform expression I found.
serverStream.websocket("/((?:[^/]*/)*)(.*)", new AsyncHttpServer.WebSocketRequestCallback() {
     @Override
     public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) {
         String uri = request.getPath();
         if (uri.equals("/live")) {
             sockets.add(webSocket);

             //Use this to clean up any references to your websocket
             webSocket.setClosedCallback(new CompletedCallback() {
                 @Override
                 public void onCompleted(Exception ex) {
                     try {
                         if (ex != null)
                             Log.e("WebSocket", "Error");
                     } finally {
                         sockets.remove(webSocket);
                     }
                 }
             });
         }
     }
});

//Updater (Observer pattern)
@Override
public void updated(byte[] data) {
    for (WebSocket socket : sockets) {
         socket.write(new ByteBufferList(data));
    }
}

Записывать активность

private long start_time = System.currentTimeMillis();

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    long now_time = System.currentTimeMillis();
    if ((now_time - start_time) > 250) {
        start_time = now_time;
        //https://forums.xamarin.com/discussion/40991/onpreviewframe-issue-converting-preview-byte-to-android-graphics-bitmap
        Camera.Size size = camera.getParameters().getPreviewSize();
        YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        image.compressToJpeg(new Rect(0, 0, size.width, size.height), 60, byteArrayOutputStream);
        MainActivity.getWebStreamer().updated(byteArrayOutputStream.toByteArray());
    }
}

JavaScript

var socket;
var imageElement;

/**
 * path - String.Format("ws://{0}:8090/live", Window.Location.HostName)
 * image - HTMLImageElement
 */
function imageStreamer(path, image) {
    imageElement = image;
    socket = new WebSocket(path);

    socket.onmessage = function(msg) {
        var arrayBuffer = msg.data;
        var reader = new FileReader();
        reader.onload = function(e) {
            imageElement.src = e.target.result;
        };
        reader.readAsDataURL(arrayBuffer);
    };
}

person Thomas Devoogdt    schedule 24.03.2017    source источник
comment
Вы добавили разрешение на Интернет в свой AndroidManifest.xml?   -  person Chester Cobus    schedule 24.03.2017
comment
Да, для моего сервера nanohttpd. Включены: CAMERA, ACCESS_WIFI_STATE, INTERNET, RECORD_AUDIO, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE.   -  person Thomas Devoogdt    schedule 25.03.2017
comment
Раньше я работал с JavaCV, и обработка изображений происходит медленно и перегружает устройство. Я знаю, что это переработка, но я бы использовал веб-сокеты в Android и на веб-сайте и просто отправил байты предварительного просмотра на веб-сайт (веб-сокеты позволят вам это сделать), таким образом, у вас нет зависимости от JavaCV и он будет транслироваться намного быстрее, потому что вы не создаете видео для потоковой передачи с приложением Cool. github.com/koush/android-websockets и html5rocks.com/en/tutorials/websockets/basics   -  person Chester Cobus    schedule 25.03.2017
comment
Используйте эту ссылку для веб-сокета сервера на стороне Android: github.com/koush/AndroidAsync   -  person Chester Cobus    schedule 25.03.2017
comment
Чтобы ответить на ваш вопрос, я предполагаю, что ваш сайт находится на отдельной машине, а ваше приложение — на мобильном устройстве, поэтому вы не можете подключиться через локальный хост: 9090. Вы должны использовать IP-адрес, который был назначен из Wi-Fi. Я не думаю, что доступ через Интернет возможен, когда мобильное устройство является сервером.   -  person Chester Cobus    schedule 25.03.2017


Ответы (1)


Вот пример того, как будет выглядеть реализация веб-сокета:

 //This code must run just before Camera is opened.    

 AsyncHttpServer server = new AsyncHttpServer();

  server.websocket("/live","ws", new WebSocketRequestCallback() {
            @Override
            public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) {
                this.webSocket = webSocket //webSocket make it an instance variable
            }
  });

 //listen on port 5000
 server.listen(5000);
 //browsing ws://{IP Address assigned by wifi}:5000/live

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
   this.websocket.send(data);
}

Используйте Gradle, чтобы получить библиотеку выше

dependencies {
    compile 'com.koushikdutta.async:androidasync:2.+'
}

Вот код клиента для вашего сайта:

  var socket = new WebSocket('ws://{IP Address assigned by wifi}:5000/live', ['soap', 'xmpp']);

  socket.onmessage = function(msg) {
      var arrayBuffer = msg.data;
      var image = document.getElementById('image'); //<img id="image" /> in HTML

      var reader = new FileReader();
      reader.onload = function(e) {
           image.src = e.target.result;
      };
      reader.readAsDataURL(arrayBuffer);
  };
person Chester Cobus    schedule 24.03.2017
comment
Спасибо за ответ. Я дам ему попробовать. - person Thomas Devoogdt; 25.03.2017
comment
Я пытаюсь использовать веб-сокет, но каждый раз, когда вместо server.websocket(...) запускается server.get(...). Любой совет? - person Thomas Devoogdt; 25.03.2017
comment
Я не думаю, что вам нужно, чтобы server.get(...) удалял его. - person Chester Cobus; 25.03.2017
comment
Наконец, я получаю данные onmenssage в своем JavaScript. Но я не могу преобразовать эти необработанные данные в изображение. - person Thomas Devoogdt; 25.03.2017
comment
stackoverflow.com/questions/13390454/ дайте мне знать, если это сработает - person Chester Cobus; 25.03.2017
comment
Это сработало, но в приложении где-то утечка памяти. Я скоро загружу ваш измененный код. Но спасибо за советы, очень помогли! - person Thomas Devoogdt; 26.03.2017
comment
Нет проблем, попробуйте сохранить фрагменты байтов предварительного просмотра в файл и прочитать фрагмент файла для отправки на ваш сайт. пожалуйста, проголосуйте или примите ответ. Благодарю. - person Chester Cobus; 26.03.2017