createFrame_(elem, parent, getBaseUris) {
    goog.asserts.assert(parent || getBaseUris,
        'Must provide either parent or getBaseUris');
    const SegmentUtils = shaka.media.SegmentUtils;
    const ManifestParserUtils = shaka.util.ManifestParserUtils;
    const TXml = shaka.util.TXml;
    parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
      contentType: '',
      mimeType: '',
      codecs: '',
      emsgSchemeIdUris: [],
      frameRate: undefined,
      pixelAspectRatio: undefined,
      numChannels: null,
      audioSamplingRate: null,
      availabilityTimeOffset: 0,
      segmentSequenceCadence: 0,
      encrypted: false,
    });
    getBaseUris = getBaseUris || parent.getBaseUris;

    const parseNumber = TXml.parseNonNegativeInt;
    const evalDivision = TXml.evalDivision;

    const id = elem.attributes['id'];
    const supplementalId = elem.attributes['supplementalId'];
    const uriObjs = TXml.findChildren(elem, 'BaseURL');
    let calculatedBaseUris;
    let someLocationValid = false;
    if (this.contentSteeringManager_) {
      for (const uriObj of uriObjs) {
        const serviceLocation = uriObj.attributes['serviceLocation'];
        const uri = TXml.getContents(uriObj);
        if (serviceLocation && uri) {
          this.contentSteeringManager_.addLocation(
              id, serviceLocation, uri);
          someLocationValid = true;
        }
      }
    }
    if (!someLocationValid || !this.contentSteeringManager_) {
      calculatedBaseUris = uriObjs.map(TXml.getContents);
    }

    const getFrameUris = () => {
      if (!uriObjs.length) {
        return [];
      }
      if (this.contentSteeringManager_ && someLocationValid) {
        return this.contentSteeringManager_.getLocations(id);
      }
      if (calculatedBaseUris) {
        return calculatedBaseUris;
      }
      return [];
    };

    let contentType = elem.attributes['contentType'] || parent.contentType;
    const mimeType = elem.attributes['mimeType'] || parent.mimeType;
    const allCodecs = [
      elem.attributes['codecs'] || parent.codecs,
    ];
    const codecs = SegmentUtils.codecsFiltering(allCodecs).join(',');
    const frameRate =
        TXml.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
    const pixelAspectRatio =
        elem.attributes['sar'] || parent.pixelAspectRatio;
    const emsgSchemeIdUris = this.emsgSchemeIdUris_(
        TXml.findChildren(elem, 'InbandEventStream'),
        parent.emsgSchemeIdUris);
    const audioChannelConfigs =
        TXml.findChildren(elem, 'AudioChannelConfiguration');
    const numChannels =
        this.parseAudioChannels_(audioChannelConfigs) || parent.numChannels;
    const audioSamplingRate =
        TXml.parseAttr(elem, 'audioSamplingRate', parseNumber) ||
        parent.audioSamplingRate;

    if (!contentType) {
      contentType = shaka.dash.DashParser.guessContentType_(mimeType, codecs);
    }

    const segmentBase = TXml.findChild(elem, 'SegmentBase');
    const segmentTemplate = TXml.findChild(elem, 'SegmentTemplate');

    // The availabilityTimeOffset is the sum of all @availabilityTimeOffset
    // values that apply to the adaptation set, via BaseURL, SegmentBase,
    // or SegmentTemplate elements.
    const segmentBaseAto = segmentBase ?
        (TXml.parseAttr(segmentBase, 'availabilityTimeOffset',
            TXml.parseFloat) || 0) : 0;
    const segmentTemplateAto = segmentTemplate ?
        (TXml.parseAttr(segmentTemplate, 'availabilityTimeOffset',
            TXml.parseFloat) || 0) : 0;
    const baseUriAto = uriObjs && uriObjs.length ?
        (TXml.parseAttr(uriObjs[0], 'availabilityTimeOffset',
            TXml.parseFloat) || 0) : 0;

    const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
        segmentBaseAto + segmentTemplateAto;

    let segmentSequenceCadence = null;
    const segmentSequenceProperties =
        TXml.findChild(elem, 'SegmentSequenceProperties');
    if (segmentSequenceProperties) {
      const sap = TXml.findChild(segmentSequenceProperties, 'SAP');
      if (sap) {
        segmentSequenceCadence = TXml.parseAttr(sap, 'cadence',
            TXml.parseInt);
      }
    }

    // This attribute is currently non-standard, but it is supported by Kaltura.
    let label = elem.attributes['label'];

    // See DASH IOP 4.3 here https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf (page 35)
    const labelElements = TXml.findChildren(elem, 'Label');
    if (labelElements && labelElements.length) {
      // NOTE: Right now only one label field is supported.
      const firstLabelElement = labelElements[0];
      if (TXml.getTextContents(firstLabelElement)) {
        label = TXml.getTextContents(firstLabelElement);
      }
    }

    return {
      getBaseUris:
          () => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
      segmentBase: segmentBase || parent.segmentBase,
      segmentList:
          TXml.findChild(elem, 'SegmentList') || parent.segmentList,
      segmentTemplate: segmentTemplate || parent.segmentTemplate,
      producerReferenceTime: TXml.findChild(elem, 'ProducerReferenceTime') ||
        parent.producerReferenceTime,
      width: TXml.parseAttr(elem, 'width', parseNumber) || parent.width,
      height: TXml.parseAttr(elem, 'height', parseNumber) || parent.height,
      contentType: contentType,
      mimeType: mimeType,
      codecs: codecs,
      frameRate: frameRate,
      pixelAspectRatio: pixelAspectRatio,
      emsgSchemeIdUris: emsgSchemeIdUris,
      id: supplementalId || id,
      originalId: id,
      language: elem.attributes['lang'],
      numChannels: numChannels,
      audioSamplingRate: audioSamplingRate,
      availabilityTimeOffset: availabilityTimeOffset,
      initialization: null,
      segmentSequenceCadence:
          segmentSequenceCadence || parent.segmentSequenceCadence,
      label: label || null,
      encrypted: false,
    };
  }
Creates a new inheritance frame for the given element.

@param {!shaka.extern.xml.Node} elem
@param {?shaka.dash.DashParser.InheritanceFrame} parent
@param {?function(): !Array<string>} getBaseUris
@return {shaka.dash.DashParser.InheritanceFrame}
@private