]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/avcodec.c
avcodec/avcodec: Use avcodec_close() on avcodec_open2() failure
[ffmpeg] / libavcodec / avcodec.c
index 13fe3d4ebfe026def264cda58b6ec2e2389fa2c6..882700f357a01b969e20d273f1993c1c35139730 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
@@ -101,13 +102,6 @@ static void unlock_avcodec(const AVCodec *codec)
         ff_mutex_unlock(&codec_mutex);
 }
 
-#if FF_API_LOCKMGR
-int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op))
-{
-    return 0;
-}
-#endif
-
 static int64_t get_bit_rate(AVCodecContext *ctx)
 {
     int64_t bit_rate;
@@ -141,7 +135,6 @@ static int64_t get_bit_rate(AVCodecContext *ctx)
 int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
 {
     int ret = 0;
-    int codec_init_ok = 0;
     AVDictionary *tmp = NULL;
     AVCodecInternal *avci;
 
@@ -187,15 +180,6 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
     }
     avctx->internal = avci;
 
-#if FF_API_OLD_ENCDEC
-    avci->to_free = av_frame_alloc();
-    avci->compat_decode_frame = av_frame_alloc();
-    avci->compat_encode_packet = av_packet_alloc();
-    if (!avci->to_free || !avci->compat_decode_frame || !avci->compat_encode_packet) {
-        ret = AVERROR(ENOMEM);
-        goto free_and_end;
-    }
-#endif
     avci->buffer_frame = av_frame_alloc();
     avci->buffer_pkt = av_packet_alloc();
     avci->es.in_frame = av_frame_alloc();
@@ -270,14 +254,6 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
         ret = AVERROR(EINVAL);
         goto free_and_end;
     }
-    if (av_codec_is_decoder(codec) &&
-        codec->type == AVMEDIA_TYPE_AUDIO &&
-        !(codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF) &&
-        avctx->channels == 0) {
-        av_log(avctx, AV_LOG_ERROR, "Decoder requires channel count but channels not set\n");
-        ret = AVERROR(EINVAL);
-        goto free_and_end;
-    }
 
     if (avctx->sample_rate < 0) {
         av_log(avctx, AV_LOG_ERROR, "Invalid sample rate: %d\n", avctx->sample_rate);
@@ -315,6 +291,13 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
         avctx->time_base.den = avctx->sample_rate;
     }
 
+    if (av_codec_is_encoder(avctx->codec))
+        ret = ff_encode_preinit(avctx);
+    else
+        ret = ff_decode_preinit(avctx);
+    if (ret < 0)
+        goto free_and_end;
+
     if (!HAVE_THREADS)
         av_log(avctx, AV_LOG_WARNING, "Warning: not compiled with thread support, using thread emulation\n");
 
@@ -336,21 +319,16 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
     if (!HAVE_THREADS && !(codec->caps_internal & FF_CODEC_CAP_AUTO_THREADS))
         avctx->thread_count = 1;
 
-    if (av_codec_is_encoder(avctx->codec))
-        ret = ff_encode_preinit(avctx);
-    else
-        ret = ff_decode_preinit(avctx);
-    if (ret < 0)
-        goto free_and_end;
-
-    if (   avctx->codec->init && (!(avctx->active_thread_type&FF_THREAD_FRAME)
-        || avci->frame_thread_encoder)) {
-        ret = avctx->codec->init(avctx);
-        if (ret < 0) {
-            codec_init_ok = -1;
-            goto free_and_end;
+    if (!(avctx->active_thread_type & FF_THREAD_FRAME) ||
+        avci->frame_thread_encoder) {
+        if (avctx->codec->init) {
+            ret = avctx->codec->init(avctx);
+            if (ret < 0) {
+                avci->needs_close = avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP;
+                goto free_and_end;
+            }
         }
-        codec_init_ok = 1;
+        avci->needs_close = 1;
     }
 
     ret=0;
@@ -401,50 +379,8 @@ end:
 
     return ret;
 free_and_end:
-    if (avctx->codec && avctx->codec->close &&
-        (codec_init_ok > 0 || (codec_init_ok < 0 &&
-         avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP)))
-        avctx->codec->close(avctx);
-
-    if (HAVE_THREADS && avci->thread_ctx)
-        ff_thread_free(avctx);
-
-    if (codec->priv_class && avctx->priv_data)
-        av_opt_free(avctx->priv_data);
-    av_opt_free(avctx);
-
-    if (av_codec_is_encoder(avctx->codec)) {
-#if FF_API_CODED_FRAME
-FF_DISABLE_DEPRECATION_WARNINGS
-        av_frame_free(&avctx->coded_frame);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-        av_freep(&avctx->extradata);
-        avctx->extradata_size = 0;
-    }
-
+    avcodec_close(avctx);
     av_dict_free(&tmp);
-    av_freep(&avctx->priv_data);
-    av_freep(&avctx->subtitle_header);
-
-#if FF_API_OLD_ENCDEC
-    av_frame_free(&avci->to_free);
-    av_frame_free(&avci->compat_decode_frame);
-    av_packet_free(&avci->compat_encode_packet);
-#endif
-    av_frame_free(&avci->buffer_frame);
-    av_packet_free(&avci->buffer_pkt);
-    av_packet_free(&avci->last_pkt_props);
-    av_fifo_freep(&avci->pkt_props);
-
-    av_packet_free(&avci->ds.in_pkt);
-    av_frame_free(&avci->es.in_frame);
-    av_bsf_free(&avci->bsf);
-
-    av_buffer_unref(&avci->pool);
-    av_freep(&avci);
-    avctx->internal = NULL;
-    avctx->codec = NULL;
     goto end;
 }
 
@@ -471,10 +407,6 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
     avci->draining_done = 0;
     avci->nb_draining_errors = 0;
     av_frame_unref(avci->buffer_frame);
-#if FF_API_OLD_ENCDEC
-    av_frame_unref(avci->compat_decode_frame);
-    av_packet_unref(avci->compat_encode_packet);
-#endif
     av_packet_unref(avci->buffer_pkt);
 
     av_packet_unref(avci->last_pkt_props);
@@ -499,13 +431,6 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
 
     if (av_codec_is_decoder(avctx->codec))
         av_bsf_flush(avci->bsf);
-
-#if FF_API_OLD_ENCDEC
-FF_DISABLE_DEPRECATION_WARNINGS
-    if (!avctx->refcounted_frames)
-        av_frame_unref(avci->to_free);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
 }
 
 void avsubtitle_free(AVSubtitle *sub)
@@ -535,45 +460,40 @@ av_cold int avcodec_close(AVCodecContext *avctx)
         return 0;
 
     if (avcodec_is_open(avctx)) {
+        AVCodecInternal *avci = avctx->internal;
+
         if (CONFIG_FRAME_THREAD_ENCODER &&
-            avctx->internal->frame_thread_encoder && avctx->thread_count > 1) {
+            avci->frame_thread_encoder && avctx->thread_count > 1) {
             ff_frame_thread_encoder_free(avctx);
         }
-        if (HAVE_THREADS && avctx->internal->thread_ctx)
+        if (HAVE_THREADS && avci->thread_ctx)
             ff_thread_free(avctx);
-        if (avctx->codec && avctx->codec->close)
+        if (avci->needs_close && avctx->codec->close)
             avctx->codec->close(avctx);
-        avctx->internal->byte_buffer_size = 0;
-        av_freep(&avctx->internal->byte_buffer);
-#if FF_API_OLD_ENCDEC
-        av_frame_free(&avctx->internal->to_free);
-        av_frame_free(&avctx->internal->compat_decode_frame);
-        av_packet_free(&avctx->internal->compat_encode_packet);
-#endif
-        av_frame_free(&avctx->internal->buffer_frame);
-        av_packet_free(&avctx->internal->buffer_pkt);
-        av_packet_unref(avctx->internal->last_pkt_props);
-        while (av_fifo_size(avctx->internal->pkt_props) >=
-               sizeof(*avctx->internal->last_pkt_props)) {
-            av_fifo_generic_read(avctx->internal->pkt_props,
-                                 avctx->internal->last_pkt_props,
-                                 sizeof(*avctx->internal->last_pkt_props),
-                                 NULL);
-            av_packet_unref(avctx->internal->last_pkt_props);
+        avci->byte_buffer_size = 0;
+        av_freep(&avci->byte_buffer);
+        av_frame_free(&avci->buffer_frame);
+        av_packet_free(&avci->buffer_pkt);
+        if (avci->pkt_props) {
+            while (av_fifo_size(avci->pkt_props) >= sizeof(*avci->last_pkt_props)) {
+                av_packet_unref(avci->last_pkt_props);
+                av_fifo_generic_read(avci->pkt_props, avci->last_pkt_props,
+                                     sizeof(*avci->last_pkt_props), NULL);
+            }
+            av_fifo_freep(&avci->pkt_props);
         }
-        av_packet_free(&avctx->internal->last_pkt_props);
-        av_fifo_freep(&avctx->internal->pkt_props);
+        av_packet_free(&avci->last_pkt_props);
 
-        av_packet_free(&avctx->internal->ds.in_pkt);
-        av_frame_free(&avctx->internal->es.in_frame);
+        av_packet_free(&avci->ds.in_pkt);
+        av_frame_free(&avci->es.in_frame);
 
-        av_buffer_unref(&avctx->internal->pool);
+        av_buffer_unref(&avci->pool);
 
         if (avctx->hwaccel && avctx->hwaccel->uninit)
             avctx->hwaccel->uninit(avctx);
-        av_freep(&avctx->internal->hwaccel_priv_data);
+        av_freep(&avci->hwaccel_priv_data);
 
-        av_bsf_free(&avctx->internal->bsf);
+        av_bsf_free(&avci->bsf);
 
         av_freep(&avctx->internal);
     }
@@ -592,84 +512,95 @@ av_cold int avcodec_close(AVCodecContext *avctx)
     av_freep(&avctx->priv_data);
     if (av_codec_is_encoder(avctx->codec)) {
         av_freep(&avctx->extradata);
-#if FF_API_CODED_FRAME
-FF_DISABLE_DEPRECATION_WARNINGS
-        av_frame_free(&avctx->coded_frame);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-    }
+        avctx->extradata_size = 0;
+    } else if (av_codec_is_decoder(avctx->codec))
+        av_freep(&avctx->subtitle_header);
+
     avctx->codec = NULL;
     avctx->active_thread_type = 0;
 
     return 0;
 }
 
+static const char *unknown_if_null(const char *str)
+{
+    return str ? str : "unknown";
+}
+
 void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
 {
     const char *codec_type;
     const char *codec_name;
     const char *profile = NULL;
+    AVBPrint bprint;
     int64_t bitrate;
     int new_line = 0;
     AVRational display_aspect_ratio;
     const char *separator = enc->dump_separator ? (const char *)enc->dump_separator : ", ";
+    const char *str;
 
     if (!buf || buf_size <= 0)
         return;
+    av_bprint_init_for_buffer(&bprint, buf, buf_size);
     codec_type = av_get_media_type_string(enc->codec_type);
     codec_name = avcodec_get_name(enc->codec_id);
     profile = avcodec_profile_name(enc->codec_id, enc->profile);
 
-    snprintf(buf, buf_size, "%s: %s", codec_type ? codec_type : "unknown",
-             codec_name);
+    av_bprintf(&bprint, "%s: %s", codec_type ? codec_type : "unknown",
+               codec_name);
     buf[0] ^= 'a' ^ 'A'; /* first letter in uppercase */
 
     if (enc->codec && strcmp(enc->codec->name, codec_name))
-        snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", enc->codec->name);
+        av_bprintf(&bprint, " (%s)", enc->codec->name);
 
     if (profile)
-        snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", profile);
+        av_bprintf(&bprint, " (%s)", profile);
     if (   enc->codec_type == AVMEDIA_TYPE_VIDEO
         && av_log_get_level() >= AV_LOG_VERBOSE
         && enc->refs)
-        snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                 ", %d reference frame%s",
-                 enc->refs, enc->refs > 1 ? "s" : "");
+        av_bprintf(&bprint, ", %d reference frame%s",
+                   enc->refs, enc->refs > 1 ? "s" : "");
 
     if (enc->codec_tag)
-        snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s / 0x%04X)",
-                 av_fourcc2str(enc->codec_tag), enc->codec_tag);
+        av_bprintf(&bprint, " (%s / 0x%04X)",
+                   av_fourcc2str(enc->codec_tag), enc->codec_tag);
 
     switch (enc->codec_type) {
     case AVMEDIA_TYPE_VIDEO:
         {
-            char detail[256] = "(";
+            unsigned len;
+
+            av_bprintf(&bprint, "%s%s", separator,
+                       enc->pix_fmt == AV_PIX_FMT_NONE ? "none" :
+                       unknown_if_null(av_get_pix_fmt_name(enc->pix_fmt)));
 
-            av_strlcat(buf, separator, buf_size);
+            av_bprint_chars(&bprint, '(', 1);
+            len = bprint.len;
+
+            /* The following check ensures that '(' has been written
+             * and therefore allows us to erase it if it turns out
+             * to be unnecessary. */
+            if (!av_bprint_is_complete(&bprint))
+                return;
 
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                 "%s", enc->pix_fmt == AV_PIX_FMT_NONE ? "none" :
-                     av_get_pix_fmt_name(enc->pix_fmt));
             if (enc->bits_per_raw_sample && enc->pix_fmt != AV_PIX_FMT_NONE &&
                 enc->bits_per_raw_sample < av_pix_fmt_desc_get(enc->pix_fmt)->comp[0].depth)
-                av_strlcatf(detail, sizeof(detail), "%d bpc, ", enc->bits_per_raw_sample);
-            if (enc->color_range != AVCOL_RANGE_UNSPECIFIED)
-                av_strlcatf(detail, sizeof(detail), "%s, ",
-                            av_color_range_name(enc->color_range));
+                av_bprintf(&bprint, "%d bpc, ", enc->bits_per_raw_sample);
+            if (enc->color_range != AVCOL_RANGE_UNSPECIFIED &&
+                (str = av_color_range_name(enc->color_range)))
+                av_bprintf(&bprint, "%s, ", str);
 
             if (enc->colorspace != AVCOL_SPC_UNSPECIFIED ||
                 enc->color_primaries != AVCOL_PRI_UNSPECIFIED ||
                 enc->color_trc != AVCOL_TRC_UNSPECIFIED) {
-                if (enc->colorspace != (int)enc->color_primaries ||
-                    enc->colorspace != (int)enc->color_trc) {
+                const char *col = unknown_if_null(av_color_space_name(enc->colorspace));
+                const char *pri = unknown_if_null(av_color_primaries_name(enc->color_primaries));
+                const char *trc = unknown_if_null(av_color_transfer_name(enc->color_trc));
+                if (strcmp(col, pri) || strcmp(col, trc)) {
                     new_line = 1;
-                    av_strlcatf(detail, sizeof(detail), "%s/%s/%s, ",
-                                av_color_space_name(enc->colorspace),
-                                av_color_primaries_name(enc->color_primaries),
-                                av_color_transfer_name(enc->color_trc));
+                    av_bprintf(&bprint, "%s/%s/%s, ", col, pri, trc);
                 } else
-                    av_strlcatf(detail, sizeof(detail), "%s, ",
-                                av_get_colorspace_name(enc->colorspace));
+                    av_bprintf(&bprint, "%s, ", col);
             }
 
             if (enc->field_order != AV_FIELD_UNKNOWN) {
@@ -683,119 +614,108 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
                 else if (enc->field_order == AV_FIELD_BT)
                     field_order = "bottom coded first (swapped)";
 
-                av_strlcatf(detail, sizeof(detail), "%s, ", field_order);
+                av_bprintf(&bprint, "%s, ", field_order);
             }
 
             if (av_log_get_level() >= AV_LOG_VERBOSE &&
-                enc->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
-                av_strlcatf(detail, sizeof(detail), "%s, ",
-                            av_chroma_location_name(enc->chroma_sample_location));
-
-            if (strlen(detail) > 1) {
-                detail[strlen(detail) - 2] = 0;
-                av_strlcatf(buf, buf_size, "%s)", detail);
+                enc->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED &&
+                (str = av_chroma_location_name(enc->chroma_sample_location)))
+                av_bprintf(&bprint, "%s, ", str);
+
+            if (len == bprint.len) {
+                bprint.str[len - 1] = '\0';
+                bprint.len--;
+            } else {
+                if (bprint.len - 2 < bprint.size) {
+                    /* Erase the last ", " */
+                    bprint.len -= 2;
+                    bprint.str[bprint.len] = '\0';
+                }
+                av_bprint_chars(&bprint, ')', 1);
             }
         }
 
         if (enc->width) {
-            av_strlcat(buf, new_line ? separator : ", ", buf_size);
-
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     "%dx%d",
-                     enc->width, enc->height);
+            av_bprintf(&bprint, "%s%dx%d", new_line ? separator : ", ",
+                       enc->width, enc->height);
 
             if (av_log_get_level() >= AV_LOG_VERBOSE &&
                 (enc->width != enc->coded_width ||
                  enc->height != enc->coded_height))
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         " (%dx%d)", enc->coded_width, enc->coded_height);
+                av_bprintf(&bprint, " (%dx%d)",
+                           enc->coded_width, enc->coded_height);
 
             if (enc->sample_aspect_ratio.num) {
                 av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
                           enc->width * (int64_t)enc->sample_aspect_ratio.num,
                           enc->height * (int64_t)enc->sample_aspect_ratio.den,
                           1024 * 1024);
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         " [SAR %d:%d DAR %d:%d]",
+                av_bprintf(&bprint, " [SAR %d:%d DAR %d:%d]",
                          enc->sample_aspect_ratio.num, enc->sample_aspect_ratio.den,
                          display_aspect_ratio.num, display_aspect_ratio.den);
             }
             if (av_log_get_level() >= AV_LOG_DEBUG) {
                 int g = av_gcd(enc->time_base.num, enc->time_base.den);
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", %d/%d",
-                         enc->time_base.num / g, enc->time_base.den / g);
+                av_bprintf(&bprint, ", %d/%d",
+                           enc->time_base.num / g, enc->time_base.den / g);
             }
         }
         if (encode) {
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", q=%d-%d", enc->qmin, enc->qmax);
+            av_bprintf(&bprint, ", q=%d-%d", enc->qmin, enc->qmax);
         } else {
             if (enc->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS)
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", Closed Captions");
+                av_bprintf(&bprint, ", Closed Captions");
             if (enc->properties & FF_CODEC_PROPERTY_LOSSLESS)
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", lossless");
+                av_bprintf(&bprint, ", lossless");
         }
         break;
     case AVMEDIA_TYPE_AUDIO:
-        av_strlcat(buf, separator, buf_size);
+        av_bprintf(&bprint, "%s", separator);
 
         if (enc->sample_rate) {
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     "%d Hz, ", enc->sample_rate);
+            av_bprintf(&bprint, "%d Hz, ", enc->sample_rate);
         }
-        av_get_channel_layout_string(buf + strlen(buf), buf_size - strlen(buf), enc->channels, enc->channel_layout);
-        if (enc->sample_fmt != AV_SAMPLE_FMT_NONE) {
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", %s", av_get_sample_fmt_name(enc->sample_fmt));
+        av_bprint_channel_layout(&bprint, enc->channels, enc->channel_layout);
+        if (enc->sample_fmt != AV_SAMPLE_FMT_NONE &&
+            (str = av_get_sample_fmt_name(enc->sample_fmt))) {
+            av_bprintf(&bprint, ", %s", str);
         }
         if (   enc->bits_per_raw_sample > 0
             && enc->bits_per_raw_sample != av_get_bytes_per_sample(enc->sample_fmt) * 8)
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     " (%d bit)", enc->bits_per_raw_sample);
+            av_bprintf(&bprint, " (%d bit)", enc->bits_per_raw_sample);
         if (av_log_get_level() >= AV_LOG_VERBOSE) {
             if (enc->initial_padding)
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", delay %d", enc->initial_padding);
+                av_bprintf(&bprint, ", delay %d", enc->initial_padding);
             if (enc->trailing_padding)
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", padding %d", enc->trailing_padding);
+                av_bprintf(&bprint, ", padding %d", enc->trailing_padding);
         }
         break;
     case AVMEDIA_TYPE_DATA:
         if (av_log_get_level() >= AV_LOG_DEBUG) {
             int g = av_gcd(enc->time_base.num, enc->time_base.den);
             if (g)
-                snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                         ", %d/%d",
-                         enc->time_base.num / g, enc->time_base.den / g);
+                av_bprintf(&bprint, ", %d/%d",
+                           enc->time_base.num / g, enc->time_base.den / g);
         }
         break;
     case AVMEDIA_TYPE_SUBTITLE:
         if (enc->width)
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", %dx%d", enc->width, enc->height);
+            av_bprintf(&bprint, ", %dx%d", enc->width, enc->height);
         break;
     default:
         return;
     }
     if (encode) {
         if (enc->flags & AV_CODEC_FLAG_PASS1)
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", pass 1");
+            av_bprintf(&bprint, ", pass 1");
         if (enc->flags & AV_CODEC_FLAG_PASS2)
-            snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", pass 2");
+            av_bprintf(&bprint, ", pass 2");
     }
     bitrate = get_bit_rate(enc);
     if (bitrate != 0) {
-        snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                 ", %"PRId64" kb/s", bitrate / 1000);
+        av_bprintf(&bprint, ", %"PRId64" kb/s", bitrate / 1000);
     } else if (enc->rc_max_rate > 0) {
-        snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                 ", max. %"PRId64" kb/s", enc->rc_max_rate / 1000);
+        av_bprintf(&bprint, ", max. %"PRId64" kb/s", enc->rc_max_rate / 1000);
     }
 }