[FFmpeg-devel,v2] avcodec/amfenc: Add support for on-demand key frames

Message ID 20240908201058.541-1-aicommander@gmail.com
State New
Headers
Series [FFmpeg-devel,v2] avcodec/amfenc: Add support for on-demand key frames |

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Cameron Gutman Sept. 8, 2024, 8:07 p.m. UTC
v2: Use forced_idr option instead of AV_FRAME_FLAG_KEY
Signed-off-by: Cameron Gutman <aicommander@gmail.com>
---

In response to the feedback from Anton on the previous patch, I opted to
switch to a new codec option plus pict_type rather than triggering IDR
frames on AV_FRAME_FLAG_KEY. However, I chose to use 'forced_idr' as the
name rather than 'forced-idr' to match the rest of the AMF options which
all use '_' instead of '-'.

---
 libavcodec/amfenc.c      | 41 +++++++++++++++++++++++++++++++++++++++-
 libavcodec/amfenc.h      |  1 +
 libavcodec/amfenc_av1.c  |  1 +
 libavcodec/amfenc_h264.c |  1 +
 libavcodec/amfenc_hevc.c |  1 +
 5 files changed, 44 insertions(+), 1 deletion(-)
  

Comments

Dmitrii Ovchinnikov Sept. 11, 2024, 1:48 p.m. UTC | #1
Thanks for your contribution.  It looks good to me. If there are no
comments, I'll merge it in a few days.
  

Patch

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 41eaef9758..9d16345b30 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -766,11 +766,50 @@  int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
         switch (avctx->codec->id) {
         case AV_CODEC_ID_H264:
             AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud);
+            switch (frame->pict_type) {
+            case AV_PICTURE_TYPE_I:
+                if (ctx->forced_idr) {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1);
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1);
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR);
+                } else {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I);
+                }
+                break;
+            case AV_PICTURE_TYPE_P:
+                AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P);
+                break;
+            case AV_PICTURE_TYPE_B:
+                AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B);
+                break;
+            }
             break;
         case AV_CODEC_ID_HEVC:
             AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud);
+            switch (frame->pict_type) {
+            case AV_PICTURE_TYPE_I:
+                if (ctx->forced_idr) {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1);
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR);
+                } else {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I);
+                }
+                break;
+            case AV_PICTURE_TYPE_P:
+                AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P);
+                break;
+            }
+            break;
+        case AV_CODEC_ID_AV1:
+            if (frame->pict_type == AV_PICTURE_TYPE_I) {
+                if (ctx->forced_idr) {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1);
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY);
+                } else {
+                    AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY);
+                }
+            }
             break;
-        //case AV_CODEC_ID_AV1 not supported
         default:
             break;
         }
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index d985d01bb1..0f2abcbd82 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -114,6 +114,7 @@  typedef struct AmfContext {
     int                 max_b_frames;
     int                 qvbr_quality_level;
     int                 hw_high_motion_quality_boost;
+    int                 forced_idr;
 
     // HEVC - specific options
 
diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c
index 2a7a782063..b40d54f70c 100644
--- a/libavcodec/amfenc_av1.c
+++ b/libavcodec/amfenc_av1.c
@@ -116,6 +116,7 @@  static const AVOption options[] = {
     { "none",                   "no adaptive quantization",         0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE }, 0, 0, VE, .unit = "adaptive_quantisation_mode" },
     { "caq",                    "context adaptive quantization",    0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ }, 0, 0, VE, .unit = "adaptive_quantisation_mode" },
 
+    { "forced_idr",             "Force I frames to be IDR frames",  OFFSET(forced_idr),   AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
 
     { "align",                  "alignment mode",                           OFFSET(align),                          AV_OPT_TYPE_INT,     {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS },         AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS, VE, .unit = "align" },
     { "64x16",                  "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY               }, 0, 0, VE, .unit = "align" },
diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c
index 8edd39c633..959be9eab6 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -133,6 +133,7 @@  static const AVOption options[] = {
     { "me_half_pel",    "Enable ME Half Pixel",                 OFFSET(me_half_pel),   AV_OPT_TYPE_BOOL,  { .i64 = -1 }, -1, 1, VE },
     { "me_quarter_pel", "Enable ME Quarter Pixel",              OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,  { .i64 = -1 }, -1, 1, VE },
 
+    { "forced_idr",     "Force I frames to be IDR frames",      OFFSET(forced_idr)   , AV_OPT_TYPE_BOOL,  { .i64 = 0  }, 0, 1, VE },
     { "aud",            "Inserts AU Delimiter NAL unit",        OFFSET(aud)          , AV_OPT_TYPE_BOOL,  { .i64 = -1 }, -1, 1, VE },
 
 
diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c
index 4898824f3a..fc25dcec1a 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -100,6 +100,7 @@  static const AVOption options[] = {
     { "me_half_pel",    "Enable ME Half Pixel",                     OFFSET(me_half_pel),   AV_OPT_TYPE_BOOL,{ .i64 = -1 },  -1, 1, VE },
     { "me_quarter_pel", "Enable ME Quarter Pixel ",                 OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = -1 },  -1, 1, VE },
 
+    { "forced_idr",     "Force I frames to be IDR frames",          OFFSET(forced_idr)    ,AV_OPT_TYPE_BOOL,{ .i64 = 0  }, 0, 1, VE },
     { "aud",            "Inserts AU Delimiter NAL unit",            OFFSET(aud)           ,AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE },