NorskOutput.cmafVideo() method

Produces video segments with the supplied settings for use in HLS or DASH manifests.

These can optionally be served the Norsk web server or be pushed to other locations - see CmafDestinationSettings

Signature:

cmafVideo(settings: CmafOutputSettings): Promise<CmafVideoOutputNode>;

Parameters

Parameter Type Description

settings

CmafOutputSettings

Configuration for the CMAF Video Stream

Returns:

Example [20_cmaf_pull_push.ts]

TODO

export async function main() {
  runWebServer(port);

  const norsk = await Norsk.connect();

  const input = await norsk.input.rtmpServer({ id: "rtmpInput" });

  const destinations: CmafDestinationSettings[] = [
    { type: "local", retentionPeriodSeconds: 60, id: "local" },
    { type: "generic", id: "genericPullPush", host: "localhost", port, pathPrefix: "/push/", retentionPeriodSeconds: 60 }
  ]

  const audioOutput = await norsk.output.cmafAudio({ id: "audio", destinations, ...segmentSettings });
  const videoOutput = await norsk.output.cmafVideo({ id: "video", destinations, ...segmentSettings });
  const masterOutput = await norsk.output.cmafMultiVariant({ id: "multi-variant", playlistName: "multi-variant", destinations });

  audioOutput.subscribe([{ source: input, sourceSelector: selectAudio }]);
  videoOutput.subscribe([{ source: input, sourceSelector: selectVideo }]);
  masterOutput.subscribe([
    { source: audioOutput, sourceSelector: selectPlaylist },
    { source: videoOutput, sourceSelector: selectPlaylist }
  ]);

  console.log(`Master playlist: ${masterOutput.url}`);
  audioOutput.url().then(logMediaPlaylist("audio"));
  videoOutput.url().then(logMediaPlaylist("video"));

}

Run the following command to generate example input at url rtmp://127.0.0.1:1935/acme/high:

ffmpeg -v error -re -stream_loop -1 -i data/InkDrop.ts  -vcodec copy -codec copy -f flv 'rtmp://127.0.0.1:1935/acme/high'

Example [27_playlist_manipulation.ts]

Manipulate an HLS playlist

export async function main() {
  const port = 3210;
  runWebServer(port, { logPlaylists: true });

  const norsk = await Norsk.connect();

  const input = await norsk.input.rtmpServer({ id: "rtmpInput" });

  const localDestination: CmafDestinationSettings = { type: "local", retentionPeriodSeconds: 10, id: "local" };
  const pushDestination: CmafDestinationSettings = { type: "generic", id: "gen", host: "localhost", port, pathPrefix: "/push/", retentionPeriodSeconds: 60 }
  const destinations: CmafDestinationSettings[] = [
    localDestination,
    pushDestination
  ]

  const segmentSettings = {
    partDurationSeconds: 2.0,
    segmentDurationSeconds: 2.0,
  };

  const audioOutput = await norsk.output.cmafAudio({ id: "audio", destinations, ...segmentSettings });
  const videoOutput = await norsk.output.cmafVideo({ id: "video", destinations, ...segmentSettings });
  const masterOutput = await norsk.output.cmafMultiVariant({ id: "multi-variant", playlistName: "multi-variant", destinations });

  const emptyHlsPlaylist: () => HlsPlaylist = () => {
    return {
      hlsStandardPlaylist: [],
      hlsByteRangePlaylist: [],
      hlsFilePartPlaylist: [],
    }
  }

  const audioPlaylistLocal: HlsPlaylist = emptyHlsPlaylist();
  const audioPlaylistPush: HlsPlaylist = emptyHlsPlaylist();

  audioOutput.onPlaylistAddition = (destinationId: DestinationId, playlistAdditions: HlsPlaylistAdditions): HlsPlaylist => {
    if (destinationId == localDestination.id) {
      audioPlaylistLocal.hlsFilePartPlaylist.push(...playlistAdditions.hlsFilePartPlaylist);
      return audioPlaylistLocal;
    } else {
      audioPlaylistPush.hlsStandardPlaylist.push(...playlistAdditions.hlsStandardPlaylist, { tag: "# Additional comment line for audio push" });
      return audioPlaylistPush;
    }
  }

  const videoPlaylistLocal: HlsPlaylist = emptyHlsPlaylist();
  const videoPlaylistPush: HlsPlaylist = emptyHlsPlaylist();

  videoOutput.onPlaylistAddition = (destinationId: DestinationId, playlistAdditions: HlsPlaylistAdditions): HlsPlaylist => {
    if (destinationId == localDestination.id) {
      videoPlaylistLocal.hlsStandardPlaylist.push(...playlistAdditions.hlsStandardPlaylist);
      videoPlaylistLocal.hlsFilePartPlaylist.push(...playlistAdditions.hlsFilePartPlaylist);
      videoPlaylistLocal.hlsByteRangePlaylist.push(...playlistAdditions.hlsByteRangePlaylist);
      return videoPlaylistLocal;
    } else {
      videoPlaylistPush.hlsStandardPlaylist.push(...playlistAdditions.hlsStandardPlaylist, { tag: "# Additional comment line for video push" });
      return videoPlaylistPush;
    }
  }

  audioOutput.subscribe([{ source: input, sourceSelector: selectAudio }]);
  videoOutput.subscribe([{ source: input, sourceSelector: selectVideo }]);
  masterOutput.subscribe([
    { source: audioOutput, sourceSelector: selectPlaylist },
    { source: videoOutput, sourceSelector: selectPlaylist }
  ]);

  console.log(`Master playlist: ${masterOutput.url}`);
  audioOutput.url().then(logMediaPlaylist("audio"));
  videoOutput.url().then(logMediaPlaylist("video"));
}

Run the following command to generate example input at url rtmp://127.0.0.1:1935/acme/high:

ffmpeg -v error -re -stream_loop -1 -i data/InkDrop.ts  -vcodec copy -codec copy -f flv 'rtmp://127.0.0.1:1935/acme/high'

Find Examples