@@ -186,6 +186,7 @@ struct amf_base {
186
186
bool bframes_supported = false ;
187
187
bool first_update = true ;
188
188
bool roi_supported = false ;
189
+ bool force_idr;
189
190
190
191
inline amf_base (bool fallback) : fallback(fallback) {}
191
192
virtual ~amf_base () = default ;
@@ -714,6 +715,26 @@ static void amf_encode_base(amf_base *enc, AMFSurface *amf_surf, encoder_packet
714
715
715
716
*received_packet = false ;
716
717
718
+ /* -------------------------------------- */
719
+ /* Force an IDR or Key frame if signalled */
720
+
721
+ if (enc->force_idr ) {
722
+ enc->force_idr = false ;
723
+ switch (enc->codec ) {
724
+ case amf_codec_type::AVC:
725
+ amf_surf->SetProperty (AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR);
726
+ break ;
727
+ case amf_codec_type::HEVC:
728
+ amf_surf->SetProperty (AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE,
729
+ AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR);
730
+ break ;
731
+ case amf_codec_type::AV1:
732
+ amf_surf->SetProperty (AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE,
733
+ AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY);
734
+ break ;
735
+ }
736
+ }
737
+
717
738
bool waiting = true ;
718
739
while (waiting) {
719
740
/* ----------------------------------- */
@@ -1316,8 +1337,14 @@ static inline int get_avc_profile(obs_data_t *settings)
1316
1337
return AMF_VIDEO_ENCODER_PROFILE_HIGH;
1317
1338
}
1318
1339
1319
- static void amf_avc_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t qp)
1340
+ static bool amf_avc_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t qp)
1320
1341
{
1342
+ /* Return a flag indicating if a pipeline flush is needed. Changing the bitrate (or any other dynamic property)
1343
+ * is updated with the next SubmitInput() call. For CBR mode, flushing the pipeline is not needed and could
1344
+ * cause unaligned IDRs in an encoder group.
1345
+ */
1346
+ bool pipeline_flush = true ;
1347
+
1321
1348
if (rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP &&
1322
1349
rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR) {
1323
1350
set_avc_property (enc, TARGET_BITRATE, bitrate);
@@ -1326,13 +1353,15 @@ static void amf_avc_update_data(amf_base *enc, int rc, int64_t bitrate, int64_t
1326
1353
1327
1354
if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) {
1328
1355
set_avc_property (enc, FILLER_DATA_ENABLE, true );
1356
+ pipeline_flush = false ;
1329
1357
}
1330
1358
} else {
1331
1359
set_avc_property (enc, QP_I, qp);
1332
1360
set_avc_property (enc, QP_P, qp);
1333
1361
set_avc_property (enc, QP_B, qp);
1334
1362
set_avc_property (enc, QVBR_QUALITY_LEVEL, qp);
1335
1363
}
1364
+ return pipeline_flush;
1336
1365
}
1337
1366
1338
1367
static bool amf_avc_update (void *data, obs_data_t *settings)
@@ -1350,15 +1379,19 @@ try {
1350
1379
int rc = get_avc_rate_control (rc_str);
1351
1380
AMF_RESULT res = AMF_OK;
1352
1381
1353
- amf_avc_update_data (enc, rc, bitrate * 1000 , qp);
1354
-
1355
- res = enc->amf_encoder ->Flush ();
1356
- if (res != AMF_OK)
1357
- throw amf_error (" AMFComponent::Flush failed" , res);
1382
+ if ( amf_avc_update_data (enc, rc, bitrate * 1000 , qp)) {
1383
+ // Flush the pipeline only when needed
1384
+ res = enc->amf_encoder ->Flush ();
1385
+ if (res != AMF_OK)
1386
+ throw amf_error (" AMFComponent::Flush failed" , res);
1358
1387
1359
- res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
1360
- if (res != AMF_OK)
1361
- throw amf_error (" AMFComponent::ReInit failed" , res);
1388
+ res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
1389
+ if (res != AMF_OK)
1390
+ throw amf_error (" AMFComponent::ReInit failed" , res);
1391
+ } else {
1392
+ // A pipeline flush was not requested, however force an IDR frame to align with the bitrate change.
1393
+ enc->force_idr = true ;
1394
+ }
1362
1395
1363
1396
return true ;
1364
1397
@@ -1738,8 +1771,14 @@ static inline int get_hevc_rate_control(const char *rc_str)
1738
1771
return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR;
1739
1772
}
1740
1773
1741
- static void amf_hevc_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t qp)
1774
+ static bool amf_hevc_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t qp)
1742
1775
{
1776
+ /* Return a flag indicating if a pipeline flush is needed. Changing the bitrate (or any other dynamic property)
1777
+ * is updated with the next SubmitInput() call. For CBR mode, flushing the pipeline is not needed and could
1778
+ * cause unaligned IDRs in an encoder group.
1779
+ */
1780
+ bool pipeline_flush = true ;
1781
+
1743
1782
if (rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP &&
1744
1783
rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR) {
1745
1784
set_hevc_property (enc, TARGET_BITRATE, bitrate);
@@ -1748,12 +1787,14 @@ static void amf_hevc_update_data(amf_base *enc, int rc, int64_t bitrate, int64_t
1748
1787
1749
1788
if (rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR) {
1750
1789
set_hevc_property (enc, FILLER_DATA_ENABLE, true );
1790
+ pipeline_flush = false ;
1751
1791
}
1752
1792
} else {
1753
1793
set_hevc_property (enc, QP_I, qp);
1754
1794
set_hevc_property (enc, QP_P, qp);
1755
1795
set_hevc_property (enc, QVBR_QUALITY_LEVEL, qp);
1756
1796
}
1797
+ return pipeline_flush;
1757
1798
}
1758
1799
1759
1800
static bool amf_hevc_update (void *data, obs_data_t *settings)
@@ -1771,15 +1812,19 @@ try {
1771
1812
int rc = get_hevc_rate_control (rc_str);
1772
1813
AMF_RESULT res = AMF_OK;
1773
1814
1774
- amf_hevc_update_data (enc, rc, bitrate * 1000 , qp);
1775
-
1776
- res = enc->amf_encoder ->Flush ();
1777
- if (res != AMF_OK)
1778
- throw amf_error (" AMFComponent::Flush failed" , res);
1815
+ if ( amf_hevc_update_data (enc, rc, bitrate * 1000 , qp)) {
1816
+ // Flush the pipeline only when needed
1817
+ res = enc->amf_encoder ->Flush ();
1818
+ if (res != AMF_OK)
1819
+ throw amf_error (" AMFComponent::Flush failed" , res);
1779
1820
1780
- res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
1781
- if (res != AMF_OK)
1782
- throw amf_error (" AMFComponent::ReInit failed" , res);
1821
+ res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
1822
+ if (res != AMF_OK)
1823
+ throw amf_error (" AMFComponent::ReInit failed" , res);
1824
+ } else {
1825
+ // A pipeline flush was not requested, however force an IDR frame to align with the bitrate change.
1826
+ enc->force_idr = true ;
1827
+ }
1783
1828
1784
1829
return true ;
1785
1830
@@ -2095,8 +2140,14 @@ static inline int get_av1_profile(obs_data_t *settings)
2095
2140
return AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN;
2096
2141
}
2097
2142
2098
- static void amf_av1_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t cq_value)
2143
+ static bool amf_av1_update_data (amf_base *enc, int rc, int64_t bitrate, int64_t cq_value)
2099
2144
{
2145
+ /* Return a flag indicating if a pipeline flush is needed. Changing the bitrate (or any other dynamic property)
2146
+ * is updated with the next SubmitInput() call. For CBR mode, flushing the pipeline is not needed and could
2147
+ * cause unaligned IDRs in an encoder group.
2148
+ */
2149
+ bool pipeline_flush = true ;
2150
+
2100
2151
if (rc != AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP &&
2101
2152
rc != AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR) {
2102
2153
set_av1_property (enc, TARGET_BITRATE, bitrate);
@@ -2105,6 +2156,7 @@ static void amf_av1_update_data(amf_base *enc, int rc, int64_t bitrate, int64_t
2105
2156
2106
2157
if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) {
2107
2158
set_av1_property (enc, FILLER_DATA, true );
2159
+ pipeline_flush = false ;
2108
2160
} else if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR ||
2109
2161
rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) {
2110
2162
set_av1_property (enc, PEAK_BITRATE, bitrate * 1.5 );
@@ -2115,6 +2167,7 @@ static void amf_av1_update_data(amf_base *enc, int rc, int64_t bitrate, int64_t
2115
2167
set_av1_property (enc, Q_INDEX_INTRA, qp);
2116
2168
set_av1_property (enc, Q_INDEX_INTER, qp);
2117
2169
}
2170
+ return pipeline_flush;
2118
2171
}
2119
2172
2120
2173
static bool amf_av1_update (void *data, obs_data_t *settings)
@@ -2132,15 +2185,19 @@ try {
2132
2185
int rc = get_av1_rate_control (rc_str);
2133
2186
AMF_RESULT res = AMF_OK;
2134
2187
2135
- amf_av1_update_data (enc, rc, bitrate * 1000 , cq_level);
2136
-
2137
- res = enc->amf_encoder ->Flush ();
2138
- if (res != AMF_OK)
2139
- throw amf_error (" AMFComponent::Flush failed" , res);
2188
+ if ( amf_av1_update_data (enc, rc, bitrate * 1000 , cq_level)) {
2189
+ // Flush the pipeline only when needed
2190
+ res = enc->amf_encoder ->Flush ();
2191
+ if (res != AMF_OK)
2192
+ throw amf_error (" AMFComponent::Flush failed" , res);
2140
2193
2141
- res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
2142
- if (res != AMF_OK)
2143
- throw amf_error (" AMFComponent::ReInit failed" , res);
2194
+ res = enc->amf_encoder ->ReInit (enc->cx , enc->cy );
2195
+ if (res != AMF_OK)
2196
+ throw amf_error (" AMFComponent::ReInit failed" , res);
2197
+ } else {
2198
+ // A pipeline flush was not requested, however force an IDR frame to align with the bitrate change.
2199
+ enc->force_idr = true ;
2200
+ }
2144
2201
2145
2202
return true ;
2146
2203
0 commit comments