실시간 스트리밍 오류 시 스트리밍 자동 재시작 (1)

냥무룩·2023년 6월 16일
0

rtsp-stream

목록 보기
2/4

ip camera의 rtsp를 node.js 환경에서 ffmpeg를 통하여 트랜스코딩 하여 소켓으로 실시간 영상 송출 해주는 작업을 하였다.

ffmpeg 사용법 참조글 https://www.minzkn.com/moniwiki/wiki.php/HowToFFmpeg


스트림을 생성하여 잘 재생되는 것을 확인하였지만,

그러나 그 다음날 와보면 영상이 꺼져 있는 경우가 매우 빈번히 발생하였다.

로깅을 더듬어가며 확인 해보니

특정시간(자정 즈음) 인풋 에러가 발생하는 것이었다. 이 것은 인터넷 오류로 발생한 것 같다.


문제는 ffmpeg에서 오류가 발생한 경우 그대로 스트림이 죽어버린다는 것이었다.

지속적으로 계속 영상을 보여줘야 하므로 이런 에러가 발생할 경우 스트림을 재시작 할 수 있도록 처리할 필요가 있었다.


현재 차일드 프로세스를 사용하여 ffmpeg를 spawn하여 트랜스코딩 해주고 있다.
ffmpeg에서는 stdout에는 아웃풋(말그대로 영상 data) stderr에는 현재 영상에 대한 에러와 로깅에 관한 정보가 담겨 있다.

우선 차일드 프로세스를 생성하는 부분이

// mpeg1muxer.js

function newStream(this) {
    this.stream = child_process.spawn(this.ffmpegPath, this.spawnOptions, {
        detached: false,
    });
    this.inputStreamStarted = true;

    this.stream.stdout.on('data', (data) => {
        return this.emit('mpeg1data', data);
    });
    this.stream.stderr.on('data', (data) => {
        return this.emit('ffmpegStderr', data);
    });

    this.stream.on('exit', (code, signal) => {
        setTimeout(() => {
            this.stream.kill();
            // newStream(_this);
        }, 2000);
        return this.emit('exitWithError');
    });
}

util.inherits(Mpeg1Muxer, events.EventEmitter);

이렇게 되며 stdout으로 받은 output data를 mpeg1data 라는 이벤트로 보내주고
stderr로 받은 로그 및 에러 메세지들을 ffmpegStderr로 보내준다.

그리고 새로운 함수로 restartStream을 만들어 간단하게
프로세스를 죽이고 다시 시작하도록 해주었다.

VideoStream.prototype.restartStream = function () {
    this.stream.kill();
    console.log(`cameraID : ${this.cameraId},  스트림 재시작`);
    return this.startMpeg1Stream();
};

https://trac.ffmpeg.org/wiki/Errors
ffmpeg 위키에 있는 error 메세지 종류를 확인하여
에러 상황이 발생하였을 때 재시작 되도록 처리해 보았다.

		if (data.includes('muxing overhead')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Could not write header for output file')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Invalid input file')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('matches no streams')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Output file is empty')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Unknown encoder')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Trailing options were found')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('No pixel format specified')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Could not open file')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Could not get frame')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Could not find tag for codec foo in stream')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Streamcopy requested for')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes("WASAPI can't initialize")) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }
        if (data.includes('Non-monotonous DTS')) {
            console.log('Logging Time : ', getDateAndTime());
            console.log(data);
            this.restartStream();
        }

일단은 이렇게 하니 오류가 잡혔다.

이렇게 처리하면 다른 문제들이 생길 수 있는데

정리해나가야 할 것 같다.

0개의 댓글