

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

# 파서 라이브러리를 사용하여 카메라의 출력 보기
<a name="parser-library"></a>

Kinesis 비디오 스트림 구문 분석기 라이브러리는 Java 애플리케이션에서 Kinesis 비디오 스트림의 MKV 데이터를 사용하는 데 사용할 수 있는 도구 세트입니다.

이 라이브러리에는 다음 도구가 포함됩니다.
+ [StreamingMkvReader](parser-library-write.md#parser-library-write-SMSR): 이 클래스는 비디오 스트림에서 지정된 MKV 요소를 읽습니다.
+ [FragmentMetadataVisitor](parser-library-write.md#parser-library-write-FMV): 이 클래스는 조각의 메타데이터를 검색하고(미디어 조각) 추적합니다(오디오 또는 자막과 같은 미디어 정보를 포함하는 개별 데이터 스트림).
+ [OutputSegmentMerger](parser-library-write.md#parser-library-write-OSM): 이 클래스는 연속 조각 또는 청크를 한 비디오 스트림에 병합합니다.
+ [KinesisVideoExample](parser-library-write.md#parser-library-write-example): Kinesis 비디오 스트림 구문 분석기 라이브러리를 사용하는 방법을 보여주는 샘플 애플리케이션입니다.

이 라이브러리에는 도구가 사용되는 방법을 보여 주는 테스트도 포함됩니다.

## 사전 조건
<a name="parser-library-prerequisites"></a>

Kinesis 비디오 스트림 구문 분석기 라이브러리를 검사하고 사용하려면 다음이 필요합니다.
+ Amazon Web Services(AWS) 계정. 아직이 없는 경우 단원을 AWS 계정참조하십시오[에 가입 AWS 계정](gs-account.md#sign-up-for-aws).
+ [Eclipse Java Neon](https://www.eclipse.org/downloads/packages/release/neon/3/eclipse-jee-neon-3) 또는 [JetBrains IntelliJ Idea](https://www.jetbrains.com/idea/download/) 같은 Java 통합 개발 환경(IDE).
+ [Amazon Corretto 11과 같은 Java 11](https://docs.aws.amazon.com//corretto/latest/corretto-11-ug/what-is-corretto-11.html).

# 코드 다운로드
<a name="parser-library-download"></a>

이 단원에서는 Java 라이브러리 및 테스트 코드를 다운로드하고 프로젝트를 Java IDE로 가져옵니다.

사전 조건 및 이 절차에 관한 기타 세부 정보는 [파서 라이브러리를 사용하여 카메라의 출력 보기](parser-library.md)를 참조하십시오.

1. 디렉터리를 생성하고 GitHub 리포지토리에서 라이브러리 소스 코드를 복제합니다([https://github.com/aws/amazon-kinesis-video-streams-parser-library](https://github.com/aws/amazon-kinesis-video-streams-parser-library)).

   ```
   git clone https://github.com/aws/amazon-kinesis-video-streams-parser-library
   ```

1. 사용 중인 Java IDE(예: [Eclipse](https://www.eclipse.org/) 또는 [IntelliJ IDEA](https://www.jetbrains.com/idea/))를 열고 다운로드한 Apache Maven 프로젝트를 가져옵니다.
   + **Eclipse에서** [**File**], [**Import**], [**Maven**], [**Existing Maven Projects**]를 차례로 선택하여 `kinesis-video-streams-parser-lib` 폴더로 이동합니다.
   + **IntelliJ Idea에서 ** [**Import**]를 선택합니다. 다운로드한 패키지의 루트에 있는 **pom.xml** 파일을 찾습니다.

    자세한 내용은 관련 IDE 문서를 참조하십시오.

# 코드 검사
<a name="parser-library-write"></a>

이 단원에서는 Java 라이브러리 및 테스트 코드를 검사하고 자체 코드에 있는 라이브러리에서 도구를 사용하는 방법을 배웁니다.

Kinesis 비디오 스트림 구문 분석기 라이브러리에는 다음 도구가 포함되어 있습니다.
+ [StreamingMkvReader](#parser-library-write-SMSR)
+ [FragmentMetadataVisitor](#parser-library-write-FMV)
+ [OutputSegmentMerger](#parser-library-write-OSM)
+ [KinesisVideoExample](#parser-library-write-example)

## StreamingMkvReader
<a name="parser-library-write-SMSR"></a>

이 클래스는 비차단 방식으로 스트림에서 지정된 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
<a name="parser-library-write-FMV"></a>

이 클래스는 조각(미디어 요소)에 대한 메타데이터를 검색하고 코덱 프라이빗 데이터, 픽셀 너비 또는 픽셀 높이와 같은 미디어 정보가 포함된 개별 데이터 스트림을 추적합니다.

다음 코드 예제(`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](#parser-library-write-SMSR)를 생성합니다.
+ 스트림에 있는 각 `MkvElement`에 대해 메타데이터가 유형 `SIMPLEBLOCK`인지 테스트합니다.
+ 이 경우 `MkvElement`에서 `MkvDataElement`를 검색합니다.
+ `MkvDataElement`에서 `Frame`(미디어 데이터)을 검색합니다.
+ `FragmentMetadataVisitor`에서 `Frame`의 `MkvTrackMetadata`를 검색합니다.
+ `Frame` 및 `MkvTrackMetadata` 객체로부터 다음 데이터를 검색하고 확인합니다.
  + 트랙 번호.
  + 프레임의 픽셀 높이.
  + 프레임의 픽셀 넓이.
  + 프레임 인코딩에 사용되는 코덱의 코덱 ID.
  + 이 프레임이 순서대로 도착했는지 여부. 이전 프레임의 트랙 번호가 있는 경우 현재 프레임의 트랙 번호보다 작은지 확인합니다.

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

```
mkvElement.get().accept(fragmentVisitor);
```

## OutputSegmentMerger
<a name="parser-library-write-OSM"></a>

이 클래스는 스트림의 여러 트랙에서 취합되는 메타데이터를 단일 세그먼트로 병합합니다.

다음 코드 예제(`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](#parser-library-write-FMV)를 생성합니다.
+ 출력 스트림을 생성하여 병합된 메타데이터를 수신합니다.
+ `OutputSegmentMerger`에 통과하는 `ByteArrayOutputStream`를 생성합니다.
+ 두 방문자를 포함한 `CompositeMkvElementVisitor`를 생성합니다.
+ 지정 파일을 가리키는 `InputStream`을 생성합니다.
+ 입력 데이터에 있는 각 요소를 출력 스트림에 병합합니다.

## KinesisVideoExample
<a name="parser-library-write-example"></a>

Kinesis 비디오 스트림 구문 분석기 라이브러리를 사용하는 방법을 보여주는 샘플 애플리케이션입니다.

이 클래스는 다음 작업을 수행합니다.
+ Kinesis 비디오 스트림을 생성합니다. 주어진 이름의 스트림이 이미 존재하는 경우, 해당 스트림은 삭제되고 다시 생성됩니다.
+ [PutMedia](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_dataplane_PutMedia.html)를 호출하여 Kinesis 비디오 스트림으로 비디오 조각을 스트리밍합니다.
+ [GetMedia](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_dataplane_GetMedia.html)를 호출하여 Kinesis 비디오 스트림에서 비디오 조각을 스트리밍합니다.
+ [StreamingMkvReader](#parser-library-write-SMSR)을 사용하여 스트림에서 반환되는 조각을 구문 분석하고, [FragmentMetadataVisitor](#parser-library-write-FMV)를 사용하여 조각을 로깅합니다.

### 스트림 삭제 및 재생성
<a name="parser-library-write-example-create"></a>

다음 코드 예제( `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 호출
<a name="parser-library-write-example-putmedia"></a>

다음 코드 예제(`PutMediaWorker.java` 파일의 예제)는 스트림에서 [PutMedia](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_dataplane_PutMedia.html)를 호출합니다.

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

### GetMedia 호출
<a name="parser-library-write-example-getmedia"></a>

다음 코드 예제(`GetMediaWorker.java` 파일의 예제)는 스트림에서 [GetMedia](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_dataplane_GetMedia.html)를 호출합니다.

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

### GetMedia 결과 구문 분석
<a name="parser-library-write-example-parse"></a>

이 단원에서는 [StreamingMkvReader](#parser-library-write-SMSR), [FragmentMetadataVisitor](#parser-library-write-FMV)와 `CompositeMkvElementVisitor`를 사용하여 `GetMedia`에서 반환되는 데이터를 구문 분석하고, 파일에 저장하고, 로깅하는 방법을 설명합니다.

#### StreamingMkvReader를 사용하여 GetMedia 출력 읽기
<a name="parser-library-write-example-parse-smr"></a>

다음 코드 예제(`GetMediaWorker.java` 파일의 예제)는 [StreamingMkvReader](#parser-library-write-SMSR)를 생성해 [GetMedia](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_dataplane_GetMedia.html) 작업의 결과를 구문 분석하는 데 사용합니다.

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

앞의 코드 예제에서 [StreamingMkvReader](#parser-library-write-SMSR)는 `GetMedia` 결과의 페이로드에서 `MKVElement` 객체를 검색합니다. 다음 단원에서는 이 요소들이 [FragmentMetadataVisitor](#parser-library-write-FMV)로 전달됩니다.

#### FragmentMetadataVisitor를 사용하여 조각 검색
<a name="parser-library-write-example-parse-fmv"></a>

다음 코드 예제(`KinesisVideoExample.java` 및 `StreamingMkvReader.java` 파일의 예제)는 [FragmentMetadataVisitor](#parser-library-write-FMV)를 생성합니다. 그런 다음 [StreamingMkvReader](#parser-library-write-SMSR)에 의해 반복되는 `MkvElement` 객체가 `accept` 메서드를 사용하여 방문자에게 전달됩니다 

*`KinesisVideoExample.java`로부터:*

```
FragmentMetadataVisitor fragmentMetadataVisitor = FragmentMetadataVisitor.create();
```

*`StreamingMkvReader.java`로부터:*

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

#### 요소를 로깅하고 파일에 쓰기
<a name="parser-library-write-example-parse-cmev"></a>

다음 코드 예제(`KinesisVideoExample.java` 파일의 예제)는 다음 객체를 생성하여 `GetMediaProcessingArguments` 함수의 반환 값의 일부로 반환합니다.
+ 시스템 로그에 쓰는 `LogVisitor`(`MkvElementVisitor`의 확장).
+ 수신 데이터를 MKV 파일에 쓰는 `OutputStream`.
+ `OutputStream`으로 가는 데이터를 버퍼링하는 `BufferedOutputStream`.
+ `GetMedia` 결과의 연속적 요소들을 동일 트랙 및 EBML 데이터와 병합하는 [OutputSegmentMerger](#parser-library-write-OSM).
+ [FragmentMetadataVisitor](#parser-library-write-FMV), [OutputSegmentMerger](#parser-library-write-OSM)및를 단일 요소 방문자`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);
```

# 코드 실행
<a name="parser-library-run"></a>

Kinesis 비디오 스트림 구문 분석기 라이브러리에는 자체 프로젝트에서 사용할 수 있는 도구가 포함되어 있습니다. 프로젝트에는 사용자가 설치를 확인할 때 실행할 수 있는 도구의 단위 테스트가 포함됩니다.

다음 유닛 테스트가 라이브러리에 포함됩니다.
+ **mkv**
  + `ElementSizeAndOffsetVisitorTest`
  + `MkvValueTest`
  + `StreamingMkvReaderTest`
+ **유틸리티**
  + `FragmentMetadataVisitorTest`
  + `OutputSegmentMergerTest`