├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── contribution-.md │ ├── feature_request.md │ └── questions-help.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── amazonaws │ │ └── kinesisvideo │ │ └── parser │ │ ├── ebml │ │ ├── EBMLElementMetaData.java │ │ ├── EBMLParser.java │ │ ├── EBMLParserCallbacks.java │ │ ├── EBMLParserInternalElement.java │ │ ├── EBMLTypeInfo.java │ │ ├── EBMLTypeInfoProvider.java │ │ ├── EBMLUtils.java │ │ ├── InputStreamParserByteSource.java │ │ ├── MkvTypeInfos.java │ │ ├── ParserBulkByteSource.java │ │ ├── ParserByteSource.java │ │ ├── ReplayIdAndSizeBuffer.java │ │ └── TrackingReplayableIdAndSizeByteSource.java │ │ ├── examples │ │ ├── .DS_Store │ │ ├── BoundingBoxImagePanel.java │ │ ├── ContinuousGetMediaWorker.java │ │ ├── GetMediaForFragmentListWorker.java │ │ ├── GetMediaWorker.java │ │ ├── ImagePanel.java │ │ ├── KinesisVideoBoundingBoxFrameViewer.java │ │ ├── KinesisVideoCommon.java │ │ ├── KinesisVideoExample.java │ │ ├── KinesisVideoFrameViewer.java │ │ ├── KinesisVideoGStreamerPiperExample.java │ │ ├── KinesisVideoRekognitionIntegrationExample.java │ │ ├── KinesisVideoRendererExample.java │ │ ├── ListFragmentWorker.java │ │ ├── PutMediaWorker.java │ │ ├── StreamOps.java │ │ └── lambda │ │ │ ├── DDBBasedFragmentCheckpointManager.java │ │ │ ├── EncodedFrame.java │ │ │ ├── FragmentCheckpoint.java │ │ │ ├── FragmentCheckpointManager.java │ │ │ ├── H264FrameProcessor.java │ │ │ ├── KVSMediaSource.java │ │ │ └── KinesisVideoRekognitionLambdaExample.java │ │ ├── kinesis │ │ ├── KinesisDataStreamsWorker.java │ │ └── KinesisRecordProcessor.java │ │ ├── mkv │ │ ├── Frame.java │ │ ├── FrameProcessException.java │ │ ├── MkvDataElement.java │ │ ├── MkvElement.java │ │ ├── MkvElementVisitException.java │ │ ├── MkvElementVisitor.java │ │ ├── MkvEndMasterElement.java │ │ ├── MkvStartMasterElement.java │ │ ├── MkvStreamReaderCallback.java │ │ ├── MkvTypeInfoProvider.java │ │ ├── MkvValue.java │ │ ├── StreamingMkvReader.java │ │ └── visitors │ │ │ ├── CompositeMkvElementVisitor.java │ │ │ ├── CopyVisitor.java │ │ │ ├── CountVisitor.java │ │ │ └── ElementSizeAndOffsetVisitor.java │ │ ├── rekognition │ │ ├── pojo │ │ │ ├── BoundingBox.java │ │ │ ├── DetectedFace.java │ │ │ ├── Face.java │ │ │ ├── FaceSearchResponse.java │ │ │ ├── FaceType.java │ │ │ ├── InputInformation.java │ │ │ ├── KinesisVideo.java │ │ │ ├── Landmark.java │ │ │ ├── MatchedFace.java │ │ │ ├── Pose.java │ │ │ ├── Quality.java │ │ │ ├── RekognitionInput.java │ │ │ ├── RekognitionOutput.java │ │ │ ├── RekognizedFragmentsIndex.java │ │ │ ├── RekognizedOutput.java │ │ │ └── StreamProcessorInformation.java │ │ └── processor │ │ │ └── RekognitionStreamProcessor.java │ │ └── utilities │ │ ├── BufferedImageUtil.java │ │ ├── DynamoDBHelper.java │ │ ├── FragmentMetadata.java │ │ ├── FragmentMetadataVisitor.java │ │ ├── FrameRendererVisitor.java │ │ ├── FrameVisitor.java │ │ ├── H264BoundingBoxFrameRenderer.java │ │ ├── H264FrameDecoder.java │ │ ├── H264FrameEncoder.java │ │ ├── H264FrameRenderer.java │ │ ├── MkvChildElementCollector.java │ │ ├── MkvTag.java │ │ ├── MkvTrackMetadata.java │ │ ├── OutputSegmentMerger.java │ │ ├── ProducerStreamUtil.java │ │ ├── SimpleFrameVisitor.java │ │ └── consumer │ │ ├── FragmentMetadataCallback.java │ │ ├── FragmentProgressTracker.java │ │ ├── GetMediaResponseStreamConsumer.java │ │ ├── GetMediaResponseStreamConsumerFactory.java │ │ ├── MergedOutputPiper.java │ │ └── MergedOutputPiperFactory.java └── resources │ ├── libKinesisVideoProducerJNI.so │ └── log4j.properties └── test ├── java └── com │ └── amazonaws │ └── kinesisvideo │ └── parser │ ├── TestResourceUtil.java │ ├── ebml │ ├── EBMLParserTest.java │ ├── EBMLUtilsTest.java │ ├── TestEBMLParserCallback.java │ └── TestEBMLTypeInfoProvider.java │ ├── examples │ ├── KinesisVideoExampleTest.java │ ├── KinesisVideoGStreamerPiperExampleTest.java │ ├── KinesisVideoRekognitionIntegrationExampleTest.java │ └── KinesisVideoRendererExampleTest.java │ ├── mkv │ ├── EBMLParserForMkvTypeInfosTest.java │ ├── ElementSizeAndOffsetVisitorTest.java │ ├── MkvValueTest.java │ ├── StreamingMkvReaderTest.java │ └── visitors │ │ └── CopyVisitorTest.java │ ├── rekognition │ └── processor │ │ └── RekognitionStreamProcessorTest.java │ └── utilities │ ├── FragmentMetadataVisitorTest.java │ ├── FrameRendererTest.java │ ├── FrameVisitorTest.java │ ├── H264FrameDecoderTest.java │ ├── H264FrameRendererTest.java │ ├── OutputSegmentMergerTest.java │ ├── SimpleFrameVisitorTest.java │ └── consumer │ └── MergedOutputPiperTest.java └── resources ├── LambdaExampleCFnTemplate.yml ├── bezos_vogels.mkv ├── clusters.mkv ├── empty-mkv-with-tags.mkv ├── kinesis_video_renderer_example_output.mkv ├── log4j2.properties ├── output-get-media-equal-timecode.mkv ├── output-get-media-non-increasing-timecode.mkv ├── output_get_media.mkv ├── output_get_media_sparse_fragments.mkv ├── output_get_media_sparse_fragments_merged.mkv ├── rendering_example_video.mkv ├── test_mixed_tags.mkv ├── test_tags_empty_cluster.mkv ├── vogels_330.mkv └── vogels_480.mkv /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG} " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Logging** 11 | Add relevent parser library logging. IMPORTANT NOTE: Please make sure to NOT share AWS access credentials under any circumstance! Please make sure they are not in the logs. 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **SDK version number** 17 | Include the SDK version you are running. If it is a specific commit on master branch, include that 18 | 19 | **Open source building** 20 | If it is a build issue, include 3rd party library version and steps to how you are building it 21 | 22 | **To Reproduce** 23 | Steps to reproduce the behavior: 24 | 1. Go to '...' 25 | 2. Click on '....' 26 | 3. Scroll down to '....' 27 | 4. See error 28 | 29 | **Expected behavior** 30 | A clear and concise description of what you expected to happen. 31 | 32 | **Screenshots** 33 | If applicable, add screenshots to help explain your problem. 34 | 35 | **Desktop (please complete the following information):** 36 | - OS: [e.g. iOS] 37 | - Browser [e.g. chrome, safari] 38 | - Version [e.g. 22] 39 | 40 | **Smartphone (please complete the following information):** 41 | - Device: [e.g. iPhone6] 42 | - OS: [e.g. iOS8.1] 43 | - Browser [e.g. stock browser, safari] 44 | - Version [e.g. 22] 45 | 46 | **Additional context** 47 | Add any other context about the problem here. 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/contribution-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Contribution ' 3 | about: We always welcome open-source contributions! Please open an issue to tag your 4 | pull requeste this issue template's purpose here. 5 | title: "[CONTRIBUTION] " 6 | labels: contribution 7 | assignees: '' 8 | 9 | --- 10 | 11 | PLEASE ADD THE APPROPRIATE TAG TO ALLOW BUCKETIZATION OF THE SOLUTIONS. IF THE TAG IS NOT AVAILABLE, DO NOT WORRY, WE WILL TAKE CARE OF IT! 12 | 13 | ** Describe the issue you are trying to solve ** 14 | Add a one line description of the issue you are trying to solve 15 | 16 | ** Details of the changes ** 17 | Give a couple of points to describe the changes you have made 18 | 19 | ** Test cases ** 20 | Give a detailed description of the tests you are running, if applicable 21 | 22 | ** Additional context ** 23 | Any details that can be preserved for the future 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/questions-help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Questions/Help 3 | about: Describe this issue template's purpose here. 4 | title: "[QUESTION] " 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | A one liner description about the use case and what you are trying to achieve 11 | 12 | ** Logging ** 13 | Add relevent SDK logging. IMPORTANT NOTE: Please make sure to NOT share AWS access credentials under any circumstance! Please make sure they are not in the logs. 14 | 15 | ** Any design considerations/constraints ** 16 | Explain in detail how you would like to integrate our SDK into your solution 17 | 18 | ** If you would not like to open an issue to discuss your solution in open-platform, please email your question to kinesis-video-support@amazon.com ** 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Parser Library Java CI with Maven 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | pull_request: 9 | branches: 10 | - develop 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ${{ matrix.os }} 16 | permissions: 17 | id-token: write 18 | contents: read 19 | strategy: 20 | matrix: 21 | os: [ macos-10.15, ubuntu-18.04, windows-2019] 22 | java: [ 8, 11, 16 ] 23 | steps: 24 | - name: Checkout the repository 25 | uses: actions/checkout@v2 26 | - name: Set up JDK 27 | uses: actions/setup-java@v2 28 | with: 29 | java-version: ${{ matrix.java }} 30 | distribution: 'adopt' 31 | cache: maven 32 | - name: Build 33 | run: mvn clean install 34 | shell: bash -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea* 2 | *.iml 3 | target/ 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws/amazon-kinesis-video-streams-parser-library/issues), or [recently closed](https://github.com/aws/amazon-kinesis-video-streams-parser-library/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/amazon-kinesis-video-streams-parser-library/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws/amazon-kinesis-video-streams-parser-library/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Amazon Kinesis Video Streams Parser Library 2 | Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/EBMLElementMetaData.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import lombok.Builder; 17 | import lombok.EqualsAndHashCode; 18 | import lombok.Getter; 19 | import lombok.ToString; 20 | 21 | 22 | /** 23 | * Class that represents the metadata of a single EBML element in an EBML stream. 24 | * It does not contain the actual data or content of the EBML element. 25 | */ 26 | @Getter 27 | @Builder 28 | @ToString 29 | @EqualsAndHashCode 30 | public class EBMLElementMetaData { 31 | private final EBMLTypeInfo typeInfo; 32 | private final long elementNumber; 33 | 34 | public boolean isMaster() { 35 | return typeInfo.getType() == EBMLTypeInfo.TYPE.MASTER; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/EBMLParserCallbacks.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import java.nio.ByteBuffer; 17 | import java.util.List; 18 | 19 | /** 20 | * The EBMLParser invokes these callbacks when it detects the start, end and contents of elements. 21 | */ 22 | public interface EBMLParserCallbacks { 23 | void onStartElement(EBMLElementMetaData elementMetaData, 24 | long elementDataSize, 25 | ByteBuffer idAndSizeRawBytes, 26 | ElementPathSupplier pathSupplier); 27 | 28 | void onPartialContent(EBMLElementMetaData elementMetaData, ParserBulkByteSource bulkByteSource, int bytesToRead); 29 | 30 | void onEndElement(EBMLElementMetaData elementMetaData, ElementPathSupplier pathSupplier); 31 | 32 | default boolean continueParsing() { 33 | return true; 34 | } 35 | 36 | @FunctionalInterface 37 | interface ElementPathSupplier { 38 | List getAncestors(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/EBMLTypeInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import lombok.AccessLevel; 17 | import lombok.AllArgsConstructor; 18 | import lombok.Builder; 19 | import lombok.EqualsAndHashCode; 20 | import lombok.Getter; 21 | import lombok.ToString; 22 | 23 | /** 24 | * The type information for an EBML element. 25 | * This specifies the semantics of the EBML elements in an EBML document. 26 | * For example the TypeInfo for MKV will specify the semantics for the EBML elements that make up a MKV document. 27 | */ 28 | 29 | @Builder 30 | @AllArgsConstructor(access = AccessLevel.PUBLIC) 31 | @Getter 32 | @ToString 33 | @EqualsAndHashCode 34 | public class EBMLTypeInfo { 35 | private final int id; 36 | private final String name; 37 | private final int level; 38 | private final TYPE type; 39 | @Builder.Default 40 | private boolean isRecursive = false; 41 | 42 | public boolean isGlobal() { 43 | return level < 0; 44 | } 45 | 46 | public enum TYPE { INTEGER, UINTEGER, FLOAT, STRING, UTF_8, DATE, MASTER, BINARY } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/EBMLTypeInfoProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import java.util.Optional; 17 | 18 | /** 19 | * An interface that vends type information used by the EBML parser. 20 | */ 21 | public interface EBMLTypeInfoProvider { 22 | Optional getType(int id); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/InputStreamParserByteSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import org.apache.commons.lang3.Validate; 17 | 18 | import java.io.BufferedInputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.nio.ByteBuffer; 22 | 23 | /** 24 | * An implementation of ParserByteSource that wraps an input stream containing the EBML stream. 25 | */ 26 | public class InputStreamParserByteSource implements ParserByteSource { 27 | private static final int BUFFER_SIZE = 8192; 28 | private static final int MARK_SIZE = 100; 29 | private final BufferedInputStream bufferedInputStream; 30 | 31 | public InputStreamParserByteSource(final InputStream inputStream) { 32 | this(inputStream, BUFFER_SIZE); 33 | } 34 | 35 | InputStreamParserByteSource(final InputStream inputStream, final int bufferSize) { 36 | bufferedInputStream = new BufferedInputStream(inputStream, bufferSize); 37 | Validate.isTrue(bufferedInputStream.markSupported()); 38 | } 39 | 40 | 41 | @Override 42 | public int readByte() { 43 | try { 44 | return bufferedInputStream.read(); 45 | } catch (final IOException e) { 46 | throw new RuntimeException("Exception while reading byte from input stream!", e); 47 | } 48 | } 49 | 50 | @Override 51 | public int available() { 52 | try { 53 | return bufferedInputStream.available(); 54 | } catch (final IOException e) { 55 | throw new RuntimeException("Exception while getting available bytes from input stream!", e); 56 | } 57 | } 58 | 59 | @Override 60 | public int readBytes(final ByteBuffer dest, final int numBytes) { 61 | try { 62 | Validate.isTrue(dest.remaining() >= numBytes); 63 | final int numBytesRead = bufferedInputStream.read(dest.array(), dest.position(), numBytes); 64 | if (numBytesRead > 0) { 65 | dest.position(dest.position() + numBytesRead); 66 | } 67 | 68 | return numBytesRead; 69 | } catch (final IOException e) { 70 | throw new RuntimeException("Exception while reading bytes from input stream!", e); 71 | } 72 | } 73 | 74 | @Override 75 | public boolean eof() { 76 | try { 77 | bufferedInputStream.mark(MARK_SIZE); 78 | if (readByte() == -1) { 79 | return true; 80 | } 81 | bufferedInputStream.reset(); 82 | return false; 83 | } catch (final IOException e) { 84 | throw new RuntimeException("Exception while resetting input stream!", e); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/ParserBulkByteSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import java.nio.ByteBuffer; 17 | 18 | /** 19 | * An interface representing a byte source for the parser which allows bulk reads. 20 | */ 21 | public interface ParserBulkByteSource { 22 | 23 | int readBytes(ByteBuffer dest, int numBytes); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/ParserByteSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | /** 17 | * Represents a source of bytes that can be parsed by the EBML parser. 18 | * It could be backed by a ByteBuffer or a netty ByteBuf or an input stream that can support these operations. 19 | */ 20 | public interface ParserByteSource extends ParserBulkByteSource { 21 | int readByte(); 22 | 23 | int available(); 24 | 25 | boolean eof(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/ReplayIdAndSizeBuffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import org.apache.commons.lang3.Validate; 17 | 18 | import java.nio.ByteBuffer; 19 | 20 | /** 21 | * Buffer used to replay the id and size of ebml elements in the ebml parser 22 | */ 23 | class ReplayIdAndSizeBuffer { 24 | private int count; 25 | private final byte[] buffer; 26 | private long startingOffset; 27 | 28 | ReplayIdAndSizeBuffer(int length) { 29 | buffer = new byte[length]; 30 | } 31 | 32 | void init(long startingOffset) { 33 | this.startingOffset = startingOffset; 34 | count = 0; 35 | } 36 | 37 | void addByte(byte val) { 38 | Validate.isTrue(count < buffer.length, "Too many bytes being added to replay buffer " + count); 39 | buffer[count] = val; 40 | count++; 41 | } 42 | 43 | boolean inReplayBuffer(long readOffset) { 44 | return (readOffset - startingOffset) < count; 45 | } 46 | 47 | int availableAfter(long readOffset) { 48 | return (int) Math.max(0, startingOffset + count - readOffset); 49 | } 50 | 51 | byte getByteFromOffset(long readOffset) { 52 | Validate.isTrue(inReplayBuffer(readOffset), 53 | "Attempt to read from replay buffer at " + readOffset + "while buffer starts at" + startingOffset 54 | + "and has " + count + "bytes"); 55 | return buffer[(int) (readOffset - startingOffset)]; 56 | } 57 | 58 | ByteBuffer getByteBuffer() { 59 | return ByteBuffer.wrap(buffer, 0, count); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/ebml/TrackingReplayableIdAndSizeByteSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | /** 17 | * An interface representing a byte source that can replay the bytes for ebml id and size. 18 | * It also keeps track of the total number of bytes read by the parser from the underlying 19 | * byte source. 20 | * This wraps a parser byte source passed in by the user. 21 | */ 22 | interface TrackingReplayableIdAndSizeByteSource { 23 | boolean checkAndReadIntoReplayBuffer(int len); 24 | 25 | int readByte(); 26 | 27 | int availableForContent(); 28 | 29 | void setReadOffsetForReplayBuffer(long readOffset); 30 | 31 | long getTotalBytesRead(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/main/java/com/amazonaws/kinesisvideo/parser/examples/.DS_Store -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/GetMediaWorker.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import com.amazonaws.auth.AWSCredentialsProvider; 17 | import com.amazonaws.client.builder.AwsClientBuilder; 18 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 21 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 22 | import com.amazonaws.regions.Regions; 23 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideo; 24 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMedia; 25 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMediaClientBuilder; 26 | import com.amazonaws.services.kinesisvideo.model.APIName; 27 | import com.amazonaws.services.kinesisvideo.model.GetDataEndpointRequest; 28 | import com.amazonaws.services.kinesisvideo.model.GetMediaRequest; 29 | import com.amazonaws.services.kinesisvideo.model.GetMediaResult; 30 | import com.amazonaws.services.kinesisvideo.model.StartSelector; 31 | import lombok.extern.slf4j.Slf4j; 32 | 33 | /** 34 | * Worker used to make a GetMedia call to Kinesis Video and stream in data and parse it and apply a visitor. 35 | */ 36 | @Slf4j 37 | public class GetMediaWorker extends KinesisVideoCommon implements Runnable { 38 | private final AmazonKinesisVideoMedia videoMedia; 39 | private final MkvElementVisitor elementVisitor; 40 | private final StartSelector startSelector; 41 | 42 | private GetMediaWorker(Regions region, 43 | AWSCredentialsProvider credentialsProvider, 44 | String streamName, 45 | StartSelector startSelector, 46 | String endPoint, 47 | MkvElementVisitor elementVisitor) { 48 | super(region, credentialsProvider, streamName); 49 | 50 | AmazonKinesisVideoMediaClientBuilder builder = AmazonKinesisVideoMediaClientBuilder.standard() 51 | .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, region.getName())) 52 | .withCredentials(getCredentialsProvider()); 53 | 54 | this.videoMedia = builder.build(); 55 | this.elementVisitor = elementVisitor; 56 | this.startSelector = startSelector; 57 | } 58 | 59 | public static GetMediaWorker create(Regions region, 60 | AWSCredentialsProvider credentialsProvider, 61 | String streamName, 62 | StartSelector startSelector, 63 | AmazonKinesisVideo amazonKinesisVideo, 64 | MkvElementVisitor visitor) { 65 | String endPoint = amazonKinesisVideo.getDataEndpoint(new GetDataEndpointRequest().withAPIName(APIName.GET_MEDIA) 66 | .withStreamName(streamName)).getDataEndpoint(); 67 | 68 | return new GetMediaWorker(region, credentialsProvider, streamName, startSelector, endPoint, visitor); 69 | } 70 | 71 | @Override 72 | public void run() { 73 | try { 74 | log.info("Start GetMedia worker on stream {}", streamName); 75 | 76 | GetMediaResult result = videoMedia.getMedia(new GetMediaRequest().withStreamName(streamName).withStartSelector(startSelector)); 77 | log.info("GetMedia called on stream {} response {} requestId {}", 78 | streamName, 79 | result.getSdkHttpMetadata().getHttpStatusCode(), 80 | result.getSdkResponseMetadata().getRequestId()); 81 | 82 | StreamingMkvReader mkvStreamReader = StreamingMkvReader.createDefault(new InputStreamParserByteSource(result.getPayload())); 83 | log.info("StreamingMkvReader created for stream {} ", streamName); 84 | try { 85 | mkvStreamReader.apply(this.elementVisitor); 86 | } catch (MkvElementVisitException e) { 87 | log.error("Exception while accepting visitor {}", e); 88 | } 89 | } catch (Throwable t) { 90 | log.error("Failure in GetMediaWorker for streamName {} {}", streamName, t.toString()); 91 | throw t; 92 | } finally { 93 | log.info("Exiting GetMediaWorker for stream {}", streamName); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/ImagePanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import java.awt.Graphics; 17 | import java.awt.Graphics2D; 18 | import java.awt.RenderingHints; 19 | import java.awt.image.BufferedImage; 20 | 21 | import javax.swing.JPanel; 22 | 23 | /** 24 | * Panel for rendering buffered image. 25 | */ 26 | class ImagePanel extends JPanel { 27 | protected BufferedImage image; 28 | 29 | @Override 30 | public void paintComponent(Graphics g) { 31 | Graphics2D g2 = (Graphics2D) g; 32 | if (image != null) { 33 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 34 | g2.clearRect(0, 0, image.getWidth(), image.getHeight()); 35 | g2.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); 36 | } 37 | } 38 | 39 | public void setImage(BufferedImage bufferedImage) { 40 | image = bufferedImage; 41 | repaint(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoBoundingBoxFrameViewer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import java.awt.image.BufferedImage; 17 | 18 | import com.amazonaws.kinesisvideo.parser.rekognition.pojo.RekognizedOutput; 19 | 20 | public class KinesisVideoBoundingBoxFrameViewer extends KinesisVideoFrameViewer { 21 | 22 | public KinesisVideoBoundingBoxFrameViewer(int width, int height) { 23 | super(width, height, "KinesisVideo Embedded Frame Viewer"); 24 | panel = new BoundingBoxImagePanel(); 25 | addImagePanel(panel); 26 | } 27 | 28 | public void update(BufferedImage image, RekognizedOutput rekognizedOutput) { 29 | ((BoundingBoxImagePanel) panel).setImage(image, rekognizedOutput); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoCommon.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import com.amazonaws.auth.AWSCredentialsProvider; 17 | import com.amazonaws.client.builder.AwsClientBuilder; 18 | import com.amazonaws.regions.Regions; 19 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideoPutMediaClientBuilder; 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | /** 24 | * Abstract class for all example classes that use the Kinesis Video clients. 25 | */ 26 | @RequiredArgsConstructor 27 | @Getter 28 | public abstract class KinesisVideoCommon { 29 | private final Regions region; 30 | private final AWSCredentialsProvider credentialsProvider; 31 | protected final String streamName; 32 | 33 | protected void configureClient(AwsClientBuilder clientBuilder) { 34 | clientBuilder.withCredentials(credentialsProvider).withRegion(region); 35 | } 36 | 37 | protected void conifgurePutMediaClient(AmazonKinesisVideoPutMediaClientBuilder builder) { 38 | builder.withCredentials(credentialsProvider).withRegion(region); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoFrameViewer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import java.awt.Color; 17 | import java.awt.Dimension; 18 | import java.awt.event.WindowAdapter; 19 | import java.awt.event.WindowEvent; 20 | import java.awt.image.BufferedImage; 21 | 22 | import javax.swing.JFrame; 23 | 24 | public class KinesisVideoFrameViewer extends JFrame { 25 | private final int width; 26 | private final int height; 27 | private final String title; 28 | 29 | protected ImagePanel panel; 30 | 31 | protected KinesisVideoFrameViewer(int width, int height, String title) { 32 | this.width = width; 33 | this.height = height; 34 | this.title = title; 35 | this.setTitle(title); 36 | this.setBackground(Color.BLACK); 37 | } 38 | 39 | public KinesisVideoFrameViewer(int width, int height) { 40 | this(width, height, "Kinesis Video Frame Viewer "); 41 | panel = new ImagePanel(); 42 | addImagePanel(panel); 43 | } 44 | 45 | protected void addImagePanel(final ImagePanel panel) { 46 | panel.setPreferredSize(new Dimension(width, height)); 47 | this.add(panel); 48 | this.pack(); 49 | addWindowListener(new WindowAdapter() { 50 | public void windowClosing(WindowEvent e) { 51 | System.out.println(title + " closed"); 52 | System.exit(0); 53 | } 54 | }); 55 | } 56 | 57 | public void update(BufferedImage image) { 58 | panel.setImage(image); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/ListFragmentWorker.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.kinesisvideo.parser.examples; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.concurrent.Callable; 7 | import com.amazonaws.auth.AWSCredentialsProvider; 8 | import com.amazonaws.client.builder.AwsClientBuilder; 9 | import com.amazonaws.regions.Regions; 10 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideo; 11 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMedia; 12 | import com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMediaClient; 13 | import com.amazonaws.services.kinesisvideo.model.*; 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | /* This worker retrieves all fragments within the specified TimestampRange from a specified Kinesis Video Stream and returns them in a list */ 17 | 18 | @Slf4j 19 | public class ListFragmentWorker extends KinesisVideoCommon implements Callable { 20 | private final FragmentSelector fragmentSelector; 21 | private final AmazonKinesisVideoArchivedMedia amazonKinesisVideoArchivedMedia; 22 | private final long fragmentsPerRequest = 100; 23 | 24 | public ListFragmentWorker(final String streamName, 25 | final AWSCredentialsProvider awsCredentialsProvider, final String endPoint, 26 | final Regions region, 27 | final FragmentSelector fragmentSelector) { 28 | super(region, awsCredentialsProvider, streamName); 29 | this.fragmentSelector = fragmentSelector; 30 | 31 | amazonKinesisVideoArchivedMedia = AmazonKinesisVideoArchivedMediaClient 32 | .builder() 33 | .withCredentials(awsCredentialsProvider) 34 | .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, region.getName())) 35 | .build(); 36 | } 37 | 38 | public static ListFragmentWorker create(final String streamName, 39 | final AWSCredentialsProvider awsCredentialsProvider, 40 | final Regions region, 41 | final AmazonKinesisVideo amazonKinesisVideo, 42 | final FragmentSelector fragmentSelector) { 43 | final GetDataEndpointRequest request = new GetDataEndpointRequest() 44 | .withAPIName(APIName.LIST_FRAGMENTS).withStreamName(streamName); 45 | final String endpoint = amazonKinesisVideo.getDataEndpoint(request).getDataEndpoint(); 46 | 47 | return new ListFragmentWorker( 48 | streamName, awsCredentialsProvider, endpoint, region, fragmentSelector); 49 | } 50 | 51 | @Override 52 | public List call() { 53 | List fragmentNumbers = new ArrayList<>(); 54 | try { 55 | log.info("Start ListFragment worker on stream {}", streamName); 56 | 57 | ListFragmentsRequest request = new ListFragmentsRequest() 58 | .withStreamName(streamName).withFragmentSelector(fragmentSelector).withMaxResults(fragmentsPerRequest); 59 | 60 | ListFragmentsResult result = amazonKinesisVideoArchivedMedia.listFragments(request); 61 | 62 | 63 | log.info("List Fragments called on stream {} response {} request ID {}", 64 | streamName, 65 | result.getSdkHttpMetadata().getHttpStatusCode(), 66 | result.getSdkResponseMetadata().getRequestId()); 67 | 68 | for (Fragment f: result.getFragments()) { 69 | fragmentNumbers.add(f.getFragmentNumber()); 70 | } 71 | String nextToken = result.getNextToken(); 72 | 73 | /* If result is truncated, keep making requests until nextToken is empty */ 74 | while (nextToken != null) { 75 | request = new ListFragmentsRequest() 76 | .withStreamName(streamName).withNextToken(nextToken); 77 | result = amazonKinesisVideoArchivedMedia.listFragments(request); 78 | 79 | for (Fragment f: result.getFragments()) { 80 | fragmentNumbers.add(f.getFragmentNumber()); 81 | } 82 | nextToken = result.getNextToken(); 83 | } 84 | Collections.sort(fragmentNumbers); 85 | 86 | for (String f: fragmentNumbers) { 87 | log.info("Retrieved fragment number {} ", f); 88 | } 89 | } 90 | catch (Throwable t) { 91 | log.error("Failure in ListFragmentWorker for streamName {} {}", streamName, t.toString()); 92 | throw t; 93 | } finally { 94 | log.info("Retrieved {} Fragments and exiting ListFragmentWorker for stream {}", fragmentNumbers.size(), streamName); 95 | return fragmentNumbers; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/lambda/DDBBasedFragmentCheckpointManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples.lambda; 15 | 16 | import com.amazonaws.auth.AWSCredentialsProvider; 17 | import com.amazonaws.kinesisvideo.parser.utilities.DynamoDBHelper; 18 | import com.amazonaws.regions.Regions; 19 | import com.amazonaws.services.dynamodbv2.model.AttributeValue; 20 | import lombok.extern.slf4j.Slf4j; 21 | 22 | import java.util.Map; 23 | import java.util.Optional; 24 | 25 | /** 26 | * DynamdDB based FragmentCheckpoint Manager which manages the checkpoints for last processed fragments. 27 | */ 28 | @Slf4j 29 | public class DDBBasedFragmentCheckpointManager implements FragmentCheckpointManager { 30 | 31 | private static final String TABLE_NAME = "FragmentCheckpoint"; 32 | private static final String KVS_STREAM_NAME = "KVSStreamName"; 33 | private static final String FRAGMENT_NUMBER = "FragmentNumber"; 34 | private static final String SERVER_TIME = "ServerTime"; 35 | private static final String PRODUCER_TIME = "ProducerTime"; 36 | private static final String UPDATED_TIME = "UpdatedTime"; 37 | private final DynamoDBHelper dynamoDBHelper; 38 | 39 | public DDBBasedFragmentCheckpointManager(final Regions region, final AWSCredentialsProvider credentialsProvider) { 40 | dynamoDBHelper = new DynamoDBHelper(region, credentialsProvider); 41 | dynamoDBHelper.createTableIfDoesntExist(); 42 | } 43 | 44 | /** 45 | * Get last processed fragment details from checkpoint for given stream name. 46 | * 47 | * @param streamName KVS Stream name 48 | * @return Optional of last processed fragment item if checkpoint exists. Empty otherwise 49 | */ 50 | @Override 51 | public Optional getLastProcessedItem(final String streamName) { 52 | final Map result = dynamoDBHelper.getItem(streamName); 53 | if (result != null && result.containsKey(FRAGMENT_NUMBER)) { 54 | return Optional.of(new FragmentCheckpoint(streamName, 55 | result.get(FRAGMENT_NUMBER).getS(), 56 | Long.parseLong(result.get(PRODUCER_TIME).getN()), 57 | Long.parseLong(result.get(SERVER_TIME).getN()), 58 | Long.parseLong(result.get(UPDATED_TIME).getN()))); 59 | } 60 | return Optional.empty(); 61 | } 62 | 63 | /** 64 | * Save last processed fragment details checkpoint for the given stream name. 65 | * 66 | * @param streamName KVS Stream name 67 | * @param fragmentNumber Last processed fragment's fragment number 68 | * @param producerTime Last processed fragment's producer time 69 | * @param serverTime Last processed fragment's server time 70 | */ 71 | @Override 72 | public void saveCheckPoint(final String streamName, final String fragmentNumber, 73 | final Long producerTime, final Long serverTime) { 74 | if (fragmentNumber != null) { 75 | if (dynamoDBHelper.getItem(streamName) != null) { 76 | log.info("Checkpoint for stream name {} already exists. So updating checkpoint with fragment number: {}", 77 | streamName, fragmentNumber); 78 | dynamoDBHelper.updateItem(streamName, fragmentNumber, producerTime, serverTime, System.currentTimeMillis()); 79 | } else { 80 | log.info("Creating checkpoint for stream name {} with fragment number: {}", streamName, fragmentNumber); 81 | dynamoDBHelper.putItem(streamName, fragmentNumber, producerTime, serverTime, System.currentTimeMillis()); 82 | } 83 | } else { 84 | log.info("Fragment number is null. Skipping save checkpoint..."); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/lambda/EncodedFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples.lambda; 15 | 16 | import lombok.Builder; 17 | import lombok.Getter; 18 | import lombok.Setter; 19 | 20 | import java.nio.ByteBuffer; 21 | 22 | /** 23 | * Container class for H264 encoded frame 24 | */ 25 | @Getter 26 | @Builder 27 | public class EncodedFrame { 28 | 29 | private final ByteBuffer byteBuffer; 30 | private final ByteBuffer cpd; 31 | private final boolean isKeyFrame; 32 | @Setter 33 | private long timeCode; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/lambda/FragmentCheckpoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples.lambda; 15 | 16 | import lombok.Getter; 17 | import lombok.RequiredArgsConstructor; 18 | 19 | /** 20 | * Class for the lambda checkpoint stored in DDB. 21 | */ 22 | @Getter 23 | @RequiredArgsConstructor 24 | public class FragmentCheckpoint { 25 | 26 | private final String streamName; 27 | private final String fragmentNumber; 28 | private final Long serverTime; 29 | private final Long producerTime; 30 | private final Long updatedTime; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/examples/lambda/FragmentCheckpointManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples.lambda; 15 | 16 | import java.util.Optional; 17 | 18 | /** 19 | * FragmentCheckpoint Manager interface which manages the checkpoints for last processed fragments. 20 | */ 21 | public interface FragmentCheckpointManager { 22 | /** 23 | * Get last processed fragment details from checkpoint for given stream name. 24 | * 25 | * @param streamName KVS Stream name 26 | * @return Optional of last processed fragment item if checkpoint exists. Empty otherwise 27 | */ 28 | Optional getLastProcessedItem(String streamName); 29 | 30 | /** 31 | * Save last processed fragment details checkpoint for the given stream name. 32 | * 33 | * @param streamName KVS Stream name 34 | * @param fragmentNumber Last processed fragment's fragment number 35 | * @param producerTime Last processed fragment's producer time 36 | * @param serverTime Last processed fragment's server time 37 | */ 38 | void saveCheckPoint(String streamName, String fragmentNumber, Long producerTime, Long serverTime); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/kinesis/KinesisDataStreamsWorker.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.kinesis; 15 | 16 | import java.net.InetAddress; 17 | import java.util.UUID; 18 | 19 | import com.amazonaws.auth.AWSCredentialsProvider; 20 | import com.amazonaws.kinesisvideo.parser.rekognition.pojo.RekognizedFragmentsIndex; 21 | import com.amazonaws.regions.Regions; 22 | import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorFactory; 23 | import com.amazonaws.services.kinesis.clientlibrary.lib.worker.InitialPositionInStream; 24 | import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration; 25 | import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker; 26 | import lombok.AccessLevel; 27 | import lombok.RequiredArgsConstructor; 28 | 29 | /** 30 | * Sample Amazon Kinesis Application. 31 | */ 32 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 33 | public final class KinesisDataStreamsWorker implements Runnable { 34 | 35 | private static final String APPLICATION_NAME = "rekognition-kds-stream-application"; 36 | 37 | // Initial position in the stream when the application starts up for the first time. 38 | // Position can be one of LATEST (most recent data) or TRIM_HORIZON (oldest available data) 39 | private static final InitialPositionInStream SAMPLE_APPLICATION_INITIAL_POSITION_IN_STREAM = 40 | InitialPositionInStream.LATEST; 41 | 42 | private final Regions region; 43 | private final AWSCredentialsProvider credentialsProvider; 44 | private final String kdsStreamName; 45 | private final RekognizedFragmentsIndex rekognizedFragmentsIndex; 46 | 47 | public static KinesisDataStreamsWorker create(final Regions region, final AWSCredentialsProvider credentialsProvider, 48 | final String kdsStreamName, final RekognizedFragmentsIndex rekognizedFragmentsIndex) { 49 | return new KinesisDataStreamsWorker(region, credentialsProvider, kdsStreamName, rekognizedFragmentsIndex); 50 | } 51 | 52 | @Override 53 | public void run() { 54 | 55 | try { 56 | String workerId = InetAddress.getLocalHost().getCanonicalHostName() + ":" + UUID.randomUUID(); 57 | KinesisClientLibConfiguration kinesisClientLibConfiguration = 58 | new KinesisClientLibConfiguration(APPLICATION_NAME, 59 | kdsStreamName, 60 | credentialsProvider, 61 | workerId); 62 | kinesisClientLibConfiguration.withInitialPositionInStream(SAMPLE_APPLICATION_INITIAL_POSITION_IN_STREAM) 63 | .withRegionName(region.getName()); 64 | 65 | final IRecordProcessorFactory recordProcessorFactory = 66 | () -> new KinesisRecordProcessor(rekognizedFragmentsIndex, credentialsProvider); 67 | final Worker worker = new Worker(recordProcessorFactory, kinesisClientLibConfiguration); 68 | 69 | System.out.printf("Running %s to process stream %s as worker %s...", 70 | APPLICATION_NAME, 71 | kdsStreamName, 72 | workerId); 73 | 74 | int exitCode = 0; 75 | try { 76 | worker.run(); 77 | } catch (Throwable t) { 78 | System.err.println("Caught throwable while processing data."); 79 | t.printStackTrace(); 80 | exitCode = 1; 81 | } 82 | System.out.println("Exit code : " + exitCode); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/Frame.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLUtils; 17 | 18 | import lombok.AccessLevel; 19 | import lombok.AllArgsConstructor; 20 | import lombok.Builder; 21 | import lombok.Getter; 22 | import lombok.ToString; 23 | import org.apache.commons.lang3.Validate; 24 | 25 | import java.nio.ByteBuffer; 26 | 27 | 28 | 29 | /** 30 | * Class that captures the meta-data and data for a frame in a Kinesis Video Stream. 31 | * This is based on the content of a SimpleBlock in Mkv. 32 | */ 33 | @Getter 34 | @AllArgsConstructor(access=AccessLevel.PRIVATE) 35 | @Builder(toBuilder = true) 36 | @ToString(exclude = {"frameData"}) 37 | public class Frame { 38 | private final long trackNumber; 39 | private final int timeCode; 40 | private final boolean keyFrame; 41 | private final boolean invisible; 42 | private final boolean discardable; 43 | private final Lacing lacing; 44 | private final ByteBuffer frameData; 45 | 46 | public enum Lacing { NO, XIPH, EBML, FIXED_SIZE} 47 | 48 | /** 49 | * Create a frame object for the provided data buffer. 50 | * Do not create a copy of the data buffer while creating the frame object. 51 | * @param simpleBlockDataBuffer The data buffer. 52 | * @return A frame containing the data buffer. 53 | */ 54 | public static Frame withoutCopy(ByteBuffer simpleBlockDataBuffer) { 55 | FrameBuilder builder = getBuilderWithCommonParams(simpleBlockDataBuffer); 56 | 57 | ByteBuffer frameData = simpleBlockDataBuffer.slice(); 58 | return builder.frameData(frameData).build(); 59 | } 60 | 61 | /** 62 | * Create a frame object for the provided data buffer. 63 | * Create a copy of the data buffer while creating the frame object. 64 | * @param simpleBlockDataBuffer The data buffer. 65 | * @return A frame containing a copy of the data buffer. 66 | */ 67 | public static Frame withCopy(ByteBuffer simpleBlockDataBuffer) { 68 | FrameBuilder builder = getBuilderWithCommonParams(simpleBlockDataBuffer); 69 | ByteBuffer frameData = ByteBuffer.allocate(simpleBlockDataBuffer.remaining()); 70 | frameData.put(simpleBlockDataBuffer); 71 | frameData.flip(); 72 | return builder.frameData(frameData).build(); 73 | } 74 | 75 | /** 76 | * Create a FrameBuilder 77 | * @param simpleBlockDataBuffer 78 | * @return 79 | */ 80 | private static FrameBuilder getBuilderWithCommonParams(ByteBuffer simpleBlockDataBuffer) { 81 | FrameBuilder builder = Frame.builder() 82 | .trackNumber(EBMLUtils.readEbmlInt(simpleBlockDataBuffer)) 83 | .timeCode((int) EBMLUtils.readDataSignedInteger(simpleBlockDataBuffer, 2)); 84 | 85 | final long flag = EBMLUtils.readUnsignedIntegerSevenBytesOrLess(simpleBlockDataBuffer, 1); 86 | builder.keyFrame((flag & (0x1 << 7)) > 0) 87 | .invisible((flag & (0x1 << 3)) > 0) 88 | .discardable((flag & 0x1) > 0); 89 | 90 | final int laceValue = (int) (flag & 0x3 << 1) >> 1; 91 | final Lacing lacing = getLacing(laceValue); 92 | builder.lacing(lacing); 93 | return builder; 94 | } 95 | 96 | private static Lacing getLacing(int laceValue) { 97 | switch(laceValue) { 98 | case 0: 99 | return Lacing.NO; 100 | case 1: 101 | return Lacing.XIPH; 102 | case 2: 103 | return Lacing.EBML; 104 | case 3: 105 | return Lacing.FIXED_SIZE; 106 | default: 107 | Validate.isTrue(false, "Invalid value of lacing "+laceValue); 108 | } 109 | throw new IllegalArgumentException("Invalid value of lacing "+laceValue); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/FrameProcessException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | public class FrameProcessException extends MkvElementVisitException { 17 | public FrameProcessException(String message, Exception cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLElementMetaData; 17 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLUtils; 18 | import lombok.AccessLevel; 19 | import lombok.AllArgsConstructor; 20 | import lombok.Getter; 21 | import lombok.ToString; 22 | import org.apache.commons.lang3.Validate; 23 | 24 | import java.io.IOException; 25 | import java.nio.ByteBuffer; 26 | import java.nio.channels.WritableByteChannel; 27 | import java.util.List; 28 | 29 | /** 30 | * Common base class for all MkvElements 31 | */ 32 | @Getter 33 | @ToString 34 | @AllArgsConstructor(access = AccessLevel.PACKAGE) 35 | public abstract class MkvElement { 36 | protected static final int MAX_ID_AND_SIZE_BYTES = EBMLUtils.EBML_ID_MAX_BYTES + EBMLUtils.EBML_SIZE_MAX_BYTES; 37 | protected final EBMLElementMetaData elementMetaData; 38 | protected final List elementPath; 39 | 40 | protected boolean typeEquals(MkvElement other) { 41 | if (!other.getClass().equals(this.getClass())) { 42 | return false; 43 | } 44 | return elementMetaData.getTypeInfo().equals(other.getElementMetaData().getTypeInfo()); 45 | } 46 | 47 | public abstract boolean isMaster(); 48 | 49 | public abstract void accept(MkvElementVisitor visitor) throws MkvElementVisitException; 50 | 51 | public abstract boolean equivalent(MkvElement other); 52 | 53 | public void writeToChannel(WritableByteChannel outputChannel) throws MkvElementVisitException { 54 | 55 | } 56 | 57 | protected void writeByteBufferToChannel(ByteBuffer src, WritableByteChannel outputChannel) 58 | throws MkvElementVisitException { 59 | src.rewind(); 60 | int size = src.remaining(); 61 | try { 62 | int numBytes = outputChannel.write(src); 63 | Validate.isTrue(size == numBytes, "Output channel wrote " + size + " bytes instead of " + numBytes); 64 | } catch (IOException e) { 65 | throw new MkvElementVisitException("Writing to output channel failed", e); 66 | } finally { 67 | src.rewind(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvElementVisitException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | 17 | /** 18 | * An exception class that represents exceptions generated when a visitor is used process a MkvElement. 19 | */ 20 | public class MkvElementVisitException extends Exception { 21 | public MkvElementVisitException(String message, Exception cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvElementVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | /** 17 | * Base visitor for visiting the different types of elements vended by a {\link StreamingMkvReader}. 18 | */ 19 | public abstract class MkvElementVisitor { 20 | public abstract void visit(MkvStartMasterElement startMasterElement) throws MkvElementVisitException; 21 | 22 | public abstract void visit(MkvEndMasterElement endMasterElement) throws MkvElementVisitException; 23 | 24 | public abstract void visit(MkvDataElement dataElement) throws MkvElementVisitException; 25 | 26 | public boolean isDone() { 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvEndMasterElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLElementMetaData; 17 | import lombok.Builder; 18 | import lombok.ToString; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | * Class representing the end of a mkv master element. 24 | * It contains the metadata {@link EBMLElementMetaData} and the path if specified. 25 | */ 26 | 27 | @ToString(callSuper = true) 28 | public class MkvEndMasterElement extends MkvElement { 29 | @Builder 30 | private MkvEndMasterElement(EBMLElementMetaData elementMetaData, List elementPath) { 31 | super(elementMetaData, elementPath); 32 | } 33 | 34 | @Override 35 | public boolean isMaster() { 36 | return true; 37 | } 38 | 39 | @Override 40 | public void accept(MkvElementVisitor visitor) throws MkvElementVisitException { 41 | visitor.visit(this); 42 | } 43 | 44 | @Override 45 | public boolean equivalent(MkvElement other) { 46 | return typeEquals(other); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvStartMasterElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLElementMetaData; 17 | import lombok.Builder; 18 | import lombok.Getter; 19 | import lombok.ToString; 20 | 21 | import java.nio.ByteBuffer; 22 | import java.nio.channels.WritableByteChannel; 23 | import java.util.List; 24 | 25 | import static com.amazonaws.kinesisvideo.parser.ebml.EBMLUtils.UNKNOWN_LENGTH_VALUE; 26 | 27 | /** 28 | * Class representing the start of a mkv master element. 29 | * It includes the bytes containing the id and size of the element along with its {@link EBMLElementMetaData} 30 | * and its path (if specified). 31 | */ 32 | @Getter 33 | @ToString(callSuper = true, exclude = "idAndSizeRawBytes") 34 | public class MkvStartMasterElement extends MkvElement { 35 | private final long dataSize; 36 | 37 | private final ByteBuffer idAndSizeRawBytes = ByteBuffer.allocate(MAX_ID_AND_SIZE_BYTES); 38 | 39 | @Builder 40 | private MkvStartMasterElement(EBMLElementMetaData elementMetaData, 41 | List elementPath, 42 | long dataSize, 43 | ByteBuffer idAndSizeRawBytes) { 44 | super(elementMetaData, elementPath); 45 | this.dataSize = dataSize; 46 | this.idAndSizeRawBytes.put(idAndSizeRawBytes); 47 | this.idAndSizeRawBytes.flip(); 48 | idAndSizeRawBytes.rewind(); 49 | } 50 | 51 | @Override 52 | public boolean isMaster() { 53 | return true; 54 | } 55 | 56 | @Override 57 | public void accept(MkvElementVisitor visitor) throws MkvElementVisitException { 58 | visitor.visit(this); 59 | } 60 | 61 | @Override 62 | public boolean equivalent(MkvElement other) { 63 | return typeEquals(other) && this.dataSize == ((MkvStartMasterElement) other).dataSize; 64 | } 65 | 66 | public boolean isUnknownLength() { 67 | return dataSize == UNKNOWN_LENGTH_VALUE; 68 | } 69 | 70 | @Override 71 | public void writeToChannel(WritableByteChannel outputChannel) throws MkvElementVisitException { 72 | writeByteBufferToChannel(idAndSizeRawBytes, outputChannel); 73 | } 74 | 75 | public int getIdAndSizeRawBytesLength() { 76 | return idAndSizeRawBytes.limit(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvTypeInfoProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLTypeInfo; 17 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLTypeInfoProvider; 18 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 19 | import org.apache.commons.lang3.Validate; 20 | 21 | import java.lang.reflect.Field; 22 | import java.lang.reflect.Modifier; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | import java.util.Optional; 26 | 27 | /** 28 | * A class to provide the type information for the EBML elements used by Mkv. 29 | * This type information is used by the EBML parser. 30 | */ 31 | public class MkvTypeInfoProvider implements EBMLTypeInfoProvider { 32 | private final Map typeInfoMap = new HashMap(); 33 | 34 | public void load() throws IllegalAccessException { 35 | for (Field field : MkvTypeInfos.class.getDeclaredFields()) { 36 | if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(EBMLTypeInfo.class)) { 37 | EBMLTypeInfo type = (EBMLTypeInfo )field.get(null); 38 | Validate.isTrue(!typeInfoMap.containsKey(type.getId())); 39 | typeInfoMap.put(type.getId(), type); 40 | } 41 | } 42 | } 43 | 44 | 45 | @Override 46 | public Optional getType(int id) { 47 | return Optional.ofNullable(typeInfoMap.get(id)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/MkvValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import lombok.AllArgsConstructor; 17 | import lombok.Getter; 18 | import lombok.NonNull; 19 | 20 | import java.nio.ByteBuffer; 21 | 22 | /** 23 | * A class to contain the values of MKV elements. 24 | */ 25 | 26 | @AllArgsConstructor 27 | public class MkvValue { 28 | @NonNull 29 | private final T val; 30 | @Getter 31 | private final long originalDataSize; 32 | 33 | public T getVal() { 34 | if (ByteBuffer.class.isAssignableFrom(val.getClass())) { 35 | ByteBuffer byteBufferVal = (ByteBuffer)val; 36 | byteBufferVal.rewind(); 37 | } 38 | return val; 39 | } 40 | 41 | public boolean equals(Object otherObj) { 42 | if (otherObj == null) { 43 | return false; 44 | } 45 | if (!otherObj.getClass().equals(this.getClass())) { 46 | return false; 47 | } 48 | MkvValue other = (MkvValue) otherObj; 49 | if (!val.getClass().equals(other.val.getClass())) { 50 | return false; 51 | } 52 | if (originalDataSize != other.originalDataSize) { 53 | return false; 54 | } 55 | return getVal().equals(other.getVal()); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | int result = val.hashCode(); 61 | result = 31 * result + (int) (originalDataSize ^ (originalDataSize >>> 32)); 62 | return result; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/visitors/CompositeMkvElementVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv.visitors; 15 | 16 | import com.amazonaws.kinesisvideo.parser.mkv.MkvDataElement; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElement; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement; 21 | import com.amazonaws.kinesisvideo.parser.mkv.MkvStartMasterElement; 22 | import lombok.AccessLevel; 23 | import lombok.RequiredArgsConstructor; 24 | import lombok.extern.slf4j.Slf4j; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | /** 30 | * Class represents a composite visitor made out of multiple visitors. 31 | * 32 | */ 33 | @RequiredArgsConstructor(access = AccessLevel.PROTECTED) 34 | @Slf4j 35 | public class CompositeMkvElementVisitor extends MkvElementVisitor { 36 | protected final List childVisitors; 37 | 38 | public CompositeMkvElementVisitor(MkvElementVisitor... visitors){ 39 | childVisitors = new ArrayList<>(); 40 | for (MkvElementVisitor visitor : visitors) { 41 | childVisitors.add(visitor); 42 | } 43 | } 44 | 45 | @Override 46 | public void visit(MkvStartMasterElement startMasterElement) throws MkvElementVisitException { 47 | visitAll(startMasterElement); 48 | } 49 | 50 | @Override 51 | public void visit(MkvEndMasterElement endMasterElement) throws MkvElementVisitException { 52 | visitAll(endMasterElement); 53 | } 54 | 55 | @Override 56 | public void visit(MkvDataElement dataElement) throws MkvElementVisitException { 57 | visitAll(dataElement); 58 | } 59 | 60 | @Override 61 | public boolean isDone() { 62 | return childVisitors.stream().anyMatch(MkvElementVisitor::isDone); 63 | } 64 | 65 | private void visitAll(MkvElement element) throws MkvElementVisitException { 66 | for (MkvElementVisitor childVisitor : childVisitors) { 67 | if (log.isDebugEnabled()) { 68 | log.debug("Composite visitor calling {} on element {}", 69 | childVisitor.getClass().toString(), 70 | element.toString()); 71 | } 72 | element.accept(childVisitor); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/visitors/CopyVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv.visitors; 15 | 16 | import com.amazonaws.kinesisvideo.parser.mkv.MkvDataElement; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvStartMasterElement; 21 | 22 | import java.io.Closeable; 23 | import java.io.IOException; 24 | import java.io.OutputStream; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.WritableByteChannel; 27 | 28 | /** 29 | * This visitor can be used to copy the ray bytes of elements to an output stream. 30 | * It can be used to create a copy of an mkv stream being parsed. 31 | * It is particularly useful for debugging as part of a {@link CompositeMkvElementVisitor} since it allows creating 32 | * a copy of an input stream while also processing it in parallel. 33 | * 34 | * For start master elements, it copies the element header, namely its id and size. 35 | * For data elements, it copies the element header as well as the data bytes. 36 | * For end master elements, there are no raw bytes to copy. 37 | */ 38 | public class CopyVisitor extends MkvElementVisitor implements Closeable { 39 | private final WritableByteChannel outputChannel; 40 | 41 | public CopyVisitor(OutputStream outputStream) { 42 | this.outputChannel = Channels.newChannel(outputStream); 43 | } 44 | 45 | @Override 46 | public void visit(MkvStartMasterElement startMasterElement) throws MkvElementVisitException { 47 | startMasterElement.writeToChannel(outputChannel); 48 | } 49 | 50 | @Override 51 | public void visit(MkvEndMasterElement endMasterElement) throws MkvElementVisitException { 52 | } 53 | 54 | @Override 55 | public void visit(MkvDataElement dataElement) throws MkvElementVisitException { 56 | dataElement.writeToChannel(outputChannel); 57 | } 58 | 59 | @Override 60 | public void close() throws IOException { 61 | outputChannel.close(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/mkv/visitors/CountVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv.visitors; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLTypeInfo; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvDataElement; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElement; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement; 21 | import com.amazonaws.kinesisvideo.parser.mkv.MkvStartMasterElement; 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Collection; 26 | import java.util.HashMap; 27 | import java.util.HashSet; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.Set; 31 | import java.util.stream.Collectors; 32 | 33 | /** 34 | * A visitor used to count elements of a particular type 35 | */ 36 | @Slf4j 37 | public class CountVisitor extends MkvElementVisitor { 38 | private final Set typesToCount = new HashSet<>(); 39 | private final Map typeCount = new HashMap<>(); 40 | private final Map endMasterCount = new HashMap<>(); 41 | 42 | public CountVisitor(Collection typesToCount) { 43 | this.typesToCount.addAll(typesToCount); 44 | this.typesToCount.stream().forEach(t -> typeCount.put(t, 0)); 45 | this.typesToCount.stream() 46 | .filter(t -> t.getType().equals(EBMLTypeInfo.TYPE.MASTER)) 47 | .forEach(t -> endMasterCount.put(t, 0)); 48 | } 49 | 50 | public static CountVisitor create(EBMLTypeInfo... typesToCount) { 51 | List typeInfoList = new ArrayList<>(); 52 | for (EBMLTypeInfo typeToCount : typesToCount) { 53 | typeInfoList.add(typeToCount); 54 | } 55 | return new CountVisitor(typeInfoList); 56 | } 57 | 58 | @Override 59 | public void visit(MkvStartMasterElement startMasterElement) { 60 | incrementTypeCount(startMasterElement); 61 | } 62 | 63 | @Override 64 | public void visit(MkvEndMasterElement endMasterElement) { 65 | incrementCount(endMasterElement, endMasterCount); 66 | } 67 | 68 | @Override 69 | public void visit(MkvDataElement dataElement) { 70 | incrementTypeCount(dataElement); 71 | } 72 | 73 | public int getCount(EBMLTypeInfo typeInfo) { 74 | return typeCount.getOrDefault(typeInfo, 0); 75 | } 76 | 77 | public boolean doEndAndStartMasterElementsMatch() { 78 | List mismatchedStartAndEnd = typeCount.entrySet().stream().filter(e -> e.getKey().getType().equals(EBMLTypeInfo.TYPE.MASTER)).filter(e -> typeCount.get(e.getKey()) != endMasterCount.get(e.getKey())).map(Map.Entry::getKey).collect( 79 | Collectors.toList()); 80 | if (!mismatchedStartAndEnd.isEmpty()) { 81 | log.warn(" Some end and master element counts did not match: "); 82 | mismatchedStartAndEnd.stream().forEach(t -> log.warn("Element {} start count {} end count {}", t, typeCount.get(t), endMasterCount.get(t))); 83 | return false; 84 | } 85 | return true; 86 | } 87 | 88 | private void incrementTypeCount(MkvElement mkvElement) { 89 | incrementCount(mkvElement, typeCount); 90 | } 91 | 92 | private void incrementCount(MkvElement mkvElement, Map mapToUpdate) { 93 | if (typesToCount.contains(mkvElement.getElementMetaData().getTypeInfo())) { 94 | log.debug("Element {} to Count found", mkvElement); 95 | int oldValue = mapToUpdate.get(mkvElement.getElementMetaData().getTypeInfo()); 96 | mapToUpdate.put(mkvElement.getElementMetaData().getTypeInfo(), oldValue + 1); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/BoundingBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class BoundingBox implements Serializable 31 | { 32 | 33 | @JsonProperty("Height") 34 | private Double height; 35 | @JsonProperty("Width") 36 | private Double width; 37 | @JsonProperty("Left") 38 | private Double left; 39 | @JsonProperty("Top") 40 | private Double top; 41 | @JsonIgnore 42 | private Map additionalProperties = new HashMap(); 43 | private final static long serialVersionUID = -3845089061670074615L; 44 | 45 | @JsonProperty("Height") 46 | public Double getHeight() { 47 | return height; 48 | } 49 | 50 | @JsonProperty("Height") 51 | public void setHeight(Double height) { 52 | this.height = height; 53 | } 54 | 55 | @JsonProperty("Width") 56 | public Double getWidth() { 57 | return width; 58 | } 59 | 60 | @JsonProperty("Width") 61 | public void setWidth(Double width) { 62 | this.width = width; 63 | } 64 | 65 | @JsonProperty("Left") 66 | public Double getLeft() { 67 | return left; 68 | } 69 | 70 | @JsonProperty("Left") 71 | public void setLeft(Double left) { 72 | this.left = left; 73 | } 74 | 75 | @JsonProperty("Top") 76 | public Double getTop() { 77 | return top; 78 | } 79 | 80 | @JsonProperty("Top") 81 | public void setTop(Double top) { 82 | this.top = top; 83 | } 84 | 85 | @JsonAnyGetter 86 | public Map getAdditionalProperties() { 87 | return this.additionalProperties; 88 | } 89 | 90 | @JsonAnySetter 91 | public void setAdditionalProperty(String name, Object value) { 92 | this.additionalProperties.put(name, value); 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return new ToStringBuilder(this) 98 | .append("height", height) 99 | .append("width", width) 100 | .append("left", left) 101 | .append("top", top) 102 | .append("additionalProperties", additionalProperties) 103 | .toString(); 104 | } 105 | 106 | @Override 107 | public int hashCode() { 108 | return new HashCodeBuilder() 109 | .append(height) 110 | .append(additionalProperties) 111 | .append(width) 112 | .append(left) 113 | .append(top) 114 | .toHashCode(); 115 | } 116 | 117 | @Override 118 | public boolean equals(Object other) { 119 | if (other == this) { 120 | return true; 121 | } 122 | if ((other instanceof BoundingBox) == false) { 123 | return false; 124 | } 125 | BoundingBox rhs = ((BoundingBox) other); 126 | return new EqualsBuilder() 127 | .append(height, rhs.height) 128 | .append(additionalProperties, rhs.additionalProperties) 129 | .append(width, rhs.width) 130 | .append(left, rhs.left) 131 | .append(top, rhs.top) 132 | .isEquals(); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/Face.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class Face implements Serializable 31 | { 32 | 33 | @JsonProperty("BoundingBox") 34 | private BoundingBox boundingBox; 35 | @JsonProperty("FaceId") 36 | private String faceId; 37 | @JsonProperty("Confidence") 38 | private Double confidence; 39 | @JsonProperty("ImageId") 40 | private String imageId; 41 | @JsonProperty("ExternalImageId") 42 | private String externalImageId; 43 | @JsonIgnore 44 | private Map additionalProperties = new HashMap(); 45 | private final static long serialVersionUID = 4320869723686571816L; 46 | 47 | @JsonProperty("BoundingBox") 48 | public BoundingBox getBoundingBox() { 49 | return boundingBox; 50 | } 51 | 52 | @JsonProperty("BoundingBox") 53 | public void setBoundingBox(BoundingBox boundingBox) { 54 | this.boundingBox = boundingBox; 55 | } 56 | 57 | @JsonProperty("FaceId") 58 | public String getFaceId() { 59 | return faceId; 60 | } 61 | 62 | @JsonProperty("FaceId") 63 | public void setFaceId(String faceId) { 64 | this.faceId = faceId; 65 | } 66 | 67 | @JsonProperty("Confidence") 68 | public Double getConfidence() { 69 | return confidence; 70 | } 71 | 72 | @JsonProperty("Confidence") 73 | public void setConfidence(Double confidence) { 74 | this.confidence = confidence; 75 | } 76 | 77 | @JsonProperty("ImageId") 78 | public String getImageId() { 79 | return imageId; 80 | } 81 | 82 | @JsonProperty("ImageId") 83 | public void setImageId(String imageId) { 84 | this.imageId = imageId; 85 | } 86 | 87 | @JsonProperty("ExternalImageId") 88 | public String getExternalImageId() { 89 | return externalImageId; 90 | } 91 | 92 | @JsonProperty("ExternalImageId") 93 | public void setExternalImageId(String externalImageId) { 94 | this.externalImageId = externalImageId; 95 | } 96 | 97 | @JsonAnyGetter 98 | public Map getAdditionalProperties() { 99 | return this.additionalProperties; 100 | } 101 | 102 | @JsonAnySetter 103 | public void setAdditionalProperty(String name, Object value) { 104 | this.additionalProperties.put(name, value); 105 | } 106 | 107 | @Override 108 | public String toString() { 109 | return new ToStringBuilder(this).append("boundingBox", boundingBox) 110 | .append("faceId", faceId).append("confidence", confidence) 111 | .append("imageId", imageId) 112 | .append("externalImageId", externalImageId) 113 | .append("additionalProperties", additionalProperties).toString(); 114 | } 115 | 116 | @Override 117 | public int hashCode() { 118 | return new HashCodeBuilder().append(boundingBox) 119 | .append(imageId) 120 | .append(externalImageId) 121 | .append(faceId) 122 | .append(additionalProperties).append(confidence).toHashCode(); 123 | } 124 | 125 | @Override 126 | public boolean equals(Object other) { 127 | if (other == this) { 128 | return true; 129 | } 130 | if ((other instanceof Face) == false) { 131 | return false; 132 | } 133 | Face rhs = ((Face) other); 134 | return new EqualsBuilder().append(boundingBox, rhs.boundingBox) 135 | .append(imageId, rhs.imageId) 136 | .append(externalImageId, rhs.externalImageId) 137 | .append(faceId, rhs.faceId).append(additionalProperties, rhs.additionalProperties) 138 | .append(confidence, rhs.confidence).isEquals(); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/FaceSearchResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 22 | import com.fasterxml.jackson.annotation.JsonAnySetter; 23 | import com.fasterxml.jackson.annotation.JsonIgnore; 24 | import com.fasterxml.jackson.annotation.JsonInclude; 25 | import com.fasterxml.jackson.annotation.JsonProperty; 26 | import org.apache.commons.lang3.builder.EqualsBuilder; 27 | import org.apache.commons.lang3.builder.HashCodeBuilder; 28 | import org.apache.commons.lang3.builder.ToStringBuilder; 29 | 30 | @JsonInclude(JsonInclude.Include.NON_NULL) 31 | public class FaceSearchResponse implements Serializable 32 | { 33 | 34 | @JsonProperty("DetectedFace") 35 | private DetectedFace detectedFace; 36 | @JsonProperty("MatchedFaces") 37 | private List matchedFaces = null; 38 | @JsonIgnore 39 | private Map additionalProperties = new HashMap(); 40 | private final static long serialVersionUID = -5645575235038800306L; 41 | 42 | @JsonProperty("DetectedFace") 43 | public DetectedFace getDetectedFace() { 44 | return detectedFace; 45 | } 46 | 47 | @JsonProperty("DetectedFace") 48 | public void setDetectedFace(DetectedFace detectedFace) { 49 | this.detectedFace = detectedFace; 50 | } 51 | 52 | @JsonProperty("MatchedFaces") 53 | public List getMatchedFaces() { 54 | return matchedFaces; 55 | } 56 | 57 | @JsonProperty("MatchedFaces") 58 | public void setMatchedFaces(List matchedFaces) { 59 | this.matchedFaces = matchedFaces; 60 | } 61 | 62 | @JsonAnyGetter 63 | public Map getAdditionalProperties() { 64 | return this.additionalProperties; 65 | } 66 | 67 | @JsonAnySetter 68 | public void setAdditionalProperty(String name, Object value) { 69 | this.additionalProperties.put(name, value); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return new ToStringBuilder(this) 75 | .append("detectedFace", detectedFace) 76 | .append("matchedFaces", matchedFaces) 77 | .append("additionalProperties", additionalProperties).toString(); 78 | } 79 | 80 | @Override 81 | public int hashCode() { 82 | return new HashCodeBuilder() 83 | .append(matchedFaces) 84 | .append(detectedFace) 85 | .append(additionalProperties).toHashCode(); 86 | } 87 | 88 | @Override 89 | public boolean equals(Object other) { 90 | if (other == this) { 91 | return true; 92 | } 93 | if ((other instanceof FaceSearchResponse) == false) { 94 | return false; 95 | } 96 | FaceSearchResponse rhs = ((FaceSearchResponse) other); 97 | return new EqualsBuilder() 98 | .append(matchedFaces, rhs.matchedFaces) 99 | .append(detectedFace, rhs.detectedFace) 100 | .append(additionalProperties, rhs.additionalProperties).isEquals(); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/FaceType.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.awt.Color; 17 | 18 | import lombok.Getter; 19 | import lombok.RequiredArgsConstructor; 20 | 21 | /** 22 | * Enum which lists down the sample types of the faces detected in given frame. This list can be expanded 23 | * based on the face type given in external image id while creating face collection. 24 | * 25 | * For more information please refer 26 | * https://docs.aws.amazon.com/rekognition/latest/dg/add-faces-to-collection-procedure.html 27 | */ 28 | @Getter 29 | @RequiredArgsConstructor 30 | public enum FaceType { 31 | TRUSTED (Color.GREEN, "Trusted"), 32 | CRIMINAL (Color.RED, "Criminal"), 33 | UNKNOWN (Color.YELLOW, "Unknown"), 34 | NOT_RECOGNIZED (Color.PINK, "NotRecognized"), 35 | ALL (Color.BLACK, "All"); 36 | 37 | private final Color color; 38 | private final String prefix; 39 | 40 | public static FaceType fromString(String value) { 41 | for (int i = 0; i < FaceType.values().length; i++) { 42 | if(FaceType.values()[i].getPrefix().toUpperCase().equals(value.toUpperCase())) 43 | return FaceType.values()[i]; 44 | } 45 | return FaceType.UNKNOWN; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/InputInformation.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class InputInformation implements Serializable 31 | { 32 | 33 | @JsonProperty("KinesisVideo") 34 | private KinesisVideo kinesisVideo; 35 | @JsonIgnore 36 | private Map additionalProperties = new HashMap(); 37 | private final static long serialVersionUID = 4448679967188698414L; 38 | 39 | @JsonProperty("KinesisVideo") 40 | public KinesisVideo getKinesisVideo() { 41 | return kinesisVideo; 42 | } 43 | 44 | @JsonProperty("KinesisVideo") 45 | public void setKinesisVideo(KinesisVideo kinesisVideo) { 46 | this.kinesisVideo = kinesisVideo; 47 | } 48 | 49 | @JsonAnyGetter 50 | public Map getAdditionalProperties() { 51 | return this.additionalProperties; 52 | } 53 | 54 | @JsonAnySetter 55 | public void setAdditionalProperty(String name, Object value) { 56 | this.additionalProperties.put(name, value); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return new ToStringBuilder(this) 62 | .append("kinesisVideo", kinesisVideo) 63 | .append("additionalProperties", additionalProperties).toString(); 64 | } 65 | 66 | @Override 67 | public int hashCode() { 68 | return new HashCodeBuilder() 69 | .append(kinesisVideo) 70 | .append(additionalProperties).toHashCode(); 71 | } 72 | 73 | @Override 74 | public boolean equals(Object other) { 75 | if (other == this) { 76 | return true; 77 | } 78 | if ((other instanceof InputInformation) == false) { 79 | return false; 80 | } 81 | InputInformation rhs = ((InputInformation) other); 82 | return new EqualsBuilder() 83 | .append(kinesisVideo, rhs.kinesisVideo) 84 | .append(additionalProperties, rhs.additionalProperties).isEquals(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/Landmark.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class Landmark implements Serializable 31 | { 32 | 33 | @JsonProperty("X") 34 | private Double x; 35 | @JsonProperty("Y") 36 | private Double y; 37 | @JsonProperty("Type") 38 | private String type; 39 | @JsonIgnore 40 | private Map additionalProperties = new HashMap(); 41 | private final static long serialVersionUID = 8108892948615651543L; 42 | 43 | @JsonProperty("X") 44 | public Double getX() { 45 | return x; 46 | } 47 | 48 | @JsonProperty("X") 49 | public void setX(Double x) { 50 | this.x = x; 51 | } 52 | 53 | @JsonProperty("Y") 54 | public Double getY() { 55 | return y; 56 | } 57 | 58 | @JsonProperty("Y") 59 | public void setY(Double y) { 60 | this.y = y; 61 | } 62 | 63 | @JsonProperty("Type") 64 | public String getType() { 65 | return type; 66 | } 67 | 68 | @JsonProperty("Type") 69 | public void setType(String type) { 70 | this.type = type; 71 | } 72 | 73 | @JsonAnyGetter 74 | public Map getAdditionalProperties() { 75 | return this.additionalProperties; 76 | } 77 | 78 | @JsonAnySetter 79 | public void setAdditionalProperty(String name, Object value) { 80 | this.additionalProperties.put(name, value); 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return new ToStringBuilder(this) 86 | .append("x", x) 87 | .append("y", y) 88 | .append("type", type) 89 | .append("additionalProperties", additionalProperties).toString(); 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return new HashCodeBuilder() 95 | .append(additionalProperties) 96 | .append(type) 97 | .append(y) 98 | .append(x).toHashCode(); 99 | } 100 | 101 | @Override 102 | public boolean equals(Object other) { 103 | if (other == this) { 104 | return true; 105 | } 106 | if ((other instanceof Landmark) == false) { 107 | return false; 108 | } 109 | Landmark rhs = ((Landmark) other); 110 | return new EqualsBuilder() 111 | .append(additionalProperties, rhs.additionalProperties) 112 | .append(type, rhs.type) 113 | .append(y, rhs.y) 114 | .append(x, rhs.x).isEquals(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/MatchedFace.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class MatchedFace implements Serializable 31 | { 32 | 33 | @JsonProperty("Similarity") 34 | private Double similarity; 35 | @JsonProperty("Face") 36 | private Face face; 37 | @JsonIgnore 38 | private Map additionalProperties = new HashMap(); 39 | private final static long serialVersionUID = -5269363379216197335L; 40 | 41 | @JsonProperty("Similarity") 42 | public Double getSimilarity() { 43 | return similarity; 44 | } 45 | 46 | @JsonProperty("Similarity") 47 | public void setSimilarity(Double similarity) { 48 | this.similarity = similarity; 49 | } 50 | 51 | @JsonProperty("Face") 52 | public Face getFace() { 53 | return face; 54 | } 55 | 56 | @JsonProperty("Face") 57 | public void setFace(Face face) { 58 | this.face = face; 59 | } 60 | 61 | @JsonAnyGetter 62 | public Map getAdditionalProperties() { 63 | return this.additionalProperties; 64 | } 65 | 66 | @JsonAnySetter 67 | public void setAdditionalProperty(String name, Object value) { 68 | this.additionalProperties.put(name, value); 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return new ToStringBuilder(this) 74 | .append("similarity", similarity) 75 | .append("face", face) 76 | .append("additionalProperties", additionalProperties).toString(); 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | return new HashCodeBuilder() 82 | .append(face) 83 | .append(additionalProperties) 84 | .append(similarity).toHashCode(); 85 | } 86 | 87 | @Override 88 | public boolean equals(Object other) { 89 | if (other == this) { 90 | return true; 91 | } 92 | if ((other instanceof MatchedFace) == false) { 93 | return false; 94 | } 95 | MatchedFace rhs = ((MatchedFace) other); 96 | return new EqualsBuilder() 97 | .append(face, rhs.face) 98 | .append(additionalProperties, rhs.additionalProperties) 99 | .append(similarity, rhs.similarity).isEquals(); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/Pose.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class Pose implements Serializable 31 | { 32 | 33 | @JsonProperty("Pitch") 34 | private Double pitch; 35 | @JsonProperty("Roll") 36 | private Double roll; 37 | @JsonProperty("Yaw") 38 | private Double yaw; 39 | @JsonIgnore 40 | private Map additionalProperties = new HashMap(); 41 | private final static long serialVersionUID = 5134659150043632590L; 42 | 43 | @JsonProperty("Pitch") 44 | public Double getPitch() { 45 | return pitch; 46 | } 47 | 48 | @JsonProperty("Pitch") 49 | public void setPitch(Double pitch) { 50 | this.pitch = pitch; 51 | } 52 | 53 | @JsonProperty("Roll") 54 | public Double getRoll() { 55 | return roll; 56 | } 57 | 58 | @JsonProperty("Roll") 59 | public void setRoll(Double roll) { 60 | this.roll = roll; 61 | } 62 | 63 | @JsonProperty("Yaw") 64 | public Double getYaw() { 65 | return yaw; 66 | } 67 | 68 | @JsonProperty("Yaw") 69 | public void setYaw(Double yaw) { 70 | this.yaw = yaw; 71 | } 72 | 73 | @JsonAnyGetter 74 | public Map getAdditionalProperties() { 75 | return this.additionalProperties; 76 | } 77 | 78 | @JsonAnySetter 79 | public void setAdditionalProperty(String name, Object value) { 80 | this.additionalProperties.put(name, value); 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return new ToStringBuilder(this) 86 | .append("pitch", pitch) 87 | .append("roll", roll) 88 | .append("yaw", yaw) 89 | .append("additionalProperties", additionalProperties).toString(); 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return new HashCodeBuilder() 95 | .append(yaw) 96 | .append(roll) 97 | .append(additionalProperties) 98 | .append(pitch).toHashCode(); 99 | } 100 | 101 | @Override 102 | public boolean equals(Object other) { 103 | if (other == this) { 104 | return true; 105 | } 106 | if ((other instanceof Pose) == false) { 107 | return false; 108 | } 109 | Pose rhs = ((Pose) other); 110 | return new EqualsBuilder() 111 | .append(yaw, rhs.yaw) 112 | .append(roll, rhs.roll) 113 | .append(additionalProperties, rhs.additionalProperties) 114 | .append(pitch, rhs.pitch).isEquals(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/Quality.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | @JsonInclude(JsonInclude.Include.NON_NULL) 30 | public class Quality implements Serializable 31 | { 32 | 33 | @JsonProperty("Brightness") 34 | private Double brightness; 35 | @JsonProperty("Sharpness") 36 | private Double sharpness; 37 | @JsonIgnore 38 | private Map additionalProperties = new HashMap(); 39 | private final static long serialVersionUID = 2898836203617659983L; 40 | 41 | @JsonProperty("Brightness") 42 | public Double getBrightness() { 43 | return brightness; 44 | } 45 | 46 | @JsonProperty("Brightness") 47 | public void setBrightness(Double brightness) { 48 | this.brightness = brightness; 49 | } 50 | 51 | @JsonProperty("Sharpness") 52 | public Double getSharpness() { 53 | return sharpness; 54 | } 55 | 56 | @JsonProperty("Sharpness") 57 | public void setSharpness(Double sharpness) { 58 | this.sharpness = sharpness; 59 | } 60 | 61 | @JsonAnyGetter 62 | public Map getAdditionalProperties() { 63 | return this.additionalProperties; 64 | } 65 | 66 | @JsonAnySetter 67 | public void setAdditionalProperty(String name, Object value) { 68 | this.additionalProperties.put(name, value); 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return new ToStringBuilder(this) 74 | .append("brightness", brightness) 75 | .append("sharpness", sharpness) 76 | .append("additionalProperties", additionalProperties).toString(); 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | return new HashCodeBuilder() 82 | .append(sharpness) 83 | .append(brightness) 84 | .append(additionalProperties).toHashCode(); 85 | } 86 | 87 | @Override 88 | public boolean equals(Object other) { 89 | if (other == this) { 90 | return true; 91 | } 92 | if ((other instanceof Quality) == false) { 93 | return false; 94 | } 95 | Quality rhs = ((Quality) other); 96 | return new EqualsBuilder() 97 | .append(sharpness, rhs.sharpness) 98 | .append(brightness, rhs.brightness) 99 | .append(additionalProperties, rhs.additionalProperties).isEquals(); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/RekognitionInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import lombok.Builder; 17 | import lombok.Value; 18 | 19 | /** 20 | * Input for Rekognition stream processor. 21 | */ 22 | @Value 23 | @Builder 24 | public class RekognitionInput { 25 | private String kinesisVideoStreamArn; 26 | private String kinesisDataStreamArn; 27 | private String iamRoleArn; 28 | private String faceCollectionId; 29 | private String streamingProcessorName; 30 | private Float matchThreshold; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/RekognitionOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 22 | import com.fasterxml.jackson.annotation.JsonAnySetter; 23 | import com.fasterxml.jackson.annotation.JsonIgnore; 24 | import com.fasterxml.jackson.annotation.JsonInclude; 25 | import com.fasterxml.jackson.annotation.JsonProperty; 26 | import org.apache.commons.lang3.builder.EqualsBuilder; 27 | import org.apache.commons.lang3.builder.HashCodeBuilder; 28 | import org.apache.commons.lang3.builder.ToStringBuilder; 29 | 30 | @JsonInclude(JsonInclude.Include.NON_NULL) 31 | public class RekognitionOutput implements Serializable 32 | { 33 | 34 | @JsonProperty("InputInformation") 35 | private InputInformation inputInformation; 36 | @JsonProperty("StreamProcessorInformation") 37 | private StreamProcessorInformation streamProcessorInformation; 38 | @JsonProperty("FaceSearchResponse") 39 | private List faceSearchResponse = null; 40 | @JsonIgnore 41 | private Map additionalProperties = new HashMap(); 42 | private final static long serialVersionUID = -4243167512470204665L; 43 | 44 | @JsonProperty("InputInformation") 45 | public InputInformation getInputInformation() { 46 | return inputInformation; 47 | } 48 | 49 | @JsonProperty("InputInformation") 50 | public void setInputInformation(InputInformation inputInformation) { 51 | this.inputInformation = inputInformation; 52 | } 53 | 54 | @JsonProperty("StreamProcessorInformation") 55 | public StreamProcessorInformation getStreamProcessorInformation() { 56 | return streamProcessorInformation; 57 | } 58 | 59 | @JsonProperty("StreamProcessorInformation") 60 | public void setStreamProcessorInformation(StreamProcessorInformation streamProcessorInformation) { 61 | this.streamProcessorInformation = streamProcessorInformation; 62 | } 63 | 64 | @JsonProperty("FaceSearchResponse") 65 | public List getFaceSearchResponse() { 66 | return faceSearchResponse; 67 | } 68 | 69 | @JsonProperty("FaceSearchResponse") 70 | public void setFaceSearchResponse(List faceSearchResponse) { 71 | this.faceSearchResponse = faceSearchResponse; 72 | } 73 | 74 | @JsonAnyGetter 75 | public Map getAdditionalProperties() { 76 | return this.additionalProperties; 77 | } 78 | 79 | @JsonAnySetter 80 | public void setAdditionalProperty(String name, Object value) { 81 | this.additionalProperties.put(name, value); 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return new ToStringBuilder(this) 87 | .append("inputInformation", inputInformation) 88 | .append("streamProcessorInformation", streamProcessorInformation) 89 | .append("faceSearchResponse", faceSearchResponse) 90 | .append("additionalProperties", additionalProperties).toString(); 91 | } 92 | 93 | @Override 94 | public int hashCode() { 95 | return new HashCodeBuilder() 96 | .append(inputInformation) 97 | .append(additionalProperties) 98 | .append(faceSearchResponse) 99 | .append(streamProcessorInformation).toHashCode(); 100 | } 101 | 102 | @Override 103 | public boolean equals(Object other) { 104 | if (other == this) { 105 | return true; 106 | } 107 | if ((other instanceof RekognitionOutput) == false) { 108 | return false; 109 | } 110 | RekognitionOutput rhs = ((RekognitionOutput) other); 111 | return new EqualsBuilder() 112 | .append(inputInformation, rhs.inputInformation) 113 | .append(additionalProperties, rhs.additionalProperties) 114 | .append(faceSearchResponse, rhs.faceSearchResponse) 115 | .append(streamProcessorInformation, rhs.streamProcessorInformation).isEquals(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/RekognizedOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | import lombok.Builder; 20 | import lombok.Getter; 21 | import lombok.Setter; 22 | import lombok.ToString; 23 | 24 | 25 | @Builder 26 | @Getter 27 | @ToString 28 | public class RekognizedOutput { 29 | 30 | private String fragmentNumber; 31 | private Double frameOffsetInSeconds; 32 | private Double serverTimestamp; 33 | private Double producerTimestamp; 34 | 35 | @Setter 36 | private String faceId; 37 | private double detectedTime; 38 | @Builder.Default 39 | private List faceSearchOutputs = new ArrayList<>(); 40 | 41 | public void addFaceSearchOutput(FaceSearchOutput faceSearchOutput) { 42 | this.faceSearchOutputs.add(faceSearchOutput); 43 | } 44 | 45 | @Getter 46 | @Builder 47 | @ToString 48 | public static class FaceSearchOutput { 49 | 50 | private DetectedFace detectedFace; 51 | @Builder.Default 52 | private List matchedFaceList = new ArrayList<>(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/rekognition/pojo/StreamProcessorInformation.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.pojo; 15 | 16 | import java.io.Serializable; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 21 | import com.fasterxml.jackson.annotation.JsonAnySetter; 22 | import com.fasterxml.jackson.annotation.JsonIgnore; 23 | import com.fasterxml.jackson.annotation.JsonInclude; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import org.apache.commons.lang3.builder.EqualsBuilder; 26 | import org.apache.commons.lang3.builder.HashCodeBuilder; 27 | import org.apache.commons.lang3.builder.ToStringBuilder; 28 | 29 | 30 | @JsonInclude(JsonInclude.Include.NON_NULL) 31 | public class StreamProcessorInformation implements Serializable 32 | { 33 | 34 | @JsonProperty("Status") 35 | private String status; 36 | @JsonIgnore 37 | private Map additionalProperties = new HashMap(); 38 | private final static long serialVersionUID = -4043725115310892727L; 39 | 40 | @JsonProperty("Status") 41 | public String getStatus() { 42 | return status; 43 | } 44 | 45 | @JsonProperty("Status") 46 | public void setStatus(String status) { 47 | this.status = status; 48 | } 49 | 50 | @JsonAnyGetter 51 | public Map getAdditionalProperties() { 52 | return this.additionalProperties; 53 | } 54 | 55 | @JsonAnySetter 56 | public void setAdditionalProperty(String name, Object value) { 57 | this.additionalProperties.put(name, value); 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return new ToStringBuilder(this) 63 | .append("status", status) 64 | .append("additionalProperties", additionalProperties).toString(); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return new HashCodeBuilder() 70 | .append(status) 71 | .append(additionalProperties).toHashCode(); 72 | } 73 | 74 | @Override 75 | public boolean equals(Object other) { 76 | if (other == this) { 77 | return true; 78 | } 79 | if ((other instanceof StreamProcessorInformation) == false) { 80 | return false; 81 | } 82 | StreamProcessorInformation rhs = ((StreamProcessorInformation) other); 83 | return new EqualsBuilder() 84 | .append(status, rhs.status) 85 | .append(additionalProperties, rhs.additionalProperties).isEquals(); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/BufferedImageUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import javax.annotation.Nonnull; 17 | import java.awt.Color; 18 | import java.awt.Font; 19 | import java.awt.Graphics; 20 | import java.awt.image.BufferedImage; 21 | 22 | public final class BufferedImageUtil { 23 | private static final int DEFAULT_FONT_SIZE = 13; 24 | private static final Font DEFAULT_FONT = new Font(null, Font.CENTER_BASELINE, DEFAULT_FONT_SIZE); 25 | 26 | public static void addTextToImage(@Nonnull BufferedImage bufferedImage, String text, int pixelX, int pixelY) { 27 | Graphics graphics = bufferedImage.getGraphics(); 28 | graphics.setColor(Color.YELLOW); 29 | graphics.setFont(DEFAULT_FONT); 30 | for (String line : text.split(MkvTag.class.getSimpleName())) { 31 | graphics.drawString(line, pixelX, pixelY += graphics.getFontMetrics().getHeight()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/H264FrameDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.mkv.Frame; 17 | import com.amazonaws.kinesisvideo.parser.mkv.FrameProcessException; 18 | import lombok.Getter; 19 | import lombok.extern.slf4j.Slf4j; 20 | import org.jcodec.codecs.h264.H264Decoder; 21 | import org.jcodec.codecs.h264.mp4.AvcCBox; 22 | import org.jcodec.common.model.ColorSpace; 23 | import org.jcodec.common.model.Picture; 24 | import org.jcodec.scale.AWTUtil; 25 | import org.jcodec.scale.Transform; 26 | import org.jcodec.scale.Yuv420jToRgb; 27 | 28 | import java.awt.image.BufferedImage; 29 | import java.nio.ByteBuffer; 30 | import java.util.List; 31 | import java.util.Optional; 32 | 33 | import static org.jcodec.codecs.h264.H264Utils.splitMOVPacket; 34 | 35 | /** 36 | * H264 Frame Decoder class which uses JCodec decoder to decode frames. 37 | */ 38 | @Slf4j 39 | public class H264FrameDecoder implements FrameVisitor.FrameProcessor { 40 | 41 | private final H264Decoder decoder = new H264Decoder(); 42 | private final Transform transform = new Yuv420jToRgb(); 43 | 44 | @Getter 45 | private int frameCount; 46 | 47 | private byte[] codecPrivateData; 48 | 49 | @Override 50 | public void process(final Frame frame, final MkvTrackMetadata trackMetadata, 51 | final Optional fragmentMetadata) throws FrameProcessException { 52 | decodeH264Frame(frame, trackMetadata); 53 | } 54 | 55 | public BufferedImage decodeH264Frame(final Frame frame, final MkvTrackMetadata trackMetadata) { 56 | final ByteBuffer frameBuffer = frame.getFrameData(); 57 | final int pixelWidth = trackMetadata.getPixelWidth().get().intValue(); 58 | final int pixelHeight = trackMetadata.getPixelHeight().get().intValue(); 59 | codecPrivateData = trackMetadata.getCodecPrivateData().array(); 60 | log.debug("Decoding frames ... "); 61 | // Read the bytes that appear to comprise the header 62 | // See: https://www.matroska.org/technical/specs/index.html#simpleblock_structure 63 | 64 | final Picture rgb = Picture.create(pixelWidth, pixelHeight, ColorSpace.RGB); 65 | final BufferedImage bufferedImage = new BufferedImage(pixelWidth, pixelHeight, BufferedImage.TYPE_3BYTE_BGR); 66 | final AvcCBox avcC = AvcCBox.parseAvcCBox(ByteBuffer.wrap(codecPrivateData)); 67 | 68 | decoder.addSps(avcC.getSpsList()); 69 | decoder.addPps(avcC.getPpsList()); 70 | 71 | final Picture buf = Picture.create(pixelWidth + ((16 - (pixelWidth % 16)) % 16), 72 | pixelHeight + ((16 - (pixelHeight % 16)) % 16), ColorSpace.YUV420J); 73 | final List byteBuffers = splitMOVPacket(frameBuffer, avcC); 74 | final Picture pic = decoder.decodeFrameFromNals(byteBuffers, buf.getData()); 75 | 76 | if (pic != null) { 77 | // Work around for color issues in JCodec 78 | // https://github.com/jcodec/jcodec/issues/59 79 | // https://github.com/jcodec/jcodec/issues/192 80 | final byte[][] dataTemp = new byte[3][pic.getData().length]; 81 | dataTemp[0] = pic.getPlaneData(0); 82 | dataTemp[1] = pic.getPlaneData(2); 83 | dataTemp[2] = pic.getPlaneData(1); 84 | 85 | final Picture tmpBuf = Picture.createPicture(pixelWidth, pixelHeight, dataTemp, ColorSpace.YUV420J); 86 | transform.transform(tmpBuf, rgb); 87 | AWTUtil.toBufferedImage(rgb, bufferedImage); 88 | frameCount++; 89 | } 90 | return bufferedImage; 91 | } 92 | 93 | public ByteBuffer getCodecPrivateData() { 94 | return ByteBuffer.wrap(codecPrivateData); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/H264FrameEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.examples.lambda.EncodedFrame; 17 | import lombok.extern.slf4j.Slf4j; 18 | import org.jcodec.codecs.h264.H264Encoder; 19 | import org.jcodec.codecs.h264.H264Utils; 20 | import org.jcodec.codecs.h264.encode.H264FixedRateControl; 21 | import org.jcodec.codecs.h264.io.model.PictureParameterSet; 22 | import org.jcodec.codecs.h264.io.model.SeqParameterSet; 23 | import org.jcodec.codecs.h264.io.model.SliceType; 24 | import org.jcodec.codecs.h264.mp4.AvcCBox; 25 | import org.jcodec.common.VideoEncoder; 26 | import org.jcodec.common.model.ColorSpace; 27 | import org.jcodec.common.model.Picture; 28 | import org.jcodec.common.model.Size; 29 | import org.jcodec.scale.AWTUtil; 30 | 31 | import java.awt.image.BufferedImage; 32 | import java.io.IOException; 33 | import java.nio.ByteBuffer; 34 | 35 | import static java.util.Arrays.asList; 36 | 37 | /** 38 | * H264 Frame Encoder class which uses JCodec encoder to encode frames. 39 | */ 40 | @Slf4j 41 | public class H264FrameEncoder { 42 | 43 | private Picture toEncode; 44 | private H264Encoder encoder; 45 | private SeqParameterSet sps; 46 | private PictureParameterSet pps; 47 | private ByteBuffer out; 48 | private byte[] cpd; 49 | private int frameNumber; 50 | 51 | public H264FrameEncoder(final int width, final int height, final int bitRate) { 52 | this.encoder = new H264Encoder(new H264FixedRateControl(bitRate)); 53 | this.out = ByteBuffer.allocate(width * height * 6); 54 | this.frameNumber = 0; 55 | 56 | final Size size = new Size(width, height); 57 | sps = this.encoder.initSPS(size); 58 | pps = this.encoder.initPPS(); 59 | 60 | final ByteBuffer spsBuffer = ByteBuffer.allocate(512); 61 | this.sps.write(spsBuffer); 62 | spsBuffer.flip(); 63 | 64 | final ByteBuffer serialSps = ByteBuffer.allocate(512); 65 | this.sps.write(serialSps); 66 | serialSps.flip(); 67 | H264Utils.escapeNALinplace(serialSps); 68 | 69 | final ByteBuffer serialPps = ByteBuffer.allocate(512); 70 | this.pps.write(serialPps); 71 | serialPps.flip(); 72 | H264Utils.escapeNALinplace(serialPps); 73 | 74 | final ByteBuffer serialAvcc = ByteBuffer.allocate(512); 75 | final AvcCBox avcC = AvcCBox.createAvcCBox(this.sps.profileIdc, 0, this.sps.levelIdc, 4, 76 | asList(serialSps), asList(serialPps)); 77 | avcC.doWrite(serialAvcc); 78 | serialAvcc.flip(); 79 | cpd = new byte[serialAvcc.remaining()]; 80 | serialAvcc.get(cpd); 81 | } 82 | 83 | public EncodedFrame encodeFrame(final BufferedImage bi) { 84 | 85 | // Perform conversion from buffered image to pic 86 | out.clear(); 87 | toEncode = AWTUtil.fromBufferedImage(bi, ColorSpace.YUV420J); 88 | 89 | // First frame is treated as I Frame (IDR Frame) 90 | final SliceType sliceType = this.frameNumber == 0 ? SliceType.I : SliceType.P; 91 | log.debug("Encoding frame no: {}, frame type : {}", frameNumber, sliceType); 92 | 93 | final boolean idr = this.frameNumber == 0; 94 | 95 | // Encode image into H.264 frame, the result is stored in 'out' buffer 96 | final ByteBuffer data = encoder.doEncodeFrame(toEncode, out, idr, this.frameNumber++, sliceType); 97 | return EncodedFrame.builder() 98 | .byteBuffer(data) 99 | .isKeyFrame(idr) 100 | .cpd(ByteBuffer.wrap(cpd)) 101 | .build(); 102 | } 103 | 104 | public void setFrameNumber(final int frameNumber) { 105 | this.frameNumber = frameNumber; 106 | } 107 | 108 | public SeqParameterSet getSps() { 109 | return sps; 110 | } 111 | 112 | public PictureParameterSet getPps() { 113 | return pps; 114 | } 115 | 116 | public byte[] getCodecPrivateData() { return cpd.clone(); } 117 | 118 | public int getKeyInterval() { 119 | return encoder.getKeyInterval(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/H264FrameRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import java.awt.image.BufferedImage; 17 | import java.util.Optional; 18 | 19 | import com.amazonaws.kinesisvideo.parser.examples.KinesisVideoFrameViewer; 20 | import com.amazonaws.kinesisvideo.parser.mkv.Frame; 21 | import com.amazonaws.kinesisvideo.parser.mkv.FrameProcessException; 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | import static com.amazonaws.kinesisvideo.parser.utilities.BufferedImageUtil.addTextToImage; 25 | 26 | 27 | @Slf4j 28 | public class H264FrameRenderer extends H264FrameDecoder { 29 | private static final int PIXEL_TO_LEFT = 10; 30 | private static final int PIXEL_TO_TOP_LINE_1 = 20; 31 | private static final int PIXEL_TO_TOP_LINE_2 = 40; 32 | 33 | private final KinesisVideoFrameViewer kinesisVideoFrameViewer; 34 | 35 | protected H264FrameRenderer(final KinesisVideoFrameViewer kinesisVideoFrameViewer) { 36 | super(); 37 | this.kinesisVideoFrameViewer = kinesisVideoFrameViewer; 38 | this.kinesisVideoFrameViewer.setVisible(true); 39 | } 40 | 41 | public static H264FrameRenderer create(KinesisVideoFrameViewer kinesisVideoFrameViewer) { 42 | return new H264FrameRenderer(kinesisVideoFrameViewer); 43 | } 44 | 45 | @Override 46 | public void process(Frame frame, MkvTrackMetadata trackMetadata, Optional fragmentMetadata, 47 | Optional tagProcessor) throws FrameProcessException { 48 | final BufferedImage bufferedImage = decodeH264Frame(frame, trackMetadata); 49 | if (tagProcessor.isPresent()) { 50 | final FragmentMetadataVisitor.BasicMkvTagProcessor processor = 51 | (FragmentMetadataVisitor.BasicMkvTagProcessor) tagProcessor.get(); 52 | 53 | if (fragmentMetadata.isPresent()) { 54 | addTextToImage(bufferedImage, 55 | String.format("Fragment Number: %s", fragmentMetadata.get().getFragmentNumberString()), 56 | PIXEL_TO_LEFT, PIXEL_TO_TOP_LINE_1); 57 | } 58 | 59 | if (processor.getTags().size() > 0) { 60 | addTextToImage(bufferedImage, "Fragment Metadata: " + processor.getTags().toString(), 61 | PIXEL_TO_LEFT, PIXEL_TO_TOP_LINE_2); 62 | } else { 63 | addTextToImage(bufferedImage, "Fragment Metadata: No Metadata Available", 64 | PIXEL_TO_LEFT, PIXEL_TO_TOP_LINE_2); 65 | } 66 | } 67 | kinesisVideoFrameViewer.update(bufferedImage); 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/MkvTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import lombok.AccessLevel; 17 | import lombok.AllArgsConstructor; 18 | import lombok.Builder; 19 | import lombok.Getter; 20 | import lombok.ToString; 21 | 22 | /** 23 | * Class that captures MKV tag key/value string pairs 24 | */ 25 | @AllArgsConstructor(access = AccessLevel.PUBLIC) 26 | @Builder 27 | @Getter 28 | @ToString 29 | public class MkvTag { 30 | @Builder.Default 31 | private String tagName = ""; 32 | @Builder.Default 33 | private String tagValue = ""; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/MkvTrackMetadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElement; 17 | import lombok.AccessLevel; 18 | import lombok.AllArgsConstructor; 19 | import lombok.Builder; 20 | import lombok.Getter; 21 | import lombok.ToString; 22 | 23 | import java.math.BigInteger; 24 | import java.nio.ByteBuffer; 25 | import java.util.List; 26 | import java.util.Optional; 27 | 28 | /** 29 | * Class that captures the meta-data for a particular track in the mkv response. 30 | */ 31 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 32 | @Builder 33 | @Getter 34 | @ToString(exclude = {"codecPrivateData", "allElementsInTrack"}) 35 | public class MkvTrackMetadata { 36 | private BigInteger trackNumber; 37 | @Builder.Default 38 | private Optional trackUID = Optional.empty(); 39 | @Builder.Default 40 | private String trackName = ""; 41 | 42 | @Builder.Default 43 | private String codecId = ""; 44 | @Builder.Default 45 | private String codecName = ""; 46 | private ByteBuffer codecPrivateData; 47 | 48 | // Video track specific 49 | @Builder.Default 50 | private Optional pixelWidth = Optional.empty(); 51 | @Builder.Default 52 | private Optional pixelHeight = Optional.empty(); 53 | 54 | // Audio track specific 55 | @Builder.Default 56 | private Optional samplingFrequency = Optional.empty(); 57 | @Builder.Default 58 | private Optional channels = Optional.empty(); 59 | @Builder.Default 60 | private Optional bitDepth = Optional.empty(); 61 | 62 | private List allElementsInTrack; 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/SimpleFrameVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 17 | import com.amazonaws.kinesisvideo.parser.mkv.Frame; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvValue; 21 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor; 22 | import lombok.extern.slf4j.Slf4j; 23 | import org.apache.commons.lang3.NotImplementedException; 24 | import org.apache.commons.lang3.Validate; 25 | 26 | import java.math.BigInteger; 27 | 28 | /** 29 | * Fragment metdata tags will not be present as there is no tag when the data (mkv/webm) is not 30 | * retrieved from Kinesis video. 31 | * As a result, user cannot get the timestamp from fragment metadata tags. 32 | * This class is used to provide a FrameVisitor to process frame as well as time elements for timestamp. 33 | **/ 34 | 35 | @Slf4j 36 | public class SimpleFrameVisitor extends CompositeMkvElementVisitor { 37 | private final FrameVisitorInternal frameVisitorInternal; 38 | private final FrameProcessor frameProcessor; 39 | 40 | private SimpleFrameVisitor(FrameProcessor frameProcessor) { 41 | this.frameProcessor = frameProcessor; 42 | frameVisitorInternal = new FrameVisitorInternal(); 43 | childVisitors.add(frameVisitorInternal); 44 | 45 | } 46 | public static SimpleFrameVisitor create(FrameProcessor frameProcessor) { 47 | return new SimpleFrameVisitor(frameProcessor); 48 | } 49 | public interface FrameProcessor { 50 | default void process(Frame frame, long clusterTimeCode, long timeCodeScale) { 51 | throw new NotImplementedException("Default FrameVisitor with No Fragement MetaData"); 52 | } 53 | } 54 | 55 | private class FrameVisitorInternal extends MkvElementVisitor { 56 | private long clusterTimeCode = -1; 57 | private long timeCodeScale = -1; 58 | @Override 59 | public void visit(com.amazonaws.kinesisvideo.parser.mkv.MkvStartMasterElement startMasterElement) 60 | throws com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException { 61 | } 62 | 63 | @Override 64 | public void visit(com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement endMasterElement) 65 | throws com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException { 66 | } 67 | 68 | @Override 69 | public void visit(com.amazonaws.kinesisvideo.parser.mkv.MkvDataElement dataElement) 70 | throws com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException { 71 | 72 | if (MkvTypeInfos.TIMECODE.equals(dataElement.getElementMetaData().getTypeInfo())) { 73 | clusterTimeCode = ((BigInteger) dataElement.getValueCopy().getVal()).longValue(); 74 | } 75 | 76 | if (MkvTypeInfos.TIMECODESCALE.equals(dataElement.getElementMetaData().getTypeInfo())) { 77 | timeCodeScale = ((BigInteger) dataElement.getValueCopy().getVal()).longValue(); 78 | } 79 | 80 | if (MkvTypeInfos.SIMPLEBLOCK.equals(dataElement.getElementMetaData().getTypeInfo())) { 81 | if (clusterTimeCode == -1 || timeCodeScale == -1) { 82 | throw new MkvElementVisitException("No timeCodeScale or timeCode found", new RuntimeException()); 83 | } 84 | final MkvValue frame = dataElement.getValueCopy(); 85 | Validate.notNull(frame); 86 | frameProcessor.process(frame.getVal(), clusterTimeCode, timeCodeScale); 87 | } 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/FragmentMetadataCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadata; 17 | 18 | /** 19 | * A callback that receives the fragment metadata of a fragment. 20 | */ 21 | @FunctionalInterface 22 | public interface FragmentMetadataCallback { 23 | void call(FragmentMetadata consumedFragment); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/FragmentProgressTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvDataElement; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvEndMasterElement; 21 | import com.amazonaws.kinesisvideo.parser.mkv.MkvStartMasterElement; 22 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor; 23 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CountVisitor; 24 | import com.amazonaws.kinesisvideo.parser.utilities.FragmentMetadataVisitor; 25 | import lombok.RequiredArgsConstructor; 26 | 27 | /** 28 | * This class is used to track the progress in processing the output of a GetMedia call. 29 | * 30 | */ 31 | public class FragmentProgressTracker extends CompositeMkvElementVisitor { 32 | private final CountVisitor countVisitor; 33 | 34 | 35 | private FragmentProgressTracker(MkvElementVisitor processingVisitor, 36 | FragmentMetadataVisitor metadataVisitor, 37 | CountVisitor countVisitor, 38 | EndOfSegmentVisitor endOfSegmentVisitor) { 39 | super(metadataVisitor, processingVisitor, countVisitor, endOfSegmentVisitor); 40 | this.countVisitor = countVisitor; 41 | } 42 | 43 | public static FragmentProgressTracker create(MkvElementVisitor processingVisitor, 44 | FragmentMetadataCallback callback) { 45 | FragmentMetadataVisitor metadataVisitor = FragmentMetadataVisitor.create(); 46 | return new FragmentProgressTracker(processingVisitor, 47 | metadataVisitor, 48 | CountVisitor.create(MkvTypeInfos.CLUSTER, 49 | MkvTypeInfos.SEGMENT, 50 | MkvTypeInfos.SIMPLEBLOCK, 51 | MkvTypeInfos.TAG), 52 | new EndOfSegmentVisitor(metadataVisitor, callback)); 53 | } 54 | 55 | public int getClustersCount() { 56 | return countVisitor.getCount(MkvTypeInfos.CLUSTER); 57 | } 58 | 59 | public int getSegmentsCount() { 60 | return countVisitor.getCount(MkvTypeInfos.SEGMENT); 61 | } 62 | 63 | public int getSimpleBlocksCount() { 64 | return countVisitor.getCount(MkvTypeInfos.SIMPLEBLOCK); 65 | } 66 | 67 | @RequiredArgsConstructor 68 | private static class EndOfSegmentVisitor extends MkvElementVisitor { 69 | private final FragmentMetadataVisitor metadataVisitor; 70 | private final FragmentMetadataCallback endOfFragmentCallback; 71 | 72 | @Override 73 | public void visit(MkvStartMasterElement startMasterElement) throws MkvElementVisitException { 74 | 75 | } 76 | 77 | @Override 78 | public void visit(MkvEndMasterElement endMasterElement) throws MkvElementVisitException { 79 | if (MkvTypeInfos.SEGMENT.equals(endMasterElement.getElementMetaData().getTypeInfo())) { 80 | metadataVisitor.getCurrentFragmentMetadata().ifPresent(endOfFragmentCallback::call); 81 | } 82 | } 83 | 84 | @Override 85 | public void visit(MkvDataElement dataElement) throws MkvElementVisitException { 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/GetMediaResponseStreamConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitor; 19 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | 24 | /** 25 | * This base class is used to consume the output of a GetMedia* call to Kinesis Video in a streaming fashion. 26 | * The first parameter for process method is the payload inputStream in a GetMediaResult returned by a call to GetMedia. 27 | * Implementations of the process method of this interface should block until all the data in the inputStream has been 28 | * processed or the process method decides to stop for some other reason. The FragmentMetadataCallback is invoked at 29 | * the end of every processed fragment. 30 | */ 31 | public abstract class GetMediaResponseStreamConsumer implements AutoCloseable { 32 | 33 | public abstract void process(InputStream inputStream, FragmentMetadataCallback callback) 34 | throws MkvElementVisitException, IOException; 35 | 36 | protected void processWithFragmentEndCallbacks(InputStream inputStream, 37 | FragmentMetadataCallback endOfFragmentCallback, 38 | MkvElementVisitor mkvElementVisitor) throws MkvElementVisitException { 39 | StreamingMkvReader.createDefault(new InputStreamParserByteSource(inputStream)) 40 | .apply(FragmentProgressTracker.create(mkvElementVisitor, endOfFragmentCallback)); 41 | } 42 | 43 | @Override 44 | public void close() { 45 | //No op close. Derived classes should implement this method to meaningfully handle cleanup of the resources. 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/GetMediaResponseStreamConsumerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import java.io.IOException; 17 | 18 | /** 19 | * A base class used to create GetMediaResponseStreamConsumers. 20 | */ 21 | public abstract class GetMediaResponseStreamConsumerFactory { 22 | public abstract GetMediaResponseStreamConsumer createConsumer() throws IOException; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/MergedOutputPiper.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 17 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 18 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 19 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor; 20 | import com.amazonaws.kinesisvideo.parser.utilities.OutputSegmentMerger; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.io.OutputStream; 26 | 27 | /** 28 | * This class merges consecutive mkv streams and pipes the merged stream to the stdin of a child process. 29 | * It is meant to be used to pipe the output of a GetMedia* call to a processing application that can not deal 30 | * with having multiple consecutive mkv streams. Gstreamer is one such application that requires a merged stream. 31 | * A merged stream is where the consecutive mkv streams are merged as long as they share the same track 32 | * and EBML information and the cluster level timecodes in those streams keep increasing. 33 | * If a non-matching mkv stream is detected, the piper stops. 34 | */ 35 | 36 | @RequiredArgsConstructor 37 | public class MergedOutputPiper extends GetMediaResponseStreamConsumer { 38 | /** 39 | * The process builder to create the child proccess to which the merged output 40 | */ 41 | private final ProcessBuilder childProcessBuilder; 42 | 43 | 44 | private OutputSegmentMerger merger; 45 | private Process targetProcess; 46 | 47 | @Override 48 | public void process(final InputStream inputStream, FragmentMetadataCallback endOfFragmentCallback) 49 | throws MkvElementVisitException, IOException { 50 | targetProcess = childProcessBuilder.start(); 51 | try (OutputStream os = targetProcess.getOutputStream()) { 52 | merger = OutputSegmentMerger.createToStopAtFirstNonMatchingSegment(os); 53 | processWithFragmentEndCallbacks(inputStream, endOfFragmentCallback, merger); 54 | } 55 | } 56 | 57 | /** 58 | * Get the number of segments that were merged by the piper. 59 | * If the merger is done because the last segment it read cannot be merged, then the number of merged segments 60 | * is the number of segments read minus the last segment. 61 | * If the merger is not done then the number of merged segments is the number of read segments. 62 | * @return 63 | */ 64 | public int getMergedSegments() { 65 | if (merger.isDone()) { 66 | return merger.getSegmentsCount() - 1; 67 | } else { 68 | return merger.getSegmentsCount(); 69 | } 70 | } 71 | 72 | @Override 73 | public void close() { 74 | targetProcess.destroyForcibly(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/kinesisvideo/parser/utilities/consumer/MergedOutputPiperFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities.consumer; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.nio.file.Files; 19 | import java.nio.file.Paths; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Optional; 23 | 24 | /** 25 | * This factory class creates MergedOutputPiper consumers based on a particular target ProcessBuilder. 26 | */ 27 | public class MergedOutputPiperFactory extends GetMediaResponseStreamConsumerFactory { 28 | private final Optional directoryOptional; 29 | private final List commandList; 30 | private final boolean redirectOutputAndError; 31 | 32 | public MergedOutputPiperFactory(String... commands) { 33 | this(Optional.empty(), commands); 34 | } 35 | 36 | public MergedOutputPiperFactory(Optional directoryOptional, String... commands) { 37 | this(directoryOptional, false, commands); 38 | } 39 | 40 | private MergedOutputPiperFactory(Optional directoryOptional, 41 | boolean redirectOutputAndError, 42 | String... commands) { 43 | this.directoryOptional = directoryOptional; 44 | this.commandList = new ArrayList(); 45 | for (String command : commands) { 46 | commandList.add(command); 47 | } 48 | this.redirectOutputAndError = redirectOutputAndError; 49 | } 50 | 51 | public MergedOutputPiperFactory(Optional directoryOptional, 52 | boolean redirectOutputAndError, 53 | List commandList) { 54 | this.directoryOptional = directoryOptional; 55 | this.commandList = commandList; 56 | this.redirectOutputAndError = redirectOutputAndError; 57 | } 58 | 59 | @Override 60 | public GetMediaResponseStreamConsumer createConsumer() throws IOException{ 61 | ProcessBuilder builder = new ProcessBuilder().command(commandList); 62 | directoryOptional.ifPresent(d -> builder.directory(new File(d))); 63 | if (redirectOutputAndError) { 64 | builder.redirectOutput(Files.createFile(Paths.get(redirectedFileName("stdout"))).toFile()); 65 | builder.redirectError(Files.createFile(Paths.get(redirectedFileName("stderr"))).toFile()); 66 | } 67 | return new MergedOutputPiper(builder); 68 | 69 | } 70 | 71 | private String redirectedFileName(String suffix) { 72 | return "MergedOutputPiper-"+System.currentTimeMillis()+"-"+suffix; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/resources/libKinesisVideoProducerJNI.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/main/resources/libKinesisVideoProducerJNI.so -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | status = warn 2 | log = . 3 | log4j.rootLogger = INFO, LAMBDA 4 | 5 | #Define the LAMBDA appender 6 | log4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j2.LambdaAppender 7 | log4j.appender.LAMBDA.immediateFlush=true 8 | log4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%m%n -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/TestResourceUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser; 15 | 16 | import org.apache.commons.lang3.Validate; 17 | 18 | import java.io.ByteArrayOutputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.net.URL; 22 | import java.net.URLClassLoader; 23 | import java.nio.ByteBuffer; 24 | import java.nio.file.Files; 25 | import java.nio.file.Paths; 26 | 27 | import static java.nio.file.Files.newInputStream; 28 | 29 | /** 30 | * Class used by the test classes to get acess to input test files 31 | */ 32 | public class TestResourceUtil { 33 | public static InputStream getTestInputStream(String name) throws IOException { 34 | //First check if we are running in maven. 35 | InputStream inputStream = ClassLoader.getSystemResourceAsStream(name); 36 | if (inputStream == null) { 37 | inputStream = newInputStream(Paths.get("testdata", name)); 38 | } 39 | Validate.isTrue(inputStream != null, "Could not read input file " + name); 40 | return inputStream; 41 | 42 | } 43 | 44 | public static byte[] getTestInputByteArray(String name) throws IOException { 45 | //First check if we are running in maven. 46 | InputStream inputStream = ClassLoader.getSystemResourceAsStream(name); 47 | if (inputStream == null) { 48 | inputStream = Files.newInputStream(Paths.get("testdata", name)); 49 | } 50 | Validate.isTrue(inputStream != null, "Could not read input file " + name); 51 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 52 | byte []buf = new byte [8192]; 53 | 54 | int readBytes; 55 | do { 56 | readBytes = inputStream.read(buf); 57 | if (readBytes > 0) { 58 | outputStream.write(buf, 0, readBytes); 59 | } 60 | }while (readBytes >= 0); 61 | 62 | return outputStream.toByteArray(); 63 | } 64 | 65 | /** 66 | * Utility debug method to print the class path. 67 | * Useful for verifying test setup in different build systems. 68 | */ 69 | public static void printClassPath() { 70 | ClassLoader cl = ClassLoader.getSystemClassLoader(); 71 | URL[] urls = ((URLClassLoader)cl).getURLs(); 72 | 73 | for(URL url: urls){ 74 | System.out.println(url.getFile()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/ebml/EBMLUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import org.junit.Assert; 17 | import org.junit.Test; 18 | 19 | import java.math.BigInteger; 20 | import java.nio.ByteBuffer; 21 | import java.nio.ByteOrder; 22 | 23 | /** 24 | * Tests for the EBMLUtils class. 25 | */ 26 | public class EBMLUtilsTest { 27 | @Test 28 | public void readSignedInteger8bytes() { 29 | byte[] data = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 30 | (byte) 0xFE }; 31 | runTestForNegativeTwo(data); 32 | } 33 | 34 | private void runTestForNegativeTwo(byte[] data) { 35 | ByteBuffer buffer = ByteBuffer.wrap(data); 36 | 37 | long value = EBMLUtils.readDataSignedInteger(buffer, data.length); 38 | Assert.assertEquals(-2, value); 39 | } 40 | 41 | @Test 42 | public void readSignedInteger7bytes() { 43 | byte[] data = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE }; 44 | runTestForNegativeTwo(data); 45 | } 46 | 47 | @Test 48 | public void readSignedInteger2bytes() { 49 | byte[] data = { (byte) 0xFF, (byte) 0xFE }; 50 | runTestForNegativeTwo(data); 51 | } 52 | 53 | @Test 54 | public void readSignedInteger1byte() { 55 | byte[] data = { (byte) 0xFE }; 56 | runTestForNegativeTwo(data); 57 | } 58 | 59 | @Test 60 | public void readUnsignedIntegerSevenBytesOrLessTwoBytes() { 61 | byte[] data = { (byte) 0xFF, (byte) 0xFE }; 62 | ByteBuffer buffer = ByteBuffer.wrap(data); 63 | 64 | long value = EBMLUtils.readUnsignedIntegerSevenBytesOrLess(buffer, data.length); 65 | Assert.assertEquals(0xFFFE, value); 66 | } 67 | 68 | @Test 69 | public void readPositiveSignedInteger1byte() { 70 | byte[] data = { (byte) 0x7E }; 71 | ByteBuffer buffer = ByteBuffer.wrap(data); 72 | 73 | long value = EBMLUtils.readDataSignedInteger(buffer, data.length); 74 | Assert.assertEquals(0x7E, value); 75 | } 76 | 77 | @Test 78 | public void readUnsignedInteger() { 79 | ByteBuffer b = ByteBuffer.allocate(8); 80 | b.putLong(-309349387097750278L); 81 | b.order(ByteOrder.BIG_ENDIAN); 82 | 83 | b.rewind(); 84 | BigInteger unsigned = EBMLUtils.readDataUnsignedInteger(b, 8); 85 | Assert.assertTrue(unsigned.signum() > 0); 86 | b.rewind(); 87 | long value = EBMLUtils.readDataSignedInteger(b, 8); 88 | Assert.assertEquals(value, -309349387097750278L); 89 | 90 | System.out.println(unsigned.toString(16)); 91 | } 92 | //:-309349387097750278 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/ebml/TestEBMLTypeInfoProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.ebml; 15 | 16 | import org.apache.commons.lang3.Validate; 17 | 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Modifier; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.Optional; 23 | 24 | 25 | /** 26 | * A EBMLTypeInfoProvider for unit tests that provides only a very samll subset of the Mkv Elements. 27 | */ 28 | public class TestEBMLTypeInfoProvider implements EBMLTypeInfoProvider { 29 | public static final EBMLTypeInfo EBML = new EBMLTypeInfo.EBMLTypeInfoBuilder().id(0x1A45DFA3).name("EBML").level(0).type( 30 | EBMLTypeInfo.TYPE.MASTER).build(); 31 | public static final EBMLTypeInfo EBMLVersion = new EBMLTypeInfo.EBMLTypeInfoBuilder().id(0x4286).name("EBMLVersion").level(1).type( 32 | EBMLTypeInfo.TYPE.UINTEGER).build(); 33 | public static final EBMLTypeInfo EBMLReadVersion = new EBMLTypeInfo.EBMLTypeInfoBuilder().id(0x42F7).name("EBMLReadVersion").level(1).type( 34 | EBMLTypeInfo.TYPE.UINTEGER).build(); 35 | public static final EBMLTypeInfo CRC = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("CRC-32").id(0xBF).level(-1).type( 36 | EBMLTypeInfo.TYPE.BINARY).build(); 37 | 38 | public static final EBMLTypeInfo SEGMENT = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("Segment").level(0).id(0x18538067).type( 39 | EBMLTypeInfo.TYPE.MASTER).build(); 40 | public static final EBMLTypeInfo SEEKHEAD = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("SeekHead").level(1).id(0x114D9B74).type( 41 | EBMLTypeInfo.TYPE.MASTER).build(); 42 | public static final EBMLTypeInfo SEEK = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("Seek").level(2).id(0x4DBB).type( 43 | EBMLTypeInfo.TYPE.MASTER).build(); 44 | public static final EBMLTypeInfo SEEKID = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("SeekID").level(3).id(0x53AB).type( 45 | EBMLTypeInfo.TYPE.BINARY).build(); 46 | public static final EBMLTypeInfo SEEKPOSITION = new EBMLTypeInfo.EBMLTypeInfoBuilder().name("SeekPosition").level(3).id(0x53AC).type( 47 | EBMLTypeInfo.TYPE.UINTEGER).build(); 48 | 49 | 50 | 51 | private Map typeInfoMap = new HashMap(); 52 | public TestEBMLTypeInfoProvider() throws IllegalAccessException { 53 | for (Field field : TestEBMLTypeInfoProvider.class.getDeclaredFields()) { 54 | if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(EBMLTypeInfo.class)) { 55 | EBMLTypeInfo type = (EBMLTypeInfo )field.get(null); 56 | Validate.isTrue(!typeInfoMap.containsKey(type.getId())); 57 | typeInfoMap.put(type.getId(), type); 58 | } 59 | } 60 | 61 | } 62 | 63 | @Override 64 | public Optional getType(int id) { 65 | return Optional.ofNullable(typeInfoMap.get(id)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoExampleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import com.amazonaws.auth.profile.ProfileCredentialsProvider; 17 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 18 | import com.amazonaws.regions.Regions; 19 | import org.junit.Assert; 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | import java.io.IOException; 24 | 25 | /** 26 | * Test to execute Kinesis Video Example. 27 | * The test in this class are currently ignored for unit tests since they require access to Kinesis Video through 28 | * valid credentials. 29 | * These can be re-enabled as integration tests. 30 | * They can be executed on any machine with valid aws credentials for access to Kinesis Video. 31 | */ 32 | public class KinesisVideoExampleTest { 33 | @Ignore 34 | @Test 35 | public void testExample() throws InterruptedException, IOException { 36 | KinesisVideoExample example = KinesisVideoExample.builder().region(Regions.US_WEST_2) 37 | .streamName("myTestStream") 38 | .credentialsProvider(new ProfileCredentialsProvider()) 39 | .inputVideoStream(TestResourceUtil.getTestInputStream("vogels_480.mkv")) 40 | .build(); 41 | 42 | example.execute(); 43 | Assert.assertEquals(9, example.getFragmentsPersisted()); 44 | Assert.assertEquals(9, example.getFragmentsRead()); 45 | } 46 | 47 | @Ignore 48 | @Test 49 | public void testConsumerExample() throws InterruptedException, IOException { 50 | KinesisVideoExample example = KinesisVideoExample.builder().region(Regions.US_WEST_2) 51 | .streamName("myTestStream") 52 | .credentialsProvider(new ProfileCredentialsProvider()) 53 | // Use existing stream in KVS (with Producer sending) 54 | .noSampleInputRequired(true) 55 | .build(); 56 | 57 | example.execute(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoGStreamerPiperExampleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import com.amazonaws.auth.profile.ProfileCredentialsProvider; 17 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 18 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 19 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 21 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 22 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CountVisitor; 23 | import com.amazonaws.regions.Regions; 24 | import lombok.Getter; 25 | import org.jcodec.common.Assert; 26 | import org.junit.Ignore; 27 | import org.junit.Test; 28 | 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.nio.file.Files; 32 | import java.nio.file.Path; 33 | import java.nio.file.Paths; 34 | 35 | /** 36 | * Test to execute Kinesis Video GStreamer Piper Example. 37 | * It passes in a pipeline that demuxes and remuxes the input mkv stream and writes to a file sink. 38 | * This can be used to demonstrate that the stream passed into the gstreamer pipeline is acceptable to it. 39 | */ 40 | public class KinesisVideoGStreamerPiperExampleTest { 41 | 42 | @Ignore 43 | @Test 44 | public void testExample() throws InterruptedException, IOException, MkvElementVisitException { 45 | final Path outputFilePath = Paths.get("output_from_gstreamer-"+System.currentTimeMillis()+".mkv"); 46 | String gStreamerPipelineArgument = 47 | "matroskademux ! matroskamux! filesink location=" + outputFilePath.toAbsolutePath().toString(); 48 | 49 | //Might need to update DEFAULT_PATH_TO_GSTREAMER variable in KinesisVideoGStreamerPiperExample class 50 | KinesisVideoGStreamerPiperExample example = KinesisVideoGStreamerPiperExample.builder().region(Regions.US_WEST_2) 51 | .streamName("myTestStream2") 52 | .credentialsProvider(new ProfileCredentialsProvider()) 53 | .inputVideoStream(TestResourceUtil.getTestInputStream("clusters.mkv")) 54 | .gStreamerPipelineArgument(gStreamerPipelineArgument) 55 | .build(); 56 | 57 | example.execute(); 58 | 59 | //Verify that the generated output file has the expected number of segments, clusters and simple blocks. 60 | CountVisitor countVisitor = 61 | CountVisitor.create(MkvTypeInfos.SEGMENT, MkvTypeInfos.CLUSTER, MkvTypeInfos.SIMPLEBLOCK); 62 | StreamingMkvReader.createDefault(new InputStreamParserByteSource(Files.newInputStream(outputFilePath))) 63 | .apply(countVisitor); 64 | 65 | Assert.assertEquals(1,countVisitor.getCount(MkvTypeInfos.SEGMENT)); 66 | Assert.assertEquals(8,countVisitor.getCount(MkvTypeInfos.CLUSTER)); 67 | Assert.assertEquals(444,countVisitor.getCount(MkvTypeInfos.SIMPLEBLOCK)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoRekognitionIntegrationExampleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import java.io.IOException; 17 | 18 | import com.amazonaws.auth.profile.ProfileCredentialsProvider; 19 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 20 | import com.amazonaws.kinesisvideo.parser.rekognition.pojo.RekognitionInput; 21 | import com.amazonaws.regions.Regions; 22 | import org.junit.Ignore; 23 | import org.junit.Test; 24 | 25 | /** 26 | * This examples demonstrates how to integrate KVS with Rekognition and draw bounding boxes for each frame. 27 | */ 28 | public class KinesisVideoRekognitionIntegrationExampleTest { 29 | /* long running test */ 30 | @Ignore 31 | @Test 32 | public void testExample() throws InterruptedException, IOException { 33 | // NOTE: Rekogntion Input needs ARN for both Kinesis Video Streams and Kinesis Data Streams. 34 | // For more info please refer https://docs.aws.amazon.com/rekognition/latest/dg/streaming-video.html 35 | RekognitionInput rekognitionInput = RekognitionInput.builder() 36 | .kinesisVideoStreamArn("") 37 | .kinesisDataStreamArn("") 38 | .streamingProcessorName("") 39 | // Refer how to add face collection : 40 | // https://docs.aws.amazon.com/rekognition/latest/dg/add-faces-to-collection-procedure.html 41 | .faceCollectionId("") 42 | .iamRoleArn("") 43 | .matchThreshold(0.08f) 44 | .build(); 45 | 46 | KinesisVideoRekognitionIntegrationExample example = KinesisVideoRekognitionIntegrationExample.builder() 47 | .region(Regions.US_WEST_2) 48 | .kvsStreamName("") 49 | .kdsStreamName("") 50 | .rekognitionInput(rekognitionInput) 51 | .credentialsProvider(new ProfileCredentialsProvider()) 52 | // NOTE: If the input stream is not passed then the example assumes that the video fragments are 53 | // ingested using other mechanisms like GStreamer sample app or AmazonKinesisVideoDemoApp 54 | .inputStream(TestResourceUtil.getTestInputStream("bezos_vogels.mkv")) 55 | .build(); 56 | 57 | // The test file resolution is 1280p. 58 | example.setWidth(1280); 59 | example.setHeight(720); 60 | 61 | // This test might render frames with high latency until the rekognition results are returned. Change below 62 | // timeout to smaller value if the frames need to be rendered with low latency when rekognition results 63 | // are not present. 64 | example.setRekognitionMaxTimeoutInMillis(100); 65 | example.execute(30L); 66 | } 67 | } -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/examples/KinesisVideoRendererExampleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.examples; 15 | 16 | import com.amazonaws.auth.profile.ProfileCredentialsProvider; 17 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 18 | import com.amazonaws.regions.Regions; 19 | import org.junit.Ignore; 20 | import org.junit.Test; 21 | 22 | import java.io.IOException; 23 | 24 | public class KinesisVideoRendererExampleTest { 25 | /* long running test */ 26 | @Ignore 27 | @Test 28 | public void testExample() throws InterruptedException, IOException { 29 | KinesisVideoRendererExample example = KinesisVideoRendererExample.builder().region(Regions.US_WEST_2) 30 | .streamName("render-example-stream") 31 | .credentialsProvider(new ProfileCredentialsProvider()) 32 | .inputVideoStream(TestResourceUtil.getTestInputStream("vogels_480.mkv")) 33 | .renderFragmentMetadata(false) 34 | .build(); 35 | 36 | example.execute(); 37 | } 38 | 39 | @Ignore 40 | @Test 41 | public void testDifferentResolution() throws InterruptedException, IOException { 42 | KinesisVideoRendererExample example = KinesisVideoRendererExample.builder().region(Regions.US_WEST_2) 43 | .streamName("render-example-stream") 44 | .credentialsProvider(new ProfileCredentialsProvider()) 45 | .inputVideoStream(TestResourceUtil.getTestInputStream("vogels_330.mkv")) 46 | .renderFragmentMetadata(false) 47 | .build(); 48 | 49 | example.execute(); 50 | } 51 | 52 | @Ignore 53 | @Test 54 | public void testConsumerExample() throws InterruptedException, IOException { 55 | KinesisVideoRendererExample example = KinesisVideoRendererExample.builder().region(Regions.US_WEST_2) 56 | .streamName("render-example-stream") 57 | .credentialsProvider(new ProfileCredentialsProvider()) 58 | // Display the tags in the frame viewer window 59 | .renderFragmentMetadata(true) 60 | // Use existing stream in KVS (with Producer sending) 61 | .noSampleInputRequired(true) 62 | .build(); 63 | 64 | example.execute(); 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/mkv/EBMLParserForMkvTypeInfosTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.EBMLParser; 18 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 19 | import com.amazonaws.kinesisvideo.parser.ebml.TestEBMLParserCallback; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | 26 | /** 27 | * Test to see that the elements in a typical input mkv file are recogized by the {@link MkvTypeInfoProvider}. 28 | */ 29 | public class EBMLParserForMkvTypeInfosTest { 30 | private EBMLParser parser; 31 | private TestEBMLParserCallback parserCallback; 32 | 33 | 34 | @Before 35 | public void setup() throws IllegalAccessException { 36 | parserCallback = new TestEBMLParserCallback(); 37 | MkvTypeInfoProvider typeInfoProvider = new MkvTypeInfoProvider(); 38 | typeInfoProvider.load(); 39 | 40 | parser = new EBMLParser(typeInfoProvider, parserCallback); 41 | } 42 | 43 | @Test 44 | public void testClustersMkv() throws IOException { 45 | final String fileName = "clusters.mkv"; 46 | final InputStream in = TestResourceUtil.getTestInputStream(fileName); 47 | 48 | InputStreamParserByteSource parserByteSource = new InputStreamParserByteSource(in); 49 | 50 | while(!parserByteSource.eof()) { 51 | parser.parse(parserByteSource); 52 | } 53 | parser.closeParser(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/mkv/ElementSizeAndOffsetVisitorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 18 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.ElementSizeAndOffsetVisitor; 19 | import org.junit.Test; 20 | 21 | import java.io.BufferedWriter; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.nio.charset.StandardCharsets; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | import java.nio.file.StandardOpenOption; 28 | import java.util.ArrayList; 29 | import java.util.Optional; 30 | 31 | /** 32 | * Test for ElementSizeAndOffsetVisitor. 33 | */ 34 | public class ElementSizeAndOffsetVisitorTest { 35 | @Test 36 | public void basicTest() throws IOException, MkvElementVisitException { 37 | final String fileName = "clusters.mkv"; 38 | final InputStream in = TestResourceUtil.getTestInputStream(fileName); 39 | 40 | StreamingMkvReader offsetReader = 41 | new StreamingMkvReader(false, new ArrayList<>(), new InputStreamParserByteSource(in)); 42 | 43 | Path tmpFilePath = Files.createTempFile("basicTest:"+fileName+":","offset"); 44 | try (BufferedWriter writer = Files.newBufferedWriter(tmpFilePath, 45 | StandardCharsets.US_ASCII, 46 | StandardOpenOption.WRITE, 47 | StandardOpenOption.CREATE)) { 48 | ElementSizeAndOffsetVisitor offsetVisitor = new ElementSizeAndOffsetVisitor(writer); 49 | 50 | while(offsetReader.mightHaveNext()) { 51 | Optional mkvElement = offsetReader.nextIfAvailable(); 52 | if (mkvElement.isPresent()) { 53 | mkvElement.get().accept(offsetVisitor); 54 | } 55 | } 56 | } finally { 57 | Files.delete(tmpFilePath); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/mkv/MkvValueTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv; 15 | 16 | import org.junit.Assert; 17 | import org.junit.Test; 18 | 19 | import java.nio.ByteBuffer; 20 | 21 | /** 22 | * Tests for MkvValue equality 23 | */ 24 | public class MkvValueTest { 25 | 26 | @Test 27 | public void integerTest() { 28 | MkvValue val1 = new MkvValue<>(2, 1); 29 | MkvValue val2 = new MkvValue<>(2, 1); 30 | 31 | Assert.assertTrue(val1.equals(val2)); 32 | 33 | MkvValue val3 = new MkvValue<>(3, 1); 34 | Assert.assertFalse(val1.equals(val3)); 35 | 36 | MkvValue val4 = new MkvValue<>(2, 2); 37 | Assert.assertFalse(val1.equals(val4)); 38 | } 39 | 40 | @Test 41 | public void byteBufferTest() { 42 | ByteBuffer buf1 = ByteBuffer.wrap(new byte[] {(byte) 0x32, (byte) 0x45, (byte) 0x73 }); 43 | ByteBuffer buf2 = ByteBuffer.wrap(new byte[] {(byte) 0x32, (byte) 0x45, (byte) 0x73 }); 44 | 45 | MkvValue val1 = new MkvValue<>(buf1, buf1.limit()); 46 | MkvValue val2 = new MkvValue<>(buf2, buf2.limit()); 47 | 48 | Assert.assertTrue(val1.equals(val2)); 49 | 50 | //Even if a buffer has been partially read, equality should still succeed 51 | buf2.get(); 52 | Assert.assertTrue(val1.equals(val2)); 53 | 54 | ByteBuffer buf3 = ByteBuffer.wrap(new byte[] {(byte) 0x28}); 55 | MkvValue val3 = new MkvValue(buf3, buf3.limit()); 56 | Assert.assertFalse(val1.equals(val3)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/mkv/visitors/CopyVisitorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.mkv.visitors; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 18 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 19 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 20 | import org.junit.Assert; 21 | import org.junit.Test; 22 | 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | 27 | public class CopyVisitorTest { 28 | 29 | @Test 30 | public void testOneCopy() throws IOException, MkvElementVisitException { 31 | testOneCopyForFile("clusters.mkv"); 32 | } 33 | 34 | @Test 35 | public void testOneCopyGetMediaOutput() throws IOException, MkvElementVisitException { 36 | testOneCopyForFile("output_get_media.mkv"); 37 | } 38 | 39 | @Test 40 | public void testTwoCopiesAtOnce() throws IOException, MkvElementVisitException { 41 | testTwoCopiesAtOnceForFile("clusters.mkv"); 42 | } 43 | 44 | @Test 45 | public void testTwoCopiesAtOnceGetMediaOutput() throws IOException, MkvElementVisitException { 46 | testTwoCopiesAtOnceForFile("output_get_media.mkv"); 47 | } 48 | 49 | private void testTwoCopiesAtOnceForFile(String fileName) throws IOException, MkvElementVisitException { 50 | byte [] inputBytes = TestResourceUtil.getTestInputByteArray(fileName); 51 | 52 | ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream(); 53 | ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream(); 54 | 55 | try (CopyVisitor copyVisitor1 = new CopyVisitor(outputStream1)) { 56 | try (CopyVisitor copyVisitor2 = new CopyVisitor(outputStream2)) { 57 | StreamingMkvReader.createDefault(getInputStreamParserByteSource(fileName)) 58 | .apply(new CompositeMkvElementVisitor(copyVisitor1, copyVisitor2)); 59 | } 60 | } 61 | 62 | Assert.assertArrayEquals(inputBytes, outputStream1.toByteArray()); 63 | Assert.assertArrayEquals(inputBytes, outputStream2.toByteArray()); 64 | } 65 | 66 | private void testOneCopyForFile(String fileName) throws IOException, MkvElementVisitException { 67 | byte [] inputBytes = TestResourceUtil.getTestInputByteArray(fileName); 68 | 69 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 70 | try (CopyVisitor copyVisitor = new CopyVisitor(outputStream)) { 71 | StreamingMkvReader.createDefault(getInputStreamParserByteSource(fileName)).apply(copyVisitor); 72 | } 73 | 74 | Assert.assertArrayEquals(inputBytes, outputStream.toByteArray()); 75 | } 76 | 77 | private InputStreamParserByteSource getInputStreamParserByteSource(String fileName) throws IOException { 78 | final InputStream in = TestResourceUtil.getTestInputStream(fileName); 79 | return new InputStreamParserByteSource(in); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/rekognition/processor/RekognitionStreamProcessorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.rekognition.processor; 15 | 16 | import com.amazonaws.auth.EnvironmentVariableCredentialsProvider; 17 | import com.amazonaws.auth.profile.ProfileCredentialsProvider; 18 | import com.amazonaws.kinesisvideo.parser.rekognition.pojo.RekognitionInput; 19 | import com.amazonaws.regions.Regions; 20 | import com.amazonaws.services.rekognition.model.CreateStreamProcessorResult; 21 | import com.amazonaws.services.rekognition.model.DescribeStreamProcessorResult; 22 | import com.amazonaws.services.rekognition.model.ListStreamProcessorsResult; 23 | import com.amazonaws.services.rekognition.model.StartStreamProcessorResult; 24 | import lombok.extern.slf4j.Slf4j; 25 | import org.junit.Assert; 26 | import org.junit.Before; 27 | import org.junit.Ignore; 28 | import org.junit.Test; 29 | 30 | @Slf4j 31 | @Ignore // Used for controlling rekognition stream processor used in Rekognition integration examples. 32 | public class RekognitionStreamProcessorTest { 33 | 34 | RekognitionStreamProcessor streamProcessor; 35 | 36 | @Before 37 | public void testSetup() { 38 | final RekognitionInput rekognitionInput = RekognitionInput.builder() 39 | .kinesisVideoStreamArn("") 40 | .kinesisDataStreamArn("") 41 | .streamingProcessorName("") 42 | // Refer how to add face collection : 43 | // https://docs.aws.amazon.com/rekognition/latest/dg/add-faces-to-collection-procedure.html 44 | .faceCollectionId("") 45 | .iamRoleArn("") 46 | .matchThreshold(0.08f) 47 | .build(); 48 | streamProcessor = RekognitionStreamProcessor.create(Regions.US_WEST_2, new ProfileCredentialsProvider(), rekognitionInput); 49 | } 50 | 51 | @Test 52 | public void createStreamProcessor() { 53 | final CreateStreamProcessorResult result = streamProcessor.createStreamProcessor(); 54 | Assert.assertNotNull(result.getStreamProcessorArn()); 55 | } 56 | 57 | @Test 58 | public void startStreamProcessor() { 59 | final StartStreamProcessorResult result = streamProcessor.startStreamProcessor(); 60 | log.info("Result : {}", result); 61 | } 62 | 63 | @Test 64 | public void describeStreamProcessor() { 65 | final DescribeStreamProcessorResult result = streamProcessor.describeStreamProcessor(); 66 | log.info("Status for stream processor : {}", result.getStatus()); 67 | } 68 | 69 | @Test 70 | public void listStreamProcessor() { 71 | final ListStreamProcessorsResult result = streamProcessor.listStreamProcessor(); 72 | log.info("List StreamProcessors : {}", result); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/utilities/FrameVisitorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 18 | import com.amazonaws.kinesisvideo.parser.mkv.Frame; 19 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 20 | import lombok.Getter; 21 | import lombok.NonNull; 22 | import org.junit.Assert; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | import java.math.BigInteger; 29 | import java.util.Optional; 30 | 31 | public class FrameVisitorTest { 32 | private static final int VIDEO_FRAMES_COUNT = 909; 33 | private static final int AUDIO_FRAMES_COUNT = 1425; 34 | private static final int SIMPLE_BLOCKS_COUNT_MKV = VIDEO_FRAMES_COUNT + AUDIO_FRAMES_COUNT; 35 | private static final long TIMESCALE = 1000000; 36 | private static final long LAST_FRAGMENT_TIMECODE = 28821; 37 | 38 | @Getter 39 | public static final class TestFrameProcessor implements FrameVisitor.FrameProcessor { 40 | private long framesCount = 0L; 41 | private long timescale = 0L; 42 | private long fragmentTimecode = 0L; 43 | 44 | @Override 45 | public void process(@NonNull final Frame frame, @NonNull final MkvTrackMetadata trackMetadata, 46 | final @NonNull Optional fragmentMetadata, 47 | final @NonNull Optional tagProcessor, 48 | final @NonNull Optional timescale, final @NonNull Optional fragmentTimecode) { 49 | this.timescale = timescale.get().longValue(); 50 | this.fragmentTimecode = fragmentTimecode.get().longValue(); 51 | framesCount++; 52 | } 53 | 54 | 55 | } 56 | private FrameVisitor frameVisitor; 57 | private TestFrameProcessor frameProcessor; 58 | private StreamingMkvReader streamingMkvReader; 59 | 60 | @Before 61 | public void setUp() throws Exception { 62 | frameProcessor = new TestFrameProcessor(); 63 | frameVisitor = FrameVisitor.create(frameProcessor); 64 | } 65 | 66 | @Test 67 | public void testWithMkvVideo() throws Exception { 68 | streamingMkvReader = StreamingMkvReader.createDefault(getClustersByteSource("vogels_480.mkv")); 69 | streamingMkvReader.apply(frameVisitor); 70 | Assert.assertEquals(SIMPLE_BLOCKS_COUNT_MKV, frameProcessor.getFramesCount()); 71 | Assert.assertEquals(TIMESCALE, frameProcessor.getTimescale()); 72 | Assert.assertEquals(LAST_FRAGMENT_TIMECODE, frameProcessor.getFragmentTimecode()); 73 | 74 | } 75 | 76 | @Test 77 | public void testForVideoFrames() throws Exception { 78 | frameVisitor = FrameVisitor.create(frameProcessor, Optional.empty(), Optional.of(1L)); 79 | streamingMkvReader = StreamingMkvReader.createDefault(getClustersByteSource("vogels_480.mkv")); 80 | streamingMkvReader.apply(frameVisitor); 81 | Assert.assertEquals(VIDEO_FRAMES_COUNT, frameProcessor.getFramesCount()); 82 | Assert.assertEquals(TIMESCALE, frameProcessor.getTimescale()); 83 | Assert.assertEquals(LAST_FRAGMENT_TIMECODE, frameProcessor.getFragmentTimecode()); 84 | } 85 | 86 | @Test 87 | public void testForAudioFrames() throws Exception { 88 | frameVisitor = FrameVisitor.create(frameProcessor, Optional.empty(), Optional.of(2L)); 89 | streamingMkvReader = StreamingMkvReader.createDefault(getClustersByteSource("vogels_480.mkv")); 90 | streamingMkvReader.apply(frameVisitor); 91 | Assert.assertEquals(AUDIO_FRAMES_COUNT, frameProcessor.getFramesCount()); 92 | Assert.assertEquals(TIMESCALE, frameProcessor.getTimescale()); 93 | Assert.assertEquals(LAST_FRAGMENT_TIMECODE, frameProcessor.getFragmentTimecode()); 94 | } 95 | 96 | private InputStreamParserByteSource getClustersByteSource(final String name) throws IOException { 97 | return getInputStreamParserByteSource(name); 98 | } 99 | 100 | private InputStreamParserByteSource getInputStreamParserByteSource(final String fileName) throws IOException { 101 | final InputStream in = TestResourceUtil.getTestInputStream(fileName); 102 | return new InputStreamParserByteSource(in); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/utilities/H264FrameDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 18 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 19 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 20 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 21 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor; 22 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CountVisitor; 23 | import org.junit.Assert; 24 | import org.junit.Test; 25 | 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | import java.nio.ByteBuffer; 29 | import java.util.Optional; 30 | 31 | public class H264FrameDecoderTest { 32 | 33 | @Test 34 | public void frameDecodeCountTest() throws IOException, MkvElementVisitException { 35 | final InputStream in = TestResourceUtil.getTestInputStream("kinesis_video_renderer_example_output.mkv"); 36 | final byte[] codecPrivateData = new byte[]{ 37 | 0x01, 0x64, 0x00, 0x28, (byte) 0xff, (byte) 0xe1, 0x00, 38 | 0x0e, 0x27, 0x64, 0x00, 0x28, (byte) 0xac, 0x2b, 0x40, 39 | 0x50, 0x1e, (byte) 0xd0, 0x0f, 0x12, 0x26, (byte) 0xa0, 40 | 0x01, 0x00, 0x04, 0x28, (byte) 0xee, 0x1f, 0x2c 41 | }; 42 | 43 | final H264FrameDecoder frameDecoder = new H264FrameDecoder(); 44 | final StreamingMkvReader mkvStreamReader = 45 | StreamingMkvReader.createDefault(new InputStreamParserByteSource(in)); 46 | 47 | final CountVisitor countVisitor = CountVisitor.create(MkvTypeInfos.CLUSTER, MkvTypeInfos.SEGMENT, 48 | MkvTypeInfos.SIMPLEBLOCK, MkvTypeInfos.TRACKS); 49 | 50 | mkvStreamReader.apply(new CompositeMkvElementVisitor(countVisitor, FrameVisitor.create(frameDecoder))); 51 | 52 | Assert.assertEquals(8, countVisitor.getCount(MkvTypeInfos.TRACKS)); 53 | Assert.assertEquals(8, countVisitor.getCount(MkvTypeInfos.CLUSTER)); 54 | Assert.assertEquals(444, countVisitor.getCount(MkvTypeInfos.SIMPLEBLOCK)); 55 | 56 | Assert.assertEquals(444, frameDecoder.getFrameCount()); 57 | final ByteBuffer codecPrivateDataFromFrame = frameDecoder.getCodecPrivateData(); 58 | Assert.assertEquals(ByteBuffer.wrap(codecPrivateData), codecPrivateDataFromFrame); 59 | } 60 | 61 | 62 | @Test 63 | public void frameDecodeForDifferentResolution() throws Exception { 64 | final InputStream in = TestResourceUtil.getTestInputStream("vogels_330.mkv"); 65 | final H264FrameDecoder frameDecoder = new H264FrameDecoder(); 66 | final StreamingMkvReader mkvStreamReader = 67 | StreamingMkvReader.createDefault(new InputStreamParserByteSource(in)); 68 | 69 | final CountVisitor countVisitor = CountVisitor.create(MkvTypeInfos.CLUSTER, MkvTypeInfos.SEGMENT, 70 | MkvTypeInfos.SIMPLEBLOCK, MkvTypeInfos.TRACKS); 71 | final FrameVisitorTest.TestFrameProcessor frameProcessor = new FrameVisitorTest.TestFrameProcessor(); 72 | mkvStreamReader.apply(new CompositeMkvElementVisitor(countVisitor, 73 | FrameVisitor.create(frameDecoder, Optional.empty(), Optional.of(1L)), 74 | FrameVisitor.create(frameProcessor, Optional.empty(), Optional.of(2L)))); 75 | 76 | Assert.assertEquals(1, countVisitor.getCount(MkvTypeInfos.TRACKS)); 77 | Assert.assertEquals(9, countVisitor.getCount(MkvTypeInfos.CLUSTER)); 78 | Assert.assertEquals(2334, countVisitor.getCount(MkvTypeInfos.SIMPLEBLOCK)); // Total frames 79 | Assert.assertEquals(909, frameDecoder.getFrameCount()); // Video frames 80 | Assert.assertEquals(1425, frameProcessor.getFramesCount()); // Audio frames 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/kinesisvideo/parser/utilities/H264FrameRendererTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"). 5 | You may not use this file except in compliance with the License. 6 | A copy of the License is located at 7 | 8 | http://aws.amazon.com/apache2.0/ 9 | 10 | or in the "license" file accompanying this file. 11 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | */ 14 | package com.amazonaws.kinesisvideo.parser.utilities; 15 | 16 | import com.amazonaws.kinesisvideo.parser.TestResourceUtil; 17 | import com.amazonaws.kinesisvideo.parser.ebml.InputStreamParserByteSource; 18 | import com.amazonaws.kinesisvideo.parser.ebml.MkvTypeInfos; 19 | import com.amazonaws.kinesisvideo.parser.examples.KinesisVideoFrameViewer; 20 | import com.amazonaws.kinesisvideo.parser.mkv.MkvElementVisitException; 21 | import com.amazonaws.kinesisvideo.parser.mkv.StreamingMkvReader; 22 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CompositeMkvElementVisitor; 23 | import com.amazonaws.kinesisvideo.parser.mkv.visitors.CountVisitor; 24 | import org.junit.Assert; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.powermock.modules.junit4.PowerMockRunner; 28 | 29 | import java.awt.image.BufferedImage; 30 | import java.io.IOException; 31 | import java.io.InputStream; 32 | 33 | import static org.mockito.Matchers.any; 34 | import static org.mockito.Mockito.doNothing; 35 | import static org.mockito.Mockito.times; 36 | import static org.mockito.Mockito.verify; 37 | import static org.powermock.api.mockito.PowerMockito.mock; 38 | 39 | 40 | @RunWith(PowerMockRunner.class) 41 | public class H264FrameRendererTest { 42 | 43 | @Test 44 | public void frameRenderCountTest() throws IOException, MkvElementVisitException { 45 | final InputStream in = TestResourceUtil.getTestInputStream("kinesis_video_renderer_example_output.mkv"); 46 | 47 | final KinesisVideoFrameViewer kinesisVideoFrameViewer = mock(KinesisVideoFrameViewer.class); 48 | doNothing().when(kinesisVideoFrameViewer).update(any(BufferedImage.class)); 49 | H264FrameRenderer frameRenderer = H264FrameRenderer.create(kinesisVideoFrameViewer); 50 | StreamingMkvReader mkvStreamReader = 51 | StreamingMkvReader.createDefault(new InputStreamParserByteSource(in)); 52 | 53 | CountVisitor countVisitor = 54 | CountVisitor.create(MkvTypeInfos.CLUSTER, MkvTypeInfos.SEGMENT, MkvTypeInfos.SIMPLEBLOCK); 55 | 56 | mkvStreamReader.apply(new CompositeMkvElementVisitor(countVisitor, FrameVisitor.create(frameRenderer))); 57 | 58 | Assert.assertEquals(444, frameRenderer.getFrameCount()); 59 | 60 | verify(kinesisVideoFrameViewer, times(444)).update(any(BufferedImage.class)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/resources/LambdaExampleCFnTemplate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: "2010-09-09" 3 | Description: This is the CloudFormation Template that creates reources for KinesisVideoRekognitionLambdaExample. 4 | Parameters: 5 | LambdaFunctionBucket: 6 | Type: String 7 | Description: S3 bucket that holds the Lambda Function which parses inference output. E.g., "yourS3BucketName" 8 | LambdaFunctionKey: 9 | Type: String 10 | Description: S3 key of the Lambda Function which parses inference output. E.g., "yours3path/amazon-kinesis-video-streams-parser-library-1.0.10-shaded.jar" 11 | KVSStreamName: 12 | Type: String 13 | Description: Input KVS Stream Name created in https://docs.aws.amazon.com/rekognition/latest/dg/recognize-faces-in-a-video-stream.html 14 | KDSStreamArn: 15 | Type: String 16 | Description: KDS StreamArn, created in https://docs.aws.amazon.com/rekognition/latest/dg/recognize-faces-in-a-video-stream.html 17 | Resources: 18 | LambdaRole: 19 | Type: "AWS::IAM::Role" 20 | Properties: 21 | AssumeRolePolicyDocument: 22 | Version: "2012-10-17" 23 | Statement: 24 | - Effect: Allow 25 | Principal: 26 | Service: 27 | - "lambda.amazonaws.com" 28 | Action: 29 | - "sts:AssumeRole" 30 | Path: "/" 31 | Policies: 32 | - 33 | PolicyName: "LambdaPolicy" 34 | PolicyDocument: 35 | Version: "2012-10-17" 36 | Statement: 37 | - 38 | Sid: "ParserLibRekognitionLambdaExamplePolicy" 39 | Effect: "Allow" 40 | Action: 41 | - "dynamodb:*" 42 | - "logs:CreateLogGroup" 43 | - "logs:CreateLogStream" 44 | - "logs:PutLogEvents" 45 | - "kinesis:Get*" 46 | - "kinesis:List*" 47 | - "kinesis:Describe*" 48 | - "kinesisvideo:*" 49 | - "s3:*" 50 | Resource: 51 | - "*" 52 | LambdaFunctionProcessingRekognitionResult: 53 | Type: "AWS::Lambda::Function" 54 | Properties: 55 | Handler: "com.amazonaws.kinesisvideo.parser.examples.lambda.KinesisVideoRekognitionLambdaExample::handleRequest" 56 | Role: !GetAtt LambdaRole.Arn 57 | Code: 58 | S3Bucket: {"Fn::Sub": "${LambdaFunctionBucket}"} 59 | S3Key: {"Fn::Sub": "${LambdaFunctionKey}"} 60 | Runtime: "java8" 61 | Environment: 62 | Variables: 63 | DISPLAY: localhost:0.0 64 | JAVA_TOOL_OPTIONS: {"Fn::Sub": "-Djava.awt.headless=true -DKVSStreamName=${KVSStreamName} -Dlog4j.debug"} 65 | Timeout: "300" 66 | MemorySize: "3008" 67 | ReservedConcurrentExecutions: 1 68 | LambdaTrigger: 69 | Type: "AWS::Lambda::EventSourceMapping" 70 | Properties: 71 | BatchSize: 100 72 | Enabled: True 73 | EventSourceArn: {"Fn::Sub": "${KDSStreamArn}"} 74 | FunctionName: !Ref LambdaFunctionProcessingRekognitionResult 75 | StartingPosition: "LATEST" 76 | -------------------------------------------------------------------------------- /src/test/resources/bezos_vogels.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/bezos_vogels.mkv -------------------------------------------------------------------------------- /src/test/resources/clusters.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/clusters.mkv -------------------------------------------------------------------------------- /src/test/resources/empty-mkv-with-tags.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/empty-mkv-with-tags.mkv -------------------------------------------------------------------------------- /src/test/resources/kinesis_video_renderer_example_output.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/kinesis_video_renderer_example_output.mkv -------------------------------------------------------------------------------- /src/test/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | #name=PropertiesConfig 2 | #appenders = console 3 | # 4 | #appender.console.type = Console 5 | #appender.console.name = STDOUT 6 | #appender.console.layout.type = PatternLayout 7 | #appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n 8 | # 9 | #rootLogger.level = error 10 | #rootLogger.appenderRefs = stdout 11 | #rootLogger.appenderRef.stdout.ref = STDOUT 12 | 13 | # Root logger option 14 | log4j.rootLogger=INFO, stdout 15 | 16 | # Direct log messages to stdout 17 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 18 | log4j.appender.stdout.Target=System.out 19 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 20 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/test/resources/output-get-media-equal-timecode.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/output-get-media-equal-timecode.mkv -------------------------------------------------------------------------------- /src/test/resources/output-get-media-non-increasing-timecode.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/output-get-media-non-increasing-timecode.mkv -------------------------------------------------------------------------------- /src/test/resources/output_get_media.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/output_get_media.mkv -------------------------------------------------------------------------------- /src/test/resources/output_get_media_sparse_fragments.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/output_get_media_sparse_fragments.mkv -------------------------------------------------------------------------------- /src/test/resources/output_get_media_sparse_fragments_merged.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/output_get_media_sparse_fragments_merged.mkv -------------------------------------------------------------------------------- /src/test/resources/rendering_example_video.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/rendering_example_video.mkv -------------------------------------------------------------------------------- /src/test/resources/test_mixed_tags.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/test_mixed_tags.mkv -------------------------------------------------------------------------------- /src/test/resources/test_tags_empty_cluster.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/test_tags_empty_cluster.mkv -------------------------------------------------------------------------------- /src/test/resources/vogels_330.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/vogels_330.mkv -------------------------------------------------------------------------------- /src/test/resources/vogels_480.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/amazon-kinesis-video-streams-parser-library/0056da083402a96cffcdfd8bca9433dd25eb7470/src/test/resources/vogels_480.mkv --------------------------------------------------------------------------------