Streaming video dari perangkat Android melalui aplikasi UDP ke JAVA

Jadi, pergi ke garis finish. Kami telah belajar cara streaming video dari android ke VLC player, sekarang tinggal mengintegrasikan jendela dengan video ke dalam aplikasi JAVA dan mulai mengarahkan robot.



Proyek open source VLCJ CAPRICA akan sangat membantu kami dalam hal ini .
Proyek vlcj menyediakan kerangka kerja Java untuk memungkinkan instance dari media player VLC asli yang akan tertanam dalam aplikasi Java.
Gagasan para lelaki itu sederhana, tetapi cerdik (benar-benar lada). Alih-alih menyiksa dengan pustaka FFmpeg dan banyak lagi, Anda harus segera memanggil spesialis inti dari pemutar media VLC yang normal, fungsional, dan profesional. Dan menyebutnya langsung dari aplikasi JAWA.

Siapa peduli, kami minta kucing.

Karena, dalam perjalanan ini, ada cukup banyak jebakan, kita akan mulai, seperti biasa, dengan yang sangat sederhana dan baru kemudian beralih ke hal sepele.

Instal Paket VLCJ


Pertama, periksa versi pemutar media VLC Anda. Kami tidak memerlukan versi baru, itu memotong apa yang diperlukan untuk aliran udp. Ini sudah disebutkan di posting sebelumnya . Oleh karena itu, kami mengunduh Payung versi 2.2.6 dan pada saat yang sama memeriksa dengan hati-hati paket JAVA kami. Mereka harus cocok dengan kedalaman bit. Jika pemain menggunakan arsitektur 64-bit, maka JDK harus sama. Dan itu tidak akan lepas landas.

Setelah itu, Anda sudah dapat mengunduh paket perpustakaan VLCJ itu sendiri



Harap dicatat bahwa kami membutuhkan paket distribusi (zip) vlcj-3.12.1 . Dialah yang bekerja dengan pemain versi VLC 2.2.x. Anda dapat unzip di mana saja, hal utama adalah bahwa itu tidak ada di folder VLC itu sendiri, karena dua file bertepatan dengan nama. Dan jika Anda menulis ulang, semua ini akan berakhir dengan kegagalan total.

Selanjutnya, kami membuat proyek di IDE IDE IntelliJ (jika Anda memiliki IDE yang berbeda, saya tidak dapat membantu apa pun) dan menuliskan dependensi yang diperlukan untuk mengintegrasikan perpustakaan VLCJ.



Kami melakukan hal itu untuk file:

jna-5.2.0

jna-platform-5.2.0

vlcj-3.12.1

Lalu kami membuat satu-satunya kelas dan menulis program kecil berikutnya di dalamnya.

import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent; import uk.co.caprica.vlcj.discovery.NativeDiscovery; import uk.co.caprica.vlcj.player.MediaPlayerFactory; import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer; import uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface; public class BasicPlayer { public final JFrame frame; public static String mrl; public static MediaPlayerFactory mpf; public static EmbeddedMediaPlayer MediaPlayer; public static CanvasVideoSurface videoSurface; public static Canvas canvas; public static void main(final String[] args) { new NativeDiscovery().discover(); mrl = "D:\\ttt.mp4"; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { BasicPlayer vp = new BasicPlayer(); vp.start(mrl); } }); } public BasicPlayer() { frame = new JFrame("My First Media Player"); frame.setBounds(200, 100, 540, 340); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.out.println(e); MediaPlayer.release(); mpf.release(); System.exit(0); } }); JPanel contentPane = new JPanel(); contentPane.setLayout(new BorderLayout()); canvas = new Canvas(); mpf = new MediaPlayerFactory(); videoSurface = mpf.newVideoSurface(canvas); MediaPlayer = mpf.newEmbeddedMediaPlayer(); MediaPlayer.setVideoSurface(videoSurface); contentPane.add(canvas, BorderLayout.CENTER); //        frame.setContentPane(contentPane); frame.setVisible(true); } public void start(String mrl) { MediaPlayer.playMedia(mrl); } } 

Ya, sementara kami mencoba memainkan hanya file (seperti yang terlihat dari kode). Lebih baik tidak memulai dengan udp - itu tidak akan berhasil. Dan file diputar sepenuhnya jika, tentu saja, Anda belum lupa untuk menempatkannya dengan nama yang sesuai sebelumnya jika diperlukan. Saya pikir bahkan untuk javista pemula sekalipun tidak akan sulit untuk memahami kode di atas.

Semua baru:

panggilan untuk VLCJ

  new NativeDiscovery().discover(); 

dan membuat instance media player itu sendiri

  mpf = new MediaPlayerFactory(); videoSurface = mpf.newVideoSurface(canvas); MediaPlayer = mpf.newEmbeddedMediaPlayer(); MediaPlayer.setVideoSurface(videoSurface); 

Dan kemudian kita tambahkan saja ke panel grafis yang diinginkan:

 contentPane.add(canvas, BorderLayout.CENTER); 

Dan semuanya, file akan diputar di jendela ini.

Sekarang coba ganti

 mrl = "D:\\ttt.mp4"; 

pada

 mrl = "udp://@:40002"; 

seperti yang kami lakukan dengan tenang di posting terakhir untuk streaming video melalui koneksi udp.
Nomor ini tidak akan berfungsi di sini. Jendela akan terbuka, tentu saja, tetapi akan menunjukkan ara, dalam arti layar gelap. Meskipun tidak akan ada log kesalahan. Tidak akan ada apa-apa.

Harus mencari tahu


Mungkin codec H264 yang kami pilih dalam pengaturan tidak ada? Berhenti, bagaimana file ttt.mp4 tadi diputar? Dia tidak bisa bermain dengan pengaturan ini, dia mp4.

Segera muncul pemahaman bahwa perpustakaan VLCJ hanya menjalankan inti pemain itu sendiri. Dan apa pra-pengaturan ada di sana, dia tidak tahu dan tidak ingin tahu. Artinya, kita perlu, entah bagaimana, ketika meluncurkan aplikasi JAVA, entah bagaimana melewati VLC player yang ingin kita gunakan secara eksplisit menggunakan H264 codec atau, katakanlah, kita ingin memutar gambar atau sesuatu yang lain.

Ternyata ini bisa dilakukan menggunakan kelas MediaPlayerFactory. Hanya kami meluncurkannya tanpa argumen, atau bahkan dengan mereka. Di stackoverflow.com, saya segera menemukan contoh sederhana terkait dengan rotasi gambar:

 String[] args = { "--video-filter", "rotate", "rotate-angle", "10" }; mpf = new MediaPlayerFactory(args); 

Artinya, kami mentransfer sesuatu di sana dengan array string ke pabrik media dan disimpan di sana untuk sumber daya media yang digunakan.

Saya mencoba metode ini untuk memutar file dan seperti biasa, tidak ada yang berhasil. Ternyata mereka lupa menambahkan dua tanda hubung dan menyebarkannya ke seluruh Internet. Saya harus menebak menggunakan metode transformasi yang serupa.

Singkatnya, seharusnya:

 String[] args = { "--video-filter", "rotate", "--rotate-angle", "10" }; 

Sekarang file referensi kami telah dikembalikan sebagaimana mestinya!



Selanjutnya akan sangat sederhana:

Untuk menentukan codec, sesuai dengan baris perintah VLC, kami menambahkan baris ke array string:

 "--demux=h264" 

Mencoba saluran udp lagi


mrl = "udp: // @: 40002";

Dan kali ini semuanya bekerja, menunjukkan kemenangan pikiran manusia. Sekarang jendela video ini atau beberapa jendela seperti itu Anda dapat dengan mudah port ke antarmuka grafis aplikasi JAVA Anda.

Akan tampak kemenangan?


Tidak juga. Sedikit kebingungan disebabkan oleh penundaan sementara atau, secara ilmiah, kelambatan. Pada awalnya mereka kurang lebih dapat diterima, tetapi jika Anda memiliki kesabaran untuk menonton video sampai akhir, maka Anda akan melihat bahwa jeda pada akhir menit pertama siaran mencapai sebanyak lima detik. Saya memiliki kesabaran yang cukup untuk pemotretan 10 menit, tetapi, anehnya, penundaan itu tidak meningkat lagi, tetapi tetap dalam batas yang sama.

videonya


Tentu saja, untuk menonton video dari kamera, ini bisa dilakukan, tetapi sulit mengendalikan robot. Bahkan penjelajah bulan bereaksi dua kali lebih cepat!

Kecurigaan segera jatuh pada proses caching dan mereka (kecurigaan) ternyata benar.

Yang paling arogan adalah:

  caching for network resources 

Itu hanya memakan hampir semuanya secara default, jika tidak diberikan kepadanya tepat waktu.
Dapat mengatur jeda dan:

 caching for cameras and microphones 

Oleh karena itu, untuk menghindari penundaan multi-detik, disarankan untuk menambahkan baris berikut ke array string yang sama, dipisahkan dengan koma:

  "--live-caching=100", "--network-caching=500", 

Parameter ditetapkan di sana dalam milidetik dan karena itu siapa pun dapat memilihnya sendiri.

Anda juga dapat menggunakan kunci:

 "--clock-jitter=time in milliseconds", 

Kemudian media player akan mencoba untuk mengoptimalkan jitter - berkedut layar. Tapi di sana, semakin banyak waktu yang ditetapkan, semakin baik itu dioptimalkan dan ini bisa dimengerti mengapa. Jadi di sini tinggal mencari konsensus dan terkadang melihat aib seperti itu di log:



Dia ingin, Anda tahu, memperbaiki jitter, dan Anda mengatur interval waktu terlalu kecil. Sekarang ini salahku.

Sekarang semuanya tampak sebagaimana mestinya. Penundaan dikurangi menjadi kurang dari satu detik (meskipun sedikit kurang).

videonya


Hasilnya, kami mendapat kode kerja yang sangat kecil

 import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import uk.co.caprica.vlcj.discovery.NativeDiscovery; import uk.co.caprica.vlcj.player.MediaPlayerFactory; import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer; import uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface; public class BasicVideoPlayer { public final JFrame frame; public static String mrl; public static MediaPlayerFactory mpf; public static EmbeddedMediaPlayer MediaPlayer; public static CanvasVideoSurface videoSurface; public static Canvas canvas; public static void main(final String[] args) { new NativeDiscovery().discover(); mrl = "udp://@:40002"; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { BasicVideoPlayer vp = new BasicVideoPlayer(); vp.start(mrl); } }); } public BasicVideoPlayer() { frame = new JFrame("My First Media Player"); frame.setBounds(200,100, 540, 340); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.out.println(e); MediaPlayer.release(); mpf.release(); System.exit(0); } }); JPanel contentPane = new JPanel(); contentPane.setLayout(new BorderLayout()); canvas = new Canvas(); String[] args = { "--video-filter", "rotate", "--rotate-angle", "270", "--demux=h264", "--clock-jitter=100", "--live-caching=100", "--network-caching=500", }; mpf = new MediaPlayerFactory(args); videoSurface = mpf.newVideoSurface(canvas); MediaPlayer = mpf.newEmbeddedMediaPlayer(); MediaPlayer.setVideoSurface(videoSurface); contentPane.add(canvas, BorderLayout.CENTER); frame.setContentPane(contentPane); frame.setVisible(true); } public void start(String mrl) { MediaPlayer.playMedia(mrl); } } 

Sekarang Anda dapat mengintegrasikan siaran video ke dalam program kontrol robot saya, tempat saya biasa mengirimkan video dalam bentuk potongan. Dan saya harus mengatakan kodenya sangat disederhanakan, dan kualitasnya telah ditingkatkan berdasarkan pesanan. Selain semuanya ke aliran video, kami dapat mengirimkan bacaan

akselerometer
giroskop
tingkat pencahayaan
tekanan udara
pembacaan kompas
suhu
dan bahkan kelembaban

Asalkan, tentu saja, bahwa semua sensor ini tersedia di smartphone Anda.

Dan bahkan nyalakan headlamp! Secara otomatis! Jika tingkat pencahayaan turun.


Hampir tidak ada orang yang tertarik, tetapi jika ada tautan ke github:

untuk kereta
untuk smartphone

Source: https://habr.com/ru/post/id473840/


All Articles