我想从大约一半的时间点从视频中获取缩略图,我通过使用以下方法实现了这一点:
但是我的解决方案非常慢,实际上它会在视频中循环播放。对于较大的文件,这不是一个聪明的解决方案。
IContainer.seekKeyFrame 看起来对我的问题很有用。有人可以解释我如何为此目的使用 seekKeyFrame 吗?
我想从大约一半的时间点从视频中获取缩略图,我通过使用以下方法实现了这一点:
但是我的解决方案非常慢,实际上它会在视频中循环播放。对于较大的文件,这不是一个聪明的解决方案。
IContainer.seekKeyFrame 看起来对我的问题很有用。有人可以解释我如何为此目的使用 seekKeyFrame 吗?
我从第五秒开始修改代码并退出循环。不是最好的,而是一个可行的解决方案。
从任何持续时间创建视频的缩略图。
public class ThumbsGenerator {
private static void processFrame(IVideoPicture picture, BufferedImage image){
try {
File file=new File("C:\\snapshot\thimbnailpic.png");//name of pic
ImageIO.write(image, "png", file);
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public static void main(String[] args) throws NumberFormatException,IOException {
String filename = "your_video.mp4";
if (!IVideoResampler.isSupported(IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION))
throw new RuntimeException("you must install the GPL version of Xuggler (with IVideoResampler support) for this demo to work");
IContainer container = IContainer.make();
if (container.open(filename, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("could not open file: "
+ filename);
String seconds="20" //20 seconds
int numStreams = container.getNumStreams();
// and iterate through the streams to find the first video stream
int videoStreamId = -1;
IStreamCoder videoCoder = null;
for (int i = 0; i < numStreams; i++) {
// find the stream object
IStream stream = container.getStream(i);
// get the pre-configured decoder that can decode this stream;
IStreamCoder coder = stream.getStreamCoder();
if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
videoStreamId = i;
videoCoder = coder;
break;
}
}
if (videoStreamId == -1)
throw new RuntimeException(
"could not find video stream in container: " + filename);
if (videoCoder.open() < 0)
throw new RuntimeException(
"could not open video decoder for container: " + filename);
IVideoResampler resampler = null;
if (videoCoder.getPixelType() != IPixelFormat.Type.BGR24) {
resampler = IVideoResampler.make(videoCoder.getWidth(), videoCoder
.getHeight(), IPixelFormat.Type.BGR24, videoCoder
.getWidth(), videoCoder.getHeight(), videoCoder
.getPixelType());
if (resampler == null)
throw new RuntimeException(
"could not create color space resampler for: "
+ filename);
}
IPacket packet = IPacket.make();
IRational timeBase = container.getStream(videoStreamId).getTimeBase();
System.out.println("Timebase " + timeBase.toString());
long timeStampOffset = (timeBase.getDenominator() / timeBase.getNumerator())
* Integer.parseInt(seconds);
System.out.println("TimeStampOffset " + timeStampOffset);
long target = container.getStartTime() + timeStampOffset;
container.seekKeyFrame(videoStreamId, target, 0);
boolean isFinished = false;
while(container.readNextPacket(packet) >= 0 && !isFinished ) {
if (packet.getStreamIndex() == videoStreamId) {
IVideoPicture picture = IVideoPicture.make(videoCoder
.getPixelType(), videoCoder.getWidth(), videoCoder
.getHeight());
int offset = 0;
while (offset < packet.getSize()) {
int bytesDecoded = videoCoder.decodeVideo(picture, packet,
offset);
if (bytesDecoded < 0) {
System.err.println("WARNING!!! got no data decoding " +
"video in one packet");
}
offset += bytesDecoded;
picture from
if (picture.isComplete()) {
IVideoPicture newPic = picture;
if (resampler != null) {
newPic = IVideoPicture.make(resampler
.getOutputPixelFormat(), picture.getWidth(),
picture.getHeight());
if (resampler.resample(newPic, picture) < 0)
throw new RuntimeException(
"could not resample video from: "
+ filename);
}
if (newPic.getPixelType() != IPixelFormat.Type.BGR24)
throw new RuntimeException(
"could not decode video as BGR 24 bit data in: "
+ filename);
BufferedImage javaImage = Utils.videoPictureToImage(newPic);
processFrame(newPic, javaImage);
isFinished = true;
}
}
}
}
if (videoCoder != null) {
videoCoder.close();
videoCoder = null;
}
if (container != null) {
container.close();
container = null;
}
}