

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

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

Amazon Kinesis Video Streams 提供转码和交付图像的功能。Kinesis Video Streams 自动从视频数据中实时提取图像，并将图像传输到您指定的亚马逊 S3 存储桶。实现实时、自动的图像提取涉及以下步骤：
+ 创建 S3 存储桶以接收生成的图像。
+ 配置 [ImageGenerationConfiguration](API_ImageGenerationConfiguration.md)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.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html)创建亚马逊 S3 存储桶。

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

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

1. 使用以下内容作为输入创建一个名`update-image-generation-input.json`为的新文件。使用要使用的值更新占位符值。有关支持的最大值和最小值，请参阅 [UpdateImageGenerationConfiguration](API_UpdateImageGenerationConfiguration.md)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](API_UpdateImageGenerationConfiguration.md) API 更新直播的图像生成配置，并附加 JSON 文件作为输入，如以下命令所示。请注意，文件路径指向当前目录中的文件。

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

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

1. 验证配置设置。使用为您的直播调用 [DescribeImageGenerationConfiguration](API_DescribeImageGenerationConfiguration.md) API。 AWS 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\$1\$1 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 、Plugin 和 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`-创建直播时使用的 AWS 账户 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.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html)。

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

如果您向 Amazon S3 写入数千张图像，则存在受限的风险。有关更多信息，请参阅 [S3 前缀放置请求限制](https://docs.aws.amazon.com/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 请求。

# 问题排查
<a name="s3-image-troubleshooting"></a>

## 图片未传送到 Amazon S3 存储桶
<a name="s3-images-not-delivered"></a>

要解决此问题，需要注意以下几点：

1. 缺少权限

1. 图像生成配置不正确

1. 该标签未添加到片段中

### 缺少权限
<a name="s3-missing-permissions"></a>

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

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

### 验证目的地
<a name="s3-verify-destination"></a>

使用为您的直播调用 DescribeImageGenerationConfiguration API。 AWS CLI 

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

查看回复`DestinationConfig`中的内容并确认其看起来正确。

### 验证图像生成标签是否已添加到片段
<a name="s3-verify-tag-added"></a>

1. 检查呼`putKinesisVideoEventMetadata`叫是否成功。

   成功后，该`putKinesisVideoEventMetadata`方法返回状态码 0。我们建议检查函数的返回值是否为 0。如果返回非零状态码，请将其转换为十六进制并查看以[错误代码参考](producer-sdk-errors.md)获取更多信息。

   确保已打开错误日志，并查看日志中是否存在应用程序中的任何其他错误。查看应用程序的帧提交调用模式并将其与推荐的实现进行比较:[为片段添加图像生成标签](s3-real-time-image-create.md#s3-adding-image-tags).

1. 验证本地生成的 MKV 文件

   确认 Producer SDK 或示例应用程序正确地附加了标签。

   1. 设置 `KVS_DEBUG_DUMP_DATA_FILE_DIR` 环境变量。如果设置了此值，Producer SDK 会将其本应发送到 Kinesis Video Streams 的媒体文件写入指定位置。

      ```
      export KVS_DEBUG_DUMP_DATA_FILE_DIR=/path/to/output/directory
      ```
**注意**  
如果路径不存在，SDK 将不会创建新目录。如有必要，请创建文件夹。

   1. 再次运行该应用程序。你应该会看到`.mkv`文件被写入到指定的输出目录。

   1. 使用 MKVTool Nix 或其他软件验证内容以确保标签存在。

      1. 安装 MKVTool Nix：`brew install mkvtoolnix`

      1. 使用输出目录中的一个`.mkv`文件运行 MKVTool Nix。

         ```
         mkvinfo -v ./path/to/video/file
         ```

      1. 查看 MKVTool Nix 的输出。如果正确调用了`KinesisVideoStream::PutFragmentMetadata`制作人 SDK 方法，您应该会看到以下 MKV 标签。

         ```
         |+ Tags
         | + Tag
         |  + Simple
         |   + Name: AWS_KINESISVIDEO_IMAGE_GENERATION
         ```
**注意**  
标签属于它之前的集群。

   1. 如果 MKV 标签不存在，请确保已使用`STREAM_EVENT_TYPE_IMAGE_GENERATION`参数调用`KinesisVideoStream::PutEventMetadata`生产者 SDK 方法，并且该方法返回成功 (0) 代码。