2단계: 코드 작성 및 검토 - Amazon Kinesis Video Streams

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

2단계: 코드 작성 및 검토

이 단원에서는 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에서 FrameMkvTrackMetadata를 검색합니다.

  • FrameMkvTrackMetadata 객체로부터 다음 데이터를 검색하고 확인합니다.

    • 트랙 번호.

    • 프레임의 픽셀 높이.

    • 프레임의 픽셀 넓이.

    • 프레임 인코딩에 사용되는 코덱의 코덱 ID.

    • 이 프레임이 순서대로 도착했는지 여부. 이전 프레임 (있는 경우) 의 트랙 번호가 현재 프레임의 트랙 번호보다 작은지 확인하십시오.

프로젝트에서 FragmentMetadataVisitor를 사용하려면, MkvElement 객체를 accept 메서드를 사용하여 방문자에 전달합니다

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를 생성합니다.

  • 두 방문자를 포함한 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

이 단원에서는 StreamingMkvReader, FragmentMetadataVisitorCompositeMkvElementVisitor를 사용하여 GetMedia에서 반환되는 데이터를 구문 분석하고, 파일에 저장하고, 로깅하는 방법을 설명합니다.

의 GetMedia 출력을 읽어 보세요. StreamingMkvReader

다음 코드 예제 (GetMediaWorker.java파일로부터) 는 a를 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.javaStreamingMkvReader.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.

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

다음 단계

3단계: 코드 실행 및 확인