UNPKG

shaka-player

Version:
167 lines (143 loc) 4.7 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.transmuxer.Ac3Transmuxer'); goog.require('shaka.device.DeviceFactory'); goog.require('shaka.media.Capabilities'); goog.require('shaka.metadata.Id3Utils'); goog.require('shaka.transmuxer.Ac3'); goog.require('shaka.transmuxer.BaseTransmuxer'); goog.require('shaka.transmuxer.TransmuxerEngine'); goog.require('shaka.transmuxer.TransmuxerUtils'); goog.require('shaka.util.BufferUtils'); goog.require('shaka.util.Error'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.Mp4Generator'); /** * @extends {shaka.transmuxer.BaseTransmuxer} * @implements {shaka.extern.Transmuxer} * @export */ shaka.transmuxer.Ac3Transmuxer = class extends shaka.transmuxer.BaseTransmuxer { /** * Check if the mime type and the content type is supported. * @param {string} mimeType * @param {string=} contentType * @return {boolean} * @override * @export */ isSupported(mimeType, contentType) { const Capabilities = shaka.media.Capabilities; if (!this.isAc3Container_(mimeType)) { return false; } const ContentType = shaka.util.ManifestParserUtils.ContentType; return Capabilities.isTypeSupported( this.convertCodecs(ContentType.AUDIO, mimeType)); } /** * Check if the mimetype is 'audio/ac3'. * @param {string} mimeType * @return {boolean} * @private */ isAc3Container_(mimeType) { return mimeType.toLowerCase().split(';')[0] == 'audio/ac3'; } /** * @override * @export */ convertCodecs(contentType, mimeType) { if (this.isAc3Container_(mimeType)) { const device = shaka.device.DeviceFactory.getDevice(); if (device.requiresEC3InitSegments()) { return 'audio/mp4; codecs="ec-3"'; } else { return 'audio/mp4; codecs="ac-3"'; } } return mimeType; } /** * @override * @export */ transmux(data, stream, reference, duration) { const Ac3 = shaka.transmuxer.Ac3; const uint8ArrayData = shaka.util.BufferUtils.toUint8(data); const id3Data = shaka.metadata.Id3Utils.getID3Data(uint8ArrayData); let offset = id3Data.length; for (; offset < uint8ArrayData.length; offset++) { if (Ac3.probe(uint8ArrayData, offset)) { break; } } const timestamp = this.getId3Timestamp( id3Data, reference.endTime * 1000); /** @type {number} */ let sampleRate = 0; /** @type {!Uint8Array} */ let audioConfig = new Uint8Array([]); /** @type {!Array<shaka.util.Mp4Generator.Mp4Sample>} */ const samples = []; /** @type {!shaka.transmuxer.Ac3.Ac3Frame} */ const frame = { sampleRate: 0, channelCount: 0, audioConfig: new Uint8Array(0), frameLength: 0, }; while (offset < uint8ArrayData.length) { const didParseFrame = Ac3.parseFrame(uint8ArrayData, offset, frame); if (!didParseFrame) { return Promise.reject(new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MEDIA, shaka.util.Error.Code.TRANSMUXING_FAILED, reference ? reference.getUris()[0] : null)); } stream.audioSamplingRate = frame.sampleRate; stream.channelsCount = frame.channelCount; sampleRate = frame.sampleRate; audioConfig = frame.audioConfig; const frameData = uint8ArrayData.subarray( offset, offset + frame.frameLength); samples.push({ data: frameData, size: frame.frameLength, duration: Ac3.AC3_SAMPLES_PER_FRAME, cts: 0, flags: shaka.transmuxer.TransmuxerUtils.AUDIO_SAMPLE_FLAGS, }); offset += frame.frameLength; } /** @type {number} */ const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000); /** @type {shaka.util.Mp4Generator.StreamInfo} */ const streamInfo = { id: stream.id, type: shaka.util.ManifestParserUtils.ContentType.AUDIO, codecs: 'ac-3', timescale: sampleRate, duration: duration, mediaConfig: audioConfig, data: { sequenceNumber: this.frameIndex, baseMediaDecodeTime: baseMediaDecodeTime, samples: samples, }, stream: stream, }; const mp4Generator = new shaka.util.Mp4Generator([streamInfo]); return Promise.resolve( this.packageSegment(mp4Generator, stream, reference)); } }; shaka.transmuxer.TransmuxerEngine.registerTransmuxer( 'audio/ac3', () => new shaka.transmuxer.Ac3Transmuxer('audio/ac3'), shaka.transmuxer.TransmuxerEngine.PluginPriority.FALLBACK);