[FFmpeg-soc] [soc]: r589 - dirac/libavcodec/dirac.c
marco
subversion at mplayerhq.hu
Thu Aug 2 14:17:39 CEST 2007
Author: marco
Date: Thu Aug 2 14:17:38 2007
New Revision: 589
Log:
the first step towards motion compensation. please not that a lot is missing, it's a hack and this will not work yet
Modified:
dirac/libavcodec/dirac.c
Modified: dirac/libavcodec/dirac.c
==============================================================================
--- dirac/libavcodec/dirac.c (original)
+++ dirac/libavcodec/dirac.c Thu Aug 2 14:17:38 2007
@@ -103,7 +103,7 @@ struct decoding_parameters
int picture_weight_ref1;
int picture_weight_ref2;
- int picture_weight_bits;
+ int picture_weight_precision;
/* Codeblocks h*v. */
int intra_hlevel_012, intra_vlevel_012;
@@ -239,6 +239,12 @@ typedef struct DiracContext {
int refcnt;
AVFrame refframes[REFFRAME_CNT]; /* XXX */
+ /* XXX: This should not be needed and will be removed ASAP when
+ either the specification or reference implementation is
+ updated. */
+ int retirecnt;
+ int retireframe[REFFRAME_CNT];
+
struct source_parameters source;
struct sequence_parameters sequence;
struct decoding_parameters decoding;
@@ -1085,7 +1091,7 @@ static void dirac_unpack_prediction_para
s->frame_decoding.chroma_xbsep = s->frame_decoding.luma_xbsep / s->chroma_hratio;
s->frame_decoding.chroma_ybsep = s->frame_decoding.luma_ybsep / s->chroma_vratio;
- /* Overrid motion vector precision. */
+ /* Override motion vector precision. */
if (get_bits(gb, 1))
s->frame_decoding.mv_precision = dirac_get_ue_golomb(gb);
@@ -1139,7 +1145,7 @@ static void dirac_unpack_prediction_para
/* Override reference picture weights. */
if (get_bits(gb, 1)) {
- s->frame_decoding.picture_weight_bits = dirac_get_ue_golomb(gb);
+ s->frame_decoding.picture_weight_precision = dirac_get_ue_golomb(gb);
s->frame_decoding.picture_weight_ref1 = dirac_get_se_golomb(gb);
if (s->refs == 2)
s->frame_decoding.picture_weight_ref2 = dirac_get_se_golomb(gb);
@@ -1831,39 +1837,189 @@ static int reference_frame_idx(AVCodecCo
return -1;
}
-static int dirac_motion_compensation(AVCodecContext *avctx, int *coeffs, int comp) {
+static int upconvert(AVFrame *refframe, int width, int height,
+ int x, int y, int comp) {
+ int xpos;
+ int ypos;
+ uint8_t *frame = refframe->data[comp];
+
+ xpos = FFMAX(0, FFMIN(x, width * 2));
+ ypos = FFMAX(0, FFMIN(y, height * 2));
+
+ /* XXX: This isn't proper interpolation, but it has to do for
+ now... */
+ return frame[(xpos >> 1) + (ypos >> 1) * refframe->linesize[comp]];
+}
+
+static int motion_comp_blockpred(AVCodecContext *avctx, AVFrame *refframe,
+ int ref, struct dirac_blockmotion *currblock,
+ int x, int y, int width, int height,
+ int comp) {
+ DiracContext *s = avctx->priv_data;
+ int vector[2];
+ int px, py;
+
+ if (!currblock->use_global) {
+ /* XXX */
+ if (ref == 0) {
+ vector[0] = currblock->ref1[0];
+ vector[1] = currblock->ref1[1];
+ } else {
+ vector[0] = currblock->ref2[0];
+ vector[1] = currblock->ref2[1];
+ }
+ } else {
+ dprintf(avctx, "global motion compensation has not been implemented yet\n");
+ /* XXX */
+ vector[0] = 0;
+ vector[1] = 0;
+ }
+
+ if (comp != 0) {
+ if (s->chroma_hratio)
+ vector[0] >>= 1;
+ if (s->chroma_vratio)
+ vector[1] >>= 1;
+ }
+
+ /* XXX: Hack */
+ s->frame_decoding.mv_precision = 0;
+
+ if (s->frame_decoding.mv_precision > 0) {
+ px = (x << s->frame_decoding.mv_precision) + vector[0];
+ py = (y << s->frame_decoding.mv_precision) + vector[1];
+ } else {
+ px = (x + vector[0]) << 1;
+ py = (y + vector[1]) << 1;
+ }
+
+ /* Upconversion. */
+ if (s->frame_decoding.mv_precision == 0
+ || s->frame_decoding.mv_precision == 1)
+ return upconvert(refframe, width, height, px, py, comp);
+
+ dprintf(avctx, "unsupported precision\n");
+
+ return 0;
+}
+
+static int motion_comp(AVCodecContext *avctx, int x, int y,
+ AVFrame *ref1, AVFrame *ref2, int *coeffs, int comp) {
DiracContext *s = avctx->priv_data;
- int x, y;
int width, height;
int xblen, yblen;
int xbsep, ybsep;
int xoffset, yoffset;
-
- AVFrame *ref1 = 0, *ref2 = 0;
+ int p = 0, val = 0;
+ int i, j;
+ int hbits, vbits;
+ int total_wt_bits;
if (comp == 0) {
width = s->sequence.luma_width;
height = s->sequence.luma_height;
xblen = s->frame_decoding.luma_yblen;
yblen = s->frame_decoding.luma_xblen;
+ xbsep = s->frame_decoding.luma_ybsep;
+ ybsep = s->frame_decoding.luma_xbsep;
} else {
width = s->sequence.chroma_width;
height = s->sequence.chroma_height;
xblen = s->frame_decoding.chroma_yblen;
yblen = s->frame_decoding.chroma_xblen;
+ xbsep = s->frame_decoding.chroma_ybsep;
+ ybsep = s->frame_decoding.chroma_xbsep;
}
xoffset = (xblen - ybsep) / 2;
yoffset = (yblen - ybsep) / 2;
- ref1 = &s->refframes[s->ref1];
- if (s->refs == 2)
- ref2 = &s->refframes[s->ref2];
+ hbits = av_log2(xoffset) + 2;
+ vbits = av_log2(yoffset) + 2;
+ total_wt_bits = hbits + vbits + s->frame_decoding.picture_weight_precision;
-/* for (y = 0; y < height; y++) */
-/* for (x = 0; x < width; x++) { */
-/* coeffs[y * s->padded_width + x] += motion_comp(avctx, x, y, coeffs, */
-/* } */
+ for (j = 0; j < s->blheight; j++)
+ for (i = 0; i < s->blwidth; i++) {
+ struct dirac_blockmotion *currblock;
+ int xstart = FFMAX(0, i * xbsep - xoffset);
+ int ystart = FFMAX(0, j * ybsep - yoffset);
+ int xstop = FFMIN(xstart + xblen, width);
+ int ystop = FFMIN(ystart + yblen, height);
+
+ /* XXX: This is terribly inefficient, but exactly what the
+ spec does. First I just want this to work, before I
+ start thinking about optimizing it. */
+ if (x < xstart || x > xstop)
+ continue;
+ if (y < ystart || y > ystop)
+ continue;
+
+ currblock = &s->blmotion[i + j * s->blwidth];
+
+ if (currblock->use_ref[0] == 0 && currblock->use_ref[1] == 0) {
+ /* Intra */
+ val = currblock->dc[comp];
+ val *= s->frame_decoding.picture_weight_precision;
+ } else if (currblock->use_ref[0]) {
+ val = motion_comp_blockpred(avctx, ref1, 0, currblock,
+ x, y, width, height, comp);
+ val *= (s->frame_decoding.picture_weight_ref1
+ + s->frame_decoding.picture_weight_ref2);
+ } else if (currblock->use_ref[1]) {
+ val = motion_comp_blockpred(avctx, ref2, 1, currblock,
+ x, y, width, height, comp);
+ val *= (s->frame_decoding.picture_weight_ref1
+ + s->frame_decoding.picture_weight_ref2);
+ } else {
+ int val1, val2;
+ val1 = motion_comp_blockpred(avctx, ref1, 0, currblock,
+ x, y, width, height, comp);
+ val1 *= s->frame_decoding.picture_weight_ref1;
+ val2 = motion_comp_blockpred(avctx, ref1, 0, currblock,
+ x, y, width, height, comp);
+ val2 *= s->frame_decoding.picture_weight_ref1;
+ val = val1 + val2;
+ }
+
+ p += val; /* XXX: Spatial weighting matrix should be used
+ here. */
+ }
+
+ p = (p + (1 << (total_wt_bits - 1))) >> total_wt_bits;
+ return p;
+}
+
+static int dirac_motion_compensation(AVCodecContext *avctx, int *coeffs,
+ int comp) {
+ DiracContext *s = avctx->priv_data;
+ int width, height;
+ int x, y;
+ int refidx1, refidx2 = 0;
+ AVFrame *ref1 = 0, *ref2 = 0;
+ int i;
+
+ if (comp == 0) {
+ width = s->sequence.luma_width;
+ height = s->sequence.luma_height;
+ } else {
+ width = s->sequence.chroma_width;
+ height = s->sequence.chroma_height;
+
+ }
+
+ refidx1 = reference_frame_idx(avctx, s->ref1);
+ ref1 = &s->refframes[refidx1];
+ if (s->refs == 2) {
+ refidx2 = reference_frame_idx(avctx, s->ref2);
+ ref2 = &s->refframes[refidx2];
+ }
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++) {
+ coeffs[y * s->padded_width + x] += motion_comp(avctx, x, y,
+ ref1, ref2,
+ coeffs, comp);
+ }
return 0;
}
@@ -1908,6 +2064,9 @@ static int dirac_decode_frame(AVCodecCon
dirac_idwt(avctx, coeffs);
+ if (s->refs)
+ dirac_motion_compensation(avctx, coeffs, comp);
+
/* Copy the decoded coefficients into the frame. */
for (x = 0; x < width; x++)
for (y = 0; y < height; y++)
@@ -1928,7 +2087,7 @@ static int parse_frame(AVCodecContext *a
DiracContext *s = avctx->priv_data;
int retire;
int filter;
- int i, j;
+ int i;
GetBitContext *gb = s->gb;
/* Setup decoding parameter defaults for this frame. */
@@ -1940,19 +2099,21 @@ static int parse_frame(AVCodecContext *a
s->picnum = get_bits_long(gb, 32);
if (s->refs) {
- s->ref1 = s->picnum + dirac_get_se_golomb(gb);
+ s->ref1 = dirac_get_se_golomb(gb) + s->picnum;
if (s->refs == 2)
- s->ref2 = s->picnum + dirac_get_se_golomb(gb);
+ s->ref2 = dirac_get_se_golomb(gb) + s->picnum;
}
/* Retire the reference frames that are not used anymore. */
retire = dirac_get_ue_golomb(gb);
+ s->retirecnt = retire;
for (i = 0; i < retire; i++) {
int retire_num;
AVFrame *f;
+ int j;
int idx;
- retire_num = dirac_get_se_golomb(gb) + s->picnum;
+ retire_num = dirac_get_se_golomb(gb) + s->picnum;
idx = reference_frame_idx(avctx, retire_num);
if (idx == -1) {
@@ -1960,6 +2121,8 @@ static int parse_frame(AVCodecContext *a
continue;
}
+ s->retireframe[i] = idx;
+#if 0
f = &s->refframes[idx];
if (f->data[0] != NULL)
avctx->release_buffer(avctx, f);
@@ -1968,6 +2131,7 @@ static int parse_frame(AVCodecContext *a
for (j = idx; j < idx + s->refcnt; j++) {
s->refframes[j] = s->refframes[j + 1];
}
+#endif
}
if (s->refs) {
@@ -2073,6 +2237,7 @@ static int decode_frame(AVCodecContext *
DiracContext *s = avctx->priv_data;
GetBitContext gb;
AVFrame *picture = data;
+ int i;
int parse_code = buf[4];
dprintf(avctx, "Decoding frame: size=%d head=%c%c%c%c parse=%02x\n",
@@ -2136,6 +2301,24 @@ static int decode_frame(AVCodecContext *
s->refframes[s->refcnt++] = s->picture;
}
+ /* XXX: Retire frames. Normally this should be done before
+ decoding the frame, but because the encoder retires a reference
+ frame it has to be done here for now. */
+ for (i = 0; i < s->retirecnt; i++) {
+ AVFrame *f;
+ int idx, j;
+
+ idx = s->retireframe[i];
+ f = &s->refframes[idx];
+ if (f->data[0] != NULL)
+ avctx->release_buffer(avctx, f);
+ s->refcnt--;
+
+ for (j = idx; j < idx + s->refcnt; j++) {
+ s->refframes[j] = s->refframes[j + 1];
+ }
+ }
+
*data_size = sizeof(AVFrame);
*picture = s->picture;
More information about the FFmpeg-soc
mailing list