Open MachineIntelligence6 opened 4 years ago
I have created a simple player with FFMPEGFrameGrabber on normal videos its working fine, but on few high quality videos its stucking.
I have attached the src and the videos to replicate the issue.
`package com.mi6.videoviewer;
import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.nio.ByteBuffer; import java.nio.ShortBuffer; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;
import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine;
import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.Java2DFrameConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class FFmpegPlayer extends Thread implements PlayerControls{
final Logger log = LoggerFactory.getLogger(FFmpegPlayer.class); private FFmpegFrameGrabber grabber; private final Java2DFrameConverter converter; private AudioFormat audioFormat; private PropertyChangeSupport listener; private ExecutorService executor; private SourceDataLine soundLine = null; private boolean audio = true; public FFmpegPlayer() { avutil.av_log_set_level(avutil.AV_LOG_TRACE); converter = new Java2DFrameConverter(); listener = new PropertyChangeSupport(this); executor = Executors.newSingleThreadExecutor(); } public void setVideo(String videoFilename) { grabber = new FFmpegFrameGrabber(videoFilename); } public void addPropertyChangeListener(PropertyChangeListener l) { listener.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { listener.removePropertyChangeListener(l); } @Override public void run() { try { grabber.start(); } catch (Exception e) { log.error("Cannot Start Grabber", e); endVideo(); return; } audioFormat = new AudioFormat(grabber.getSampleRate(), 16, grabber.getAudioChannels(), true, true); final DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); try { soundLine = (SourceDataLine) AudioSystem.getLine(info); soundLine.open(audioFormat); soundLine.start(); } catch (LineUnavailableException e) { log.error("No Audio Found", e); } catch(IllegalArgumentException e) { log.error("No Audio Found", e); } while (!Thread.interrupted()) { Frame frame = null; try { frame = grabber.grabFrame(true, true, true, false, true); } catch (Exception e) { log.error("No Frame Found", e); } if (frame == null) { break; } if (frame.image != null) { BufferedImage image = converter.convert(frame); listener.firePropertyChange("Image", null, image); } else if (frame.samples != null && audio) { final ShortBuffer channelSamplesShortBuffer = (ShortBuffer) frame.samples[0]; channelSamplesShortBuffer.rewind(); final ByteBuffer outBuffer = ByteBuffer.allocate(channelSamplesShortBuffer.capacity() * 2); for (int i = 0; i < channelSamplesShortBuffer.capacity(); i++) { short val = channelSamplesShortBuffer.get(i); outBuffer.putShort(val); } try { if(soundLine == null) break; executor.submit(new Runnable() { public void run() { soundLine.write(outBuffer.array(), 0, outBuffer.capacity()); outBuffer.clear(); } }).get(); } catch (InterruptedException interruptedException) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { e.printStackTrace(); } catch (NullPointerException e) { break; } } } executor.shutdownNow(); try { executor.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { log.error("Cannot stop the sound thread", e); } if(soundLine!=null) soundLine.stop(); try { grabber.stop(); } catch (Exception e) { log.error("Cannot stop grabber", e); } try { grabber.release(); } catch (Exception e) { log.error("Cannot release grabber", e); } endVideo(); } public void endVideo() { listener.firePropertyChange("Stop", null, null); } public void playVideo() { start(); } public void muteVideo() { audio = !audio; } public void stopVideo() { interrupt(); }
} `
import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List;
import javax.swing.JComponent; import javax.swing.JFrame;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class VideoPanel extends JComponent implements PlayerControls, PropertyChangeListener {
final Logger log = LoggerFactory.getLogger(VideoPanel.class); private static final long serialVersionUID = 1L; private volatile FFmpegPlayer processor; private BufferedImage image; private List<String> videos; private int index = 0; public VideoPanel(List<String> videos) { this.videos = videos; } public void setVideos() { if(videos == null || videos.isEmpty()) { log.error("Playlist is Empty"); return; } String videoFilename = videos.get(index++); if(index > videos.size() -1) { log.info("Resetting Playlist Order. "); index = 0; } log.info("Setting Video to Play, Video Path is: "+ videoFilename); if(processor!=null) { processor.stopVideo(); processor.removePropertyChangeListener(this); } processor = new FFmpegPlayer(); processor.addPropertyChangeListener(this); processor.setVideo(videoFilename); playVideo(); } public void playVideo() { log.info("Play Video Event arise"); processor.playVideo(); } public void stopVideo() { log.info("Stop Video Event arise. "); processor.stopVideo(); } public void muteVideo() { log.info("Mute Video Event arise"); processor.muteVideo(); } public void cleanMemory() { log.info("Memory Cleaning Event arise. "); Object obj = new Object(); WeakReference<Object> ref = new WeakReference<>(obj); obj = null; while (ref.get() != null) { System.gc(); } } @Override protected void paintComponent(Graphics g) { if (image == null) return; g.drawImage(image, 0, 0, getWidth(), getHeight(), null); g.dispose(); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("Image")) { image = (BufferedImage) evt.getNewValue(); repaint(); } if (evt.getPropertyName().equals("Stop")) { log.info("Stop Playing Video. "); setVideos(); } } public static void main(String[] args) { EventQueue.invokeLater(() -> { int rows = 1; int cols = 1; int size = rows * cols; List<String> videos = new ArrayList<>(); //videos.add("C:\\Users\\Mi6\\Desktop\\test\\1.mp4"); videos.add("C:\\Users\\Mi6\\Desktop\\test\\Video257.mp4"); videos.add("C:\\Users\\Mi6\\Desktop\\test\\Video264.mp4"); videos.add("C:\\Users\\Mi6\\Desktop\\test\\Video258.mp4"); VideoPanel[] video = new VideoPanel[size]; for (int i = 0; i < size; i++) video[i] = new VideoPanel(videos); JFrame frame = new JFrame(); frame.setPreferredSize(new Dimension(1920, 1024)); frame.setLayout(new GridLayout(rows, cols, 1, 1)); for (int i = 0; i < size; i++) frame.add(video[i]); frame.pack(); frame.setVisible(true); for (int i = 0; i < size; i++) video[i].setVideos(); }); }
[https://1drv.ms/u/s!As2o7s_R_SwDgg31nsERCTgd414A?e=dMPe5d](Test Videos)
Be sure to try JavaFX: https://groups.google.com/forum/#!topic/javacv/uTpd9FGRvyE
I have created a simple player with FFMPEGFrameGrabber on normal videos its working fine, but on few high quality videos its stucking.
I have attached the src and the videos to replicate the issue.
`package com.mi6.videoviewer;
import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.nio.ByteBuffer; import java.nio.ShortBuffer; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;
import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine;
import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.Java2DFrameConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class FFmpegPlayer extends Thread implements PlayerControls{
} `
`package com.mi6.videoviewer;
import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List;
import javax.swing.JComponent; import javax.swing.JFrame;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class VideoPanel extends JComponent implements PlayerControls, PropertyChangeListener {
} `
[https://1drv.ms/u/s!As2o7s_R_SwDgg31nsERCTgd414A?e=dMPe5d](Test Videos)