use of org.fagu.fmv.ffmpeg.metadatas.MovieMetadatas in project fmv by f-agu.
the class FFReducer method createCropDetectFFExecListener.
/**
* @param logger
* @param cropDetect
* @param videoMetadatas
* @return
*/
private FFExecListener createCropDetectFFExecListener(Logger logger, CropDetect cropDetect, MovieMetadatas videoMetadatas) {
return new FFExecListener() {
/**
* @see org.fagu.fmv.soft.exec.FMVExecListener#eventPostExecute(org.fagu.fmv.soft.exec.FMVExecutor,
* org.apache.commons.exec.CommandLine, java.util.Map, org.apache.commons.exec.ExecuteResultHandler)
*/
@Override
public void eventPostExecute(FMVExecutor fmvExecutor, CommandLine command, Map environment, ExecuteResultHandler handler) {
CropDetection cropDetection = cropDetect.getCropSizeDetected();
SortedSet<CropSize> orderedCropSizes = cropDetection.getOrderedCropSizes();
if (!orderedCropSizes.isEmpty()) {
CropSize first = orderedCropSizes.first();
Size size = first.toSize();
if (!videoMetadatas.getVideoStreams().stream().anyMatch(s -> size.equals(s.size()))) {
logger.log("CropDetect: " + cropDetection.getTotalCount() + " lines parsed");
orderedCropSizes.stream().limit(10).forEach(cs -> logger.log("CropDetect: " + cs));
logger.log("CropDetect: Add crop filter: " + first.toCrop());
}
}
}
};
}
use of org.fagu.fmv.ffmpeg.metadatas.MovieMetadatas in project fmv by f-agu.
the class FFReducer method reduceMedia.
/**
* @see org.fagu.fmv.mymedia.reduce.Reducer#reduceMedia(java.io.File, String, Logger)
*/
@Override
public Reduced reduceMedia(File srcFile, String consolePrefixMessage, Logger logger) throws IOException {
File destFile = null;
boolean forceReplace = false;
MovieMetadatas metadatas = MovieMetadatas.with(srcFile).extract();
if (isVideo(metadatas, logger)) {
logger.log("is video");
if (needToReduceVideo(metadatas)) {
destFile = getTempFile(srcFile, getVideoFormat(srcFile));
forceReplace = reduceVideo(metadatas, srcFile, destFile, consolePrefixMessage, logger);
} else {
logger.log("Video already reduced by FMV");
}
} else if (metadatas.contains(Type.AUDIO)) {
logger.log("is audio");
if (needToReduceAudio(metadatas, srcFile)) {
destFile = getTempFile(srcFile, getAudioFormat(srcFile));
forceReplace = reduceAudio(metadatas, srcFile, destFile, "128k", consolePrefixMessage, logger);
} else {
logger.log("Audio already reduced by FMV");
}
}
return new Reduced(destFile, forceReplace);
}
use of org.fagu.fmv.ffmpeg.metadatas.MovieMetadatas in project fmv by f-agu.
the class FFReducer method reduceVideo.
/**
* @param metadatas
* @param srcFile
* @param movieMetadatas
* @param destFile
* @param consolePrefixMessage
* @param logger
* @throws IOException
*/
private boolean reduceVideo(MovieMetadatas metadatas, File srcFile, File destFile, String consolePrefixMessage, Logger logger) throws IOException {
AudioStream audioStream = metadatas.getAudioStream();
boolean audioCodecCopy = audioStream.isCodec(Formats.AC3);
FFMPEGExecutorBuilder builder = FFMPEGExecutorBuilder.create();
builder.hideBanner();
InputProcessor inputProcessor = builder.addMediaInputFile(srcFile);
builder.filter(AutoRotate.create(metadatas));
applyScaleIfNecessary(builder, metadatas, getMaxSize(), logger);
VolumeDetect volumeDetect = null;
if (!audioCodecCopy) {
volumeDetect = VolumeDetect.build();
builder.filter(volumeDetect);
}
CropDetect cropDetect = CropDetect.build();
builder.filter(cropDetect);
MovieMetadatas videoMetadatas = inputProcessor.getMovieMetadatas();
Collection<AudioStream> audioStreams = StreamOrder.sort(videoMetadatas.getAudioStreams());
OutputProcessor outputProcessor = builder.addMediaOutputFile(destFile);
outputProcessor.qualityScale(0);
// video
for (Stream stream : videoMetadatas.getVideoStreams()) {
logger.log("map[" + stream.index() + "] video: " + stream);
outputProcessor.map().streams(stream).input(inputProcessor);
}
// audio
for (Stream stream : audioStreams) {
logger.log("map[" + stream.index() + "] audio: " + stream);
outputProcessor.map().streams(stream).input(inputProcessor);
}
// subtitle
Collection<SubtitleStream> subtitleStreams = StreamOrder.sort(videoMetadatas.getSubtitleStreams());
for (Stream stream : subtitleStreams) {
logger.log("map[" + stream.index() + "] subtitle: " + stream);
outputProcessor.map().streams(stream).input(inputProcessor);
}
// other stream (Apple... again bullshit)
// for (Stream stream : videoMetadatas.getStreams()) {
// Type type = stream.type();
// if (type != Type.AUDIO && type != Type.VIDEO && type != Type.SUBTITLE) {
// logger.log("map other stream: " + stream);
// outputProcessor.map().streams(stream).input(inputProcessor);
// }
// }
// -------------------------- codec -------------------------
outputProcessor.codec(H264.findRecommanded().strict(Strict.EXPERIMENTAL).quality(crf));
// audio
if (audioCodecCopy) {
logger.log("Audio: AC3, copy");
outputProcessor.codecCopy(Type.AUDIO);
} else {
logger.log("Audio: force AAC");
outputProcessor.codecAutoSelectAAC();
}
// subtitle
if (videoMetadatas.contains(Type.SUBTITLE)) {
outputProcessor.codecCopy(Type.SUBTITLE);
}
outputProcessor.overwrite();
FFExecutor<Object> executor = builder.build();
executor.addListener(createLogFFExecListener(logger));
executor.addListener(createCropDetectFFExecListener(logger, cropDetect, videoMetadatas));
if (!audioCodecCopy) {
executor.addListener(createVolumeDetectFFExecListener(logger, volumeDetect));
}
VideoStream videoStream = metadatas.getVideoStream();
OptionalInt countEstimateFrames = videoStream.countEstimateFrames();
Progress progress = executor.getProgress();
if (countEstimateFrames.isPresent() && progress != null) {
textProgressBar = FFMpegProgressBar.with(progress).byFrame(countEstimateFrames.getAsInt()).fileSize(srcFile.length()).build().makeBar(consolePrefixMessage);
} else {
StringJoiner joiner = new StringJoiner(", ");
if (progress == null) {
joiner.add("progress not found");
}
if (!countEstimateFrames.isPresent()) {
joiner.add("nb frames nout found");
}
logger.log("No progress bar: " + joiner.toString());
}
executor.execute();
Optional<String> codecName = videoStream.codecName();
if (codecName.isPresent() && codecName.get().equalsIgnoreCase(Formats.HEVC.getName())) {
// h265
return true;
}
return false;
}
use of org.fagu.fmv.ffmpeg.metadatas.MovieMetadatas in project fmv by f-agu.
the class Bootstrap method reduce.
/**
* @param rootFile
* @throws IOException
*/
public void reduce(File rootFile) throws IOException {
Logger logger = LoggerFactory.openLogger(LoggerFactory.getLogFile(rootFile, PROPERTY_LOG_FILE, PROPERTY_LOG_FILE_DEFAULT_NAME));
AppVersion.logMyVersion(logger::log);
logger.log("#################### Root: " + rootFile.getAbsolutePath());
//
Files.walk(rootFile.toPath()).filter(//
p -> p.toFile().isFile()).forEach(p -> {
logger.log("Reduce to 720p" + p);
String extension = FilenameUtils.getExtension(p.getName(p.getNameCount() - 1).toString()).toLowerCase();
if (!"mkv".equals(extension) && !"mp4".equals(extension)) {
return;
}
File srcFile = p.toFile();
try {
MovieMetadatas metadatas = MovieMetadatas.with(srcFile).extract();
if (!isUpperThan720p(metadatas, logger)) {
return;
}
File destFile = new File(srcFile.getParentFile(), FilenameUtils.getBaseName(srcFile.getName()) + "-720p." + extension);
try (org.fagu.fmv.mymedia.reduce.to720p.FFReducer reducer = new org.fagu.fmv.mymedia.reduce.to720p.FFReducer()) {
String msg = LocalDateTime.now().format(DATE_TIME_FORMATTER) + ' ' + srcFile.getPath();
System.out.print(msg);
reducer.reduceVideo(metadatas, srcFile, metadatas, destFile, msg, logger);
}
} catch (IOException e) {
logger.log(e);
}
System.out.println();
});
System.out.println();
}
use of org.fagu.fmv.ffmpeg.metadatas.MovieMetadatas in project fmv by f-agu.
the class Ripper method encode.
/**
* @param vobFile
* @param mp4File
* @param mPlayerDump
* @param progressEncode
* @throws IOException
*/
private void encode(File vobFile, File mp4File, MPlayerDump mPlayerDump, AtomicInteger progressEncode, AtomicInteger currentEncoding, CountDownLatch encodingLatch) throws IOException {
FFMPEGExecutorBuilder builder = ffMPEGExecutorBuilderSupplier.get();
builder.hideBanner();
InputProcessor inputProcessor = builder.addMediaInputFile(vobFile);
MovieMetadatas movieMetadatas = inputProcessor.getMovieMetadatas();
OutputProcessor outputProcessor = builder.addMediaOutputFile(mp4File);
// video
for (VideoStream stream : movieMetadatas.getVideoStreams()) {
outputProcessor.map().streams(stream).input(inputProcessor);
}
// audio
filterAndMap(inputProcessor, outputProcessor, movieMetadatas.getAudioStreams().iterator(), mPlayerDump.getAudioStreams());
// subtitle
filterAndMap(inputProcessor, outputProcessor, movieMetadatas.getSubtitleStreams().iterator(), mPlayerDump.getSubtitles());
outputProcessor.codec(H264.findRecommanded().strict(Strict.EXPERIMENTAL).quality(21)).overwrite();
int nbFrames = 0;
OptionalInt countEstimateFrames = movieMetadatas.getVideoStream().countEstimateFrames();
if (countEstimateFrames.isPresent()) {
nbFrames = countEstimateFrames.getAsInt();
} else {
// TODO
}
builder.progressReadLine(new FFMpegProgress(progressEncode, nbFrames));
FFExecutor<Object> executor = builder.build();
logger.log(executor.getCommandLine());
ffmpegService.submit(() -> {
try {
currentEncoding.incrementAndGet();
executor.execute();
} catch (Exception e) {
logger.log(e);
} finally {
encodingLatch.countDown();
vobFile.delete();
}
});
}
Aggregations