[FFmpeg-devel] [PATCH] DeluxePaint Animation playback system (r2)
Reimar Döffinger
Reimar.Doeffinger
Tue Sep 1 15:29:18 CEST 2009
On Tue, Sep 01, 2009 at 10:21:03PM +1000, Peter Ross wrote:
> On Fri, Aug 28, 2009 at 04:31:51PM +0200, Reimar D?ffinger wrote:
> > On Sat, Aug 29, 2009 at 12:16:25AM +1000, Peter Ross wrote:
> > > > That will probably mean your code can't work with AVFMT_GENERIC_INDEX.
> > > > I really think that seeking should be working.
> > >
> > > There is only one guaranteed keyframe: the first frame!
> >
> > For normal playback I've always considered seeking to non-keyframes,
> > too, a good idea. The only real issue I have with it is that just too
> > many decoders had the habit of crashing often with that.
>
> But it looks ugly!
Compared to no image at all it looks great.
Anyway I didn't say it should be disabled completely, I just don't like
to have code that simply can't support it at all.
> +static inline void skip(uint8_t **dst, const uint8_t *dst_end,
> + int count,
> + int *x, int width, int linesize)
> +{
> + while (count > 0) {
> + int striplen = FFMIN(count, width - *x);
> + *dst += striplen;
> + *x += striplen;
> + count -= striplen;
> + if (*x >= width) {
> + *dst += linesize - width;
> + *x = 0;
> + }
> + }
> +}
> +
> +static inline void fill(uint8_t **dst, const uint8_t *dst_end,
> + int pixel, int count,
> + int *x, int width, int linesize)
> +{
> + while (*dst < dst_end && count > 0) {
> + int striplen = FFMIN(count, width - *x);
> + memset(*dst, pixel, striplen);
> + *dst += striplen;
> + *x += striplen;
> + count -= striplen;
> + if (*x >= width) {
> + *dst += linesize - width;
> + *x = 0;
> + }
> + }
> +}
> +
> +static inline void copy(uint8_t **dst, const uint8_t *dst_end,
> + const uint8_t **buf, const uint8_t *buf_end,
> + int count,
> + int *x, int width, int linesize)
> +{
> + while (*dst < dst_end && *buf < buf_end && count > 0) {
> + int striplen = FFMIN(count, FFMIN(width - *x, buf_end - *buf));
> + memcpy(*dst, *buf, striplen);
> + *dst += striplen;
> + *buf += striplen;
> + *x += striplen;
> + count -= striplen;
> + if (*x >= width) {
> + *dst += linesize - width;
> + *x = 0;
> + }
> + }
> +}
In the first you forgot the dst_end check, or the dst_end argument is
useless.
In the last, you should use FFMIN3
I think it might be reasonable to use a single function like
static inline void do_op(uint8_t **dst, const uint8_t *dst_end,
const uint8_t **buf, const uint8_t *buf_end,
int pixel, int count,
int *x, int width, int linesize)
{
while (*dst < dst_end && count > 0) {
int striplen = FFMIN(count, width - *x);
if (buf) {
striplen = FFMIN(striplen, buf_end - *buf);
memcpy(*dst, *buf, striplen);
*buf += striplen;
} else if (pixel >= 0)
memset(*dst, pixel, striplen);
*dst += striplen;
*x += striplen;
count -= striplen;
if (*x >= width) {
*dst += linesize - width;
*x = 0;
}
}
}
of course with proper doxy documentation
> + count = bytestream_get_byte(&buf);
> + if (count > 0 && count < 0x80) { /* copy */
> + copy(&dst, dst_end, &buf, buf_end, count, &s->x, avctx->width, s->frame.linesize[0]);
> + } else if (count > 0x80) { /* shortskip */
> + skip(&dst, dst_end, count & 0x7F, &s->x, avctx->width, s->frame.linesize[0]);
> + } else if (count == 0) { /* fill */
> + int pixel;
> + count = bytestream_get_byte(&buf); /* count==0 gives nop */
> + pixel = bytestream_get_byte(&buf);
> + fill(&dst, dst_end, pixel, count, &s->x, avctx->width, s->frame.linesize[0]);
> + } else { /* (0x80) longop */
> + count = bytestream_get_le16(&buf);
> + if (count > 0 && count < 0x8000) { /* longskip */
> + skip(&dst, dst_end, count, &s->x, avctx->width, s->frame.linesize[0]);
> + } else if (count > 0x8000 && count < 0xC000) { /* longcopy */
> + copy(&dst, dst_end, &buf, buf_end, count & 0x3FFF, &s->x, avctx->width, s->frame.linesize[0]);
> + } else if (count == 0) { /* stop */
> + break;
> + } else if (count >= 0xC000) { /* longfill; count==0xc000 gives nop */
> + int pixel = bytestream_get_byte(&buf);
> + fill(&dst, dst_end, pixel, count & 0x3FFF, &s->x, avctx->width, s->frame.linesize[0]);
> + } else { /* (0x8000) unknown */
> + av_log_ask_for_sample(avctx, "unknown opcode");
> + return AVERROR_INVALIDDATA;
> + }
out of which I would make something like (can probably be improved,
though I _think_ that my variant is closer to what the designers had in
mind when they created the format):
#define DO_OP(buf, pixel, count) do_op(&dst, dst_end, (buf), buf_end, (pixel), (count), &s->x, avctx->width, s->frame.linesize[0])
type = bytestream_get_byte(&buf);
count = type & 0x7f;
type >>= 7;
if (count)
DO_OP(type ? NULL : &buf, -1, count);
} else if (!type) {
int pixel;
count = bytestream_get_byte(&buf); /* count==0 gives nop */
pixel = bytestream_get_byte(&buf);
DO_OP(NULL, pixel, count);
} else {
int pixel;
type = bytestream_get_le16(&buf);
count = type & 0x3fff;
type >>= 14;
if (!count) {
if (type == 0)
break; // stop processing
if (type == 2) {
av_log_ask_for_sample(avctx, "unknown opcode");
return AVERROR_INVALIDDATA;
}
// extra long skip (type == 1) or nop (type == 3)
}
switch (type) {
case 1:
// same as originally read value & 0x7fff instead of 0x3fff
count += 0x4000;
case 0:
DO_OP(NULL, -1, count);
break;
case 2:
DO_OP(&buf, -1, count);
break;
case 3:
pixel = bytestream_get_byte(&buf);
DO_OP(NULL, pixel, count);
break;
}
}
The switch could also be replaced by
pixel = type == 3 ? bytestream_get_byte(&buf) : -1;
if (type == 1) count += 0x4000;
DO_OP(type == 2 ? &buf : NULL, pixel, count);
More information about the ffmpeg-devel
mailing list