/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.sequencer.video;
import io.humble.video.Decoder;
import io.humble.video.Demuxer;
import io.humble.video.DemuxerStream;
import io.humble.video.Global;
import io.humble.video.KeyValueBag;
import io.humble.video.MediaDescriptor.Type;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.modeshape.common.util.IoUtil;
/**
* Utility for extracting Metadata from video formats.
*
* @since 5.1
*/
public class VideoMetadata {
static final String[] MIME_TYPE_STRINGS = { "video/x-matroska", // mkv
"video/quicktime", // mov
"video/x-msvideo", // avi
"video/x-ms-wmv", // wmv
"video/x-flv", // flv
"video/3gpp", // 3gpp
"video/webm", // webp
"video/mp4", // mp4
"video/ogg" //ogg
};
private Double duration;
private Integer bitrate;
private String title;
private String comment;
private String encoder;
private List<StreamMetadata> streams = new ArrayList<>();
private InputStream in;
public VideoMetadata( InputStream inputStream ) {
this.in = inputStream;
}
/*
* Check that given file is supported by this sequencer.
*/
public boolean check() throws Exception {
// create a temporary copy from input
File fileCopy = File.createTempFile("modeshape-sequencer-video", ".tmp");
IoUtil.write(in, new BufferedOutputStream(new FileOutputStream(fileCopy)));
final Demuxer container = Demuxer.make();
container.open(fileCopy.getAbsolutePath(), null, false, true, null, null);
// try to delete the file immediately or on JVM exit
boolean deleted = false;
try {
deleted = fileCopy.delete();
} catch (SecurityException e) {
// ignore
}
if (!deleted) {
fileCopy.deleteOnExit();
}
KeyValueBag metadata = container.getMetaData();
for (String key : metadata.getKeys()) {
if (key.toLowerCase(Locale.ROOT).equals("title")) {
title = metadata.getValue(key);
}
if (key.toLowerCase(Locale.ROOT).equals("comment")) {
comment = metadata.getValue(key);
}
if (key.toLowerCase(Locale.ROOT).equals("encoder")) {
encoder = metadata.getValue(key);
}
}
if (container.getDuration() != Global.NO_PTS) {
// convert to seconds
duration = (float) container.getDuration() / 1000.0 / 1000.0;
}
if (container.getBitRate() > 0) {
bitrate = container.getBitRate();
}
for (int i = 0; i < container.getNumStreams(); i++) {
StreamMetadata streamMetadata = new StreamMetadata();
DemuxerStream stream = container.getStream(i);
Decoder coder = stream.getDecoder();
if (coder.getCodecType() == Type.MEDIA_AUDIO) {
streamMetadata.setStreamType("audio");
} else if (coder.getCodecType() == Type.MEDIA_VIDEO) {
streamMetadata.setStreamType("video");
} else {
streamMetadata.setStreamType("unknown");
}
if (coder.getCodec() != null) {
streamMetadata.setCodec(coder.getCodec().getName());
}
streamMetadata.setSamplerate(nullValueIfInvalid(coder.getSampleRate()));
streamMetadata.setChannels(nullValueIfInvalid(coder.getChannels()));
streamMetadata.setWidth(nullValueIfInvalid(coder.getWidth()));
streamMetadata.setHeight(nullValueIfInvalid(coder.getHeight()));
if (coder.getTimeBase() != null) {
streamMetadata.setFramerate(nullValueIfInvalid(1.0 / coder.getTimeBase().getDouble()));
}
streams.add(streamMetadata);
}
container.close();
return true;
}
private Integer nullValueIfInvalid( int value ) {
if (value > 0) {
return value;
} else {
return null;
}
}
private Double nullValueIfInvalid( double value ) {
if (value > 0) {
return value;
} else {
return null;
}
}
public Double getDuration() {
return duration;
}
public Integer getBitrate() {
return bitrate;
}
public String getTitle() {
return title;
}
public String getComment() {
return comment;
}
public String getEncoder() {
return encoder;
}
public List<StreamMetadata> getStreams() {
return streams;
}
}