Commit 1a8706812b for ffmpeg
commit 1a8706812b1790251891a426b3d6e760973b9015
Author: Rainbaby <r@bgr.jp>
Date: Fri Aug 28 16:18:09 2026 +0900
avcodec/cavsdec: decode enhanced field coded B pictures
Read pb_field_enhanced_flag out of the four reserved bits of table 22.
A field coded B picture that sets BFieldEnhanced derives its reference
fields, its co-located block and the parity offsets of its direct mode
vectors per clause 9.9.1 b). The P picture half of the same flag,
PFieldSkip, has no sample and is refused. no_forward_reference_flag is
read and discarded; no sample sets it.
Signed-off-by: Rainbaby <r@bgr.jp>
diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h
index 32d267d7f8..8c3dac34ca 100644
--- a/libavcodec/cavs.h
+++ b/libavcodec/cavs.h
@@ -203,6 +203,7 @@ typedef struct AVSContext {
int progressive;
int pic_structure;
int top_field_first; ///< first coded field is the top one, clause 7.2.3
+ int b_field_enhanced; ///< BFieldEnhanced of the picture, clause 9.9.1 b)
int field; ///< field of the current MB, 0 or 1, clause 3.24
int field_mby; ///< macroblock row of the current macroblock in it
int skip_mode_flag; ///< select between skip_count or one skip_flag per MB
diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c
index bce8eb290b..ae82bece5c 100644
--- a/libavcodec/cavsdec.c
+++ b/libavcodec/cavsdec.c
@@ -471,37 +471,74 @@ static inline void store_mvs(AVSContext *h)
h->col_mv[h->mbidx * 4 + 3] = h->mv[MV_FWD_X3];
}
+/**
+ * Scale one component of the co-located motion vector, den being
+ * 16384 / BlockDistanceRef (clause 9.9.1 b) 3)). The intermediate
+ * products stay unsigned, they can overflow an int.
+ */
+static inline int scale_direct(unsigned den, int mv, int dist)
+{
+ int m = FF_SIGNBIT(mv);
+
+ return (((den + (den * mv * dist ^ m) - m - 1) >> 14) ^ m) - m;
+}
+
+/**
+ * The parity of a field is the parity of its distance index: a first
+ * coded field has an even one, a second field an odd one (clause 9.4.6.1).
+ */
+static inline int field_parity(AVSContext *h, int distance_index)
+{
+ return (distance_index & 1) ^ !h->top_field_first;
+}
+
/**
* Direct mode: scale the co-located motion vector by its own
- * BlockDistance, carried in the mv cache (clause 9.9.1 b)).
+ * BlockDistance, carried in the mv cache (clause 9.9.1 b)). Annex B
+ * fixes PictureStructure over a sequence, so the frame and field
+ * conversion of step 2 cannot arise.
*/
static inline void mv_pred_direct(AVSContext *h, cavs_vector *pmv_fw,
cavs_vector *col_mv)
{
cavs_vector *pmv_bw = pmv_fw + MV_BWD_OFFS;
unsigned den = h->direct_den[col_mv->dist];
- int m = FF_SIGNBIT(col_mv->x);
+ int delta_fw = 0, delta_bw = 0;
+ int mv_ref_y = col_mv->y;
pmv_fw->ref = h->ref_base[0];
pmv_bw->ref = h->ref_base[1];
if (!h->pic_structure) {
- /* reference field selection of 9.9.1 b) 1), BFieldEnhanced 0 */
- int di_col = h->DPB[0].poc + h->field;
+ /* reference field selection of 9.9.1 b) 1): an enhanced second
+ * field references index 0 in both directions, its co-located
+ * block being in the first field of the backward reference */
+ int enh = h->b_field_enhanced;
+ int di_col = h->DPB[0].poc + (enh ? 0 : h->field);
int di_ref = (di_col - col_mv->dist) & 511;
int di_fw0 = (h->DPB[1].poc + 1) & 511;
- pmv_fw->ref += di_ref != di_fw0;
- pmv_bw->ref += h->field;
+ if (!enh || !h->field)
+ pmv_fw->ref += di_ref != di_fw0;
+ if (!enh)
+ pmv_bw->ref += h->field;
+ if (enh) {
+ /* the field parity offsets of 9.9.1 b) 3) */
+ int par_cur = h->field ^ !h->top_field_first;
+ int par_bw = h->ref[pmv_bw->ref].parity;
+
+ mv_ref_y += 2 * (field_parity(h, di_ref) - par_bw);
+ delta_fw = 2 * (h->ref[pmv_fw->ref].parity - par_cur);
+ delta_bw = 2 * (par_bw - par_cur);
+ }
}
pmv_fw->dist = h->dist[pmv_fw->ref];
pmv_bw->dist = h->dist[pmv_bw->ref];
pmv_fw->ref_idx = pmv_bw->ref_idx = 0; /* derived (clause 9.4.5) */
/* scale the co-located motion vector according to its temporal span */
- pmv_fw->x = (((den + (den * col_mv->x * pmv_fw->dist ^ m) - m - 1) >> 14) ^ m) - m;
- pmv_bw->x = m - (((den + (den * col_mv->x * pmv_bw->dist ^ m) - m - 1) >> 14) ^ m);
- m = FF_SIGNBIT(col_mv->y);
- pmv_fw->y = (((den + (den * col_mv->y * pmv_fw->dist ^ m) - m - 1) >> 14) ^ m) - m;
- pmv_bw->y = m - (((den + (den * col_mv->y * pmv_bw->dist ^ m) - m - 1) >> 14) ^ m);
+ pmv_fw->x = scale_direct(den, col_mv->x, pmv_fw->dist);
+ pmv_bw->x = -scale_direct(den, col_mv->x, pmv_bw->dist);
+ pmv_fw->y = scale_direct(den, mv_ref_y, pmv_fw->dist) - delta_fw;
+ pmv_bw->y = -scale_direct(den, mv_ref_y, pmv_bw->dist) - delta_bw;
}
/**
@@ -1402,6 +1439,10 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
int flags;
int ref[2][4];
int ret;
+ /* the co-located macroblock of an enhanced second field is the one at
+ * the same position in the first field (clause 9.9.1 b) 1)) */
+ int col = h->mbidx - (h->b_field_enhanced && h->field ?
+ h->mb_width * h->mb_height / 2 : 0);
ff_cavs_init_mb(h);
set_inter_mb_ctx(h, mb_type, mb_type == B_SKIP);
@@ -1414,7 +1455,7 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
switch (mb_type) {
case B_SKIP:
case B_DIRECT:
- if (!h->col_type_base[h->mbidx]) {
+ if (!h->col_type_base[col]) {
/* intra MB at co-location: in-plane prediction (9.9.1 b) 1)) */
ff_cavs_mv(h, MV_FWD_X0, MV_FWD_C2, MV_PRED_BSKIP, BLK_16X16,
h->ref_base[0]);
@@ -1424,7 +1465,7 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
/* direct prediction from co-located P MB, block-wise */
for (block = 0; block < 4; block++)
mv_pred_direct(h, &h->mv[mv_scan[block]],
- &h->col_mv[h->mbidx * 4 + block]);
+ &h->col_mv[col * 4 + block]);
break;
case B_FWD_16X16:
REF(ref[0][0], 0, MV_FWD_X0);
@@ -1458,7 +1499,7 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
for (block = 0; block < 4; block++) {
switch (sub_type[block]) {
case B_SUB_DIRECT:
- if (!h->col_type_base[h->mbidx]) {
+ if (!h->col_type_base[col]) {
/* intra MB at co-location, do in-plane prediction */
if(flags==0) {
// if col-MB is a Intra MB, current Block size is 16x16.
@@ -1486,7 +1527,7 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
}
} else
mv_pred_direct(h, &h->mv[mv_scan[block]],
- &h->col_mv[h->mbidx * 4 + block]);
+ &h->col_mv[col * 4 + block]);
break;
case B_SUB_FWD:
MV(mv_scan[block], mv_scan[block] - 3,
@@ -1802,6 +1843,7 @@ static int decode_pic(AVSContext *h)
int ret;
int field;
int skip_count = -1;
+ int pb_field_enhanced_flag = 0;
if (!h->top_qp) {
av_log(h->avctx, AV_LOG_ERROR, "No sequence header decoded yet\n");
@@ -1894,7 +1936,12 @@ static int decode_pic(AVSContext *h)
else
/* 1 for a frame coded B picture (clause 7.2.3.2) */
h->ref_flag = 1;
- skip_bits(&h->gb, 4); //reserved bits
+ /* no_forward_reference_flag, pb_field_enhanced_flag, r(2); table 22.
+ * JiZhun has reserved bits here and must ignore them (clause 5.4) */
+ skip_bits1(&h->gb);
+ pb_field_enhanced_flag = get_bits1(&h->gb) &&
+ h->profile == AV_PROFILE_CAVS_BROADCASTING;
+ skip_bits(&h->gb, 2);
h->skip_mode_flag = get_bits1(&h->gb);
}
h->loop_filter_disable = get_bits1(&h->gb);
@@ -1920,6 +1967,16 @@ static int decode_pic(AVSContext *h)
h->aec_enable = get_bits1(&h->gb);
}
+ /* in a frame picture the field derivations reduce to the frame ones
+ * (9.9.1 b) 3)); PFieldSkip of 9.9.1 a) 1) is not implemented */
+ h->b_field_enhanced = pb_field_enhanced_flag && !h->pic_structure &&
+ h->cur.f->pict_type == AV_PICTURE_TYPE_B;
+ if (pb_field_enhanced_flag && !h->pic_structure &&
+ h->cur.f->pict_type == AV_PICTURE_TYPE_P) {
+ avpriv_request_sample(h->avctx, "Enhanced field coded P picture");
+ return AVERROR_PATCHWELCOME;
+ }
+
if (!h->progressive) {
h->cur.f->flags |= AV_FRAME_FLAG_INTERLACED;
if (h->top_field_first)