

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 编写并检查代码
<a name="producersdk-cpp-write"></a>

在本节中[使用 C\+\+ 制作人库](producer-sdk-cpp.md)，您将研究 C\+\+ 测试工具（`tst/ProducerTestFixture.h`和其他文件）中的代码。您在上一部分中已下载该代码。

**平台独立的** C\+\+ 示例演示了以下编码模式：
+ 创建实例`KinesisVideoProducer`以访问 Kinesis Video Streams。
+ 创建 `KinesisVideoStream` 的实例。 Amazon Web Services 账户 如果同名视频流尚不存在，则会在你中创建 Kinesis 视频流。
+ 对于每个数据帧，当其可用时，对 `KinesisVideoStream` 调用 `putFrame` 以将其发送到流。

以下各节提供了有关此编码模式的更多信息。



## 创建的实例 KinesisVideoProducer
<a name="producersdk-cpp-write-create-producer"></a>

您可以通过调用 `KinesisVideoProducer::createSync` 方法来创建 `KinesisVideoProducer` 对象。以下示例在 `ProducerTestFixture.h` 文件中创建 `KinesisVideoProducer`：

```
kinesis_video_producer_ = KinesisVideoProducer::createSync(move(device_provider_),
    move(client_callback_provider_),
    move(stream_callback_provider_),
    move(credential_provider_),
    defaultRegion_);
```

`createSync` 方法采用以下参数：
+ 一个 `DeviceInfoProvider` 对象，此对象返回一个包含有关设备或存储配置的信息的 `DeviceInfo` 对象。
**注意**  
您可以使用 `deviceInfo.storageInfo.storageSize` 参数配置内容存储大小。您的内容流共享内容存储。要确定存储大小要求，请将平均帧大小乘以为所有流存储最大持续时间的帧数。然后再乘以 1.2（考虑碎片整理）。例如，假设您的应用程序具有以下配置：  
三个流
3 分钟的最大持续时间
每个流为 30 帧/秒 (FPS)
每个帧的大小为 10000 KB
此应用程序的内容存储要求为 **3（流）\* 3（分钟）\* 60（一分钟内的秒）\* 10000（kb）\* 1.2（碎片整理余量）= 194.4 Mb \~ 200 Mb**。
+ 一个 `ClientCallbackProvider` 对象，此对象返回报告客户端特定的事件的函数指针。
+ 一个 `StreamCallbackProvider` 对象，此对象返回在发生流特定的事件时将回调的函数指针。
+ 一个`CredentialProvider`对象，它提供对 Amazon 凭证环境变量的访问权限。
+  Amazon Web Services 区域 (“us-west-2”)。从区域确定服务终端节点。

## 创建的实例 KinesisVideoStream
<a name="producersdk-cpp-write-create-stream"></a>

您可以通过调用带 `StreamDefinition` 参数的 `KinesisVideoProducer::CreateStream` 方法来创建 `KinesisVideoStream` 对象。该示例在 `ProducerTestFixture.h` 文件中创建 `KinesisVideoStream`，轨道类型为视频，轨道 ID 为 1：

```
auto stream_definition = make_unique<StreamDefinition>(stream_name,
                                               hours(2),
                                               tags,
                                               "",
                                               STREAMING_TYPE_REALTIME,
                                               "video/h264",
                                               milliseconds::zero(),
                                               seconds(2),
                                               milliseconds(1),
                                               true,
                                               true,
                                               true);
return kinesis_video_producer_->createStream(move(stream_definition));
```

`StreamDefinition` 对象具有以下字段：
+ 流名称。
+ 数据保留期。
+ 流的标记。使用者应用程序可使用这些标记来查找正确的流或获取有关流的更多信息。也可以在 Amazon Web Services 管理控制台中查看这些标记。
+ Amazon KMS 直播的加密密钥。有关更多信息，请参阅 [Kinesis Video Streams 中的数据保护](how-kms.md)。
+ 流式处理类型。目前唯一有效的值是 `STREAMING_TYPE_REALTIME`。
+ 媒体内容类型。
+ 媒体延迟。当前未使用此值，应将其设置为 0。
+ 每个片段的播放持续时间。
+ 媒体时间码标度。
+ 媒体是否使用关键帧片段。
+ 媒体是否使用时间码。
+ 媒体是否使用绝对片段时间。

## 在 Kinesis 视频流中添加音轨
<a name="producersdk-cpp-write-add-audiotrack-to-stream"></a>

您可以使用以下`addTrack`方法将音轨详细信息添加到视频轨道流定义中`StreamDefinition`：

```
stream_definition->addTrack(DEFAULT_AUDIO_TRACKID, DEFAULT_AUDIO_TRACK_NAME, DEFAULT_AUDIO_CODEC_ID, MKV_TRACK_INFO_TYPE_AUDIO);
```

该`addTrack`方法需要以下参数：
+ 曲目 ID（作为音频的 ID）。该值应为唯一的非零值。
+ 用户定义的轨道名称（例如，音轨的 “音频”）。
+ 此曲目的编解码器 ID（例如，音轨 “A\_AAC”）。
+ 轨道类型（例如，使用 MKV\_TRACK\_INFO\_TYPE\_AUDIO 的枚举值作为音频）。

如果有用于音轨的编解码器专用数据，可在调用 addTrack 函数时传递。您也可以在中调用 start 方法的同时在创建 KinesisVideoStream 对象之后发送编解码器的私有数据。 KinesisVideoStream

## 在 Kinesis 视频流中放一帧
<a name="producersdk-cpp-write-putframe"></a>

你可以使用将媒体放入 Kinesis 视频流`KinesisVideoStream::putFrame`，传入一个包含标题和媒体数据的`Frame`对象。此示例调用 `ProducerApiTest.cpp` 文件中的 `putFrame`：

```
frame.duration = FRAME_DURATION_IN_MICROS * HUNDREDS_OF_NANOS_IN_A_MICROSECOND;
    frame.size = SIZEOF(frameBuffer_);
    frame.frameData = frameBuffer_;
    MEMSET(frame.frameData, 0x55, frame.size);

    while (!stop_producer_) {
        // Produce frames
        timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
                std::chrono::system_clock::now().time_since_epoch()).count() / DEFAULT_TIME_UNIT_IN_NANOS;
        frame.index = index++;
        frame.decodingTs = timestamp;
        frame.presentationTs = timestamp;

        // Key frame every 50th
        frame.flags = (frame.index % 50 == 0) ? FRAME_FLAG_KEY_FRAME : FRAME_FLAG_NONE;
    ...

    EXPECT_TRUE(kinesis_video_stream->putFrame(frame));
```

**注意**  
前面的 C\+\+ 生成器示例发送测试数据的缓冲区。在实际应用中，您应从媒体源 (例如摄像机) 的帧数据中获取帧缓冲区和大小。

`Frame` 对象具有以下字段：
+ 帧索引。这应是一个单调递增的值。
+ 与帧关联的标记。例如，如果编码器已配置为生成关键帧，则将为此帧分配 `FRAME_FLAG_KEY_FRAME` 标记。
+ 解码时间戳。
+ 演示时间戳。
+ 帧的持续时间 (最多 100 ns)。
+ 帧大小 (以字节为单位)。
+ 帧数据。

有关帧的格式的更多信息，请参阅 [Kinesis Video Streams 数据模型](how-data.md)。

## 将 a 放 KinesisVideoFrame 入特定的曲目中 KinesisVideoStream
<a name="producersdk-cpp-write-putframeintospecifictrack"></a>

您可以使用该`PutFrameHelper`类将帧数据放入特定的轨道中。首先，调用，`getFrameDataBuffer`获取指向其中一个预先分配的缓冲区的指针，以填充数据。`KinesisVideoFrame`然后，您可以调用，`putFrameMultiTrack`将与布尔值`KinesisVideoFrame`一起发送，以指示帧数据的类型。如果是视频数据，请使用 true；如果帧包含音频数据，则使用 false。该`putFrameMultiTrack`方法使用排队机制来确保 MKV 片段保持单调递增的帧时间戳，并且任意两个片段不会重叠。例如，片段第一帧的 MKV 时间戳应始终大于前一片段最后一帧的 MKV 时间戳。

`PutFrameHelper` 包含以下字段：
+ 队列中音频帧的最大数量。
+ 队列中视频帧的最大数量。
+ 为单个音频帧分配的大小。
+ 为单个视频帧分配的大小。

## 访问指标和指标记录
<a name="producersdk-cpp-write-metrics"></a>

C\+\+ 制作器 SDK 包括指标和指标日志记录功能。

您可以使用`getKinesisVideoMetrics`和 `getKinesisVideoStreamMetrics` API 操作来检索有关 Kinesis Video Streams 和您的活跃直播的信息。

以下代码来自 `kinesis-video-pic/src/client/include/com/amazonaws/kinesis/video/client/Include.h` 文件。

```
/**
* Gets information about the storage availability.
*
* @param 1 CLIENT_HANDLE - the client object handle.
* @param 2 PKinesisVideoMetrics - OUT - Kinesis Video metrics to be filled.
*
* @return Status of the function call.
*/
PUBLIC_API STATUS getKinesisVideoMetrics(CLIENT_HANDLE, PKinesisVideoMetrics);

/**
* Gets information about the stream content view.
*
* @param 1 STREAM_HANDLE - the stream object handle.
* @param 2 PStreamMetrics - Stream metrics to fill.
*
* @return Status of the function call.
*/
PUBLIC_API STATUS getKinesisVideoStreamMetrics(STREAM_HANDLE, PStreamMetrics);
```

`getKinesisVideoMetrics` 填入的 `PClientMetrics` 对象包含以下信息：
+ **contentStoreSize：**内容存储的总大小（用于存储流数据的内存），以字节为单位。
+ **contentStoreAvailable大小：**内容存储中的可用内存，以字节为单位。
+ **contentStoreAllocated大小：**内容存储中分配的内存。
+ **totalContentViews大小：**用于内容视图的总内存。内容视图是内容存储中一系列信息的索引。
+ **totalFrameRate：**所有活动直播中每秒的总帧数。
+ **totalTransferRate：**所有流中发送的每秒总位数 (bps)。

`getKinesisVideoStreamMetrics` 填入的 `PStreamMetrics` 对象包含以下信息：
+ **currentViewDuration：**内容视图的头部（对帧进行编码时）和当前位置（当帧数据发送到 Kinesis Video Streams Video Streams 时）之间的差异，以 100 ns 为单位。
+ **overallViewDuration：**内容视图的头部（对帧进行编码时）与尾部（当帧从内存中刷新时，要么是因为超出了为内容视图分配的总空间，要么是因为收到来自 Kinesis Video Streams 的`PersistedAck`消息，并且已知保留的帧被刷新）之间的差异，以 100 ns 为单位。
+ **currentViewSize：**内容视图从头部（对帧进行编码时）到当前位置（帧发送到 Kinesis Video Streams 时）的大小（以字节为单位）。
+ **overallViewSize：**内容视图的总大小（以字节为单位）。
+ **currentFrameRate：**上次测量的直播速率，以每秒帧数为单位。
+ **currentTransferRate：**上次测量的流速率，以每秒字节数为单位。

## 分解
<a name="producersdk-cpp-write-teardown"></a>

如果要发送缓冲区中的剩余字节并等待 `ACK`，您可以使用 `stopSync`：

```
kinesis_video_stream->stopSync();            
```

或者，您可以调用 `stop` 来结束流式传输：

```
kinesis_video_stream->stop();            
```

停止流式传输后，您可以通过调用以下 API 释放流：

```
kinesis_video_producer_->freeStream(kinesis_video_stream);            
```