fc_pipe now muxes video + that frame's embedded audio into ONE streaming AVI
container on stdout, so ffmpeg reads a SINGLE input (-f avi -i pipe:0) instead
of a raw video pipe + a separate live audio FIFO. The two-live-pipe design
deadlocked ffmpeg (it stalled forever probing input 0); a single interleaved
stream removes that failure mode entirely.
fc_pipe.c:
- New AVI mode (argv[3] == "--avi"/"avi"). Writes RIFF('AVI ') + LIST(hdrl)
{ avih + strl(vids: strh+BITMAPINFOHEADER UYVY 16bpp) + strl(auds:
strh+WAVEFORMATEX PCM s16le 48k 2ch) } + LIST(movi) once, then per ring
entry a '00dc' video chunk followed by a '01wb' audio chunk (LE sizes,
even-pad). RIFF/movi sizes use the 0x7FFFFFFF streaming sentinel (pipe is
unseekable); dwFlags has NO index bits. Frame-coupled by construction: both
chunks come from the SAME ring entry in one read-loop iteration.
- dwScale/dwRate = fps_den/fps_num (video) and nBlockAlign/nAvgBytesPerSec
(audio). If a frame has audio_size 0, emits one frame-interval of silence
(round(48000*fps_den/fps_num) samples) so the audio timeline tracks video
and ffmpeg never starves on the audio demuxer.
- Legacy raw video-only mode retained when no avi flag is given. The old
split-stdout/audio-FIFO threaded path is removed (it was the deadlock).
fc_client.{h,c}:
- Add fc_consumer_info() / fc_stream_info_t to expose the slot header's
width/height/fps/audio params to fc_pipe for the AVI header.
capture-manager.js (_buildInputArgs deltacast/sdi framecache branch):
- Spawn fc_pipe with "--avi" (no audio FIFO). Remove the mkfifo + audio-FIFO
creation for this path.
- inputArgs: ONE input -thread_queue_size 512 -f avi [AUDIO_OFFSET_MS] -i pipe:0
(was: -f rawvideo -i pipe:0 AND -f s16le -ar 48000 -ac 2 -i <fifo>).
- audioInputIndex 0, audioFifo null. Growing VC-3/HEVC builders already map
[0:v] and audioMap 0🅰️0?; with one AVI input that resolves to 0:v / 0:a.
Validated on zampp3 against the LIVE deltacast-0-0 slot: fc_pipe --avi | ffmpeg
-f avi -i pipe:0 -> dnxhd/pcm_s24le MXF gives 360 video / 360 audio packets in
6.006s (no stall at 2 frames). A synthetic 1 kHz sine slot through the same
path yields mean_volume -9 dB / max -6 dB, proving the muxer carries real audio
end-to-end (the live SDI input currently carries no embedded audio, so the
bridge's silence fallback reads -91 dB — upstream of the muxer).
63 lines
2.6 KiB
CMake
63 lines
2.6 KiB
CMake
cmake_minimum_required(VERSION 3.16)
|
|
project(framecache C)
|
|
|
|
set(CMAKE_C_STANDARD 11)
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -O2")
|
|
|
|
# ── libmicrohttpd ────────────────────────────────────────────────────
|
|
find_library(MHD_LIB microhttpd REQUIRED)
|
|
find_path(MHD_INCLUDE microhttpd.h REQUIRED)
|
|
include_directories(${MHD_INCLUDE})
|
|
|
|
# ── framecache server ────────────────────────────────────────────────
|
|
add_executable(framecache
|
|
src/framecache.c
|
|
src/slot.c
|
|
src/registry.c
|
|
)
|
|
target_link_libraries(framecache ${MHD_LIB} rt pthread)
|
|
|
|
# ── fc_client static library (used by bridges + test) ───────────────
|
|
add_library(fc_client STATIC
|
|
client/fc_client.c
|
|
src/slot.c # client needs fc_slot_shm_size / fc_frame_at
|
|
)
|
|
target_include_directories(fc_client PUBLIC src client)
|
|
target_link_libraries(fc_client rt pthread)
|
|
|
|
# ── net_ingest — network source (RTMP/SRT) → framecache slot ─────────
|
|
# Spawned by node-agent when a network recorder starts.
|
|
# Decodes the network stream to raw UYVY422 via ffmpeg and writes frames
|
|
# into a framecache slot, giving capture-manager the same fc_pipe consumer
|
|
# interface as SDI sources.
|
|
add_executable(net_ingest
|
|
src/net_ingest.c
|
|
src/slot.c
|
|
)
|
|
target_include_directories(net_ingest PRIVATE src)
|
|
target_link_libraries(net_ingest rt pthread)
|
|
install(TARGETS net_ingest DESTINATION bin)
|
|
|
|
# ── fc_pipe — slot → stdout adapter (used by capture-manager.js) ─────
|
|
# Spawned by capture-manager as a child process; writes raw UYVY422
|
|
# frames from a framecache slot to stdout so ffmpeg reads them as
|
|
# rawvideo pipe input. Multiple fc_pipe instances on the same slot
|
|
# each get an independent cursor — zero-copy fan-out.
|
|
add_executable(fc_pipe
|
|
client/fc_pipe.c
|
|
)
|
|
target_link_libraries(fc_pipe fc_client pthread)
|
|
target_include_directories(fc_pipe PRIVATE src client)
|
|
|
|
# ── test consumer (dev utility) ──────────────────────────────────────
|
|
if(BUILD_TESTS)
|
|
add_executable(fc_test_consumer
|
|
client/fc_test_consumer.c
|
|
)
|
|
target_link_libraries(fc_test_consumer fc_client)
|
|
target_include_directories(fc_test_consumer PRIVATE src client)
|
|
endif()
|
|
|
|
install(TARGETS framecache fc_pipe DESTINATION bin)
|
|
install(FILES client/fc_client.h src/slot.h DESTINATION include/framecache)
|
|
install(TARGETS fc_client DESTINATION lib)
|