Commit 064698d3 authored by Guillaume Martres's avatar Guillaume Martres Committed by Anton Khirnov

Add HEVC decoder

Initially written by Guillaume Martres <smarter@ubuntu.com> as a GSoC
project. Further contributions by the OpenHEVC project and other
developers, namely:

Mickaël Raulet <mraulet@insa-rennes.fr>
Seppo Tomperi <seppo.tomperi@vtt.fi>
Gildas Cocherel <gildas.cocherel@laposte.net>
Khaled Jerbi <khaled_jerbi@yahoo.fr>
Wassim Hamidouche <wassim.hamidouche@insa-rennes.fr>
Vittorio Giovara <vittorio.giovara@gmail.com>
Jan Ekström <jeebjp@gmail.com>
Anton Khirnov <anton@khirnov.net>
Martin Storsjö <martin@martin.st>
Luca Barbato <lu_zero@gentoo.org>
Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
Reimar Döffinger <Reimar.Doeffinger@gmx.de>
Diego Biurrun <diego@biurrun.de>
Signed-off-by: default avatarAnton Khirnov <anton@khirnov.net>
parent 0a9e94bb
......@@ -41,6 +41,7 @@ version 10:
- Enhanced Low Delay AAC (ER AAC ELD) decoding (no LD SBR support)
- F4V muxer
- HNM version 4 demuxer and video decoder
- HEVC decoder
version 9:
......
......@@ -1599,6 +1599,7 @@ h263i_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="golomb h264chroma h264dsp h264pred h264qpel videodsp"
h264_decoder_suggest="error_resilience"
hevc_decoder_select="dsputil golomb videodsp"
huffyuv_decoder_select="dsputil"
huffyuv_encoder_select="dsputil huffman"
iac_decoder_select="dsputil fft mdct sinewin"
......
......@@ -526,6 +526,7 @@ following image formats are supported:
@item H.263+ / H.263-1998 / H.263 version 2 @tab X @tab X
@item H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 @tab E @tab X
@tab encoding supported through external library libx264
@item HEVC @tab @tab X
@item HNM version 4 @tab @tab X
@item HuffYUV @tab X @tab X
@item HuffYUV FFmpeg variant @tab X @tab X
......
......@@ -196,6 +196,9 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \
h264_loopfilter.o h264_direct.o \
cabac.o h264_sei.o h264_ps.o \
h264_refs.o h264_cavlc.o h264_cabac.o
OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
hevc_cabac.o hevc_refs.o hevcpred.o \
hevcdsp.o hevc_filter.o cabac.o
OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o
OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
......@@ -635,6 +638,7 @@ OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264.o \
h264_refs.o h264_sei.o h264_direct.o \
h264_loopfilter.o h264_cabac.o \
h264_cavlc.o h264_ps.o
OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o
OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o
OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o
OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \
......
......@@ -153,6 +153,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(H263I, h263i);
REGISTER_ENCODER(H263P, h263p);
REGISTER_DECODER(H264, h264);
REGISTER_DECODER(HEVC, hevc);
REGISTER_DECODER(HNM4_VIDEO, hnm4_video);
REGISTER_ENCDEC (HUFFYUV, huffyuv);
REGISTER_DECODER(IDCIN, idcin);
......@@ -453,6 +454,7 @@ void avcodec_register_all(void)
REGISTER_PARSER(H261, h261);
REGISTER_PARSER(H263, h263);
REGISTER_PARSER(H264, h264);
REGISTER_PARSER(HEVC, hevc);
REGISTER_PARSER(MJPEG, mjpeg);
REGISTER_PARSER(MLP, mlp);
REGISTER_PARSER(MPEG4VIDEO, mpeg4video);
......
......@@ -275,6 +275,7 @@ enum AVCodecID {
AV_CODEC_ID_G2M,
AV_CODEC_ID_WEBP,
AV_CODEC_ID_HNM4_VIDEO,
AV_CODEC_ID_HEVC,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
......
......@@ -162,4 +162,24 @@ static int av_unused get_cabac_terminate(CABACContext *c){
}
}
/**
* Skip @p n bytes and reset the decoder.
* @return the address of the first skipped byte or NULL if there's less than @p n bytes left
*/
static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) {
const uint8_t *ptr = c->bytestream;
if (c->low & 0x1)
ptr--;
#if CABAC_BITS == 16
if (c->low & 0x1FF)
ptr--;
#endif
if ((int) (c->bytestream_end - ptr) < n)
return NULL;
ff_init_cabac_decoder(c, ptr + n, c->bytestream_end - ptr - n);
return ptr;
}
#endif /* AVCODEC_CABAC_FUNCTIONS_H */
......@@ -1243,6 +1243,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"),
.props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_HEVC,
.type = AVMEDIA_TYPE_VIDEO,
.name = "hevc",
.long_name = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
.props = AV_CODEC_PROP_LOSSY,
},
/* various PCM "codecs" */
{
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* HEVC Annex B format parser
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
* This file is part of Libav.
*
* Libav 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,
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/common.h"
#include "parser.h"
#include "hevc.h"
#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or END_NOT_FOUND
*/
static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
int buf_size)
{
int i;
ParseContext *pc = s->priv_data;
for (i = 0; i < buf_size; i++) {
int nut;
pc->state64 = (pc->state64 << 8) | buf[i];
if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE)
continue;
nut = (pc->state64 >> 2 * 8 + 1) & 0x3F;
// Beginning of access unit
if ((nut >= NAL_VPS && nut <= NAL_AUD) || nut == NAL_SEI_PREFIX ||
(nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) {
if (pc->frame_start_found) {
pc->frame_start_found = 0;
return i - 5;
}
} else if (nut <= NAL_RASL_R ||
(nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT)) {
int first_slice_segment_in_pic_flag = buf[i] >> 7;
if (first_slice_segment_in_pic_flag) {
if (!pc->frame_start_found) {
pc->frame_start_found = 1;
s->key_frame = nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT;
} else { // First slice of next frame found
pc->frame_start_found = 0;
return i - 5;
}
}
}
}
return END_NOT_FOUND;
}
static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
int next;
ParseContext *pc = s->priv_data;
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
next = buf_size;
} else {
next = hevc_find_frame_end(s, buf, buf_size);
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
return buf_size;
}
}
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
}
// Split after the parameter sets at the beginning of the stream if they exist.
static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
{
int i;
uint32_t state = -1;
int has_ps = 0;
for (i = 0; i < buf_size; i++) {
state = (state << 8) | buf[i];
if (((state >> 8) & 0xFFFFFF) == START_CODE) {
int nut = (state >> 1) & 0x3F;
if (nut >= NAL_VPS && nut <= NAL_PPS)
has_ps = 1;
else if (has_ps)
return i - 3;
else // no parameter set at the beginning of the stream
return 0;
}
}
return 0;
}
AVCodecParser ff_hevc_parser = {
.codec_ids = { AV_CODEC_ID_HEVC },
.priv_data_size = sizeof(ParseContext),
.parser_parse = hevc_parse,
.parser_close = ff_parse_close,
.split = hevc_split,
};
This diff is collapsed.
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
*
* This file is part of Libav.
*
* Libav 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,
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/pixdesc.h"
#include "internal.h"
#include "thread.h"
#include "hevc.h"
void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
{
/* frame->frame can be NULL if context init failed */
if (!frame->frame || !frame->frame->buf[0])
return;
frame->flags &= ~flags;
if (!frame->flags) {
ff_thread_release_buffer(s->avctx, &frame->tf);
av_buffer_unref(&frame->tab_mvf_buf);
frame->tab_mvf = NULL;
av_buffer_unref(&frame->rpl_buf);
av_buffer_unref(&frame->rpl_tab_buf);
frame->rpl_tab = NULL;
frame->refPicList = NULL;
frame->collocated_ref = NULL;
}
}
RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0)
{
if (x0 < 0 || y0 < 0) {
return s->ref->refPicList;
} else {
int x_cb = x0 >> s->sps->log2_ctb_size;
int y_cb = y0 >> s->sps->log2_ctb_size;
int pic_width_cb = (s->sps->width + (1 << s->sps->log2_ctb_size) - 1) >>
s->sps->log2_ctb_size;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
return (RefPicList *)ref->rpl_tab[ctb_addr_ts];
}
}
void ff_hevc_clear_refs(HEVCContext *s)
{
int i;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
ff_hevc_unref_frame(s, &s->DPB[i],
HEVC_FRAME_FLAG_SHORT_REF |
HEVC_FRAME_FLAG_LONG_REF);
}
void ff_hevc_flush_dpb(HEVCContext *s)
{
int i;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
ff_hevc_unref_frame(s, &s->DPB[i], ~0);
}
static HEVCFrame *alloc_frame(HEVCContext *s)
{
int i, j, ret;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if (frame->frame->buf[0])
continue;
ret = ff_thread_get_buffer(s->avctx, &frame->tf,
AV_GET_BUFFER_FLAG_REF);
if (ret < 0)
return NULL;
frame->rpl_buf = av_buffer_allocz(s->nb_nals * sizeof(RefPicListTab));
if (!frame->rpl_buf)
goto fail;
frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool);
if (!frame->tab_mvf_buf)
goto fail;
frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data;
frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool);
if (!frame->rpl_tab_buf)
goto fail;
frame->rpl_tab = (RefPicListTab **)frame->rpl_tab_buf->data;
frame->ctb_count = s->sps->ctb_width * s->sps->ctb_height;
for (j = 0; j < frame->ctb_count; j++)
frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data;
return frame;
fail:
ff_hevc_unref_frame(s, frame, ~0);
return NULL;
}
av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n");
return NULL;
}
int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc)
{
HEVCFrame *ref;
int i;
/* check that this POC doesn't already exist */
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if (frame->frame->buf[0] && frame->sequence == s->seq_decode &&
frame->poc == poc) {
av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n",
poc);
return AVERROR_INVALIDDATA;
}
}
ref = alloc_frame(s);
if (!ref)
return AVERROR(ENOMEM);
*frame = ref->frame;
s->ref = ref;
ref->poc = poc;
ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
ref->sequence = s->seq_decode;
ref->window = s->sps->output_window;
return 0;
}
int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
{
do {
int nb_output = 0;
int min_poc = INT_MAX;
int i, min_idx, ret;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) &&
frame->sequence == s->seq_output) {
nb_output++;
if (frame->poc < min_poc) {
min_poc = frame->poc;
min_idx = i;
}
}
}
/* wait for more frames before output */
if (!flush && s->seq_output == s->seq_decode && s->sps &&
nb_output <= s->sps->temporal_layer[s->sps->max_sub_layers - 1].num_reorder_pics)
return 0;
if (nb_output) {
HEVCFrame *frame = &s->DPB[min_idx];
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->frame->format);
int pixel_shift;
if (!desc)
return AVERROR_BUG;
pixel_shift = desc->comp[0].depth_minus1 > 7;
ret = av_frame_ref(out, frame->frame);
ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
if (ret < 0)
return ret;
for (i = 0; i < 3; i++) {
int hshift = (i > 0) ? desc->log2_chroma_w : 0;
int vshift = (i > 0) ? desc->log2_chroma_h : 0;
int off = ((frame->window.left_offset >> hshift) << pixel_shift) +
(frame->window.top_offset >> vshift) * out->linesize[i];
out->data[i] += off;
}
av_log(s->avctx, AV_LOG_DEBUG,
"Output frame with POC %d.\n", frame->poc);
return 1;
}
if (s->seq_output != s->seq_decode)
s->seq_output = (s->seq_output + 1) & 0xff;
else
break;
} while (1);
return 0;
}
static int init_slice_rpl(HEVCContext *s)
{
HEVCFrame *frame = s->ref;
int ctb_count = frame->ctb_count;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr];
int i;
if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab))
return AVERROR_INVALIDDATA;
for (i = ctb_addr_ts; i < ctb_count; i++)
frame->rpl_tab[i] = (RefPicListTab *)frame->rpl_buf->data + s->slice_idx;
frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts];
return 0;
}
int ff_hevc_slice_rpl(HEVCContext *s)
{
SliceHeader *sh = &s->sh;
uint8_t nb_list = sh->slice_type == B_SLICE ? 2 : 1;
uint8_t list_idx;
int i, j, ret;
ret = init_slice_rpl(s);
if (ret < 0)
return ret;
if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs +
s->rps[LT_CURR].nb_refs)) {
av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n");
return AVERROR_INVALIDDATA;
}
for (list_idx = 0; list_idx < nb_list; list_idx++) {
RefPicList rpl_tmp = { { 0 } };
RefPicList *rpl = &s->ref->refPicList[list_idx];
/* The order of the elements is
* ST_CURR_BEF - ST_CURR_AFT - LT_CURR for the L0 and
* ST_CURR_AFT - ST_CURR_BEF - LT_CURR for the L1 */
int cand_lists[3] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF,
list_idx ? ST_CURR_BEF : ST_CURR_AFT,
LT_CURR };
/* concatenate the candidate lists for the current frame */
while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) {
for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) {
RefPicList *rps = &s->rps[cand_lists[i]];
for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < MAX_REFS; j++) {
rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j];
rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j];
rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = i == 2;
rpl_tmp.nb_refs++;
}
}
}
/* reorder the references if necessary */
if (sh->rpl_modification_flag[list_idx]) {
for (i = 0; i < sh->nb_refs[list_idx]; i++) {
int idx = sh->list_entry_lx[list_idx][i];
if (idx >= rpl_tmp.nb_refs) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n");
return AVERROR_INVALIDDATA;
}
rpl->list[i] = rpl_tmp.list[idx];
rpl->ref[i] = rpl_tmp.ref[idx];
rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx];
rpl->nb_refs++;
}
} else {
memcpy(rpl, &rpl_tmp, sizeof(*rpl));
rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]);
}
if (sh->collocated_list == list_idx &&
sh->collocated_ref_idx < rpl->nb_refs)
s->ref->collocated_ref = rpl->ref[sh->collocated_ref_idx];
}
return 0;
}
static HEVCFrame *find_ref_idx(HEVCContext *s, int poc)
{
int i;
int LtMask = (1 << s->sps->log2_max_poc_lsb) - 1;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *ref = &s->DPB[i];
if (ref->frame->buf[0] && (ref->sequence == s->seq_decode)) {
if ((ref->poc & LtMask) == poc)
return ref;
}
}
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *ref = &s->DPB[i];
if (ref->frame->buf[0] && ref->sequence == s->seq_decode) {
if (ref->poc == poc || (ref->poc & LtMask) == poc)
return ref;
}
}
av_log(s->avctx, AV_LOG_ERROR,
"Could not find ref with POC %d\n", poc);
return NULL;
}
static void mark_ref(HEVCFrame *frame, int flag)
{
frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF);
frame->flags |= flag;
}
static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
{
HEVCFrame *frame;
int i, x, y;
frame = alloc_frame(s);
if (!frame)
return NULL;
if (!s->sps->pixel_shift) {
for (i = 0; frame->frame->buf[i]; i++)
memset(frame->frame->buf[i]->data, 1 << (s->sps->bit_depth - 1),
frame->frame->buf[i]->size);
} else {
for (i = 0; frame->frame->data[i]; i++)
for (y = 0; y < (s->sps->height >> s->sps->vshift[i]); y++)
for (x = 0; x < (s->sps->width >> s->sps->hshift[i]); x++) {
AV_WN16(frame->frame->data[i] + y * frame->frame->linesize[i] + 2 * x,
1 << (s->sps->bit_depth - 1));
}
}