Search in sources :

Example 1 with MediaContainerMetadata

use of org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata in project opencast by opencast.

the class FFmpegAnalyzer method analyze.

@Override
public MediaContainerMetadata analyze(File media) throws MediaAnalyzerException {
    if (binary == null)
        throw new IllegalStateException("Binary is not set");
    List<String> command = new ArrayList<>();
    command.add("-show_format");
    command.add("-show_streams");
    if (accurateFrameCount)
        command.add("-count_frames");
    command.add("-of");
    command.add("json");
    command.add(media.getAbsolutePath().replaceAll(" ", "\\ "));
    String commandline = StringUtils.join(command, " ");
    /* Execute ffprobe and obtain the result */
    logger.debug("Running {} {}", binary, commandline);
    MediaContainerMetadata metadata = new MediaContainerMetadata();
    final StringBuilder sb = new StringBuilder();
    try {
        ProcessInfo info = ProcessRunner.mk(binary, command.toArray(new String[command.size()]));
        int exitCode = ProcessRunner.run(info, new Pred<String>() {

            @Override
            public Boolean apply(String s) {
                logger.debug(s);
                sb.append(s);
                sb.append(System.getProperty("line.separator"));
                return true;
            }
        }, fnLogError);
        // Windows binary will return -1 when queried for options
        if (exitCode != -1 && exitCode != 0 && exitCode != 255)
            throw new MediaAnalyzerException("Frame analyzer " + binary + " exited with code " + exitCode);
    } catch (IOException e) {
        logger.error("Error executing ffprobe: {}", ExceptionUtils.getStackTrace(e));
        throw new MediaAnalyzerException("Error while running ffprobe " + binary, e);
    }
    JSONParser parser = new JSONParser();
    try {
        JSONObject jsonObject = (JSONObject) parser.parse(sb.toString());
        Object obj;
        Double duration;
        /* Get format specific stuff */
        JSONObject jsonFormat = (JSONObject) jsonObject.get("format");
        /* File Name */
        obj = jsonFormat.get("filename");
        if (obj != null) {
            metadata.setFileName((String) obj);
        }
        /* Format */
        obj = jsonFormat.get("format_long_name");
        if (obj != null) {
            metadata.setFormat((String) obj);
        }
        /*
       * Mediainfo does not return a duration if there is no stream but FFprobe will return 0. For compatibility
       * reasons, check if there are any streams before reading the duration:
       */
        obj = jsonFormat.get("nb_streams");
        if (obj != null && (Long) obj > 0) {
            obj = jsonFormat.get("duration");
            if (obj != null) {
                duration = new Double((String) obj) * 1000;
                metadata.setDuration(duration.longValue());
            }
        }
        /* File Size */
        obj = jsonFormat.get("size");
        if (obj != null) {
            metadata.setSize(new Long((String) obj));
        }
        /* Bitrate */
        obj = jsonFormat.get("bit_rate");
        if (obj != null) {
            metadata.setBitRate(new Float((String) obj));
        }
        /* Loop through streams */
        /*
       * FFprobe will return an empty stream array if there are no streams. Thus we do not need to check.
       */
        JSONArray streams = (JSONArray) jsonObject.get("streams");
        Iterator<JSONObject> iterator = streams.iterator();
        while (iterator.hasNext()) {
            JSONObject stream = iterator.next();
            /* Check type of string */
            String codecType = (String) stream.get("codec_type");
            if ("audio".equals(codecType)) {
                /* Extract audio stream metadata */
                AudioStreamMetadata aMetadata = new AudioStreamMetadata();
                /* Codec */
                obj = stream.get("codec_long_name");
                if (obj != null) {
                    aMetadata.setFormat((String) obj);
                }
                /* Duration */
                obj = stream.get("duration");
                if (obj != null) {
                    duration = new Double((String) obj) * 1000;
                    aMetadata.setDuration(duration.longValue());
                } else {
                    /*
             * If no duration for this stream is specified assume the duration of the file for this as well.
             */
                    aMetadata.setDuration(metadata.getDuration());
                }
                /* Bitrate */
                obj = stream.get("bit_rate");
                if (obj != null) {
                    aMetadata.setBitRate(new Float((String) obj));
                }
                /* Channels */
                obj = stream.get("channels");
                if (obj != null) {
                    aMetadata.setChannels(((Long) obj).intValue());
                }
                /* Sample Rate */
                obj = stream.get("sample_rate");
                if (obj != null) {
                    aMetadata.setSamplingRate(Integer.parseInt((String) obj));
                }
                /* Frame Count */
                obj = stream.get("nb_read_frames");
                if (obj != null) {
                    aMetadata.setFrames(Long.parseLong((String) obj));
                } else {
                    /* alternate JSON element if accurate frame count is not requested from ffmpeg */
                    obj = stream.get("nb_frames");
                    if (obj != null) {
                        aMetadata.setFrames(Long.parseLong((String) obj));
                    }
                }
                /* Add video stream metadata to overall metadata */
                metadata.getAudioStreamMetadata().add(aMetadata);
            /* Handle video streams ----------------------------- */
            } else if ("video".equals(codecType)) {
                /* Extract video stream metadata */
                VideoStreamMetadata vMetadata = new VideoStreamMetadata();
                /* Codec */
                obj = stream.get("codec_long_name");
                if (obj != null) {
                    vMetadata.setFormat((String) obj);
                }
                /* Duration */
                obj = stream.get("duration");
                if (obj != null) {
                    duration = new Double((String) obj) * 1000;
                    vMetadata.setDuration(duration.longValue());
                } else {
                    /*
             * If no duration for this stream is specified assume the duration of the file for this as well.
             */
                    vMetadata.setDuration(metadata.getDuration());
                }
                /* Bitrate */
                obj = stream.get("bit_rate");
                if (obj != null) {
                    vMetadata.setBitRate(new Float((String) obj));
                }
                /* Width */
                obj = stream.get("width");
                if (obj != null) {
                    vMetadata.setFrameWidth(((Long) obj).intValue());
                }
                /* Height */
                obj = stream.get("height");
                if (obj != null) {
                    vMetadata.setFrameHeight(((Long) obj).intValue());
                }
                /* Profile */
                obj = stream.get("profile");
                if (obj != null) {
                    vMetadata.setFormatProfile((String) obj);
                }
                /* Aspect Ratio */
                obj = stream.get("sample_aspect_ratio");
                if (obj != null) {
                    vMetadata.setPixelAspectRatio(parseFloat((String) obj));
                }
                /* Frame Rate */
                obj = stream.get("avg_frame_rate");
                if (obj != null) {
                    vMetadata.setFrameRate(parseFloat((String) obj));
                }
                /* Frame Count */
                obj = stream.get("nb_read_frames");
                if (obj != null) {
                    vMetadata.setFrames(Long.parseLong((String) obj));
                } else {
                    /* alternate JSON element if accurate frame count is not requested from ffmpeg */
                    obj = stream.get("nb_frames");
                    if (obj != null) {
                        vMetadata.setFrames(Long.parseLong((String) obj));
                    }
                }
                /* Add video stream metadata to overall metadata */
                metadata.getVideoStreamMetadata().add(vMetadata);
            }
        }
    } catch (ParseException e) {
        logger.error("Error parsing ffprobe output: {}", e.getMessage());
    }
    return metadata;
}
Also used : MediaContainerMetadata(org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata) ArrayList(java.util.ArrayList) JSONArray(org.json.simple.JSONArray) ProcessInfo(org.opencastproject.util.ProcessRunner.ProcessInfo) IOException(java.io.IOException) VideoStreamMetadata(org.opencastproject.inspection.ffmpeg.api.VideoStreamMetadata) JSONObject(org.json.simple.JSONObject) MediaAnalyzerException(org.opencastproject.inspection.ffmpeg.api.MediaAnalyzerException) AudioStreamMetadata(org.opencastproject.inspection.ffmpeg.api.AudioStreamMetadata) JSONParser(org.json.simple.parser.JSONParser) JSONObject(org.json.simple.JSONObject) ParseException(org.json.simple.parser.ParseException)

Example 2 with MediaContainerMetadata

use of org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata in project opencast by opencast.

the class MediaInspector method enrichTrack.

/**
 * Enriches the track's metadata and can be executed in an asynchronous way.
 *
 * @param originalTrack
 *          the original track
 * @param override
 *          <code>true</code> to override existing metadata
 * @return the media package element
 * @throws MediaInspectionException
 */
private MediaPackageElement enrichTrack(final Track originalTrack, final boolean override, final Map<String, String> options) throws MediaInspectionException {
    try {
        URI originalTrackUrl = originalTrack.getURI();
        MediaPackageElementFlavor flavor = originalTrack.getFlavor();
        logger.debug("enrich(" + originalTrackUrl + ") called");
        // Get the file from the URL
        File file = null;
        try {
            file = workspace.get(originalTrackUrl);
        } catch (NotFoundException e) {
            throw new MediaInspectionException("File " + originalTrackUrl + " was not found and can therefore not be " + "inspected", e);
        } catch (IOException e) {
            throw new MediaInspectionException("Error accessing " + originalTrackUrl, e);
        }
        // TODO: Try to guess the extension from the container's metadata
        if ("".equals(FilenameUtils.getExtension(file.getName()))) {
            throw new MediaInspectionException("Can not inspect files without a filename extension");
        }
        MediaContainerMetadata metadata = getFileMetadata(file, getAccurateFrameCount(options));
        if (metadata == null) {
            throw new MediaInspectionException("Unable to acquire media metadata for " + originalTrackUrl);
        } else {
            TrackImpl track = null;
            try {
                track = (TrackImpl) MediaPackageElementBuilderFactory.newInstance().newElementBuilder().elementFromURI(originalTrackUrl, MediaPackageElement.Type.Track, flavor);
            } catch (UnsupportedElementException e) {
                throw new MediaInspectionException("Unable to create track element from " + file, e);
            }
            // init the new track with old
            track.setChecksum(originalTrack.getChecksum());
            track.setDuration(originalTrack.getDuration());
            track.setElementDescription(originalTrack.getElementDescription());
            track.setFlavor(flavor);
            track.setIdentifier(originalTrack.getIdentifier());
            track.setMimeType(originalTrack.getMimeType());
            track.setReference(originalTrack.getReference());
            track.setSize(file.length());
            track.setURI(originalTrackUrl);
            for (String tag : originalTrack.getTags()) {
                track.addTag(tag);
            }
            // enrich the new track with basic info
            if (track.getDuration() == null || override)
                track.setDuration(metadata.getDuration());
            if (track.getChecksum() == null || override) {
                try {
                    track.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, file));
                } catch (IOException e) {
                    throw new MediaInspectionException("Unable to read " + file, e);
                }
            }
            // Add the mime type if it's not already present
            if (track.getMimeType() == null || override) {
                try {
                    MimeType mimeType = MimeTypes.fromURI(track.getURI());
                    // The mimetype library doesn't know about audio/video metadata, so the type might be wrong.
                    if ("audio".equals(mimeType.getType()) && metadata.hasVideoStreamMetadata()) {
                        mimeType = MimeTypes.parseMimeType("video/" + mimeType.getSubtype());
                    } else if ("video".equals(mimeType.getType()) && !metadata.hasVideoStreamMetadata()) {
                        mimeType = MimeTypes.parseMimeType("audio/" + mimeType.getSubtype());
                    }
                    track.setMimeType(mimeType);
                } catch (UnknownFileTypeException e) {
                    logger.info("Unable to detect the mimetype for track {} at {}", track.getIdentifier(), track.getURI());
                }
            }
            // find all streams
            Dictionary<String, Stream> streamsId2Stream = new Hashtable<String, Stream>();
            for (Stream stream : originalTrack.getStreams()) {
                streamsId2Stream.put(stream.getIdentifier(), stream);
            }
            // audio list
            try {
                addAudioStreamMetadata(track, metadata);
            } catch (Exception e) {
                throw new MediaInspectionException("Unable to extract audio metadata from " + file, e);
            }
            // video list
            try {
                addVideoStreamMetadata(track, metadata);
            } catch (Exception e) {
                throw new MediaInspectionException("Unable to extract video metadata from " + file, e);
            }
            logger.info("Successfully inspected track {}", track);
            return track;
        }
    } catch (Exception e) {
        logger.warn("Error enriching track " + originalTrack, e);
        if (e instanceof MediaInspectionException) {
            throw (MediaInspectionException) e;
        } else {
            throw new MediaInspectionException(e);
        }
    }
}
Also used : MediaContainerMetadata(org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata) TrackImpl(org.opencastproject.mediapackage.track.TrackImpl) Hashtable(java.util.Hashtable) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) URI(java.net.URI) MediaPackageElementFlavor(org.opencastproject.mediapackage.MediaPackageElementFlavor) MimeType(org.opencastproject.util.MimeType) MediaAnalyzerException(org.opencastproject.inspection.ffmpeg.api.MediaAnalyzerException) UnsupportedElementException(org.opencastproject.mediapackage.UnsupportedElementException) MediaInspectionException(org.opencastproject.inspection.api.MediaInspectionException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) UnknownFileTypeException(org.opencastproject.util.UnknownFileTypeException) MediaInspectionException(org.opencastproject.inspection.api.MediaInspectionException) UnsupportedElementException(org.opencastproject.mediapackage.UnsupportedElementException) UnknownFileTypeException(org.opencastproject.util.UnknownFileTypeException) Stream(org.opencastproject.mediapackage.Stream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) File(java.io.File)

Example 3 with MediaContainerMetadata

use of org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata in project opencast by opencast.

the class MediaInspector method inspectTrack.

/**
 * Inspects the element that is passed in as uri.
 *
 * @param trackURI
 *          the element uri
 * @return the inspected track
 * @throws org.opencastproject.inspection.api.MediaInspectionException
 *           if inspection fails
 */
public Track inspectTrack(URI trackURI, Map<String, String> options) throws MediaInspectionException {
    logger.debug("inspect(" + trackURI + ") called, using workspace " + workspace);
    throwExceptionIfInvalid(options);
    try {
        // Get the file from the URL (runtime exception if invalid)
        File file = null;
        try {
            file = workspace.get(trackURI);
        } catch (NotFoundException notFound) {
            throw new MediaInspectionException("Unable to find resource " + trackURI, notFound);
        } catch (IOException ioe) {
            throw new MediaInspectionException("Error reading " + trackURI + " from workspace", ioe);
        }
        // TODO: Try to guess the extension from the container's metadata
        if ("".equals(FilenameUtils.getExtension(file.getName()))) {
            throw new MediaInspectionException("Can not inspect files without a filename extension");
        }
        MediaContainerMetadata metadata = getFileMetadata(file, getAccurateFrameCount(options));
        if (metadata == null) {
            throw new MediaInspectionException("Media analyzer returned no metadata from " + file);
        } else {
            MediaPackageElementBuilder elementBuilder = MediaPackageElementBuilderFactory.newInstance().newElementBuilder();
            TrackImpl track;
            MediaPackageElement element;
            try {
                element = elementBuilder.elementFromURI(trackURI, MediaPackageElement.Type.Track, null);
            } catch (UnsupportedElementException e) {
                throw new MediaInspectionException("Unable to create track element from " + file, e);
            }
            track = (TrackImpl) element;
            // Duration
            if (metadata.getDuration() != null && metadata.getDuration() > 0)
                track.setDuration(metadata.getDuration());
            // Checksum
            try {
                track.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, file));
            } catch (IOException e) {
                throw new MediaInspectionException("Unable to read " + file, e);
            }
            // Mimetype
            InputStream is = null;
            try {
                // Try to get the Mimetype from Apache Tika
                is = new FileInputStream(file);
                MimeType mimeType = extractContentType(is);
                // If Mimetype could not be extracted try to get it from opencast
                if (mimeType == null) {
                    mimeType = MimeTypes.fromURL(file.toURI().toURL());
                    // The mimetype library doesn't know about audio/video metadata, so the type might be wrong.
                    if ("audio".equals(mimeType.getType()) && metadata.hasVideoStreamMetadata()) {
                        mimeType = MimeTypes.parseMimeType("video/" + mimeType.getSubtype());
                    } else if ("video".equals(mimeType.getType()) && !metadata.hasVideoStreamMetadata()) {
                        mimeType = MimeTypes.parseMimeType("audio/" + mimeType.getSubtype());
                    }
                }
                track.setMimeType(mimeType);
            } catch (Exception e) {
                logger.error("Unable to find mimetype for {}", file.getAbsolutePath());
            } finally {
                IoSupport.closeQuietly(is);
            }
            // Audio metadata
            try {
                addAudioStreamMetadata(track, metadata);
            } catch (Exception e) {
                throw new MediaInspectionException("Unable to extract audio metadata from " + file, e);
            }
            // Videometadata
            try {
                addVideoStreamMetadata(track, metadata);
            } catch (Exception e) {
                throw new MediaInspectionException("Unable to extract video metadata from " + file, e);
            }
            return track;
        }
    } catch (Exception e) {
        logger.warn("Error inspecting " + trackURI, e);
        if (e instanceof MediaInspectionException) {
            throw (MediaInspectionException) e;
        } else {
            throw new MediaInspectionException(e);
        }
    }
}
Also used : MediaContainerMetadata(org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata) TrackImpl(org.opencastproject.mediapackage.track.TrackImpl) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) MimeType(org.opencastproject.util.MimeType) MediaAnalyzerException(org.opencastproject.inspection.ffmpeg.api.MediaAnalyzerException) UnsupportedElementException(org.opencastproject.mediapackage.UnsupportedElementException) MediaInspectionException(org.opencastproject.inspection.api.MediaInspectionException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) UnknownFileTypeException(org.opencastproject.util.UnknownFileTypeException) MediaPackageElementBuilder(org.opencastproject.mediapackage.MediaPackageElementBuilder) MediaInspectionException(org.opencastproject.inspection.api.MediaInspectionException) UnsupportedElementException(org.opencastproject.mediapackage.UnsupportedElementException) MediaPackageElement(org.opencastproject.mediapackage.MediaPackageElement) File(java.io.File)

Aggregations

IOException (java.io.IOException)3 MediaAnalyzerException (org.opencastproject.inspection.ffmpeg.api.MediaAnalyzerException)3 MediaContainerMetadata (org.opencastproject.inspection.ffmpeg.api.MediaContainerMetadata)3 File (java.io.File)2 FileInputStream (java.io.FileInputStream)2 InputStream (java.io.InputStream)2 MediaInspectionException (org.opencastproject.inspection.api.MediaInspectionException)2 UnsupportedElementException (org.opencastproject.mediapackage.UnsupportedElementException)2 TrackImpl (org.opencastproject.mediapackage.track.TrackImpl)2 MimeType (org.opencastproject.util.MimeType)2 NotFoundException (org.opencastproject.util.NotFoundException)2 UnknownFileTypeException (org.opencastproject.util.UnknownFileTypeException)2 URI (java.net.URI)1 ArrayList (java.util.ArrayList)1 Hashtable (java.util.Hashtable)1 JSONArray (org.json.simple.JSONArray)1 JSONObject (org.json.simple.JSONObject)1 JSONParser (org.json.simple.parser.JSONParser)1 ParseException (org.json.simple.parser.ParseException)1 AudioStreamMetadata (org.opencastproject.inspection.ffmpeg.api.AudioStreamMetadata)1