「小程式JAVA實戰」小程式視訊處理工具ffmpeg(46)
前面已經把視訊成功的上傳到我們的伺服器,選擇了背景音樂的ID,現在需要把視訊和背景音樂進行合併,需要使用一個工具ffmpeg。原始碼:https://github.com/limingios/wxProgram.git 中wx-springboot 和 No.15
ffmpeg
-
介紹
>視音訊處理工具,跨平臺的視音訊處理解決方案,主頁:http://ffmpeg.org
- 應用的場景
- 播放器:射手播放器,暴風影音,迅雷播放器……
- 轉換工具:格式工廠,剪輯工具……
- 直播,視訊加碼,濾鏡,水印,特效……
-
下載
根據你的需求進行下載,我選擇在windows平臺來進行下載
- 測試
C:\Users\Administrator>D: D:\>cd D:\Program Files\ffmpeg D:\Program Files\ffmpeg>cd bin D:\Program Files\ffmpeg\bin>ffmpeg.exe -i shanzhu.mp4 shanzhu.avi ffmpeg version N-91949-g6304268e39 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 8.2.1 (GCC) 20180813 configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth libavutil56. 19.101 / 56. 19.101 libavcodec58. 30.100 / 58. 30.100 libavformat58. 18.100 / 58. 18.100 libavdevice58.4.103 / 58.4.103 libavfilter7. 31.100 /7. 31.100 libswscale5.2.100 /5.2.100 libswresample3.2.100 /3.2.100 libpostproc55.2.100 / 55.2.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'shanzhu.mp4': Metadata: major_brand: mp42 minor_version: 1 compatible_brands: mp41mp42isom creation_time: 2018-09-16T05:29:47.000000Z Duration: 00:00:09.34, start: 0.000000, bitrate: 1210 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 544x960, 1159 kb/s, 29.97 fps, 29.97 tbr, 600 tbn, 1200 tbc (default) Metadata: creation_time: 2018-09-16T05:29:47.000000Z handler_name: Core Media Video Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 46 kb/s (default) Metadata: creation_time: 2018-09-16T05:29:47.000000Z handler_name: Core Media Audio Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> mpeg4 (native)) Stream #0:1 -> #0:1 (aac (native) -> mp3 (libmp3lame)) Press [q] to stop, [?] for help Output #0, avi, to 'shanzhu.avi': Metadata: major_brand: mp42 minor_version: 1 compatible_brands: mp41mp42isom ISFT: Lavf58.18.100 Stream #0:0(und): Video: mpeg4 (FMP4 / 0x34504D46), yuv420p, 544x960, q=2-31, 200 kb/s, 29.97 fps, 29.97 tbn, 29.97 tbc (default) Metadata: creation_time: 2018-09-16T05:29:47.000000Z handler_name: Core Media Video encoder: Lavc58.30.100 mpeg4 Side data: cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1 Stream #0:1(und): Audio: mp3 (libmp3lame) (U[0][0][0] / 0x0055), 44100 Hz, mono, fltp (default) Metadata: creation_time: 2018-09-16T05:29:47.000000Z handler_name: Core Media Audio encoder: Lavc58.30.100 libmp3lame frame=280 fps=0.0 q=31.0 Lsize=1096kB time=00:00:09.34 bitrate= 961.3kbits/s speed=16.7x video:999kB audio:72kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.338377%
- java程式呼叫cmd轉換視訊
springboot-common中新增FFMpegTest
package com.idig8.utils; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class FFMpegTest { private String ffmpegEXE; public FFMpegTest(String ffmpegEXE) { super(); this.ffmpegEXE = ffmpegEXE; } public void convertor(String videoInputPath, String videoOutputPath) throws Exception { //ffmpeg -i input.mp4 -y output.avi List<String> command = new ArrayList<>(); command.add(ffmpegEXE); command.add("-i"); command.add(videoInputPath); command.add("-y"); command.add(videoOutputPath); for (String c : command) { System.out.print(c + " "); } ProcessBuilder builder = new ProcessBuilder(command); Process process = builder.start(); InputStream errorStream = process.getErrorStream(); InputStreamReader inputStreamReader = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(inputStreamReader); String line = ""; while ( (line = br.readLine()) != null ) { } if (br != null) { br.close(); } if (inputStreamReader != null) { inputStreamReader.close(); } if (errorStream != null) { errorStream.close(); } } public static void main(String[] args) { FFMpegTest ffmpeg = new FFMpegTest("D:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe"); try { ffmpeg.convertor("D:\\Program Files\\ffmpeg\\bin\\shanzhu.mp4", "D:\\Program Files\\ffmpeg\\bin\\shanzhu.avi"); } catch (Exception e) { e.printStackTrace(); } } }
-
視訊音訊合併命令
> 通過這種方式,可以讓我們的mp4和我們的mp3 做一個結合。
ffmpeg.exe -i shanzhu.avi -i music.mp3 -t 10 -y 合併音樂和視訊.avi
D:\Program Files\ffmpeg\bin>ffmpeg.exe -i shanzhu.avi -i music.mp3 -t 10 -y 合併音樂和視訊.avi ffmpeg version N-91949-g6304268e39 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 8.2.1 (GCC) 20180813 configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth libavutil56. 19.101 / 56. 19.101 libavcodec58. 30.100 / 58. 30.100 libavformat58. 18.100 / 58. 18.100 libavdevice58.4.103 / 58.4.103 libavfilter7. 31.100 /7. 31.100 libswscale5.2.100 /5.2.100 libswresample3.2.100 /3.2.100 libpostproc55.2.100 / 55.2.100 Input #0, avi, from 'shanzhu.avi': Metadata: encoder: Lavf58.18.100 Duration: 00:00:09.38, start: 0.000000, bitrate: 957 kb/s Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 544x960 [SAR 1:1 DAR 17:30], 876 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 30k tbc Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, mono, fltp, 64 kb/s [mp3 @ 000001fcfa57d6c0] Estimating duration from bitrate, this may be inaccurate Input #1, mp3, from 'music.mp3': Duration: 00:00:33.47, start: 0.000000, bitrate: 320 kb/s Stream #1:0: Audio: mp3, 48000 Hz, stereo, fltp, 320 kb/s Stream mapping: Stream #0:0 -> #0:0 (mpeg4 (native) -> mpeg4 (native)) Stream #1:0 -> #0:1 (mp3 (mp3float) -> mp3 (libmp3lame)) Press [q] to stop, [?] for help Output #0, avi, to '鍚堝苟闊充箰鍜岃棰?avi': Metadata: ISFT: Lavf58.18.100 Stream #0:0: Video: mpeg4 (FMP4 / 0x34504D46), yuv420p(progressive), 544x960 [SAR 1:1 DAR 17:30], q=2-31, 200 kb/s, 29.97 fps, 29.97 tbn, 29.97 tbc Metadata: encoder: Lavc58.30.100 mpeg4 Side data: cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1 Stream #0:1: Audio: mp3 (libmp3lame) (U[0][0][0] / 0x0055), 48000 Hz, stereo, fltp Metadata: encoder: Lavc58.30.100 libmp3lame frame=280 fps=274 q=31.0 Lsize=1076kB time=00:00:10.00 bitrate= 880.4kbits/s speed=9.79x video:892kB audio:157kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.510280%
- java程式呼叫cmd轉換視訊增加音訊
package com.idig8.utils; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class MergeVideoMp3 { private String ffmpegEXE; public MergeVideoMp3(String ffmpegEXE) { super(); this.ffmpegEXE = ffmpegEXE; } public void convertor(String videoInputPath, String mp3InputPath, double seconds, String videoOutputPath) throws Exception { //ffmpeg.exe -i 蘇州大褲衩.mp4 -i bgm.mp3 -t 7 -y 新的視訊.mp4 List<String> command = new ArrayList<>(); command.add(ffmpegEXE); command.add("-i"); command.add(videoInputPath); command.add("-i"); command.add(mp3InputPath); command.add("-t"); command.add(String.valueOf(seconds)); command.add("-y"); command.add(videoOutputPath); //for (String c : command) { //System.out.print(c + " "); //} ProcessBuilder builder = new ProcessBuilder(command); Process process = builder.start(); InputStream errorStream = process.getErrorStream(); InputStreamReader inputStreamReader = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(inputStreamReader); String line = ""; while ( (line = br.readLine()) != null ) { } if (br != null) { br.close(); } if (inputStreamReader != null) { inputStreamReader.close(); } if (errorStream != null) { errorStream.close(); } } public static void main(String[] args) { MergeVideoMp3 ffmpeg = new MergeVideoMp3("D:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe"); try { ffmpeg.convertor("D:\\Program Files\\ffmpeg\\bin\\shanzhu.mp4", "D:\\Program Files\\ffmpeg\\bin\\music.mp3", 7.1, "D:\\Program Files\\ffmpeg\\bin\\合併音樂和視訊.avi"); } catch (Exception e) { e.printStackTrace(); } } }
開發功能
視訊上傳後通過java呼叫ffmpge.exe完成音樂和視訊的合併,並將視訊資訊儲存在資料庫中。
-
視訊service開發
VideoService
package com.idig8.service; import com.idig8.pojo.Videos; public interface VideoService { /** * 儲存視訊資訊 * @param Id * @return */ public void saveVideo(Videos video); }
VideoServiceImpl
package com.idig8.service.Impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.idig8.mapper.BgmMapper; import com.idig8.pojo.Bgm; import com.idig8.service.BgmService; @Service public class BgmServiceImpl implements BgmService { @Autowired private BgmMapper bgmMapper; @Transactional(propagation =Propagation.SUPPORTS) @Override public List<Bgm> queryBgmList(){ return bgmMapper.selectAll(); } @Transactional(propagation =Propagation.SUPPORTS) @Override public Bgm queryBgmById(String Id){ return bgmMapper.selectByPrimaryKey(Id); } }
BgmService
package com.idig8.service; import java.util.List; import com.idig8.pojo.Bgm; public interface BgmService { /** * 獲取所有的Bgm列表 * @return */ public List<Bgm> queryBgmList(); /** * 通過bgmId獲取Bgm物件 * @param Id * @return */ public Bgm queryBgmById(String Id); }
BgmServiceImpl
package com.idig8.service.Impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.idig8.mapper.BgmMapper; import com.idig8.pojo.Bgm; import com.idig8.service.BgmService; @Service public class BgmServiceImpl implements BgmService { @Autowired private BgmMapper bgmMapper; @Transactional(propagation =Propagation.SUPPORTS) @Override public List<Bgm> queryBgmList(){ return bgmMapper.selectAll(); } @Transactional(propagation =Propagation.SUPPORTS) @Override public Bgm queryBgmById(String Id){ return bgmMapper.selectByPrimaryKey(Id); } }
VideoController
package com.idig8.controller; import java.io.File; import java.util.Date; import java.util.UUID; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.idig8.pojo.Bgm; import com.idig8.pojo.Videos; import com.idig8.service.BgmService; import com.idig8.service.VideoService; import com.idig8.utils.JSONResult; import com.idig8.utils.MergeVideoMp3; import com.idig8.utils.enums.VideoStatusEnum; import com.idig8.utils.file.FileUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @RestController @Api(value="視訊相關業務的介面", tags= {"視訊相關業務的controller"}) @RequestMapping("/video") public class VideoController extends BasicController { @Autowired private BgmService bgmService; @Autowired private VideoService videosService; @Value("${server.file.path}") private String fileSpace; @Value("${server.ffmpeg.path}") private String ffmpegexe; @ApiOperation(value="上傳視訊", notes="上傳視訊的介面") @ApiImplicitParams({ @ApiImplicitParam(name="userId", value="使用者id", required=true, dataType="String", paramType="form"), @ApiImplicitParam(name="bgmId", value="背景音樂id", required=false, dataType="String", paramType="form"), @ApiImplicitParam(name="videoSeconds", value="背景音樂播放長度", required=true, dataType="String", paramType="form"), @ApiImplicitParam(name="videoWidth", value="視訊寬度", required=true, dataType="String", paramType="form"), @ApiImplicitParam(name="videoHeight", value="視訊高度", required=true, dataType="String", paramType="form"), @ApiImplicitParam(name="desc", value="視訊描述", required=false, dataType="String", paramType="form") }) @PostMapping(value="/upload", headers="content-type=multipart/form-data") public JSONResult upload(String userId, String bgmId, double videoSeconds, int videoWidth, int videoHeight, String desc, @ApiParam(value="短視訊", required=true) MultipartFile file) throws Exception { if (StringUtils.isBlank(userId)) { return JSONResult.errorMsg("使用者id不能為空..."); } // 檔案儲存的名稱空間 String fileName = file.getOriginalFilename(); // 儲存到資料庫中的相對路徑 String path = ""; String videOutPath = ""; try { path = FileUtil.uploadFile(file.getBytes(), fileSpace, fileName); } catch (Exception e) { e.getStackTrace(); return JSONResult.errorMsg(e.getMessage()); } if(StringUtils.isNotBlank(bgmId)){ Bgm bgm = bgmService.queryBgmById(bgmId); String mp3BgmPath = fileSpace + bgm.getPath(); MergeVideoMp3 mergeVideoMp3 = new MergeVideoMp3(ffmpegexe); String videOutPathName = UUID.randomUUID().toString()+".mp4"; File targetFile = new File(fileSpace + userId); if (!targetFile.exists()) { targetFile.mkdirs(); } videOutPath = "/"+userId+"/"+videOutPathName; String videoInput = fileSpace +path; mergeVideoMp3.convertor(videoInput, mp3BgmPath, videoSeconds, fileSpace +videOutPath); } Videos videos = new Videos(); videos.setAudioId(bgmId); videos.setCreateTime(new Date()); videos.setVideoDesc(desc); videos.setId(UUID.randomUUID().toString()); videos.setUserId(userId); videos.setVideoHeight(videoHeight); videos.setVideoWidth(videoWidth); videos.setVideoPath(videOutPath); videos.setStatus(VideoStatusEnum.SUCCESS.value); videosService.saveVideo(videos); return JSONResult.ok(path); } }
PS:已經完成了視訊的上傳,並把相關的資訊儲存在資料庫中。
百度未收錄
>>原創文章,歡迎轉載。轉載請註明:轉載自IT人故事會,謝謝!
>>原文連結地址: