#include "libavutil/md5.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/stereo3d.h"
#include "bytestream.h"
#include "cabac_functions.h"
const HEVCSPS *sps = s->sps;
int max_poc_lsb = 1 << sps->log2_max_poc_lsb;
int prev_delta_msb = 0;
- int nb_sps = 0, nb_sh;
+ unsigned int nb_sps = 0, nb_sh;
int i;
rps->nb_refs = 0;
static int set_sps(HEVCContext *s, const HEVCSPS *sps)
{
int ret;
+ int num = 0, den = 0;
pic_arrays_free(s);
ret = pic_arrays_init(s, sps);
}
s->sps = sps;
- s->vps = s->vps_list[s->sps->vps_id];
+ s->vps = (HEVCVPS*) s->vps_list[s->sps->vps_id]->data;
+
+ if (s->vps->vps_timing_info_present_flag) {
+ num = s->vps->vps_num_units_in_tick;
+ den = s->vps->vps_time_scale;
+ } else if (sps->vui.vui_timing_info_present_flag) {
+ num = sps->vui.vui_num_units_in_tick;
+ den = sps->vui.vui_time_scale;
+ }
+
+ if (num != 0 && den != 0)
+ av_reduce(&s->avctx->time_base.num, &s->avctx->time_base.den,
+ num, den, 1 << 30);
+
return 0;
fail:
s->max_ra = INT_MAX;
}
+ s->avctx->profile = s->sps->ptl.general_ptl.profile_idc;
+ s->avctx->level = s->sps->ptl.general_ptl.level_idc;
+
sh->dependent_slice_segment_flag = 0;
if (!sh->first_slice_in_pic_flag) {
int slice_address_length;
}
sh->slice_qp_delta = get_se_golomb(gb);
+
if (s->pps->pic_slice_level_chroma_qp_offsets_present_flag) {
sh->slice_cb_qp_offset = get_se_golomb(gb);
sh->slice_cr_qp_offset = get_se_golomb(gb);
}
if (s->pps->slice_header_extension_present_flag) {
- int length = get_ue_golomb_long(gb);
+ unsigned int length = get_ue_golomb_long(gb);
for (i = 0; i < length; i++)
skip_bits(gb, 8); // slice_header_extension_data_byte
}
// Inferred parameters
- sh->slice_qp = 26 + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta;
+ sh->slice_qp = 26 + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta;
+ if (sh->slice_qp > 51 ||
+ sh->slice_qp < -s->sps->qp_bd_offset) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "The slice_qp %d is outside the valid range "
+ "[%d, 51].\n",
+ sh->slice_qp,
+ -s->sps->qp_bd_offset);
+ return AVERROR_INVALIDDATA;
+ }
+
sh->slice_ctb_addr_rs = sh->slice_segment_addr;
+ if (!s->sh.slice_ctb_addr_rs && s->sh.dependent_slice_segment_flag) {
+ av_log(s->avctx, AV_LOG_ERROR, "Impossible slice segment.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
s->HEVClc.first_qp_group = !s->sh.dependent_slice_segment_flag;
if (!s->pps->cu_qp_delta_enabled_flag)
- s->HEVClc.qp_y = ((s->sh.slice_qp + 52 + 2 * s->sps->qp_bd_offset) %
- (52 + s->sps->qp_bd_offset)) - s->sps->qp_bd_offset;
+ s->HEVClc.qp_y = FFUMOD(s->sh.slice_qp + 52 + 2 * s->sps->qp_bd_offset,
+ 52 + s->sps->qp_bd_offset) - s->sps->qp_bd_offset;
s->slice_initialized = 1;
}
}
-static void hls_transform_unit(HEVCContext *s, int x0, int y0,
- int xBase, int yBase, int cb_xBase, int cb_yBase,
- int log2_cb_size, int log2_trafo_size,
- int trafo_depth, int blk_idx)
+static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+ int xBase, int yBase, int cb_xBase, int cb_yBase,
+ int log2_cb_size, int log2_trafo_size,
+ int trafo_depth, int blk_idx)
{
HEVCLocalContext *lc = &s->HEVClc;
if (ff_hevc_cu_qp_delta_sign_flag(s) == 1)
lc->tu.cu_qp_delta = -lc->tu.cu_qp_delta;
lc->tu.is_cu_qp_delta_coded = 1;
+
+ if (lc->tu.cu_qp_delta < -(26 + s->sps->qp_bd_offset / 2) ||
+ lc->tu.cu_qp_delta > (25 + s->sps->qp_bd_offset / 2)) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "The cu_qp_delta %d is outside the valid range "
+ "[%d, %d].\n",
+ lc->tu.cu_qp_delta,
+ -(26 + s->sps->qp_bd_offset / 2),
+ (25 + s->sps->qp_bd_offset / 2));
+ return AVERROR_INVALIDDATA;
+ }
+
ff_hevc_set_qPy(s, x0, y0, cb_xBase, cb_yBase, log2_cb_size);
}
hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 2);
}
}
+ return 0;
}
static void set_deblocking_bypass(HEVCContext *s, int x0, int y0, int log2_cb_size)
s->is_pcm[i + j * min_pu_width] = 2;
}
-static void hls_transform_tree(HEVCContext *s, int x0, int y0,
- int xBase, int yBase, int cb_xBase, int cb_yBase,
- int log2_cb_size, int log2_trafo_size,
- int trafo_depth, int blk_idx)
+static int hls_transform_tree(HEVCContext *s, int x0, int y0,
+ int xBase, int yBase, int cb_xBase, int cb_yBase,
+ int log2_cb_size, int log2_trafo_size,
+ int trafo_depth, int blk_idx)
{
HEVCLocalContext *lc = &s->HEVClc;
uint8_t split_transform_flag;
+ int ret;
if (trafo_depth > 0 && log2_trafo_size == 2) {
SAMPLE_CBF(lc->tt.cbf_cb[trafo_depth], x0, y0) =
int x1 = x0 + ((1 << log2_trafo_size) >> 1);
int y1 = y0 + ((1 << log2_trafo_size) >> 1);
- hls_transform_tree(s, x0, y0, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
- log2_trafo_size - 1, trafo_depth + 1, 0);
- hls_transform_tree(s, x1, y0, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
- log2_trafo_size - 1, trafo_depth + 1, 1);
- hls_transform_tree(s, x0, y1, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
- log2_trafo_size - 1, trafo_depth + 1, 2);
- hls_transform_tree(s, x1, y1, x0, y0, cb_xBase, cb_yBase, log2_cb_size,
- log2_trafo_size - 1, trafo_depth + 1, 3);
+ ret = hls_transform_tree(s, x0, y0, x0, y0, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size - 1,
+ trafo_depth + 1, 0);
+ if (ret < 0)
+ return ret;
+ ret = hls_transform_tree(s, x1, y0, x0, y0, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size - 1,
+ trafo_depth + 1, 1);
+ if (ret < 0)
+ return ret;
+ ret = hls_transform_tree(s, x0, y1, x0, y0, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size - 1,
+ trafo_depth + 1, 2);
+ if (ret < 0)
+ return ret;
+ ret = hls_transform_tree(s, x1, y1, x0, y0, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size - 1,
+ trafo_depth + 1, 3);
+ if (ret < 0)
+ return ret;
} else {
int min_tu_size = 1 << s->sps->log2_min_tb_size;
int log2_min_tu_size = s->sps->log2_min_tb_size;
lc->tt.cbf_luma = ff_hevc_cbf_luma_decode(s, trafo_depth);
}
- hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase,
- log2_cb_size, log2_trafo_size, trafo_depth, blk_idx);
-
+ ret = hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase,
+ log2_cb_size, log2_trafo_size, trafo_depth,
+ blk_idx);
+ if (ret < 0)
+ return ret;
// TODO: store cbf_luma somewhere else
if (lc->tt.cbf_luma) {
int i, j;
set_deblocking_bypass(s, x0, y0, log2_trafo_size);
}
}
+ return 0;
}
static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
int stride2 = s->frame->linesize[2];
uint8_t *dst2 = &s->frame->data[2][(y0 >> s->sps->vshift[2]) * stride2 + ((x0 >> s->sps->hshift[2]) << s->sps->pixel_shift)];
- int length = cb_size * cb_size * s->sps->pcm.bit_depth + ((cb_size * cb_size) >> 1) * s->sps->pcm.bit_depth;
+ int length = cb_size * cb_size * s->sps->pcm.bit_depth + ((cb_size * cb_size) >> 1) * s->sps->pcm.bit_depth_chroma;
const uint8_t *pcm = skip_bytes(&s->HEVClc.cc, (length + 7) >> 3);
int ret;
return ret;
s->hevcdsp.put_pcm(dst0, stride0, cb_size, &gb, s->sps->pcm.bit_depth);
- s->hevcdsp.put_pcm(dst1, stride1, cb_size / 2, &gb, s->sps->pcm.bit_depth);
- s->hevcdsp.put_pcm(dst2, stride2, cb_size / 2, &gb, s->sps->pcm.bit_depth);
+ s->hevcdsp.put_pcm(dst1, stride1, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
+ s->hevcdsp.put_pcm(dst2, stride2, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
return 0;
}
if (x_off < extra_left || y_off < extra_top ||
x_off >= pic_width - block_w - ff_hevc_qpel_extra_after[mx] ||
y_off >= pic_height - block_h - ff_hevc_qpel_extra_after[my]) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
int offset = extra_top * srcstride + (extra_left << s->sps->pixel_shift);
+ int buf_offset = extra_top *
+ edge_emu_stride + (extra_left << s->sps->pixel_shift);
s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src - offset,
- srcstride, srcstride,
+ edge_emu_stride, srcstride,
block_w + ff_hevc_qpel_extra[mx],
block_h + ff_hevc_qpel_extra[my],
x_off - extra_left, y_off - extra_top,
pic_width, pic_height);
- src = lc->edge_emu_buffer + offset;
+ src = lc->edge_emu_buffer + buf_offset;
+ srcstride = edge_emu_stride;
}
s->hevcdsp.put_hevc_qpel[my][mx](dst, dststride, src, srcstride, block_w,
block_h, lc->mc_buffer);
if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER ||
x_off >= pic_width - block_w - EPEL_EXTRA_AFTER ||
y_off >= pic_height - block_h - EPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift));
+ int buf_offset1 = EPEL_EXTRA_BEFORE *
+ (edge_emu_stride + (1 << s->sps->pixel_shift));
int offset2 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift));
+ int buf_offset2 = EPEL_EXTRA_BEFORE *
+ (edge_emu_stride + (1 << s->sps->pixel_shift));
s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1 - offset1,
- src1stride, src1stride,
+ edge_emu_stride, src1stride,
block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
x_off - EPEL_EXTRA_BEFORE,
y_off - EPEL_EXTRA_BEFORE,
pic_width, pic_height);
- src1 = lc->edge_emu_buffer + offset1;
+ src1 = lc->edge_emu_buffer + buf_offset1;
+ src1stride = edge_emu_stride;
s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
block_w, block_h, mx, my, lc->mc_buffer);
s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src2 - offset2,
- src2stride, src2stride,
+ edge_emu_stride, src2stride,
block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
x_off - EPEL_EXTRA_BEFORE,
y_off - EPEL_EXTRA_BEFORE,
pic_width, pic_height);
- src2 = lc->edge_emu_buffer + offset2;
+ src2 = lc->edge_emu_buffer + buf_offset2;
+ src2stride = edge_emu_stride;
+
s->hevcdsp.put_hevc_epel[!!my][!!mx](dst2, dststride, src2, src2stride,
block_w, block_h, mx, my,
lc->mc_buffer);
int min_cb_width = s->sps->min_cb_width;
int x_cb = x0 >> log2_min_cb_size;
int y_cb = y0 >> log2_min_cb_size;
- int x, y;
+ int x, y, ret;
lc->cu.x = x0;
lc->cu.y = y0;
lc->cu.pcm_flag = ff_hevc_pcm_flag_decode(s);
}
if (lc->cu.pcm_flag) {
- int ret;
intra_prediction_unit_default_value(s, x0, y0, log2_cb_size);
ret = hls_pcm_sample(s, x0, y0, log2_cb_size);
if (s->sps->pcm.loop_filter_disable_flag)
lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ?
s->sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag :
s->sps->max_transform_hierarchy_depth_inter;
- hls_transform_tree(s, x0, y0, x0, y0, x0, y0, log2_cb_size,
- log2_cb_size, 0, 0);
+ ret = hls_transform_tree(s, x0, y0, x0, y0, x0, y0,
+ log2_cb_size,
+ log2_cb_size, 0, 0);
+ if (ret < 0)
+ return ret;
} else {
if (!s->sh.disable_deblocking_filter_flag)
ff_hevc_deblocking_boundary_strengths(s, x0, y0, log2_cb_size,
}
}
+static int set_side_data(HEVCContext *s)
+{
+ AVFrame *out = s->ref->frame;
+
+ if (s->sei_frame_packing_present &&
+ s->frame_packing_arrangement_type >= 3 &&
+ s->frame_packing_arrangement_type <= 5 &&
+ s->content_interpretation_type > 0 &&
+ s->content_interpretation_type < 3) {
+ AVStereo3D *stereo = av_stereo3d_create_side_data(out);
+ if (!stereo)
+ return AVERROR(ENOMEM);
+
+ switch (s->frame_packing_arrangement_type) {
+ case 3:
+ if (s->quincunx_subsampling)
+ stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
+ else
+ stereo->type = AV_STEREO3D_SIDEBYSIDE;
+ break;
+ case 4:
+ stereo->type = AV_STEREO3D_TOPBOTTOM;
+ break;
+ case 5:
+ stereo->type = AV_STEREO3D_FRAMESEQUENCE;
+ break;
+ }
+
+ if (s->content_interpretation_type == 2)
+ stereo->flags = AV_STEREO3D_FLAG_INVERT;
+ }
+
+ return 0;
+}
+
static int hevc_frame_start(HEVCContext *s)
{
HEVCLocalContext *lc = &s->HEVClc;
lc->start_of_tiles_x = 0;
s->is_decoded = 0;
+ s->first_nal_type = s->nal_unit_type;
if (s->pps->tiles_enabled_flag)
lc->end_of_tiles_x = s->pps->column_width[0] << s->sps->log2_ctb_size;
if (ret < 0)
goto fail;
- av_fast_malloc(&lc->edge_emu_buffer, &lc->edge_emu_buffer_size,
- (MAX_PB_SIZE + 7) * s->ref->frame->linesize[0]);
- if (!lc->edge_emu_buffer) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
ret = ff_hevc_frame_rps(s);
if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Error constructing the frame RPS.\n");
goto fail;
}
+ ret = set_side_data(s);
+ if (ret < 0)
+ goto fail;
+
av_frame_unref(s->output_frame);
ret = ff_hevc_output_frame(s, s->output_frame, 0);
if (ret < 0)
return AVERROR_INVALIDDATA;
}
+ if (s->nal_unit_type != s->first_nal_type) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Non-matching NAL types of the VCL NALUs: %d %d\n",
+ s->first_nal_type, s->nal_unit_type);
+ return AVERROR_INVALIDDATA;
+ }
+
if (!s->sh.dependent_slice_segment_flag &&
s->sh.slice_type != I_SLICE) {
ret = ff_hevc_slice_rpl(s);
static int verify_md5(HEVCContext *s, AVFrame *frame)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
- int pixel_shift = desc->comp[0].depth_minus1 > 7;
+ int pixel_shift;
int i, j;
if (!desc)
return AVERROR(EINVAL);
+ pixel_shift = desc->comp[0].depth_minus1 > 7;
+
av_log(s->avctx, AV_LOG_DEBUG, "Verifying checksum for frame with POC %d: ",
s->poc);
static av_cold int hevc_decode_free(AVCodecContext *avctx)
{
HEVCContext *s = avctx->priv_data;
- HEVCLocalContext *lc = &s->HEVClc;
int i;
pic_arrays_free(s);
- av_freep(&lc->edge_emu_buffer);
av_freep(&s->md5_ctx);
av_frame_free(&s->tmp_frame);
}
for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++)
- av_freep(&s->vps_list[i]);
+ av_buffer_unref(&s->vps_list[i]);
for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++)
av_buffer_unref(&s->sps_list[i]);
for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
}
}
+ for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++) {
+ av_buffer_unref(&s->vps_list[i]);
+ if (s0->vps_list[i]) {
+ s->vps_list[i] = av_buffer_ref(s0->vps_list[i]);
+ if (!s->vps_list[i])
+ return AVERROR(ENOMEM);
+ }
+ }
+
for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++) {
av_buffer_unref(&s->sps_list[i]);
if (s0->sps_list[i]) {
#define OFFSET(x) offsetof(HEVCContext, x)
#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
+
+static const AVProfile profiles[] = {
+ { FF_PROFILE_HEVC_MAIN, "Main" },
+ { FF_PROFILE_HEVC_MAIN_10, "Main 10" },
+ { FF_PROFILE_HEVC_MAIN_STILL_PICTURE, "Main Still Picture" },
+ { FF_PROFILE_UNKNOWN },
+};
+
static const AVOption options[] = {
{ "apply_defdispwin", "Apply default display window from VUI", OFFSET(apply_defdispwin),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR },
.init_thread_copy = hevc_init_thread_copy,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY |
CODEC_CAP_FRAME_THREADS,
+ .profiles = NULL_IF_CONFIG_SMALL(profiles),
};