Schritt 2: Schreiben und untersuchen Sie den Code - Amazon Kinesis Video Streams

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Schritt 2: Schreiben und untersuchen Sie den Code

In diesem Abschnitt prüfen Sie die Java-Bibliothek sowie den Testcode und lernen, wie Sie die Klassen der Bibliothek in eigenem Code verwenden können.

Die Kinesis Video Stream Parser Library enthält die folgenden Tools:

StreamingMkvReader

Diese Klasse liest bestimmte MKV-Elemente aus einem Stream blockierungsfrei.

Das folgende Beispiel (aus der Datei FragmentMetadataVisitorTest) zeigt, wie Sie ein Streaming MkvReader-Objekt erstellen und verwenden können, um MkvElement-Objekte aus dem Eingabe-Stream inputStream zu extrahieren:

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

FragmentMetadataVisitor

Diese Klasse ruft Metadaten für Fragmente (Medienelemente) ab und verfolgt einzelne Datenströme, die Medieninformationen wie private Codec-Daten, Pixelbreite oder Pixelhöhe enthalten.

Das folgende Codebeispiel (aus der Datei FragmentMetadataVisitorTest) zeigt, wie Sie mit FragmentMetadataVisitor Daten aus einem MkvElement-Objekt auslesen können:

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

Das vorhergehende Beispiel weist folgendes Codierungsmuster auf:

  • Ein FragmentMetadataVisitor-Objekt wird zum Analysieren der Daten und ein StreamingMkvReader-Objekt zum Bereitstellen der Daten erstellt.

  • Bei jedem MkvElement im Stream wird geprüft, ob dessen Metadaten den Typ SIMPLEBLOCK haben.

  • Ist dies der Fall, wird das MkvDataElement aus dem MkvElement abgerufen.

  • Das Frame-Objekt (Mediendaten) wird aus MkvDataElement abgerufen.

  • Das MkvTrackMetadata-Element des Frame-Objekts wird aus dem FragmentMetadataVisitor-Objekt abgerufen.

  • Die folgenden Daten werden aus den Frame- und MkvTrackMetadata-Objekten abgerufen und geprüft:

    • Track-Nummer

    • Framehöhe in Pixeln

    • Framebreite in Pixeln

    • ID des zur Codierung des Frames verwendeten Codecs

    • Richtige Position des Frames im Stream. Stellen Sie sicher, dass die Titelnummer des vorherigen Frames, falls vorhanden, kleiner ist als die des aktuellen Frames.

Um FragmentMetadataVisitor im Projekt zu verwenden, übergeben Sie MkvElement-Objekte mit deren accept-Methode an das Visitor-Objekt:

mkvElement.get().accept(fragmentVisitor);

OutputSegmentMerger

Diese Klasse führt die Metadaten verschiedener Tracks im Stream zu einem Stream mit einem einzigen Segment zusammen.

Das folgende Codebeispiel (aus der Datei FragmentMetadataVisitorTest) zeigt, wie Sie mit einem OutputSegmentMerger-Objekt die Track-Metadaten im Byte-Array inputBytes zusammenführen:

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

Das vorhergehende Beispiel weist folgendes Codierungsmuster auf:

  • Erstellen Sie FragmentMetadataVisitor, um die Metadaten aus dem Stream abzurufen.

  • Ein Ausgabe-Stream für die zusammengeführten Metadaten wird erstellt.

  • Erstellen Sie OutputSegmentMerger, übergeben Sie dabei ByteArrayOutputStream.

  • Erstellen Sie das CompositeMkvElementVisitor-Objekt, das die beiden Besucher enthält.

  • Erstellen Sie einen InputStream, der auf die angegebene Datei zeigt.

  • Die einzelnen Elemente in den Eingabedaten werden im Ausgabe-Stream zusammengeführt.

KinesisVideoExample

Dies ist eine Beispielanwendung, die zeigt, wie die Kinesis Video Stream Parser Library verwendet wird.

Diese Klasse führt die folgenden Operationen aus:

  • Erzeugt einen Kinesis-Videostream. Wenn ein Stream mit dem angegebenen Namen bereits vorhanden ist, wird der Stream gelöscht und neu erstellt.

  • Aufrufe PutMediazum Streamen von Videofragmenten in den Kinesis-Videostream.

  • Aufrufe GetMediazum Streamen von Videofragmenten aus dem Kinesis-Videostream.

  • Verwendet einen StreamingMkvReader zum Analysieren der zurückgegebenen Fragmente auf dem Stream und verwendet FragmentMetadataVisitor für die Protokollierung der Fragmente.

Löschen und Neuerstellen des Streams

Das folgende Codebeispiel (aus der StreamOps.java Datei) löscht einen bestimmten Kinesis-Videostream:

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

Das folgende Codebeispiel (aus der StreamOps.java Datei) erstellt einen Kinesis-Videostream mit dem angegebenen Namen:

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

Rufen PutMedia

Das folgende Codebeispiel (aus der PutMediaWorker.java Datei) ruft den Stream PutMediaauf:

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

Rufen Sie GetMedia

Das folgende Codebeispiel (aus der GetMediaWorker.java Datei) ruft den Stream GetMediaauf:

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

Analysieren Sie das Ergebnis GetMedia

Dieser Abschnitt beschreibt, wie StreamingMkvReader, FragmentMetadataVisitor und CompositeMkvElementVisitor zur Analyse, zum Speichern in die Datei und zur Protokollierung der von GetMedia zurückgegebenen Daten verwendet wird.

Lesen Sie die Ausgabe von mit GetMedia StreamingMkvReader

Das folgende Codebeispiel (aus der GetMediaWorker.java Datei) erstellt eine StreamingMkvReader und verwendet sie, um das Ergebnis der GetMediaOperation zu analysieren:

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

Im vorigen Codebeispiel ruft der StreamingMkvReader MKVElement-Objekte aus der Nutzlast des Ergebnisses von GetMedia ab. Im nächsten Abschnitt werden die Elemente einem FragmentMetadataVisitor übergeben.

Fragmente abrufen mit FragmentMetadataVisitor

Die folgenden Codebeispiele (aus den Dateien KinesisVideoExample.java und StreamingMkvReader.java) erstellen einen FragmentMetadataVisitor. Die MkvElement-Objekte, die von dem StreamingMkvReader durchlaufen werden, werden dann über die Methode accept dem Besucher übergeben.

von KinesisVideoExample.java:

FragmentMetadataVisitor fragmentMetadataVisitor = FragmentMetadataVisitor.create();

von StreamingMkvReader.java:

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

Die Elemente schreiben und in eine Datei schreiben

Das folgende Code-Beispiel (aus der KinesisVideoExample.java-Datei) erstellt die folgenden Objekte und gibt sie als Teil des Rückgabewerts der GetMediaProcessingArguments-Funktion zurück:

  • Einen LogVisitor (eine Erweiterung von MkvElementVisitor), die in das Systemprotokoll schreibt.

  • Einen OutputStream , der die eingehenden Daten in eine MKV-Datei schreibt.

  • Einen BufferedOutputStream , der die für OutputStream gebundenen Daten puffert.

  • Einen OutputSegmentMerger, der aufeinanderfolgende Elemente in das GetMedia-Ergebnis einfügt, mit denselben Track- und EBML-Daten.

  • ACompositeMkvElementVisitor, das das FragmentMetadataVisitorOutputSegmentMerger, und zu einem einzigen Element zusammensetzt, LogVisitor den Besucher.

//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);

Die Argumente für die Medienverarbeitung werden dann an den übergebenGetMediaWorker, der wiederum an den übergeben wirdExecutorService, der den Worker in einem separaten Thread ausführt:

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

Nächster Schritt

Schritt 3: Führen Sie den Code aus und überprüfen Sie ihn