Source: lib/msf/packaging/cmaf.js

/*! @license
 * Shaka Player
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

goog.provide('shaka.msf.packaging.Cmaf');

goog.require('shaka.log');
goog.require('shaka.media.InitSegmentReference');
goog.require('shaka.media.SegmentUtils');
goog.require('shaka.msf.PackagingRegistry');


/**
 * Packaging for CMAF tracks, where every MoQT object is one CMAF chunk.
 *
 * A chunk carries its own `moof`, so an object is self-describing: its timing
 * comes out of the chunk itself and it can be appended on its own. That makes
 * this the simplest packaging -- one object in, one segment out -- and the
 * lowest latency one, since nothing has to be accumulated.
 *
 * @see https://datatracker.ietf.org/doc/draft-ietf-moq-cmsf/
 *
 * @implements {shaka.extern.MsfPackaging}
 * @final
 */
shaka.msf.packaging.Cmaf = class {
  constructor() {
    /** @private {number} */
    this.timescale_ = 0;
  }

  /**
   * @override
   */
  describeTrack(track, initData) {
    const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
        initData, initData, /* disableText= */ false);
    if (!basicInfo) {
      return null;
    }

    const timescale = basicInfo.timescale || track.timescale;
    if (!timescale) {
      shaka.log.info(
          'Skipping incompatible track due missing timescale', track);
      return null;
    }
    this.timescale_ = timescale;

    return {
      basicInfo,
      initSegmentReference: new shaka.media.InitSegmentReference(
          () => [],
          /* startBytes= */ 0,
          /* endBytes= */ null,
          /* mediaQuality= */ null,
          timescale,
          initData),
    };
  }

  /**
   * @override
   */
  createSegmenter() {
    return new shaka.msf.packaging.CmafSegmenter(this.timescale_);
  }
};


/**
 * @implements {shaka.extern.MsfSegmenter}
 * @final
 */
shaka.msf.packaging.CmafSegmenter = class {
  /**
   * @param {number} timescale
   */
  constructor(timescale) {
    /** @private {number} */
    this.timescale_ = timescale;
  }

  /**
   * @override
   */
  push(obj) {
    if (!obj.data.byteLength) {
      return [];
    }

    const info = shaka.media.SegmentUtils.getStartTimeAndDurationFromMp4(
        obj.data, this.timescale_);
    if (!info.duration) {
      return [];
    }

    return [{
      startTime: info.startTime,
      duration: info.duration,
      data: obj.data,
      timestampOffset: 0,
      discontinuitySequence: -1,
    }];
  }
};


shaka.msf.PackagingRegistry.registerPackaging(
    'cmaf', () => new shaka.msf.packaging.Cmaf());

shaka.msf.PackagingRegistry.registerPackaging(
    'chunk-per-object', () => new shaka.msf.packaging.Cmaf());