private void decodeLeadingFrames() throws IOException, JCodecException { SeekableDemuxerTrack sdt = sdt(); int curFrame = (int) sdt.getCurFrame(); int keyFrame = detectKeyFrame(curFrame); sdt.gotoFrame(keyFrame); Packet frame = sdt.nextFrame(); if (decoder == null) decoder = detectDecoder(sdt); while (frame.getFrameNo() < curFrame) { decoder.decodeFrame(frame, getBuffer()); frame = sdt.nextFrame(); } sdt.gotoFrame(curFrame); }
private int detectKeyFrame(int start) throws IOException { int[] seekFrames = videoTrack.getMeta().getSeekFrames(); if (seekFrames == null) return start; int prev = seekFrames[0]; for (int i = 1; i < seekFrames.length; i++) { if (seekFrames[i] > start) break; prev = seekFrames[i]; } return prev; }
/** * Seeks to a previous key frame prior or on the given frame, if the track is * not seekable returns 0. * * @param frame * A frame to seek * @return Frame number of a key frame or 0 if the track is not seekable. * @throws IOException */ protected int seekToKeyFrame(int frame) throws IOException { if (videoInputTrack instanceof SeekableDemuxerTrack) { SeekableDemuxerTrack seekable = (SeekableDemuxerTrack) videoInputTrack; seekable.gotoSyncFrame(frame); return (int) seekable.getCurFrame(); } else { Logger.warn("Can not seek in " + videoInputTrack + " container."); return -1; } }
private void goToPrevKeyframe() throws IOException, JCodecException { sdt().gotoFrame(detectKeyFrame((int) sdt().getCurFrame())); }
ByteBuffer codecPrivate = inTrack.getMeta().getCodecPrivate(); H264Decoder decoder = H264Decoder.createH264DecoderFromCodecPrivate(codecPrivate); inTrack.gotoFrame(sf); while ((inFrame = inTrack.nextFrame()) != null && !inFrame.isKeyFrame()) inTrack.gotoFrame(inFrame.getFrameNo()); int totalFrames = (int) inTrack.getMeta().getTotalFrames(), seqNo = 0; for (int i = sf; (inFrame = inTrack.nextFrame()) != null; i++) { ByteBuffer data = inFrame.getData(); List<ByteBuffer> nalUnits = H264Utils.splitFrame(data); Size size = inTrack.getMeta().getVideoCodecMeta().getSize();
/** * Get frame at current position in JCodec native image * * @return A decoded picture with metadata. * @throws IOException */ public PictureWithMetadata getNativeFrameWithMetadata() throws IOException { Packet frame = videoTrack.nextFrame(); if (frame == null) return null; Picture picture = decoder.decodeFrame(frame, getBuffer()); return new PictureWithMetadata(picture, frame.getPtsD(), frame.getDurationD(), videoTrack.getMeta().getOrientation()); }
/** * Position frame grabber to a specific frame in a movie. As a result the * next decoded frame will be precisely the requested frame number. * * WARNING: potentially very slow. Use only when you absolutely need precise * seek. Tries to seek to exactly the requested frame and for this it might * have to decode a sequence of frames from the closes key frame. Depending * on GOP structure this may be as many as 500 frames. * * @param frameNumber * @return * @throws IOException * @throws JCodecException */ public FrameGrab seekToFramePrecise(int frameNumber) throws IOException, JCodecException { sdt().gotoFrame(frameNumber); decodeLeadingFrames(); return this; }
/** * Position frame grabber to a specific second in a movie. As a result the * next decoded frame will be precisely at the requested second. * * WARNING: potentially very slow. Use only when you absolutely need precise * seek. Tries to seek to exactly the requested second and for this it might * have to decode a sequence of frames from the closes key frame. Depending * on GOP structure this may be as many as 500 frames. * * @param second * @return * @throws IOException * @throws JCodecException */ public FrameGrab seekToSecondPrecise(double second) throws IOException, JCodecException { sdt().seek(second); decodeLeadingFrames(); return this; }
/** * Get frame at current position in JCodec native image * * @return * @throws IOException */ public Picture getNativeFrame() throws IOException { Packet frame = videoTrack.nextFrame(); if (frame == null) return null; return decoder.decodeFrame(frame, getBuffer()); }
/** * Position frame grabber to a specific frame in a movie * * Performs a sloppy seek, meaning that it may actually not seek to exact * frame requested, instead it will seek to the closest key frame * * NOTE: fast, as it just seeks to the closest previous key frame and * doesn't try to decode frames in the middle * * @param frameNumber * @return * @throws IOException * @throws JCodecException */ public FrameGrab seekToFrameSloppy(int frameNumber) throws IOException, JCodecException { sdt().gotoFrame(frameNumber); goToPrevKeyframe(); return this; }
/** * Position frame grabber to a specific second in a movie. * * Performs a sloppy seek, meaning that it may actually not seek to exact * second requested, instead it will seek to the closest key frame * * NOTE: fast, as it just seeks to the closest previous key frame and * doesn't try to decode frames in the middle * * @param second * @return * @throws IOException * @throws JCodecException */ public FrameGrab seekToSecondSloppy(double second) throws IOException, JCodecException { sdt().seek(second); goToPrevKeyframe(); return this; }
private static ContainerAdaptor detectDecoder(SeekableDemuxerTrack videoTrack) throws JCodecException { DemuxerTrackMeta meta = videoTrack.getMeta(); switch (meta.getCodec()) { case H264: return new AVCMP4Adaptor(meta); default: throw new UnsupportedFormatException("Codec is not supported"); } }