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;
  }