/* * Copyright (c) 2010, Google, Inc. * * This file is part of FFmpeg. * * 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. * * 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* * Portion of struct aom_codec_cx_pkt from aom_encoder.h. * One encoded frame returned from the library.
*/ struct FrameListData { void *buf; /**< compressed data buffer */
size_t sz; /**< length of compressed data */
int64_t pts; /**< time stamp to show frame
(in timebase units) */ unsignedlong duration; /**< duration to show frame
(in timebase units) */
uint32_t flags; /**< flags for this frame */
uint64_t sse[4]; int have_sse; /**< true if we have pending sse[] */
uint64_t frame_number; struct FrameListData *next;
};
typedefstruct AOMEncoderContext {
AVClass *class;
AVBSFContext *bsf;
DOVIContext dovi; struct aom_codec_ctx encoder; struct aom_image rawimg; struct aom_fixed_buf twopass_stats; unsigned twopass_stats_size; struct FrameListData *coded_frame_list; int cpu_used; int auto_alt_ref; int arnr_max_frames; int arnr_strength; int aq_mode; int lag_in_frames; int error_resilient; int crf; int static_thresh; int drop_threshold; int denoise_noise_level; int denoise_block_size;
uint64_t sse[4]; int have_sse; /**< true if we have pending sse[] */
uint64_t frame_number; int rc_undershoot_pct; int rc_overshoot_pct; int minsection_pct; int maxsection_pct; int frame_parallel; int tile_cols, tile_rows; int tile_cols_log2, tile_rows_log2;
aom_superblock_size_t superblock_size; int uniform_tiles; int row_mt; int enable_cdef; int enable_global_motion; int enable_intrabc; int enable_restoration; int usage; int tune; int still_picture; int enable_rect_partitions; int enable_1to4_partitions; int enable_ab_partitions; int enable_angle_delta; int enable_cfl_intra; int enable_paeth_intra; int enable_smooth_intra; int enable_intra_edge_filter; int enable_palette; int enable_filter_intra; int enable_flip_idtx; int enable_tx64; int reduced_tx_type_set; int use_intra_dct_only; int use_inter_dct_only; int use_intra_default_tx_only; int enable_ref_frame_mvs; int enable_interinter_wedge; int enable_interintra_wedge; int enable_interintra_comp; int enable_masked_comp; int enable_obmc; int enable_onesided_comp; int enable_reduced_reference_set; int enable_smooth_interintra; int enable_diff_wtd_comp; int enable_dist_wtd_comp; int enable_dual_filter;
AVDictionary *svc_parameters;
AVDictionary *aom_params;
} AOMContext;
res = aom_codec_control(&ctx->encoder, id, svc_params); if (res != AOM_CODEC_OK) {
snprintf(buf, sizeof(buf), "Failed to get %s codec control",
ctlidstr[id]);
log_encoder_error(avctx, buf); return AVERROR(EINVAL);
}
return 0;
}
static av_cold int aom_free(AVCodecContext *avctx)
{
AOMContext *ctx = avctx->priv_data;
#ifdefined(AOM_CTRL_AV1E_GET_NUM_OPERATING_POINTS) && \ defined(AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX) && \ defined(AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX) if (ctx->encoder.iface && !(avctx->flags & AV_CODEC_FLAG_PASS1)) { int num_operating_points; int levels[32]; int target_levels[32];
if (!codecctl_intp(avctx, AV1E_GET_NUM_OPERATING_POINTS,
&num_operating_points) &&
!codecctl_intp(avctx, AV1E_GET_SEQ_LEVEL_IDX, levels) &&
!codecctl_intp(avctx, AV1E_GET_TARGET_SEQ_LEVEL_IDX,
target_levels)) { for (int i = 0; i < num_operating_points; i++) { if (levels[i] > target_levels[i]) { // Warn when the target level was not met
av_log(avctx, AV_LOG_WARNING, "Could not encode to target level %d.%d for " "operating point %d. The output level is %d.%d.\n",
2 + (target_levels[i] >> 2), target_levels[i] & 3,
i, 2 + (levels[i] >> 2), levels[i] & 3);
} elseif (target_levels[i] < 31) { // Log the encoded level if a target level was given
av_log(avctx, AV_LOG_INFO, "Output level for operating point %d is %d.%d.\n",
i, 2 + (levels[i] >> 2), levels[i] & 3);
}
}
}
} #endif
if ((res = aom_codec_enc_config_default(iface, &enccfg, ctx->usage)) != AOM_CODEC_OK) {
av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
aom_codec_err_to_string(res)); return AVERROR(EINVAL);
}
if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt)) return AVERROR(EINVAL);
if(!avctx->bit_rate) if(avctx->rc_max_rate || avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without a bitrate\n"); return AVERROR(EINVAL);
}
if (enccfg.rc_end_usage == AOM_CQ || enccfg.rc_end_usage == AOM_Q) { if (ctx->crf < enccfg.rc_min_quantizer || ctx->crf > enccfg.rc_max_quantizer) {
av_log(avctx, AV_LOG_ERROR, "CQ level %d must be between minimum and maximum quantizer value (%d-%d)\n",
ctx->crf, enccfg.rc_min_quantizer, enccfg.rc_max_quantizer); return AVERROR(EINVAL);
}
}
if (ctx->rc_undershoot_pct >= 0)
enccfg.rc_undershoot_pct = ctx->rc_undershoot_pct; if (ctx->rc_overshoot_pct >= 0)
enccfg.rc_overshoot_pct = ctx->rc_overshoot_pct;
// _enc_init() will balk if kf_min_dist differs from max w/AOM_KF_AUTO if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
enccfg.kf_min_dist = avctx->keyint_min; if (avctx->gop_size >= 0)
enccfg.kf_max_dist = avctx->gop_size;
if (enccfg.g_pass == AOM_RC_FIRST_PASS)
enccfg.g_lag_in_frames = 0; elseif (enccfg.g_pass == AOM_RC_LAST_PASS) { int decode_size, ret;
if (!avctx->stats_in) {
av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); return AVERROR_INVALIDDATA;
}
/* 0-3: For non-zero values the encoder increasingly optimizes for reduced * complexity playback on low powered devices at the expense of encode
* quality. */ if (avctx->profile != AV_PROFILE_UNKNOWN)
enccfg.g_profile = avctx->profile;
enccfg.g_error_resilient = ctx->error_resilient;
res = choose_tiling(avctx, &enccfg); if (res < 0) return res;
if (ctx->still_picture) { // Set the maximum number of frames to 1. This will let libaom set // still_picture and reduced_still_picture_header to 1 in the Sequence // Header as required by AVIF still images.
enccfg.g_limit = 1; // Reduce memory usage for still images.
enccfg.g_lag_in_frames = 0; // All frames will be key frames.
enccfg.kf_max_dist = 0;
enccfg.kf_mode = AOM_KF_DISABLED;
}
/* Construct Encoder Context */
res = aom_codec_enc_init(&ctx->encoder, iface, &enccfg, flags); if (res != AOM_CODEC_OK) {
dump_enc_cfg(avctx, &enccfg, AV_LOG_WARNING);
log_encoder_error(avctx, "Failed to initialize encoder"); return AVERROR(EINVAL);
}
dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG);
// codec control failures are currently treated only as warnings
av_log(avctx, AV_LOG_DEBUG, "aom_codec_control\n");
codecctl_int(avctx, AOME_SET_CPUUSED, ctx->cpu_used); if (ctx->auto_alt_ref >= 0)
codecctl_int(avctx, AOME_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref); if (ctx->arnr_max_frames >= 0)
codecctl_int(avctx, AOME_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames); if (ctx->arnr_strength >= 0)
codecctl_int(avctx, AOME_SET_ARNR_STRENGTH, ctx->arnr_strength); if (ctx->enable_cdef >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_CDEF, ctx->enable_cdef); if (ctx->enable_restoration >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_RESTORATION, ctx->enable_restoration); if (ctx->enable_rect_partitions >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_RECT_PARTITIONS, ctx->enable_rect_partitions); if (ctx->enable_1to4_partitions >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_1TO4_PARTITIONS, ctx->enable_1to4_partitions); if (ctx->enable_ab_partitions >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_AB_PARTITIONS, ctx->enable_ab_partitions); if (ctx->enable_angle_delta >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_ANGLE_DELTA, ctx->enable_angle_delta); if (ctx->enable_cfl_intra >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_CFL_INTRA, ctx->enable_cfl_intra); if (ctx->enable_filter_intra >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_FILTER_INTRA, ctx->enable_filter_intra); if (ctx->enable_intra_edge_filter >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, ctx->enable_intra_edge_filter); if (ctx->enable_paeth_intra >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_PAETH_INTRA, ctx->enable_paeth_intra); if (ctx->enable_smooth_intra >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTRA, ctx->enable_smooth_intra); if (ctx->enable_palette >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_PALETTE, ctx->enable_palette); if (ctx->enable_tx64 >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_TX64, ctx->enable_tx64); if (ctx->enable_flip_idtx >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_FLIP_IDTX, ctx->enable_flip_idtx); if (ctx->use_intra_dct_only >= 0)
codecctl_int(avctx, AV1E_SET_INTRA_DCT_ONLY, ctx->use_intra_dct_only); if (ctx->use_inter_dct_only >= 0)
codecctl_int(avctx, AV1E_SET_INTER_DCT_ONLY, ctx->use_inter_dct_only); if (ctx->use_intra_default_tx_only >= 0)
codecctl_int(avctx, AV1E_SET_INTRA_DEFAULT_TX_ONLY, ctx->use_intra_default_tx_only); if (ctx->reduced_tx_type_set >= 0)
codecctl_int(avctx, AV1E_SET_REDUCED_TX_TYPE_SET, ctx->reduced_tx_type_set); if (ctx->enable_ref_frame_mvs >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_REF_FRAME_MVS, ctx->enable_ref_frame_mvs); if (ctx->enable_reduced_reference_set >= 0)
codecctl_int(avctx, AV1E_SET_REDUCED_REFERENCE_SET, ctx->enable_reduced_reference_set); if (ctx->enable_diff_wtd_comp >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_DIFF_WTD_COMP, ctx->enable_diff_wtd_comp); if (ctx->enable_dist_wtd_comp >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_DIST_WTD_COMP, ctx->enable_dist_wtd_comp); if (ctx->enable_dual_filter >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_DUAL_FILTER, ctx->enable_dual_filter); if (ctx->enable_interinter_wedge >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTER_WEDGE, ctx->enable_interinter_wedge); if (ctx->enable_masked_comp >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_MASKED_COMP, ctx->enable_masked_comp); if (ctx->enable_interintra_comp >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_COMP, ctx->enable_interintra_comp); if (ctx->enable_interintra_wedge >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_INTERINTRA_WEDGE, ctx->enable_interintra_wedge); if (ctx->enable_obmc >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_OBMC, ctx->enable_obmc); if (ctx->enable_onesided_comp >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_ONESIDED_COMP, ctx->enable_onesided_comp); if (ctx->enable_smooth_interintra >= 0)
codecctl_int(avctx, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, ctx->enable_smooth_interintra);
codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0)
codecctl_int(avctx, AOME_SET_CQ_LEVEL, ctx->crf); if (ctx->tune >= 0)
codecctl_int(avctx, AOME_SET_TUNING, ctx->tune);
while ((en = av_dict_iterate(ctx->aom_params, en))) { int ret = aom_codec_set_option(&ctx->encoder, en->key, en->value); if (ret != AOM_CODEC_OK) {
log_encoder_error(avctx, en->key); return AVERROR_EXTERNAL;
}
}
} #endif
// provide dummy value to initialize wrapper, values will be updated each _encode()
aom_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
(unsignedchar*)1);
if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH)
ctx->rawimg.bit_depth = enccfg.g_bit_depth;
cpb_props = ff_encode_add_cpb_side_data(avctx); if (!cpb_props) return AVERROR(ENOMEM);
/** * Store coded frame information in format suitable for return from encode2(). * * Write information from @a cx_frame to @a pkt * @return packet data size on success * @return a negative AVERROR on error
*/ staticint storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame,
AVPacket *pkt)
{
AOMContext *ctx = avctx->priv_data; int av_unused pict_type; int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0); if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %"SIZE_SPECIFIER".\n", cx_frame->sz); return ret;
}
memcpy(pkt->data, cx_frame->buf, pkt->size);
pkt->pts = pkt->dts = cx_frame->pts;
pkt->duration = cx_frame->duration;
/** * Queue multiple output frames from the encoder, returning the front-most. * In cases where aom_codec_get_cx_data() returns more than 1 frame append * the frame queue. Return the head frame if available. * @return Stored frame size * @return AVERROR(EINVAL) on output size error * @return AVERROR(ENOMEM) on coded frame queue data allocation error
*/ staticint queue_frames(AVCodecContext *avctx, AVPacket *pkt_out)
{
AOMContext *ctx = avctx->priv_data; conststruct aom_codec_cx_pkt *pkt; constvoid *iter = NULL; int size = 0;
if (ctx->coded_frame_list) { struct FrameListData *cx_frame = ctx->coded_frame_list; /* return the leading frame if we've already begun queueing */
size = storeframe(avctx, cx_frame, pkt_out); if (size < 0) return size;
ctx->coded_frame_list = cx_frame->next;
free_coded_frame(cx_frame);
}
/* consume all available output from the encoder before returning. buffers
* are only good through the next aom_codec call */ while ((pkt = aom_codec_get_cx_data(&ctx->encoder, &iter))) { switch (pkt->kind) { case AOM_CODEC_CX_FRAME_PKT: if (!size) { struct FrameListData cx_frame;
/* avoid storing the frame when the list is empty and we haven't yet
* provided a frame for output */
av_assert0(!ctx->coded_frame_list);
cx_pktcpy(ctx, &cx_frame, pkt);
size = storeframe(avctx, &cx_frame, pkt_out); if (size < 0) return size;
} else { struct FrameListData *cx_frame =
av_malloc(sizeof(struct FrameListData));
if (!cx_frame) {
av_log(avctx, AV_LOG_ERROR, "Frame queue element alloc failed\n"); return AVERROR(ENOMEM);
}
cx_pktcpy(ctx, cx_frame, pkt);
cx_frame->buf = av_malloc(cx_frame->sz);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.