java - Humble Video 拍摄给定时间的快照
问题描述
您好,我正在使用https://github.com/artclarke/humble-video从视频中获取缩略图。到目前为止,我已经成功地通过以下方法从视频中拍摄了快照。
private static Path generateThumbnail(final Path videoFile) throws InterruptedException, IOException { final Demuxer demuxer = Demuxer.make(); demuxer.open(videoFile.toString(), null, false, true, null, null); int streamIndex = -1; Decoder videoDecoder = null; String rotate = null; final int numStreams = demuxer.getNumStreams(); for (int i = 0; i < numStreams; ++i) { final DemuxerStream stream = demuxer.getStream(i); final KeyValueBag metaData = stream.getMetaData(); final Decoder decoder = stream.getDecoder(); if (decoder != null && decoder.getCodecType() == MediaDescriptor.Type.MEDIA_VIDEO) { videoDecoder = decoder; streamIndex = i; rotate = metaData.getValue("rotate", KeyValueBag.Flags.KVB_NONE); break; } } if (videoDecoder == null) { throw new IOException("Not a valid video file"); } videoDecoder.open(null, null); final MediaPicture picture = MediaPicture.make(videoDecoder.getWidth(), videoDecoder.getHeight(), videoDecoder.getPixelFormat()); final MediaPictureConverter converter = MediaPictureConverterFactory .createConverter(MediaPictureConverterFactory.HUMBLE_BGR_24, picture); final MediaPacket packet = MediaPacket.make(); BufferedImage image = null; MUX : while (demuxer.read(packet) >= 0) { if (packet.getStreamIndex() != streamIndex) { continue; } int offset = 0; int bytesRead = 0; videoDecoder.decodeVideo(picture, packet, offset); do { bytesRead += videoDecoder.decode(picture, packet, offset); if (picture.isComplete()) { image = converter.toImage(null, picture); break MUX; } offset += bytesRead; } while (offset < packet.getSize()); } if (image == null) { throw new IOException("Unable to find a complete video frame"); } if (rotate != null) { final AffineTransform transform = new AffineTransform(); transform.translate(0.5 * image.getHeight(), 0.5 * image.getWidth()); transform.rotate(Math.toRadians(Double.parseDouble(rotate))); transform.translate(-0.5 * image.getWidth(), -0.5 * image.getHeight()); final AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); image = op.filter(image, null); } final Path target = videoFile.getParent() .resolve(videoFile.getFileName() + ".thumb.jpg"); final double mul; if (image.getWidth() > image.getHeight()) { mul = 216 / (double) image.getWidth(); } else { mul = 216 / (double) image.getHeight(); } final int newW = (int) (image.getWidth() * mul); final int newH = (int) (image.getHeight() * mul); final Image thumbnailImage = image.getScaledInstance(newW, newH, Image.SCALE_SMOOTH); image = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_BGR); final Graphics2D g2d = image.createGraphics(); g2d.drawImage(thumbnailImage, 0, 0, null); g2d.dispose(); ImageIO.write(image, "jpeg", target.toFile()); return target.toAbsolutePath(); }
现在,我想做的是在视频开始后 2 秒后拍摄快照,这可能吗?我曾尝试使用“Demuxer”-s seek 方法,但没有运气。
解决方案
我已经用下面的代码成功地做到了
图书馆的方法
public int seek(int stream_index, long min_ts, long ts, long max_ts, int flags);
参数是
- stream_index流的索引,用作时基参考
- min_ts可接受的最小时间戳
- ts目标时间戳
- max_ts最大可接受时间戳
我的实施是
final int success = demuxer.seek(streamIndex, 0, 700, 99999999,VideoJNI.Demuxer_SEEK_FRAME_get());
推荐阅读
- amazon-web-services - 下载以纪元时间为文件名的 S3 文件
- javascript - MongoError:集合名称必须是字符串 - 即使我已经指定了字符串
- c - 如何处理以下错误代码:
- jquery - 如果这是空的(jQuery),则在 prev() 上设置类
- string - 有没有办法优化 KMP 算法以涉及我们正在比较的字符?
- swift - 全局变量/常量如何在 swift 中变得懒惰
- mongodb - CentOS for MongoDB 进程上的 bindIP 退出并显示错误代码
- java - 在 Spring Boot 中将文本值传递给 thymeleaf 视图
- c# - 单击该行时,DATAGRIDVIEW(允许用户添加行)被设置为空白
- javascript - 为什么将对象设置为不可扩展使其 [[prototype]] 不可变?