Adding very basic library to emit image events from ffmpeg rtsp stream

This commit is contained in:
watsonb8
2020-11-01 16:50:24 -05:00
commit de4cd7b572
10 changed files with 468 additions and 0 deletions

94
src/index.ts Normal file
View File

@ -0,0 +1,94 @@
import { ChildProcess, spawn } from "child_process"
import { EventEmitter } from "events";
import { Writable } from "stream";
import { IOptions } from "./options";
const ef1 = "ff";
const ef2 = "d9";
export class Rtsp extends EventEmitter {
private _connecteionString: string;
private _childProcess: ChildProcess | undefined;
private _started: boolean;
private _buffer: Buffer;
private _options: IOptions;
constructor(connectionString: string, options: IOptions) {
super();
this._started = false;
this._connecteionString = connectionString;
this._childProcess = undefined;
this._buffer = Buffer.from('');
this._options = options;
}
public get isStarted(): boolean {
return this._started;
}
public start(): void {
const argStrings = [
`-i ${this._connecteionString}`,
`-r ${this._options.rate ?? 10}`,
`-f image2`,
`-codec:v ${this._options.codec ?? 'libx264'}`,
`-update 1 -`
];
const args = argStrings.join(" ");
this._childProcess = spawn("ffmpeg", args.split(/\s+/));
if(!this._childProcess){
return;
}
this._childProcess.stdout?.on('data', this.onData)
this._childProcess.on('exit', this.onExit);
this._childProcess.on('error', this.onError);
if (this._childProcess.stderr) {
this._childProcess.stderr.on('data', this.onStdErrorData);
}
}
public close(): void {
this._childProcess && this._childProcess.kill('SIGKILL');
this.emit('closed');
}
public getStdin(): Writable | null {
return this._childProcess ? this._childProcess.stdin : null;
}
private onError = (err: Error): void => {
this.emit('error', new Error('Failed to start stream: ' + err.message));
}
private onStdErrorData = (data: any): void => {
if (!this._started) {
this._started = true;
}
let msg = "";
data.toString().split(/\n/).forEach((line: string) => {
msg += `line\n`;
});
this.emit("error", msg);
}
private onExit = (code: number, signal: NodeJS.Signals): void => {
const message = 'FFmpeg exited with code: ' + code + ' and signal: ' + signal;
this.emit('closed', message);
}
private onData = (data: Buffer): void => {
if (data.length > 1) {
this._buffer = this._buffer ? Buffer.concat([this._buffer, data]) : this._buffer = Buffer.from(data);
//End of image
if(data[data.length - 2].toString(16) == ef1 && data[data.length -1].toString(16) == ef2){
this.emit('data', this._buffer)
this._buffer = Buffer.from('');
}
}
}
}

6
src/options.ts Normal file
View File

@ -0,0 +1,6 @@
export interface IOptions {
rate?: number,
quality?: number,
resolution?: string,
codec?: string,
}