{
  "id": "osc-stack-media-transcode-package",
  "job": "Turn a source video file into the renditions a player needs, then package the output as DASH and HLS, without hand-wiring transcoding and packaging together.",
  "aliases": [
    "video transcoding pipeline",
    "encore packaging automation",
    "vod transcode and package",
    "media file to adaptive bitrate output"
  ],
  "inputs": [
    {
      "protocol": "file",
      "source": "a source video file in S3-compatible storage, submitted to Encore as a transcode job"
    }
  ],
  "outputs": [
    {
      "protocol": "DASH/HLS",
      "packager": "produced by eyevinn-encore-packager reading a packaging queue in your own Valkey instance, which eyevinn-encore-callback-listener fills when Encore reports a job as done, or by eyevinn-shaka-packager-s3 when the source is already-segmented media rather than a fresh Encore job",
      "renditions": "set by the transcoding profile supplied to Encore; no default ladder is imposed by this stack the way the live-encoding stack has one",
      "renditionsAreDefaultLadder": false
    }
  ],
  "recommendedPath": {
    "chain": [
      {
        "step": 1,
        "serviceId": "encore",
        "role": "transcode",
        "requiredConfig": ["name"],
        "requiresCredential": false,
        "note": "profilesUrl and the S3 credential fields are optional at create time; a profile must still be supplied per transcode job. Each job must also set progressCallbackUri to the callback listener from step 3 (its URL plus /encoreCallback), or nothing is ever packaged. Encore keeps its own Redis internally; that Redis is not part of this chain and is never shared with the packager."
      },
      {
        "step": 2,
        "serviceId": "valkey-io-valkey",
        "role": "packaging queue",
        "requiredConfig": ["name"],
        "requiresCredential": false,
        "note": "your own Valkey instance holds the queue between steps 3 and 4. Password is optional on its schema. Both the callback listener and the packager declare RedisUrl as an association to valkey-io-valkey, so the same instance URL goes into both."
      },
      {
        "step": 3,
        "serviceId": "eyevinn-encore-callback-listener",
        "role": "turn Encore's completion callback into a packaging job",
        "requiredConfig": ["name", "RedisUrl", "EncoreUrl"],
        "requiresCredential": true,
        "fieldMapping": {
          "RedisUrl": "the Valkey instance URL from step 2 (sensitive field)",
          "EncoreUrl": "the Encore instance URL from step 1",
          "RedisQueue": "optional; defaults to packaging-queue in the upstream source and must match the packager's RedisQueue in step 4"
        },
        "imageChannel": "beta",
        "note": "an HTTP server that receives Encore's progress callbacks on POST /encoreCallback; when a job reports SUCCESSFUL it posts the jobId and job URL onto the queue in step 2. Its only catalog image is on the beta channel (read live 2026-10-23), unlike the packager, which runs a stable image."
      },
      {
        "step": 4,
        "serviceId": "eyevinn-encore-packager",
        "role": "package",
        "requiredConfig": [
          "name",
          "RedisUrl",
          "OutputFolder",
          "PersonalAccessToken",
          "AwsAccessKeyId",
          "AwsSecretAccessKey"
        ],
        "requiresCredential": true,
        "fieldMapping": {
          "RedisUrl": "the same Valkey instance URL as step 2",
          "RedisQueue": "optional; must match the callback listener's queue name (upstream default packaging-queue on both)",
          "PersonalAccessToken": "an OSC access token, so the packager can read the Encore job in OSC"
        },
        "note": "listens on the packaging queue in your Valkey instance (step 2), which the callback listener (step 3) fills, then fetches the finished Encore job and packages its output to DASH and HLS. Needs S3-compatible output storage as a separate service instance: set S3EndpointUrl to your minio-minio instance, because if it is left empty the output goes to AWS S3 by default."
      }
    ],
    "alternativePath": {
      "serviceId": "eyevinn-shaka-packager-s3",
      "role": "package, for already-segmented S3 source media rather than a fresh Encore job",
      "requiredConfig": ["name", "cmdLineArgs"],
      "requiresCredential": false
    },
    "optionalIndexStep": {
      "serviceId": "eyevinn-tams-gateway",
      "role": "index the packaged output so it can be searched and referenced once the library grows past a handful of assets",
      "requiredConfig": [
        "name",
        "DbUrl",
        "DbUsername",
        "DbPassword",
        "AwsAccessKeyId",
        "AwsSecretAccessKey",
        "S3Bucket"
      ],
      "requiresCredential": true,
      "note": "no MAM service exists in the OSC catalog as such (re-verified live 2026-09-20); this is the honest hook for the MAM-adjacent story, not a MAM product."
    },
    "tokensPerDay": null,
    "tokensPerDayMeasured": false,
    "measuredWallClockSeconds": null,
    "wallClockMeasured": false,
    "gapNote": "Unlike the live-streaming stack (386s, measured), this pipeline has not had an author's own end-to-end run timed or costed yet. No number is invented here; this is a named gap, not a filled-in figure.",
    "agentFoundServiceUnaided": null
  },
  "configSurface": {
    "servicesInChain": 4,
    "totalRequiredFieldsAcrossChain": 11,
    "sensitiveFields": [
      "PersonalAccessToken",
      "AwsSecretAccessKey",
      "s3SecretAccessKey",
      "AwsAccessKeyId",
      "RedisUrl"
    ],
    "note": "Four services must be wired together: Encore calls the callback listener over HTTP, the listener writes a queue in your own Valkey, and the packager reads that queue and writes to shared S3-compatible output storage. This is longer than the single-service live-streaming stack."
  },
  "setup": {
    "codeRequired": false,
    "knownDeployGotcha": "Deploy Valkey and S3-compatible storage first, then the callback listener and the packager pointed at the same Valkey URL and queue name. Without the callback listener, Encore transcodes but nothing ever reaches the packager. The listener's image is on the beta channel."
  },
  "cost": {
    "unit": "tokens/day",
    "ceiling": null,
    "ceilingMeasured": false,
    "note": "Not costed as a named stack yet, per the P5 CEO decision that a stack states its required tier up front once that measurement exists. This is a named gap for the next author to close, not an invented figure."
  },
  "servicesVerifiedLive": {
    "date": "2026-10-23",
    "method": "osc_call_tool wrap (mcp__osc__osc_call_tool with name=get-service-schema / name=list-service-categories) on encore, valkey-io-valkey, eyevinn-encore-callback-listener, eyevinn-encore-packager, eyevinn-shaka-packager-s3, eyevinn-tams-gateway; queue wiring read from the Eyevinn/encore-callback-listener and Eyevinn/encore-packager source and READMEs",
    "catalogTotal": 198,
    "mediaCategory": 66
  },
  "gateCheck": {
    "gatedServiceId": "eyevinn-just-go-live",
    "usesGatedService": false,
    "note": "This stack does not name or link eyevinn-just-go-live; the P3 gate does not bind it."
  },
  "verifiedOn": "2026-10-23",
  "publishedAt": "https://www.osaas.io/use-cases/vod-transcoding",
  "descriptorUrl": "https://www.osaas.io/stacks/media-transcode-package.json"
}
