// @ts-nocheck import * as _ from 'lodash'; import { createFFmpegCommand } from '@ownzones/meh'; import { s3Lib as ownS3 } from '@ownzones/lib'; import * as path from 'path'; import * as fs from 'fs'; import { spawnSync } from 'child_process'; import { FsFileLocator, S3FileLocator } from '@ownzones/locators'; import { IAudioChannelPath } from '../lib/workers/audio-demux'; import { config, log } from '../config'; import { TrackedFFmpegCommand } from '../utils/types'; import { IComposition, IResource } from '../lib/connect-api'; function getAudioChannelPath(cacheLocation: string, fileId: string, trackIndex: number, channelNumber: number): IAudioChannelPath { const fileName = `${fileId}_${trackIndex}_${channelNumber}.raw`; const filesLocation = `${cacheLocation}${fileName}`; const { bucket, key } = ownS3.parseUrl(filesLocation); return { fileName, bucket, key, }; } async function generatePcm(definition: IComposition, cacheLocation: string): Promise { if (!definition || !definition.segments || !definition.segments.length) { return; } const segment = definition.segments[0]; if (!segment || !segment.sequences || !segment.sequences.length) { return; } const audioTracks: IResource[] = []; const audioSequences = _.filter(segment.sequences, (s) => s.type === 'audio'); if (!audioSequences || !audioSequences.length) { return; } audioSequences.forEach((as) => { if (as.resources && as.resources.length) { audioTracks.push(as.resources[0]); } }); const sourceUrl = audioTracks[0]?.track?.file?.fileLocator?.url as string; log.info(`--- Audio source URL: ${sourceUrl}`); const { ffmpegCommand, ffmpegPromise } = createFFmpegCommand({ ffmpegStdoutLines: 15, }) as TrackedFFmpegCommand; const s3Promises = []; const localPaths = []; const signedUrl = await ownS3.signUrl(sourceUrl); ffmpegCommand.input(signedUrl); ffmpegCommand.inputOptions(['-vn', '-sn', '-dn']); audioTracks.map((at) => { const track = at.track; if (track) { const trackProperties = _.get(track, 'properties.probeResult'); if (trackProperties) { const trackIndex = trackProperties.index; const channels = trackProperties.channels; const fileId = track.fileId; for (let i = 0; i < channels; i += 1) { const location = getAudioChannelPath(cacheLocation, fileId, trackIndex, i); const localPath = path.join(config.mediaPath, location.fileName); if (fs.existsSync(localPath)) { fs.unlinkSync(localPath); } spawnSync('mkfifo', [localPath], { stdio: 'ignore' }); ffmpegCommand.output(localPath); ffmpegCommand.outputOptions(['-map_channel', `0.${trackIndex}.${i}`]); ffmpegCommand.outputOptions(['-ar', '48000']); ffmpegCommand.outputOptions(['-c:a', 'pcm_s16le']); ffmpegCommand.format('s16le'); localPaths.push({ location, localPath }); } } } }); localPaths.map((lPath) => { const channelFsFileLocator = new FsFileLocator({ path: lPath.localPath }); const channelS3FileLocator = new S3FileLocator(lPath.location); s3Promises.push(channelS3FileLocator.uploadFrom(channelFsFileLocator)); }); ffmpegCommand.run(); // This is bugged locally, something is blocking... The promises can't complete on the same thread, but if the ffmpeg // promise is awaited on one thread(process) and the s3Promises on another it works fine. await Promise.all([ ffmpegPromise, ...s3Promises, ]); log.info('ddd'); } const def = { id: 'b232f209-f934-4d89-9e13-9eae62c17cb6', file: { id: 'd0d1ec64-9dcd-4ea9-8fe2-e7cf0c7036ed', locatorUrl: 's3://oz-zl-test-files/mediaview/5-1-audio.mp4', }, annotation: null, creator: null, contentOriginator: null, contentTitle: null, compositionTimecode: null, localeList: null, editRate: { numerator: 2997, denominator: 100, }, markers: null, dpp: null, applicationType: null, segments: [ { annotation: null, sequences: [ { type: 'audio', virtualTrackId: '743132cf-fe67-4827-8651-fd3b20c67955', resources: [ { id: '808995e5-a0ee-41e7-87a4-c3b4f7a4ccf9', track: { file: { id: 'd0d1ec64-9dcd-4ea9-8fe2-e7cf0c7036ed', locatorUrl: 's3://oz-zl-test-files/mediaview/5-1-audio.mp4', fileLocator: { type: 'S3FileLocator', bucket: 'oz-zl-test-files', key: 'mediaview/5-1-audio.mp4', url: 's3://oz-zl-test-files/mediaview/5-1-audio.mp4', }, }, fileId: 'd0d1ec64-9dcd-4ea9-8fe2-e7cf0c7036ed', type: 'audio', properties: { codec: 'aac', codecLongName: 'PCM signed 24-bit little-endian', probeResult: { tags: { language: 'eng', handlerName: 'SoundHandler', }, index: 1, bitRate: '159999', channels: 6, codecTag: '0x6134706d', duration: '46.625669', nbFrames: '1004', startPts: 0, timeBase: '1/44100', codecName: 'aac', codecType: 'audio', sampleFmt: 'fltp', startTime: '0.000000', durationTs: 2056192, rFrameRate: '0/0', sampleRate: '44100', disposition: { dub: 0, forced: 0, lyrics: 0, comment: 0, default: 1, karaoke: 0, original: 0, attachedPic: 0, cleanEffects: 0, visualImpaired: 0, hearingImpaired: 0, timedThumbnails: 0, }, avgFrameRate: '0/0', bitsPerSample: 0, channelLayout: '5.1', codecLongName: 'PCM signed 24-bit little-endian', codecTimeBase: '1/44100', codecTagString: 'mp4a', bitsPerRawSample: '24', }, }, }, trackId: '743132cf-fe67-4827-8651-fd3b20c67955', trackFileLocator: { type: 'S3FileLocator', bucket: 'oz-zl-test-files', key: 'mediaview/5-1-audio.mp4', url: 's3://oz-zl-test-files/mediaview/5-1-audio.mp4', }, editRate: { numerator: 44100, denominator: 1, }, intrinsicDuration: 240575, entryPoint: 0, sourceDuration: 2056192, repeatCount: 1, sourceEncoding: '743132cf-fe67-4827-8651-fd3b20c67955', }, ], }, ], }, ], }; void (async () => { await generatePcm(def, 's3://test/test'); })();