[PATCH 12/18] avcodec/h264: implement inter-view reference list modification
Dom Cobley via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
A coded slice extension carries ref_pic_list_mvc_modification() rather than ref_pic_list_modification() (H.7.3.3.1.1), which has two further values of modification_of_pic_nums_idc: 4 and 5 select an inter-view reference by walking the inter-view dependency list of the current view, as per H.8.2.2.3. These were rejected as illegal, which failed the slice header of every dependent view slice in a stream that uses them -- and real streams overwhelmingly do, since it is how the inter-view reference is placed at index 0. The value names a view rather than a picture, so duplicates are identified by view when the list is compacted, cf. the viewID() term of H-4. Also keep the display hold on a dependent view picture when it is evicted from its own view's reference lists. unreference_pic() re-establishes that hold for a picture in delayed_pic, but reordering is driven by the base view and a dependent view picture is deliberately not in that array, so it would be reclaimed before the base view picture it is paired with was output. Signed-off-by: Dom Cobley <[email protected]> --- libavcodec/h264_refs.c | 88 +++++++++++++++++++++++++++++++++++++++-- libavcodec/h264_slice.c | 1 + libavcodec/h264dec.h | 2 + 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 05cdc07c58..526636d813 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -373,11 +373,14 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) for (int list = 0; list < sl->list_count; list++) { int pred = sl->curr_pic_num; + /* picViewIdxLXPred of H.8.2.2.3, which starts out at -1 for each list */ + int view_pred = -1; for (int index = 0; index < sl->nb_ref_modifications[list]; index++) { unsigned int modification_of_pic_nums_idc = sl->ref_modifications[list][index].op; unsigned int val = sl->ref_modifications[list][index].val; - unsigned int pic_id; + unsigned int pic_id = 0; + int is_inter_view = 0; int i, pic_structure; H264Picture *ref = NULL; @@ -434,11 +437,64 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) } break; } + case 4: + case 5: { + /* Inter-view reference picture list modification, H.8.2.2.3. The + * value indexes the inter-view dependency list of this view, and + * names a view rather than a picture. */ + const SPSMVCExt *mvc = &h->ps.sps->mvc; + const unsigned voidx = h->cur_view; + const int abs_diff_view_idx = val + 1; + const uint16_t *refs; + int nb_refs, ref_voidx; + + is_inter_view = 1; + + if (!h->ps.sps->is_subset || !voidx || voidx >= mvc->num_views) { + i = -1; + break; + } + + if (sl->anchor_pic_flag) { + nb_refs = mvc->num_anchor_refs[list][voidx]; + refs = mvc->anchor_ref[list][voidx]; + } else { + nb_refs = mvc->num_non_anchor_refs[list][voidx]; + refs = mvc->non_anchor_ref[list][voidx]; + } + if (nb_refs <= 0) { + i = -1; + break; + } + + if (modification_of_pic_nums_idc == 4) { + view_pred -= abs_diff_view_idx; + if (view_pred < 0) + view_pred += nb_refs; + } else { + view_pred += abs_diff_view_idx; + if (view_pred >= nb_refs) + view_pred -= nb_refs; + } + if (view_pred < 0 || view_pred >= nb_refs) { + i = -1; + break; + } + + ref_voidx = ff_h264_view_idx(h, refs[view_pred]); + if (ref_voidx < 0 || ref_voidx >= FF_ARRAY_ELEMS(h->views)) { + i = -1; + break; + } + ref = h->views[ref_voidx].cur_pic_ptr; + i = (ref && ref->f->buf[0]) ? 0 : -1; + break; + } default: av_assert0(0); } - if (i < 0 || mismatches_ref(h, ref)) { + if (i < 0 || (!is_inter_view && mismatches_ref(h, ref))) { av_log(h->avctx, AV_LOG_ERROR, i < 0 ? "reference picture missing during reorder\n" : "mismatching reference\n" @@ -447,6 +503,23 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) return AVERROR_INVALIDDATA; } memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME + } else if (is_inter_view) { + /* Duplicates are identified by view rather than by pic_id here, + * cf. the viewID() term of H-4. */ + for (i = index; i + 1 < sl->ref_count[list]; i++) { + if (sl->ref_list[list][i].parent && + sl->ref_list[list][i].inter_view && + sl->ref_list[list][i].parent->view_id == ref->view_id) + break; + } + for (; i > index; i--) + sl->ref_list[list][i] = sl->ref_list[list][i - 1]; + + ref_from_h264pic(&sl->ref_list[list][index], ref); + sl->ref_list[list][index].reference = h->picture_structure; + if (FIELD_PICTURE(h)) + pic_as_field(&sl->ref_list[list][index], h->picture_structure); + sl->ref_list[list][index].inter_view = 1; } else { for (i = index; i + 1 < sl->ref_count[list]; i++) { if (sl->ref_list[list][i].parent && @@ -521,7 +594,9 @@ int ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx) if (index >= sl->ref_count[list]) { av_log(logctx, AV_LOG_ERROR, "reference count overflow\n"); return AVERROR_INVALIDDATA; - } else if (op > 2) { + } else if (op > 2 && !(sl->is_mvc && op <= 5)) { + /* 4 and 5 are the inter-view modifications of + * ref_pic_list_mvc_modification(), H.7.3.3.1.1 */ av_log(logctx, AV_LOG_ERROR, "illegal modification_of_pic_nums_idc %u\n", op); @@ -552,6 +627,13 @@ static inline int unreference_pic(H264Context *h, H264Picture *pic, int refmask) if (pic->reference &= refmask) { return 0; } else { + /* A dependent view picture is not in delayed_pic -- reordering is driven + * by the base view -- but is still awaiting output alongside the base view + * picture it is paired with, until resolve_view_pair() clears the link. */ + if (pic->base_view_pic >= 0) { + pic->reference = DELAYED_PIC_REF; + return 1; + } for (int i = 0; h->delayed_pic[i]; i++) if(pic == h->delayed_pic[i]){ pic->reference = DELAYED_PIC_REF; diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 9322b4359d..5b2749e3b5 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -2023,6 +2023,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, return AVERROR_INVALIDDATA; } + sl->is_mvc = nal->type == H264_NAL_EXTEN_SLICE; sl->anchor_pic_flag = nal->anchor_pic_flag; sl->frame_num = get_bits(&sl->gb, sps->log2_max_frame_num); diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 500a49e824..b63d8ad658 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -257,6 +257,8 @@ typedef struct H264SliceContext { int redundant_pic_count; + /** whether this is a coded slice extension, i.e. belongs to a dependent view */ + int is_mvc; /** anchor_pic_flag of the MVC NAL unit header, 0 for a base view slice */ int anchor_pic_flag; -- 2.53.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]