* copyright (c) 2013 Yukinori Yamazoe
* copyright (c) 2015 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/log.h"
#include "libavutil/time.h"
#include "libavutil/imgutils.h"
+#include "libavcodec/bytestream.h"
#include "avcodec.h"
#include "internal.h"
#if QSV_HAVE_CO2
mfxExtCodingOption2 *co2 = (mfxExtCodingOption2*)coding_opts[1];
#endif
-#if QSV_HAVE_CO3
- mfxExtCodingOption3 *co3 = (mfxExtCodingOption3*)coding_opts[2];
-#endif
av_log(avctx, AV_LOG_VERBOSE, "profile: %s; level: %"PRIu16"\n",
print_profile(info->CodecProfile), info->CodecLevel);
info->ICQQuality, co2->LookAheadDepth);
}
#endif
-#if QSV_HAVE_QVBR
- else if (info->RateControlMethod == MFX_RATECONTROL_QVBR) {
- av_log(avctx, AV_LOG_VERBOSE, "QVBRQuality: %"PRIu16"\n",
- co3->QVBRQuality);
- }
-#endif
av_log(avctx, AV_LOG_VERBOSE, "NumSlice: %"PRIu16"; NumRefFrame: %"PRIu16"\n",
info->NumSlice, info->NumRefFrame);
const char *rc_desc;
mfxU16 rc_mode;
- int want_la = q->la_depth >= 10;
+ int want_la = q->look_ahead;
int want_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE);
int want_vcm = q->vcm;
return 0;
}
-static int rc_supported(QSVEncContext *q)
+static int check_enc_param(AVCodecContext *avctx, QSVEncContext *q)
{
mfxVideoParam param_out = { .mfx.CodecId = q->param.mfx.CodecId };
mfxStatus ret;
+#define UNMATCH(x) (param_out.mfx.x != q->param.mfx.x)
+
ret = MFXVideoENCODE_Query(q->session, &q->param, ¶m_out);
- if (ret < 0 ||
- param_out.mfx.RateControlMethod != q->param.mfx.RateControlMethod)
+
+ if (ret < 0) {
+ if (UNMATCH(CodecId))
+ av_log(avctx, AV_LOG_ERROR, "Current codec type is unsupported\n");
+ if (UNMATCH(CodecProfile))
+ av_log(avctx, AV_LOG_ERROR, "Current profile is unsupported\n");
+ if (UNMATCH(RateControlMethod))
+ av_log(avctx, AV_LOG_ERROR, "Selected ratecontrol mode is unsupported\n");
+ if (UNMATCH(LowPower))
+ av_log(avctx, AV_LOG_ERROR, "Low power mode is unsupported\n");
+ if (UNMATCH(FrameInfo.FrameRateExtN) || UNMATCH(FrameInfo.FrameRateExtD))
+ av_log(avctx, AV_LOG_ERROR, "Current frame rate is unsupported\n");
+ if (UNMATCH(FrameInfo.PicStruct))
+ av_log(avctx, AV_LOG_ERROR, "Current picture structure is unsupported\n");
+ if (UNMATCH(FrameInfo.Width) || UNMATCH(FrameInfo.Height))
+ av_log(avctx, AV_LOG_ERROR, "Current resolution is unsupported\n");
+ if (UNMATCH(FrameInfo.FourCC))
+ av_log(avctx, AV_LOG_ERROR, "Current pixel format is unsupported\n");
return 0;
+ }
return 1;
}
#if QSV_HAVE_LA
case MFX_RATECONTROL_LA:
q->param.mfx.TargetKbps = avctx->bit_rate / 1000;
- q->extco2.LookAheadDepth = q->la_depth;
+ q->extco2.LookAheadDepth = q->look_ahead_depth;
break;
#if QSV_HAVE_ICQ
case MFX_RATECONTROL_LA_ICQ:
- q->extco2.LookAheadDepth = q->la_depth;
+ q->extco2.LookAheadDepth = q->look_ahead_depth;
case MFX_RATECONTROL_ICQ:
q->param.mfx.ICQQuality = avctx->global_quality;
break;
q->extco.Header.BufferId = MFX_EXTBUFF_CODING_OPTION;
q->extco.Header.BufferSz = sizeof(q->extco);
+ q->extco.PicTimingSEI = q->pic_timing_sei ?
+ MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN;
+
if (q->rdo >= 0)
q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
if (q->recovery_point_sei >= 0)
q->extco.RecoveryPointSEI = q->recovery_point_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
q->extco.MaxDecFrameBuffering = q->max_dec_frame_buffering;
+ q->extco.AUDelimiter = q->aud ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
}
q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco;
#endif
#if QSV_HAVE_LA_DS
- q->extco2.LookAheadDS = q->la_ds;
+ q->extco2.LookAheadDS = q->look_ahead_downsampling;
#endif
#if QSV_HAVE_BREF_TYPE
q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2;
}
+#endif
+#if QSV_HAVE_MF
+ if (avctx->codec_id == AV_CODEC_ID_H264) {
+ mfxVersion ver;
+ ret = MFXQueryVersion(q->session,&ver);
+ if (ret >= MFX_ERR_NONE && QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) {
+ q->extmfp.Header.BufferId = MFX_EXTBUFF_MULTI_FRAME_PARAM;
+ q->extmfp.Header.BufferSz = sizeof(q->extmfp);
+
+ q->extmfp.MFMode = q->mfmode;
+ av_log(avctx,AV_LOG_VERBOSE,"MFMode:%d\n", q->extmfp.MFMode);
+ q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extmfp;
+ }
+ }
#endif
}
- if (!rc_supported(q)) {
+ if (!check_enc_param(avctx,q)) {
av_log(avctx, AV_LOG_ERROR,
- "Selected ratecontrol mode is not supported by the QSV "
- "runtime. Choose a different mode.\n");
+ "some encoding parameters are not supported by the QSV "
+ "runtime. Please double check the input parameters.\n");
return AVERROR(ENOSYS);
}
.Header.BufferSz = sizeof(co2),
};
#endif
-#if QSV_HAVE_CO3
- mfxExtCodingOption3 co3 = {
- .Header.BufferId = MFX_EXTBUFF_CODING_OPTION3,
- .Header.BufferSz = sizeof(co3),
- };
-#endif
mfxExtBuffer *ext_buffers[] = {
(mfxExtBuffer*)&extradata,
(mfxExtBuffer*)&co,
#if QSV_HAVE_CO2
(mfxExtBuffer*)&co2,
-#endif
-#if QSV_HAVE_CO3
- (mfxExtBuffer*)&co3,
#endif
};
return 0;
}
+static void free_encoder_ctrl_payloads(mfxEncodeCtrl* enc_ctrl)
+{
+ if (enc_ctrl) {
+ int i;
+ for (i = 0; i < enc_ctrl->NumPayload && i < QSV_MAX_ENC_PAYLOAD; i++) {
+ av_free(enc_ctrl->Payload[i]);
+ }
+ enc_ctrl->NumPayload = 0;
+ }
+}
+
static void clear_unused_frames(QSVEncContext *q)
{
QSVFrame *cur = q->work_frames;
while (cur) {
if (cur->used && !cur->surface.Data.Locked) {
+ free_encoder_ctrl_payloads(&cur->enc_ctrl);
av_frame_unref(cur->frame);
cur->used = 0;
}
av_freep(&frame);
return AVERROR(ENOMEM);
}
+ frame->enc_ctrl.Payload = av_mallocz(sizeof(mfxPayload*) * QSV_MAX_ENC_PAYLOAD);
+ if (!frame->enc_ctrl.Payload) {
+ av_freep(&frame);
+ return AVERROR(ENOMEM);
+ }
*last = frame;
*f = frame;
}
static int submit_frame(QSVEncContext *q, const AVFrame *frame,
- mfxFrameSurface1 **surface)
+ QSVFrame **new_frame)
{
QSVFrame *qf;
int ret;
qf->surface.Data.TimeStamp = av_rescale_q(frame->pts, q->avctx->time_base, (AVRational){1, 90000});
- *surface = &qf->surface;
+ *new_frame = qf;
return 0;
}
mfxFrameSurface1 *surf = NULL;
mfxSyncPoint *sync = NULL;
+ QSVFrame *qsv_frame = NULL;
+ mfxEncodeCtrl* enc_ctrl = NULL;
int ret;
if (frame) {
- ret = submit_frame(q, frame, &surf);
+ ret = submit_frame(q, frame, &qsv_frame);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error submitting the frame for encoding.\n");
return ret;
}
}
+ if (qsv_frame) {
+ surf = &qsv_frame->surface;
+ enc_ctrl = &qsv_frame->enc_ctrl;
+ }
ret = av_new_packet(&new_pkt, q->packet_size);
if (ret < 0) {
bs->Data = new_pkt.data;
bs->MaxLength = new_pkt.size;
+ if (q->set_encode_ctrl_cb) {
+ q->set_encode_ctrl_cb(avctx, frame, &qsv_frame->enc_ctrl);
+ }
+
sync = av_mallocz(sizeof(*sync));
if (!sync) {
av_freep(&bs);
}
do {
- ret = MFXVideoENCODE_EncodeFrameAsync(q->session, NULL, surf, bs, sync);
+ ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
if (ret == MFX_WRN_DEVICE_BUSY)
- av_usleep(1);
+ av_usleep(500);
} while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION);
if (ret > 0)
while (cur) {
q->work_frames = cur->next;
av_frame_free(&cur->frame);
+ av_free(cur->enc_ctrl.Payload);
av_freep(&cur);
cur = q->work_frames;
}