From de4cd7b57276c4c306cad3232a638d4cc0e3b648 Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sun, 1 Nov 2020 16:50:24 -0500 Subject: [PATCH] Adding very basic library to emit image events from ffmpeg rtsp stream --- .gitignore | 116 ++++++++++++++++++++++++++++++++++++++++++++ .vscode/launch.json | 21 ++++++++ .vscode/tasks.json | 15 ++++++ lib/index.js | 110 +++++++++++++++++++++++++++++++++++++++++ lib/index.js.map | 1 + package-lock.json | 19 ++++++++ package.json | 26 ++++++++++ src/index.ts | 94 +++++++++++++++++++++++++++++++++++ src/options.ts | 6 +++ tsconfig.json | 60 +++++++++++++++++++++++ 10 files changed, 468 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 lib/index.js create mode 100644 lib/index.js.map create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/index.ts create mode 100644 src/options.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5a06f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,116 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..14f0161 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceFolder}/lib/index.js", + "preLaunchTask": "build", + "console": "internalConsole", + "internalConsoleOptions": "openOnSessionStart", + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a4f6e00 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,15 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "typescript", + "tsconfig": "tsconfig.json", + "problemMatcher": [ + "$tsc" + ] + } + ] +} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..32f2998 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,110 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var child_process_1 = require("child_process"); +var events_1 = require("events"); +var fs_1 = __importDefault(require("fs")); +var Rtsp = /** @class */ (function (_super) { + __extends(Rtsp, _super); + function Rtsp(connectionString) { + var _this = _super.call(this) || this; + _this.onError = function (err) { + console.error('Failed to start stream: ' + err.message); + }; + _this.onStdErrorData = function (data) { + if (!_this._started) { + _this._started = true; + } + data.toString().split(/\n/).forEach(function (line) { + console.debug(line); + }); + }; + _this.onExit = function (code, signal) { + var message = 'FFmpeg exited with code: ' + code + ' and signal: ' + signal; + if (code == null || code === 255) { + if (_this._childProcess && _this._childProcess.killed) { + console.debug(message + ' (Expected)'); + } + else { + console.error(message + ' (Unexpected)'); + } + } + else { + console.error(message + ' (Error)'); + } + }; + _this.onData = function (data) { + 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) == "ff" && data[data.length - 1].toString(16) == "d9") { + _this.emit('data', _this._buffer); + _this._buffer = Buffer.from(''); + console.log(); + } + } + }; + _this._started = false; + _this._connecteionString = connectionString; + _this._childProcess = undefined; + _this._buffer = Buffer.from(''); + return _this; + } + Object.defineProperty(Rtsp.prototype, "isStarted", { + get: function () { + return this._started; + }, + enumerable: true, + configurable: true + }); + Rtsp.prototype.start = function () { + var _a; + var args = "-i " + this._connecteionString + " -r 30 -f image2 -update 1 -"; + this._childProcess = child_process_1.spawn("ffmpeg", args.split(/\s+/)); + if (!this._childProcess) { + return; + } + (_a = this._childProcess.stdout) === null || _a === void 0 ? void 0 : _a.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); + } + }; + Rtsp.prototype.close = function () { + this._childProcess && this._childProcess.kill('SIGKILL'); + this.emit('closed'); + }; + Rtsp.prototype.getStdin = function () { + return this._childProcess ? this._childProcess.stdin : null; + }; + return Rtsp; +}(events_1.EventEmitter)); +exports.Rtsp = Rtsp; +var rtsp = new Rtsp("rtsp://brandon:asdf1234@192.168.1.229/live"); +rtsp.on('data', function (data) { + rtsp.close(); + fs_1.default.writeFile("/Users/brandonwatson/Documents/Git/Gitea/asdf.jpeg", data, 'base64', function (err) { + if (err) { + console.log(err); + process.exit(1); + } + }); +}); +rtsp.start(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..eaf02cf --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3f712a9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,19 @@ +{ + "name": "rtsp-stream", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "14.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", + "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", + "dev": true + }, + "child_process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", + "integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..84ea3b3 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "rtsp-stream", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc --build" + }, + "repository": { + "type": "git", + "url": "ssh://git@thebword.ddns.net:3122/watsonb8/rtsp-stream.git" + }, + "keywords": [ + "rtsp", + "typescript" + ], + "author": "Brandon Watson", + "license": "ISC", + "dependencies": { + "child_process": "^1.0.2" + }, + "devDependencies": { + "@types/node": "^14.14.6" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..643f57f --- /dev/null +++ b/src/index.ts @@ -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(''); + } + } + } +} diff --git a/src/options.ts b/src/options.ts new file mode 100644 index 0000000..f17779f --- /dev/null +++ b/src/options.ts @@ -0,0 +1,6 @@ +export interface IOptions { + rate?: number, + quality?: number, + resolution?: string, + codec?: string, +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2af2ac1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,60 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./lib", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} \ No newline at end of file