001package net.bramp.ffmpeg.info;
002
003import com.google.common.base.Preconditions;
004import com.google.errorprone.annotations.Immutable;
005import net.bramp.ffmpeg.shared.CodecType;
006import org.apache.commons.lang3.builder.EqualsBuilder;
007import org.apache.commons.lang3.builder.HashCodeBuilder;
008
009/**
010 * Information about supported Codecs.
011 *
012 * @author bramp
013 */
014@Immutable
015public class Codec {
016  private final String name;
017  private final String longName;
018
019  /** Can I decode with this codec. */
020  private final boolean canDecode;
021
022  /** Can I encode with this codec. */
023  private final boolean canEncode;
024
025  /** What type of codec is this. */
026  private final CodecType type;
027
028  /** Intra frame only codec. */
029  final boolean intraFrameOnly;
030
031  /** Codec supports lossy compression. */
032  final boolean lossyCompression;
033
034  /** Codeco supports lessless compression. */
035  final boolean losslessCompression;
036
037  /**
038   * Creates a new Codec.
039   *
040   * @param name short codec name
041   * @param longName long codec name
042   * @param flags is expected to be in the following format:
043   *     <pre>
044   *     D..... = Decoding supported
045   *     .E.... = Encoding supported
046   *     ..V... = Video codec
047   *     ..A... = Audio codec
048   *     ..S... = Subtitle codec
049   *     ..D... = Data codec
050   *     ..T... = Attachment codec
051   *     ...I.. = Intra frame-only codec
052   *     ....L. = Lossy compression
053   *     .....S = Lossless compression
054   *     </pre>
055   */
056  public Codec(String name, String longName, String flags) {
057    this.name = Preconditions.checkNotNull(name).trim();
058    this.longName = Preconditions.checkNotNull(longName).trim();
059
060    Preconditions.checkNotNull(flags);
061    Preconditions.checkArgument(flags.length() == 6, "Codec flags is invalid '%s'", flags);
062
063    switch (flags.charAt(0)) {
064      case 'D':
065        this.canDecode = true;
066        break;
067      case '.':
068        this.canDecode = false;
069        break;
070      default:
071        throw new IllegalArgumentException("Invalid decoding value '" + flags.charAt(0) + "'");
072    }
073
074    switch (flags.charAt(1)) {
075      case 'E':
076        this.canEncode = true;
077        break;
078      case '.':
079        this.canEncode = false;
080        break;
081      default:
082        throw new IllegalArgumentException("Invalid encoding value '" + flags.charAt(1) + "'");
083    }
084
085    switch (flags.charAt(2)) {
086      case 'V':
087        this.type = CodecType.VIDEO;
088        break;
089      case 'A':
090        this.type = CodecType.AUDIO;
091        break;
092      case 'S':
093        this.type = CodecType.SUBTITLE;
094        break;
095      case 'D':
096        this.type = CodecType.DATA;
097        break;
098      case 'T':
099        this.type = CodecType.ATTACHMENT;
100        break;
101      default:
102        throw new IllegalArgumentException("Invalid codec type '" + flags.charAt(2) + "'");
103    }
104
105    switch (flags.charAt(3)) {
106      case 'I':
107        this.intraFrameOnly = true;
108        break;
109      case '.':
110        this.intraFrameOnly = false;
111        break;
112      default:
113        throw new IllegalArgumentException("Invalid encoding value '" + flags.charAt(3) + "'");
114    }
115
116    switch (flags.charAt(4)) {
117      case 'L':
118        this.lossyCompression = true;
119        break;
120      case '.':
121        this.lossyCompression = false;
122        break;
123      default:
124        throw new IllegalArgumentException(
125            "Invalid lossy compression value '" + flags.charAt(4) + "'");
126    }
127
128    switch (flags.charAt(5)) {
129      case 'S':
130        this.losslessCompression = true;
131        break;
132      case '.':
133        this.losslessCompression = false;
134        break;
135      default:
136        throw new IllegalArgumentException(
137            "Invalid lossless compression value '" + flags.charAt(5) + "'");
138    }
139  }
140
141  @Override
142  public String toString() {
143    return name + " " + longName;
144  }
145
146  @Override
147  public boolean equals(Object obj) {
148    return EqualsBuilder.reflectionEquals(this, obj);
149  }
150
151  @Override
152  public int hashCode() {
153    return HashCodeBuilder.reflectionHashCode(this);
154  }
155
156  public String getName() {
157    return name;
158  }
159
160  public String getLongName() {
161    return longName;
162  }
163
164  public boolean getCanDecode() {
165    return canDecode;
166  }
167
168  public boolean getCanEncode() {
169    return canEncode;
170  }
171
172  public CodecType getType() {
173    return type;
174  }
175
176  public boolean isIntraFrameOnly() {
177    return intraFrameOnly;
178  }
179
180  /** Returns whether this codec supports lossy compression. */
181  public boolean supportsLossyCompression() {
182    return lossyCompression;
183  }
184
185  /** Returns whether this codec supports lossless compression. */
186  public boolean supportsLosslessCompression() {
187    return losslessCompression;
188  }
189}