[FFmpeg-soc] [soc]: r3876 - in dirac/libavcodec: dirac.c dirac.h diracdec.c
conrad
subversion at mplayerhq.hu
Sat Dec 6 03:01:09 CET 2008
Author: conrad
Date: Sat Dec 6 03:01:09 2008
New Revision: 3876
Log:
Completely rewrite reference and delay frame management (based on h264)
Also remove caching of the halfpel planes, this will be replaced
with better motion compensation anyways.
Modified:
dirac/libavcodec/dirac.c
dirac/libavcodec/dirac.h
dirac/libavcodec/diracdec.c
Modified: dirac/libavcodec/dirac.c
==============================================================================
--- dirac/libavcodec/dirac.c (original)
+++ dirac/libavcodec/dirac.c Sat Dec 6 03:01:09 2008
@@ -448,25 +448,6 @@ const struct dirac_block_params ff_dirac
};
/**
- * Search a frame in the buffer of reference frames
- *
- * @param frameno frame number in display order
- * @return index of the reference frame in the reference frame buffer
- */
-int dirac_reference_frame_idx(DiracContext *s, int frameno)
-{
- int i;
-
- for (i = 0; i < s->refcnt; i++) {
- AVFrame *f = &s->refframes[i].frame;
- if (f->display_picture_number == frameno)
- return i;
- }
-
- return -1;
-}
-
-/**
* Interpolate a frame
*
* @param refframe frame to grab the upconverted pixel from
@@ -1036,9 +1017,6 @@ int dirac_motion_compensation(DiracConte
{
int i, j;
int x, y;
- int refidx[2] = { 0 };
- int cacheframe[2] = {1, 1};
- AVFrame *ref[2] = { 0 };
struct dirac_blockmotion *currblock;
int xstart, ystart;
int xstop, ystop;
@@ -1084,14 +1062,11 @@ int dirac_motion_compensation(DiracConte
return -1;
for (i = 0; i < s->refs; i++) {
- refidx[i] = dirac_reference_frame_idx(s, s->ref[i]);
- if (refidx[i] < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "Reference frame %d not in buffer\n", s->ref[i]);
+ if (!s->ref_pics[i]) {
+ av_log(s->avctx, AV_LOG_ERROR, "Reference frame %d not in buffer\n", i);
return -1;
}
- ref[i] = &s->refframes[refidx[i]].frame;
- if (s->refframes[refidx[i]].halfpel[comp] == NULL) {
s->refdata[i] = av_malloc(s->refwidth * s->refheight);
if (!s->refdata[i]) {
if (i == 1)
@@ -1099,12 +1074,8 @@ int dirac_motion_compensation(DiracConte
av_log(s->avctx, AV_LOG_ERROR, "av_malloc() failed\n");
return -1;
}
- interpolate_frame_halfpel(ref[i], s->width, s->height,
+ interpolate_frame_halfpel(s->ref_pics[i], s->width, s->height,
s->refdata[i], comp, s->xblen, s->yblen);
- } else {
- s->refdata[i] = s->refframes[refidx[i]].halfpel[comp];
- cacheframe[i] = 2;
- }
}
if (avcodec_check_dimensions(s->avctx, s->width, s->height)) {
@@ -1180,17 +1151,7 @@ int dirac_motion_compensation(DiracConte
av_freep(&s->spatialwt);
- for (i = 0; i < s->retirecnt; i++) {
- if (cacheframe[0] == 1 && i == refidx[0])
- cacheframe[0] = 0;
- if (cacheframe[1] == 1 && i == refidx[1])
- cacheframe[1] = 0;
- }
-
for (i = 0; i < s->refs; i++) {
- if (cacheframe[i])
- s->refframes[refidx[i]].halfpel[comp] = s->refdata[i];
- else
av_freep(&s->refdata[i]);
}
Modified: dirac/libavcodec/dirac.h
==============================================================================
--- dirac/libavcodec/dirac.h (original)
+++ dirac/libavcodec/dirac.h Sat Dec 6 03:01:09 2008
@@ -143,13 +143,10 @@ struct dirac_blockmotion {
int16_t dc[3];
};
-/* XXX */
-#define REFFRAME_CNT 20
-
-struct reference_frame {
- AVFrame frame;
- int8_t *halfpel[3];
-};
+// Schoedinger limits these to 8
+#define MAX_REFERENCE_FRAMES 16
+#define MAX_DELAYED_FRAMES 16
+#define MAX_FRAMES 32
typedef struct DiracContext {
AVCodecContext *avctx;
@@ -160,13 +157,13 @@ typedef struct DiracContext {
char *encodebuf;
int prev_size;
- AVFrame picture;
+ AVFrame *current_picture;
+ AVFrame *ref_pics[2];
- int refcnt;
- struct reference_frame refframes[REFFRAME_CNT]; /* XXX */
+ AVFrame *ref_frames[MAX_REFERENCE_FRAMES+1];
+ AVFrame *delay_frames[MAX_DELAYED_FRAMES+1];
+ AVFrame *all_frames;
- int retirecnt;
- uint32_t retireframe[REFFRAME_CNT];
int16_t *mcpic;
dirac_source_params source;
@@ -195,7 +192,6 @@ typedef struct DiracContext {
int globalmc_flag; ///< use global motion compensation flag
/** global motion compensation parameters */
struct globalmc_parameters globalmc;
- uint32_t ref[2]; ///< reference pictures
int16_t *spatialwt;
int8_t *refdata[2];
@@ -554,8 +550,6 @@ int block_dc_prediction(DiracContext *s,
return sign * (total + (cnt >> 1)) / cnt;
}
-int dirac_reference_frame_idx(DiracContext *s, int frameno);
-
int dirac_motion_compensation(DiracContext *s, int16_t *coeffs, int comp);
int dirac_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
Modified: dirac/libavcodec/diracdec.c
==============================================================================
--- dirac/libavcodec/diracdec.c (original)
+++ dirac/libavcodec/diracdec.c Sat Dec 6 03:01:09 2008
@@ -35,14 +35,66 @@
#include "dirac_wavelet.h"
#include "mpeg12data.h"
+/**
+ * Value of Picture.reference when Picture is not a reference picture, but
+ * is held for delayed output.
+ */
+#define DELAYED_PIC_REF 4
+
+static AVFrame *get_frame(AVFrame *framelist[], int picnum)
+{
+ int i;
+ for (i = 0; framelist[i]; i++)
+ if (framelist[i]->display_picture_number == picnum)
+ return framelist[i];
+ return NULL;
+}
+
+static AVFrame *remove_frame(AVFrame *(*framelist)[], int picnum)
+{
+ AVFrame *remove_pic = NULL;
+ int i, remove_idx = -1;
+
+ for (i = 0; (*framelist)[i]; i++)
+ if ((*framelist)[i]->display_picture_number == picnum) {
+ remove_pic = (*framelist)[i];
+ remove_idx = i;
+ }
+
+ if (remove_pic)
+ for (i = remove_idx; (*framelist)[i]; i++)
+ (*framelist)[i] = (*framelist)[i+1];
+
+ return remove_pic;
+}
+
+static int add_frame(AVFrame *(*framelist)[], int maxframes, AVFrame *frame)
+{
+ int i;
+ for (i = 0; i < maxframes; i++)
+ if (!(*framelist)[i]) {
+ (*framelist)[i] = frame;
+ return 0;
+ }
+ return -1;
+}
+
static int decode_init(AVCodecContext *avctx)
{
+ DiracContext *s = avctx->priv_data;
+
+ s->all_frames = av_mallocz(MAX_FRAMES * sizeof(AVFrame));
+ if (!s->all_frames)
+ return -1;
+
return 0;
}
static int decode_end(AVCodecContext *avctx)
{
- // DiracContext *s = avctx->priv_data;
+ DiracContext *s = avctx->priv_data;
+
+ av_free(s->all_frames);
return 0;
}
@@ -626,7 +678,7 @@ static int dirac_decode_frame_internal(D
}
for (comp = 0; comp < 3; comp++) {
- uint8_t *frame = s->picture.data[comp];
+ uint8_t *frame = s->current_picture->data[comp];
int width, height;
width = s->source.width >> (comp ? s->chroma_hshift : 0);
@@ -669,7 +721,7 @@ static int dirac_decode_frame_internal(D
}
line += s->padded_width;
- frame += s->picture.linesize[comp];
+ frame += s->current_picture->linesize[comp];
mcline += s->width;
}
} else {
@@ -679,7 +731,7 @@ static int dirac_decode_frame_internal(D
}
line += s->padded_width;
- frame += s->picture.linesize[comp];
+ frame += s->current_picture->linesize[comp];
}
}
@@ -704,22 +756,35 @@ static int dirac_decode_frame_internal(D
*/
static int parse_frame(DiracContext *s)
{
- int retire;
+ int retire, picnum;
int i;
GetBitContext *gb = &s->gb;
- s->picture.display_picture_number = get_bits_long(gb, 32);
+ picnum= s->current_picture->display_picture_number = get_bits_long(gb, 32);
+ s->ref_pics[0] = s->ref_pics[1] = NULL;
for (i = 0; i < s->refs; i++)
- s->ref[i] = dirac_get_se_golomb(gb) + s->picture.display_picture_number;
+ s->ref_pics[i] = get_frame(s->ref_frames, picnum + dirac_get_se_golomb(gb));
/* Retire the reference frames that are not used anymore. */
- s->retirecnt = 0;
- if (s->picture.reference) {
- retire = dirac_get_se_golomb(gb);
- if (retire) {
- s->retireframe[0] = s->picture.display_picture_number + retire;
- s->retirecnt = 1;
+ if (s->current_picture->reference) {
+ retire = picnum + dirac_get_se_golomb(gb);
+ if (retire != picnum) {
+ AVFrame *retire_pic = remove_frame(&s->ref_frames, retire);
+
+ if (retire_pic) {
+ if (retire_pic->reference & DELAYED_PIC_REF)
+ retire_pic->reference = DELAYED_PIC_REF;
+ else
+ retire_pic->reference = 0;
+ } else
+ av_log(s->avctx, AV_LOG_DEBUG, "Frame to retire not found\n");
+ }
+
+ // if reference array is full, remove the oldest as per the spec
+ while (add_frame(&s->ref_frames, MAX_REFERENCE_FRAMES, s->current_picture)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Reference frame overflow\n");
+ remove_frame(&s->ref_frames, s->ref_frames[0]->display_picture_number);
}
}
@@ -777,15 +842,59 @@ static int parse_frame(DiracContext *s)
return 0;
}
-static void parse_picture_code(DiracContext *s, int parse_code)
+static int alloc_frame(AVCodecContext *avctx, int parse_code)
{
static const uint8_t pict_type[3] = { FF_I_TYPE, FF_P_TYPE, FF_B_TYPE };
- avcodec_get_frame_defaults(&s->picture);
+ DiracContext *s = avctx->priv_data;
+ AVFrame *pic = NULL;
+ int i;
+
+ // find an unused frame
+ for (i = 0; i < MAX_FRAMES; i++)
+ if (s->all_frames[i].data[0] == NULL)
+ pic = &s->all_frames[i];
+ if (!pic) {
+ av_log(avctx, AV_LOG_ERROR, "framelist full\n");
+ return -1;
+ }
+
+ avcodec_get_frame_defaults(pic);
s->refs = parse_code & 0x03;
- s->picture.reference = (parse_code & 0x0C) == 0x0C;
- s->picture.key_frame = s->refs == 0;
- s->picture.pict_type = pict_type[s->refs];
+ pic->reference = (parse_code & 0x0C) == 0x0C;
+ pic->key_frame = s->refs == 0;
+ pic->pict_type = pict_type[s->refs];
+
+ if (avctx->get_buffer(avctx, pic) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ return -1;
+ }
+ s->current_picture = pic;
+ return 0;
+}
+
+static int get_delayed_pic(DiracContext *s, AVFrame *picture, int *data_size)
+{
+ AVFrame *out = s->delay_frames[0];
+ int i, out_idx = 0;
+
+ // find frame with lowest picture number
+ for (i = 1; s->delay_frames[i]; i++)
+ if (s->delay_frames[i]->display_picture_number < out->display_picture_number) {
+ out = s->delay_frames[i];
+ out_idx = i;
+ }
+
+ for (i = out_idx; s->delay_frames[i]; i++)
+ s->delay_frames[i] = s->delay_frames[i+1];
+
+ if (out) {
+ out->reference ^= DELAYED_PIC_REF;
+ *data_size = sizeof(AVFrame);
+ *picture = *out;
+ }
+
+ return 0;
}
int dirac_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
@@ -797,17 +906,14 @@ int dirac_decode_frame(AVCodecContext *a
int parse_code;
unsigned data_unit_size, buf_read = 0;
- if (buf_size == 0) {
- int idx = dirac_reference_frame_idx(s, avctx->frame_number);
- if (idx == -1) {
- /* The frame was not found. */
- *data_size = 0;
- } else {
- *data_size = sizeof(AVFrame);
- *picture = s->refframes[idx].frame;
- }
- return 0;
- }
+ // release unused frames
+ for (i = 0; i < MAX_FRAMES; i++)
+ if (s->all_frames[i].data[0] && !s->all_frames[i].reference)
+ avctx->release_buffer(s->avctx, &s->all_frames[i]);
+
+ // end of stream, so flush delayed pics
+ if (buf_size == 0)
+ return get_delayed_pic(s, picture, data_size);
// read through data units until we find a picture
while (buf_read < buf_size) {
@@ -843,101 +949,31 @@ int dirac_decode_frame(AVCodecContext *a
if ((parse_code & 0x08) != 0x08)
return 0;
- parse_picture_code(s, parse_code);
- if (parse_frame(s) < 0)
+ if (alloc_frame(avctx, parse_code) < 0)
return -1;
- if (s->picture.data[0] != NULL)
- avctx->release_buffer(avctx, &s->picture);
-
- if (avctx->get_buffer(avctx, &s->picture) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if (parse_frame(s) < 0)
return -1;
- }
if (dirac_decode_frame_internal(s))
return -1;
- if (s->picture.reference
- || s->picture.display_picture_number != avctx->frame_number) {
- if (s->refcnt + 1 == REFFRAME_CNT) {
- av_log(avctx, AV_LOG_ERROR, "reference picture buffer overrun\n");
- return -1;
- }
-
- s->refframes[s->refcnt].halfpel[0] = 0;
- s->refframes[s->refcnt].halfpel[1] = 0;
- s->refframes[s->refcnt].halfpel[2] = 0;
- s->refframes[s->refcnt++].frame = s->picture;
- }
-
- /* Retire frames that were reordered and displayed if they are no
- reference frames either. */
- for (i = 0; i < s->refcnt; i++) {
- AVFrame *f = &s->refframes[i].frame;
-
- if (f->reference == 0
- && f->display_picture_number < avctx->frame_number) {
- s->retireframe[s->retirecnt++] = f->display_picture_number;
- }
- }
-
- for (i = 0; i < s->retirecnt; i++) {
- AVFrame *f;
- int idx, j;
-
- idx = dirac_reference_frame_idx(s, s->retireframe[i]);
- if (idx == -1) {
- av_log(avctx, AV_LOG_WARNING, "frame to retire #%d not found\n",
- s->retireframe[i]);
- continue;
- }
-
- f = &s->refframes[idx].frame;
- /* Do not retire frames that were not displayed yet. */
- if (f->display_picture_number >= avctx->frame_number) {
- f->reference = 0;
- continue;
- }
-
- if (f->data[0] != NULL)
- avctx->release_buffer(avctx, f);
-
- av_free(s->refframes[idx].halfpel[0]);
- av_free(s->refframes[idx].halfpel[1]);
- av_free(s->refframes[idx].halfpel[2]);
-
- s->refcnt--;
-
- for (j = idx; j < idx + s->refcnt; j++) {
- s->refframes[j] = s->refframes[j + 1];
- }
- }
-
- if (s->picture.display_picture_number > avctx->frame_number) {
- int idx;
-
- if (!s->picture.reference) {
- /* This picture needs to be shown at a later time. */
+ if (s->current_picture->display_picture_number > avctx->frame_number) {
+ AVFrame *delayed_frame = remove_frame(&s->delay_frames, avctx->frame_number);
- s->refframes[s->refcnt].halfpel[0] = 0;
- s->refframes[s->refcnt].halfpel[1] = 0;
- s->refframes[s->refcnt].halfpel[2] = 0;
- s->refframes[s->refcnt++].frame = s->picture;
- }
+ s->current_picture->reference |= DELAYED_PIC_REF;
+ if (add_frame(&s->delay_frames, MAX_DELAYED_FRAMES, s->current_picture))
+ av_log(avctx, AV_LOG_ERROR, "Delay frame overflow\n");
- idx = dirac_reference_frame_idx(s, avctx->frame_number);
- if (idx == -1) {
- /* The frame is not yet decoded. */
- *data_size = 0;
- } else {
+ if (delayed_frame) {
+ delayed_frame->reference ^= DELAYED_PIC_REF;
*data_size = sizeof(AVFrame);
- *picture = s->refframes[idx].frame;
+ *picture = *delayed_frame;
}
} else {
/* The right frame at the right time :-) */
*data_size = sizeof(AVFrame);
- *picture = s->picture;
+ *picture = *s->current_picture;
}
return buf_read + data_unit_size;
More information about the FFmpeg-soc
mailing list