v0.3.19
Fix OAK .h264 → .mp4 remux on PyAV ≥14
Field-reported on 0.3.18: the on-device H.264 encoder correctly delivered 30 fps on dual-OAK rigs, but the finalization step consistently failed, leaving the raw .h264 bitstream on disk instead of the expected .mp4. Two separate bugs were responsible.
Changes
- PyAV API drift.
output_container.add_stream(template=...)was removed in PyAV 14 in favour of a dedicatedadd_stream_from_template(template=...)method. 0.3.18 still called the old form, raisingTypeError: add_stream() takes at least 1 positional argument (0 given). Now using the new method with ahasattrfallback so PyAV 12–13 users keep working. - Timestamp synthesis. Raw Annex-B has no PTS/DTS — every packet surfaces with
dts=None. The previous code treateddts is Noneas an end-of-stream marker and skipped every real packet, so the output MP4 would have been empty even with the API call fixed. Real flush packets are detectable viasize == 0instead. The remux now synthesises a uniform 1/fps cadence at a ms-granularity timebase, matchingffmpeg -framerate N -i in.h264 -c copy out.mp4.
Added tests/integration/adapters/test_remux_h264_to_mp4.py that drives real PyAV + ffmpeg CLI to round-trip an Annex-B stream through the helper and verify the output is demuxable. The fake-av unit mock accepted any signature and so did not surface either regression — the new integration test closes the gap.
Recovering .h264 files from a 0.3.18 session
Raw bitstreams left behind by 0.3.18 are valid H.264 and can be repacked manually without re-encoding:
```bash
ffmpeg -framerate 30 -i oak_d.h264 -c copy oak_d.mp4
```
Upgrade
```bash
pip install --upgrade 'syncfield==0.3.19'
```