Commit 17dd3f6d for libheif

commit 17dd3f6d7e09146b42c91534f6d19e79cfdf911a
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri Dec 19 10:08:25 2025 +0100

    [BSD3] pass sequence framerate through to encoders

diff --git a/libheif/api/libheif/heif_plugin.h b/libheif/api/libheif/heif_plugin.h
index c8af91e1..a45d2343 100644
--- a/libheif/api/libheif/heif_plugin.h
+++ b/libheif/api/libheif/heif_plugin.h
@@ -286,6 +286,7 @@ typedef struct heif_encoder_plugin

   heif_error (* start_sequence_encoding)(void* encoder, const heif_image* image,
                                          enum heif_image_input_class image_class,
+                                         uint32_t framerate_num, uint32_t framerate_denom,
                                          const heif_sequence_encoding_options* options);
   // TODO: is heif_sequence_encoding_options a good choice here?

diff --git a/libheif/codecs/avc_enc.cc b/libheif/codecs/avc_enc.cc
index 9c65405d..b985af76 100644
--- a/libheif/codecs/avc_enc.cc
+++ b/libheif/codecs/avc_enc.cc
@@ -121,13 +121,16 @@ Error Encoder_AVC::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&
                                          heif_encoder* encoder,
                                          const heif_sequence_encoding_options& options,
                                          heif_image_input_class input_class,
+                                         uint32_t framerate_num, uint32_t framerate_denom,
                                          uintptr_t frame_number)
 {
   heif_image c_api_image;
   c_api_image.image = image;

   if (!m_encoder_active) {
-    heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder, &c_api_image, input_class,
+    heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder, &c_api_image,
+                                                              input_class,
+                                                              framerate_num, framerate_denom,
                                                               &options);
     if (err.code) {
       return {
diff --git a/libheif/codecs/avc_enc.h b/libheif/codecs/avc_enc.h
index 77ff75ff..c63d406d 100644
--- a/libheif/codecs/avc_enc.h
+++ b/libheif/codecs/avc_enc.h
@@ -46,6 +46,7 @@ public:
                               heif_encoder* encoder,
                               const heif_sequence_encoding_options& options,
                               heif_image_input_class input_class,
+                              uint32_t framerate_num, uint32_t framerate_denom,
                               uintptr_t frame_number) override;

   Error encode_sequence_flush(heif_encoder* encoder) override;
diff --git a/libheif/codecs/avif_enc.cc b/libheif/codecs/avif_enc.cc
index 0160a76b..b47664d0 100644
--- a/libheif/codecs/avif_enc.cc
+++ b/libheif/codecs/avif_enc.cc
@@ -86,6 +86,7 @@ Error Encoder_AVIF::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&
                                     heif_encoder* encoder,
                                     const heif_sequence_encoding_options& options,
                                     heif_image_input_class input_class,
+                                    uint32_t framerate_num, uint32_t framerate_denom,
                                     uintptr_t frame_number)
 {
   // Box_av1C::configuration config;
@@ -101,6 +102,7 @@ Error Encoder_AVIF::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&
     heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder,
                                                               &c_api_image,
                                                               input_class,
+                                                              framerate_num, framerate_denom,
                                                               &options);
     if (err.code) {
       return {
diff --git a/libheif/codecs/avif_enc.h b/libheif/codecs/avif_enc.h
index 4a7eafe7..f704a4f8 100644
--- a/libheif/codecs/avif_enc.h
+++ b/libheif/codecs/avif_enc.h
@@ -48,6 +48,7 @@ public:
                                       heif_encoder* encoder,
                                       const heif_sequence_encoding_options& options,
                                       heif_image_input_class input_class,
+                                      uint32_t framerate_num, uint32_t framerate_denom,
                                       uintptr_t frame_number) override;

   Error encode_sequence_flush(heif_encoder* encoder) override;
diff --git a/libheif/codecs/encoder.h b/libheif/codecs/encoder.h
index 349d2b36..ba51d0e0 100644
--- a/libheif/codecs/encoder.h
+++ b/libheif/codecs/encoder.h
@@ -79,6 +79,7 @@ public:
                                       heif_encoder* encoder,
                                       const heif_sequence_encoding_options& options,
                                       heif_image_input_class input_class,
+                                      uint32_t framerate_num, uint32_t framerate_denom,
                                       uintptr_t frame_number) { return {}; }

   virtual Error encode_sequence_flush(heif_encoder* encoder) { return {}; }
diff --git a/libheif/codecs/hevc_enc.cc b/libheif/codecs/hevc_enc.cc
index 90d5e550..ada5b89d 100644
--- a/libheif/codecs/hevc_enc.cc
+++ b/libheif/codecs/hevc_enc.cc
@@ -116,13 +116,16 @@ Error Encoder_HEVC::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&
                                           heif_encoder* encoder,
                                           const heif_sequence_encoding_options& options,
                                           heif_image_input_class input_class,
+                                          uint32_t framerate_num, uint32_t framerate_denom,
                                           uintptr_t frame_number)
 {
   heif_image c_api_image;
   c_api_image.image = image;

   if (!m_encoder_active) {
-    heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder, &c_api_image, input_class,
+    heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder, &c_api_image,
+                                                              input_class,
+                                                              framerate_num, framerate_denom,
                                                               &options);
     if (err.code) {
       return {
diff --git a/libheif/codecs/hevc_enc.h b/libheif/codecs/hevc_enc.h
index 79c38c09..20c7cfaa 100644
--- a/libheif/codecs/hevc_enc.h
+++ b/libheif/codecs/hevc_enc.h
@@ -46,6 +46,7 @@ public:
                               heif_encoder* encoder,
                               const heif_sequence_encoding_options& options,
                               heif_image_input_class input_class,
+                              uint32_t framerate_num, uint32_t framerate_denom,
                               uintptr_t frame_number) override;

   Error encode_sequence_flush(heif_encoder* encoder) override;
diff --git a/libheif/codecs/jpeg2000_enc.h b/libheif/codecs/jpeg2000_enc.h
index dfff2623..a535bab7 100644
--- a/libheif/codecs/jpeg2000_enc.h
+++ b/libheif/codecs/jpeg2000_enc.h
@@ -48,6 +48,7 @@ public:
                                       heif_encoder* encoder,
                                       const heif_sequence_encoding_options& options,
                                       heif_image_input_class input_class,
+                                      uint32_t framerate_num, uint32_t framerate_denom,
                                       uintptr_t frame_number) override
   {
     heif_encoding_options dummy_options{};
diff --git a/libheif/codecs/jpeg_enc.h b/libheif/codecs/jpeg_enc.h
index 62c1cdc6..ed8b8cdd 100644
--- a/libheif/codecs/jpeg_enc.h
+++ b/libheif/codecs/jpeg_enc.h
@@ -51,6 +51,7 @@ public:
                                       heif_encoder* encoder,
                                       const heif_sequence_encoding_options& options,
                                       heif_image_input_class input_class,
+                                      uint32_t framerate_num, uint32_t framerate_denom,
                                       uintptr_t frame_number) override
   {
     heif_encoding_options dummy_options{};
diff --git a/libheif/codecs/uncompressed/unc_enc.h b/libheif/codecs/uncompressed/unc_enc.h
index c61285a3..01d7eeeb 100644
--- a/libheif/codecs/uncompressed/unc_enc.h
+++ b/libheif/codecs/uncompressed/unc_enc.h
@@ -48,6 +48,7 @@ public:
                                       heif_encoder* encoder,
                                       const heif_sequence_encoding_options& options,
                                       heif_image_input_class input_class,
+                                      uint32_t framerate_num, uint32_t framerate_denom,
                                       uintptr_t frame_number) override
   {
     heif_encoding_options dummy_options{};
diff --git a/libheif/codecs/vvc_enc.cc b/libheif/codecs/vvc_enc.cc
index 948a94ed..db21faf1 100644
--- a/libheif/codecs/vvc_enc.cc
+++ b/libheif/codecs/vvc_enc.cc
@@ -120,6 +120,7 @@ Error Encoder_VVC::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&
                                          heif_encoder* encoder,
                                          const heif_sequence_encoding_options& options,
                                          heif_image_input_class input_class,
+                                         uint32_t framerate_num, uint32_t framerate_denom,
                                          uintptr_t frame_number)
 {
   heif_image c_api_image;
@@ -127,6 +128,7 @@ Error Encoder_VVC::encode_sequence_frame(const std::shared_ptr<HeifPixelImage>&

   if (!m_encoder_active) {
     heif_error err = encoder->plugin->start_sequence_encoding(encoder->encoder, &c_api_image, input_class,
+                                                              framerate_num, framerate_denom,
                                                               &options);
     if (err.code) {
       return {
diff --git a/libheif/codecs/vvc_enc.h b/libheif/codecs/vvc_enc.h
index 324620a2..40b3b24f 100644
--- a/libheif/codecs/vvc_enc.h
+++ b/libheif/codecs/vvc_enc.h
@@ -49,6 +49,7 @@ public:
                               heif_encoder* encoder,
                               const heif_sequence_encoding_options& options,
                               heif_image_input_class input_class,
+                              uint32_t framerate_num, uint32_t framerate_denom,
                               uintptr_t frame_number) override;

   Error encode_sequence_flush(heif_encoder* encoder) override;
diff --git a/libheif/plugins/encoder_aom.cc b/libheif/plugins/encoder_aom.cc
index 0d7db404..6e58a8aa 100644
--- a/libheif/plugins/encoder_aom.cc
+++ b/libheif/plugins/encoder_aom.cc
@@ -859,6 +859,7 @@ chroma_info get_chroma_info(heif_chroma chroma,

 static heif_error aom_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                                      enum heif_image_input_class input_class,
+                                                     uint32_t framerate_num, uint32_t framerate_denom,
                                                      const heif_sequence_encoding_options* options,
                                                      bool image_sequence)
 {
@@ -1014,6 +1015,9 @@ static heif_error aom_start_sequence_encoding_intern(void* encoder_raw, const he
     cfg.monochrome = 1;
   }

+  cfg.g_timebase.num = static_cast<int>(framerate_num);
+  cfg.g_timebase.den = static_cast<int>(framerate_denom);
+
   // --- initialize codec

   aom_codec_flags_t encoder_flags = 0;
@@ -1115,9 +1119,10 @@ static heif_error aom_start_sequence_encoding_intern(void* encoder_raw, const he

 static heif_error aom_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
-  return aom_start_sequence_encoding_intern(encoder_raw, image, input_class, options,
+  return aom_start_sequence_encoding_intern(encoder_raw, image, input_class, framerate_num, framerate_denom, options,
     true);
 }

@@ -1309,7 +1314,7 @@ static heif_error aom_encode_image(void* encoder_raw, const heif_image* image,
                                    heif_image_input_class input_class)
 {
   heif_error err;
-  err = aom_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = aom_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_jpeg.cc b/libheif/plugins/encoder_jpeg.cc
index 633c12ae..7dde0e43 100644
--- a/libheif/plugins/encoder_jpeg.cc
+++ b/libheif/plugins/encoder_jpeg.cc
@@ -446,6 +446,7 @@ heif_error jpeg_get_compressed_data(void* encoder_raw, uint8_t** data, int* size

 heif_error jpeg_start_sequence_encoding(void* encoder, const heif_image* image,
                                        enum heif_image_input_class image_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
   return heif_error_ok;
diff --git a/libheif/plugins/encoder_kvazaar.cc b/libheif/plugins/encoder_kvazaar.cc
index 1150aff1..3f5fae0e 100644
--- a/libheif/plugins/encoder_kvazaar.cc
+++ b/libheif/plugins/encoder_kvazaar.cc
@@ -453,6 +453,7 @@ std::unique_ptr<T, D> make_guard(T* ptr, D&& deleter) {

 static heif_error kvazaar_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                                          enum heif_image_input_class input_class,
+                                                         uint32_t framerate_num, uint32_t framerate_denom,
                                                          const heif_sequence_encoding_options* options,
                                                          bool image_sequence)
 {
@@ -503,6 +504,9 @@ static heif_error kvazaar_start_sequence_encoding_intern(void* encoder_raw, cons
   uint32_t encoded_width, encoded_height;
   kvazaar_query_encoded_size(encoder_raw, input_width, input_height, &encoded_width, &encoded_height);

+  config->framerate_num = framerate_num;
+  config->framerate_denom = framerate_denom;
+
   if (isGreyscale) {
     config->input_format = KVZ_FORMAT_P400;
   }
@@ -558,8 +562,6 @@ static heif_error kvazaar_start_sequence_encoding_intern(void* encoder_raw, cons
     // TODO
     /*
     config->target_bitrate = options->sequence_bitrate;
-    config->framerate_num = options->framerate_num;
-    config->framerate_den = options->framerate_den;
     */

     if (options->keyframe_distance_max) {
@@ -893,9 +895,10 @@ static heif_error kvazaar_get_compressed_data2(void* encoder_raw, uint8_t** data

 static heif_error kvazaar_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                                   enum heif_image_input_class input_class,
+                                                  uint32_t framerate_num, uint32_t framerate_denom,
                                                   const heif_sequence_encoding_options* options)
 {
-  return kvazaar_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return kvazaar_start_sequence_encoding_intern(encoder_raw, image, input_class, framerate_num, framerate_denom, options, true);
 }


@@ -903,7 +906,7 @@ static heif_error kvazaar_encode_image(void* encoder_raw, const heif_image* imag
                                        heif_image_input_class input_class)
 {
   heif_error err;
-  err = kvazaar_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = kvazaar_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_openjpeg.cc b/libheif/plugins/encoder_openjpeg.cc
index 4282ca77..3bbbe0b2 100644
--- a/libheif/plugins/encoder_openjpeg.cc
+++ b/libheif/plugins/encoder_openjpeg.cc
@@ -598,6 +598,7 @@ void opj_query_encoded_size(void* encoder, uint32_t input_width, uint32_t input_

 heif_error opj_start_sequence_encoding(void* encoder, const heif_image* image,
                                        enum heif_image_input_class image_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
   return heif_error_ok;
diff --git a/libheif/plugins/encoder_openjph.cc b/libheif/plugins/encoder_openjph.cc
index 07c1d4e0..284e7176 100644
--- a/libheif/plugins/encoder_openjph.cc
+++ b/libheif/plugins/encoder_openjph.cc
@@ -853,6 +853,7 @@ const char* ojph_plugin_name()

 heif_error ojph_start_sequence_encoding(void* encoder, const heif_image* image,
                                        enum heif_image_input_class image_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
   return heif_error_ok;
diff --git a/libheif/plugins/encoder_rav1e.cc b/libheif/plugins/encoder_rav1e.cc
index bfe1f529..641618b7 100644
--- a/libheif/plugins/encoder_rav1e.cc
+++ b/libheif/plugins/encoder_rav1e.cc
@@ -503,6 +503,7 @@ void rav1e_query_input_colorspace2(void* encoder_raw, heif_colorspace* colorspac

 heif_error rav1e_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options,
                                        bool image_sequence)
 {
@@ -562,6 +563,8 @@ heif_error rav1e_start_sequence_encoding_intern(void* encoder_raw, const heif_im
     return heif_error_codec_library_error;
   }

+  rav1e_config_set_time_base(rav1eConfig.get(), RaRational{framerate_num, framerate_denom});
+
   if (!image_sequence) {
     if (rav1e_config_parse(rav1eConfig.get(), "still_picture", "true") == -1) {
       return heif_error_codec_library_error;
@@ -654,9 +657,11 @@ heif_error rav1e_start_sequence_encoding_intern(void* encoder_raw, const heif_im

 heif_error rav1e_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
-  return rav1e_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return rav1e_start_sequence_encoding_intern(encoder_raw, image, input_class,
+                                              framerate_num, framerate_denom, options, true);
 }


@@ -807,7 +812,7 @@ heif_error rav1e_encode_image(void* encoder_raw, const heif_image* image,
                               heif_image_input_class input_class)
 {
   heif_error err;
-  err = rav1e_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = rav1e_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_svt.cc b/libheif/plugins/encoder_svt.cc
index 83fa4bc3..03d87ca1 100644
--- a/libheif/plugins/encoder_svt.cc
+++ b/libheif/plugins/encoder_svt.cc
@@ -690,6 +690,7 @@ void svt_query_encoded_size(void* encoder_raw, uint32_t input_width, uint32_t in

 static heif_error svt_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                                      enum heif_image_input_class input_class,
+                                                     uint32_t framerate_num, uint32_t framerate_denom,
                                                      const heif_sequence_encoding_options* options,
                                                      bool image_sequence)
 {
@@ -869,6 +870,9 @@ static heif_error svt_start_sequence_encoding_intern(void* encoder_raw, const he
     svt_config.profile = HIGH_PROFILE;
   }

+  svt_config.frame_rate_numerator = framerate_num;
+  svt_config.frame_rate_denominator = framerate_denom;
+
   res = svt_av1_enc_set_parameter(svt_encoder, &svt_config);
   if (res == EB_ErrorBadParameter) {
     return heif_error_codec_library_error;
@@ -1165,9 +1169,11 @@ heif_error svt_get_compressed_data(void* encoder_raw, uint8_t** data, int* size,

 static heif_error svt_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                               enum heif_image_input_class input_class,
+                                              uint32_t framerate_num, uint32_t framerate_denom,
                                               const heif_sequence_encoding_options* options)
 {
-  return svt_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return svt_start_sequence_encoding_intern(encoder_raw, image, input_class,
+                                            framerate_num, framerate_denom, options, true);
 }


@@ -1175,7 +1181,7 @@ heif_error svt_encode_image(void* encoder_raw, const heif_image* image,
                             heif_image_input_class input_class)
 {
   heif_error err;
-  err = svt_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = svt_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_uncompressed.cc b/libheif/plugins/encoder_uncompressed.cc
index 29091c86..05ab2391 100644
--- a/libheif/plugins/encoder_uncompressed.cc
+++ b/libheif/plugins/encoder_uncompressed.cc
@@ -292,6 +292,7 @@ heif_error uncompressed_get_compressed_data(void* encoder_raw, uint8_t** data, i

 heif_error uncompressed_start_sequence_encoding(void* encoder, const heif_image* image,
                                                 enum heif_image_input_class image_class,
+                                                uint32_t framerate_num, uint32_t framerate_denom,
                                                 const heif_sequence_encoding_options* options)
 {
   return heif_error_ok;
diff --git a/libheif/plugins/encoder_uvg266.cc b/libheif/plugins/encoder_uvg266.cc
index 4bb4976e..90ff2d2e 100644
--- a/libheif/plugins/encoder_uvg266.cc
+++ b/libheif/plugins/encoder_uvg266.cc
@@ -459,6 +459,7 @@ static void copy_plane(uvg_pixel* out_p, size_t out_stride, const uint8_t* in_p,

 static heif_error uvg266_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                                         heif_image_input_class input_class,
+                                                        uint32_t framerate_num, uint32_t framerate_denom,
                                                         const heif_sequence_encoding_options* options,
                                                         bool image_sequence)
 {
@@ -592,6 +593,9 @@ static heif_error uvg266_start_sequence_encoding_intern(void* encoder_raw, const
     }
   }

+  config->framerate_num = framerate_num;
+  config->framerate_denom = framerate_denom;
+
   uint32_t encoded_width, encoded_height;
   uvg266_query_encoded_size(encoder_raw, input_width, input_height, &encoded_width, &encoded_height);

@@ -789,9 +793,11 @@ static heif_error uvg266_get_compressed_data_intern(void* encoder_raw, uint8_t**

 static heif_error uvg266_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                                  heif_image_input_class input_class,
+                                                 uint32_t framerate_num, uint32_t framerate_denom,
                                                  const heif_sequence_encoding_options* options)
 {
-  return uvg266_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return uvg266_start_sequence_encoding_intern(encoder_raw, image, input_class,
+                                               framerate_num, framerate_denom, options, true);
 }

 static heif_error uvg266_end_sequence_encoding(void* encoder_raw)
@@ -851,7 +857,7 @@ static heif_error uvg266_encode_image(void* encoder_raw, const heif_image* image
                                       heif_image_input_class input_class)
 {
   heif_error err;
-  err = uvg266_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = uvg266_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_vvenc.cc b/libheif/plugins/encoder_vvenc.cc
index 3ac7d3c4..778b68bf 100644
--- a/libheif/plugins/encoder_vvenc.cc
+++ b/libheif/plugins/encoder_vvenc.cc
@@ -428,6 +428,7 @@ static void copy_plane(int16_t* dst_p, size_t dst_stride, const uint8_t* in_p, s

 static heif_error vvenc_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                                        enum heif_image_input_class input_class,
+                                                       uint32_t framerate_num, uint32_t framerate_denom,
                                                        const heif_sequence_encoding_options* options,
                                                        bool image_sequence)
 {
@@ -455,8 +456,9 @@ static heif_error vvenc_start_sequence_encoding_intern(void* encoder_raw, const
   int encoder_quality = 63 - encoder->quality*63/100;

   int ret = vvenc_init_default(&params,
-                               encoder->encoded_width, encoder->encoded_height,
-                               25,  // TODO: framerate
+                               static_cast<int>(encoder->encoded_width),
+                               static_cast<int>(encoder->encoded_height),
+                               static_cast<int>((framerate_denom + framerate_num / 2) / framerate_num),
                                0,
                                encoder_quality,
                                VVENC_MEDIUM);
@@ -482,6 +484,9 @@ static heif_error vvenc_start_sequence_encoding_intern(void* encoder_raw, const
     params.m_internChromaFormat = VVENC_CHROMA_400;
   }

+  params.m_FrameRate = framerate_num;
+  params.m_FrameScale = framerate_denom;
+
   if (image_sequence) {
     if (options->keyframe_distance_max) {
       params.m_IntraPeriod = options->keyframe_distance_max;
@@ -750,7 +755,7 @@ static heif_error vvenc_encode_image(void* encoder_raw, const heif_image* image,
                                      heif_image_input_class input_class)
 {
   heif_error err;
-  err = vvenc_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = vvenc_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
@@ -767,9 +772,10 @@ static heif_error vvenc_encode_image(void* encoder_raw, const heif_image* image,

 static heif_error vvenc_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                                 enum heif_image_input_class input_class,
+                                                uint32_t framerate_num, uint32_t framerate_denom,
                                                 const heif_sequence_encoding_options* options)
 {
-  return vvenc_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return vvenc_start_sequence_encoding_intern(encoder_raw, image, input_class, framerate_num, framerate_denom, options, true);
 }


diff --git a/libheif/plugins/encoder_x264.cc b/libheif/plugins/encoder_x264.cc
index 247abcbd..bce1d522 100644
--- a/libheif/plugins/encoder_x264.cc
+++ b/libheif/plugins/encoder_x264.cc
@@ -710,6 +710,7 @@ static int rounded_size(int s)

 static heif_error x264_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                        heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options,
                                        bool image_sequence)
 {
@@ -742,9 +743,8 @@ static heif_error x264_start_sequence_encoding_intern(void* encoder_raw, const h
   }


-  param.i_fps_num = 1; // TODO: set to sequence parameters
-  param.i_fps_den = 1;
-
+  param.i_fps_num = framerate_num;
+  param.i_fps_den = framerate_denom;

   if (options) {
     if (options->keyframe_distance_min) {
@@ -943,9 +943,11 @@ static heif_error x264_start_sequence_encoding_intern(void* encoder_raw, const h

 static heif_error x264_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
-  return x264_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return x264_start_sequence_encoding_intern(encoder_raw, image, input_class,
+                                             framerate_num, framerate_denom, options, true);
 }


@@ -1060,7 +1062,7 @@ static heif_error x264_encode_image(void* encoder_raw, const heif_image* image,
                                     heif_image_input_class input_class)
 {
   heif_error err;
-  err = x264_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = x264_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/plugins/encoder_x265.cc b/libheif/plugins/encoder_x265.cc
index b5d8e510..1c35c0a4 100644
--- a/libheif/plugins/encoder_x265.cc
+++ b/libheif/plugins/encoder_x265.cc
@@ -747,6 +747,7 @@ void encoder_struct_x265::append_nal_packets(x265_nal* nals, uint32_t num_nals,

 static heif_error x265_start_sequence_encoding_intern(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options,
                                        bool image_sequence)
 {
@@ -800,10 +801,6 @@ static heif_error x265_start_sequence_encoding_intern(void* encoder_raw, const h
   }


-  param->fpsNum = 1; // TODO: set to sequence parameters
-  param->fpsDenom = 1;
-
-
   // x265 cannot encode images smaller than one CTU size
   // https://bitbucket.org/multicoreware/x265/issues/475/x265-does-not-allow-image-sizes-smaller
   // -> use smaller CTU sizes for very small images
@@ -1024,6 +1021,8 @@ static heif_error x265_start_sequence_encoding_intern(void* encoder_raw, const h
   param->sourceWidth = rounded_size(param->sourceWidth);
   param->sourceHeight = rounded_size(param->sourceHeight);

+  param->fpsNum = framerate_num;
+  param->fpsDenom = framerate_denom;

   encoder->bit_depth = bit_depth;

@@ -1050,9 +1049,11 @@ static heif_error x265_start_sequence_encoding_intern(void* encoder_raw, const h

 static heif_error x265_start_sequence_encoding(void* encoder_raw, const heif_image* image,
                                        enum heif_image_input_class input_class,
+                                       uint32_t framerate_num, uint32_t framerate_denom,
                                        const heif_sequence_encoding_options* options)
 {
-  return x265_start_sequence_encoding_intern(encoder_raw, image, input_class, options, true);
+  return x265_start_sequence_encoding_intern(encoder_raw, image, input_class,
+                                             framerate_num, framerate_denom, options, true);
 }


@@ -1188,7 +1189,7 @@ static heif_error x265_encode_image(void* encoder_raw, const heif_image* image,
                                     heif_image_input_class input_class)
 {
   heif_error err;
-  err = x265_start_sequence_encoding_intern(encoder_raw, image, input_class, nullptr, false);
+  err = x265_start_sequence_encoding_intern(encoder_raw, image, input_class, 1,25, nullptr, false);
   if (err.code) {
     return err;
   }
diff --git a/libheif/sequences/track_visual.cc b/libheif/sequences/track_visual.cc
index 1b905f0f..a8a238ed 100644
--- a/libheif/sequences/track_visual.cc
+++ b/libheif/sequences/track_visual.cc
@@ -512,6 +512,7 @@ Error Track_Visual::encode_image(std::shared_ptr<HeifPixelImage> image,
   Error encodeError = encoder->encode_sequence_frame(colorConvertedImage, h_encoder,
                                                      in_options ? *in_options : *local_dummy_options,
                                                      input_class,
+                                                     colorConvertedImage->get_sample_duration(), get_timescale(),
                                                      m_current_frame_nr);
   if (local_dummy_options) {
     heif_sequence_encoding_options_release(local_dummy_options);