Skip to content

Feature/318 input builder #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ FFprobe ffprobe = new FFprobe("/path/to/ffprobe");
FFmpegBuilder builder = new FFmpegBuilder()

.setInput("input.mp4") // Filename, or a FFmpegProbeResult
.done()
.overrideOutputFiles(true) // Override the output if it exists

.addOutput("output.mp4") // Filename for the destination
Expand Down Expand Up @@ -100,6 +101,7 @@ FFmpegProbeResult in = ffprobe.probe("input.flv");

FFmpegBuilder builder = new FFmpegBuilder()
.setInput(in) // Or filename
.done()
.addOutput("output.mp4")
.done();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package net.bramp.ffmpeg.builder;

import com.google.common.collect.ImmutableList;
import net.bramp.ffmpeg.options.EncodingOptions;
import net.bramp.ffmpeg.probe.FFmpegProbeResult;

import javax.annotation.CheckReturnValue;

public abstract class AbstractFFmpegInputBuilder<T extends AbstractFFmpegInputBuilder<T>> extends AbstractFFmpegStreamBuilder<T> {
private final FFmpegProbeResult probeResult;

private boolean readAtNativeFrameRate;
/**
* Number of times input stream shall be looped. Loop 0 means no loop, loop -1 means infinite loop.
*/
private int streamLoop;

protected AbstractFFmpegInputBuilder(FFmpegBuilder parent, String filename) {
this(parent, null, filename);
}

protected AbstractFFmpegInputBuilder(FFmpegBuilder parent, FFmpegProbeResult probeResult, String filename) {
super(parent, filename);
this.probeResult = probeResult;
}

public T readAtNativeFrameRate() {
this.readAtNativeFrameRate = true;
return getThis();
}

/**
* Sets number of times input stream shall be looped. Loop 0 means no loop, loop -1 means infinite loop.
* @param streamLoop loop counter
* @return this
*/
public T setStreamLoop(int streamLoop) {
this.streamLoop = streamLoop;

return getThis();
}

public FFmpegProbeResult getProbeResult() {
return probeResult;
}

@Override
@CheckReturnValue
@SuppressWarnings("unchecked")
protected T getThis() {
return (T) this;
}

@Override
public EncodingOptions buildOptions() {
return null;
}

@Override
protected void addGlobalFlags(FFmpegBuilder parent, ImmutableList.Builder<String> args) {
if (this.readAtNativeFrameRate) {
args.add("-re");
}

if (this.streamLoop != 0) {
args.add("-stream_loop", Integer.toString(this.streamLoop));
}

super.addGlobalFlags(parent, args);
}

public int getStreamLoop() {
return streamLoop;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import net.bramp.ffmpeg.probe.FFmpegProbeResult;

/** Builds a representation of a single output/encoding setting */
@SuppressWarnings({"DeprecatedIsStillUsed", "deprecation","unchecked"})
@SuppressWarnings({"DeprecatedIsStillUsed", "unchecked"})
public abstract class AbstractFFmpegOutputBuilder<T extends AbstractFFmpegOutputBuilder<T>> extends AbstractFFmpegStreamBuilder<T> {

static final Pattern trailingZero = Pattern.compile("\\.0*$");
Expand Down Expand Up @@ -67,6 +67,8 @@ public abstract class AbstractFFmpegOutputBuilder<T extends AbstractFFmpegOutput
@Deprecated
public String video_bit_stream_filter;

protected String complexFilter;

public AbstractFFmpegOutputBuilder() {
super();
}
Expand Down Expand Up @@ -194,6 +196,12 @@ public T setAudioBitStreamFilter(String filter) {
return (T) this;
}

public T setComplexFilter(String filter) {
this.complexFilter = checkNotEmpty(filter, "filter must not be empty");

return (T) this;
}

/**
* Sets Audio Filter
*
Expand Down Expand Up @@ -247,6 +255,7 @@ public EncodingOptions buildOptions() {
@Override
protected List<String> build(int pass) {
Preconditions.checkState(parent != null, "Can not build without parent being set");

return build(parent, pass);
}

Expand All @@ -265,15 +274,18 @@ protected List<String> build(FFmpegBuilder parent, int pass) {
checkArgument(
targetSize != 0 || video_bit_rate != 0,
"Target size, or video bitrate must be specified when using two-pass");

checkArgument(format != null, "Format must be specified when using two-pass");
}

if (targetSize > 0) {
checkState(parent.inputs.size() == 1, "Target size does not support multiple inputs");

checkArgument(
constantRateFactor == null, "Target size can not be used with constantRateFactor");

String firstInput = parent.inputs.iterator().next();
FFmpegProbeResult input = parent.inputProbes.get(firstInput);
AbstractFFmpegInputBuilder<?> firstInput = parent.inputs.iterator().next();
FFmpegProbeResult input = firstInput.getProbeResult();

checkState(input != null, "Target size must be used with setInput(FFmpegProbeResult)");

Expand Down Expand Up @@ -316,6 +328,10 @@ protected void addGlobalFlags(FFmpegBuilder parent, ImmutableList.Builder<String
if (constantRateFactor != null) {
args.add("-crf", formatDecimalInteger(constantRateFactor));
}

if (complexFilter != null) {
args.add("-filter_complex", complexFilter);
}
}

@Override
Expand Down Expand Up @@ -381,6 +397,24 @@ protected void addAudioFlags(ImmutableList.Builder<String> args) {
}
}

@Override
protected void addSourceTarget(int pass, ImmutableList.Builder<String> args) {
if (filename != null && uri != null) {
throw new IllegalStateException("Only one of filename and uri can be set");
}

// Output
if (pass == 1) {
args.add(DEVNULL);
} else if (filename != null) {
args.add(filename);
} else if (uri != null) {
args.add(uri.toString());
} else {
assert false;
}
}

@CheckReturnValue
@Override
protected T getThis() {
Expand Down Expand Up @@ -431,4 +465,8 @@ public String getVideoFilter() {
public String getVideoBitStreamFilter() {
return video_bit_stream_filter;
}

public String getComplexFilter() {
return complexFilter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
*/
public abstract class AbstractFFmpegStreamBuilder<T extends AbstractFFmpegStreamBuilder<T>> {

private static final String DEVNULL = SystemUtils.IS_OS_WINDOWS ? "NUL" : "/dev/null";
protected static final String DEVNULL = SystemUtils.IS_OS_WINDOWS ? "NUL" : "/dev/null";

final FFmpegBuilder parent;

Expand Down Expand Up @@ -551,11 +551,6 @@ protected List<String> build(int pass) {
protected List<String> build(FFmpegBuilder parent, int pass) {
checkNotNull(parent);

if (pass > 0) {
// TODO Write a test for this:
checkArgument(format != null, "Format must be specified when using two-pass");
}

ImmutableList.Builder<String> args = new ImmutableList.Builder<>();

addGlobalFlags(parent, args);
Expand Down Expand Up @@ -589,24 +584,13 @@ protected List<String> build(FFmpegBuilder parent, int pass) {

args.addAll(extra_args);

if (filename != null && uri != null) {
throw new IllegalStateException("Only one of filename and uri can be set");
}

// Output
if (pass == 1) {
args.add(DEVNULL);
} else if (filename != null) {
args.add(filename);
} else if (uri != null) {
args.add(uri.toString());
} else {
assert false;
}
addSourceTarget(pass, args);

return args.build();
}

protected abstract void addSourceTarget(int pass, ImmutableList.Builder<String> args);

protected void addGlobalFlags(FFmpegBuilder parent, ImmutableList.Builder<String> args) {
if (strict != FFmpegBuilder.Strict.NORMAL) {
args.add("-strict", strict.toString());
Expand Down
Loading
Loading