Adding more options

This commit is contained in:
watsonb8 2020-11-27 12:30:56 -05:00
parent d59a58f63d
commit 9b92a43c2f
3 changed files with 113 additions and 78 deletions

View File

@ -1,4 +1,4 @@
import { ChildProcess, spawn } from "child_process" import { ChildProcess, spawn } from "child_process";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { Writable } from "stream"; import { Writable } from "stream";
import { IOptions } from "./options"; import { IOptions } from "./options";
@ -7,88 +7,114 @@ const ef1 = "ff";
const ef2 = "d9"; const ef2 = "d9";
export class Rtsp extends EventEmitter { export class Rtsp extends EventEmitter {
private _connecteionString: string; private _connecteionString: string;
private _childProcess: ChildProcess | undefined; private _childProcess: ChildProcess | undefined;
private _started: boolean; private _started: boolean;
private _buffer: Buffer; private _buffer: Buffer;
private _options: IOptions; private _options: IOptions;
private _paused: boolean;
constructor(connectionString: string, options: IOptions) { constructor(connectionString: string, options: IOptions) {
super(); super();
this._started = false; this._started = false;
this._connecteionString = connectionString; this._connecteionString = connectionString;
this._childProcess = undefined; this._childProcess = undefined;
this._buffer = Buffer.from(''); this._buffer = Buffer.from("");
this._options = options; this._options = options;
this._paused = false;
this.onData = this.onData.bind(this);
}
public get isStarted(): boolean {
return this._started;
}
public get isPaused(): boolean {
return this._paused;
}
public start(): void {
const argStrings = [
// `-rtsp_transport tcp`,
`-i ${this._connecteionString}`,
`-r ${this._options.rate ?? 10}`,
this._options.image
? `-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;
} }
public get isStarted(): boolean { this._childProcess.stdout?.on("data", this.onData);
return this._started; this._childProcess.on("exit", this.onExit);
this._childProcess.on("error", this.onError);
if (this._childProcess.stderr) {
this._childProcess.stderr.on("data", this.onStdErrorData);
} }
}
public start(): void { public close(): void {
const argStrings = [ this._childProcess && this._childProcess.kill("SIGKILL");
`-i ${this._connecteionString}`, this.emit("closed");
`-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){ public pause(): void {
return; this._paused = true;
} }
this._childProcess.stdout?.on('data', this.onData)
this._childProcess.on('exit', this.onExit);
this._childProcess.on('error', this.onError);
if (this._childProcess.stderr) { public resume(): void {
this._childProcess.stderr.on('data', this.onStdErrorData); this._paused = false;
} }
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`;
});
public close(): void { this.emit("error", msg);
this._childProcess && this._childProcess.kill('SIGKILL'); };
this.emit('closed');
}
public getStdin(): Writable | null { private onExit = (code: number, signal: NodeJS.Signals): void => {
return this._childProcess ? this._childProcess.stdin : null; const message =
"FFmpeg exited with code: " + code + " and signal: " + signal;
this.emit("closed", message);
};
private onData(data: Buffer): void {
if (!this._paused && 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("");
} }
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('');
}
}
} }
}
} }

View File

@ -1,6 +1,7 @@
export interface IOptions { export interface IOptions {
rate?: number, rate?: number;
quality?: number, quality?: number;
resolution?: string, resolution?: string;
codec?: string, codec?: string;
} image?: boolean;
}

8
workspace.code-workspace Normal file
View File

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}