setSize(inputFile.getFile().length());
} else {
setSize(inputFile.getSize());
}
ProcessWrapperImpl pw = null;
boolean ffmpeg_parsing = true;
if (type == Format.AUDIO || ext instanceof AudioAsVideo) {
ffmpeg_parsing = false;
DLNAMediaAudio audio = new DLNAMediaAudio();
if (inputFile.getFile() != null) {
try {
AudioFile af = AudioFileIO.read(inputFile.getFile());
AudioHeader ah = af.getAudioHeader();
if (ah != null && !thumbOnly) {
int length = ah.getTrackLength();
int rate = ah.getSampleRateAsNumber();
if (ah.getEncodingType().toLowerCase().contains("flac 24")) {
audio.setBitsperSample(24);
}
audio.setSampleFrequency("" + rate);
setDuration((double) length);
setBitrate((int) ah.getBitRateAsNumber());
audio.getAudioProperties().setNumberOfChannels(2);
if (ah.getChannels() != null && ah.getChannels().toLowerCase().contains("mono")) {
audio.getAudioProperties().setNumberOfChannels(1);
} else if (ah.getChannels() != null && ah.getChannels().toLowerCase().contains("stereo")) {
audio.getAudioProperties().setNumberOfChannels(2);
} else if (ah.getChannels() != null) {
audio.getAudioProperties().setNumberOfChannels(Integer.parseInt(ah.getChannels()));
}
audio.setCodecA(ah.getEncodingType().toLowerCase());
if (audio.getCodecA().contains("(windows media")) {
audio.setCodecA(audio.getCodecA().substring(0, audio.getCodecA().indexOf("(windows media")).trim());
}
}
Tag t = af.getTag();
if (t != null) {
if (t.getArtworkList().size() > 0) {
setThumb(t.getArtworkList().get(0).getBinaryData());
} else {
if (configuration.getAudioThumbnailMethod() > 0) {
setThumb(
CoverUtil.get().getThumbnailFromArtistAlbum(
configuration.getAudioThumbnailMethod() == 1 ?
CoverUtil.AUDIO_AMAZON :
CoverUtil.AUDIO_DISCOGS,
audio.getArtist(), audio.getAlbum()
)
);
}
}
if (!thumbOnly) {
audio.setAlbum(t.getFirst(FieldKey.ALBUM));
audio.setArtist(t.getFirst(FieldKey.ARTIST));
audio.setSongname(t.getFirst(FieldKey.TITLE));
String y = t.getFirst(FieldKey.YEAR);
try {
if (y.length() > 4) {
y = y.substring(0, 4);
}
audio.setYear(Integer.parseInt(((y != null && y.length() > 0) ? y : "0")));
y = t.getFirst(FieldKey.TRACK);
audio.setTrack(Integer.parseInt(((y != null && y.length() > 0) ? y : "1")));
audio.setGenre(t.getFirst(FieldKey.GENRE));
} catch (Throwable e) {
logger.debug("Error parsing unimportant metadata: " + e.getMessage());
}
}
}
} catch (Throwable e) {
logger.debug("Error parsing audio file: {} - {}", e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
ffmpeg_parsing = false;
}
if (audio.getSongname() == null || audio.getSongname().length() == 0) {
audio.setSongname(inputFile.getFile().getName());
}
if (!ffmpeg_parsing) {
getAudioTracksList().add(audio);
}
}
}
if (type == Format.IMAGE && inputFile.getFile() != null) {
try {
ffmpeg_parsing = false;
ImageInfo info = Sanselan.getImageInfo(inputFile.getFile());
setWidth(info.getWidth());
setHeight(info.getHeight());
setBitsPerPixel(info.getBitsPerPixel());
String formatName = info.getFormatName();
if (formatName.startsWith("JPEG")) {
setCodecV("jpg");
IImageMetadata meta = Sanselan.getMetadata(inputFile.getFile());
if (meta != null && meta instanceof JpegImageMetadata) {
JpegImageMetadata jpegmeta = (JpegImageMetadata) meta;
TiffField tf = jpegmeta.findEXIFValue(TiffConstants.EXIF_TAG_MODEL);
if (tf != null) {
setModel(tf.getStringValue().trim());
}
tf = jpegmeta.findEXIFValue(TiffConstants.EXIF_TAG_EXPOSURE_TIME);
if (tf != null) {
setExposure((int) (1000 * tf.getDoubleValue()));
}
tf = jpegmeta.findEXIFValue(TiffConstants.EXIF_TAG_ORIENTATION);
if (tf != null) {
setOrientation(tf.getIntValue());
}
tf = jpegmeta.findEXIFValue(TiffConstants.EXIF_TAG_ISO);
if (tf != null) {
// Galaxy Nexus jpg pictures may contain multiple values, take the first
int[] isoValues = tf.getIntArrayValue();
setIso(isoValues[0]);
}
}
} else if (formatName.startsWith("PNG")) {
setCodecV("png");
} else if (formatName.startsWith("GIF")) {
setCodecV("gif");
} else if (formatName.startsWith("TIF")) {
setCodecV("tiff");
}
setContainer(getCodecV());
} catch (Throwable e) {
logger.info("Error parsing image ({}) with Sanselan, switching to FFmpeg.", inputFile.getFile().getAbsolutePath());
}
}
if (configuration.getImageThumbnailsEnabled() && type != Format.VIDEO && type != Format.AUDIO) {
try {
File thumbDir = new File(configuration.getTempFolder(), THUMBNAIL_DIRECTORY_NAME);
logger.trace("Generating thumbnail for: {}", inputFile.getFile().getAbsolutePath());
if (!thumbDir.exists() && !thumbDir.mkdirs()) {
logger.warn("Could not create thumbnail directory: {}", thumbDir.getAbsolutePath());
} else {
File thumbFile = new File(thumbDir, inputFile.getFile().getName() + ".jpg");
String thumbFilename = thumbFile.getAbsolutePath();
logger.trace("Creating (temporary) thumbnail: {}", thumbFilename);
// Create the thumbnail image using the Thumbnailator library
final Builder<File> thumbnail = Thumbnails.of(inputFile.getFile());
thumbnail.size(320, 180);
thumbnail.outputFormat("jpg");
thumbnail.outputQuality(1.0f);
try {
thumbnail.toFile(thumbFilename);
} catch (IIOException e) {
logger.debug("Error generating thumbnail for: " + inputFile.getFile().getName());
logger.debug("The full error was: " + e);
}
File jpg = new File(thumbFilename);
if (jpg.exists()) {
InputStream is = new FileInputStream(jpg);
int sz = is.available();
if (sz > 0) {
setThumb(new byte[sz]);
is.read(getThumb());
}
is.close();
if (!jpg.delete()) {
jpg.deleteOnExit();
}
}
}
} catch (UnsupportedFormatException ufe) {
logger.debug("Thumbnailator does not support the format of {}: {}", inputFile.getFile().getAbsolutePath(), ufe.getMessage());
} catch (Exception e) {
logger.debug("Thumbnailator could not generate a thumbnail for: {}", inputFile.getFile().getAbsolutePath(), e);
}
}
if (ffmpeg_parsing) {
if (!thumbOnly || !configuration.isUseMplayerForVideoThumbs()) {
pw = getFFmpegThumbnail(inputFile);
}
String input = "-";
boolean dvrms = false;
if (inputFile.getFile() != null) {
input = ProcessUtil.getShortFileNameIfWideChars(inputFile.getFile().getAbsolutePath());
dvrms = inputFile.getFile().getAbsolutePath().toLowerCase().endsWith("dvr-ms");
}
if (!ffmpeg_failure && !thumbOnly) {
if (input.equals("-")) {
input = "pipe:";
}
boolean matchs = false;
ArrayList<String> lines = (ArrayList<String>) pw.getResults();
int langId = 0;
int subId = 0;
ListIterator<String> FFmpegMetaData = lines.listIterator();
for (String line : lines) {
FFmpegMetaData.next();
line = line.trim();
if (line.startsWith("Output")) {
matchs = false;
} else if (line.startsWith("Input")) {
if (line.indexOf(input) > -1) {
matchs = true;
setContainer(line.substring(10, line.indexOf(",", 11)).trim());
} else {
matchs = false;
}
} else if (matchs) {
if (line.indexOf("Duration") > -1) {
StringTokenizer st = new StringTokenizer(line, ",");
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
if (token.startsWith("Duration: ")) {
String durationStr = token.substring(10);
int l = durationStr.substring(durationStr.indexOf(".") + 1).length();
if (l < 4) {
durationStr = durationStr + "00".substring(0, 3 - l);
}
if (durationStr.indexOf("N/A") > -1) {
setDuration(null);
} else {
setDuration(parseDurationString(durationStr));
}
} else if (token.startsWith("bitrate: ")) {
String bitr = token.substring(9);
int spacepos = bitr.indexOf(" ");
if (spacepos > -1) {
String value = bitr.substring(0, spacepos);
String unit = bitr.substring(spacepos + 1);
setBitrate(Integer.parseInt(value));
if (unit.equals("kb/s")) {
setBitrate(1024 * getBitrate());
}
if (unit.equals("mb/s")) {
setBitrate(1048576 * getBitrate());
}
}
}
}
} else if (line.indexOf("Audio:") > -1) {
StringTokenizer st = new StringTokenizer(line, ",");
int a = line.indexOf("(");
int b = line.indexOf("):", a);
DLNAMediaAudio audio = new DLNAMediaAudio();
audio.setId(langId++);
if (a > -1 && b > a) {
audio.setLang(line.substring(a + 1, b));
} else {
audio.setLang(DLNAMediaLang.UND);
}
// Get TS IDs
a = line.indexOf("[0x");
b = line.indexOf("]", a);
if (a > -1 && b > a + 3) {
String idString = line.substring(a + 3, b);
try {
audio.setId(Integer.parseInt(idString, 16));
} catch (NumberFormatException nfe) {
logger.debug("Error parsing Stream ID: " + idString);
}
}
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
Integer nChannels;
if (token.startsWith("Stream")) {
audio.setCodecA(token.substring(token.indexOf("Audio: ") + 7));
} else if (token.endsWith("Hz")) {
audio.setSampleFrequency(token.substring(0, token.indexOf("Hz")).trim());
} else if ((nChannels = audioChannelLayout.get(token)) != null) {
audio.getAudioProperties().setNumberOfChannels(nChannels);
} else if (token.matches("\\d+(?:\\s+channels?)")) { // implicitly anchored at both ends e.g. ^ ... $
// setNumberOfChannels(String) parses the number out of the string
audio.getAudioProperties().setNumberOfChannels(token);
} else if (token.equals("s32")) {
audio.setBitsperSample(32);
} else if (token.equals("s24")) {
audio.setBitsperSample(24);
} else if (token.equals("s16")) {
audio.setBitsperSample(16);
}
}
int FFmpegMetaDataNr = FFmpegMetaData.nextIndex();
if (FFmpegMetaDataNr > -1) {
line = lines.get(FFmpegMetaDataNr);
}
if (line.indexOf("Metadata:") > -1) {
FFmpegMetaDataNr = FFmpegMetaDataNr + 1;
line = lines.get(FFmpegMetaDataNr);
while (line.indexOf(" ") == 0) {
if (line.toLowerCase().indexOf("title :") > -1) {
int aa = line.indexOf(": ");
int bb = line.length();
if (aa > -1 && bb > aa) {
audio.setFlavor(line.substring(aa+2, bb));
break;
}
} else {
FFmpegMetaDataNr = FFmpegMetaDataNr + 1;
line = lines.get(FFmpegMetaDataNr);
}
}
}
getAudioTracksList().add(audio);
} else if (line.indexOf("Video:") > -1) {
StringTokenizer st = new StringTokenizer(line, ",");
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
if (token.startsWith("Stream")) {
setCodecV(token.substring(token.indexOf("Video: ") + 7));
} else if ((token.indexOf("tbc") > -1 || token.indexOf("tb(c)") > -1)) {
// A/V sync issues with newest FFmpeg, due to the new tbr/tbn/tbc outputs
// Priority to tb(c)
String frameRateDoubleString = token.substring(0, token.indexOf("tb")).trim();
try {
if (!frameRateDoubleString.equals(getFrameRate())) {// tbc taken into account only if different than tbr
Double frameRateDouble = Double.parseDouble(frameRateDoubleString);
setFrameRate(String.format(Locale.ENGLISH, "%.2f", frameRateDouble / 2));
}
} catch (NumberFormatException nfe) {
// Could happen if tbc is "1k" or something like that, no big deal
logger.debug("Could not parse frame rate \"" + frameRateDoubleString + "\"");
}
} else if ((token.indexOf("tbr") > -1 || token.indexOf("tb(r)") > -1) && getFrameRate() == null) {
setFrameRate(token.substring(0, token.indexOf("tb")).trim());
} else if ((token.indexOf("fps") > -1 || token.indexOf("fps(r)") > -1) && getFrameRate() == null) { // dvr-ms ?
setFrameRate(token.substring(0, token.indexOf("fps")).trim());
} else if (token.indexOf("x") > -1) {
String resolution = token.trim();
if (resolution.indexOf(" [") > -1) {
resolution = resolution.substring(0, resolution.indexOf(" ["));
}
try {
setWidth(Integer.parseInt(resolution.substring(0, resolution.indexOf("x"))));
} catch (NumberFormatException nfe) {
logger.debug("Could not parse width from \"" + resolution.substring(0, resolution.indexOf("x")) + "\"");
}
try {
setHeight(Integer.parseInt(resolution.substring(resolution.indexOf("x") + 1)));
} catch (NumberFormatException nfe) {
logger.debug("Could not parse height from \"" + resolution.substring(resolution.indexOf("x") + 1) + "\"");
}
}
}
} else if (line.indexOf("Subtitle:") > -1 && !line.contains("tx3g")) {
DLNAMediaSubtitle lang = new DLNAMediaSubtitle();
lang.setType((line.contains("dvdsub") && Platform.isWindows() ? SubtitleType.VOBSUB : SubtitleType.UNKNOWN));
int a = line.indexOf("(");
int b = line.indexOf("):", a);
if (a > -1 && b > a) {
lang.setLang(line.substring(a + 1, b));
} else {
lang.setLang(DLNAMediaLang.UND);
}
lang.setId(subId++);
int FFmpegMetaDataNr = FFmpegMetaData.nextIndex();
if (FFmpegMetaDataNr > -1) {
line = lines.get(FFmpegMetaDataNr);
}
if (line.indexOf("Metadata:") > -1) {
FFmpegMetaDataNr = FFmpegMetaDataNr + 1;
line = lines.get(FFmpegMetaDataNr);
while (line.indexOf(" ") == 0) {
if (line.toLowerCase().indexOf("title :") > -1) {
int aa = line.indexOf(": ");
int bb = line.length();
if (aa > -1 && bb > aa) {
lang.setFlavor(line.substring(aa+2, bb));
break;
}
} else {
FFmpegMetaDataNr = FFmpegMetaDataNr + 1;
line = lines.get(FFmpegMetaDataNr);
}
}
}
getSubtitleTracksList().add(lang);
}
}
}
}
if (!thumbOnly
&& getContainer() != null
&& inputFile.getFile() != null
&& getContainer().equals("mpegts")
&& isH264()
&& getDurationInSeconds() == 0) {
// Parse the duration
try {
int length = MpegUtil.getDurationFromMpeg(inputFile.getFile());
if (length > 0) {
setDuration((double) length);
}
} catch (IOException e) {
logger.trace("Error retrieving length: " + e.getMessage());
}
}
if (configuration.isUseMplayerForVideoThumbs() && type == Format.VIDEO && !dvrms) {
try {
getMplayerThumbnail(inputFile);
String frameName = "" + inputFile.hashCode();
frameName = configuration.getTempFolder() + "/mplayer_thumbs/" + frameName + "00000001/00000001.jpg";
frameName = frameName.replace(',', '_');
File jpg = new File(frameName);
if (jpg.exists()) {
InputStream is = new FileInputStream(jpg);
int sz = is.available();
if (sz > 0) {
setThumb(new byte[sz]);
is.read(getThumb());
}
is.close();
if (!jpg.delete()) {
jpg.deleteOnExit();
}
// Try and retry
if (!jpg.getParentFile().delete() && !jpg.getParentFile().delete()) {
logger.debug("Failed to delete \"" + jpg.getParentFile().getAbsolutePath() + "\"");
}
}
} catch (IOException e) {
logger.debug("Caught exception", e);
}
}
if (type == Format.VIDEO && pw != null && getThumb() == null) {
InputStream is;
try {
is = pw.getInputStream(0);
int sz = is.available();
if (sz > 0) {
setThumb(new byte[sz]);
is.read(getThumb());
}