private Optional getRekognizedOutput()

in src/main/java/com/amazonaws/kinesisvideo/parser/utilities/H264BoundingBoxFrameRenderer.java [65:129]


    private Optional<RekognizedOutput> getRekognizedOutput(final Frame frame,
                                                           final Optional<FragmentMetadata> fragmentMetadata) {

        Optional<RekognizedOutput> rekognizedOutput = Optional.empty();
        if (rekognizedFragmentsIndex != null && fragmentMetadata.isPresent()) {
            final String fragmentNumber = fragmentMetadata.get().getFragmentNumberString();

            int timeout = 0;
            List<RekognizedOutput> rekognizedOutputs = null;

            // if rekognizedOutputs is null then Rekognition did not return the results for this fragment.
            // Wait until the results are received.
            while (true) {
                rekognizedOutputs = rekognizedFragmentsIndex.getRekognizedOutputList(fragmentNumber);
                if (rekognizedOutputs != null) {
                    break;
                } else {
                    timeout += waitForResults(WAIT_TIMEOUT);
                    if (timeout >= maxTimeout) {
                        log.warn("No rekognized result after waiting for {} ms ", timeout);
                        break;
                    }
                }
            }
            if (rekognizedOutputs != null) {

                // Currently Rekognition samples frames and calculates the frame offset from the fragment start time.
                // So, in order to match with rekognition results, we have to compute the same frame offset from the
                // beginning of the fragments.
                if (frame.isKeyFrame()) {
                    keyFrameTimecode = frame.getTimeCode();
                    log.debug("Key frame timecode : {}", keyFrameTimecode);
                }
                final long frameOffset = (frame.getTimeCode() > keyFrameTimecode)
                        ? frame.getTimeCode() - keyFrameTimecode : 0;
                log.debug("Current Fragment Number : {} Computed Frame offset : {}", fragmentNumber, frameOffset);
                if (log.isDebugEnabled()) {
                    rekognizedOutputs
                            .forEach(p -> log.debug("frameOffsetInSeconds from Rekognition : {}",
                                    p.getFrameOffsetInSeconds()));
                }

                // Check whether the computed offset matches the rekognized output frame offset. Rekognition
                // output is in seconds whereas the frame offset is calculated in milliseconds.
                // NOTE: Rekognition frame offset doesn't exactly match with the computed offset below. So
                // take the closest one possible within 10ms delta.
                rekognizedOutput = rekognizedOutputs.stream()
                        .filter(p -> isOffsetDeltaWithinThreshold(frameOffset, p))
                        .findFirst();

                // Remove from the index once the RekognizedOutput is processed. Else it would increase the memory
                // footprint and blow up the JVM.
                if (rekognizedOutput.isPresent()) {
                    log.debug("Computed offset matched with retrieved offset. Delta : {}",
                            Math.abs(frameOffset - (rekognizedOutput.get().getFrameOffsetInSeconds() * MILLIS_IN_SEC)));
                    rekognizedOutputs.remove(rekognizedOutput.get());
                    if (rekognizedOutputs.isEmpty()) {
                        log.debug("All frames processed for this fragment number : {}", fragmentNumber);
                        rekognizedFragmentsIndex.remove(fragmentNumber);
                    }
                }
            }
        }
        return rekognizedOutput;
    }