aws / amazon-kinesis-video-streams-parser-library

Amazon Kinesis Video Streams parser library is for developers to include in their applications that makes it easy to work with the output of video streams such as retrieving frame-level objects, metadata for fragments, and more.
Apache License 2.0
103 stars 52 forks source link

[BUG] Duplicate key error #123

Open FlorianRuen opened 2 years ago

FlorianRuen commented 2 years ago

Hi there,

I'm opened a Github issue as suggested by the AWS Premium Support, to continue an issue on Duplicate Key Error I got on my consumer.

To make a quick summary on this case :

Here is a screenshot of the issue, including stacktrace : https://i.ibb.co/gg41ShR/duplicate-key-error-1.png

I'm using the latest version of the parser library compile("com.amazonaws:amazon-kinesis-video-streams-parser-library:1.0.15")

And I'm using a Frame visitor which is based on this link : https://github.com/aws/amazon-kinesis-video-streams-parser-library/blob/master/src/main/java/com/amazonaws/kinesisvideo/parser/utilities/FrameRendererVisitor.java, I just surcharge the meethod to take a destination folder to save my frames on the disk.

There is any update or thing I can try to fix this issue ? Today I try a lot of things, but anything has changed, and it's almost a production system impaired, because I need to restart it many times a day ...

Hope I can find help here,

Kind regards, Florian

FlorianRuen commented 2 years ago

Help needed here. I do some other debugs :

FlorianRuen commented 2 years ago

Few more tests, after trying a lot of possibilities, I think that I run a multiple thread pool for every stream my consumer need to extract.

So what I trying to do, is to change newFixedThreadPoolExecutor(4) by newSingleThreadExecutor

var kvsSessionExpiredOrNeedToRestartConsumer = false
val getMediaProcessingArguments = FrameRendererVisitor(framesFolder, FragmentMetadataVisitor.create())
val executorService = Executors.newSingleThreadExecutor()

I'm testing now, it seems the error isn't complety dissapear, but it seems it fired less times than before.

Still help needed to understand why and go deeper to completly fix this error or find any workaround that can help me to deploy a production system that works !

disa6302 commented 2 years ago

@FlorianRuen ,

Can you explain what this code snippet is or where it resides? Is this your own code?

vattay commented 2 years ago

This is really fascinating because I had a working Java Kinesis Video Consumer application that I last ran three weeks ago and was working fine, and now I'm getting a DuplicateKeyError as well.

java.lang.IllegalStateException: Duplicate key 25 (attempted merging values 91343852333181532036951704798106065785361265741 and 91343852333181532046855225112389109058398434006)
    at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)
    at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:182)
    at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadataVisitor.getTagNameToValueMap(FragmentMetadataVisitor.java:295)
    at com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadataVisitor.setMillisBehindLatestAndContinuationToken(FragmentMetadataVisitor.java:205)
    at com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadataVisitor.access$400(FragmentMetadataVisitor.java:48)
    at com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadataVisitor$StateMachineVisitor.visit(FragmentMetadataVisitor.java:167)
    at com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement.accept(MkvEndMasterElement.java:36)
    at com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor.visitAll(CompositeMkvElementVisitor.java:66)
    at com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor.visit(CompositeMkvElementVisitor.java:48)
    at com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement.accept(MkvEndMasterElement.java:36)
    at com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor.visitAll(CompositeMkvElementVisitor.java:66)
    at com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor.visit(CompositeMkvElementVisitor.java:48)
    at com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement.accept(MkvEndMasterElement.java:36)
    at com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader.apply(StreamingMkvReader.java:131)
    at com.cuttingedgeai.ghost.GhostlyGetMediaWorker.run(GhostlyGetMediaWorker.java:80)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:831)
disa6302 commented 2 years ago

@vattay ,

It is strange because nothing has changed within the SDK. Any changes in your application?

FlorianRuen commented 2 years ago

@disa6302 The frame renderer visitor is from AWS Github, I just personalize the way to not display the final image but save it on the disk. For the rest, yes it's a custom code But i'm in the same situation than @vattay, I didn't get this error for a long time, without any changes on this part on the code, and sometime I get it many many times.

After some tries, I seems if we change the newFixedThreadPoolExecutor(4)by newSingleThreadExecutor (on my side, don't know what @vattay use ?), the problem doesn't append.

But from now I already used a fixedThreadPool and nothing goes wrong.

vattay commented 2 years ago

I might be having a slightly different issue. And yes, probably both our code is based on the aws parser, but with customization since you have to customize the example code to make something useful.

My root cause was actually that the video metadata no longer appears to have height and width embedded in it and I had a lot of exception handlers that caught exceptions during frame processing and attempted to resume, this led to the duplicate key error somehow.

This is the fix I made for myself, clearly just a temporary hack, copied from H264FrameProcessor, but I added default values to the pixelWidth and pixelHeight, and then it started working fine again.

    public BufferedImage decodeH264Frame(final Frame frame, final MkvTrackMetadata trackMetadata) {
        final ByteBuffer frameBuffer = frame.getFrameData();
        // TODO - Oddity: we aren't getting the image size. Needed to add these defaults. Could cause strange bugs.
        final int pixelWidth = trackMetadata.getPixelWidth().orElse(BigInteger.valueOf(352)).intValue();
        final int pixelHeight = trackMetadata.getPixelHeight().orElse(BigInteger.valueOf(240)).intValue();
        codecPrivateData = trackMetadata.getCodecPrivateData().array();
        log.debug("Decoding frames ... ");