Search in sources :

Example 1 with StreamType

use of net.pms.dlna.MediaInfo.StreamType in project UniversalMediaServer by UniversalMediaServer.

the class LibMediaInfoParser method parse.

/**
 * Parse media via MediaInfo.
 */
public static synchronized void parse(DLNAMediaInfo media, InputFile inputFile, int type, RendererConfiguration renderer) {
    File file = inputFile.getFile();
    if (!media.isMediaparsed() && file != null && MI.isValid() && MI.Open(file.getAbsolutePath()) > 0) {
        StreamType general = StreamType.General;
        StreamType video = StreamType.Video;
        StreamType audio = StreamType.Audio;
        StreamType image = StreamType.Image;
        StreamType text = StreamType.Text;
        DLNAMediaAudio currentAudioTrack = new DLNAMediaAudio();
        DLNAMediaSubtitle currentSubTrack;
        media.setSize(file.length());
        String value;
        // set General
        getFormat(general, media, currentAudioTrack, MI.Get(general, 0, "Format"), file);
        getFormat(general, media, currentAudioTrack, MI.Get(general, 0, "CodecID").trim(), file);
        media.setDuration(getDuration(MI.Get(general, 0, "Duration/String1")));
        media.setBitrate(getBitrate(MI.Get(general, 0, "OverallBitRate")));
        media.setStereoscopy(MI.Get(general, 0, "StereoscopicLayout"));
        value = MI.Get(general, 0, "Cover_Data");
        if (!value.isEmpty()) {
            try {
                media.setThumb(DLNAThumbnail.toThumbnail(new Base64().decode(value.getBytes(StandardCharsets.US_ASCII)), 640, 480, ScaleType.MAX, ImageFormat.SOURCE, false));
            } catch (EOFException e) {
                LOGGER.debug("Error reading \"{}\" thumbnail from MediaInfo: Unexpected end of stream, probably corrupt or read error.", file.getName());
            } catch (UnknownFormatException e) {
                LOGGER.debug("Could not read \"{}\" thumbnail from MediaInfo: {}", file.getName(), e.getMessage());
            } catch (IOException e) {
                LOGGER.error("Error reading \"{}\" thumbnail from MediaInfo: {}", file.getName(), e.getMessage());
                LOGGER.trace("", e);
            }
        }
        value = MI.Get(general, 0, "Title");
        if (!value.isEmpty()) {
            media.setFileTitleFromMetadata(value);
        }
        // set Video
        media.setVideoTrackCount(MI.Count_Get(video));
        if (media.getVideoTrackCount() > 0) {
            for (int i = 0; i < media.getVideoTrackCount(); i++) {
                // check for DXSA and DXSB subtitles (subs in video format)
                if (MI.Get(video, i, "Title").startsWith("Subtitle")) {
                    currentSubTrack = new DLNAMediaSubtitle();
                    // First attempt to detect subtitle track format
                    currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(video, i, "Format")));
                    // Second attempt to detect subtitle track format (CodecID usually is more accurate)
                    currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(video, i, "CodecID")));
                    currentSubTrack.setId(media.getSubtitleTracksList().size());
                    addSub(currentSubTrack, media);
                } else {
                    getFormat(video, media, currentAudioTrack, MI.Get(video, i, "Format"), file);
                    getFormat(video, media, currentAudioTrack, MI.Get(video, i, "Format_Version"), file);
                    getFormat(video, media, currentAudioTrack, MI.Get(video, i, "CodecID"), file);
                    media.setWidth(getPixelValue(MI.Get(video, i, "Width")));
                    media.setHeight(getPixelValue(MI.Get(video, i, "Height")));
                    media.setMatrixCoefficients(MI.Get(video, i, "matrix_coefficients"));
                    if (!media.is3d()) {
                        media.setStereoscopy(MI.Get(video, i, "MultiView_Layout"));
                    }
                    media.setAspectRatioContainer(MI.Get(video, i, "DisplayAspectRatio/String"));
                    media.setAspectRatioVideoTrack(MI.Get(video, i, "DisplayAspectRatio_Original/String"));
                    media.setFrameRate(getFPSValue(MI.Get(video, i, "FrameRate")));
                    media.setFrameRateOriginal(MI.Get(video, i, "FrameRate_Original"));
                    media.setFrameRateMode(getFrameRateModeValue(MI.Get(video, i, "FrameRate_Mode")));
                    media.setFrameRateModeRaw(MI.Get(video, i, "FrameRate_Mode"));
                    media.setReferenceFrameCount(getReferenceFrameCount(MI.Get(video, i, "Format_Settings_RefFrames/String")));
                    media.setVideoTrackTitleFromMetadata(MI.Get(video, i, "Title"));
                    value = MI.Get(video, i, "Format_Settings_QPel");
                    if (!value.isEmpty()) {
                        media.putExtra(FormatConfiguration.MI_QPEL, value);
                    }
                    value = MI.Get(video, i, "Format_Settings_GMC");
                    if (!value.isEmpty()) {
                        media.putExtra(FormatConfiguration.MI_GMC, value);
                    }
                    value = MI.Get(video, i, "Format_Settings_GOP");
                    if (!value.isEmpty()) {
                        media.putExtra(FormatConfiguration.MI_GOP, value);
                    }
                    media.setMuxingMode(MI.Get(video, i, "MuxingMode"));
                    if (!media.isEncrypted()) {
                        media.setEncrypted("encrypted".equals(MI.Get(video, i, "Encryption")));
                    }
                    value = MI.Get(video, i, "BitDepth");
                    if (!value.isEmpty()) {
                        try {
                            media.setVideoBitDepth(Integer.parseInt(value));
                        } catch (NumberFormatException nfe) {
                            LOGGER.debug("Could not parse bits per sample \"" + value + "\"");
                        }
                    }
                    value = MI.Get(video, i, "Format_Profile");
                    if (!value.isEmpty() && media.getCodecV() != null && media.getCodecV().equals(FormatConfiguration.H264)) {
                        media.setAvcLevel(getAvcLevel(value));
                    }
                }
            }
        }
        // set Audio
        int audioTracks = MI.Count_Get(audio);
        if (audioTracks > 0) {
            for (int i = 0; i < audioTracks; i++) {
                currentAudioTrack = new DLNAMediaAudio();
                getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format"), file);
                getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format_Version"), file);
                getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format_Profile"), file);
                getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "CodecID"), file);
                value = MI.Get(audio, i, "CodecID_Description");
                if (isNotBlank(value) && value.startsWith("Windows Media Audio 10")) {
                    currentAudioTrack.setCodecA(FormatConfiguration.WMA10);
                }
                currentAudioTrack.setLang(getLang(MI.Get(audio, i, "Language/String")));
                currentAudioTrack.setAudioTrackTitleFromMetadata((MI.Get(audio, i, "Title")).trim());
                currentAudioTrack.getAudioProperties().setNumberOfChannels(MI.Get(audio, i, "Channel(s)"));
                currentAudioTrack.setSampleFrequency(getSampleFrequency(MI.Get(audio, i, "SamplingRate")));
                currentAudioTrack.setBitRate(getBitrate(MI.Get(audio, i, "BitRate")));
                currentAudioTrack.setSongname(MI.Get(general, 0, "Track"));
                if (renderer.isPrependTrackNumbers() && currentAudioTrack.getTrack() > 0 && currentAudioTrack.getSongname() != null && currentAudioTrack.getSongname().length() > 0) {
                    currentAudioTrack.setSongname(currentAudioTrack.getTrack() + ": " + currentAudioTrack.getSongname());
                }
                currentAudioTrack.setAlbum(MI.Get(general, 0, "Album"));
                currentAudioTrack.setArtist(MI.Get(general, 0, "Performer"));
                currentAudioTrack.setGenre(MI.Get(general, 0, "Genre"));
                // Try to parse the year from the stored date
                String recordedDate = MI.Get(general, 0, "Recorded_Date");
                Matcher matcher = yearPattern.matcher(recordedDate);
                if (matcher.matches()) {
                    try {
                        currentAudioTrack.setYear(Integer.parseInt(matcher.group(1)));
                    } catch (NumberFormatException nfe) {
                        LOGGER.debug("Could not parse year from recorded date \"" + recordedDate + "\"");
                    }
                }
                // Special check for OGM: MediaInfo reports specific Audio/Subs IDs (0xn) while mencoder does not
                value = MI.Get(audio, i, "ID/String");
                if (!value.isEmpty()) {
                    if (value.contains("(0x") && !FormatConfiguration.OGG.equals(media.getContainer())) {
                        currentAudioTrack.setId(getSpecificID(value));
                    } else {
                        currentAudioTrack.setId(media.getAudioTracksList().size());
                    }
                }
                value = MI.Get(general, i, "Track/Position");
                if (!value.isEmpty()) {
                    try {
                        currentAudioTrack.setTrack(Integer.parseInt(value));
                    } catch (NumberFormatException nfe) {
                        LOGGER.debug("Could not parse track \"" + value + "\"");
                    }
                }
                value = MI.Get(audio, i, "BitDepth");
                if (!value.isEmpty()) {
                    try {
                        currentAudioTrack.setBitsperSample(Integer.parseInt(value));
                    } catch (NumberFormatException nfe) {
                        LOGGER.debug("Could not parse bits per sample \"" + value + "\"");
                    }
                }
                addAudio(currentAudioTrack, media);
            }
        }
        // set Image
        media.setImageCount(MI.Count_Get(image));
        if (media.getImageCount() > 0 || type == Format.IMAGE) {
            boolean parseByMediainfo = false;
            // For images use our own parser instead of MediaInfo which doesn't provide enough information
            try {
                ImagesUtil.parseImage(file, media);
                // so that MI.Count_Get(image) might return 0 even if there is an image.
                if (media.getImageCount() == 0) {
                    media.setImageCount(1);
                }
            } catch (IOException e) {
                if (media.getImageCount() > 0) {
                    LOGGER.debug("Error parsing image ({}), switching to MediaInfo: {}", file.getAbsolutePath(), e.getMessage());
                    LOGGER.trace("", e);
                    parseByMediainfo = true;
                } else {
                    LOGGER.warn("Image parsing for \"{}\" failed both with MediaInfo and internally: {}", file.getAbsolutePath(), e.getMessage());
                    LOGGER.trace("", e);
                    media.setImageCount(1);
                }
            }
            if (parseByMediainfo) {
                getFormat(image, media, currentAudioTrack, MI.Get(image, 0, "Format"), file);
                media.setWidth(getPixelValue(MI.Get(image, 0, "Width")));
                media.setHeight(getPixelValue(MI.Get(image, 0, "Height")));
            }
        }
        // set Subs in text format
        int subTracks = MI.Count_Get(text);
        if (subTracks > 0) {
            for (int i = 0; i < subTracks; i++) {
                currentSubTrack = new DLNAMediaSubtitle();
                currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(text, i, "Format")));
                currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(text, i, "CodecID")));
                currentSubTrack.setLang(getLang(MI.Get(text, i, "Language/String")));
                currentSubTrack.setSubtitlesTrackTitleFromMetadata((MI.Get(text, i, "Title")).trim());
                // Special check for OGM: MediaInfo reports specific Audio/Subs IDs (0xn) while mencoder does not
                value = MI.Get(text, i, "ID/String");
                if (!value.isEmpty()) {
                    if (value.contains("(0x") && !FormatConfiguration.OGG.equals(media.getContainer())) {
                        currentSubTrack.setId(getSpecificID(value));
                    } else {
                        currentSubTrack.setId(media.getSubtitleTracksList().size());
                    }
                }
                addSub(currentSubTrack, media);
            }
        }
        /*
			 * Some container formats (like MP4/M4A) can represent both audio
			 * and video media. UMS initially recognized this as video, but this
			 * is corrected here it the content is only audio.
			 */
        if (media.isAudioOrVideoContainer() && media.isAudio()) {
            media.setContainer(media.getAudioVariantFormatConfigurationString());
        }
        /*
			 * Recognize 3D layout from the filename.
			 *
			 * First we check for our custom naming convention, for which the filename
			 * either has to start with "3DSBSLF" or "3DSBSRF" for side-by-side layout
			 * or "3DOULF" or "3DOURF" for over-under layout.
			 * For anaglyph 3D video can be used following combination:
			 * 		3DARCG 	anaglyph_red_cyan_gray
			 *		3DARCH 	anaglyph_red_cyan_half_color
			 *		3DARCC 	anaglyph_red_cyan_color
			 *		3DARCD 	anaglyph_red_cyan_dubois
			 *		3DAGMG 	anaglyph_green_magenta_gray
			 *		3DAGMH 	anaglyph_green_magenta_half_color
			 *		3DAGMC 	anaglyph_green_magenta_color
			 *		3DAGMD 	anaglyph_green_magenta_dubois
			 *		3DAYBG 	anaglyph_yellow_blue_gray
			 *		3DAYBH 	anaglyph_yellow_blue_half_color
			 *		3DAYBC 	anaglyph_yellow_blue_color
			 *		3DAYBD 	anaglyph_yellow_blue_dubois
			 *
			 * Next we check for common naming conventions.
			 */
        if (!media.is3d()) {
            String upperCaseFileName = file.getName().toUpperCase();
            if (upperCaseFileName.startsWith("3DSBS")) {
                LOGGER.debug("3D format SBS detected for " + file.getName());
                media.setStereoscopy(file.getName().substring(2, 7));
            } else if (upperCaseFileName.startsWith("3DOU")) {
                LOGGER.debug("3D format OU detected for " + file.getName());
                media.setStereoscopy(file.getName().substring(2, 6));
            } else if (upperCaseFileName.startsWith("3DA")) {
                LOGGER.debug("3D format Anaglyph detected for " + file.getName());
                media.setStereoscopy(file.getName().substring(2, 6));
            } else if (upperCaseFileName.matches(".*[\\s\\.](H-|H|HALF-|HALF.)SBS[\\s\\.].*")) {
                LOGGER.debug("3D format HSBS detected for " + file.getName());
                media.setStereoscopy("half side by side (left eye first)");
            } else if (upperCaseFileName.matches(".*[\\s\\.](H-|H|HALF-|HALF.)(OU|TB)[\\s\\.].*")) {
                LOGGER.debug("3D format HOU detected for " + file.getName());
                media.setStereoscopy("half top-bottom (left eye first)");
            } else if (upperCaseFileName.matches(".*[\\s\\.]SBS[\\s\\.].*")) {
                if (media.getWidth() > 1920) {
                    LOGGER.debug("3D format SBS detected for " + file.getName());
                    media.setStereoscopy("side by side (left eye first)");
                } else {
                    LOGGER.debug("3D format HSBS detected based on width for " + file.getName());
                    media.setStereoscopy("half side by side (left eye first)");
                }
            } else if (upperCaseFileName.matches(".*[\\s\\.](OU|TB)[\\s\\.].*")) {
                if (media.getHeight() > 1080) {
                    LOGGER.debug("3D format OU detected for " + file.getName());
                    media.setStereoscopy("top-bottom (left eye first)");
                } else {
                    LOGGER.debug("3D format HOU detected based on height for " + file.getName());
                    media.setStereoscopy("half top-bottom (left eye first)");
                }
            }
        }
        media.postParse(type, inputFile);
        MI.Close();
        if (media.getContainer() == null) {
            media.setContainer(DLNAMediaLang.UND);
        }
        if (media.getCodecV() == null) {
            media.setCodecV(DLNAMediaLang.UND);
        }
        media.setMediaparsed(true);
    }
}
Also used : StreamType(net.pms.dlna.MediaInfo.StreamType) Base64(org.apache.commons.codec.binary.Base64) Matcher(java.util.regex.Matcher) IOException(java.io.IOException) EOFException(java.io.EOFException) UnknownFormatException(net.pms.util.UnknownFormatException) File(java.io.File)

Aggregations

EOFException (java.io.EOFException)1 File (java.io.File)1 IOException (java.io.IOException)1 Matcher (java.util.regex.Matcher)1 StreamType (net.pms.dlna.MediaInfo.StreamType)1 UnknownFormatException (net.pms.util.UnknownFormatException)1 Base64 (org.apache.commons.codec.binary.Base64)1