Медленное чтение из входного потока HttpUrlConnection

У меня есть URL-адрес, который ссылается на прямую трансляцию — сама прямая трансляция находится в файле «.ts».

Я использую vlcj для отображения видео с помощью Java, но сетевой код написан на чистой Java. Вот что у меня есть до сих пор:

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;


import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.discovery.NativeDiscovery;
import uk.co.caprica.vlcj.player.media.callback.DefaultCallbackMedia;

public class Main {

  public static class StreamMedia extends DefaultCallbackMedia{

    private InputStream stream;

    public StreamMedia(InputStream stream, String[] mediaOptions) {
      //512 bytes to read per call to onRead
      super(false, 512, mediaOptions);
      this.stream = stream;
    }

    @Override
    protected int onRead(byte[] arg0, int arg1) throws IOException {
      int amnt = stream.read(arg0);
      return amnt;
    }

    @Override
    protected void onClose() {
      try {
        stream.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    @Override
    protected long onGetSize() {
      return 0;
    }

    @Override
    protected boolean onOpen() {
      return true;
    }

    @Override
    protected boolean onSeek(long arg0) {
      return false;
    }

  }

  public static void main(String[] args) throws Exception{    
      //The url I'm streaming to my machine.
      //It's a ".ts" resource 
      URL url = new URL("STREAM URL");

      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setUseCaches(false);
      connection.connect();

      StreamMedia test = new StreamMedia(connection.getInputStream(), new String[0]);


      //Just sets up my VLC JFrame. Right from the vlc tutorials
      new NativeDiscovery().discover();
      SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        JFrame frame = new JFrame("A GUI");
        frame.setBounds(100, 100, 600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        EmbeddedMediaPlayerComponent mediaPlayer = new EmbeddedMediaPlayerComponent();
        frame.setContentPane(mediaPlayer);

        frame.setVisible(true);

        //play the StreamMedia object I've created
        mediaPlayer.getMediaPlayer().playMedia(test);
      }
    });

    }

}

Основное узкое место возникает в методе onRead() в классе StreamMedia, поскольку моя программа должна блокироваться, пока не будет получено больше данных. Это приводит к прерывистому воспроизведению со значительными зависаниями.

Однако, когда я воспроизвожу поток с помощью программы VLC, он воспроизводится хорошо, поэтому я не думаю, что это проблема с моим сервером.

Я пытался использовать буферизованные потоки, но это позволяло плавное воспроизведение только на начальных этапах. Я также пробовал, чтобы рабочий поток читал входные данные, в то время как другой фактически проигрывал их, но изменений не было.

В любом случае, я могу это исправить? Спасибо.


person heftyulson    schedule 15.08.2018    source источник


Ответы (1)


Этот подход с использованием Java для чтения вашего потока действительно НЕ рекомендуется.

Если у вас есть сетевой поток для воспроизведения, воспроизведите его, используя стандартный сетевой MRL, используя mediaPlayer.playMedia. Итак, если VLC может воспроизводить ваш поток, используйте тот же MRL при использовании vlcj.

С сетевым потоком и файлом .ts вам нужно будет иметь дело с подпунктами в vlcj. В тестовых источниках vlcj есть множество примеров, которые воспроизводят сетевые потоки.

Если вы должны настаивать на этом подходе, я не уверен, что 512 байт — это хороший размер буфера, поэтому вы можете попробовать увеличить его. Размер буфера vlcj по умолчанию для этого был 10 КБ, но даже в этом случае этот подход неоптимален.

person caprica    schedule 23.12.2018