public boolean readNextImage() {
    try {
      while (demuxer.read(packet) >= 0) {
        if (packet.getStreamIndex() == videoStreamId) {
          int offset = 0;
          int bytesRead = 0;
          do {
            bytesRead += videoDecoder.decode(picture, packet, offset);
            if (picture.isComplete()) {
              image3ByteBGR = converter.toImage(image3ByteBGR, picture);
              frameIndex++;

              this.presentationTimestamp = packet.getPts();

              dirtyImageRGB = true;
              return true;
            }
            offset += bytesRead;
          } while (offset < packet.getSize());
        }
      }
    } catch (Exception ex) {
      throw new RuntimeException("Failed readNextImage", ex);
    }
    return false;
  }
  public void close() {
    try {
      do {
        videoDecoder.decode(picture, null, 0);
        if (picture.isComplete()) {
          image3ByteBGR = converter.toImage(image3ByteBGR, picture);
        }
      } while (picture.isComplete());

      demuxer.close();
    } catch (Exception ex) {
      LOG.warn("Faile to close ... ignore, no rethrow", ex);
    }

    demuxer = null;
    videoDecoder = null;
    videoStreamId = -1;
    picture = null;
    converter = null;
    packet = null;
    image3ByteBGR = null;
    imageRGB = null;
    demuxer = null;
  }
  public void init() {
    try {
      this.demuxer = Demuxer.make();

      demuxer.open(inputFile.getAbsolutePath(), null, false, true, null, null);

      int numStreams = demuxer.getNumStreams();

      videoStreamId = -1;
      videoDecoder = null;
      for (int i = 0; i < numStreams; i++) {
        final DemuxerStream stream = demuxer.getStream(i);
        final Decoder decoder = stream.getDecoder();
        if (decoder != null && decoder.getCodecType() == MediaDescriptor.Type.MEDIA_VIDEO) {
          videoStreamId = i;
          videoDecoder = decoder;
          // stop at the first one.
          break;
        }
      }
      if (videoStreamId == -1) {
        throw new RuntimeException(
            "could not find video stream in video file: '" + inputFile + "'");
      }

      videoDecoder.open(null, null);

      int width = videoDecoder.getWidth();
      int height = videoDecoder.getHeight();
      this.dim = new Dim(width, height);
      picture = MediaPicture.make(width, height, videoDecoder.getPixelFormat());

      // converter to BGR_24 for java swing
      converter =
          MediaPictureConverterFactory.createConverter(
              MediaPictureConverterFactory.HUMBLE_BGR_24, picture);
      image3ByteBGR = null; // new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);

      imageRGB = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
      imageRGBDataInts = ((DataBufferInt) imageRGB.getRaster().getDataBuffer()).getData();

      packet = MediaPacket.make();
    } catch (Exception ex) {
      throw new RuntimeException("Failed init HumbleioPacketReader '" + inputFile + "'", ex);
    }
  }