2017-07-19 63 views
0

我有一个使用JavaCV逐帧过滤视频的代码。该代码是像下面使用JavaCV的并发视频帧处理

try (FFmpegFrameGrabber grabber = createGrabber()) { 
    grabber.start(); 
    try (FFmpegFrameRecorder recorder = createRecorder(grabber)) { 
     recorder.start(); 
     Frame frame; 
     while ((frame = grabber.grab()) != null) { 
      Frame editedFrame = filterFrame(frame); //This takes a long time. 
      recorder.setTimestamp(grabber.getTimestamp()); 
      recorder.record(editedFrame); 
     } 
    } 
} 

由于线Frame editedFrame = filterFrame(frame);需要相当长的时间,是有可能利用多线程等全过程可以更快?我正在考虑使用类似ExecutorServiceLinkedBlockingQueue的东西来一次处理多个帧,然后根据时间戳记录帧。

+0

你的filterFrame方法(你没有显示)是否利用多线程,所以它的执行速度更快? – auburg

+0

是的,你可以。但你应该考虑同步帧。可能你可以像这里https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html那样在filterFrame中分割工作。这将是更明智的 –

+0

@VladislavKysliy是否有可能像4线程一样执行器服务,然后过滤将每4帧完成,帧将被记录在他们抓住相同的序列? –

回答

0

这是pattern producer

生产者类是执行长期任务(filterFrame):

import java.util.concurrent.Callable; 

public class Producer implements Callable<Frame> { 

    private final Frame frame; 

    public Producer(Frame frame) { 
     this.frame = frame; 
    } 

    @Override 
    public Frame call() throws Exception { 
     return filterFrame(frame); 
    } 
} 

消费类店面帧:

import java.util.Map; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.Future; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.concurrent.TimeUnit; 

public class Consumer implements Runnable { 

    private final BlockingQueue<Map.Entry<Long, Future<Frame>>> queue; 
    public Boolean continueProducing = Boolean.TRUE; 
    private final FFmpegFrameRecorder recorder; 

    public Consumer(FFmpegFrameRecorder recorder, 
        BlockingQueue<Map.Entry<Long, Future<Frame>>> queue) { 
     this.recorder = recorder; 
     this.queue = queue; 
    } 

    @Override 
    public void run() { 
     try { 
      Map.Entry<Long, Future<Frame>> entry = this.queue.poll(2, TimeUnit.SECONDS); 
      Frame editedFrame = entry.getValue().get(); 
      recorder.setTimestamp(entry.getKey()); 
      recorder.record(editedFrame); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

和管理任务的主要部分并关机threadPool

try (FFmpegFrameGrabber grabber = createGrabber()) { 
      grabber.start(); 
      try (FFmpegFrameRecorder recorder = createRecorder(grabber)) { 
       recorder.start(); 
       Frame frame; 
       ExecutorService threadPool = Executors.newWorkStealingPool(); 
       BlockingQueue<Map.Entry<Long, Future<Frame>>> queue = new LinkedBlockingQueue<>(); 
       threadPool.execute(new Consumer(recorder, queue)); 
       while ((frame = grabber.grab()) != null) { 
        queue.put(new Map.Entry<Long, Future<Frame>>() { 
         @Override 
         public Long getKey() { 
          return grabber.getTimestamp(); 
         } 

         @Override 
         public Future<Frame> getValue() { 
          return threadPool.submit(new Producer(frame)); // Frame editedFrame = filterFrame(frame); //This takes a long time. 
         } 

         @Override 
         public Future<Frame> setValue(Future<Frame> value) { 
          return null; 
         } 
        }); 
       } 
       threadPool.shutdownNow(); 
      } 
     } 

注意:它没有复制粘贴解决方案,需要为您的代码进行一些自定义。如果你分享更多的信息,我会改变它