> >>> + > >>> +int ff_amf_encode_frame(AVCodecContext *avctx, AVPacket *pkt, > >>> + const AVFrame *frame, int *got_packet) { > >>> + int ret = 0; > >>> + AMF_RESULT res = AMF_OK; > >>> + AmfContext *ctx = avctx->priv_data; > >>> + AMFSurface *surface = NULL; > >>> + AMFData *data = NULL; > >>> + amf_bool submitted = 0; > >>> + > >>> + while (!submitted) { > >>> + if (!frame) { // submit drain > >>> + if (!ctx->eof) { // submit drain onre time only > >>> + res = ctx->encoder->pVtbl->Drain(ctx->encoder); > >>> + if (res == AMF_INPUT_FULL) { > >>> + av_usleep(1000); // input queue is full: wait, > >>> + poll and submit > >> Drain again > >>> + // need to get some output and try > >>> again > >>> + } else if (res == AMF_OK) { > >>> + ctx->eof = 1; // drain started > >>> + submitted = 1; > >>> + } > >>> + } > >>> + } else { // submit frame > >>> + if (surface == NULL) { // prepare surface from frame one time > only > >>> + if (frame->hw_frames_ctx && ( // HW frame detected > >>> + // check if the same > >>> + hw_frames_ctx as used in > >> initialization > >>> + (ctx->hw_frames_ctx && > >>> + frame->hw_frames_ctx->data == ctx- > >>> hw_frames_ctx->data) || > >>> + // check if the same hw_device_ctx as used in > >>> initialization > >>> + (ctx->hw_device_ctx && > >>> + ((AVHWFramesContext*)frame- > >>> hw_frames_ctx->data)->device_ctx == > >>> + (AVHWDeviceContext*)ctx->hw_device_ctx->data) > >>> + )) { > > (Here.) > > >>> + ID3D11Texture2D* texture = > >>> + (ID3D11Texture2D*)frame- > >>> data[0]; // actual texture > >>> + int index = (int)(size_t)frame->data[1]; // > >>> + index is a slice in > >> texture array is - set to tell AMF which slice to use > >> > >> (int)(intptr_t)frame->data[1]; > >> > >>> + texture->lpVtbl->SetPrivateData(texture, > >> &AMFTextureArrayIndexGUID, sizeof(index), &index); > >>> + > >>> + res = > >>> + ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx- > >>> context, texture, &surface, NULL); // wrap to AMF surface > >>> + surface->pVtbl->SetCrop(surface, 0, 0, > >>> + frame->width, frame- > >>> height); // decode surfaces are vertically aligned by 16 tell AMF > >>> real size > >> > >> "decode surfaces"? These need not come from a decoder. Does it work > >> with hwupload? > >> > >>> + surface->pVtbl->SetPts(surface, frame->pts); > >>> + } else { > >>> + res = > >>> + ctx->context->pVtbl->AllocSurface(ctx->context, > >> AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, > &surface); > >>> + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, > >>> + AVERROR_BUG, > >> "AllocSurface() failed with error %d \n", res); > >>> + amf_copy_surface(avctx, frame, surface); > >>> + } > >>> + } > >>> + // encode > >>> + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, > >> (AMFData*)surface); > >>> + if (res == AMF_INPUT_FULL) { // handle full queue > >>> + av_usleep(1000); // input queue is full: wait, poll > >>> + and submit > >> surface again > >>> + } else { > >>> + surface->pVtbl->Release(surface); > >>> + surface = NULL; > >>> + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, > >> AVERROR_UNKNOWN, "SubmitInput() failed with error %d \n", res); > >>> + submitted = 1; > >>> + } > >>> + } > >>> + // poll results > >>> + if (!data) { > >>> + res = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); > >>> + if (data) { > >>> + AMFBuffer* buffer; > >>> + AMFGuid guid = IID_AMFBuffer(); > >>> + data->pVtbl->QueryInterface(data, &guid, > >>> + (void**)&buffer); // > >> query for buffer interface > >>> + ret = amf_copy_buffer(avctx, pkt, buffer); > >>> + if (!ret) > >>> + *got_packet = 1; > >>> + buffer->pVtbl->Release(buffer); > >>> + data->pVtbl->Release(data); > >>> + if (ctx->eof) { > >>> + submitted = 1; // we are in the drain state - no > >>> submissions > >>> + } > >>> + } else if (res == AMF_EOF) { > >>> + submitted = 1; // drain complete > >>> + } else { > >>> + if (!submitted) { > >>> + av_usleep(1000); // wait and poll again > >>> + } > >>> + } > >>> + } > >>> + } > >>> + return ret; > >>> +} > >> > >> I still think this would be much better off using the > >> send_frame()/receive_packet() API. Even if your API doesn't expose > >> any information about the queue length, you only need to hold a > >> single input frame transiently to get around that (the user is not > >> allowed to call > >> send_frame() twice in a row without calling receive_packet()). > >> > > > > So to implement this I would have to: > > - in the send_frame() if AMF_INPUT_FULL is returned - store input > > frame (or copy?) > > - In the next receive_frame() check if frame is stored > > - Wait till some output is produced > > - resubmit stored frame > > Sounds about right. > > > Issues I see: > > - Isn't this logic defeat the purpose of independent send()/receive()? > > - How can I report a error if receive() produced a compressed frame but > the delayed submission failed? > > Since this is asynchronous anyway, just report it at the next available > opportunity. > > > - This logic depends on the particular logic in the calling code. > > The API requires this behaviour of the caller. See the documentation in > avcodec.h. > > > - This logic depends on the particular HW behaviour. > > How so? > > > - In the future, we would like to output individual slices of a compressed > frame. > > When this added receive_frame() must be called several times to clear > space in the HW queue. > > Granted, current implementation also does not cover this case but > > truly independent send/receive implementation would. > > Note that the user is required to call receive_packet() repeatedly until it > returns EAGAIN, and only then are they allowed to call send_frame() again.
The implementation will be cumbersome at least. Note that calling Drain() may also return AMF_INPUT_FULL and therefore will have to be remembered and called again in receive(). But I will implement as you suggests. It is not a huge change. > > >>> +static const AVOption options[] = { > >>> + // Static > >>> + /// Usage > >>> + { "usage", "Encoder Usage", OFFSET(usage), > >> AV_OPT_TYPE_INT, { .i64 = > AMF_VIDEO_ENCODER_USAGE_TRANSCONDING > >> }, AMF_VIDEO_ENCODER_USAGE_TRANSCONDING, > >> AMF_VIDEO_ENCODER_USAGE_WEBCAM, VE, "usage" }, > >>> + { "transcoding", "Generic Transcoding", 0, > >> AV_OPT_TYPE_CONST, { .i64 = > >> AMF_VIDEO_ENCODER_USAGE_TRANSCONDING }, 0, 0, VE, "usage" }, > >>> + { "ultralowlatency","", 0, > >>> AV_OPT_TYPE_CONST, { > .i64 > >> = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, > "usage" > >> }, > >>> + { "lowlatency", "", 0, > >>> AV_OPT_TYPE_CONST, { .i64 > = > >> AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY }, 0, 0, VE, "usage" }, > >>> + { "webcam", "Webcam", 0, > >>> AV_OPT_TYPE_CONST, > { > >> .i64 = AMF_VIDEO_ENCODER_USAGE_WEBCAM }, 0, 0, VE, "usage" > }, > >>> + > >>> + /// Profile, > >>> + { "profile", "Profile", > >>> OFFSET(profile),AV_OPT_TYPE_INT, { > >> .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, > >> AMF_VIDEO_ENCODER_PROFILE_BASELINE, > >> AMF_VIDEO_ENCODER_PROFILE_HIGH, VE, "profile" }, > >>> + { "baseline", "", 0, > >>> AV_OPT_TYPE_CONST, { .i64 > = > >> AMF_VIDEO_ENCODER_PROFILE_BASELINE }, 0, 0, VE, "profile" }, > >> > >> You still don't support baseline profile. > > > > Talked to codec folks. Currently this is really baseline by mistake. > > The intention was to expose only "constrained baseline" They want to > > correct this but it should go into the driver first and then reflected in > > AMF > API. Once done this entry will be updated. > > Ok, so baseline profile will not be included at all, and then constrained > baseline added later? That sounds fine. It appeared that the "constrained baseline" and "constrained high" were implemented but not published in AMF API. They will review it briefly and I will include them in the next submission. > > >>> + /// Maximum Access Unit Size > >>> + { "max_au_size", "Maximum Access Unit Size for rate control (in > bits)", > >> OFFSET(max_au_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, > >> NULL }, > >> > >> Did you check whether this really means the maximum access unit size? > >> If yes, what is the use-case for that? > >> > > > > I've changed the description. This parameter is used in rate control to > > limit > AU size. > > It is useful for streaming. > > When do you want to explicitly set an access unit size limit? That sort of > thing is better limited by setting maxrate with a shorter window, IMO. This is domain of codec rate control team. They feel that this parameter is important for some users. Some of them actually do use it. > > >>> + { "me_half_pel", "Enable ME Half Pixel", > >> OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE, NULL }, > >>> + { "me_quater_pel", "Enable ME Quarter Pixel ", > >> OFFSET(me_quater_pel), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE, > >> NULL }, > >> > >> What is the use-case for these options? > >> > > > > These are options for motion estimator precision. Spelling is corrected > "me_quarter_pel" > > What I mean is, why would anyone ever set these options to zero? One can speed up encoding by disabling detailed motion estimation. I am aware of at least one customer who is using this. > > >>> + > >>> + { NULL } > >>> +}; > >>> + > >>> +static av_cold int amf_encode_init_h264(AVCodecContext *avctx) { > >>> + int ret = 0; > >>> + AMF_RESULT res = AMF_OK; > >>> + AmfContext *ctx = avctx->priv_data; > >>> + AMFVariantStruct var = {0}; > >>> + amf_int64 profile = 0; > >>> + amf_int64 profile_level = 0; > >>> + AMFBuffer *buffer; > >>> + AMFGuid guid; > >>> + > >>> + AMFSize framesize = AMFConstructSize(avctx->width, avctx- > >>> height); > >>> + AMFRate framerate = AMFConstructRate(avctx- > >time_base.den, > >> avctx->time_base.num * avctx->ticks_per_frame); > >> > >> avctx->framerate should be set if the input is CFR, use that first. > >> > >>> + > >>> + int deblocking_filter = (avctx->flags & > >> AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; > >>> + > >>> + if ((ret = ff_amf_encode_init(avctx)) != 0) > >>> + return ret; > >>> + > >>> + // Static parameters > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_USAGE, ctx->usage); > >>> + > >>> + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_FRAMESIZE, framesize); > >>> + > >>> + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_FRAMERATE, framerate); > >>> + > >>> + profile = avctx->profile; > >> > >> avctx->profile might be (is by default, even) FF_PROFILE_UNKNOWN, > >> avctx->which is > >> not zero. > >> > >>> + if (profile == 0) { > >>> + profile = ctx->profile; > >>> + } > >>> + > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_PROFILE, profile); > >>> + > >>> + profile_level = avctx->level; > >> > >> Similarly FF_LEVEL_UNKNOWN. > >> > >>> + if (profile_level == 0) { > >>> + profile_level = ctx->level; > >>> + } > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_PROFILE_LEVEL, profile_level); > >>> + > >>> + // Maximum Reference Frames > >>> + if (avctx->refs != -1) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MAX_NUM_REFRAMES, avctx->refs); > >>> + } > >>> + if (avctx->sample_aspect_ratio.den && avctx- > >>> sample_aspect_ratio.num) { > >>> + AMFRatio ratio = AMFConstructRatio(avctx- > >>> sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); > >>> + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio); > >>> + } > >>> + > >>> + /// Color Range (Partial/TV/MPEG or Full/PC/JPEG) > >>> + if (avctx->color_range == AVCOL_RANGE_JPEG) { > >>> + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, 1); > >>> + } > >>> + > >>> + if (ctx->rate_control_mode == > >> AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, > >> AMF_VIDEO_ENCODER_PREENCODE_DISABLED); > >>> + if (ctx->preanalysis) > >>> + av_log(ctx, AV_LOG_WARNING, "Pre-Analysis is not > >>> + supported by > >> cqp Rate Control Method, automatically disabled. \n"); > >>> + } else { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, ctx- > >>> preanalysis); > >>> + } > >>> + > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_QUALITY_PRESET, ctx->quality); > >>> + > >>> + // Initialize Encoder > >>> + res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, > >>> + avctx- > >>> width, avctx->height); > >>> + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, > "encoder- > >>> Init() failed with error %d \n", res); > >>> + > >>> + // Dynamic parmaters > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, ctx- > >>> rate_control_mode); > >>> + > >>> + /// VBV Buffer > >>> + if (avctx->rc_buffer_size != 0) > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, avctx->rc_buffer_size); > >>> + if (avctx->rc_initial_buffer_occupancy != 0) { > >>> + int amf_buffer_fullness = avctx->rc_buffer_size * 64 / > >>> + avctx- > >>> rc_initial_buffer_occupancy; > >>> + if (amf_buffer_fullness > 64) > >>> + amf_buffer_fullness = 64; > >> > >> I still don't understand what this is trying to do. > >> > >> rc_initial_buffer_occupancy is necessarily at most rc_buffer_size, so > >> the calculation will always get a number >= 64, so you always pass 64. > >> > >> What are the units of > >> AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS meant to be? > >> > > > > They meant to be an abstract value from 0 to 64 meaning 64 is 100%. > > Don’t ask me why ☹ Calculation should be the opposite. My fault. > > Right, that makes more sense. > > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, > >> amf_buffer_fullness); > >>> + } > >>> + /// Maximum Access Unit Size > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MAX_AU_SIZE, ctx->max_au_size); > >>> + > >>> + // QP Minimum / Maximum > >>> + if (ctx->rate_control_mode == > >> AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MIN_QP, 0); > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MAX_QP, 51); > >>> + } else { > >>> + if (avctx->qmin != -1) { > >>> + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MIN_QP, qval); > >>> + } > >>> + if (avctx->qmax != -1) { > >>> + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_MAX_QP, qval); > >>> + } > >>> + } > >>> + // QP Values > >>> + if (ctx->qp_i != -1) > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_QP_I, ctx->qp_i); > >>> + if (ctx->qp_p != -1) > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_QP_P, ctx->qp_p); > >>> + if (ctx->qp_b != -1) > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_QP_B, ctx->qp_b); > >>> + > >>> + // Bitrate > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_TARGET_BITRATE, avctx->bit_rate); > >>> + > >>> + // Peak (max) bitrate. If not set make it out of bit_rate for best > results. > >>> + if (ctx->rate_control_mode == > >> AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->bit_rate); > >>> + } else { > >>> + int rc_max_rate = avctx->rc_max_rate >= avctx->bit_rate ? > >>> + avctx- > >>> rc_max_rate : avctx->bit_rate * 13 / 10; > >> > >> Please calculate a real value here as suggested in the previous > >> comments rather than using 13/10. > > > > The suggestion was to set rc_max_rate to infinity. This will produce > unpredicted results. > > I can set it to bit_rate but quality will be not good. Another option would > > be > to generate error. > > I am open to suggestions. > > Is the window over which rc_max_rate applies defined anywhere? If so, > then if rc_buffer_size is set you can calculate rc_max_rate as (rc_buffer_size > + bit_rate * window) / window (i.e. the maximum number of bits which > could be included in one window region given the buffer constraints). > > If rc_buffer_size isn't set either, then it isn't meant to be constrained - > the > average should be right over the long term, but locally it doesn't matter. > Hence infinity (or at least some very large value), to not impose any > constraint. > I will ask rate control guy tomorrow and let him weight on this. > >>> + { "max_au_size", "Max AU Size in bits", > >> OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, INT_MAX, VE, > NULL > >> }, > >> > >> Same question as in H.264. Also other stuff below. > >> > >>> + { "min_qp_i", "min quantization parameter for I-frame", > >> OFFSET(min_qp_i), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "max_qp_i", "max quantization parameter for I-frame", > >> OFFSET(max_qp_i), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "min_qp_p", "min quantization parameter for P-frame", > >> OFFSET(min_qp_p), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "max_qp_p", "max quantization parameter for P-frame", > >> OFFSET(max_qp_p), AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "qp_p", "quantization parameter for P-frame", > OFFSET(qp_p), > >> AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "qp_i", "quantization parameter for I-frame", > OFFSET(qp_i), > >> AV_OPT_TYPE_INT,{ .i64 = -1 }, -1, 51, VE }, > >>> + { "skip_frame", "Rate Control Based Frame Skip", > >> OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE, NULL }, > >>> + { "me_half_pel", "Enable ME Half Pixel", > >> OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE, NULL }, > >>> + { "me_quater_pel", "Enable ME Quarter Pixel ", > >> OFFSET(me_quater_pel), AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE, NULL > >> }, > >>> + > >>> + { NULL } > >>> +}; > >>> + > >>> +static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) { > >>> + int ret = 0; > >>> + AMF_RESULT res = AMF_OK; > >>> + AmfContext *ctx = avctx->priv_data; > >>> + AMFVariantStruct var = {0}; > >>> + amf_int64 profile = 0; > >>> + amf_int64 profile_level = 0; > >>> + AMFBuffer *buffer; > >>> + AMFGuid guid; > >>> + > >>> + AMFSize framesize = AMFConstructSize(avctx->width, avctx- > >>> height); > >>> + AMFRate framerate = AMFConstructRate(avctx- > >time_base.den, > >> avctx->time_base.num * avctx->ticks_per_frame); > >>> + > >>> + int deblocking_filter = (avctx->flags & > >> AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; > >>> + > >>> + if ((ret = ff_amf_encode_init(avctx)) < 0) > >>> + return ret; > >>> + > >>> + // init static parameters > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_USAGE, ctx->usage); > >>> + > >>> + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_FRAMESIZE, framesize); > >>> + > >>> + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_FRAMERATE, framerate); > >>> + > >>> + switch (avctx->profile) { > >>> + case FF_PROFILE_HEVC_MAIN: > >>> + profile = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN; > >>> + break; > >>> + default: > >>> + break; > >>> + } > >>> + if (profile == 0) { > >>> + profile = ctx->profile; > >>> + } > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_PROFILE, profile); > >>> + > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_TIER, ctx->tier); > >>> + > >>> + profile_level = avctx->level; > >>> + if (profile_level == 0) { > >>> + profile_level = ctx->level; > >>> + } > >>> + if (profile_level != 0) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL, profile_level); > >>> + } > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET, ctx->quality); > >>> + // Maximum Reference Frames > >>> + if (avctx->refs != 0) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_MAX_NUM_REFRAMES, avctx->refs); > >>> + } > >>> + // Aspect Ratio > >>> + if (avctx->sample_aspect_ratio.den && avctx- > >>> sample_aspect_ratio.num) { > >>> + AMFRatio ratio = AMFConstructRatio(avctx- > >>> sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); > >>> + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); > >>> + } > >>> + > >>> + // Picture control properties > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR, ctx->gops_per_idr); > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, avctx->gop_size); > >>> + if (avctx->slices > 1) { > >>> + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_SLICES_PER_FRAME, avctx->slices); > >>> + } > >>> + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, > >> AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, > >> deblocking_filter); > >> > >> What about SAO? > > > > SAO ??? > > You're looking at AV_CODEC_FLAG_LOOP_FILTER to disable this, so you > might want to consider both loop filters in H.265, not just the deblocking > filter. > > - Mark > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel Thanks, Mikhail _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel