Conversation
… error transcoding from MPEG-TS
…quick fix for mp4e tests
There was a problem hiding this comment.
Pull Request Overview
This PR migrates the codebase to use newer FFmpeg APIs, removing deprecated functions and updating to modern channel layout handling. The changes address deprecation warnings and prepare the code for compatibility with recent FFmpeg versions.
Key Changes
- Removed
libavresampledependency in favor oflibswresample - Migrated from deprecated channel layout APIs (
channel_layout,channels) to the newAVChannelLayoutstruct withch_layout - Updated I/O callback signatures to use
io_close2instead ofio_closeand addedconstqualifiers - Replaced deprecated struct fields:
frame_number→frame_num,pkt_duration→duration,coded_picture_numberremoved - Removed deprecated
avcodec_close()calls (now handled byavcodec_free_context()) - Improved error handling in MP4 validation to allow partial parsing
- Disabled flaky HLS tests and updated test data paths
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| rules.make | Removed libavresample from pkg-config dependencies |
| mp4e/mp4_test.go | Updated test data paths to use cmd/mez-validator/testdata |
| mp4e/mp4.go | Improved error handling to support partial MP4 parsing |
| live/lhr_tool_test.go | Disabled three flaky HLS tests due to unavailable manifest URLs |
| libavpipe/src/avpipe_xc.c | Migrated to new channel layout API, updated io_close2, replaced deprecated frame fields, added delay_moov flag |
| libavpipe/src/avpipe_utils.c | Updated dump functions to use ch_layout and frame_num |
| libavpipe/src/avpipe_mux.c | Changed io_close signature to return int and use io_close2 |
| libavpipe/src/avpipe_io.{h,c} | Updated elv_io_close signature to return int for io_close2 compatibility |
| libavpipe/src/avpipe_format.c | Replaced deprecated fields: channels → ch_layout.nb_channels, pkt_duration → duration |
| libavpipe/src/avpipe_filters.c | Migrated audio filter channel layout handling to new API |
| libavpipe/src/avpipe_copy_mpegts.c | Updated MPEG-TS encoder channel layout handling |
| libavpipe/include/avpipe_xc.h | Changed AVCodec pointer to const, updated writer callback signature |
| exc/elv_xc.c | Added const qualifier to writer functions, migrated channel layout parsing |
| exc/elv_mux.c | Added const qualifier to writer functions |
| avpipe_test.go | Added profile and level parameters to TestABRMuxing |
| avpipe_errors.go | Removed libavresample cgo directive |
| avpipe.go | Removed libavresample, added channel layout helper, implemented ChannelLayout with proper memory management |
| avpipe.c | Updated writer callback signatures with const qualifiers |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func TestParseSegment(t *testing.T) { | ||
| f := "testdata/vfsegment.mp4" | ||
| //f := "testdata/vfsegment.mp4" // something wrong with this file | ||
| f := "../cmd/mez-validator/testdata/video-mez-segment-1.mp4" |
There was a problem hiding this comment.
Brittle test data path dependency. The test now depends on files in ../cmd/mez-validator/testdata/ which creates a fragile cross-package dependency. If the cmd/mez-validator package is moved or its testdata reorganized, this test will break. Consider either: 1) copying necessary test files to mp4e/testdata/, 2) using a relative path that's less likely to break, or 3) documenting this dependency clearly if it's intentional.
| // TODO validate the segments together as one file | ||
| func TestCheckSegments(t *testing.T) { | ||
| directory := "testdata" | ||
| directory := "../cmd/mez-validator/testdata" |
There was a problem hiding this comment.
Brittle test data path dependency. Similar to TestParseSegment, this test now depends on ../cmd/mez-validator/testdata/ which creates a fragile cross-package dependency. Consider the same alternatives: copying test files locally, using a more stable path, or documenting the dependency.
| int64_t h = *((int64_t *)(inctx->opaque)); | ||
| int64_t fd = *(int64_t *)outctx->opaque; | ||
| int bwritten = AVPipeWriteOutput(h, fd, buf, buf_size); | ||
| int bwritten = AVPipeWriteOutput(h, fd, (uint8_t *)buf, buf_size); |
There was a problem hiding this comment.
Type casting away const qualifier. The function signature was changed to accept const uint8_t *buf but here it's cast back to uint8_t *. This defeats the purpose of the const correctness improvement and could lead to undefined behavior if AVPipeWriteOutput modifies the buffer. Either change AVPipeWriteOutput to accept const uint8_t * or reconsider the const qualifier in the signature.
| int bwritten = AVPipeWriteOutput(h, fd, (uint8_t *)buf, buf_size); | |
| int bwritten = AVPipeWriteOutput(h, fd, buf, buf_size); |
| xcparams_t *xcparams = (inctx != NULL) ? inctx->params : NULL; | ||
| int64_t fd = *(int64_t *)outctx->opaque; | ||
| int bwritten = AVPipeWriteMuxOutput(fd, buf, buf_size); | ||
| int bwritten = AVPipeWriteMuxOutput(fd, (uint8_t *)buf, buf_size); |
There was a problem hiding this comment.
Type casting away const qualifier. Similar to line 647, the const qualifier is being cast away. This defeats the purpose of the const correctness improvement in the function signature. Either AVPipeWriteMuxOutput should accept const uint8_t * or reconsider the const qualifier.
| int bwritten = AVPipeWriteMuxOutput(fd, (uint8_t *)buf, buf_size); | |
| int bwritten = AVPipeWriteMuxOutput(fd, buf, buf_size); |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| goavpipe.Log.Error("InSeeker SEEK_END", "offset", offset, "whence", whence, "input_size", h.input.Size(), "about_to_call_seek", true) | ||
| } | ||
|
|
||
| // FFmpeg 7.1: Handle AVSEEK_SIZE (0x10000 = 65536) - return file size directly | ||
| if int(whence) == 65536 { // AVSEEK_SIZE | ||
| size := h.input.Size() | ||
| goavpipe.Log.Error("InSeeker AVSEEK_SIZE", "offset", offset, "whence", whence, "returning_size", size) | ||
| return size, nil | ||
| } | ||
|
|
||
| n, err := h.input.Seek(int64(offset), int(whence)) | ||
| if int(whence) == 2 { // io.SeekEnd | ||
| goavpipe.Log.Error("InSeeker SEEK_END result", "offset", offset, "whence", whence, "returned_pos", n, "error", err) |
There was a problem hiding this comment.
Using Log.Error() for debug/trace messages is incorrect. Lines 269, 275, and 281 log normal control flow information at ERROR level. These should use Log.Debug() or Log.Trace() instead, as they're informational messages for debugging FFmpeg 7.1 behavior, not actual errors.
| goavpipe.Log.Error("InSeeker SEEK_END", "offset", offset, "whence", whence, "input_size", h.input.Size(), "about_to_call_seek", true) | |
| } | |
| // FFmpeg 7.1: Handle AVSEEK_SIZE (0x10000 = 65536) - return file size directly | |
| if int(whence) == 65536 { // AVSEEK_SIZE | |
| size := h.input.Size() | |
| goavpipe.Log.Error("InSeeker AVSEEK_SIZE", "offset", offset, "whence", whence, "returning_size", size) | |
| return size, nil | |
| } | |
| n, err := h.input.Seek(int64(offset), int(whence)) | |
| if int(whence) == 2 { // io.SeekEnd | |
| goavpipe.Log.Error("InSeeker SEEK_END result", "offset", offset, "whence", whence, "returned_pos", n, "error", err) | |
| goavpipe.Log.Debug("InSeeker SEEK_END", "offset", offset, "whence", whence, "input_size", h.input.Size(), "about_to_call_seek", true) | |
| } | |
| // FFmpeg 7.1: Handle AVSEEK_SIZE (0x10000 = 65536) - return file size directly | |
| if int(whence) == 65536 { // AVSEEK_SIZE | |
| size := h.input.Size() | |
| goavpipe.Log.Debug("InSeeker AVSEEK_SIZE", "offset", offset, "whence", whence, "returning_size", size) | |
| return size, nil | |
| } | |
| n, err := h.input.Seek(int64(offset), int(whence)) | |
| if int(whence) == 2 { // io.SeekEnd | |
| goavpipe.Log.Debug("InSeeker SEEK_END result", "offset", offset, "whence", whence, "returned_pos", n, "error", err) |
| // FFmpeg 7.1: Use size callback to fake stream size instead of deprecated 'written' field | ||
| // This tells FFmpeg the total size of the stream for avio_size() calls | ||
| if (inctx->sz > 0) { | ||
| avioctx->seek = in_handlers->avpipe_seeker; // Ensure seeker handles SEEK_END for size | ||
| } |
There was a problem hiding this comment.
The comment says 'Use size callback to fake stream size' but the code is setting avioctx->seek, not implementing a size callback. The avioctx->seek is likely already set earlier, and this doesn't replace the deprecated avioctx->written behavior. The proper approach would be to ensure the seeker callback handles AVSEEK_SIZE (whence=0x10000) as done in avpipe.go:273.
| int64_t h = *((int64_t *)(inctx->opaque)); | ||
| int64_t fd = *(int64_t *)outctx->opaque; | ||
| int bwritten = AVPipeWriteOutput(h, fd, buf, buf_size); | ||
| int bwritten = AVPipeWriteOutput(h, fd, (uint8_t *)buf, buf_size); |
There was a problem hiding this comment.
Casting away const (from 'const uint8_t *' to 'uint8_t *') violates the const contract and could lead to undefined behavior if AVPipeWriteOutput modifies the buffer. Either update AVPipeWriteOutput's signature to accept 'const uint8_t *', or document why this cast is safe.
| int bwritten = AVPipeWriteOutput(h, fd, (uint8_t *)buf, buf_size); | |
| int bwritten = AVPipeWriteOutput(h, fd, buf, buf_size); |
| 4. OutputHandler: is the output handler with Write/Seek/Close methods. An implementation of this | ||
| interface is needed by ffmpeg to write encoded streams properly. | ||
|
|
||
| TODO: Call C.free for every C.CString to not leak memory. |
There was a problem hiding this comment.
This TODO indicates a known memory leak issue where C.CString allocations are not being freed throughout the codebase. While line 983 correctly uses 'defer C.free(unsafe.Pointer(cName))', this suggests there may be other locations with leaks. This should be tracked and addressed systematically.
| TODO: Call C.free for every C.CString to not leak memory. | |
| // TODO [MEMORY LEAK]: For every allocation with C.CString, immediately defer C.free(unsafe.Pointer(...)) to avoid memory leaks. |
|
Moving to ffmpeg 8 instead |
https://github.com/eluv-io/avpipe/commits/peter/ffmpeg-7.1 is too messy due to merges from master
For this branch, keep all commits rebased on top of master.