X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fqsvenc_h264.c;h=4600831f20070863632c250c60a12079103b6c32;hb=06d69a2d225ae0db433b62f0fa537b06e29b0db5;hp=0e5a26cd1ff2ec2646a667f5ca2fbb658d2d7dcf;hpb=cde68661bfa5a3049c08e79f1e38a3df597f18d8;p=ffmpeg diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 0e5a26cd1ff..4600831f200 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -40,10 +40,75 @@ typedef struct QSVH264EncContext { QSVEncContext qsv; } QSVH264EncContext; +static int qsv_h264_set_encode_ctrl(AVCodecContext *avctx, + const AVFrame *frame, mfxEncodeCtrl* enc_ctrl) +{ + AVFrameSideData *side_data = NULL; + QSVH264EncContext *qh264 = avctx->priv_data; + QSVEncContext *q = &qh264->qsv; + + if (q->a53_cc && frame) { + side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC); + if (side_data) { + + int sei_payload_size = 0; + mfxU8* sei_data = NULL; + mfxPayload* payload = NULL; + + sei_payload_size = side_data->size + 13; + + sei_data = av_mallocz(sei_payload_size); + if (!sei_data) { + av_log(avctx, AV_LOG_ERROR, "No memory for CC, skipping...\n"); + return AVERROR(ENOMEM); + } + + // SEI header + sei_data[0] = 4; + sei_data[1] = sei_payload_size - 2; // size of SEI data + + // country code + sei_data[2] = 181; + sei_data[3] = 0; + sei_data[4] = 49; + + // ATSC_identifier - using 'GA94' only + AV_WL32(sei_data + 5, + MKTAG('G', 'A', '9', '4')); + sei_data[9] = 3; + sei_data[10] = + ((side_data->size/3) & 0x1f) | 0xC0; + + sei_data[11] = 0xFF; // reserved + + memcpy(sei_data + 12, side_data->data, side_data->size); + + sei_data[side_data->size+12] = 255; + + payload = av_mallocz(sizeof(mfxPayload)); + if (!payload) { + av_log(avctx, AV_LOG_ERROR, "No memory, skipping captions\n"); + av_freep(&sei_data); + return AVERROR(ENOMEM); + } + payload->BufSize = side_data->size + 13; + payload->NumBit = payload->BufSize * 8; + payload->Type = 4; + payload->Data = sei_data; + + enc_ctrl->NumExtParam = 0; + enc_ctrl->NumPayload = 1; + enc_ctrl->Payload[0] = payload; + } + } + return 0; +} + static av_cold int qsv_enc_init(AVCodecContext *avctx) { QSVH264EncContext *q = avctx->priv_data; + q->qsv.set_encode_ctrl_cb = qsv_h264_set_encode_ctrl; return ff_qsv_enc_init(avctx, &q->qsv); } @@ -65,13 +130,14 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(QSVH264EncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE }, + QSV_COMMON_OPTS + { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, - { "avbr_accuracy", "Accuracy of the AVBR ratecontrol", OFFSET(qsv.avbr_accuracy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, - { "avbr_convergence", "Convergence of the AVBR ratecontrol", OFFSET(qsv.avbr_convergence), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "pic_timing_sei", "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, + { "single_sei_nal_unit", "Put all the SEI messages into one NALU", OFFSET(qsv.single_sei_nal_unit), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, + { "max_dec_frame_buffering", "Maximum number of frames buffered in the DPB", OFFSET(qsv.max_dec_frame_buffering), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE }, -#if QSV_VERSION_ATLEAST(1,7) +#if QSV_HAVE_LA { "look_ahead", "Use VBR algorithm with look ahead", OFFSET(qsv.look_ahead), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, { "look_ahead_depth", "Depth of look ahead in number frames", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE }, #endif @@ -83,21 +149,26 @@ static const AVOption options[] = { { "2x" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_2x }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, #endif + { "int_ref_type", "Intra refresh type", OFFSET(qsv.int_ref_type), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE, "int_ref_type" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .flags = VE, "int_ref_type" }, + { "vertical", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .flags = VE, "int_ref_type" }, + { "int_ref_cycle_size", "Number of frames in the intra refresh cycle", OFFSET(qsv.int_ref_cycle_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE }, + { "int_ref_qp_delta", "QP difference for the refresh MBs", OFFSET(qsv.int_ref_qp_delta), AV_OPT_TYPE_INT, { .i64 = INT16_MIN }, INT16_MIN, INT16_MAX, VE }, + { "recovery_point_sei", "Insert recovery point SEI messages", OFFSET(qsv.recovery_point_sei), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, + + { "trellis", "Trellis quantization", OFFSET(qsv.trellis), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, UINT_MAX, VE, "trellis" }, + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_OFF }, .flags = VE, "trellis" }, + { "I", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_I }, .flags = VE, "trellis" }, + { "P", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_P }, .flags = VE, "trellis" }, + { "B", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_B }, .flags = VE, "trellis" }, + { "profile", NULL, OFFSET(qsv.profile), AV_OPT_TYPE_INT, { .i64 = MFX_PROFILE_UNKNOWN }, 0, INT_MAX, VE, "profile" }, { "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, VE, "profile" }, { "baseline", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, { "main" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, { "high" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_HIGH }, INT_MIN, INT_MAX, VE, "profile" }, - { "preset", NULL, OFFSET(qsv.preset), AV_OPT_TYPE_INT, { .i64 = MFX_TARGETUSAGE_BALANCED }, MFX_TARGETUSAGE_BEST_QUALITY, MFX_TARGETUSAGE_BEST_SPEED, VE, "preset" }, - { "veryfast", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_SPEED }, INT_MIN, INT_MAX, VE, "preset" }, - { "faster", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_6 }, INT_MIN, INT_MAX, VE, "preset" }, - { "fast", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_5 }, INT_MIN, INT_MAX, VE, "preset" }, - { "medium", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BALANCED }, INT_MIN, INT_MAX, VE, "preset" }, - { "slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_3 }, INT_MIN, INT_MAX, VE, "preset" }, - { "slower", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_2 }, INT_MIN, INT_MAX, VE, "preset" }, - { "veryslow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY }, INT_MIN, INT_MAX, VE, "preset" }, - + { "a53cc" , "Use A53 Closed Captions (if available)", OFFSET(qsv.a53_cc), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, VE}, { NULL }, }; @@ -117,6 +188,7 @@ static const AVCodecDefault qsv_enc_defaults[] = { { "coder", "ac" }, { "flags", "+cgop" }, + { "b_strategy", "-1" }, { NULL }, };