/* * 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 vpx_codec_cx_pkt from vpx_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) */
uint32_t flags; /**< flags for this frame */
uint64_t sse[4]; int have_sse; /**< true if we have pending sse[] */ struct FrameListData *next;
};
typedefstruct VPxEncoderContext {
AVClass *class; struct vpx_codec_ctx encoder; struct vpx_image rawimg; struct vpx_codec_ctx encoder_alpha; struct vpx_image rawimg_alpha;
uint8_t is_alpha; struct vpx_fixed_buf twopass_stats; unsigned twopass_stats_size; int deadline; //i.e., RT/GOOD/BEST
uint64_t sse[4]; int have_sse; /**< true if we have pending sse[] */ struct FrameListData *coded_frame_list; struct FrameListData *alpha_coded_frame_list;
int cpu_used; int sharpness; /** * VP8 specific flags, see VP8F_* below.
*/ int flags; #define VP8F_ERROR_RESILIENT 0x00000001 ///< Enable measures appropriate for streaming over lossy links #define VP8F_AUTO_ALT_REF 0x00000002 ///< Enable automatic alternate reference frame generation
int auto_alt_ref;
int arnr_max_frames; int arnr_strength; int arnr_type;
int tune;
int lag_in_frames; int error_resilient; int crf; int static_thresh; int max_intra_rate; int rc_undershoot_pct; int rc_overshoot_pct;
AVDictionary *vpx_ts_parameters; int *ts_layer_flags; int current_temporal_idx;
// VP8-only int screen_content_mode;
// VP9-only int lossless; int tile_columns; int tile_rows; int frame_parallel; int aq_mode; int drop_threshold; int noise_sensitivity; int vpx_cs; float level; int row_mt; int tune_content; int corpus_complexity; int tpl_model; int min_gf_interval;
// This FIFO is used to propagate various properties from frames to packets.
AVFifo *fifo; /** * If the driver does not support ROI then warn the first time we * encounter a frame with ROI side data.
*/ int roi_warned; #if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT)
vpx_svc_ref_frame_config_t ref_frame_config; #endif
} VPxContext;
if (IS_VP9(avctx) && // Keep HDR10+ if it has bit depth higher than 8 and // it has PQ trc (SMPTE2084).
enccfg->g_bit_depth > 8 && avctx->color_trc == AVCOL_TRC_SMPTE2084) { const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS);
if (sd) {
fd.hdr10_plus = av_buffer_ref(sd->buf); if (!fd.hdr10_plus) return AVERROR(ENOMEM);
}
}
fd.duration = frame->duration;
fd.frame_opaque = frame->opaque; if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE && frame->opaque_ref) {
ret = av_buffer_replace(&fd.frame_opaque_ref, frame->opaque_ref); if (ret < 0) goto fail;
}
ret = av_fifo_write(fifo, &fd, 1); if (ret < 0) goto fail;
if (fd.hdr10_plus) {
data = av_packet_new_side_data(pkt, AV_PKT_DATA_DYNAMIC_HDR10_PLUS, fd.hdr10_plus->size); if (!data) {
ret = AVERROR(ENOMEM); goto skip;
}
#if (VPX_ENCODER_ABI_VERSION >= 12) && CONFIG_LIBVPX_VP9_ENCODER
enccfg->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; // only bypass mode is supported for now.
enccfg->ss_number_layers = 1; // TODO: add spatial scalability support. #endif if (ts_layering_mode) { // make sure the ts_layering_mode comes at the end of the ts_parameter string to ensure that // correct configuration is done.
ctx->ts_layer_flags = av_malloc_array(VPX_TS_MAX_PERIODICITY, sizeof(*ctx->ts_layer_flags));
set_temporal_layer_pattern(ts_layering_mode, enccfg, ctx->ts_layer_flags, &enccfg->ts_periodicity);
}
/** * Set the target bitrate to VPX library default. Also set CRF to 32 if needed.
*/ staticvoid set_vp8_defaults(AVCodecContext *avctx, struct vpx_codec_enc_cfg *enccfg)
{
VPxContext *ctx = avctx->priv_data;
av_assert0(!avctx->bit_rate);
avctx->bit_rate = enccfg->rc_target_bitrate * 1000; if (enccfg->rc_end_usage == VPX_CQ) {
av_log(avctx, AV_LOG_WARNING, "Bitrate not specified for constrained quality mode, using default of %dkbit/sec\n",
enccfg->rc_target_bitrate);
} else {
enccfg->rc_end_usage = VPX_CQ;
ctx->crf = 32;
av_log(avctx, AV_LOG_WARNING, "Neither bitrate nor constrained quality specified, using default CRF of %d and bitrate of %dkbit/sec\n",
ctx->crf, enccfg->rc_target_bitrate);
}
}
#if CONFIG_LIBVPX_VP9_ENCODER /** * Keep the target bitrate at 0 to engage constant quality mode. If CRF is not * set, use 32.
*/ staticvoid set_vp9_defaults(AVCodecContext *avctx, struct vpx_codec_enc_cfg *enccfg)
{
VPxContext *ctx = avctx->priv_data;
av_assert0(!avctx->bit_rate); if (enccfg->rc_end_usage != VPX_Q && ctx->lossless < 0) {
enccfg->rc_end_usage = VPX_Q;
ctx->crf = 32;
av_log(avctx, AV_LOG_WARNING, "Neither bitrate nor constrained quality specified, using default CRF of %d\n",
ctx->crf);
}
} #endif
/** * Called when the bitrate is not set. It sets appropriate default values for * bitrate and CRF.
*/ staticvoid set_vpx_defaults(AVCodecContext *avctx, struct vpx_codec_enc_cfg *enccfg)
{
av_assert0(!avctx->bit_rate); #if CONFIG_LIBVPX_VP9_ENCODER if (avctx->codec_id == AV_CODEC_ID_VP9) {
set_vp9_defaults(avctx, enccfg); return;
} #endif
set_vp8_defaults(avctx, enccfg);
}
if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P)
ctx->is_alpha = 1;
if ((res = vpx_codec_enc_config_default(iface, &enccfg, 0)) != VPX_CODEC_OK) {
av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
vpx_codec_err_to_string(res)); return AVERROR(EINVAL);
}
ctx->fifo = av_fifo_alloc2(1, sizeof(FrameData), AV_FIFO_FLAG_AUTO_GROW); if (!ctx->fifo) return AVERROR(ENOMEM);
#if CONFIG_LIBVPX_VP9_ENCODER if (avctx->codec_id == AV_CODEC_ID_VP9) { if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt)) return AVERROR(EINVAL);
} #endif
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 (avctx->rc_buffer_size)
enccfg.rc_buf_sz =
avctx->rc_buffer_size * 1000LL / avctx->bit_rate; if (avctx->rc_initial_buffer_occupancy)
enccfg.rc_buf_initial_sz =
avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate;
enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; 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/VPX_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 == VPX_RC_FIRST_PASS)
enccfg.g_lag_in_frames = 0; elseif (enccfg.g_pass == VPX_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;
staticinlinevoid cx_pktcpy(struct FrameListData *dst, conststruct vpx_codec_cx_pkt *src,
VPxContext *ctx)
{
dst->pts = src->data.frame.pts;
dst->flags = src->data.frame.flags;
dst->sz = src->data.frame.sz;
dst->buf = src->data.frame.buf;
dst->have_sse = 0; /* For alt-ref frame, don't store PSNR */ if (!(dst->flags & VPX_FRAME_IS_INVISIBLE)) {
dst->have_sse = ctx->have_sse; if (ctx->have_sse) { /* associate last-seen SSE to the frame. */ /* Transfers ownership from ctx to dst. */ /* WARNING! This makes the assumption that PSNR_PKT comes
just before the frame it refers to! */
memcpy(dst->sse, ctx->sse, sizeof(dst->sse));
ctx->have_sse = 0;
}
}
}
/** * 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, struct FrameListData *alpha_cx_frame, AVPacket *pkt)
{
VPxContext *ctx = avctx->priv_data; int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0);
uint8_t *side_data; int pict_type; int quality;
if (cx_frame->have_sse) { /* Beware of the Y/U/V/all order! */ for (int i = 0; i < 3; ++i)
avctx->error[i] += cx_frame->sse[i + 1];
cx_frame->have_sse = 0;
} if (alpha_cx_frame) {
side_data = av_packet_new_side_data(pkt,
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
alpha_cx_frame->sz + 8); if (!side_data) {
av_packet_unref(pkt); return AVERROR(ENOMEM);
}
AV_WB64(side_data, 1);
memcpy(side_data + 8, alpha_cx_frame->buf, alpha_cx_frame->sz);
}
ret = frame_data_apply(avctx, ctx->fifo, pkt); if (ret < 0) return ret;
return pkt->size;
}
/** * Queue multiple output frames from the encoder, returning the front-most. * In cases where vpx_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, struct vpx_codec_ctx *encoder, struct FrameListData **frame_list, AVPacket *pkt_out)
{
VPxContext *ctx = avctx->priv_data; conststruct vpx_codec_cx_pkt *pkt; constvoid *iter = NULL; int size = 0;
if (!ctx->is_alpha && *frame_list) { struct FrameListData *cx_frame = *frame_list; /* return the leading frame if we've already begun queueing */
size = storeframe(avctx, cx_frame, NULL, pkt_out); if (size < 0) return size;
*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 vpx_codec call */ while (pkt = vpx_codec_get_cx_data(encoder, &iter)) { switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: if (!ctx->is_alpha && !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(&cx_frame, pkt, ctx);
size = storeframe(avctx, &cx_frame, NULL, pkt_out); if (size < 0) return size;
} else { struct FrameListData *cx_frame = av_malloc(sizeof(*cx_frame));
if (!cx_frame) {
av_log(avctx, AV_LOG_ERROR, "Frame queue element alloc failed\n"); return AVERROR(ENOMEM);
}
cx_pktcpy(cx_frame, pkt, ctx);
cx_frame->buf = av_malloc(cx_frame->sz);
staticint set_roi_map(AVCodecContext *avctx, const AVFrameSideData *sd, int frame_width, int frame_height,
vpx_roi_map_t *roi_map, int block_size, int segment_cnt)
{ /** * range of vpx_roi_map_t.delta_q[i] is [-63, 63]
*/ #define MAX_DELTA_Q 63
const AVRegionOfInterest *roi = NULL; int nb_rois;
uint32_t self_size; int segment_id;
/* record the mapping from delta_q to "segment id + 1" in segment_mapping[]. * the range of delta_q is [-MAX_DELTA_Q, MAX_DELTA_Q], * and its corresponding array index is [0, 2 * MAX_DELTA_Q], * and so the length of the mapping array is 2 * MAX_DELTA_Q + 1. * "segment id + 1", so we can say there's no mapping if the value of array element is zero.
*/ int segment_mapping[2 * MAX_DELTA_Q + 1] = { 0 };
memset(roi_map, 0, sizeof(*roi_map));
/* segment id 0 in roi_map is reserved for the areas not covered by AVRegionOfInterest. * segment id 0 in roi_map is also for the areas with AVRegionOfInterest.qoffset near 0. * (delta_q of segment id 0 is 0).
*/
segment_mapping[MAX_DELTA_Q] = 1;
segment_id = 1;
/* This list must be iterated from zero because regions are * defined in order of decreasing importance. So discard less * important areas if they exceed the segment count.
*/ for (int i = 0; i < nb_rois; i++) { int delta_q; int mapping_index;
roi = (const AVRegionOfInterest*)(sd->data + self_size * i); if (!roi->qoffset.den) {
av_log(avctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n"); return AVERROR(EINVAL);
}
mapping_index = delta_q + MAX_DELTA_Q; if (!segment_mapping[mapping_index]) { if (segment_id == segment_cnt) {
av_log(avctx, AV_LOG_WARNING, "ROI only supports %d segments (and segment 0 is reserved for non-ROIs), skipping the left ones.\n",
segment_cnt); break;
}
/* This list must be iterated in reverse, so for the case that * two regions are overlapping, the more important area takes effect.
*/ for (int i = nb_rois - 1; i >= 0; i--) { int delta_q; int mapping_value; int starty, endy, startx, endx;
roi = (const AVRegionOfInterest*)(sd->data + self_size * i);
mapping_value = segment_mapping[delta_q + MAX_DELTA_Q]; if (mapping_value) { for (int y = starty; y < endy; y++) for (int x = startx; x < endx; x++)
roi_map->roi_map[x + y * roi_map->cols] = mapping_value - 1;
}
}
return 0;
}
staticint vp9_encode_set_roi(AVCodecContext *avctx, int frame_width, int frame_height, const AVFrameSideData *sd)
{
VPxContext *ctx = avctx->priv_data;
#ifdef VPX_CTRL_VP9E_SET_ROI_MAP int version = vpx_codec_version(); int major = VPX_VERSION_MAJOR(version); int minor = VPX_VERSION_MINOR(version); int patch = VPX_VERSION_PATCH(version);
if (major > 1 || (major == 1 && minor > 8) || (major == 1 && minor == 8 && patch >= 1)) {
vpx_roi_map_t roi_map; constint segment_cnt = 8; constint block_size = 8; int ret;
if (ctx->aq_mode > 0 || ctx->cpu_used < 5 || ctx->deadline != VPX_DL_REALTIME) { if (!ctx->roi_warned) {
ctx->roi_warned = 1;
av_log(avctx, AV_LOG_WARNING, "ROI is only enabled when aq_mode is 0, cpu_used >= 5 " "and deadline is REALTIME, so skipping ROI.\n"); return AVERROR(EINVAL);
}
}
ret = set_roi_map(avctx, sd, frame_width, frame_height, &roi_map, block_size, segment_cnt); if (ret) {
log_encoder_error(avctx, "Failed to set_roi_map.\n"); return ret;
}
if (vpx_codec_control(&ctx->encoder, VP9E_SET_ROI_MAP, &roi_map)) {
log_encoder_error(avctx, "Failed to set VP9E_SET_ROI_MAP codec control.\n");
ret = AVERROR_INVALIDDATA;
}
av_freep(&roi_map.roi_map); return ret;
} #endif
if (!ctx->roi_warned) {
ctx->roi_warned = 1;
av_log(avctx, AV_LOG_WARNING, "ROI is not supported, please upgrade libvpx to version >= 1.8.1. " "You may need to rebuild ffmpeg.\n");
} return 0;
}
int ret = set_roi_map(avctx, sd, frame_width, frame_height, &roi_map, block_size, segment_cnt); if (ret) {
log_encoder_error(avctx, "Failed to set_roi_map.\n"); return ret;
}
if (vpx_codec_control(&ctx->encoder, VP8E_SET_ROI_MAP, &roi_map)) {
log_encoder_error(avctx, "Failed to set VP8E_SET_ROI_MAP codec control.\n");
ret = AVERROR_INVALIDDATA;
}
av_freep(&roi_map.roi_map); return ret;
}
staticint realloc_alpha_uv(AVCodecContext *avctx, int width, int height)
{
VPxContext *ctx = avctx->priv_data; struct vpx_image *rawimg_alpha = &ctx->rawimg_alpha; unsignedchar **planes = rawimg_alpha->planes; int *stride = rawimg_alpha->stride;
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.