]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/nvenc.c
avcodec/nvenc: Check capabilities for interlaced encoding
[ffmpeg] / libavcodec / nvenc.c
index 14ed0d22e60127bb50276a7a4285a862f0a28335..ae1612ff2a981b461bd5ec1cf427ec7e6a501e6b 100644 (file)
@@ -306,6 +306,14 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
         return AVERROR(ENOSYS);
     }
 
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_FIELD_ENCODING);
+    if (ret < 1 && avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
+        av_log(avctx, AV_LOG_VERBOSE,
+               "Interlaced encoding is not supported. Supported level: %d\n",
+               ret);
+        return AVERROR(ENOSYS);
+    }
+
     return 0;
 }
 
@@ -531,6 +539,14 @@ static av_cold void set_vbr(AVCodecContext *avctx)
         rc->maxQP.qpIntra = avctx->qmax;
 
         qp_inter_p = (avctx->qmax + 3 * avctx->qmin) / 4; // biased towards Qmin
+    } else if (avctx->qmin >= 0) {
+        rc->enableMinQP = 1;
+
+        rc->minQP.qpInterB = avctx->qmin;
+        rc->minQP.qpInterP = avctx->qmin;
+        rc->minQP.qpIntra = avctx->qmin;
+
+        qp_inter_p = avctx->qmin;
     } else {
         qp_inter_p = 26; // default to 26
     }
@@ -598,15 +614,9 @@ static void nvenc_override_rate_control(AVCodecContext *avctx)
         set_vbr(avctx);
         break;
     case NV_ENC_PARAMS_RC_CBR:
-        break;
     case NV_ENC_PARAMS_RC_2_PASS_QUALITY:
     case NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP:
-        if (!(ctx->flags & NVENC_LOWLATENCY)) {
-            av_log(avctx, AV_LOG_WARNING,
-                   "The multipass rate-control requires "
-                   "a low-latency preset.\n");
-            return;
-        }
+        break;
     }
 
     rc->rateControlMode = ctx->rc;
@@ -826,8 +836,6 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
     int res = 0;
     int dw, dh;
 
-    ctx->last_dts = AV_NOPTS_VALUE;
-
     ctx->encode_config.version = NV_ENC_CONFIG_VER;
     ctx->init_encode_params.version = NV_ENC_INITIALIZE_PARAMS_VER;
 
@@ -895,9 +903,8 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
         ctx->encode_config.gopLength = 1;
     }
 
-    /* when there're b frames, set dts offset */
-    if (ctx->encode_config.frameIntervalP >= 2)
-        ctx->last_dts = -2;
+    ctx->initial_pts[0] = AV_NOPTS_VALUE;
+    ctx->initial_pts[1] = AV_NOPTS_VALUE;
 
     nvenc_setup_rate_control(avctx);
 
@@ -1416,19 +1423,30 @@ static int nvenc_set_timestamp(AVCodecContext *avctx,
     NvencContext *ctx = avctx->priv_data;
 
     pkt->pts = params->outputTimeStamp;
-    pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list);
 
-    /* when there're b frame(s), set dts offset */
-    if (ctx->encode_config.frameIntervalP >= 2)
-        pkt->dts -= 1;
+    /* generate the first dts by linearly extrapolating the
+     * first two pts values to the past */
+    if (avctx->max_b_frames > 0 && !ctx->first_packet_output &&
+        ctx->initial_pts[1] != AV_NOPTS_VALUE) {
+        int64_t ts0 = ctx->initial_pts[0], ts1 = ctx->initial_pts[1];
+        int64_t delta;
+
+        if ((ts0 < 0 && ts1 > INT64_MAX + ts0) ||
+            (ts0 > 0 && ts1 < INT64_MIN + ts0))
+            return AVERROR(ERANGE);
+        delta = ts1 - ts0;
+
+        if ((delta < 0 && ts0 > INT64_MAX + delta) ||
+            (delta > 0 && ts0 < INT64_MIN + delta))
+            return AVERROR(ERANGE);
+        pkt->dts = ts0 - delta;
 
-    if (pkt->dts > pkt->pts)
-        pkt->dts = pkt->pts;
+        ctx->first_packet_output = 1;
+        return 0;
+    }
 
-    if (ctx->last_dts != AV_NOPTS_VALUE && pkt->dts <= ctx->last_dts)
-        pkt->dts = ctx->last_dts + 1;
+    pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list);
 
-    ctx->last_dts = pkt->dts;
     return 0;
 }
 
@@ -1548,6 +1566,12 @@ static int output_ready(AVCodecContext *avctx, int flush)
     NvencContext *ctx = avctx->priv_data;
     int nb_ready, nb_pending;
 
+    /* when B-frames are enabled, we wait for two initial timestamps to
+     * calculate the first dts */
+    if (!flush && avctx->max_b_frames > 0 &&
+        (ctx->initial_pts[0] == AV_NOPTS_VALUE || ctx->initial_pts[1] == AV_NOPTS_VALUE))
+        return 0;
+
     nb_ready   = av_fifo_size(ctx->output_surface_ready_queue)   / sizeof(NvencSurface*);
     nb_pending = av_fifo_size(ctx->output_surface_queue)         / sizeof(NvencSurface*);
     if (flush)
@@ -1599,7 +1623,6 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 
         pic_params.encodePicFlags = 0;
         pic_params.inputTimeStamp = frame->pts;
-        pic_params.inputDuration = 0;
 
         nvenc_codec_specific_pic_params(avctx, &pic_params);
     } else {
@@ -1614,6 +1637,11 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     if (frame) {
         av_fifo_generic_write(ctx->output_surface_queue, &inSurf, sizeof(inSurf), NULL);
         timestamp_queue_enqueue(ctx->timestamp_list, frame->pts);
+
+        if (ctx->initial_pts[0] == AV_NOPTS_VALUE)
+            ctx->initial_pts[0] = frame->pts;
+        else if (ctx->initial_pts[1] == AV_NOPTS_VALUE)
+            ctx->initial_pts[1] = frame->pts;
     }
 
     /* all the pending buffers are now ready for output */