JavaCV 視訊濾鏡(LOGO、滾動字幕、畫中畫、NxN宮格)

HiIT青年發表於2021-04-21

其實,在JavaCV中除了FFmpegFrameGrabber和FFmpegFrameRecorder之外,還有一個重要的類,那就是FFmpegFrameFilter。

FFmpegFrameFilter封裝了ffmpeg濾鏡相關操作,使得使用JavaCV進行濾鏡操作變成簡單,關於ffmpeg濾鏡的使用文件可以檢視ffmpeg的文件:http://www.ffmpeg.org/ffmpeg-filters.html

簡單來說,如果熟悉ffmpeg的濾鏡功能,那麼使用FFmpegFrameFilter的難度不大,下面通過幾個例項演示一下FFmpegFrameFilter的使用方式:

視訊縮放

視訊縮放使用的濾鏡為scale,語法為:scale=width:height[:interl={1|-1}],這裡需要注意的是,JavaCV對視訊輸入的濾鏡命名是固定的:

  1. 如果是一路視訊,那麼輸入為in,輸出為out
  2. 如果是多路視訊,那麼輸入為n:v,輸出為v,這裡的n就是第幾路視訊輸入

瞭解了這一點之後,使用FFmpegFrameFilter就很簡單了,下面以視訊縮放為例,完整的程式碼如下:

public class Scale {

  public static void main(String[] args) throws IOException {

    String filterStr = "scale=320:240[out]";
    //
    FFmpegFrameGrabber stream0 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
    stream0.start();
    // width=640, height=352
    System.out.println("width=" + stream0.getImageWidth() + ", height=" + stream0.getImageHeight());
    //
    FFmpegFrameFilter filter = new FFmpegFrameFilter(filterStr, stream0.getImageWidth(), stream0.getImageHeight());
    filter.start();
    //
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new File("stream0.mp4"), 320, 240);
    recorder.setFormat("mp4");
    recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
    recorder.start();

    int idx = 0;
    Frame frame0, frame;
    while ((frame0 = stream0.grabImage()) != null) {
      filter.push(frame0);
      frame = filter.pullImage();
      if (frame != null && frame.image != null) {
        recorder.record(frame);
      }
      if (idx++ > 100) {
        break;
      }
    }
    recorder.close();
    filter.close();
    stream0.close();
  }
}

濾鏡效果:

視訊填充

視訊填充效果使用的濾鏡為pad,語法為:pad=width[:height[:x[:y[:color]]]], FFmpegFrameFilter使用例項跟視訊縮放一樣,不過濾鏡要調整為下面這句:

String filterStr = "pad=700:412:30:30:pink[out]";

另外錄製寬高改為原視訊寬高:

FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new File("stream0.mp4"), stream0.getImageWidth(), stream0.getImageHeight());

濾鏡效果:

LOGO、字幕

為視訊新增LOGO和字幕(滾動)的濾鏡相對於前面兩個要複雜一點,不過Java程式碼實現是一樣的,採用的濾鏡如下:

movie='logo.png'[logo];[in]drawtext=text='我是滾動字幕--HiIT青年':fontfile=simhei.ttf:y=h-line_h-10:x=w-(t-4.5)*w/5.5:fontcolor=white:fontsize=40:shadowx=2:shadowy=2[text];[text][logo]overlay=15:15[out]

濾鏡效果:

視訊合成

前面提到的都是一路視訊操作,對於多路視訊的濾鏡相對於單路視訊有點區別,就是輸入有in變成n:v,輸出由out變成v, 下面是兩路視訊合成的完整原始碼:

public class Hstack {

  public static void main(String[] args) throws IOException {

    String filterStr = "[0:v][1:v]hstack=inputs=2[v]";
    //
    FFmpegFrameGrabber stream0 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
    FFmpegFrameGrabber stream1 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
    stream0.start();
    stream1.start();
    // width=640, height=352
    System.out.println("width=" + stream0.getImageWidth() + ", height=" + stream0.getImageHeight());
    //
    FFmpegFrameFilter filter = new FFmpegFrameFilter(filterStr, stream0.getImageWidth(), stream0.getImageHeight());
    filter.setVideoInputs(2);
    filter.start();
    //
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new File("stream0.mp4"), stream0.getImageWidth(), stream0.getImageHeight());
    recorder.setFormat("mp4");
    recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
    recorder.start();

    int idx = 0;
    Frame frame0, frame1, frame;
    while ((frame0 = stream0.grabImage()) != null && (frame1 = stream1.grabImage()) != null) {
      filter.push(0, frame0);
      filter.push(1, frame1);
      frame = filter.pullImage();
      if (frame != null && frame.image != null) {
        recorder.record(frame);
      }
      if (idx++ > 200) {
        break;
      }
    }
    recorder.close();
    filter.close();
    stream0.close();
    stream1.close();
  }
}

濾鏡效果:

畫中畫

畫中畫濾鏡其實跟兩路視訊合成差不多,不過用的是overlay,語法為:overlay[=x:y[[:rgb={0, 1}]]。下面一個畫中畫效果的濾鏡例子:

String filterStr = "[0:v]scale=iw/2:ih/2[a];[1:v][a]overlay=30:30[v]";

濾鏡效果:

NxN N宮格視訊

其實不管是NxN,還是1xN,Nx1都可以使用padoverlay組合來實現,下面是2x2四宮格的濾鏡:

String filterStr = "[0:v]pad=iw*2:ih*2[a];[a][1:v]overlay=w[b];[b][2:v]overlay=0:h[c];[c][3:v]overlay=w:h[v]"; 

四路視訊輸入:

FFmpegFrameGrabber stream0 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
FFmpegFrameGrabber stream1 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
FFmpegFrameGrabber stream2 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));
FFmpegFrameGrabber stream3 = new FFmpegFrameGrabber(new File("F:/Video/1.mp4"));

濾鏡效果:

文章原始碼後續整理後將會在公眾號釋出!

=========================================================

HiIT青年
關注公眾號,閱讀更多文章。

相關文章