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 public FFprobe() throws IOException { 034 this(DEFAULT_PATH, new RunProcessFunction()); 035 } 036 037 public FFprobe(@Nonnull ProcessFunction runFunction) throws IOException { 038 this(DEFAULT_PATH, runFunction); 039 } 040 041 public FFprobe(@Nonnull String path) throws IOException { 042 this(path, new RunProcessFunction()); 043 } 044 045 public FFprobe(@Nonnull String path, @Nonnull ProcessFunction runFunction) { 046 super(path, runFunction); 047 } 048 049 public FFmpegProbeResult probe(String mediaPath) throws IOException { 050 return probe(mediaPath, null); 051 } 052 053 /** 054 * Returns true if the binary we are using is the true ffprobe. This is to avoid conflict with 055 * avprobe (from the libav project), that some symlink to ffprobe. 056 * 057 * @return true iff this is the official ffprobe binary. 058 * @throws IOException If a I/O error occurs while executing ffprobe. 059 */ 060 public boolean isFFprobe() throws IOException { 061 return version().startsWith("ffprobe"); 062 } 063 064 /** 065 * Throws an exception if this is an unsupported version of ffprobe. 066 * 067 * @throws IllegalArgumentException if this is not the official ffprobe binary. 068 * @throws IOException If a I/O error occurs while executing ffprobe. 069 */ 070 private void checkIfFFprobe() throws IllegalArgumentException, IOException { 071 if (!isFFprobe()) { 072 throw new IllegalArgumentException( 073 "This binary '" + path + "' is not a supported version of ffprobe"); 074 } 075 } 076 077 @Override 078 public void run(List<String> args) throws IOException { 079 checkIfFFprobe(); 080 super.run(args); 081 } 082 083 public FFmpegProbeResult probe(String mediaPath, @Nullable String userAgent) throws IOException { 084 return probe(this.builder().setInput(mediaPath).setUserAgent(userAgent)); 085 } 086 087 public FFmpegProbeResult probe(FFprobeBuilder builder) throws IOException { 088 checkNotNull(builder); 089 return probe(builder.build()); 090 } 091 092 public FFmpegProbeResult probe( 093 String mediaPath, @Nullable String userAgent, @Nullable String... extraArgs) 094 throws IOException { 095 return probe( 096 this.builder().setInput(mediaPath).setUserAgent(userAgent).addExtraArgs(extraArgs).build()); 097 } 098 099 // TODO Add Probe Inputstream 100 public FFmpegProbeResult probe(List<String> args) throws IOException { 101 checkIfFFprobe(); 102 103 Process p = runFunc.run(path(args)); 104 try { 105 Reader reader = wrapInReader(p); 106 if (LOG.isDebugEnabled()) { 107 reader = new LoggingFilterReader(reader, LOG); 108 } 109 110 FFmpegProbeResult result = gson.fromJson(reader, FFmpegProbeResult.class); 111 112 throwOnError(p, result); 113 114 if (result == null) { 115 throw new IllegalStateException("Gson returned null, which shouldn't happen :("); 116 } 117 118 return result; 119 120 } finally { 121 p.destroy(); 122 } 123 } 124 125 @CheckReturnValue 126 public FFprobeBuilder builder() { 127 return new FFprobeBuilder(); 128 } 129}