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;
}
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);
}
}
}
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);
}
}
}
Aggregations