コードの確認 - Amazon Kinesis Video Streams

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

コードの確認

このセクションでは、Java ライブラリとテストコードを検証し、ライブラリに含まれるツールを独自のコードで使用する方法について学習します。

Kinesis ビデオストリームパーサーライブラリには、次のツールが含まれています。

StreamingMkvReader

このクラスは、ブロックしない方法でストリームから指定されたMKV要素を読み取ります。

次のコード例 (FragmentMetadataVisitorTest から) は、Streaming MkvReader を作成、使用して inputStream と呼ばれる入力ストリームから MkvElement オブジェクトを取得する方法を示しています。

StreamingMkvReader mkvStreamReader = StreamingMkvReader.createDefault(new InputStreamParserByteSource(inputStream)); while (mkvStreamReader.mightHaveNext()) { Optional<MkvElement> mkvElement = mkvStreamReader.nextIfAvailable(); if (mkvElement.isPresent()) { mkvElement.get().accept(fragmentVisitor); ... } } }

FragmentMetadataVisitor

このクラスはフラグメント (メディア要素) のメタデータを取得し、コーデックプライベートデータ、ピクセル幅、ピクセル高さなどのメディア情報を含む個々のデータストリームを追跡します。

次のコード例 (FragmentMetadataVisitorTest ファイルから) は FragmentMetadataVisitor を使って MkvElement オブジェクトからデータを取得する方法を示しています。

FragmentMetadataVisitor fragmentVisitor = FragmentMetadataVisitor.create(); StreamingMkvReader mkvStreamReader = StreamingMkvReader.createDefault(new InputStreamParserByteSource(in)); int segmentCount = 0; while(mkvStreamReader.mightHaveNext()) { Optional<MkvElement> mkvElement = mkvStreamReader.nextIfAvailable(); if (mkvElement.isPresent()) { mkvElement.get().accept(fragmentVisitor); if (MkvTypeInfos.SIMPLEBLOCK.equals(mkvElement.get().getElementMetaData().getTypeInfo())) { MkvDataElement dataElement = (MkvDataElement) mkvElement.get(); Frame frame = ((MkvValue<Frame>)dataElement.getValueCopy()).getVal(); MkvTrackMetadata trackMetadata = fragmentVisitor.getMkvTrackMetadata(frame.getTrackNumber()); assertTrackAndFragmentInfo(fragmentVisitor, frame, trackMetadata); } if (MkvTypeInfos.SEGMENT.equals(mkvElement.get().getElementMetaData().getTypeInfo())) { if (mkvElement.get() instanceof MkvEndMasterElement) { if (segmentCount < continuationTokens.size()) { Optional<String> continuationToken = fragmentVisitor.getContinuationToken(); Assert.assertTrue(continuationToken.isPresent()); Assert.assertEquals(continuationTokens.get(segmentCount), continuationToken.get()); } segmentCount++; } } } }

前述の例は、次のコーディングパターンを示しています。

  • データ解析のための FragmentMetadataVisitor およびデータ提供のための StreamingMkvReader を作成します。

  • ストリーム内の各 MkvElement について、そのメタデータが SIMPLEBLOCK タイプかどうかを検証します。

  • 該当する場合は MkvElement から MkvDataElement を取得します。

  • MkvDataElement から Frame (メディアデータ) を取得します。

  • FragmentMetadataVisitor から Frame 用の MkvTrackMetadata を取得します。

  • Frame および MkvTrackMetadata オブジェクトから次のデータを取得して検証します。

    • 追跡番号。

    • フレームのピクセルの高さ。

    • フレームのピクセルの幅。

    • フレームのエンコードに使用するコーデックのコーデック ID。

    • このフレームが順番に到着したこと。前のフレームのトラック番号が存在する場合、現在のフレームのトラック番号より小さいことを確認します。

プロジェクトで FragmentMetadataVisitor を使用するには、ビジターの accept 方法を使って MkvElement オブジェクトをビジターにパスします。

mkvElement.get().accept(fragmentVisitor);

OutputSegmentMerger

このクラスは、ストリーム内の異なるトラックのメタデータを単一のセグメントを持つストリームにマージします。

次のコード例 (FragmentMetadataVisitorTest ファイルから) は、OutputSegmentMerger を使って inputBytes と呼ばれるバイト配列の追跡メタデータをマージする方法を示しています。

FragmentMetadataVisitor fragmentVisitor = FragmentMetadataVisitor.create(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); OutputSegmentMerger outputSegmentMerger = OutputSegmentMerger.createDefault(outputStream); CompositeMkvElementVisitor compositeVisitor = new TestCompositeVisitor(fragmentVisitor, outputSegmentMerger); final InputStream in = TestResourceUtil.getTestInputStream("output_get_media.mkv"); StreamingMkvReader mkvStreamReader = StreamingMkvReader.createDefault(new InputStreamParserByteSource(in)); while (mkvStreamReader.mightHaveNext()) { Optional<MkvElement> mkvElement = mkvStreamReader.nextIfAvailable(); if (mkvElement.isPresent()) { mkvElement.get().accept(compositeVisitor); if (MkvTypeInfos.SIMPLEBLOCK.equals(mkvElement.get().getElementMetaData().getTypeInfo())) { MkvDataElement dataElement = (MkvDataElement) mkvElement.get(); Frame frame = ((MkvValue<Frame>) dataElement.getValueCopy()).getVal(); Assert.assertTrue(frame.getFrameData().limit() > 0); MkvTrackMetadata trackMetadata = fragmentVisitor.getMkvTrackMetadata(frame.getTrackNumber()); assertTrackAndFragmentInfo(fragmentVisitor, frame, trackMetadata); } }

前述の例は、次のコーディングパターンを示しています。

  • FragmentMetadataVisitor を作成してストリームからメタデータを取得する。

  • 出力ストリームを作成してマージされたメタデータを取得する。

  • OutputSegmentMerger を作成し、ByteArrayOutputStream に渡す。

  • 2 つのビジターを含む CompositeMkvElementVisitor を作成する。

  • 指定されたファイルを指す InputStream を作成する。

  • 入力データ内の各要素を出力ストリームにマージします。

KinesisVideoExample

これは、Kinesis ビデオストリームパーサーライブラリの使用方法を示すサンプルアプリケーションです。

このクラスは次の操作を実行します。

  • Kinesis のビデオストリームを作成します。指定した名前がすでに存在する場合は、ストリームが削除され、再作成されます。

  • Kinesis ビデオストリームPutMediaにビデオフラグメントをストリーミングするための呼び出し。

  • Kinesis ビデオストリームからビデオフラグメントをストリーミングGetMediaするための呼び出し。

  • StreamingMkvReader を使用してストリームで返されたフラグメントを解析し、FragmentMetadataVisitor を使用してフラグメントを記録します。

ストリームを削除して再作成

次のコード例 (StreamOps.java ファイルから) は、特定の Kinesis のビデオストリーム を削除します。

//Delete the stream amazonKinesisVideo.deleteStream(new DeleteStreamRequest().withStreamARN(streamInfo.get().getStreamARN()));

次のコード例 (StreamOps.java ファイルから) は、指定された名前の Kinesis のビデオストリームを作成します。

amazonKinesisVideo.createStream(new CreateStreamRequest().withStreamName(streamName) .withDataRetentionInHours(DATA_RETENTION_IN_HOURS) .withMediaType("video/h264"));

呼び出し PutMedia

次のコード例 ( PutMediaWorker.java ファイルから) は、ストリームPutMediaで を呼び出します。

putMedia.putMedia(new PutMediaRequest().withStreamName(streamName) .withFragmentTimecodeType(FragmentTimecodeType.RELATIVE) .withProducerStartTimestamp(new Date()) .withPayload(inputStream), new PutMediaAckResponseHandler() { ... });

呼び出し GetMedia

次のコード例 ( GetMediaWorker.java ファイルから) は、ストリームGetMediaで を呼び出します。

GetMediaResult result = videoMedia.getMedia(new GetMediaRequest().withStreamName(streamName).withStartSelector(startSelector));

GetMedia 結果を解析する

このセクションでは、StreamingMkvReaderFragmentMetadataVisitorCompositeMkvElementVisitor を使用して、GetMedia から返されたデータを解析し、ファイルに保存して、ログに記録する方法について説明します。

GetMedia で の出力を読み取る StreamingMkvReader

次のコード例 ( GetMediaWorker.java ファイルから) は StreamingMkvReaderを作成し、それを使用して GetMediaオペレーションの結果を解析します。

StreamingMkvReader mkvStreamReader = StreamingMkvReader.createDefault(new InputStreamParserByteSource(result.getPayload())); log.info("StreamingMkvReader created for stream {} ", streamName); try { mkvStreamReader.apply(this.elementVisitor); } catch (MkvElementVisitException e) { log.error("Exception while accepting visitor {}", e); }

上記のコード例では、StreamingMkvReaderGetMedia 結果のペイロードから MKVElement オブジェクトを取得します。次のセクションでは、要素は FragmentMetadataVisitor に渡されます。

を使用してフラグメントを取得する FragmentMetadataVisitor

次のコード例 (KinesisVideoExample.java および StreamingMkvReader.java ファイルから) は、FragmentMetadataVisitor を作成します。StreamingMkvReader で反復された MkvElement オブジェクトは、accept メソッドを使用して訪問者に渡されます。

KinesisVideoExample.java: から

FragmentMetadataVisitor fragmentMetadataVisitor = FragmentMetadataVisitor.create();

StreamingMkvReader.java: から

if (mkvElementOptional.isPresent()) { //Apply the MkvElement to the visitor mkvElementOptional.get().accept(elementVisitor); }

要素を記録し、ファイルに書き込む

次のコード例 (KinesisVideoExample.javaファイルから) は、以下のオブジェクトを作成し、それらを GetMediaProcessingArguments 関数の戻り値の一部として返します。

  • システムログに書き込む LogVisitor (MkvElementVisitor の拡張)。

  • 受信データを MKVファイルに書きOutputStream込む 。

  • OutputStream にバインドされたデータをバッファする BufferedOutputStream

  • GetMedia 結果内の連続した要素を同じトラックとEBMLデータにマージOutputSegmentMergerする 。

  • FragmentMetadataVisitorOutputSegmentMerger、および を単一の要素訪問者LogVisitorに構成CompositeMkvElementVisitorする 。

//A visitor used to log as the GetMedia stream is processed. LogVisitor logVisitor = new LogVisitor(fragmentMetadataVisitor); //An OutputSegmentMerger to combine multiple segments that share track and ebml metadata into one //mkv segment. OutputStream fileOutputStream = Files.newOutputStream(Paths.get("kinesis_video_example_merged_output2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); BufferedOutputStream outputStream = new BufferedOutputStream(fileOutputStream); OutputSegmentMerger outputSegmentMerger = OutputSegmentMerger.createDefault(outputStream); //A composite visitor to encapsulate the three visitors. CompositeMkvElementVisitor mkvElementVisitor = new CompositeMkvElementVisitor(fragmentMetadataVisitor, outputSegmentMerger, logVisitor); return new GetMediaProcessingArguments(outputStream, logVisitor, mkvElementVisitor);

その後、メディア処理引数は に渡されGetMediaWorker、次に に渡されExecutorService、別のスレッドでワーカーを実行します。

GetMediaWorker getMediaWorker = GetMediaWorker.create(getRegion(), getCredentialsProvider(), getStreamName(), new StartSelector().withStartSelectorType(StartSelectorType.EARLIEST), amazonKinesisVideo, getMediaProcessingArgumentsLocal.getMkvElementVisitor()); executorService.submit(getMediaWorker);