// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.video.livestream.v1;

import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/type/datetime.proto";

option csharp_namespace = "Google.Cloud.Video.LiveStream.V1";
option go_package = "cloud.google.com/go/video/livestream/apiv1/livestreampb;livestreampb";
option java_multiple_files = true;
option java_outer_classname = "OutputsProto";
option java_package = "com.google.cloud.video.livestream.v1";
option php_namespace = "Google\\Cloud\\Video\\LiveStream\\V1";
option ruby_package = "Google::Cloud::Video::LiveStream::V1";

// Encoding of an input element such as an audio, video, or text track.
// Elementary streams must be packaged before mapping and sharing between
// different output formats.
message ElementaryStream {
  // A unique key for this elementary stream. The key must be 1-63
  // characters in length. The key must begin and end with a letter (regardless
  // of case) or a number, but can contain dashes or underscores in between.
  string key = 4;

  // Required. Encoding of an audio, video, or text track.
  oneof elementary_stream {
    // Encoding of a video stream.
    VideoStream video_stream = 1;

    // Encoding of an audio stream.
    AudioStream audio_stream = 2;

    // Encoding of a text stream. For example, closed captions or subtitles.
    TextStream text_stream = 3;
  }
}

// Multiplexing settings for output stream.
message MuxStream {
  // A unique key for this multiplexed stream. The key must be 1-63
  // characters in length. The key must begin and end with a letter (regardless
  // of case) or a number, but can contain dashes or underscores in between.
  string key = 1;

  // The container format. The default is `fmp4`.
  //
  // Supported container formats:
  //
  // - `fmp4` - the corresponding file extension is `.m4s`
  // - `ts` - the corresponding file extension is `.ts`
  string container = 3;

  // List of `ElementaryStream`
  // [key][google.cloud.video.livestream.v1.ElementaryStream.key]s multiplexed
  // in this stream.
  //
  // - For `fmp4` container, must contain either one video or one audio stream.
  // - For `ts` container, must contain exactly one audio stream and up to one
  // video stream.
  repeated string elementary_streams = 4;

  // Segment settings for `fmp4` and `ts`.
  SegmentSettings segment_settings = 5;

  // Identifier of the encryption configuration to use. If omitted, output
  // will be unencrypted.
  string encryption_id = 6;
}

// Manifest configuration.
message Manifest {
  // The manifest type can be either `HLS` or `DASH`.
  enum ManifestType {
    // The manifest type is not specified.
    MANIFEST_TYPE_UNSPECIFIED = 0;

    // Create an `HLS` manifest. The corresponding file extension is `.m3u8`.
    HLS = 1;

    // Create a `DASH` manifest. The corresponding file extension is `.mpd`.
    DASH = 2;
  }

  // The name of the generated file. The default is `manifest` with the
  // extension suffix corresponding to the `Manifest`
  // [type][google.cloud.video.livestream.v1.Manifest.type]. If multiple
  // manifests are added to the channel, each must have a unique file name.
  string file_name = 1;

  // Required. Type of the manifest, can be `HLS` or `DASH`.
  ManifestType type = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. List of `MuxStream`
  // [key][google.cloud.video.livestream.v1.MuxStream.key]s that should appear
  // in this manifest.
  //
  // - For HLS, either `fmp4` or `ts` mux streams can be specified but not
  // mixed.
  // - For DASH, only `fmp4` mux streams can be specified.
  repeated string mux_streams = 3 [(google.api.field_behavior) = REQUIRED];

  // Maximum number of segments that this manifest holds. Once the manifest
  // reaches this maximum number of segments, whenever a new segment is added to
  // the manifest, the oldest segment will be removed from the manifest.
  // The minimum value is 3 and the default value is 5.
  int32 max_segment_count = 4;

  // How long to keep a segment on the output Google Cloud Storage bucket after
  // it is removed from the manifest. This field should be large enough to cover
  // the manifest propagation delay. Otherwise, a player could receive 404
  // errors while accessing segments which are listed in the manifest that the
  // player has, but were already deleted from the output Google Cloud Storage
  // bucket. Default value is `60s`.
  //
  // If both segment_keep_duration and
  // [RetentionConfig.retention_window_duration][google.cloud.video.livestream.v1.RetentionConfig.retention_window_duration]
  // are set,
  // [RetentionConfig.retention_window_duration][google.cloud.video.livestream.v1.RetentionConfig.retention_window_duration]
  // is used and segment_keep_duration is ignored.
  google.protobuf.Duration segment_keep_duration = 5;

  // Whether to use the timecode, as specified in timecode config, when setting:
  //
  // - `availabilityStartTime` attribute in DASH manifests.
  // - `#EXT-X-PROGRAM-DATE-TIME` tag in HLS manifests.
  //
  // If false, ignore the input timecode and use the time from system clock
  // when the manifest is first generated. This is the default behavior.
  bool use_timecode_as_timeline = 6;

  // Optional. A unique key for this manifest.
  string key = 7 [(google.api.field_behavior) = OPTIONAL];
}

// Sprite sheet configuration.
message SpriteSheet {
  // Format type. The default is `jpeg`.
  //
  // Supported formats:
  //
  // - `jpeg`
  string format = 1;

  // Required. File name prefix for the generated sprite sheets. If multiple
  // sprite sheets are added to the channel, each must have a unique file
  // prefix.
  // Each sprite sheet has an incremental 10-digit zero-padded suffix starting
  // from 0 before the extension, such as `sprite_sheet0000000123.jpeg`.
  string file_prefix = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The width of the sprite in pixels. Must be an even integer.
  int32 sprite_width_pixels = 3 [(google.api.field_behavior) = REQUIRED];

  // Required. The height of the sprite in pixels. Must be an even integer.
  int32 sprite_height_pixels = 4 [(google.api.field_behavior) = REQUIRED];

  // The maximum number of sprites per row in a sprite sheet. Valid range is
  // [1, 10] and the default value is 1.
  int32 column_count = 5;

  // The maximum number of rows per sprite sheet. When the sprite sheet is full,
  // a new sprite sheet is created. Valid range is [1, 10] and the default value
  // is 1.
  int32 row_count = 6;

  // Create sprites at regular intervals. Valid range is [1 second, 1 hour] and
  // the default value is `10s`.
  google.protobuf.Duration interval = 7;

  // The quality of the generated sprite sheet. Enter a value between 1
  // and 100, where 1 is the lowest quality and 100 is the highest quality.
  // The default is 100. A high quality value corresponds to a low image data
  // compression ratio.
  int32 quality = 8;
}

// Preprocessing configurations.
message PreprocessingConfig {
  // Audio preprocessing configuration.
  message Audio {
    // Specify audio loudness normalization in loudness units relative to full
    // scale (LUFS). Enter a value between -24 and 0 according to the following:
    //
    // - -24 is the Advanced Television Systems Committee (ATSC A/85)
    // - -23 is the EU R128 broadcast standard
    // - -19 is the prior standard for online mono audio
    // - -18 is the ReplayGain standard
    // - -16 is the prior standard for stereo audio
    // - -14 is the new online audio standard recommended by Spotify, as well as
    // Amazon Echo
    // - 0 disables normalization. The default is 0.
    double lufs = 1;
  }

  // Video cropping configuration for the input video. The cropped input video
  // is scaled to match the output resolution.
  message Crop {
    // The number of pixels to crop from the top. The default is 0.
    int32 top_pixels = 1;

    // The number of pixels to crop from the bottom. The default is 0.
    int32 bottom_pixels = 2;

    // The number of pixels to crop from the left. The default is 0.
    int32 left_pixels = 3;

    // The number of pixels to crop from the right. The default is 0.
    int32 right_pixels = 4;
  }

  // Pad filter configuration for the input video. The padded input video
  // is scaled after padding with black to match the output resolution.
  message Pad {
    // The number of pixels to add to the top. The default is 0.
    int32 top_pixels = 1;

    // The number of pixels to add to the bottom. The default is 0.
    int32 bottom_pixels = 2;

    // The number of pixels to add to the left. The default is 0.
    int32 left_pixels = 3;

    // The number of pixels to add to the right. The default is 0.
    int32 right_pixels = 4;
  }

  // Audio preprocessing configuration.
  Audio audio = 1;

  // Specify the video cropping configuration.
  Crop crop = 2;

  // Specify the video pad filter configuration.
  Pad pad = 3;
}

// Video stream resource.
message VideoStream {
  // H264 codec settings.
  message H264CodecSettings {
    // Required. The width of the video in pixels. Must be an even integer.
    // Valid range is [320, 1920].
    int32 width_pixels = 1;

    // Required. The height of the video in pixels. Must be an even integer.
    // Valid range is [180, 1080].
    int32 height_pixels = 2;

    // Required. The target video frame rate in frames per second (FPS). Must be
    // less than or equal to 60. Will default to the input frame rate if larger
    // than the input frame rate. The API will generate an output FPS that is
    // divisible by the input FPS, and smaller or equal to the target FPS. See
    // [Calculating frame
    // rate](https://cloud.google.com/transcoder/docs/concepts/frame-rate) for
    // more information.
    double frame_rate = 3 [(google.api.field_behavior) = REQUIRED];

    // Required. The video bitrate in bits per second. Minimum value is 10,000.
    //
    // - For SD resolution (< 720p), must be <= 3,000,000 (3 Mbps).
    // - For HD resolution (<= 1080p), must be <= 15,000,000 (15 Mbps).
    int32 bitrate_bps = 4 [(google.api.field_behavior) = REQUIRED];

    // Specifies whether an open Group of Pictures (GOP) structure should be
    // allowed or not. The default is `false`.
    bool allow_open_gop = 6;

    // GOP mode can be either by frame count or duration.
    oneof gop_mode {
      // Select the GOP size based on the specified frame count.
      // If GOP frame count is set instead of GOP duration, GOP duration will be
      // calculated by `gopFrameCount`/`frameRate`. The calculated GOP duration
      // must satisfy the limitations on `gopDuration` as well.
      // Valid range is [60, 600].
      int32 gop_frame_count = 7;

      // Select the GOP size based on the specified duration. The default is
      // `2s`. Note that `gopDuration` must be less than or equal to
      // [segment_duration][google.cloud.video.livestream.v1.SegmentSettings.segment_duration],
      // and
      // [segment_duration][google.cloud.video.livestream.v1.SegmentSettings.segment_duration]
      // must be divisible by `gopDuration`. Valid range is [2s, 20s].
      //
      // All video streams in the same channel must have the same GOP size.
      google.protobuf.Duration gop_duration = 8;
    }

    // Size of the Video Buffering Verifier (VBV) buffer in bits. Must be
    // greater than zero. The default is equal to
    // [bitrate_bps][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings.bitrate_bps].
    int32 vbv_size_bits = 9;

    // Initial fullness of the Video Buffering Verifier (VBV) buffer in bits.
    // Must be greater than zero. The default is equal to 90% of
    // [vbv_size_bits][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings.vbv_size_bits].
    int32 vbv_fullness_bits = 10;

    // The entropy coder to use. The default is `cabac`.
    //
    // Supported entropy coders:
    //
    // - `cavlc`
    // - `cabac`
    string entropy_coder = 11;

    // Allow B-pyramid for reference frame selection. This may not be supported
    // on all decoders. The default is `false`.
    bool b_pyramid = 12;

    // The number of consecutive B-frames. Must be greater than or equal to
    // zero. Must be less than
    // [gop_frame_count][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings.gop_frame_count]
    // if set. The default is 0.
    int32 b_frame_count = 13;

    // Specify the intensity of the adaptive quantizer (AQ). Must be between 0
    // and 1, where 0 disables the quantizer and 1 maximizes the quantizer. A
    // higher value equals a lower bitrate but smoother image. The default is 0.
    double aq_strength = 14;

    // Enforces the specified codec profile. The following profiles are
    // supported:
    //
    // *   `baseline`
    // *   `main` (default)
    // *   `high`
    //
    // The available options are [FFmpeg-compatible Profile
    // Options](https://trac.ffmpeg.org/wiki/Encode/H.264#Profile).
    // Note that certain values for this field may cause the
    // transcoder to override other fields you set in the
    // [H264CodecSettings][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings]
    // message.
    string profile = 15;

    // Enforces the specified codec tune. The available options are
    // [FFmpeg-compatible Encode
    // Options](https://trac.ffmpeg.org/wiki/Encode/H.264#Tune)
    // Note that certain values for this field may cause the transcoder to
    // override other fields you set in the
    // [H264CodecSettings][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings]
    // message.
    string tune = 16;
  }

  // Codec settings.
  oneof codec_settings {
    // H264 codec settings.
    H264CodecSettings h264 = 20;
  }
}

// Audio stream resource.
message AudioStream {
  // The mapping for the input streams and audio channels.
  message AudioMapping {
    // Required. The `Channel`
    // [InputAttachment.key][google.cloud.video.livestream.v1.InputAttachment.key]
    // that identifies the input that this audio mapping applies to. If an
    // active input doesn't have an audio mapping, the primary audio track in
    // the input stream will be selected.
    string input_key = 6 [(google.api.field_behavior) = REQUIRED];

    // Required. The zero-based index of the track in the input stream.
    // All [mapping][google.cloud.video.livestream.v1.AudioStream.mapping]s in
    // the same [AudioStream][google.cloud.video.livestream.v1.AudioStream] must
    // have the same input track.
    int32 input_track = 2 [(google.api.field_behavior) = REQUIRED];

    // Required. The zero-based index of the channel in the input stream.
    int32 input_channel = 3 [(google.api.field_behavior) = REQUIRED];

    // Required. The zero-based index of the channel in the output audio stream.
    // Must be consistent with the
    // [input_channel][google.cloud.video.livestream.v1.AudioStream.AudioMapping.input_channel].
    int32 output_channel = 4 [(google.api.field_behavior) = REQUIRED];

    // Audio volume control in dB. Negative values decrease volume,
    // positive values increase. The default is 0.
    double gain_db = 5;
  }

  // Specifies whether pass through (transmuxing) is enabled or not.
  // If set to `true`, the rest of the settings, other than `mapping`, will be
  // ignored. The default is `false`.
  bool transmux = 8;

  // The codec for this audio stream. The default is `aac`.
  //
  // Supported audio codecs:
  //
  // - `aac`
  string codec = 1;

  // Required. Audio bitrate in bits per second. Must be between 1 and
  // 10,000,000.
  int32 bitrate_bps = 2 [(google.api.field_behavior) = REQUIRED];

  // Number of audio channels. Must be between 1 and 6. The default is 2.
  int32 channel_count = 3;

  // A list of channel names specifying layout of the audio channels.
  // This only affects the metadata embedded in the container headers, if
  // supported by the specified format. The default is `[fl, fr]`.
  //
  // Supported channel names:
  //
  // - `fl` - Front left channel
  // - `fr` - Front right channel
  // - `sl` - Side left channel
  // - `sr` - Side right channel
  // - `fc` - Front center channel
  // - `lfe` - Low frequency
  repeated string channel_layout = 4;

  // The mapping for the input streams and audio channels.
  repeated AudioMapping mapping = 5;

  // The audio sample rate in Hertz. The default is 48000 Hertz.
  int32 sample_rate_hertz = 6;
}

// Encoding of a text stream. For example, closed captions or subtitles.
message TextStream {
  // Required. The codec for this text stream.
  //
  // Supported text codecs:
  //
  // - `cea608`
  // - `cea708`
  string codec = 1 [(google.api.field_behavior) = REQUIRED];
}

// Segment settings for `fmp4` and `ts`.
message SegmentSettings {
  // Duration of the segments in seconds. The default is `6s`. Note that
  // `segmentDuration` must be greater than or equal to
  // [gop_duration][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings.gop_duration],
  // and `segmentDuration` must be divisible by
  // [gop_duration][google.cloud.video.livestream.v1.VideoStream.H264CodecSettings.gop_duration].
  // Valid range is [2s, 20s].
  //
  // All [mux_streams][google.cloud.video.livestream.v1.Manifest.mux_streams] in
  // the same manifest must have the same segment duration.
  google.protobuf.Duration segment_duration = 1;
}

// Timecode configuration.
message TimecodeConfig {
  // The source of timecode.
  enum TimecodeSource {
    // The timecode source is not specified.
    TIMECODE_SOURCE_UNSPECIFIED = 0;

    // Use input media timestamp.
    MEDIA_TIMESTAMP = 1;

    // Use input embedded timecode e.g. picture timing SEI message.
    EMBEDDED_TIMECODE = 2;
  }

  // The source of the timecode that will later be used in outputs/manifests.
  // It determines the initial timecode/timestamp (first frame) of output
  // streams.
  TimecodeSource source = 1;

  // For EMBEDDED_TIMECODE source only.
  // Used to interpret the embedded timecode (which contains only the time part
  // and no date). We assume all inputs are live.
  oneof time_offset {
    // UTC offset. Must be whole seconds, between -18 hours and +18 hours.
    google.protobuf.Duration utc_offset = 2;

    // Time zone e.g. "America/Los_Angeles".
    google.type.TimeZone time_zone = 3;
  }
}
