PR #22446 opened by Jun Zhao (mypopydev) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22446 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22446.patch
The recent five commits focus on improving the robustness and correctness of FFmpeg's documentation examples (doc/examples). These fixes address issues such as incorrect API usage (replacing avformat_close_input with avio_closep/avformat_free_context for output contexts), cross-platform data corruption (enforcing binary mode for raw YUV input on Windows), unsafe file operations (adding missing NULL checks for fopen), and silent error suppression (fixing invalid fwrite return value checks). Additionally, they correct logic for dumping multi-plane raw video frames (NV12/P010) by respecting per-plane line sizes, preventing buffer over-reads and corrupted output. Collectively, these changes enhance the reliability and safety of the example code From 97b5ea3aa6fa74acd131fb6ebb9caec8e2d2fc72 Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Sun, 8 Mar 2026 22:44:17 +0800 Subject: [PATCH 1/5] doc/examples: fix output context cleanup in transcode examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit avformat_close_input() is designed for input format contexts only. Using it on output contexts is API misuse — it accesses iformat (which is NULL for output contexts) and does not follow the correct output cleanup path. Replace with the proper pattern already used in remux.c and transcode.c: avio_closep() to close the IO handle, followed by avformat_free_context() to free the format context. Signed-off-by: Jun Zhao <[email protected]> --- doc/examples/qsv_transcode.c | 4 +++- doc/examples/vaapi_transcode.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c index c3f507e8e6..b4230e7a38 100644 --- a/doc/examples/qsv_transcode.c +++ b/doc/examples/qsv_transcode.c @@ -430,7 +430,9 @@ int main(int argc, char **argv) end: avformat_close_input(&ifmt_ctx); - avformat_close_input(&ofmt_ctx); + if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) + avio_closep(&ofmt_ctx->pb); + avformat_free_context(ofmt_ctx); avcodec_free_context(&decoder_ctx); avcodec_free_context(&encoder_ctx); av_buffer_unref(&hw_device_ctx); diff --git a/doc/examples/vaapi_transcode.c b/doc/examples/vaapi_transcode.c index e1b7a43883..dba37d4bcb 100644 --- a/doc/examples/vaapi_transcode.c +++ b/doc/examples/vaapi_transcode.c @@ -294,7 +294,9 @@ int main(int argc, char **argv) end: avformat_close_input(&ifmt_ctx); - avformat_close_input(&ofmt_ctx); + if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) + avio_closep(&ofmt_ctx->pb); + avformat_free_context(ofmt_ctx); avcodec_free_context(&decoder_ctx); avcodec_free_context(&encoder_ctx); av_buffer_unref(&hw_device_ctx); -- 2.52.0 From 369353b42ae024ffc610f7955d983b75bd64640a Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Sun, 8 Mar 2026 22:48:46 +0800 Subject: [PATCH 2/5] doc/examples/vaapi_encode: open raw YUV input in binary mode fopen() with "r" opens the file in text mode, which on Windows translates \r\n to \n, corrupting raw NV12 pixel data. Use "rb" to open in binary mode, matching the output file which already uses "w+b". Signed-off-by: Jun Zhao <[email protected]> --- doc/examples/vaapi_encode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/vaapi_encode.c b/doc/examples/vaapi_encode.c index 330a6524ef..d4381776ca 100644 --- a/doc/examples/vaapi_encode.c +++ b/doc/examples/vaapi_encode.c @@ -118,7 +118,7 @@ int main(int argc, char *argv[]) height = atoi(argv[2]); size = width * height; - if (!(fin = fopen(argv[3], "r"))) { + if (!(fin = fopen(argv[3], "rb"))) { fprintf(stderr, "Fail to open input file : %s\n", strerror(errno)); return -1; } -- 2.52.0 From a52862ee5e94cf7cc6c6e6b395313fc3d558e687 Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Sun, 8 Mar 2026 22:49:38 +0800 Subject: [PATCH 3/5] doc/examples/decode_video: check fopen return value in pgm_save pgm_save() passes the FILE pointer from fopen() directly to fprintf() and fwrite() without a NULL check. If fopen() fails (e.g. permission denied or disk full), this causes a NULL pointer dereference and crash. Signed-off-by: Jun Zhao <[email protected]> --- doc/examples/decode_video.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/examples/decode_video.c b/doc/examples/decode_video.c index b0b3a6ae92..9d92ebbe9c 100644 --- a/doc/examples/decode_video.c +++ b/doc/examples/decode_video.c @@ -42,7 +42,11 @@ static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, FILE *f; int i; - f = fopen(filename,"wb"); + f = fopen(filename, "wb"); + if (!f) { + fprintf(stderr, "Could not open %s\n", filename); + return; + } fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255); for (i = 0; i < ysize; i++) fwrite(buf + i * wrap, 1, xsize, f); -- 2.52.0 From b8ec487b4c7f3aaa02024f99dfaad5002cababb8 Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Sun, 8 Mar 2026 22:52:51 +0800 Subject: [PATCH 4/5] doc/examples/hw_decode: fix fwrite error check fwrite() returns size_t (unsigned), so comparing its return value with < 0 is always false and write errors are silently ignored. Check against the expected byte count instead. Signed-off-by: Jun Zhao <[email protected]> --- doc/examples/hw_decode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index ce18814760..7c73d59d93 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -132,8 +132,9 @@ static int decode_write(AVCodecContext *avctx, AVPacket *packet) goto fail; } - if ((ret = fwrite(buffer, 1, size, output_file)) < 0) { + if (fwrite(buffer, 1, size, output_file) != size) { fprintf(stderr, "Failed to dump raw data.\n"); + ret = -1; goto fail; } -- 2.52.0 From 52f08b0eb36de01e01d5635d3057d3346275de9d Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Sun, 8 Mar 2026 22:55:37 +0800 Subject: [PATCH 5/5] doc/examples/qsv_decode: fix raw frame dump for chroma planes The output loop used sw_frame->width as the write size for all planes. This is only correct for NV12 where the interleaved UV plane happens to have the same byte width as the Y plane. For other pixel formats (e.g. YUV420P where U/V planes are half width, or P010 where samples are 2 bytes), the output would be corrupted. Use av_image_get_linesize() to compute the correct byte width for each plane based on the actual pixel format. Signed-off-by: Jun Zhao <[email protected]> --- doc/examples/qsv_decode.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/examples/qsv_decode.c b/doc/examples/qsv_decode.c index ec91109480..cdfde89652 100644 --- a/doc/examples/qsv_decode.c +++ b/doc/examples/qsv_decode.c @@ -39,6 +39,7 @@ #include <libavutil/error.h> #include <libavutil/hwcontext.h> #include <libavutil/hwcontext_qsv.h> +#include <libavutil/imgutils.h> #include <libavutil/mem.h> static int get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) @@ -88,9 +89,16 @@ static int decode_packet(AVCodecContext *decoder_ctx, goto fail; } - for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++) - for (j = 0; j < (sw_frame->height >> (i > 0)); j++) - avio_write(output_ctx, sw_frame->data[i] + j * sw_frame->linesize[i], sw_frame->width); + for (i = 0; i < FF_ARRAY_ELEMS(sw_frame->data) && sw_frame->data[i]; i++) { + int h = sw_frame->height >> (i > 0); + int linesize = av_image_get_linesize(sw_frame->format, sw_frame->width, i); + if (linesize < 0) { + ret = linesize; + goto fail; + } + for (j = 0; j < h; j++) + avio_write(output_ctx, sw_frame->data[i] + j * sw_frame->linesize[i], linesize); + } fail: av_frame_unref(sw_frame); -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
