当前位置:   article > 正文

JAVACV+ffmpeg+OpenCV实现视频叠加合成(AR效果视频生成)_javacv 多个音频滤镜交互

javacv 多个音频滤镜交互

同时抓取两个视频的帧,在叠加合并时进行一些图像处理,并将合并后的帧写入输出文件,最后释放资源

具体实现步骤:

  1. 准备工作

    • 导入所需的库,这里主要是 OpenCV 和 JavaCV 相关的库。
    • 创建一个 OpenCVFrameConverter.ToIplImage 对象 converter,它用于将 JavaCV 帧转换为 OpenCV 的 IplImage 对象。
  2. 设置视频抓取器

    • 创建两个 FFmpegFrameGrabber 对象,分别用于原始视频文件和待合并的视频文件。
    • 设置连接超时时间和读取数据超时时间。
    • 启动两个抓取器并获取视频的长度(单位:微秒),用于后续的处理。
  3. 设置视频参数

    • 检查并调整两个视频的帧率,确保它们相同。
    • 设置输出视频的宽度和高度。
    • 计算视频的宽高比例,并计算目标高度。
  4. 设置临时文件和输出文件

    • 获取系统临时文件目录,创建临时文件对象。
    • 设置输出文件路径,并准备好文件名。
  5. 设置录制器参数

    • 创建一个 FFmpegFrameRecorder 对象,用于录制合并后的视频。
    • 设置输出编码器、音频采样率、帧率、视频比特率、视频编码器等参数。
  6. 抓取和处理视频帧

    • 循环抓取原始视频的帧,同时抓取待合并视频的帧。
    • 如果当前帧是图像帧,则进行叠加处理:
      • 将 JavaCV 帧转换为 OpenCV 的 Mat 对象,进行图像边界处理。
      • 将 JavaCV 帧转换为 BufferedImage,并创建 Graphics2D 对象。
      • 抓取待合并视频的帧,进行相应处理。
      • 将待合并视频的帧叠加到当前帧上,并写入输出文件。
    • 如果当前帧包含音频,则也将音频写入输出文件。
  7. 释放资源

    • 停止并释放所有的抓取器和录制器。
    • 关闭颜色转换过滤器。
      1. OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
      2. System.out.println(mergeFilePath);
      3. FFmpegFrameGrabber frameGrabber1 = new FFmpegFrameGrabber(file);
      4. FFmpegFrameGrabber frameGrabber2 = new FFmpegFrameGrabber(mergeFilePath);
      5. frameGrabber2.setOption("timeout", "5000000"); // 设置连接超时时间
      6. frameGrabber2.setOption("stimeout", "20000000"); // 设置读取数据超时时间
      7. Frame frame = null;
      8. Frame mergeFrame1= null;
      9. Frame mergeFrame = null;
      10. FFmpegFrameRecorder recorder = null;
      11. String fileName = null;
      12. try {
      13. frameGrabber1.start();
      14. frameGrabber2.start();
      15. int videoLengthInSeconds = (int) (frameGrabber1.getLengthInTime() / 1000000);
      16. int videoLengthInSeconds2 = (int) (frameGrabber2.getLengthInTime() / 1000000);
      17. System.out.println("秒数"+videoLengthInSeconds+"-----------"+videoLengthInSeconds2);
      18. System.out.println(frameGrabber1.getImageWidth()+"11111111111111"+frameGrabber1.getImageHeight());
      19. double frameRate = frameGrabber2.getFrameRate();
      20. if (frameRate != frameGrabber1.getFrameRate()) {
      21. frameGrabber1.setFrameRate(frameRate);
      22. }
      23. frameGrabber2.setFrameRate(24);
      24. frameGrabber1.setFrameRate(24);
      25. // 计算两个视频的长度(单位:秒)
      26. // 设置帧率
      27. frameGrabber1.setImageWidth(1080);
      28. frameGrabber1.setImageHeight(1920);
      29. int outputWidth = 1080; // 合成后视频的宽度
      30. int outputHeight = 1920;
      31. // 根据视频的宽高比例计算目标高度
      32. double videoRatio1 = (double) frameGrabber1.getImageWidth() / frameGrabber1.getImageHeight();
      33. double videoRatio2 = (double) frameGrabber2.getImageWidth() / frameGrabber2.getImageHeight();
      34. // 获取图像宽和高
      35. int imageWidth = outputWidth;
      36. int imageHeight = outputHeight;
      37. int imageWidth1 = frameGrabber2.getImageWidth();;
      38. int imageHeight1 = frameGrabber2.getImageHeight();
      39. long sourceVideoDuration = frameGrabber1.getLengthInTime();
      40. long mergeVideoDuration = frameGrabber2.getLengthInTime();
      41. FFmpegFrameFilter colorConvertFilter = new FFmpegFrameFilter("format=rgb24", imageWidth, imageHeight);
      42. colorConvertFilter.setPixelFormat(avutil.AV_PIX_FMT_RGB24);
      43. colorConvertFilter.start();
      44. FFmpegFrameFilter filter = new FFmpegFrameFilter("colorkey=black", imageWidth1, imageHeight1);
      45. filter.setPixelFormat(avutil.AV_PIX_FMT_RGB24);
      46. filter.start();
      47. // 设置时间戳,确保两个视频的起始点一致
      48. // 随机生成一个新的文件名
      49. Random random = new Random();
      50. long name1 = System.currentTimeMillis() + RandomUtils.nextInt(100, 9999);
      51. // 获取系统默认的临时文件目录
      52. String tempDir = System.getProperty("java.io.tmpdir");
      53. // 创建临时文件对象8
      54. File tempFile = new File(tempDir);
      55. String path = tempFile.getAbsolutePath();
      56. fileName = path +File.separator+ String.valueOf(name1) + ".mp4";
      57. ajaxResult.put("fileUrl", domainName + String.valueOf(name1) + ".mp4");
      58. ajaxResult.put("filePath",fileName);
      59. System.out.println("--文件名-->>" + fileName);
      60. // 设置输出编码器、音频采样率、帧率、时间戳、视频比特率、视频编码器
      61. // 创建临时文件流记录器,将输出流作为参数传入
      62. recorder = new FFmpegFrameRecorder(fileName, imageWidth, imageHeight, frameGrabber1.getAudioChannels());
      63. recorder.setFormat("mp4");
      64. recorder.setSampleRate(frameGrabber1.getSampleRate());
      65. recorder.setVideoBitrate(frameGrabber1.getVideoBitrate());
      66. recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
      67. recorder.setFrameRate(24);
      68. recorder.setTimestamp(frameGrabber2.getTimestamp());
      69. // 启动录制器和另一个视频的抓取器
      70. frameGrabber2.setVideoCodec(avcodec.AV_CODEC_ID_H264);
      71. frameGrabber2.setPixelFormat(avutil.AV_PIX_FMT_RGB24);
      72. frameGrabber2.setVideoBitrate(frameGrabber1.getVideoCodec());
      73. frameGrabber2.setFrameRate(frameGrabber1.getVideoCodec());
      74. recorder.start();
      75. int index = 0;
      76. // 获取视频的总帧数
      77. int totalFrameCount = frameGrabber2.getLengthInFrames();
      78. System.out.println("视频总帧数:" + totalFrameCount);
      79. int totalFrameCount1 = frameGrabber1.getLengthInFrames();
      80. System.out.println("视频总帧数:" + totalFrameCount1);
      81. int xum =700;
      82. while (index < 500) {
      83. // 抓取当前视频的一帧
      84. frame = frameGrabber1.grabFrame();
      85. if (frame == null) {
      86. break;
      87. }
      88. // 如果当前帧是图像,则进行叠加
      89. if (frame.image != null) {
      90. // 将JavaCV帧转换为OpenCV的Mat对象,方便后续处理颜色通道
      91. Mat mat = converter.convertToMat(frame);
      92. // 进行图像边界处理,例如裁剪掉边界黑线条
      93. // 将JavaCV帧转换为BufferedImage,并创建Graphics2D对象
      94. BufferedImage buffImg = Java2DFrameUtils.toBufferedImage(frame);
      95. Graphics2D graphics = buffImg.createGraphics();
      96. // 抓取另一个视频的一帧
      97. mergeFrame1 = frameGrabber2.grabFrame();
      98. if(mergeFrame1!=null){
      99. Mat mat1 = converter.convertToMat(mergeFrame1);
      100. int borderSize = 1;
      101. mat1 = mat1.apply(new Rect(borderSize, borderSize, mat1.cols() - 2 * borderSize, mat1.rows() - 2 * borderSize));
      102. // 将处理后的 Mat 对象转换回帧对象
      103. mergeFrame = converter.convert(mat1);
      104. }
      105. frameGrabber2.setImageMode(FrameGrabber.ImageMode.COLOR);
      106. if (mergeFrame != null) {
      107. // 如果当前帧是空帧,则一直循环直到抓取到带图像的帧
      108. while (mergeFrame.image == null) {
      109. mergeFrame = frameGrabber2.grabFrame();
      110. frameGrabber2.setImageMode(FrameGrabber.ImageMode.COLOR);
      111. }
      112. // 进行颜色空间转换(例如,将图像从BGR转换为RGB)
      113. // cvtColor(mat, mat, COLOR_BGR2RGB);
      114. // 判断颜色空间是否需要转换
      115. // if (mat.channels() > 1) {
      116. // cvtColor(mat, mat, COLOR_BGR2RGB);
      117. // }
      118. // 将另一个视频的帧应用颜色过滤器,并将结果转换为BufferedImage
      119. filter.push(mergeFrame);
      120. Frame filteredFrame = filter.pullImage();
      121. BufferedImage mergeBuffer = Java2DFrameUtils.toBufferedImage(filteredFrame);
      122. // 进行颜色空间转换(例如,将图像从BGR转换为RGB
      123. // cvtColor(converter.convertToMat(filteredFrame), converter.convertToMat(filteredFrame), COLOR_BGR2RGB);
      124. // 进行直方图均衡化或颜色映射等处理(根据具体需求进行选择和调整)
      125. // 将另一个视频的帧叠加到当前帧上
      126. graphics.drawImage(mergeBuffer, 0, 0, outputWidth, outputHeight, null);
      127. // graphics.drawImage(mergeBuffer, 0, 0, frameGrabber1.getImageWidth(), frameGrabber1.getImageHeight(), null);
      128. }else {
      129. break;
      130. }
      131. // 将叠加后的JavaCV帧写入输出文件
      132. Frame newFrame = Java2DFrameUtils.toFrame(buffImg);
      133. recorder.record(newFrame);
      134. }
      135. // 如果当前帧包含音频,则将其写入输出文件
      136. if (frame.samples != null) {
      137. recorder.recordSamples(frame.sampleRate, frame.audioChannels, frame.samples);
      138. }
      139. if(mergeFrame1 != null){
      140. if (mergeFrame1.samples != null) {
      141. recorder.recordSamples(mergeFrame1.sampleRate, mergeFrame1.audioChannels, mergeFrame1.samples);
      142. }
      143. }
      144. System.out.println("帧值=" + index);
      145. index++;
      146. }
      147. // 停止并释放资源
      148. recorder.stop();
      149. recorder.release();
      150. filter.stop();
      151. colorConvertFilter.stop();
      152. frameGrabber2.stop();
      153. frameGrabber1.stop();
      154. //在业务侧写代码时记得处理掉这个临时文件
      155. // if (file!=null){
      156. // file.deleteOnExit();
      157. // }
      158. } catch (Exception e) {
      159. e.printStackTrace();
      160. }
      1. <dependency>
      2. <groupId>org.bytedeco</groupId>
      3. <artifactId>javacv</artifactId>
      4. <version>1.5.2</version>
      5. </dependency>
      6. <dependency>
      7. <groupId>org.bytedeco</groupId>
      8. <artifactId>javacpp</artifactId>
      9. <version>1.5.2</version>
      10. </dependency>
      11. <dependency>
      12. <groupId>org.bytedeco</groupId>
      13. <artifactId>opencv</artifactId>
      14. <version>4.1.2-1.5.2</version>
      15. <classifier>windows-x86_64</classifier>
      16. </dependency>
      17. <dependency>
      18. <groupId>org.bytedeco</groupId>
      19. <artifactId>openblas</artifactId>
      20. <version>0.3.7-1.5.2</version>
      21. <classifier>windows-x86_64</classifier>
      22. </dependency>
      23. <dependency>
      24. <groupId>org.bytedeco</groupId>
      25. <artifactId>ffmpeg</artifactId>
      26. <version>4.2.1-1.5.2</version>
      27. <classifier>windows-x86_64</classifier>
      28. </dependency>
      29. <dependency>
      30. <groupId>org.bytedeco</groupId>
      31. <artifactId>opencv</artifactId>
      32. <version>4.1.2-1.5.2</version>
      33. <classifier>linux-x86_64</classifier>
      34. </dependency>
      35. <dependency>
      36. <groupId>org.bytedeco</groupId>
      37. <artifactId>openblas</artifactId>
      38. <version>0.3.7-1.5.2</version>
      39. <classifier>linux-x86_64</classifier>
      40. </dependency>
      41. <dependency>
      42. <groupId>org.bytedeco</groupId>
      43. <artifactId>ffmpeg</artifactId>
      44. <version>4.2.1-1.5.2</version>
      45. <classifier>linux-x86_64</classifier>
      46. </dependency>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/705218
推荐阅读
相关标签
  

闽ICP备14008679号