vaapi_encode: Support forcing IDR frames via AVFrame.pict_type
authorMark Thompson <sw@jkqxz.net>
Mon, 12 Dec 2016 21:25:28 +0000 (21:25 +0000)
committerMark Thompson <sw@jkqxz.net>
Wed, 11 Jan 2017 23:03:58 +0000 (23:03 +0000)
libavcodec/vaapi_encode.c
libavcodec/vaapi_encode.h

index c670ae6..c93bfcc 100644 (file)
@@ -590,6 +590,10 @@ static int vaapi_encode_step(AVCodecContext *avctx,
     } else if (ctx->issue_mode == ISSUE_MODE_MAXIMISE_THROUGHPUT) {
         int activity;
 
+        // Run through the list of all available pictures repeatedly
+        // and issue the first one found which has all dependencies
+        // available (including previously-issued but not necessarily
+        // completed pictures).
         do {
             activity = 0;
             for (pic = ctx->pic_start; pic; pic = pic->next) {
@@ -605,9 +609,15 @@ static int vaapi_encode_step(AVCodecContext *avctx,
                 if (err < 0)
                     return err;
                 activity = 1;
+                // Start again from the beginning of the list,
+                // because issuing this picture may have satisfied
+                // forward dependencies of earlier ones.
+                break;
             }
         } while(activity);
 
+        // If we had a defined target for this step then it will
+        // always have been issued by now.
         if (target) {
             av_assert0(target->encode_issued && "broken dependencies?");
         }
@@ -639,8 +649,10 @@ static int vaapi_encode_get_next(AVCodecContext *avctx,
     if (!pic)
         return AVERROR(ENOMEM);
 
-    if (ctx->input_order == 0 || ctx->gop_counter >= avctx->gop_size) {
+    if (ctx->input_order == 0 || ctx->force_idr ||
+        ctx->gop_counter >= avctx->gop_size) {
         pic->type = PICTURE_TYPE_IDR;
+        ctx->force_idr = 0;
         ctx->gop_counter = 1;
         ctx->p_counter = 0;
     } else if (ctx->p_counter >= ctx->p_per_i) {
@@ -722,7 +734,7 @@ fail:
     return AVERROR(ENOMEM);
 }
 
-static int vaapi_encode_mangle_end(AVCodecContext *avctx)
+static int vaapi_encode_truncate_gop(AVCodecContext *avctx)
 {
     VAAPIEncodeContext *ctx = avctx->priv_data;
     VAAPIEncodePicture *pic, *last_pic, *next;
@@ -772,7 +784,7 @@ static int vaapi_encode_mangle_end(AVCodecContext *avctx)
         // mangle anything.
     }
 
-    av_log(avctx, AV_LOG_DEBUG, "Pictures at end of stream:");
+    av_log(avctx, AV_LOG_DEBUG, "Pictures ending truncated GOP:");
     for (pic = ctx->pic_start; pic; pic = pic->next) {
         av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")",
                picture_type_name[pic->type],
@@ -826,6 +838,13 @@ int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt,
         av_log(avctx, AV_LOG_DEBUG, "Encode frame: %ux%u (%"PRId64").\n",
                input_image->width, input_image->height, input_image->pts);
 
+        if (input_image->pict_type == AV_PICTURE_TYPE_I) {
+            err = vaapi_encode_truncate_gop(avctx);
+            if (err < 0)
+                goto fail;
+            ctx->force_idr = 1;
+        }
+
         err = vaapi_encode_get_next(avctx, &pic);
         if (err) {
             av_log(avctx, AV_LOG_ERROR, "Input setup failed: %d.\n", err);
@@ -854,7 +873,7 @@ int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt,
 
     } else {
         if (!ctx->end_of_stream) {
-            err = vaapi_encode_mangle_end(avctx);
+            err = vaapi_encode_truncate_gop(avctx);
             if (err < 0)
                 goto fail;
             ctx->end_of_stream = 1;
index e8ed4fd..2a72510 100644 (file)
@@ -192,6 +192,7 @@ typedef struct VAAPIEncodeContext {
     // Frame type decision.
     int p_per_i;
     int b_per_p;
+    int force_idr;
     int gop_counter;
     int p_counter;
     int end_of_stream;