001package net.bramp.ffmpeg; 002 003import static com.google.common.base.Preconditions.checkNotNull; 004 005import com.google.common.base.MoreObjects; 006import com.google.gson.Gson; 007import java.io.IOException; 008import java.io.Reader; 009import java.util.List; 010import javax.annotation.CheckReturnValue; 011import javax.annotation.Nonnull; 012import javax.annotation.Nullable; 013import net.bramp.ffmpeg.builder.FFprobeBuilder; 014import net.bramp.ffmpeg.io.LoggingFilterReader; 015import net.bramp.ffmpeg.probe.FFmpegProbeResult; 016import org.slf4j.Logger; 017import org.slf4j.LoggerFactory; 018 019/** 020 * Wrapper around FFprobe. 021 * 022 * @author bramp 023 */ 024public class FFprobe extends FFcommon { 025 026 static final Logger LOG = LoggerFactory.getLogger(FFprobe.class); 027 028 static final String FFPROBE = "ffprobe"; 029 static final String DEFAULT_PATH = MoreObjects.firstNonNull(System.getenv("FFPROBE"), FFPROBE); 030 031 static final Gson gson = FFmpegUtils.getGson(); 032 033 /** Constructs an FFprobe instance using the default path. */ 034 public FFprobe() throws IOException { 035 this(DEFAULT_PATH, new RunProcessFunction()); 036 } 037 038 /** Constructs an FFprobe instance using the default path and the specified process function. */ 039 public FFprobe(@Nonnull ProcessFunction runFunction) throws IOException { 040 this(DEFAULT_PATH, runFunction); 041 } 042 043 /** Constructs an FFprobe instance using the specified path. */ 044 public FFprobe(@Nonnull String path) throws IOException { 045 this(path, new RunProcessFunction()); 046 } 047 048 /** Constructs an FFprobe instance using the specified path and process function. */ 049 public FFprobe(@Nonnull String path, @Nonnull ProcessFunction runFunction) { 050 super(path, runFunction); 051 } 052 053 /** Probes the specified media file and returns the result. */ 054 public FFmpegProbeResult probe(String mediaPath) throws IOException { 055 return probe(mediaPath, null); 056 } 057 058 /** Probes the specified media file with an optional user agent. */ 059 public FFmpegProbeResult probe(String mediaPath, @Nullable String userAgent) throws IOException { 060 return probe(this.builder().setInput(mediaPath).setUserAgent(userAgent)); 061 } 062 063 /** Probes media using the supplied FFprobeBuilder. */ 064 public FFmpegProbeResult probe(FFprobeBuilder builder) throws IOException { 065 checkNotNull(builder); 066 return probe(builder.build()); 067 } 068 069 /** Probes media with an optional user agent and extra arguments. */ 070 public FFmpegProbeResult probe( 071 String mediaPath, @Nullable String userAgent, @Nullable String... extraArgs) 072 throws IOException { 073 return probe( 074 this.builder().setInput(mediaPath).setUserAgent(userAgent).addExtraArgs(extraArgs).build()); 075 } 076 077 // TODO Add Probe Inputstream 078 /** Probes media using the supplied arguments and returns the result. */ 079 public FFmpegProbeResult probe(List<String> args) throws IOException { 080 checkIfFFprobe(); 081 082 Process p = runFunc.run(path(args)); 083 try { 084 Reader reader = wrapInReader(p); 085 if (LOG.isDebugEnabled()) { 086 reader = new LoggingFilterReader(reader, LOG); 087 } 088 089 FFmpegProbeResult result = gson.fromJson(reader, FFmpegProbeResult.class); 090 091 throwOnError(p, result); 092 093 if (result == null) { 094 throw new IllegalStateException("Gson returned null, which shouldn't happen :("); 095 } 096 097 return result; 098 099 } finally { 100 p.destroy(); 101 } 102 } 103 104 /** 105 * Returns true if the binary we are using is the true ffprobe. This is to avoid conflict with 106 * avprobe (from the libav project), that some symlink to ffprobe. 107 * 108 * @return true iff this is the official ffprobe binary. 109 * @throws IOException If a I/O error occurs while executing ffprobe. 110 */ 111 public boolean isFFprobe() throws IOException { 112 return version().startsWith("ffprobe"); 113 } 114 115 /** 116 * Throws an exception if this is an unsupported version of ffprobe. 117 * 118 * @throws IllegalArgumentException if this is not the official ffprobe binary. 119 * @throws IOException If a I/O error occurs while executing ffprobe. 120 */ 121 private void checkIfFFprobe() throws IllegalArgumentException, IOException { 122 if (!isFFprobe()) { 123 throw new IllegalArgumentException( 124 "This binary '" + path + "' is not a supported version of ffprobe"); 125 } 126 } 127 128 @Override 129 public void run(List<String> args) throws IOException { 130 checkIfFFprobe(); 131 super.run(args); 132 } 133 134 /** Returns a new FFprobeBuilder instance. */ 135 @CheckReturnValue 136 public FFprobeBuilder builder() { 137 return new FFprobeBuilder(); 138 } 139}