JAVA 操作视频转分辨率、编码格式、视频类型

您所在的位置:网站首页 1080p怎么转换成4k JAVA 操作视频转分辨率、编码格式、视频类型

JAVA 操作视频转分辨率、编码格式、视频类型

2024-06-30 22:07| 来源: 网络整理| 查看: 265

客户提了一个新需求,上传视频之后要根据设定的宽和高转换视频分辨率,尝试了很多办法,踩了好几个坑,有的方法转换完成之后,浏览器播放有声音但是没图像,有的方法转换某个视频的时候会报错(应该是视频文件的原因,但是没找到具体原因)。最终找到一个目前来说比较靠谱的方法,记录一下。

通过ffmpeg操作视频,进行视频的转码等操作,不需要单独安装ffmpeg工具。

开发工具:idea

环境:jdk1.8

主要maven依赖:

org.jboss.logging jboss-logging 3.4.1.Final cn.hutool hutool-all 5.7.16 com.google.guava guava 31.1-jre org.bytedeco javacv-platform 1.5.7

主要作用是,可以根据输入的源文件,生成想要的视频文件,修改视频的分辨率,编码格式,视频格式。

直接上代码:

import cn.hutool.core.util.IdUtil; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.bytedeco.ffmpeg.avcodec.AVCodecParameters; import org.bytedeco.ffmpeg.avformat.AVFormatContext; import org.bytedeco.ffmpeg.avformat.AVStream; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.javacv.*; import java.io.File; import java.util.Arrays; import java.util.List; /** * @author hy * @date 2022-06-13 上午 10:38 */ @Slf4j public class VideoUtils { /** * 视频转分辨率转视频编码 * * @param inputFile 源文件 * @param outputPath 输出目录 * @param width 需要转成的视频的宽度 * @param height 需要转成的视频的高度 * @param videoFormat 需要转换成的视频格式 * @return 返回新文件名称,可以根据实际使用修改 */ public static String videoConvert(String inputFile, String outputPath, Integer width, Integer height, String videoFormat) { List paths = Splitter.on(".").splitToList(inputFile); String ext = paths.get(paths.size() - 1); if (StringUtils.isEmpty(videoFormat)) { videoFormat = ext; } String newFileName = IdUtil.simpleUUID() + "." + videoFormat; String resultPath = Joiner.on(File.separator).join(Arrays.asList(outputPath, newFileName)); FFmpegLogCallback.set(); Frame frame; FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile); FFmpegFrameRecorder recorder = null; try { // 初始化帧抓取器,例如数据结构(时间戳、编码器上下文、帧对象等), // 如果入参等于true,还会调用avformat_find_stream_info方法获取流的信息,放入AVFormatContext类型的成员变量oc中 grabber.start(true); // grabber.start方法中,初始化的解码器信息存在放在grabber的成员变量oc中 AVFormatContext avformatcontext = grabber.getFormatContext(); // 文件内有几个媒体流(一般是视频流+音频流) int streamNum = avformatcontext.nb_streams(); // 没有媒体流就不用继续了 if (streamNum < 1) { log.info("视频文件格式不对"); return "error"; } // 取得视频的帧率 int framerate = (int) grabber.getVideoFrameRate(); log.info("视频帧率:{},视频时长:{}秒,媒体流数量:{}", framerate, avformatcontext.duration() / 1000000, streamNum); // 遍历每一个流,检查其类型 for (int i = 0; i < streamNum; i++) { AVStream avstream = avformatcontext.streams(i); AVCodecParameters avcodecparameters = avstream.codecpar(); log.info("流的索引:{},编码器类型:{},编码器ID:{}", i, avcodecparameters.codec_type(), avcodecparameters.codec_id()); } // 源视频宽度 int frameWidth = grabber.getImageWidth(); // 源视频高度 int frameHeight = grabber.getImageHeight(); // 源音频通道数量 int audioChannels = grabber.getAudioChannels(); log.info("源视频宽度:{},源视频高度:{},音频通道数:{}", frameWidth, frameHeight, audioChannels); recorder = new FFmpegFrameRecorder(resultPath, width, height, audioChannels); // 设置H264编码 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 设置视频格式 recorder.setFormat(videoFormat); // 使用原始视频的码率,若需要则自行修改码率 recorder.setVideoBitrate(grabber.getVideoBitrate()); // 一秒内的帧数,帧率 recorder.setFrameRate(framerate); // 两个关键帧之间的帧数 recorder.setGopSize(framerate); // 设置音频通道数,与视频源的通道数相等 recorder.setAudioChannels(grabber.getAudioChannels()); recorder.start(); int videoFrameNum = 0; int audioFrameNum = 0; int dataFrameNum = 0; // 持续从视频源取帧 while (null != (frame = grabber.grab())) { // 有图像,就把视频帧加一 if (null != frame.image) { videoFrameNum++; // 取出的每一帧,都保存到视频 recorder.record(frame); } // 有声音,就把音频帧加一 if (null != frame.samples) { audioFrameNum++; // 取出的每一帧,都保存到视频 recorder.record(frame); } // 有数据,就把数据帧加一 if (null != frame.data) { dataFrameNum++; } } log.info("转码完成,视频帧:{},音频帧:{},数据帧:{}", videoFrameNum, audioFrameNum, dataFrameNum); } catch (Exception e) { log.error(e.getMessage()); return "error"; } finally { if (recorder != null) { try { recorder.close(); } catch (Exception e) { log.info("recorder.close异常" + e); } } try { grabber.close(); } catch (FrameGrabber.Exception e) { log.info("frameGrabber.close异常" + e); } } return newFileName; } public static void main(String[] args) { videoConvert("D:\\tmbls\\a.mp4", "D:\\tmbls", 256, 64, ""); } }

视频的源分辨率是:640*252

 转化完之后是 256*64

通过videoFormat 参数可以修改想要转换成avi、mp4、或者其他的视频格式

public static void main(String[] args) { videoConvert("D:\\tmbls\\a.mp4", "D:\\tmbls", 256, 64, "avi"); }

转换完成,就可以看到在设定的目录之下生成了一个avi文件。

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3