Codemaru 1.0.0.0
QR 코드, 모바일 랜딩 페이지, vCard 연락처 저장과 명함 디자인을 한 화면에서 제공하는 디지털 명함 서비스입니다.
로딩중...
검색중...
일치하는것 없음
Codemaru.Services.FfmpegHlsService 클래스 참조sealed

더 자세히 ...

Codemaru.Services.FfmpegHlsService에 대한 상속 다이어그램 :
Codemaru.Services.FfmpegHlsService에 대한 협력 다이어그램:

Public 멤버 함수

 FfmpegHlsService (ILogger< FfmpegHlsService > log, IOptions< FfmpegOptions > opt, IOptions< List< StreamConfig > > streams, IWebHostEnvironment env)
override Task StopAsync (CancellationToken cancellationToken)

Protected 멤버 함수

override async Task ExecuteAsync (CancellationToken ct)

Private 멤버 함수

string GetOutputRoot ()
string string segFmt GetOutputPaths (StreamConfig s)
void SafeRestart (StreamConfig s)
void TryStartOne (StreamConfig s)
void InitWatchStats (StreamConfig s)
long DateTime lastWrite ReadSeqAndTime (string m3u8Path)

Private 속성

readonly ILogger< FfmpegHlsService_log
readonly FfmpegOptions _opt
readonly IReadOnlyList< StreamConfig_streams
readonly IWebHostEnvironment _env
readonly Dictionary< string, Process > _procs = new()
readonly Dictionary< string, long > _lastSeq = new()
readonly Dictionary< string, DateTime > _lastWrite = new()
string m3u8Path
long seq

정적 Private 속성

static readonly Regex MediaSeqRegex = new(@"#EXT-X-MEDIA-SEQUENCE:(\d+)", RegexOptions.Compiled)

상세한 설명

ffmpeg 프로세스를 관리하는 HostedService(워치독 포함).

FfmpegHlsService.cs 파일의 31 번째 라인에서 정의되었습니다.

생성자 & 소멸자 문서화

◆ FfmpegHlsService()

Codemaru.Services.FfmpegHlsService.FfmpegHlsService ( ILogger< FfmpegHlsService > log,
IOptions< FfmpegOptions > opt,
IOptions< List< StreamConfig > > streams,
IWebHostEnvironment env )
inline

생성자.

매개변수
loglog에 사용할 ILogger<FfmpegHlsService> 값입니다.
optopt에 사용할 IOptions<FfmpegOptions> 값입니다.
streamsstreams에 사용할 IOptions<List<StreamConfig>> 값입니다.
envenv에 사용할 IWebHostEnvironment 값입니다.

FfmpegHlsService.cs 파일의 151 번째 라인에서 정의되었습니다.

156 {
157 _log = log;
158 _opt = opt.Value;
159 _streams = streams.Value;
160 _env = env;
161 }

다음을 참조함 : _env, _log, _opt, _streams.

멤버 함수 문서화

◆ ExecuteAsync()

override async Task Codemaru.Services.FfmpegHlsService.ExecuteAsync ( CancellationToken ct)
inlineprotected

서비스 시작 시 각 스트림 ffmpeg 실행 + 워치독 루프 가동.

매개변수
ct취소 요청을 감시하는 토큰입니다.
반환값
Execute Async 작업에서 생성한 Task 결과입니다.

FfmpegHlsService.cs 파일의 187 번째 라인에서 정의되었습니다.

188 {
189 Directory.CreateDirectory(GetOutputRoot());
190
191 foreach (var s in _streams)
192 {
193 TryStartOne(s);
194 InitWatchStats(s);
195 }
196
197 // 주기적으로 프로세스 상태와 m3u8 갱신을 점검
198 while (!ct.IsCancellationRequested)
199 {
200 foreach (var s in _streams)
201 {
202 // 1) ffmpeg 죽었으면 재시작
203 if (!_procs.TryGetValue(s.Name, out var p) || p.HasExited)
204 {
205 _log.LogWarning("ffmpeg 재시작(프로세스 종료 감지): {Name}", s.Name);
206 TryStartOne(s);
207 InitWatchStats(s);
208 continue;
209 }
210
211 // 2) m3u8 갱신 감시(워치독)
212 var (m3u8Path, _) = GetOutputPaths(s);
213 if (File.Exists(m3u8Path))
214 {
215 var (seq, write) = ReadSeqAndTime(m3u8Path);
216 var lastSeq = _lastSeq[s.Name];
217 var lastWrite = _lastWrite[s.Name];
218
219 // 시퀀스 증가 또는 수정 시간이 갱신되면 정상
220 if (seq > lastSeq || write > lastWrite)
221 {
222 _lastSeq[s.Name] = Math.Max(seq, lastSeq);
223 _lastWrite[s.Name] = write > lastWrite ? write : lastWrite;
224 }
225 else
226 {
227 // 일정 시간 이상 변화가 없으면 재시작
228 var idleSec = (DateTime.UtcNow - lastWrite.ToUniversalTime()).TotalSeconds;
229 var idleLimit = Math.Max(_opt.WatchdogIdleSeconds, _opt.HlsSegmentSeconds * _opt.HlsListSize);
230 if (idleSec >= idleLimit)
231 {
232 _log.LogWarning("m3u8 갱신 정지 감지({Idle}s >= {Limit}s): {Name} → ffmpeg 재시작",
233 idleSec, idleLimit, s.Name);
234 SafeRestart(s);
235 InitWatchStats(s);
236 continue;
237 }
238 }
239 }
240 else
241 {
242 // 파일이 없으면 ffmpeg가 아직 시작 중이거나 실패→ 잠시 후 다시 확인
243 _log.LogDebug("m3u8 미존재: {Name} ({Path})", s.Name, m3u8Path);
244 }
245 }
246
247 await Task.Delay(TimeSpan.FromSeconds(_opt.WatchdogIntervalSeconds), ct);
248 }
249 }

다음을 참조함 : _lastSeq, _lastWrite, _log, _opt, _procs, _streams, GetOutputPaths(), GetOutputRoot(), InitWatchStats(), m3u8Path, ReadSeqAndTime(), SafeRestart(), seq, TryStartOne().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:

◆ GetOutputPaths()

string string segFmt Codemaru.Services.FfmpegHlsService.GetOutputPaths ( StreamConfig s)
inlineprivate

FfmpegHlsService.cs 파일의 341 번째 라인에서 정의되었습니다.

342 {
343 var outRoot = GetOutputRoot();
344 var outDir = Path.Combine(outRoot, s.Name);
345 Directory.CreateDirectory(outDir);
346
347 // 가독성 및 캐싱 안전성 위해 seg_%05d.ts 권장
348 var m3u8Path = Path.Combine(outDir, "index.m3u8");
349 var segFmt = Path.Combine(outDir, "seg_%05d.ts");
350 return (m3u8Path, segFmt);
351 }

다음을 참조함 : GetOutputRoot(), m3u8Path, Codemaru.Models.StreamConfig.Name.

다음에 의해서 참조됨 : ExecuteAsync(), TryStartOne().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ GetOutputRoot()

string Codemaru.Services.FfmpegHlsService.GetOutputRoot ( )
inlineprivate

HLS 출력 루트의 절대경로를 반환합니다.

반환값
Get Output Root 작업에서 생성한 string 결과입니다.

FfmpegHlsService.cs 파일의 309 번째 라인에서 정의되었습니다.

310 {
311 // appsettings에 상대경로("wwwroot\\hls")인 경우 ContentRoot 기준으로 절대경로화
312 return Path.IsPathRooted(_opt.OutputRoot)
313 ? _opt.OutputRoot
314 : Path.Combine(_env.ContentRootPath, _opt.OutputRoot);
315 }

다음을 참조함 : _env, _opt.

다음에 의해서 참조됨 : ExecuteAsync(), GetOutputPaths().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ InitWatchStats()

void Codemaru.Services.FfmpegHlsService.InitWatchStats ( StreamConfig s)
inlineprivate

워치독 초기 통계값을 리셋합니다.

매개변수
s이벤트를 발생시킨 객체입니다.

FfmpegHlsService.cs 파일의 502 번째 라인에서 정의되었습니다.

503 {
504 _lastSeq[s.Name] = -1;
505 _lastWrite[s.Name] = DateTime.MinValue;
506 }

다음을 참조함 : _lastSeq, _lastWrite, Codemaru.Models.StreamConfig.Name.

다음에 의해서 참조됨 : ExecuteAsync().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ ReadSeqAndTime()

long DateTime lastWrite Codemaru.Services.FfmpegHlsService.ReadSeqAndTime ( string m3u8Path)
inlineprivate

FfmpegHlsService.cs 파일의 532 번째 라인에서 정의되었습니다.

533 {
534 try
535 {
536 var text = File.ReadAllText(m3u8Path);
537 var m = MediaSeqRegex.Match(text);
538 var seq = m.Success ? long.Parse(m.Groups[1].Value) : -1;
539 var info = new FileInfo(m3u8Path);
540 return (seq, info.LastWriteTimeUtc);
541 }
542 catch (Exception ex)
543 {
544 _log.LogDebug("m3u8 읽기 실패: {Path} - {Msg}", m3u8Path, ex.Message);
545 return (-1, DateTime.MinValue);
546 }
547 }

다음을 참조함 : _log, m3u8Path, MediaSeqRegex, seq.

다음에 의해서 참조됨 : ExecuteAsync().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ SafeRestart()

void Codemaru.Services.FfmpegHlsService.SafeRestart ( StreamConfig s)
inlineprivate

한 개 스트림 ffmpeg 시작(이미 있으면 종료 후 재시작).

매개변수
s이벤트를 발생시킨 객체입니다.

FfmpegHlsService.cs 파일의 369 번째 라인에서 정의되었습니다.

370 {
371 if (_procs.TryGetValue(s.Name, out var old))
372 {
373 try
374 {
375 if (!old.HasExited)
376 {
377 old.Kill(entireProcessTree: true);
378 old.WaitForExit(2000);
379 }
380 }
381 catch { /* ignore */ }
382 }
383 TryStartOne(s);
384 }

다음을 참조함 : _procs, Codemaru.Models.StreamConfig.Name, TryStartOne().

다음에 의해서 참조됨 : ExecuteAsync().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ StopAsync()

override Task Codemaru.Services.FfmpegHlsService.StopAsync ( CancellationToken cancellationToken)
inline

서비스 중지 시 모든 ffmpeg 종료.

매개변수
cancellationToken취소 요청을 감시하는 토큰입니다.
반환값
Stop Async 작업에서 생성한 Task 결과입니다.

FfmpegHlsService.cs 파일의 275 번째 라인에서 정의되었습니다.

276 {
277 foreach (var p in _procs.Values)
278 {
279 try
280 {
281 if (!p.HasExited)
282 {
283 p.Kill(entireProcessTree: true);
284 p.WaitForExit(2000);
285 }
286 }
287 catch { /* ignore */ }
288 }
289 _procs.Clear();
290 return Task.CompletedTask;
291 }

다음을 참조함 : _procs.

◆ TryStartOne()

void Codemaru.Services.FfmpegHlsService.TryStartOne ( StreamConfig s)
inlineprivate

ffmpeg 시작 시도(성공 시 딕셔너리 등록).

매개변수
s이벤트를 발생시킨 객체입니다.

FfmpegHlsService.cs 파일의 402 번째 라인에서 정의되었습니다.

403 {
404 var (m3u8Path, segFmt) = GetOutputPaths(s);
405
406 // 입력 옵션: TCP 강제(안정), 타임스탬프 보정
407 var inputOpts = "-rtsp_transport tcp -rtsp_flags prefer_tcp -fflags +genpts -use_wallclock_as_timestamps 1";
408
409 // 인코딩/복사 분기
410 var v = (s.VideoCodec ?? _opt.VideoCodec).ToLowerInvariant();
411 var a = (s.AudioCodec ?? _opt.AudioCodec).ToLowerInvariant();
412
413 // 비디오 파트
414 // - 트랜스코딩: GOP 고정 (hls_time 2초라면 gop≈50@25fps / 60@30fps 등으로 맞추세요)
415 var videoPart =
416 v == "copy"
417 ? "-c:v copy -bsf:v h264_mp4toannexb"
418 : "-c:v libx264 -preset veryfast -tune zerolatency -profile:v high -level 4.1 -pix_fmt yuv420p " +
419 "-g 50 -keyint_min 50 -sc_threshold 0 -force_key_frames \"expr:gte(t,n_forced*2)\"";
420
421 // 오디오 파트
422 var audioPart =
423 a == "an" ? "-an"
424 : $"-c:a {a} -b:a {_opt.AudioBitrate} -ar {_opt.AudioRate} -ac {_opt.AudioChannels}";
425
426 // HLS 파트(독립 세그먼트 + 프로그램 시간 + 삭제)
427 var hlsPart = string.Join(' ', new[]
428 {
429 "-f hls",
430 $"-hls_time {_opt.HlsSegmentSeconds}",
431 $"-hls_list_size {_opt.HlsListSize}",
432 "-hls_flags delete_segments+program_date_time+independent_segments",
433 $"-hls_segment_filename \"{segFmt}\"",
434 $"\"{m3u8Path}\""
435 });
436
437 // 전체 인자 조합
438 var args = string.Join(' ', new[]
439 {
440 inputOpts,
441 $"-i \"{s.RtspUrl}\"",
442 videoPart,
443 audioPart,
444 hlsPart
445 });
446
447 var psi = new ProcessStartInfo
448 {
449 FileName = _opt.Path,
450 Arguments = args,
451 UseShellExecute = false,
452 RedirectStandardError = true,
453 RedirectStandardOutput = true,
454 CreateNoWindow = true
455 };
456
457 var proc = new Process { StartInfo = psi, EnableRaisingEvents = true };
458 proc.ErrorDataReceived += (_, e) =>
459 {
460 if (!string.IsNullOrEmpty(e.Data))
461 _log.LogInformation("[{name}] {line}", s.Name, e.Data);
462 };
463 proc.OutputDataReceived += (_, e) =>
464 {
465 if (!string.IsNullOrEmpty(e.Data))
466 _log.LogDebug("[{name}] {line}", s.Name, e.Data);
467 };
468 proc.Exited += (_, __) =>
469 {
470 _log.LogWarning("ffmpeg 종료 감지: {Name} (ExitCode={Code})", s.Name, proc.ExitCode);
471 };
472
473 if (proc.Start())
474 {
475 proc.BeginErrorReadLine();
476 proc.BeginOutputReadLine();
477 _procs[s.Name] = proc;
478 _log.LogInformation("ffmpeg 시작: {Name} → {Out}", s.Name, Path.GetDirectoryName(m3u8Path));
479 }
480 else
481 {
482 _log.LogError("ffmpeg 시작 실패: {Name}", s.Name);
483 }
484 }

다음을 참조함 : _log, _opt, _procs, GetOutputPaths(), m3u8Path, Codemaru.Models.StreamConfig.Name.

다음에 의해서 참조됨 : ExecuteAsync(), SafeRestart().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

멤버 데이터 문서화

◆ _env

readonly IWebHostEnvironment Codemaru.Services.FfmpegHlsService._env
private

env 값을 보관합니다.

FfmpegHlsService.cs 파일의 68 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : FfmpegHlsService(), GetOutputRoot().

◆ _lastSeq

readonly Dictionary<string, long> Codemaru.Services.FfmpegHlsService._lastSeq = new()
private

last Seq 값을 보관합니다.

FfmpegHlsService.cs 파일의 90 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), InitWatchStats().

◆ _lastWrite

readonly Dictionary<string, DateTime> Codemaru.Services.FfmpegHlsService._lastWrite = new()
private

last Write 값을 보관합니다.

FfmpegHlsService.cs 파일의 99 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), InitWatchStats().

◆ _log

readonly ILogger<FfmpegHlsService> Codemaru.Services.FfmpegHlsService._log
private

log 값을 보관합니다.

FfmpegHlsService.cs 파일의 41 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), FfmpegHlsService(), ReadSeqAndTime(), TryStartOne().

◆ _opt

readonly FfmpegOptions Codemaru.Services.FfmpegHlsService._opt
private

opt 값을 보관합니다.

FfmpegHlsService.cs 파일의 50 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), FfmpegHlsService(), GetOutputRoot(), TryStartOne().

◆ _procs

readonly Dictionary<string, Process> Codemaru.Services.FfmpegHlsService._procs = new()
private

procs 값을 보관합니다.

FfmpegHlsService.cs 파일의 79 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), SafeRestart(), StopAsync(), TryStartOne().

◆ _streams

readonly IReadOnlyList<StreamConfig> Codemaru.Services.FfmpegHlsService._streams
private

streams 값을 보관합니다.

FfmpegHlsService.cs 파일의 59 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), FfmpegHlsService().

◆ m3u8Path

string Codemaru.Services.FfmpegHlsService.m3u8Path
private

스트림별 m3u8/세그먼트 경로를 반환합니다.

매개변수
s이벤트를 발생시킨 객체입니다.
반환값
Get Output Paths 작업에서 생성한 (string m3u8Path, string segFmt) 결과입니다.

FfmpegHlsService.cs 파일의 341 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), GetOutputPaths(), ReadSeqAndTime(), TryStartOne().

◆ MediaSeqRegex

readonly Regex Codemaru.Services.FfmpegHlsService.MediaSeqRegex = new(@"#EXT-X-MEDIA-SEQUENCE:(\d+)", RegexOptions.Compiled)
staticprivate

Media Seq Regex 값을 보관합니다.

FfmpegHlsService.cs 파일의 109 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ReadSeqAndTime().

◆ seq

long Codemaru.Services.FfmpegHlsService.seq
private

m3u8에서 MEDIA-SEQUENCE와 파일 수정시각을 읽습니다.

반환값
(seq, lastWrite)
매개변수
m3u8Pathm3u8 Path에 사용할 string 값입니다.
반환값
Read Seq And Time 작업에서 생성한 (long seq, DateTime lastWrite) 결과입니다.

FfmpegHlsService.cs 파일의 532 번째 라인에서 정의되었습니다.

다음에 의해서 참조됨 : ExecuteAsync(), ReadSeqAndTime().


이 클래스에 대한 문서화 페이지는 다음의 파일로부터 생성되었습니다.: