summaryrefslogtreecommitdiff
path: root/node_modules/prism-media/src/transcoders/ffmpeg/FfmpegProcess.js
blob: c6561a9d89a8d56d09544cc7084ca1f6c31b7a0b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
const EventEmitter = require('events').EventEmitter;
const ChildProcess = require('child_process');

/**
 * A spawned FFMPEG process
 */
class FfmpegProcess extends EventEmitter {
  constructor(ffmpegTranscoder, options) {
    super();
    /**
     * The ffmpeg process
     * @type {ChildProcess}
     */
    this.process = ChildProcess.spawn(ffmpegTranscoder.command, options.ffmpegArguments);
    /**
     * The FFMPEG transcoder that created this process
     * @type {FfmpegTranscoder}
     */
    this.transcoder = ffmpegTranscoder;
    /**
     * The input media
     * @type {?ReadableStream|string}
     */
    this.inputMedia = options.media;

    if (typeof this.inputMedia !== 'string') {
      try {
        this.connectStream(this.inputMedia);
      } catch (e) {
        this.emit('error', e, 'instantiation');
      }
    } else {
      this.attachErrorHandlers();
    }

    this.on('error', this.kill.bind(this));
    this.once('end', this.kill.bind(this));
  }

  /**
   * The ffmpeg output stream
   * @type {?ReadableStream}
   */
  get output() {
    return this.process ? this.process.stdout : null;
  }

  attachErrorHandlers() {
    this.process.stdin.on('error', e => {
      // if not killed
      if (this.process) {
        this.emit('error', e, 'ffmpegProcess.stdin');
      }
    });
    this.process.stdout.on('error', e => {
      // if not killed
      if (this.process) {
        this.emit('error', e, 'ffmpegProcess.stdout');
      }
    });
    this.process.on('error', e => this.emit('error', e, 'ffmpegProcess'));
    this.process.stdout.on('end', () => this.emit('end'));
  }

  /**
   * Connects an input stream to the ffmpeg process
   * @param {ReadableStream} inputMedia the stream to pass to ffmpeg
   * @returns {ReadableStream} the ffmpeg output stream
   */
  connectStream(inputMedia) {
    if (!this.process) throw new Error('No FFMPEG process available');
    this.inputMedia = inputMedia;
    this.inputMedia.pipe(this.process.stdin, { end: false });

    inputMedia.on('error', e => this.emit('error', e, 'inputstream', inputMedia));

    this.attachErrorHandlers();

    return this.process.stdout;
  }

  /**
   * Kills the ffmpeg process
   */
  kill() {
    if (!this.process) return;
    if (this.inputMedia && this.inputMedia.unpipe) {
      this.inputMedia.unpipe(this.process.stdin);
    }
    this.process.kill('SIGKILL');
    this.process = null;
  }
}

module.exports = FfmpegProcess;