Compare commits
2 Commits
49a54616b9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
3a4d9fe45d
|
|||
|
eeec3582c9
|
@ -60,15 +60,18 @@ async def init_video_fifo():
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print(f"Opening FIFO {VIDEO_FIFO_PATH} for reading (will block until C++ opens for writing)...")
|
print(f"Opening FIFO {VIDEO_FIFO_PATH} for reading (non-blocking mode)...")
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
# Open file in BLOCKING mode - this will unblock C++ when it opens for writing
|
# Open file in NON-BLOCKING mode to prevent deadlock
|
||||||
|
# GStreamer filesink opens FIFO lazily (only when first frame arrives)
|
||||||
|
# Using O_NONBLOCK prevents Python from blocking while waiting for C++ writer
|
||||||
def open_fifo():
|
def open_fifo():
|
||||||
return open(VIDEO_FIFO_PATH, 'rb', buffering=0)
|
fd = os.open(VIDEO_FIFO_PATH, os.O_RDONLY | os.O_NONBLOCK)
|
||||||
|
return os.fdopen(fd, 'rb', buffering=0)
|
||||||
|
|
||||||
video_fifo_file = await loop.run_in_executor(None, open_fifo)
|
video_fifo_file = await loop.run_in_executor(None, open_fifo)
|
||||||
print(f"FIFO opened successfully - C++ should now be writing")
|
print(f"FIFO opened successfully in non-blocking mode")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to open video FIFO: {e}")
|
print(f"Failed to open video FIFO: {e}")
|
||||||
|
|
||||||
@ -294,9 +297,11 @@ async def stream_video_from_fifo():
|
|||||||
# -c:v copy: copy video codec without re-encoding (use hardware-encoded H.264)
|
# -c:v copy: copy video codec without re-encoding (use hardware-encoded H.264)
|
||||||
# -f hls: output HLS format
|
# -f hls: output HLS format
|
||||||
# -hls_time 1: 1 second per segment (low latency)
|
# -hls_time 1: 1 second per segment (low latency)
|
||||||
# -hls_list_size 5: keep 5 segments in playlist
|
# -hls_list_size 10: keep 10 segments in playlist (more buffer for clients)
|
||||||
|
# -hls_delete_threshold 3: delete segments only after 3 new ones created
|
||||||
# -hls_flags delete_segments+append_list+omit_endlist: live streaming flags
|
# -hls_flags delete_segments+append_list+omit_endlist: live streaming flags
|
||||||
# -hls_segment_type mpegts: use MPEG-TS segments
|
# -hls_segment_type mpegts: use MPEG-TS segments
|
||||||
|
# -hls_segment_filename: use %d for unlimited numbering
|
||||||
# -start_number 0: start segment numbering from 0
|
# -start_number 0: start segment numbering from 0
|
||||||
ffmpeg_process = subprocess.Popen(
|
ffmpeg_process = subprocess.Popen(
|
||||||
['ffmpeg',
|
['ffmpeg',
|
||||||
@ -308,10 +313,11 @@ async def stream_video_from_fifo():
|
|||||||
'-c:v', 'copy',
|
'-c:v', 'copy',
|
||||||
'-f', 'hls',
|
'-f', 'hls',
|
||||||
'-hls_time', '1',
|
'-hls_time', '1',
|
||||||
'-hls_list_size', '5',
|
'-hls_list_size', '10',
|
||||||
|
'-hls_delete_threshold', '3',
|
||||||
'-hls_flags', 'delete_segments+append_list+omit_endlist',
|
'-hls_flags', 'delete_segments+append_list+omit_endlist',
|
||||||
'-hls_segment_type', 'mpegts',
|
'-hls_segment_type', 'mpegts',
|
||||||
'-hls_segment_filename', f'{hls_dir}/segment_%03d.ts',
|
'-hls_segment_filename', f'{hls_dir}/segment_%d.ts',
|
||||||
'-start_number', '0',
|
'-start_number', '0',
|
||||||
f'{hls_dir}/playlist.m3u8'],
|
f'{hls_dir}/playlist.m3u8'],
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
@ -330,16 +336,39 @@ async def stream_video_from_fifo():
|
|||||||
async def read_from_fifo():
|
async def read_from_fifo():
|
||||||
"""Read from FIFO and pipe to ffmpeg stdin"""
|
"""Read from FIFO and pipe to ffmpeg stdin"""
|
||||||
nonlocal bytes_written
|
nonlocal bytes_written
|
||||||
|
writer_connected = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while streaming_active:
|
while streaming_active:
|
||||||
def read_chunk():
|
def read_chunk():
|
||||||
return fifo.read(chunk_size)
|
try:
|
||||||
|
return fifo.read(chunk_size)
|
||||||
|
except BlockingIOError:
|
||||||
|
# No data available yet (writer not connected or no data)
|
||||||
|
return None
|
||||||
|
|
||||||
data = await loop.run_in_executor(None, read_chunk)
|
data = await loop.run_in_executor(None, read_chunk)
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
# BlockingIOError: no data available, wait a bit
|
||||||
|
if not writer_connected:
|
||||||
|
print("Waiting for C++ to start writing to FIFO...")
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
print("FIFO EOF reached")
|
# Empty data: EOF (writer closed the FIFO)
|
||||||
|
if writer_connected:
|
||||||
|
print("FIFO EOF reached - C++ stopped writing")
|
||||||
|
else:
|
||||||
|
print("FIFO closed before C++ started writing")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Got data! Mark writer as connected
|
||||||
|
if not writer_connected:
|
||||||
|
writer_connected = True
|
||||||
|
print("C++ started writing to FIFO successfully")
|
||||||
|
|
||||||
if ffmpeg_process and ffmpeg_process.stdin:
|
if ffmpeg_process and ffmpeg_process.stdin:
|
||||||
try:
|
try:
|
||||||
ffmpeg_process.stdin.write(data)
|
ffmpeg_process.stdin.write(data)
|
||||||
|
|||||||
@ -367,13 +367,14 @@
|
|||||||
|
|
||||||
if (Hls.isSupported()) {
|
if (Hls.isSupported()) {
|
||||||
hls = new Hls({
|
hls = new Hls({
|
||||||
// Low latency configuration
|
// Low latency configuration with increased buffer
|
||||||
lowLatencyMode: true,
|
lowLatencyMode: true,
|
||||||
backBufferLength: 90,
|
backBufferLength: 90,
|
||||||
maxBufferLength: 3,
|
maxBufferLength: 10, // Increased from 3 to 10 seconds
|
||||||
maxBufferSize: 1 * 1024 * 1024, // 1MB
|
maxBufferSize: 3 * 1024 * 1024, // Increased from 1MB to 3MB
|
||||||
liveSyncDurationCount: 1,
|
liveSyncDurationCount: 3, // Keep 3 segments in sync
|
||||||
liveMaxLatencyDurationCount: 2,
|
liveMaxLatencyDurationCount: 5, // Max 5 segments latency before catchup
|
||||||
|
maxMaxBufferLength: 30, // Maximum buffer length
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
debug: false
|
debug: false
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user