From a7753942b4a4d2d76a094a2253da537a34462cd7 Mon Sep 17 00:00:00 2001 From: awstools Date: Tue, 3 May 2022 21:10:30 +0000 Subject: [PATCH] feat(client-kinesis-video-archived-media): Add support for GetImages API for retrieving images from a video stream --- .../src/KinesisVideoArchivedMedia.ts | 27 ++ .../src/KinesisVideoArchivedMediaClient.ts | 3 + .../src/commands/GetImagesCommand.ts | 99 ++++++ .../src/commands/index.ts | 1 + .../src/models/models_0.ts | 166 +++++++++ .../src/protocols/Aws_restJson1.ts | 135 +++++++ .../kinesis-video-archived-media.json | 333 +++++++++++++++++- 7 files changed, 745 insertions(+), 19 deletions(-) create mode 100644 clients/client-kinesis-video-archived-media/src/commands/GetImagesCommand.ts diff --git a/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMedia.ts b/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMedia.ts index 3ec6b1be1dde..ca94dee9dda6 100644 --- a/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMedia.ts +++ b/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMedia.ts @@ -11,6 +11,7 @@ import { GetHLSStreamingSessionURLCommandInput, GetHLSStreamingSessionURLCommandOutput, } from "./commands/GetHLSStreamingSessionURLCommand"; +import { GetImagesCommand, GetImagesCommandInput, GetImagesCommandOutput } from "./commands/GetImagesCommand"; import { GetMediaForFragmentListCommand, GetMediaForFragmentListCommandInput, @@ -482,6 +483,32 @@ export class KinesisVideoArchivedMedia extends KinesisVideoArchivedMediaClient { } } + /** + *

Retrieves a list of Images corresponding to each timestamp for a given time range, sampling interval, and image format configuration.

+ */ + public getImages(args: GetImagesCommandInput, options?: __HttpHandlerOptions): Promise; + public getImages(args: GetImagesCommandInput, cb: (err: any, data?: GetImagesCommandOutput) => void): void; + public getImages( + args: GetImagesCommandInput, + options: __HttpHandlerOptions, + cb: (err: any, data?: GetImagesCommandOutput) => void + ): void; + public getImages( + args: GetImagesCommandInput, + optionsOrCb?: __HttpHandlerOptions | ((err: any, data?: GetImagesCommandOutput) => void), + cb?: (err: any, data?: GetImagesCommandOutput) => void + ): Promise | void { + const command = new GetImagesCommand(args); + if (typeof optionsOrCb === "function") { + this.send(command, optionsOrCb); + } else if (typeof cb === "function") { + if (typeof optionsOrCb !== "object") throw new Error(`Expect http options but get ${typeof optionsOrCb}`); + this.send(command, optionsOrCb || {}, cb); + } else { + return this.send(command, optionsOrCb); + } + } + /** *

Gets media for a list of fragments (specified by fragment number) from the archived * data in an Amazon Kinesis video stream.

diff --git a/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMediaClient.ts b/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMediaClient.ts index 99aeb782fd27..12fd6e8ce2ed 100644 --- a/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMediaClient.ts +++ b/clients/client-kinesis-video-archived-media/src/KinesisVideoArchivedMediaClient.ts @@ -60,6 +60,7 @@ import { GetHLSStreamingSessionURLCommandInput, GetHLSStreamingSessionURLCommandOutput, } from "./commands/GetHLSStreamingSessionURLCommand"; +import { GetImagesCommandInput, GetImagesCommandOutput } from "./commands/GetImagesCommand"; import { GetMediaForFragmentListCommandInput, GetMediaForFragmentListCommandOutput, @@ -71,6 +72,7 @@ export type ServiceInputTypes = | GetClipCommandInput | GetDASHStreamingSessionURLCommandInput | GetHLSStreamingSessionURLCommandInput + | GetImagesCommandInput | GetMediaForFragmentListCommandInput | ListFragmentsCommandInput; @@ -78,6 +80,7 @@ export type ServiceOutputTypes = | GetClipCommandOutput | GetDASHStreamingSessionURLCommandOutput | GetHLSStreamingSessionURLCommandOutput + | GetImagesCommandOutput | GetMediaForFragmentListCommandOutput | ListFragmentsCommandOutput; diff --git a/clients/client-kinesis-video-archived-media/src/commands/GetImagesCommand.ts b/clients/client-kinesis-video-archived-media/src/commands/GetImagesCommand.ts new file mode 100644 index 000000000000..d4e82470830f --- /dev/null +++ b/clients/client-kinesis-video-archived-media/src/commands/GetImagesCommand.ts @@ -0,0 +1,99 @@ +import { getSerdePlugin } from "@aws-sdk/middleware-serde"; +import { HttpRequest as __HttpRequest, HttpResponse as __HttpResponse } from "@aws-sdk/protocol-http"; +import { Command as $Command } from "@aws-sdk/smithy-client"; +import { + FinalizeHandlerArguments, + Handler, + HandlerExecutionContext, + HttpHandlerOptions as __HttpHandlerOptions, + MetadataBearer as __MetadataBearer, + MiddlewareStack, + SerdeContext as __SerdeContext, +} from "@aws-sdk/types"; + +import { + KinesisVideoArchivedMediaClientResolvedConfig, + ServiceInputTypes, + ServiceOutputTypes, +} from "../KinesisVideoArchivedMediaClient"; +import { GetImagesInput, GetImagesOutput } from "../models/models_0"; +import { + deserializeAws_restJson1GetImagesCommand, + serializeAws_restJson1GetImagesCommand, +} from "../protocols/Aws_restJson1"; + +export interface GetImagesCommandInput extends GetImagesInput {} +export interface GetImagesCommandOutput extends GetImagesOutput, __MetadataBearer {} + +/** + *

Retrieves a list of Images corresponding to each timestamp for a given time range, sampling interval, and image format configuration.

+ * @example + * Use a bare-bones client and the command you need to make an API call. + * ```javascript + * import { KinesisVideoArchivedMediaClient, GetImagesCommand } from "@aws-sdk/client-kinesis-video-archived-media"; // ES Modules import + * // const { KinesisVideoArchivedMediaClient, GetImagesCommand } = require("@aws-sdk/client-kinesis-video-archived-media"); // CommonJS import + * const client = new KinesisVideoArchivedMediaClient(config); + * const command = new GetImagesCommand(input); + * const response = await client.send(command); + * ``` + * + * @see {@link GetImagesCommandInput} for command's `input` shape. + * @see {@link GetImagesCommandOutput} for command's `response` shape. + * @see {@link KinesisVideoArchivedMediaClientResolvedConfig | config} for KinesisVideoArchivedMediaClient's `config` shape. + * + */ +export class GetImagesCommand extends $Command< + GetImagesCommandInput, + GetImagesCommandOutput, + KinesisVideoArchivedMediaClientResolvedConfig +> { + // Start section: command_properties + // End section: command_properties + + constructor(readonly input: GetImagesCommandInput) { + // Start section: command_constructor + super(); + // End section: command_constructor + } + + /** + * @internal + */ + resolveMiddleware( + clientStack: MiddlewareStack, + configuration: KinesisVideoArchivedMediaClientResolvedConfig, + options?: __HttpHandlerOptions + ): Handler { + this.middlewareStack.use(getSerdePlugin(configuration, this.serialize, this.deserialize)); + + const stack = clientStack.concat(this.middlewareStack); + + const { logger } = configuration; + const clientName = "KinesisVideoArchivedMediaClient"; + const commandName = "GetImagesCommand"; + const handlerExecutionContext: HandlerExecutionContext = { + logger, + clientName, + commandName, + inputFilterSensitiveLog: GetImagesInput.filterSensitiveLog, + outputFilterSensitiveLog: GetImagesOutput.filterSensitiveLog, + }; + const { requestHandler } = configuration; + return stack.resolve( + (request: FinalizeHandlerArguments) => + requestHandler.handle(request.request as __HttpRequest, options || {}), + handlerExecutionContext + ); + } + + private serialize(input: GetImagesCommandInput, context: __SerdeContext): Promise<__HttpRequest> { + return serializeAws_restJson1GetImagesCommand(input, context); + } + + private deserialize(output: __HttpResponse, context: __SerdeContext): Promise { + return deserializeAws_restJson1GetImagesCommand(output, context); + } + + // Start section: command_body_extra + // End section: command_body_extra +} diff --git a/clients/client-kinesis-video-archived-media/src/commands/index.ts b/clients/client-kinesis-video-archived-media/src/commands/index.ts index 670f736f2eda..cd688a509025 100644 --- a/clients/client-kinesis-video-archived-media/src/commands/index.ts +++ b/clients/client-kinesis-video-archived-media/src/commands/index.ts @@ -1,5 +1,6 @@ export * from "./GetClipCommand"; export * from "./GetDASHStreamingSessionURLCommand"; export * from "./GetHLSStreamingSessionURLCommand"; +export * from "./GetImagesCommand"; export * from "./GetMediaForFragmentListCommand"; export * from "./ListFragmentsCommand"; diff --git a/clients/client-kinesis-video-archived-media/src/models/models_0.ts b/clients/client-kinesis-video-archived-media/src/models/models_0.ts index 6791e3151f0b..c5bdc8963b80 100644 --- a/clients/client-kinesis-video-archived-media/src/models/models_0.ts +++ b/clients/client-kinesis-video-archived-media/src/models/models_0.ts @@ -970,6 +970,172 @@ export namespace GetHLSStreamingSessionURLOutput { }); } +export enum Format { + JPEG = "JPEG", + PNG = "PNG", +} + +export enum FormatConfigKey { + JPEGQuality = "JPEGQuality", +} + +export enum ImageSelectorType { + PRODUCER_TIMESTAMP = "PRODUCER_TIMESTAMP", + SERVER_TIMESTAMP = "SERVER_TIMESTAMP", +} + +export interface GetImagesInput { + /** + *

The name of the stream from which to retrieve the images. You must specify either the StreamName or the StreamARN.

+ */ + StreamName?: string; + + /** + *

The Amazon Resource Name (ARN) of the stream from which to retrieve the images. You must specify either the StreamName or the StreamARN.

+ */ + StreamARN?: string; + + /** + *

The origin of the Server or Producer timestamps to use to generate the images.

+ */ + ImageSelectorType: ImageSelectorType | string | undefined; + + /** + *

The starting point from which the images should be generated. This StartTimestamp must be within an inclusive range of timestamps for an image to be returned.

+ */ + StartTimestamp: Date | undefined; + + /** + *

The end timestamp for the range of images to be generated.

+ */ + EndTimestamp: Date | undefined; + + /** + *

The time interval in milliseconds (ms) at which the images need to be generated from the stream. The minimum value that can be provided is 3000 ms. If the timestamp range is less than the sampling interval, the Image from the startTimestamp will be returned if available. + *

+ * + *

The minimum value of 3000 ms is a soft limit. If needed, a lower sampling frequency can be requested.

+ *
+ */ + SamplingInterval: number | undefined; + + /** + *

The format that will be used to encode the image.

+ */ + Format: Format | string | undefined; + + /** + *

The list of a key-value pair structure that contains extra parameters that can be applied when the image is generated. The FormatConfig key is the JPEGQuality, which indicates the JPEG quality key to be used to generate the image. + * The FormatConfig value accepts ints from 1 to 100. If the value is 1, the image will be generated with less quality and the best compression. + * If the value is 100, the image will be generated with the best quality and less compression. If no value is provided, the default value of the JPEGQuality key will be set to 80.

+ */ + FormatConfig?: { [key: string]: string }; + + /** + *

The width of the output image that is used in conjunction with the HeightPixels parameter. When both WidthPixels and HeightPixels parameters are provided, + * the image will be stretched to fit the specified aspect ratio. If only the WidthPixels parameter is provided or if only the HeightPixels is provided, a ValidationException will be thrown. + * If neither parameter is provided, the original image size from the stream will be returned.

+ */ + WidthPixels?: number; + + /** + *

The height of the output image that is used in conjunction with the WidthPixels parameter. When both HeightPixels and WidthPixels parameters are provided, the image will be stretched to fit the + * specified aspect ratio. If only the HeightPixels parameter is provided, its original aspect ratio will be used to calculate the WidthPixels ratio. If neither parameter is provided, + * the original image size will be returned.

+ */ + HeightPixels?: number; + + /** + *

The maximum number of images to be returned by the API.

+ * + *

The default limit is 100 images per API response. The additional results will be paginated.

+ *
+ */ + MaxResults?: number; + + /** + *

A token that specifies where to start paginating the next set of Images. This is the GetImages:NextToken from a previously truncated response.

+ */ + NextToken?: string; +} + +export namespace GetImagesInput { + /** + * @internal + */ + export const filterSensitiveLog = (obj: GetImagesInput): any => ({ + ...obj, + }); +} + +export enum ImageError { + MEDIA_ERROR = "MEDIA_ERROR", + NO_MEDIA = "NO_MEDIA", +} + +/** + *

A structure that contains the Timestamp, Error, and ImageContent.

+ */ +export interface Image { + /** + *

An attribute of the Image object that is used to extract an image from the video stream. This field is used to manage gaps on images or to better understand the pagination + * window.

+ */ + TimeStamp?: Date; + + /** + *

The error message shown when the image for the provided timestamp was not extracted due to a non-tryable error. An error will be returned if:

+ *
    + *
  • + *

    There is no media that exists for the specified Timestamp.

    + *
  • + *
+ *
    + *
  • + *

    The media for the specified time does not allow an image to be extracted. In this case the media is audio only, or the incorrect + * media has been ingested.

    + *
  • + *
+ */ + Error?: ImageError | string; + + /** + *

An attribute of the Image object that is Base64 encoded.

+ */ + ImageContent?: string; +} + +export namespace Image { + /** + * @internal + */ + export const filterSensitiveLog = (obj: Image): any => ({ + ...obj, + }); +} + +export interface GetImagesOutput { + /** + *

The list of images generated from the video stream. If there is no media available for the given timestamp, the NO_MEDIA error will be listed in the output. + * If an error occurs while the image is being generated, the MEDIA_ERROR will be listed in the output as the cause of the missing image.

+ */ + Images?: Image[]; + + /** + *

The encrypted token that was used in the request to get more images.

+ */ + NextToken?: string; +} + +export namespace GetImagesOutput { + /** + * @internal + */ + export const filterSensitiveLog = (obj: GetImagesOutput): any => ({ + ...obj, + }); +} + export interface GetMediaForFragmentListInput { /** *

The name of the stream from which to retrieve fragment media. Specify either this parameter or the StreamARN parameter.

diff --git a/clients/client-kinesis-video-archived-media/src/protocols/Aws_restJson1.ts b/clients/client-kinesis-video-archived-media/src/protocols/Aws_restJson1.ts index 6e03f580bef7..786aefab8285 100644 --- a/clients/client-kinesis-video-archived-media/src/protocols/Aws_restJson1.ts +++ b/clients/client-kinesis-video-archived-media/src/protocols/Aws_restJson1.ts @@ -23,6 +23,7 @@ import { GetHLSStreamingSessionURLCommandInput, GetHLSStreamingSessionURLCommandOutput, } from "../commands/GetHLSStreamingSessionURLCommand"; +import { GetImagesCommandInput, GetImagesCommandOutput } from "../commands/GetImagesCommand"; import { GetMediaForFragmentListCommandInput, GetMediaForFragmentListCommandOutput, @@ -35,10 +36,12 @@ import { ClipTimestampRange, DASHFragmentSelector, DASHTimestampRange, + FormatConfigKey, Fragment, FragmentSelector, HLSFragmentSelector, HLSTimestampRange, + Image, InvalidArgumentException, InvalidCodecPrivateDataException, InvalidMediaFrameException, @@ -159,6 +162,46 @@ export const serializeAws_restJson1GetHLSStreamingSessionURLCommand = async ( }); }; +export const serializeAws_restJson1GetImagesCommand = async ( + input: GetImagesCommandInput, + context: __SerdeContext +): Promise<__HttpRequest> => { + const { hostname, protocol = "https", port, path: basePath } = await context.endpoint(); + const headers: any = { + "content-type": "application/json", + }; + const resolvedPath = `${basePath?.endsWith("/") ? basePath.slice(0, -1) : basePath || ""}` + "/getImages"; + let body: any; + body = JSON.stringify({ + ...(input.EndTimestamp !== undefined && + input.EndTimestamp !== null && { EndTimestamp: Math.round(input.EndTimestamp.getTime() / 1000) }), + ...(input.Format !== undefined && input.Format !== null && { Format: input.Format }), + ...(input.FormatConfig !== undefined && + input.FormatConfig !== null && { FormatConfig: serializeAws_restJson1FormatConfig(input.FormatConfig, context) }), + ...(input.HeightPixels !== undefined && input.HeightPixels !== null && { HeightPixels: input.HeightPixels }), + ...(input.ImageSelectorType !== undefined && + input.ImageSelectorType !== null && { ImageSelectorType: input.ImageSelectorType }), + ...(input.MaxResults !== undefined && input.MaxResults !== null && { MaxResults: input.MaxResults }), + ...(input.NextToken !== undefined && input.NextToken !== null && { NextToken: input.NextToken }), + ...(input.SamplingInterval !== undefined && + input.SamplingInterval !== null && { SamplingInterval: input.SamplingInterval }), + ...(input.StartTimestamp !== undefined && + input.StartTimestamp !== null && { StartTimestamp: Math.round(input.StartTimestamp.getTime() / 1000) }), + ...(input.StreamARN !== undefined && input.StreamARN !== null && { StreamARN: input.StreamARN }), + ...(input.StreamName !== undefined && input.StreamName !== null && { StreamName: input.StreamName }), + ...(input.WidthPixels !== undefined && input.WidthPixels !== null && { WidthPixels: input.WidthPixels }), + }); + return new __HttpRequest({ + protocol, + hostname, + port, + method: "POST", + headers, + path: resolvedPath, + body, + }); +}; + export const serializeAws_restJson1GetMediaForFragmentListCommand = async ( input: GetMediaForFragmentListCommandInput, context: __SerdeContext @@ -418,6 +461,63 @@ const deserializeAws_restJson1GetHLSStreamingSessionURLCommandError = async ( } }; +export const deserializeAws_restJson1GetImagesCommand = async ( + output: __HttpResponse, + context: __SerdeContext +): Promise => { + if (output.statusCode !== 200 && output.statusCode >= 300) { + return deserializeAws_restJson1GetImagesCommandError(output, context); + } + const contents: GetImagesCommandOutput = { + $metadata: deserializeMetadata(output), + Images: undefined, + NextToken: undefined, + }; + const data: { [key: string]: any } = __expectNonNull(__expectObject(await parseBody(output.body, context)), "body"); + if (data.Images !== undefined && data.Images !== null) { + contents.Images = deserializeAws_restJson1Images(data.Images, context); + } + if (data.NextToken !== undefined && data.NextToken !== null) { + contents.NextToken = __expectString(data.NextToken); + } + return Promise.resolve(contents); +}; + +const deserializeAws_restJson1GetImagesCommandError = async ( + output: __HttpResponse, + context: __SerdeContext +): Promise => { + const parsedOutput: any = { + ...output, + body: await parseBody(output.body, context), + }; + let response: __BaseException; + let errorCode = "UnknownError"; + errorCode = loadRestJsonErrorCode(output, parsedOutput.body); + switch (errorCode) { + case "ClientLimitExceededException": + case "com.amazonaws.kinesisvideoarchivedmedia#ClientLimitExceededException": + throw await deserializeAws_restJson1ClientLimitExceededExceptionResponse(parsedOutput, context); + case "InvalidArgumentException": + case "com.amazonaws.kinesisvideoarchivedmedia#InvalidArgumentException": + throw await deserializeAws_restJson1InvalidArgumentExceptionResponse(parsedOutput, context); + case "NotAuthorizedException": + case "com.amazonaws.kinesisvideoarchivedmedia#NotAuthorizedException": + throw await deserializeAws_restJson1NotAuthorizedExceptionResponse(parsedOutput, context); + case "ResourceNotFoundException": + case "com.amazonaws.kinesisvideoarchivedmedia#ResourceNotFoundException": + throw await deserializeAws_restJson1ResourceNotFoundExceptionResponse(parsedOutput, context); + default: + const parsedBody = parsedOutput.body; + response = new __BaseException({ + name: parsedBody.code || parsedBody.Code || errorCode, + $fault: "client", + $metadata: deserializeMetadata(output), + }); + throw __decorateServiceException(response, parsedBody); + } +}; + export const deserializeAws_restJson1GetMediaForFragmentListCommand = async ( output: __HttpResponse, context: __SerdeContext @@ -714,6 +814,18 @@ const serializeAws_restJson1DASHTimestampRange = (input: DASHTimestampRange, con }; }; +const serializeAws_restJson1FormatConfig = (input: { [key: string]: string }, context: __SerdeContext): any => { + return Object.entries(input).reduce((acc: { [key: string]: any }, [key, value]: [FormatConfigKey | string, any]) => { + if (value === null) { + return acc; + } + return { + ...acc, + [key]: value, + }; + }, {}); +}; + const serializeAws_restJson1FragmentNumberList = (input: string[], context: __SerdeContext): any => { return input .filter((e: any) => e != null) @@ -793,6 +905,29 @@ const deserializeAws_restJson1FragmentList = (output: any, context: __SerdeConte return retVal; }; +const deserializeAws_restJson1Image = (output: any, context: __SerdeContext): Image => { + return { + Error: __expectString(output.Error), + ImageContent: __expectString(output.ImageContent), + TimeStamp: + output.TimeStamp !== undefined && output.TimeStamp !== null + ? __expectNonNull(__parseEpochTimestamp(__expectNumber(output.TimeStamp))) + : undefined, + } as any; +}; + +const deserializeAws_restJson1Images = (output: any, context: __SerdeContext): Image[] => { + const retVal = (output || []) + .filter((e: any) => e != null) + .map((entry: any) => { + if (entry === null) { + return null as any; + } + return deserializeAws_restJson1Image(entry, context); + }); + return retVal; +}; + const deserializeMetadata = (output: __HttpResponse): __ResponseMetadata => ({ httpStatusCode: output.statusCode, requestId: output.headers["x-amzn-requestid"] ?? output.headers["x-amzn-request-id"], diff --git a/codegen/sdk-codegen/aws-models/kinesis-video-archived-media.json b/codegen/sdk-codegen/aws-models/kinesis-video-archived-media.json index f88e00ebf071..d7adba83b3ac 100644 --- a/codegen/sdk-codegen/aws-models/kinesis-video-archived-media.json +++ b/codegen/sdk-codegen/aws-models/kinesis-video-archived-media.json @@ -31,6 +31,21 @@ "shapes": { "com.amazonaws.kinesisvideoarchivedmedia#AWSAcuityReader": { "type": "service", + "traits": { + "aws.api#service": { + "sdkId": "Kinesis Video Archived Media", + "arnNamespace": "kinesisvideo", + "cloudFormationName": "KinesisVideoArchivedMedia", + "cloudTrailEventSource": "kinesisvideoarchivedmedia.amazonaws.com", + "endpointPrefix": "kinesisvideo" + }, + "aws.auth#sigv4": { + "name": "kinesisvideo" + }, + "aws.protocols#restJson1": {}, + "smithy.api#documentation": "

", + "smithy.api#title": "Amazon Kinesis Video Streams Archived Media" + }, "version": "2017-09-30", "operations": [ { @@ -42,28 +57,16 @@ { "target": "com.amazonaws.kinesisvideoarchivedmedia#GetHLSStreamingSessionURL" }, + { + "target": "com.amazonaws.kinesisvideoarchivedmedia#GetImages" + }, { "target": "com.amazonaws.kinesisvideoarchivedmedia#GetMediaForFragmentList" }, { "target": "com.amazonaws.kinesisvideoarchivedmedia#ListFragments" } - ], - "traits": { - "aws.api#service": { - "sdkId": "Kinesis Video Archived Media", - "arnNamespace": "kinesisvideo", - "cloudFormationName": "KinesisVideoArchivedMedia", - "cloudTrailEventSource": "kinesisvideoarchivedmedia.amazonaws.com", - "endpointPrefix": "kinesisvideo" - }, - "aws.auth#sigv4": { - "name": "kinesisvideo" - }, - "aws.protocols#restJson1": {}, - "smithy.api#documentation": "

", - "smithy.api#title": "Amazon Kinesis Video Streams Archived Media" - } + ] }, "com.amazonaws.kinesisvideoarchivedmedia#ClientLimitExceededException": { "type": "structure", @@ -292,6 +295,57 @@ } } }, + "com.amazonaws.kinesisvideoarchivedmedia#Format": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "JPEG", + "name": "JPEG" + }, + { + "value": "PNG", + "name": "PNG" + } + ] + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#FormatConfig": { + "type": "map", + "key": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#FormatConfigKey" + }, + "value": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#FormatConfigValue" + }, + "traits": { + "smithy.api#length": { + "min": 1, + "max": 1 + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#FormatConfigKey": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "JPEGQuality", + "name": "JPEGQuality" + } + ] + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#FormatConfigValue": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 0, + "max": 256 + }, + "smithy.api#pattern": "^[a-zA-Z_0-9]+$" + } + }, "com.amazonaws.kinesisvideoarchivedmedia#Fragment": { "type": "structure", "members": { @@ -704,6 +758,146 @@ } } }, + "com.amazonaws.kinesisvideoarchivedmedia#GetImages": { + "type": "operation", + "input": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#GetImagesInput" + }, + "output": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#GetImagesOutput" + }, + "errors": [ + { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ClientLimitExceededException" + }, + { + "target": "com.amazonaws.kinesisvideoarchivedmedia#InvalidArgumentException" + }, + { + "target": "com.amazonaws.kinesisvideoarchivedmedia#NotAuthorizedException" + }, + { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ResourceNotFoundException" + } + ], + "traits": { + "smithy.api#documentation": "

Retrieves a list of Images corresponding to each timestamp for a given time range, sampling interval, and image format configuration.

", + "smithy.api#http": { + "method": "POST", + "uri": "/getImages", + "code": 200 + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#GetImagesInput": { + "type": "structure", + "members": { + "StreamName": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#StreamName", + "traits": { + "smithy.api#documentation": "

The name of the stream from which to retrieve the images. You must specify either the StreamName or the StreamARN.

" + } + }, + "StreamARN": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ResourceARN", + "traits": { + "smithy.api#documentation": "

The Amazon Resource Name (ARN) of the stream from which to retrieve the images. You must specify either the StreamName or the StreamARN.

" + } + }, + "ImageSelectorType": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ImageSelectorType", + "traits": { + "smithy.api#documentation": "

The origin of the Server or Producer timestamps to use to generate the images.

", + "smithy.api#required": {} + } + }, + "StartTimestamp": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Timestamp", + "traits": { + "smithy.api#documentation": "

The starting point from which the images should be generated. This StartTimestamp must be within an inclusive range of timestamps for an image to be returned.

", + "smithy.api#required": {} + } + }, + "EndTimestamp": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Timestamp", + "traits": { + "smithy.api#documentation": "

The end timestamp for the range of images to be generated.

", + "smithy.api#required": {} + } + }, + "SamplingInterval": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#SamplingInterval", + "traits": { + "smithy.api#documentation": "

The time interval in milliseconds (ms) at which the images need to be generated from the stream. The minimum value that can be provided is 3000 ms. If the timestamp range is less than the sampling interval, the Image from the startTimestamp will be returned if available.\n

\n \n

The minimum value of 3000 ms is a soft limit. If needed, a lower sampling frequency can be requested.

\n
", + "smithy.api#required": {} + } + }, + "Format": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Format", + "traits": { + "smithy.api#documentation": "

The format that will be used to encode the image.

", + "smithy.api#required": {} + } + }, + "FormatConfig": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#FormatConfig", + "traits": { + "smithy.api#documentation": "

The list of a key-value pair structure that contains extra parameters that can be applied when the image is generated. The FormatConfig key is the JPEGQuality, which indicates the JPEG quality key to be used to generate the image.\n The FormatConfig value accepts ints from 1 to 100. If the value is 1, the image will be generated with less quality and the best compression. \n If the value is 100, the image will be generated with the best quality and less compression. If no value is provided, the default value of the JPEGQuality key will be set to 80.

" + } + }, + "WidthPixels": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#WidthPixels", + "traits": { + "smithy.api#documentation": "

The width of the output image that is used in conjunction with the HeightPixels parameter. When both WidthPixels and HeightPixels parameters are provided, \n the image will be stretched to fit the specified aspect ratio. If only the WidthPixels parameter is provided or if only the HeightPixels is provided, a ValidationException will be thrown. \n If neither parameter is provided, the original image size from the stream will be returned.

" + } + }, + "HeightPixels": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#HeightPixels", + "traits": { + "smithy.api#documentation": "

The height of the output image that is used in conjunction with the WidthPixels parameter. When both HeightPixels and WidthPixels parameters are provided, the image will be stretched to fit the \n specified aspect ratio. If only the HeightPixels parameter is provided, its original aspect ratio will be used to calculate the WidthPixels ratio. If neither parameter is provided, \n the original image size will be returned.

" + } + }, + "MaxResults": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#GetImagesMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of images to be returned by the API.

\n \n

The default limit is 100 images per API response. The additional results will be paginated.

\n
" + } + }, + "NextToken": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#NextToken", + "traits": { + "smithy.api#documentation": "

A token that specifies where to start paginating the next set of Images. This is the GetImages:NextToken from a previously truncated response.

" + } + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#GetImagesMaxResults": { + "type": "long", + "traits": { + "smithy.api#box": {}, + "smithy.api#range": { + "min": 1, + "max": 100 + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#GetImagesOutput": { + "type": "structure", + "members": { + "Images": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Images", + "traits": { + "smithy.api#documentation": "

The list of images generated from the video stream. If there is no media available for the given timestamp, the NO_MEDIA error will be listed in the output. \n If an error occurs while the image is being generated, the MEDIA_ERROR will be listed in the output as the cause of the missing image.

" + } + }, + "NextToken": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#NextToken", + "traits": { + "smithy.api#documentation": "

The encrypted token that was used in the request to get more images.

" + } + } + } + }, "com.amazonaws.kinesisvideoarchivedmedia#GetMediaForFragmentList": { "type": "operation", "input": { @@ -899,6 +1093,87 @@ "smithy.api#documentation": "

The start and end of the timestamp range for the requested media.

\n

This value should not be present if PlaybackType is\n LIVE.

" } }, + "com.amazonaws.kinesisvideoarchivedmedia#HeightPixels": { + "type": "integer", + "traits": { + "smithy.api#box": {}, + "smithy.api#range": { + "min": 1, + "max": 2160 + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#Image": { + "type": "structure", + "members": { + "TimeStamp": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Timestamp", + "traits": { + "smithy.api#documentation": "

An attribute of the Image object that is used to extract an image from the video stream. This field is used to manage gaps on images or to better understand the pagination\n window.

" + } + }, + "Error": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ImageError", + "traits": { + "smithy.api#documentation": "

The error message shown when the image for the provided timestamp was not extracted due to a non-tryable error. An error will be returned if:

\n
    \n
  • \n

    There is no media that exists for the specified Timestamp.

    \n
  • \n
\n
    \n
  • \n

    The media for the specified time does not allow an image to be extracted. In this case the media is audio only, or the incorrect\n media has been ingested.

    \n
  • \n
" + } + }, + "ImageContent": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#ImageContent", + "traits": { + "smithy.api#documentation": "

An attribute of the Image object that is Base64 encoded.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

A structure that contains the Timestamp, Error, and ImageContent.

" + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#ImageContent": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 6291456 + } + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#ImageError": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "NO_MEDIA", + "name": "NO_MEDIA" + }, + { + "value": "MEDIA_ERROR", + "name": "MEDIA_ERROR" + } + ] + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#ImageSelectorType": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "PRODUCER_TIMESTAMP", + "name": "PRODUCER_TIMESTAMP" + }, + { + "value": "SERVER_TIMESTAMP", + "name": "SERVER_TIMESTAMP" + } + ] + } + }, + "com.amazonaws.kinesisvideoarchivedmedia#Images": { + "type": "list", + "member": { + "target": "com.amazonaws.kinesisvideoarchivedmedia#Image" + } + }, "com.amazonaws.kinesisvideoarchivedmedia#InvalidArgumentException": { "type": "structure", "members": { @@ -1054,7 +1329,7 @@ "min": 1, "max": 4096 }, - "smithy.api#pattern": "[a-zA-Z0-9+/]+={0,2}" + "smithy.api#pattern": "^[a-zA-Z0-9+/]+={0,2}$" } }, "com.amazonaws.kinesisvideoarchivedmedia#NoDataRetentionException": { @@ -1096,7 +1371,7 @@ "min": 1, "max": 1024 }, - "smithy.api#pattern": "arn:[a-z\\d-]+:kinesisvideo:[a-z0-9-]+:[0-9]+:[a-z]+/[a-zA-Z0-9_.-]+/[0-9]+" + "smithy.api#pattern": "^arn:[a-z\\d-]+:kinesisvideo:[a-z0-9-]+:[0-9]+:[a-z]+/[a-zA-Z0-9_.-]+/[0-9]+$" } }, "com.amazonaws.kinesisvideoarchivedmedia#ResourceNotFoundException": { @@ -1112,6 +1387,16 @@ "smithy.api#httpError": 404 } }, + "com.amazonaws.kinesisvideoarchivedmedia#SamplingInterval": { + "type": "integer", + "traits": { + "smithy.api#box": {}, + "smithy.api#range": { + "min": 3000, + "max": 20000 + } + } + }, "com.amazonaws.kinesisvideoarchivedmedia#StreamName": { "type": "string", "traits": { @@ -1119,7 +1404,7 @@ "min": 1, "max": 256 }, - "smithy.api#pattern": "[a-zA-Z0-9_.-]+" + "smithy.api#pattern": "^[a-zA-Z0-9_.-]+$" } }, "com.amazonaws.kinesisvideoarchivedmedia#Timestamp": { @@ -1159,6 +1444,16 @@ "smithy.api#error": "client", "smithy.api#httpError": 400 } + }, + "com.amazonaws.kinesisvideoarchivedmedia#WidthPixels": { + "type": "integer", + "traits": { + "smithy.api#box": {}, + "smithy.api#range": { + "min": 1, + "max": 3840 + } + } } } }