mirror of
https://github.com/koush/scrypted.git
synced 2026-02-13 18:32:56 +00:00
homekit: use ffmpeg pipe for mp4 parsing
This commit is contained in:
@@ -1,49 +1,38 @@
|
||||
import { createServer, Socket } from 'net';
|
||||
import child_process from 'child_process';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { FFMpegInput } from '@scrypted/sdk/types';
|
||||
import { listenZero } from './listen-cluster';
|
||||
import sdk from "@scrypted/sdk";
|
||||
import { ffmpegLogInitialOutput } from './media-helpers';
|
||||
import { MP4Atom, parseFragmentedMP4 } from './stream-parser';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
const { mediaManager } = sdk;
|
||||
|
||||
export interface FFMpegFragmentedMP4Session {
|
||||
socket: Socket;
|
||||
cp: ChildProcess;
|
||||
generator: AsyncGenerator<MP4Atom>;
|
||||
}
|
||||
|
||||
export async function startFFMPegFragmetedMP4Session(inputArguments: string[], audioOutputArgs: string[], videoOutputArgs: string[], console: Console): Promise<FFMpegFragmentedMP4Session> {
|
||||
return new Promise(async (resolve) => {
|
||||
const server = createServer(socket => {
|
||||
server.close();
|
||||
const args = inputArguments.slice();
|
||||
args.push(
|
||||
...videoOutputArgs,
|
||||
...audioOutputArgs,
|
||||
'-movflags', 'frag_keyframe+empty_moov+default_base_moof',
|
||||
'-f', 'mp4',
|
||||
'pipe:3',
|
||||
);
|
||||
|
||||
resolve({
|
||||
socket,
|
||||
cp,
|
||||
generator: parseFragmentedMP4(socket),
|
||||
});
|
||||
});
|
||||
const serverPort = await listenZero(server);
|
||||
args.unshift('-hide_banner');
|
||||
console.log(args.join(' '));
|
||||
|
||||
const args = inputArguments.slice();
|
||||
args.push(
|
||||
'-f', 'mp4',
|
||||
...videoOutputArgs,
|
||||
...audioOutputArgs,
|
||||
'-movflags', 'frag_keyframe+empty_moov+default_base_moof',
|
||||
`tcp://127.0.0.1:${serverPort}`
|
||||
);
|
||||
|
||||
args.unshift('-hide_banner');
|
||||
console.log(args.join(' '));
|
||||
|
||||
const cp = child_process.spawn(await mediaManager.getFFmpegPath(), args, {
|
||||
// stdio: 'ignore',
|
||||
});
|
||||
|
||||
ffmpegLogInitialOutput(console, cp);
|
||||
const cp = child_process.spawn(await mediaManager.getFFmpegPath(), args, {
|
||||
stdio: ['pipe', 'pipe', 'pipe', 'pipe',]
|
||||
});
|
||||
|
||||
ffmpegLogInitialOutput(console, cp);
|
||||
|
||||
return {
|
||||
cp,
|
||||
generator: parseFragmentedMP4(cp.stdio[3] as Readable),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ export async function* handleFragmentsRequests(device: ScryptedDevice & VideoCam
|
||||
const socketUrl = new URL(ffmpegInput.url);
|
||||
const socket = net.connect(parseInt(socketUrl.port), socketUrl.hostname);
|
||||
session = {
|
||||
socket,
|
||||
cp: undefined,
|
||||
generator: parseFragmentedMP4(socket),
|
||||
}
|
||||
@@ -101,8 +100,8 @@ export async function* handleFragmentsRequests(device: ScryptedDevice & VideoCam
|
||||
}
|
||||
else {
|
||||
audioArgs = [
|
||||
'-acodec', 'copy',
|
||||
'-bsf:a', 'aac_adtstoasc',
|
||||
'-acodec', 'copy'
|
||||
];
|
||||
}
|
||||
|
||||
@@ -136,11 +135,13 @@ export async function* handleFragmentsRequests(device: ScryptedDevice & VideoCam
|
||||
}
|
||||
|
||||
console.log(`motion recording started`);
|
||||
const { socket, cp, generator } = session;
|
||||
const { cp, generator } = session;
|
||||
let pending: Buffer[] = [];
|
||||
try {
|
||||
let i = 0;
|
||||
for await (const box of generator) {
|
||||
const { header, type, data } = box;
|
||||
// console.log('motion fragment box', type);
|
||||
|
||||
// every moov/moof frame designates an iframe?
|
||||
pending.push(header, data);
|
||||
@@ -148,17 +149,17 @@ export async function* handleFragmentsRequests(device: ScryptedDevice & VideoCam
|
||||
if (type === 'moov' || type === 'mdat') {
|
||||
const fragment = Buffer.concat(pending);
|
||||
pending = [];
|
||||
console.log(`motion fragment #${++i} sent. size:`, fragment.length);
|
||||
yield fragment;
|
||||
}
|
||||
// console.log('mp4 box type', type, length);
|
||||
}
|
||||
console.log(`motion recording finished`);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(`motion recording complete ${e}`);
|
||||
generator.throw(e);
|
||||
}
|
||||
finally {
|
||||
socket.destroy();
|
||||
cp?.kill('SIGKILL');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user