com.day.cq.dam.handler.ffmpeg.FFMpegWrapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
package com.day.cq.dam.handler.ffmpeg;
import static com.day.cq.dam.video.VideoConstants.*;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import javax.imageio.ImageIO;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.IOUtils;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.dam.video.VideoProfile;
public class FFMpegWrapper {
/**
* flag indicating the installation status of ffmpeg. null
=
* not tested, true
= installed, false
= not
* installed
*/
private Boolean installed = null;
private static final Logger log = LoggerFactory.getLogger(FFMpegWrapper.class);
private static final LoggerOutputStream LOG_STREAM;
private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("H:mm:ss.S");
private static final String FFMPEG_CMD = "ffmpeg";
private File input;
private Dimension outputsize;
private DefaultExecutor infoExecutor = new DefaultExecutor();
private DefaultExecutor transcodeExecutor = new DefaultExecutor();
private DefaultExecutor testExecutor = new DefaultExecutor();
private long duration = -1;
private boolean letterbox = false;
private Dimension inputsize;
private int bitrate = 0;
private String fps = null;
private int bitrateTolerance = 0;
private String videoCodec = null;
private String audioCodec = null;
private int audioChannels = 0;
private int audioSamplingRate = 0;
private int audioBitrate = 0;
private boolean twoPass = false;
private String[] customFlags = null;
private long startTime = 0;
private long clipDuration = 0;
private Rectangle crop;
private String preset = null;
private boolean fitInside;
private String extension;
private String outputMimetype;
private String profileName;
private String renditionSelector;
private StringBuilder ffmpegOutput = new StringBuilder();
public String getOutputExtension() {
return extension;
}
public void setOutputExtension(String extension) {
this.extension = extension;
}
public StringBuilder getFFMpegOutput() {
return ffmpegOutput;
}
public String getProfileName() {
return profileName;
}
public void setProfileName(String profileName) {
this.profileName = profileName;
}
public String getRenditionSelector() {
return renditionSelector;
}
public void setRenditionSelector(String renditionSelector) {
this.renditionSelector = renditionSelector;
}
public String getOutputMimetype() {
return outputMimetype;
}
public void setOutputMimetype(String outputMimetype) {
this.outputMimetype = outputMimetype;
}
private ExecutableLocator locator = new ExecutableLocator() {
public String getPath(String cmd) {
return FFMPEG_CMD;
}
};
static {
TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
LOG_STREAM = new LoggerOutputStream(log);
}
public void setTwoPass() {
this.twoPass = true;
}
public void setTwoPass(boolean twoPass) {
this.twoPass = twoPass;
}
public void setPreset(String preset) {
this.preset = preset;
}
public void setAudioSamplingRate(int audioSamplingRate) {
this.audioSamplingRate = audioSamplingRate;
}
public void setAudioBitrate(int audioBitrate) {
this.audioBitrate = audioBitrate;
}
public void setVideoCodec(String videoCodec) {
this.videoCodec = videoCodec;
}
public void setAudioCodec(String audioCodec) {
this.audioCodec = audioCodec;
}
/**
* Sets the output video bitrate in kbits/second
*
* @param bitrate
* The bitrate
*/
public void setBitrate(int bitrate) {
this.bitrate = bitrate;
}
/**
* Creates a wrapper to run ffmpeg for the given video file. Will run ffmpeg
* in the current working directory of JVM.
*
* @param file
* video file to call ffmpeg with
*/
public FFMpegWrapper(File file) {
this(file, null);
}
/**
* Creates a wrapper to run ffmpeg for the given video file. Provide a
* different workingDir every time you create this FFMpegWrapper
as
* ffmpeg's temp file name in 2-pass encoding is hard coded in the ffmpeg
* build, which causes problem while running simultaneous multiple
* encodings. Even you use -passlogfile option, x264_2pass.log file name is
* hard coded in the older ffmpeg builds. For more details please refer to
* bug:42346.
*
* @param file video file to call ffmpeg with
* @param workingDir a working directory for ffmpeg; if null
,
* the current working directory of the JVM is used
*/
public FFMpegWrapper(File file, File workingDir) {
this.setInput(file);
final InfoParser infoParser = new InfoParser(this);
this.infoExecutor.setStreamHandler(new PumpStreamHandler(infoParser, infoParser));
this.infoExecutor.setExitValue(1);
LOG_STREAM.setWrapper(this);
this.transcodeExecutor.setStreamHandler(new PumpStreamHandler(LOG_STREAM, LOG_STREAM));
if (workingDir != null) {
this.infoExecutor.setWorkingDirectory(workingDir);
this.transcodeExecutor.setWorkingDirectory(workingDir);
this.testExecutor.setWorkingDirectory(workingDir);
}
}
public void setInput(File f) {
this.input = f;
}
public void setExecutableLocator(ExecutableLocator locator) {
this.locator = locator;
}
public void setOutputSize(Dimension dimension) {
this.outputsize = dimension;
// outputsize must be a multiple of two
if (this.outputsize != null) {
this.outputsize.setSize(this.outputsize.width % 2 + this.outputsize.width, this.outputsize.height % 2
+ this.outputsize.height);
}
}
public Dimension getOutputSize() {
return outputsize;
}
public long getInputDuration() {
if (this.duration > -1) {
return this.duration;
}
try {
info();
} catch (IOException e) {
return -1;
}
return this.duration;
}
public Dimension getInputSize() {
if (this.inputsize != null) {
return this.inputsize;
}
try {
info();
} catch (IOException e) {
log.warn("getInputSize: I/O error: ", e);
return null;
}
return this.inputsize;
}
private String getFfmpegPath() {
String path = locator.getPath(FFMPEG_CMD);
if (path == null) {
log.info("Could not find ffmpeg's location, trying direct call to '{}'", FFMPEG_CMD);
path = FFMPEG_CMD;
}
return path;
}
private CommandLine ffmpeg() {
if (!isFfmpegInstalled()) {
throw new FfmpegNotFoundException("Could not find ffmpeg's executable");
}
String path = getFfmpegPath();
CommandLine cmd = new CommandLine(path);
return cmd;
}
private void info() throws IOException {
CommandLine cli = ffmpeg();
cli.addArgument("-i");
cli.addArgument(input.getPath());
log.info("**** Exec (info): [{}]", cli);
this.infoExecutor.execute(cli);
}
/**
* Create thumbnails from the video.
*
* @param thumbnails
* The number of desired thumbnails.
* @param start
* The start position in seconds from where to take the first
* thumbnail.
* @return The thumbnails.
*/
public BufferedImage[] getThumbnails(final int thumbnails, final int start) {
try {
final double fraction = (getInputDuration() / 1000) / thumbnails;
final long specifier = System.currentTimeMillis();
int i = 0;
while (i < thumbnails) {
final double pos = i * fraction;
final CommandLine cli = ffmpeg();
if (start > 0) {
cli.addArgument("-itsoffset");
cli.addArgument("-" + String.valueOf(start));
}
cli.addArgument("-ss");
cli.addArgument(String.valueOf(pos));
cli.addArgument("-i");
cli.addArgument(input.getPath());
cli.addArgument("-vframes");
cli.addArgument("1");
cli.addArgument("-y");
cli.addArgument(input.getParent() + File.separator + "tempthumb." + specifier + "." + i + ".jpg");
log.debug("grabbing frame [{}] at pos [{}] for [" + input.getPath() + "]...", (i + 1), pos);
log.info("**** Exec (thumbs): [{}]", cli);
this.transcodeExecutor.execute(cli);
i++;
}
File[] thumbFiles = input.getParentFile().listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.matches("tempthumb\\." + specifier + "\\.(\\d)+\\.jpg");
}
});
log.info("created {} thumbnails", thumbFiles.length);
BufferedImage[] images = new BufferedImage[thumbFiles.length];
for (int j = 0; j < thumbFiles.length; j++) {
FileInputStream fis = null;
try {
fis = new FileInputStream(thumbFiles[j]);
images[j] = ImageIO.read(fis);
} catch (Exception e) {
log.warn("error reading image [{}]", thumbFiles[j]);
images[j] = null;
} finally {
IOUtils.closeQuietly(fis);
}
thumbFiles[j].delete();
}
return images;
} catch (IOException e) {
return null;
}
}
/**
* Create clip from the video.
*
* @param startTime
* startTime of the clip.
* @param endTime
* The end position in seconds of the clip.
* @param mimeType
* Mime type for the clip.
* @return The thumbnails.
*/
public File getClip(final double startTime, final double endTime, String mimeType) {
try {
final double duration = endTime - startTime;
final String extension = mimeType.substring(mimeType.indexOf("/") + 1);
final CommandLine cli = ffmpeg();
cli.addArgument("-ss");
cli.addArgument( String.valueOf(startTime));
cli.addArgument("-t");
cli.addArgument(String.valueOf(duration));
cli.addArgument("-i");
cli.addArgument(input.getPath());
cli.addArgument("-strict");
cli.addArgument("experimental");
cli.addArgument(input.getParent() + File.separator + "clipped." + extension);
//log.debug("grabbing frame [{}] at pos [{}] for [" + input.getPath() + "]...", (i + 1), pos);
//log.info("**** Exec (thumbs): [{}]", cli);
this.transcodeExecutor.execute(cli);
File[] clippedFiles= input.getParentFile().listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("clipped");
}
});
return clippedFiles[0];
} catch (IOException e) {
return null;
}
}
public File join(File other, String name) throws IOException {
CommandLine intermediate1cli = ffmpeg();
CommandLine intermediate2cli = ffmpeg();
CommandLine joincli = ffmpeg();
File intermediate1file = new File(input.getParentFile(), "intermediate."
+ input.getName().replaceAll("\\.\\w+", "") + ".mpg");
File intermediate2file = new File(other.getParentFile(), "intermediate."
+ other.getName().replaceAll("\\.\\w+", "") + ".mpg");
File joinfile = new File(input.getParentFile(), name + ".intermediate."
+ input.getName().replaceAll("\\.\\w+", "") + ".mpg");
File outputfile = new File(input.getParentFile(), name + "." + input.getName());
intermediate1cli.addArgument("-i");
intermediate1cli.addArgument(input.getPath());
intermediate1cli.addArgument("-y");
intermediate1cli.addArgument("-sameq");
intermediate1cli.addArgument("-r");
intermediate1cli.addArgument("24");
intermediate1cli.addArgument(intermediate1file.getPath());
// transcode the first file into intermediate format
log.info("**** Exec (intermediate join 1): [{}]", joincli);
this.transcodeExecutor.execute(intermediate1cli);
intermediate2cli.addArgument("-i");
intermediate2cli.addArgument(other.getPath());
intermediate2cli.addArgument("-y");
intermediate2cli.addArgument("-sameq");
intermediate2cli.addArgument("-r");
intermediate2cli.addArgument("24");
intermediate2cli.addArgument(intermediate2file.getPath());
// transcode the second file into intermediate format
log.info("**** Exec (intermediate join 2): [{}]", joincli);
this.transcodeExecutor.execute(intermediate2cli);
FileOutputStream join = null;
FileInputStream isOne = null;
FileInputStream isTwo = null;
try {
join = new FileOutputStream(joinfile);
isOne = new FileInputStream(intermediate1file);
IOUtils.copy(isOne, join);
join.flush();
isTwo = new FileInputStream(intermediate2file);
IOUtils.copy(isTwo, join);
} finally {
IOUtils.closeQuietly(join);
IOUtils.closeQuietly(isOne);
IOUtils.closeQuietly(isTwo);
}
joincli.addArgument("-i");
joincli.addArgument(joinfile.getPath());
joincli.addArgument("-y");
joincli.addArgument("-sameq");
joincli.addArgument("-s");
Dimension size = this.getInputSize();
joincli.addArgument(size.width + "x" + size.height);
joincli.addArgument(outputfile.getPath());
log.info("**** Exec (join): [{}]", joincli);
this.transcodeExecutor.execute(joincli);
intermediate1file.delete();
intermediate2file.delete();
joinfile.delete();
return outputfile;
}
public File trim(String name) throws IOException {
CommandLine cli = ffmpeg();
cli.addArgument("-i");
cli.addArgument(input.getPath());
cli.addArgument("-y");
if (this.startTime > 0) {
Date start = new Date(this.startTime);
cli.addArgument("-ss");
cli.addArgument(TIME_FORMAT.format(start));
}
if (this.clipDuration > 0) {
Date clipduration = new Date(this.clipDuration);
cli.addArgument("-t");
cli.addArgument(TIME_FORMAT.format(clipduration));
}
Dimension outputsize = this.getInputSize();
if (this.crop != null) {
int cropleft = this.crop.getLocation().x;
cropleft += cropleft % 2;
cropleft = Math.max(0, cropleft);
int croptop = this.crop.getLocation().y;
croptop += croptop % 2;
croptop = Math.max(0, croptop);
int cropright = outputsize.width - cropleft - this.crop.getSize().width;
cropright -= cropright % 2;
cropright = Math.max(0, cropright);
int cropbottom = outputsize.height - croptop - this.crop.getSize().height;
cropbottom -= cropbottom % 2;
cropbottom = Math.max(0, cropbottom);
addArgument(cli, "croptop", croptop);
addArgument(cli, "cropleft", cropleft);
addArgument(cli, "cropbottom", cropbottom);
addArgument(cli, "cropright", cropright);
// calculate remaining size
outputsize.setSize(outputsize.width - cropleft - cropright, outputsize.height - croptop - cropbottom);
}
// TODO: not sure if this is right (had to remove the second argument
// from addResizeArguments())
this.outputsize = outputsize;
// resize, using the remaining size after cropping
addResizeArguments(cli);
File output = new File(input.getParentFile(), name + "." + input.getName());
cli.addArgument(output.getPath());
log.info("**** Exec (trim): [{}]", cli);
this.transcodeExecutor.execute(cli);
return output;
}
public File transcode() throws IOException {
return transcode(getOutputExtension());
}
public File transcode(String extension) throws IOException {
CommandLine cli = ffmpeg();
cli.addArgument("-i");
cli.addArgument(input.getPath());
addResizeArguments(cli);
addArgument(cli, "b", this.bitrate, "k");
addArgument(cli, "r", this.fps);
addArgument(cli, "bt", this.bitrateTolerance, "k");
addArgument(cli, "vcodec", this.videoCodec);
addArgument(cli, "acodec", this.audioCodec);
addArgument(cli, "ac", this.audioChannels);
addArgument(cli, "ar", this.audioSamplingRate);
addArgument(cli, "ab", this.audioBitrate, "k");
if (this.customFlags != null) {
cli.addArguments(this.customFlags, true);
}
if (this.preset != null) {
addArgument(cli, "vpre", this.preset);
}
cli.addArgument("-y");
File output = new File(input.getParentFile(), this.input.getName().replaceAll("\\.\\w+", "") + ".out."
+ extension);
// resetting the output builder
ffmpegOutput = new StringBuilder();
try {
if (this.twoPass) {
CommandLine pass2 = ffmpeg().addArguments(cli.getArguments());
addArgument(cli, "pass", 1);
cli.addArgument(output.getPath());
addArgument(pass2, "pass", 2);
pass2.addArgument(output.getPath());
log.info("**** Exec (pass1): [{}]", cli.toString());
ffmpegOutput.append(cli.toString()).append("\n\n");
this.transcodeExecutor.execute(cli);
log.info("**** Exec (pass2): [{}]", pass2.toString());
ffmpegOutput.append(pass2.toString()).append("\n\n");
this.transcodeExecutor.execute(pass2);
} else {
cli.addArgument(output.getPath());
log.info("**** Exec: [{}]", cli.toString());
ffmpegOutput.append(cli.toString()).append("\n\n");
this.transcodeExecutor.execute(cli);
}
if (output.exists()) {
return output;
} else {
throw new IOException("Transcoding did not create an output file");
}
} catch (ExecuteException e) {
throw ((IOException) new IOException(e.getMessage()).initCause(e));
}
}
private void addResizeArguments(CommandLine cli) {
if (outputsize != null) {
if (letterbox) {
cli.addArgument("-aspect");
cli.addArgument(outputsize.width + ":" + outputsize.height);
}
// do not stretch
Dimension inputSize = getInputSize();
// input size may be null if the file has no video(audio-only)
if (inputSize != null) {
int maxwidth = (outputsize.width > inputSize.width) ? inputSize.width : outputsize.width;
int maxheight = (outputsize.height > inputSize.height) ? inputSize.height : outputsize.height;
outputsize.setSize(new Dimension(maxwidth, maxheight));
// Don't need resize if calculated output size is same as input size,
// resize may result in loss of 1 pixel from input size
if (fitInside && !(outputsize.width == inputSize.width && outputsize.height == inputSize.height)) {
float inputRatio = (float) inputSize.width / (float) inputSize.height;
float outputRatio = (float) outputsize.width / (float) outputsize.height;
if (inputRatio > outputRatio) {
// need to keep the width of the desired output size
// and adapt the height
// eg. 16:9 to 4:3 (landscape)
// 3:4 to 9:16 (portrait)
int height = Math.round(outputsize.width / inputRatio);
if (letterbox) {
int padding = outputsize.height - height;
// padding has to be a multiple of two
int padtop = padding / 2;
padtop = padtop + (padtop % 2);
int padbottom = padding / 2;
padbottom = padbottom - (padbottom % 2);
cli.addArgument("-padtop");
cli.addArgument("" + padtop);
cli.addArgument("-padbottom");
cli.addArgument("" + padbottom);
}
// keep output size even, some encoders don't accept odd output size. e.g. H264
outputsize.height = (height / 2) * 2;
} else if (inputRatio < outputRatio) {
// need to keep the height of the desired output size
// and adapt the width
// eg. 4:3 to 16:9 (landscape)
// 9:16 to 3:4 (portrait)
int width = Math.round(outputsize.height * inputRatio);
if (letterbox) {
int padding = outputsize.width - width;
// padding has to be a multiple of two
int padleft = padding / 2;
padleft = padleft + (padleft % 2);
int padright = padding / 2;
padright = padright - (padright % 2);
cli.addArgument("-padleft");
cli.addArgument("" + padleft);
cli.addArgument("-padright");
cli.addArgument("" + padright);
}
// keep output size even, some encoders don't accept odd output size. e.g. H264
outputsize.width = (width / 2) * 2;
}
}
}
cli.addArgument("-s");
cli.addArgument(this.outputsize.width + "x" + this.outputsize.height);
}
}
public void setLetterbox() {
this.letterbox = true;
}
public void setLetterbox(boolean letterbox) {
this.letterbox = letterbox;
}
public void setFitInside() {
this.fitInside = true;
}
public void setFitInside(boolean fitInside) {
this.fitInside = fitInside;
}
public BufferedImage getFilmStrip(int frames, int width) {
BufferedImage[] thumbs = this.getThumbnails(frames, 0);
BufferedImage combined = new BufferedImage(frames * thumbs[0].getWidth(), thumbs[0].getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = combined.getGraphics();
for (int i = 0; i < thumbs.length; i++) {
g.drawImage(thumbs[i], (thumbs[0].getWidth()) * i, 0, null);
}
double ratio = (double) width / (double) combined.getWidth();
int outHeight = (int) (combined.getHeight() * ratio);
BufferedImage resized = new BufferedImage(width, outHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D h = resized.createGraphics();
AffineTransform scale = AffineTransform.getScaleInstance(ratio, ratio);
h.drawRenderedImage(combined, scale);
return resized;
}
public void setFps(String fps) {
this.fps = fps;
}
public void setBitrateTolerance(int i) {
this.bitrateTolerance = i;
}
private void addArgument(CommandLine cli, String argument, int value) {
if (value > 0) {
cli.addArgument("-" + argument);
cli.addArgument("" + value);
}
}
private void addArgument(CommandLine cli, String argument, int value, String suffix) {
if (value > 0) {
cli.addArgument("-" + argument);
cli.addArgument(value + suffix);
}
}
// private void addArgument(CommandLine cli, String argument, double value) {
// if (value > 0) {
// cli.addArgument("-" + argument);
// cli.addArgument("" + value);
// }
// }
private void addArgument(CommandLine cli, String argument, String value) {
if (value != null) {
cli.addArgument("-" + argument);
cli.addArgument(value);
}
}
public void setAudioChannels(int i) {
this.audioChannels = i;
}
public void setCustomFlags(String[] flags) {
this.customFlags = flags;
}
public void setStartTime(long i) {
this.startTime = i;
}
public void setClipDuration(long i) {
this.clipDuration = i;
}
public void setCropArea(Rectangle rectangle) {
this.crop = rectangle;
}
public void setInputsize(final Dimension inputsize) {
this.inputsize = inputsize;
}
public void setDuration(final long duration) {
this.duration = duration;
}
private class InfoParser extends LogOutputStream {
private FFMpegWrapper wrapper;
public InfoParser(final FFMpegWrapper wrapper) {
this.wrapper = wrapper;
}
@Override
protected void processLine(final String line, final int level) {
String trimmedLine = line.trim();
if (trimmedLine.matches("Duration: .*")) {
// contains the duration
String duration = trimmedLine.replaceFirst("Duration: (\\d\\d:\\d\\d:\\d\\d.\\d\\d),.*", "$1");
try {
Date time = TIME_FORMAT.parse(duration);
wrapper.setDuration(time.getTime());
} catch (ParseException e) {
// ignore
}
} else if (trimmedLine.matches("Stream.* Video: .* \\d+x\\d+.*")) {
String width = trimmedLine.replaceFirst("Stream.* Video: .* (\\d+)x\\d+.*", "$1");
String height = trimmedLine.replaceFirst("Stream.* Video: .* \\d+x(\\d+).*", "$1");
wrapper.setInputsize(new Dimension(Integer.parseInt(width), Integer.parseInt(height)));
}
}
}
/**
* Turns a video profile into a FFMpegWrapper.
*
* @param inputFile
* property file
* @param profile
* can be the cq:Page or jcr:content node of a profile page
* @param workingDir
* working directory for ffmpeg
* @return configured FFMpegWrapper
*/
public static FFMpegWrapper fromProfile(File inputFile, VideoProfile profile, File workingDir) {
ValueMap props = profile.getProperties();
FFMpegWrapper wrapper = new FFMpegWrapper(inputFile, workingDir);
wrapper.setProfileName(profile.getName());
wrapper.setRenditionSelector(props.get(PN_RENDITION_SELECTOR, String.class));
wrapper.setOutputExtension(props.get(PN_OUTPUT_EXTENSION, String.class));
wrapper.setOutputMimetype(props.get(PN_OUTPUT_MIMETYPE, String.class));
wrapper.setTwoPass(props.get(PN_TWO_PASS, Boolean.FALSE));
boolean customOnly = props.get(PN_CUSTOM_ARGS_ONLY, Boolean.FALSE);
if (!customOnly) {
wrapper.setFps(props.get(PN_VIDEO_FRAME_RATE, String.class));
wrapper.setBitrate(props.get(PN_VIDEO_BITRATE, Integer.valueOf(0)));
wrapper.setBitrateTolerance(props.get(PN_VIDEO_BITRATE_TOLERANCE, Integer.valueOf(0)));
wrapper.setVideoCodec(props.get(PN_VIDEO_CODEC, String.class));
wrapper.setAudioCodec(props.get(PN_AUDIO_CODEC, String.class));
wrapper.setAudioChannels(props.get(PN_AUDIO_CHANNELS, Integer.valueOf(0)));
wrapper.setAudioSamplingRate(props.get(PN_AUDIO_SAMPLING_RATE, Integer.valueOf(0)));
wrapper.setAudioBitrate(props.get(PN_AUDIO_BITRATE, Integer.valueOf(0)));
wrapper.setOutputSize(profile.getOutputSize());
wrapper.setFitInside(props.get(PN_VIDEO_FIT_INSIDE, Boolean.FALSE));
wrapper.setLetterbox(props.get(PN_VIDEO_LETTERBOX, Boolean.FALSE));
}
wrapper.setCustomFlags(formatCustomArgs(props.get(PN_CUSTOM_ARGS, String.class)));
return wrapper;
}
/**
*
* @param customArgs
* @return
*/
private static String[] formatCustomArgs(String customArgs) {
if (customArgs != null) {
List formattetArgs = new ArrayList();
String[] splitted = customArgs.split(" ");
for (String splitt : splitted) {
formattetArgs.add(splitt.trim());
}
return formattetArgs.toArray(new String[formattetArgs.size()]);
}
return null;
}
/**
* Tests if the ffmpeg executable cann be found and executed.
*
* @return true
if called without error and returning exit code
* 0, false
otherwise.
*/
private boolean isFfmpegInstalled() {
if (installed == null) {
String path = getFfmpegPath();
CommandLine cmd = new CommandLine(path);
cmd.addArgument("-version");
try {
int exitValue = testExecutor.execute(cmd);
installed = Boolean.valueOf(exitValue == 0);
} catch (ExecuteException e) {
log.warn(e.getMessage(), e);
installed = Boolean.FALSE;
} catch (IOException e) {
log.warn(e.getMessage(), e);
installed = Boolean.FALSE;
}
}
return installed.booleanValue();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy