

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

# 自动实时图像生成
<a name="s3-real-time-image-create"></a>

Amazon Kinesis Video Streams 提供转码和交付图像的功能。Kinesis Video Streams 自动从视频数据中实时提取图像，并将图像传输到您指定的亚马逊 S3 存储桶。实现实时、自动的图像提取涉及以下步骤：
+ 创建 S3 存储桶以接收生成的图像。
+ 配置 [ImageGenerationConfiguration](https://docs.amazonaws.cn/kinesisvideostreams/latest/APIReference/API_ImageGenerationConfiguration.html)stream 属性，告诉 Kinesis Video Streams 如何创建图像以及将图像发送到何处。
+ 添加图像生成标签 — Kinesis Video Streams 仅使用带有图像生成标签的片段生成图像。这些标签是在使用 Kinesis Video Streams Producer SDK 和方法上传视频时添加`putKinesisVideoEventMetadata`的。

以下过程提供了完成每个步骤的说明。

如果您使用的是客户托管密钥，请确保执行`PutMedia`调用的角色（上传者）具有加密和解密数据以及访问 Amazon S3 存储桶所需的以下权限。
+ `kms:Encrypt`
+ `kms:GenerateDataKey`
+ `kms:Decrypt`
+ `s3:PutObject`

有关更多信息，请参阅 [如何开始使用服务器端加密？](how-kms.md#getting-started-with-sse-akvs)。

**配置生成的图像目标**

1. 创建用于发送图像的 S3 目标存储桶。

   按照[亚马逊 S3 用户指南](https://docs.amazonaws.cn/AmazonS3/latest/userguide/create-bucket-overview.html)创建亚马逊 S3 存储桶。

   记下存储桶的 URI，在下一步更新直播的图像生成配置时，你将需要使用这个 URI。

1. 确认您已 Amazon CLI 安装并配置了。有关更多信息，请参阅[版本 2 的Amazon Command Line Interface 用户指南](cli/latest/userguide/cli-chap-welcome.html)。

1. 使用以下内容作为输入创建一个名`update-image-generation-input.json`为的新文件。使用要使用的值更新占位符值。有关支持的最大值和最小值，请参阅 [UpdateImageGenerationConfiguration](https://docs.amazonaws.cn/kinesisvideostreams/latest/APIReference/API_UpdateImageGenerationConfiguration.html)API。

   ```
   {
      "StreamName": "{{demo-stream}}",
      "ImageGenerationConfiguration": {
         "Status": "ENABLED",
         "DestinationConfig": {
            "DestinationRegion": "{{us-east-1}}",
            "Uri": "s3://{{my-bucket-name}}"
         },
         "SamplingInterval": 200,
         "ImageSelectorType": "PRODUCER_TIMESTAMP",
         "Format": "JPEG",
         "FormatConfig": {
            "JPEGQuality": "80"
         },
         "WidthPixels": 320,
         "HeightPixels": 240
      }
   }
   ```

1. 使用 [UpdateImageGenerationConfiguration](https://docs.amazonaws.cn/kinesisvideostreams/latest/APIReference/API_UpdateImageGenerationConfiguration.html)API 更新直播的图像生成配置，并附加 JSON 文件作为输入，如以下命令所示。请注意，文件路径指向当前目录中的文件。

   ```
   aws kinesisvideo update-image-generation-configuration \
     --cli-input-json file://./update-image-generation-input.json
   ```

1. 成功后，将返回一个空响应，并且终端中不会打印任何内容。
**注意**  
更新图像生成配置后，启动图像生成工作流程至少需要 1 分钟。至少等待 1 分钟，然后再将视频上传到直播中。

1. 验证配置设置。使用为您的直播调用 [DescribeImageGenerationConfiguration](https://docs.amazonaws.cn/kinesisvideostreams/latest/APIReference/API_DescribeImageGenerationConfiguration.html)API。 Amazon CLI 

   ```
   aws kinesisvideo describe-image-generation-configuration \
     --stream-name "{{demo-stream}}"
   ```

Kinesis Video Streams 只会为带有图像生成标签的片段生成和交付图像。与 Amazon S3 图像生成标签一起提供的任何其他片段元数据都将另存为 Amazon S3 元数据。

**注意**  
图像生成标签是指片段元数据标签，而不是流级标签。

**重要**  
图像生成标签计入片段元数据标签限制。有关更多信息，请参阅 [流式传输元数据服务配额](limits.md#limits-streaming-metadata)。

以下是使用该`mkvinfo`实用程序创建片段元数据标签结构的示例。图像生成标签是一个 MKV 简单标签，其密钥为`AWS_KINESISVIDEO_IMAGE_GENERATION`，没有值。有关更多信息，请参阅 Matroska 文档中的[视频标签示例](https://www.matroska.org/technical/tagging-video-example.html)。

```
|+ Tags
| + Tag
|  // MANDATORY: Predefined MKV tag to trigger image generation for the fragment
|  + Simple
|   + Name: AWS_KINESISVIDEO_IMAGE_GENERATION

|  // OPTIONAL: S3 prefix which will be set as prefix for generated image.
|  + Simple
|   + Name: AWS_KINESISVIDEO_IMAGE_PREFIX 
|   + String: {{image_prefix_in_s3}} // 256 bytes max

| // OPTIONAL: Key value pairs that will be persisted as S3 Image object metadata.
|  + Simple
|   + Name: {{CUSTOM_KEY_1}} // Max 128 bytes
|   + String: {{CUSTOM_VALUE_1}} // Max 256 bytes
|  + Simple
|   + Name: {{CUSTOM_KEY_2}} // Max 128 bytes
|   + String: {{CUSTOM_VALUE_2}} // Max 256 bytes
```

## 为片段添加图像生成标签
<a name="s3-adding-image-tags"></a>

Kinesis Video Streams 仅为带有图像生成标签的片段生成和提供图像。Kinesis Video Streams 可以识别这些特殊的 MKV 标签，并根据直播的图像处理配置启动图像生成工作流程。

使用 Kinesis Video Streams Producer SDK 上传媒体时，您可以使用`putKinesisVideoEventMetadata`方法将图像生成标签添加到要标记的每个片段。当使用包含该`keyframe`标志的帧调`putFrame`用新片段时，就会开始一个新的片段。

如果您上传的是预先录制的视频，则该视频的上传速度可能与其录制速度不同，具体取决于您的网络速度。如果您想根据视频的原始时间戳定期生成图像，我们建议您使用制作人时间戳来配置图像生成，而不是使用基于 Amazon Kinesis Video Streams 接收视频的速率生成的服务器时间戳。

要查看此代码的完整示例，请参阅中的[https://github.com/awslabs/amazon-kinesis-video-streams-producer-c/blob/master/samples/KvsVideoOnlyRealtimeStreamingSample.c](https://github.com/awslabs/amazon-kinesis-video-streams-producer-c/blob/master/samples/KvsVideoOnlyRealtimeStreamingSample.c)代码示例 GitHub。

```
// Setup sample frame
MEMSET(frameBuffer, 0x00, frameSize);
frame.frameData = frameBuffer;
frame.version = FRAME_CURRENT_VERSION;
frame.trackId = DEFAULT_VIDEO_TRACK_ID;
frame.duration = HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FPS_VALUE;
frame.decodingTs = defaultGetTime(); // current time
frame.presentationTs = frame.decodingTs;

Frame eofr = EOFR_FRAME_INITIALIZER;

while(defaultGetTime() > streamStopTime) {
    frame.index = frameIndex;
    frame.flags = fileIndex % DEFAULT_KEY_FRAME_INTERVAL == 0 ? FRAME_FLAG_KEY_FRAME : FRAME_FLAG_NONE;
    frame.size = SIZEOF(frameBuffer);

    CHK_STATUS(readFrameData(&frame, frameFilePath));

    // 1. End the previous fragment
    if (frame.flags == FRAME_FLAG_KEY_FRAME && !firstFrame) {
        putKinesisVideoFrame(streamHandle, &eofr);
    }

    // 2. putFrame call
    CHK_STATUS(putKinesisVideoFrame(streamHandle, &frame));

    if (frame.flags == FRAME_FLAG_KEY_FRAME) {
        // 3. Adding the image generation tag
        CHK_STATUS(putKinesisVideoEventMetadata(streamHandle, STREAM_EVENT_TYPE_IMAGE_GENERATION, NULL);)

        // 4. Adding fragment metadata
        for (n = 1; n <= 5; n++) {
            SNPRINTF(metadataKey, METADATA_MAX_KEY_LENGTH, "SAMPLE_KEY_%d", n);
            SNPRINTF(metadataValue, METADATA_MAX_VALUE_LENGTH, "SAMPLE_VALUE_%d", frame.index + n);
            CHK_STATUS(putKinesisVideoFragmentMetadata(streamHandle, metadataKey, metadataValue, FALSE));
        }
    }
    defaultThreadSleep(frame.duration);

    frame.decodingTs += frame.duration;
    frame.presentationTs = frame.decodingTs;
    frameIndex++;
    fileIndex++;
    fileIndex = fileIndex % NUMBER_OF_FRAME_FILES;
    firstFrame = TRUE;
}

// 5. End the final fragment
putKinesisVideoFrame(streamHandle, &eofr);
```

设置样本帧的示例代码的元素解释如下：

1. 每个片段都需要以片段 (`eofr`) 结尾。此语句说，每当收到一个新的关键帧（表示下一帧的开始）时，在将下一帧添加到流中`eofr`之前放一个。

1. 将当前帧放入直播中。

1. 添加图像生成标签。可以在调用之后和调用之前的任何时间`putFrame(keyFrame)`调用该`putKinesisVideoEventMetadata`方法`putFrame(eofr)`。每个片段最多只能调用一次。由于每个片段只有一个关键帧，因此为了简单起见，我们现在将其命名为。检查的返回值`putKinesisVideoEventMetadata`中是否有成功代码 (0)。

1. 添加其他自定义片段元数据，Kinesis Video Streams 会将其转换为 Amazon S3 对象元数据。

1. 结束此上传会话中的最后一个片段。

### 使用样本添加图像生成标签
<a name="use-samples-add-image-gen-tags"></a>

如果您想使用命令行选项来添加图像生成标签，则可以`kvs_gstreamer_audio_video_sample`在 C\+\+ Producer SDK 中使用。通过添加`-e image`或`-e both`参数来启用此功能，如以下示例所示。

```
./kvs_gstreamer_audio_video_sample {{stream-name}} \
  -f {{video-to-upload.mp4}} \
  -e both
```

有关此示例应用程序的更多信息，请参阅中的 [Amazon Kinesis Video Streams CPP Producer、gStreamer 插件和 JNI](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/README.md) 自述文件。 GitHub

## 亚马逊 S3 对象路径（图片）
<a name="s3-object-path"></a>

S3 对象路径描述了已配置的 S3 存储桶上生成图像的交付位置。它使用以下格式：

```
{{ImagePrefix}}_{{AccountID}}_{{StreamName}}_{{ImageTimecode}}_{{RandomID}}.{{file-extension}}
```

对象路径元素的定义如下：
+ `ImagePrefix`-`AWS_KINESISVIDEO_IMAGE_PREFIX` 如果存在则为的值。
+ `AccountID`-创建直播时使用的 Amazon Web Services 账户 ID。
+ `StreamName`-生成图像的流的名称。
+ `ImageTimecode`-生成图像的片段中的纪元时间码（以毫秒为单位）。
+ `RandomID`-随机指南。
+ `file-extension`-根据要求的图像格式提供 JPG 或 PNG。

在此示例中，生成的图像的对象路径将如下所示：

```
111122223333_demo-stream_16907729324_f20f9add-75e7-4399-a30f-fc7aefb1bab7.jpg
```

## 检索图像元数据
<a name="s3-object-metadata"></a>

您可以使用 S3 控制台或 CLI 检索生成的图像的元数据。

Kinesis Video Streams 设置片段编号、制作者和服务器时间戳以及生成的图像的内容类型元数据，所有这些都格式化为 Amazon S3 对象元数据。如果存在任何其他 MKV 标签，则这些标签也将作为 Amazon S3 对象元数据进行添加。以下示例说明如何使用 Amazon S3 头对象 API 命令来检索对象元数据。响应包含 Kinesis Video Streams 创建的元数据。

```
aws s3api head-object --bucket {{my-bucket-name}} --key {{111122223333}}_{{demo-stream}}_1690707290324_f20f9add-7e57-4399-a30f-fc7aefb1bab7.jpg
{
    "AcceptRanges": "bytes",
    "LastModified": "2023-07-30T08:54:51+00:00",
    "ContentLength": 22693,
    "ETag": "\"63e03cb6d57f77e2db984c1d344b1083\"",
    "ContentType": "image/jpeg",
    "ServerSideEncryption": "AES256",
    "Metadata": {
        "aws_kinesisvideo_producer_timestamp": "1690707290324",
        "aws_kinesisvideo_server_timestamp": "1690707289209",
        "aws_kinesisvideo_fragment_number": "91343852333182036507421233921329142742245756394"
    }
}
```

有关 S3 对象元数据的更多信息，请参阅[https://docs.amazonaws.cn/AmazonS3/latest/userguide/UsingMetadata.html](https://docs.amazonaws.cn/AmazonS3/latest/userguide/UsingMetadata.html)。

## 防范限制的 Amazon S3 URI 建议
<a name="s3-uri-recommendations"></a>

如果您向 Amazon S3 写入数千张图像，则存在受限的风险。有关更多信息，请参阅 [S3 前缀放置请求限制](https://docs.amazonaws.cn/AmazonS3/latest/userguide/optimizing-performance.html)。

Amazon S3 前缀以每秒 3,500 个 PUT 请求的 PUT 限制开头，随着时间的推移，唯一前缀的上限将逐渐增加。避免使用日期和时间作为 Amazon S3 的前缀。时间编码的数据将一次影响一个前缀，并且还会定期更改，从而使之前的前缀放大无效。

为了实现更快、更一致的 Amazon S3 扩展，我们建议在 Amazon S3 目标 URI 中添加一个随机前缀，例如十六进制代码或 UUID。例如，十六进制代码前缀自然会将您的请求随机分配给 16 个不同的前缀（每个唯一十六进制字符的前缀），这将允许在 Amazon S3 自动缩放后每秒 56,000 个 PUT 请求。