This commit allows for the decoding of field-coded pictures in the HQ profile of VC-2. What it basically does is it gets a single field while in HQ field-coded mode, does not output a frame on that field but waits for the second field, decodes it to the same frame as the last field (avoiding a memcpy) and then outputs a frame with the 2 fields interleaved. This is done in a bit of a hacky way since it works around the whole previous structure of the decoder which is needingly complex to support old Dirac P and B frames.
Signed-off-by: Rostislav Pehlivanov <atomnu...@gmail.com> --- libavcodec/dirac.c | 15 ++----- libavcodec/dirac.h | 1 + libavcodec/diracdec.c | 116 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 91 insertions(+), 41 deletions(-) diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c index 39df2a8..d19adcf 100644 --- a/libavcodec/dirac.c +++ b/libavcodec/dirac.c @@ -324,7 +324,7 @@ int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh, { AVDiracSeqHeader *dsh; GetBitContext gb; - unsigned video_format, picture_coding_mode; + unsigned video_format; int ret; dsh = av_mallocz(sizeof(*dsh)); @@ -373,17 +373,8 @@ int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh, if (ret < 0) goto fail; - /* [DIRAC_STD] picture_coding_mode shall be 0 for fields and 1 for frames - * currently only used to signal field coding */ - picture_coding_mode = svq3_get_ue_golomb(&gb); - if (picture_coding_mode != 0) { - if (log_ctx) { - av_log(log_ctx, AV_LOG_ERROR, "Unsupported picture coding mode %d", - picture_coding_mode); - } - ret = AVERROR_INVALIDDATA; - goto fail; - } + /* [DIRAC_STD] picture_coding_mode shall be 1 for fields and 0 for frames */ + dsh->field_coding = svq3_get_ue_golomb(&gb); *pdsh = dsh; return 0; diff --git a/libavcodec/dirac.h b/libavcodec/dirac.h index cb80fdc..447fafc 100644 --- a/libavcodec/dirac.h +++ b/libavcodec/dirac.h @@ -74,6 +74,7 @@ typedef struct AVDiracSeqHeader { uint8_t interlaced; uint8_t top_field_first; + uint8_t field_coding; uint8_t frame_rate_index; ///< index into dirac_frame_rate[] uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index ca44e7b..57a96bb 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -161,6 +161,8 @@ typedef struct DiracContext { int dc_prediction; /* has dc prediction */ int globalmc_flag; /* use global motion compensation */ int num_refs; /* number of reference pictures */ + int field_coding; /* fields instead of frames */ + int cur_field; /* 0 -> progressive/top, 1 -> bottom */ /* wavelet decoding */ unsigned wavelet_depth; /* depth of the IDWT */ @@ -227,6 +229,9 @@ typedef struct DiracContext { dirac_weight_func weight_func; dirac_biweight_func biweight_func; + DiracFrame dummy_picture; + + DiracFrame prev_field; DiracFrame *current_picture; DiracFrame *ref_pics[2]; @@ -456,9 +461,11 @@ static av_cold int dirac_decode_init(AVCodecContext *avctx) ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx); ff_videodsp_init(&s->vdsp, 8); + s->dummy_picture.avframe = av_frame_alloc(); for (i = 0; i < MAX_FRAMES; i++) { s->all_frames[i].avframe = av_frame_alloc(); if (!s->all_frames[i].avframe) { + av_frame_free(&s->dummy_picture.avframe); while (i > 0) av_frame_free(&s->all_frames[--i].avframe); return AVERROR(ENOMEM); @@ -482,6 +489,7 @@ static av_cold int dirac_decode_end(AVCodecContext *avctx) int i; dirac_decode_flush(avctx); + av_frame_free(&s->dummy_picture.avframe); for (i = 0; i < MAX_FRAMES; i++) av_frame_free(&s->all_frames[i].avframe); @@ -1822,6 +1830,7 @@ static int dirac_decode_frame_internal(DiracContext *s) for (comp = 0; comp < 3; comp++) { Plane *p = &s->plane[comp]; uint8_t *frame = s->current_picture->avframe->data[comp]; + frame += s->cur_field*p->stride; /* FIXME: small resolutions */ for (i = 0; i < 4; i++) @@ -1838,11 +1847,12 @@ static int dirac_decode_frame_internal(DiracContext *s) return ret; if (!s->num_refs) { /* intra */ + const int idx = (s->bit_depth - 8) >> 1; + const int ostride = p->stride << s->field_coding; for (y = 0; y < p->height; y += 16) { - int idx = (s->bit_depth - 8) >> 1; ff_spatial_idwt_slice2(&d, y+16); /* decode */ - s->diracdsp.put_signed_rect_clamped[idx](frame + y*p->stride, - p->stride, + s->diracdsp.put_signed_rect_clamped[idx](frame + y*ostride, + ostride, p->idwt_buf + y*p->idwt_stride, p->idwt_stride, p->width, 16); } @@ -1929,10 +1939,10 @@ static int dirac_decode_picture_header(DiracContext *s) GetBitContext *gb = &s->gb; /* [DIRAC_STD] 11.1.1 Picture Header. picture_header() PICTURE_NUM */ - picnum = s->current_picture->avframe->display_picture_number = get_bits_long(gb, 32); - - - av_log(s->avctx,AV_LOG_DEBUG,"PICTURE_NUM: %d\n",picnum); + if (!s->field_coding) { + picnum = s->current_picture->avframe->display_picture_number = get_bits_long(gb, 32); + av_log(s->avctx,AV_LOG_DEBUG,"PICTURE_NUM: %d\n",picnum); + } /* if this is the first keyframe after a sequence header, start our reordering from here */ @@ -2070,6 +2080,10 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int } ret = ff_set_dimensions(avctx, dsh->width, dsh->height); + + if (dsh->field_coding) + dsh->height >>= 1; + if (ret < 0) { av_freep(&dsh); return ret; @@ -2084,6 +2098,8 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int avctx->profile = dsh->profile; avctx->level = dsh->level; avctx->framerate = dsh->framerate; + avctx->field_order = dsh->top_field_first ? AV_FIELD_TT : avctx->field_order; + s->field_coding = dsh->field_coding; s->bit_depth = dsh->bit_depth; s->version.major = dsh->version.major; s->version.minor = dsh->version.minor; @@ -2117,17 +2133,22 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int return AVERROR_INVALIDDATA; } - /* find an unused frame */ - for (i = 0; i < MAX_FRAMES; i++) - if (s->all_frames[i].avframe->data[0] == NULL) - pic = &s->all_frames[i]; - if (!pic) { - av_log(avctx, AV_LOG_ERROR, "framelist full\n"); - return AVERROR_INVALIDDATA; + if (!s->field_coding) { + /* find an unused frame */ + for (i = 0; i < MAX_FRAMES; i++) { + if (s->all_frames[i].avframe->data[0] == NULL) + pic = &s->all_frames[i]; + if (!pic) { + av_log(avctx, AV_LOG_ERROR, "framelist full\n"); + return AVERROR_INVALIDDATA; + } + } + av_frame_unref(pic->avframe); + } else { + /* Setup a dummy picture in interlaced mode */ + pic = &s->dummy_picture; } - av_frame_unref(pic->avframe); - /* [DIRAC_STD] Defined in 9.6.1 ... */ tmp = parse_code & 0x03; /* [DIRAC_STD] num_refs() */ if (tmp > 2) { @@ -2154,20 +2175,54 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int return AVERROR_INVALIDDATA; } - if ((ret = get_buffer_with_edge(avctx, pic->avframe, (parse_code & 0x0C) == 0x0C ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) - return ret; - s->current_picture = pic; - s->plane[0].stride = pic->avframe->linesize[0]; - s->plane[1].stride = pic->avframe->linesize[1]; - s->plane[2].stride = pic->avframe->linesize[2]; + if (s->field_coding && !s->hq_picture) { + av_log(avctx, AV_LOG_ERROR, "Interlaced input supported only under the HQ profile!\n"); + return AVERROR_PATCHWELCOME; + } - if (alloc_buffers(s, FFMAX3(FFABS(s->plane[0].stride), FFABS(s->plane[1].stride), FFABS(s->plane[2].stride))) < 0) - return AVERROR(ENOMEM); + if (!s->field_coding) { + if ((ret = get_buffer_with_edge(avctx, pic->avframe, (parse_code & 0x0C) == 0x0C ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) + return ret; + s->current_picture = pic; + s->plane[0].stride = pic->avframe->linesize[0]; + s->plane[1].stride = pic->avframe->linesize[1]; + s->plane[2].stride = pic->avframe->linesize[2]; - /* [DIRAC_STD] 11.1 Picture parse. picture_parse() */ - ret = dirac_decode_picture_header(s); - if (ret < 0) - return ret; + if (alloc_buffers(s, FFMAX3(FFABS(s->plane[0].stride), FFABS(s->plane[1].stride), FFABS(s->plane[2].stride))) < 0) + return AVERROR(ENOMEM); + + /* [DIRAC_STD] 11.1 Picture parse. picture_parse() */ + ret = dirac_decode_picture_header(s); + if (ret < 0) + return ret; + } else { + /* [DIRAC_STD] 11.1.1 Picture Header. picture_header() PICTURE_NUM */ + uint32_t pict_num = get_bits_long(&s->gb, 32); + av_log(s->avctx,AV_LOG_DEBUG,"PICTURE_NUM: %d\n",pict_num); + + s->cur_field = pict_num & 1; + + if (!s->cur_field) { + av_frame_unref(s->prev_field.avframe); + if ((ret = get_buffer_with_edge(avctx, pic->avframe, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + s->prev_field.avframe = pic->avframe; + s->plane[0].stride = pic->avframe->linesize[0]; + s->plane[1].stride = pic->avframe->linesize[1]; + s->plane[2].stride = pic->avframe->linesize[2]; + s->current_picture = &s->prev_field; + } else { + s->plane[0].stride = s->current_picture->avframe->linesize[0]; + s->plane[1].stride = s->current_picture->avframe->linesize[1]; + s->plane[2].stride = s->current_picture->avframe->linesize[2]; + s->current_picture->avframe = s->prev_field.avframe; + s->current_picture->avframe->display_picture_number = s->frame_number; + } + + ret = dirac_decode_picture_header(s); + if (ret < 0) + return ret; + } /* [DIRAC_STD] 13.0 Transform data syntax. transform_data() */ ret = dirac_decode_frame_internal(s); @@ -2194,7 +2249,6 @@ static int dirac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, memset(s->all_frames[i].interpolated, 0, sizeof(s->all_frames[i].interpolated)); } - s->current_picture = NULL; *got_frame = 0; /* end of stream, so flush delayed pics */ @@ -2267,6 +2321,10 @@ static int dirac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, *got_frame = 1; } + /* No output for the top field, wait for the second */ + if (s->field_coding && !s->cur_field) + *got_frame = 0; + if (*got_frame) s->frame_number = picture->display_picture_number + 1; -- 2.7.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel