import type { RobotMetaInput } from './_instructions-primitives.ts' import { z } from 'zod' import { stackVersions } from '../stackVersions.ts' import { interpolateRobot, robotBase, robotFFmpegVideo, robotUse, } from './_instructions-primitives.ts' export const meta: RobotMetaInput = { bytescount: Number.POSITIVE_INFINITY, discount_factor: 1, discount_pct: 0, example_code: { steps: { ':original': { robot: '/upload/handle', }, encoded_480p: { robot: '/video/encode', use: ':original', preset: 'hls/480p', ffmpeg_stack: stackVersions.ffmpeg.recommendedVersion, }, encoded_720p: { robot: '/video/encode', use: ':original', preset: 'hls/720p', ffmpeg_stack: stackVersions.ffmpeg.recommendedVersion, }, encoded_1080p: { robot: '/video/encode', use: ':original', preset: 'hls/1080p', ffmpeg_stack: stackVersions.ffmpeg.recommendedVersion, }, hls_bundled: { robot: '/video/adaptive', use: { steps: ['encoded_480p', 'encoded_720p', 'encoded_1080p'], bundle_steps: true, }, technique: 'hls', playlist_name: 'my_playlist.m3u8', }, }, }, example_code_description: 'Implementing HTTP Live Streaming: encode the uploaded video into three versions, then cut them into several segments and generate playlist files containing all the segments:', minimum_charge: 0, output_factor: 1.2, override_lvl1: 'Video Encoding', purpose_sentence: 'encodes videos into HTTP Live Streaming (HLS), MPEG-Dash and CMAF supported formats and generates the necessary manifest and playlist files', purpose_verb: 'convert', purpose_word: 'make adaptive', purpose_words: 'Convert videos to HLS, MPEG-Dash and CMAF', service_slug: 'video-encoding', slot_count: 60, title: 'Convert videos to HLS, MPEG-Dash and CMAF', typical_file_size_mb: 80, typical_file_type: 'video', name: 'VideoAdaptiveRobot', priceFactor: 1, queueSlotCount: 60, isAllowedForUrlTransform: false, trackOutputFileSize: true, isInternal: false, removeJobResultFilesFromDiskRightAfterStoringOnS3: false, stage: 'ga', } export const robotVideoAdaptiveInstructionsSchema = robotBase .merge(robotUse) .merge(robotFFmpegVideo) .extend({ robot: z.literal('/video/adaptive').describe(` This Robot accepts all types of video files and audio files. Do not forget to use Step bundling in your \`use\` parameter to make the Robot work on several input files at once. This Robot is normally used in combination with [🤖/video/encode](/docs/robots/video-encode/). We have implemented video and audio encoding presets specifically for MPEG-Dash and HTTP Live Streaming support. These presets are prefixed with \`"dash/"\` and \`"hls/"\`. [View a HTTP Live Streaming demo here](/demos/video-encoding/implement-http-live-streaming/). ### Required CORS settings for MPEG-Dash and HTTP Live Streaming Playing back MPEG-Dash Manifest or HLS playlist files requires a proper CORS setup on the server-side. The file-serving server should be configured to add the following header fields to responses: \`\`\` Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: * \`\`\` If the files are stored in an Amazon S3 Bucket, you can use the following [CORS definition](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ManageCorsUsing.html) to ensure the CORS header fields are set correctly: \`\`\`json [ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET"], "AllowedOrigins": ["*"], "ExposeHeaders": [] } ] \`\`\` To set up CORS for your S3 bucket: 1. Visit 1. Click on your bucket 1. Click "Permissions" 1. Edit "Cross-origin resource sharing (CORS)" ### Storing Segments and Playlist files The Robot gives its result files (segments, initialization segments, MPD manifest files and M3U8 playlist files) the right metadata property \`relative_path\`, so that you can store them easily using one of our storage Robots. In the \`path\` parameter of the storage Robot of your choice, use the Assembly Variable \`\${file.meta.relative_path}\` to store files in the proper paths to make the playlist files work. `), technique: z .enum(['dash', 'hls', 'cmaf']) .default('dash') .describe(` Determines which streaming technique should be used. Supports \`"dash"\` for MPEG-Dash, \`"hls"\` for HTTP Live Streaming and \`"cmaf"\` for FFmpeg-based CMAF output with both MPEG-Dash and HLS manifests that reference the same fMP4 segments. `), playlist_name: z .string() .optional() .describe(` The filename for the generated manifest/playlist file. The default is \`"playlist.mpd"\` if your \`technique\` is \`"dash"\`, and \`"playlist.m3u8"\` if your \`technique\` is \`"hls"\`. For \`"cmaf"\`, this value names the MPEG-Dash manifest and defaults to \`"playlist.mpd"\`. `), hls_playlist_name: z .string() .optional() .describe(` Only used when \`technique\` is \`"cmaf"\`. Defines the filename for the generated HLS master playlist. The default is \`"playlist.m3u8"\`. `), segment_duration: z .number() .int() .default(10) .describe(` The duration for each segment in seconds. `), closed_captions: z .boolean() .default(true) .describe(` Determines whether you want closed caption support when using the \`"hls"\` technique. `), audio_group: z .boolean() .default(false) .describe(` When set to \`true\` and using the \`"hls"\` technique, audio-only input files are treated as alternate audio renditions instead of standalone stream variants. This enables players to offer audio track selection (e.g. for multiple languages). Audio-only files are listed as \`#EXT-X-MEDIA:TYPE=AUDIO\` entries in the multivariant playlist, and video variants reference them via the \`AUDIO\` attribute. When enabled, video inputs only include their video stream in the output segments (any muxed audio is excluded). Provide audio separately as audio-only input files. This option is only supported for the \`"hls"\` technique and has no effect when using \`"dash"\`. `), }) .strict() export const robotVideoAdaptiveInstructionsWithHiddenFieldsSchema = robotVideoAdaptiveInstructionsSchema.extend({ result: z .union([z.literal('debug'), robotVideoAdaptiveInstructionsSchema.shape.result]) .optional(), }) export type RobotVideoAdaptiveInstructions = z.infer export type RobotVideoAdaptiveInstructionsWithHiddenFields = z.infer< typeof robotVideoAdaptiveInstructionsWithHiddenFieldsSchema > export const interpolatableRobotVideoAdaptiveInstructionsSchema = interpolateRobot( robotVideoAdaptiveInstructionsSchema, ) export type InterpolatableRobotVideoAdaptiveInstructions = InterpolatableRobotVideoAdaptiveInstructionsInput export type InterpolatableRobotVideoAdaptiveInstructionsInput = z.input< typeof interpolatableRobotVideoAdaptiveInstructionsSchema > export const interpolatableRobotVideoAdaptiveInstructionsWithHiddenFieldsSchema = interpolateRobot( robotVideoAdaptiveInstructionsWithHiddenFieldsSchema, ) export type InterpolatableRobotVideoAdaptiveInstructionsWithHiddenFields = z.infer< typeof interpolatableRobotVideoAdaptiveInstructionsWithHiddenFieldsSchema > export type InterpolatableRobotVideoAdaptiveInstructionsWithHiddenFieldsInput = z.input< typeof interpolatableRobotVideoAdaptiveInstructionsWithHiddenFieldsSchema >