增加了对hls直播转换mp4的playlist结尾检查,确保使用的直播为结束直播
This commit is contained in:
parent
8d57e593f8
commit
2d2be4e9a7
|
|
@ -378,6 +378,7 @@ class VideoUtils:
|
||||||
raise RuntimeError("输出是空文件")
|
raise RuntimeError("输出是空文件")
|
||||||
else:
|
else:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
|
if "SKIP" not in line:
|
||||||
logger.warning(line)
|
logger.warning(line)
|
||||||
|
|
||||||
return ffmpeg_cmd
|
return ffmpeg_cmd
|
||||||
|
|
@ -754,7 +755,6 @@ class VideoUtils:
|
||||||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
local_m3u8_path, temp_dir = await VideoUtils.convert_m3u8_to_local_source(media_stream_url)
|
local_m3u8_path, temp_dir = await VideoUtils.convert_m3u8_to_local_source(media_stream_url)
|
||||||
# 使用ffmpeg合并TS片段
|
# 使用ffmpeg合并TS片段
|
||||||
ffmpeg_cmd = VideoUtils.async_ffmpeg_init()
|
ffmpeg_cmd = VideoUtils.async_ffmpeg_init()
|
||||||
|
|
@ -1194,8 +1194,9 @@ class VideoUtils:
|
||||||
reconnect_at_eof="1",
|
reconnect_at_eof="1",
|
||||||
reconnect_streamed="1",
|
reconnect_streamed="1",
|
||||||
reconnect_delay_max="5")
|
reconnect_delay_max="5")
|
||||||
|
output_playlist = f"{playlist_output_dir}/playlist.m3u8"
|
||||||
ffmpeg_cmd.output(
|
ffmpeg_cmd.output(
|
||||||
f"{playlist_output_dir}/playlist.m3u8",
|
output_playlist,
|
||||||
f="hls",
|
f="hls",
|
||||||
hls_init_time=first_segment_duration,
|
hls_init_time=first_segment_duration,
|
||||||
hls_time=segment_duration,
|
hls_time=segment_duration,
|
||||||
|
|
@ -1210,3 +1211,4 @@ class VideoUtils:
|
||||||
)
|
)
|
||||||
await ffmpeg_cmd.execute()
|
await ffmpeg_cmd.execute()
|
||||||
logger.info(f'停止录制')
|
logger.info(f'停止录制')
|
||||||
|
return output_playlist
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ with ffmpeg_worker_image.imports():
|
||||||
raise NotImplementedError(f"暂不支持使用{media_stream.protocol.value}协议")
|
raise NotImplementedError(f"暂不支持使用{media_stream.protocol.value}协议")
|
||||||
output_path = f"{output_path_prefix}/{config.modal_environment}/convert_stream/{func_id}/output.mp4"
|
output_path = f"{output_path_prefix}/{config.modal_environment}/convert_stream/{func_id}/output.mp4"
|
||||||
|
|
||||||
local_output, metadata = await VideoUtils.ffmpeg_convert_stream_media(media_stream_url=stream_url,
|
local_output, metadata = await VideoUtils.ffmpeg_convert_stream_media_multithread(
|
||||||
|
media_stream_url=stream_url,
|
||||||
output_path=output_path)
|
output_path=output_path)
|
||||||
s3_outputs = local_copy_to_s3([local_output])
|
s3_outputs = local_copy_to_s3([local_output])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import modal
|
||||||
|
|
||||||
|
|
||||||
from ..ffmpeg_app import ffmpeg_worker_image, app, config, s3_mount
|
from ..ffmpeg_app import ffmpeg_worker_image, app, config, s3_mount
|
||||||
|
|
||||||
|
|
@ -11,7 +13,7 @@ with ffmpeg_worker_image.imports():
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
import backoff
|
import backoff
|
||||||
import httpx
|
import httpx
|
||||||
import modal
|
import m3u8
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from modal import current_function_call_id
|
from modal import current_function_call_id
|
||||||
|
|
@ -163,13 +165,19 @@ with ffmpeg_worker_image.imports():
|
||||||
playlist_observer.schedule(playlist_handler, path=volume_output_dir, recursive=False)
|
playlist_observer.schedule(playlist_handler, path=volume_output_dir, recursive=False)
|
||||||
playlist_observer.start()
|
playlist_observer.start()
|
||||||
try:
|
try:
|
||||||
await VideoUtils.ffmpeg_stream_record_as_hls(stream_url=stream_url,
|
playlist = await VideoUtils.ffmpeg_stream_record_as_hls(stream_url=stream_url,
|
||||||
first_segment_duration=first_segment_duration,
|
first_segment_duration=first_segment_duration,
|
||||||
segment_duration=segment_duration,
|
segment_duration=segment_duration,
|
||||||
stream_content_timeout=recording_timeout,
|
stream_content_timeout=recording_timeout,
|
||||||
stream_monitor_timeout=monitor_timeout,
|
stream_monitor_timeout=monitor_timeout,
|
||||||
segments_output_dir=volume_output_dir,
|
segments_output_dir=volume_output_dir,
|
||||||
playlist_output_dir=volume_output_dir)
|
playlist_output_dir=volume_output_dir)
|
||||||
|
# 确保playlist有 #EXT-X-ENDLIST 结尾
|
||||||
|
pl = m3u8.load(playlist)
|
||||||
|
pl.is_endlist = True
|
||||||
|
pl.dump(playlist)
|
||||||
|
logger.info(f"[End] playlist = {playlist}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
playlist_observer.stop()
|
playlist_observer.stop()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue