X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fsvq1dec.c;h=cc43f1491c1776cf27c5879b10dce9bb189c1669;hb=d1a91ebe4990001e0800ee9ac54ed2207e4f56ff;hp=6e096f3f4370cbafd815c27bba1022f1e9ac9a1e;hpb=63a46c6101ffe0ba6a5f6e90d595583ecf943d0d;p=ffmpeg diff --git a/libavcodec/svq1dec.c b/libavcodec/svq1dec.c index 6e096f3f437..cc43f1491c1 100644 --- a/libavcodec/svq1dec.c +++ b/libavcodec/svq1dec.c @@ -4,7 +4,7 @@ * ported to libavcodec by Nick Kurshev * * Copyright (C) 2002 the xine project - * Copyright (C) 2002 the ffmpeg project + * Copyright (C) 2002 The FFmpeg project * * SVQ1 Encoder (c) 2004 Mike Melanson * @@ -33,16 +33,13 @@ */ #include "avcodec.h" -#include "dsputil.h" -#include "mpegvideo.h" +#include "get_bits.h" +#include "h263.h" +#include "hpeldsp.h" +#include "internal.h" #include "mathops.h" #include "svq1.h" -#undef NDEBUG -#include - -extern const uint8_t ff_mvtab[33][2]; - static VLC svq1_block_type; static VLC svq1_motion_component; static VLC svq1_intra_multistage[6]; @@ -56,6 +53,20 @@ typedef struct svq1_pmv_s { int y; } svq1_pmv; +typedef struct SVQ1Context { + HpelDSPContext hdsp; + GetBitContext gb; + AVFrame *prev; + + uint8_t *pkt_swapped; + int pkt_swapped_allocated; + + int width; + int height; + int frame_code; + int nonref; // 1 if the current frame won't be referenced +} SVQ1Context; + static const uint8_t string_table[256] = { 0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54, 0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D, @@ -131,32 +142,6 @@ static const uint8_t string_table[256] = { n2 &= n3 & 0x00FF00FF; \ } -#define SVQ1_DO_CODEBOOK_INTRA() \ - for (y = 0; y < height; y++) { \ - for (x = 0; x < width / 4; x++, codebook++) { \ - n1 = n4; \ - n2 = n4; \ - SVQ1_ADD_CODEBOOK() \ - /* store result */ \ - dst[x] = n1 << 8 | n2; \ - } \ - dst += pitch / 4; \ - } - -#define SVQ1_DO_CODEBOOK_NONINTRA() \ - for (y = 0; y < height; y++) { \ - for (x = 0; x < width / 4; x++, codebook++) { \ - n3 = dst[x]; \ - /* add mean value to vector */ \ - n1 = n4 + ((n3 & 0xFF00FF00) >> 8); \ - n2 = n4 + (n3 & 0x00FF00FF); \ - SVQ1_ADD_CODEBOOK() \ - /* store result */ \ - dst[x] = n1 << 8 | n2; \ - } \ - dst += pitch / 4; \ - } - #define SVQ1_CALC_CODEBOOK_ENTRIES(cbook) \ codebook = (const uint32_t *)cbook[level]; \ if (stages > 0) \ @@ -170,7 +155,7 @@ static const uint8_t string_table[256] = { n4 = mean + (mean >> 31) << 16 | (mean & 0xFFFF); static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels, - int pitch) + ptrdiff_t pitch) { uint32_t bit_cache; uint8_t *list[63]; @@ -203,11 +188,11 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels, continue; /* skip vector */ } - if (stages > 0 && level >= 4) { - av_dlog(NULL, + if ((stages > 0 && level >= 4) || stages < 0) { + ff_dlog(NULL, "Error (svq1_decode_block_intra): invalid vector: stages=%i level=%i\n", stages, level); - return -1; /* invalid vector */ + return AVERROR_INVALIDDATA; /* invalid vector */ } mean = get_vlc2(bitbuf, svq1_intra_mean.table, 8, 3); @@ -217,7 +202,17 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels, memset(&dst[y * (pitch / 4)], mean, width); } else { SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_intra_codebooks); - SVQ1_DO_CODEBOOK_INTRA() + + for (y = 0; y < height; y++) { + for (x = 0; x < width / 4; x++, codebook++) { + n1 = n4; + n2 = n4; + SVQ1_ADD_CODEBOOK() + /* store result */ + dst[x] = n1 << 8 | n2; + } + dst += pitch / 4; + } } } @@ -225,7 +220,7 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels, } static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels, - int pitch) + ptrdiff_t pitch) { uint32_t bit_cache; uint8_t *list[63]; @@ -255,17 +250,29 @@ static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels, if (stages == -1) continue; /* skip vector */ - if ((stages > 0) && (level >= 4)) { - av_dlog(NULL, + if ((stages > 0 && level >= 4) || stages < 0) { + ff_dlog(NULL, "Error (svq1_decode_block_non_intra): invalid vector: stages=%i level=%i\n", stages, level); - return -1; /* invalid vector */ + return AVERROR_INVALIDDATA; /* invalid vector */ } mean = get_vlc2(bitbuf, svq1_inter_mean.table, 9, 3) - 256; SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_inter_codebooks); - SVQ1_DO_CODEBOOK_NONINTRA() + + for (y = 0; y < height; y++) { + for (x = 0; x < width / 4; x++, codebook++) { + n3 = dst[x]; + /* add mean value to vector */ + n1 = n4 + ((n3 & 0xFF00FF00) >> 8); + n2 = n4 + (n3 & 0x00FF00FF); + SVQ1_ADD_CODEBOOK() + /* store result */ + dst[x] = n1 << 8 | n2; + } + dst += pitch / 4; + } } return 0; } @@ -280,7 +287,7 @@ static int svq1_decode_motion_vector(GetBitContext *bitbuf, svq1_pmv *mv, /* get motion code */ diff = get_vlc2(bitbuf, svq1_motion_component.table, 7, 2); if (diff < 0) - return -1; + return AVERROR_INVALIDDATA; else if (diff) { if (get_bits1(bitbuf)) diff = -diff; @@ -297,7 +304,7 @@ static int svq1_decode_motion_vector(GetBitContext *bitbuf, svq1_pmv *mv, } static void svq1_skip_block(uint8_t *current, uint8_t *previous, - int pitch, int x, int y) + ptrdiff_t pitch, int x, int y) { uint8_t *src; uint8_t *dst; @@ -313,9 +320,10 @@ static void svq1_skip_block(uint8_t *current, uint8_t *previous, } } -static int svq1_motion_inter_block(MpegEncContext *s, GetBitContext *bitbuf, +static int svq1_motion_inter_block(HpelDSPContext *hdsp, GetBitContext *bitbuf, uint8_t *current, uint8_t *previous, - int pitch, svq1_pmv *motion, int x, int y) + ptrdiff_t pitch, svq1_pmv *motion, int x, int y, + int width, int height) { uint8_t *src; uint8_t *dst; @@ -345,22 +353,21 @@ static int svq1_motion_inter_block(MpegEncContext *s, GetBitContext *bitbuf, motion[x / 8 + 2].y = motion[x / 8 + 3].y = mv.y; - if (y + (mv.y >> 1) < 0) - mv.y = 0; - if (x + (mv.x >> 1) < 0) - mv.x = 0; + mv.x = av_clip(mv.x, -2 * x, 2 * (width - x - 16)); + mv.y = av_clip(mv.y, -2 * y, 2 * (height - y - 16)); src = &previous[(x + (mv.x >> 1)) + (y + (mv.y >> 1)) * pitch]; dst = current; - s->dsp.put_pixels_tab[0][(mv.y & 1) << 1 | (mv.x & 1)](dst, src, pitch, 16); + hdsp->put_pixels_tab[0][(mv.y & 1) << 1 | (mv.x & 1)](dst, src, pitch, 16); return 0; } -static int svq1_motion_inter_4v_block(MpegEncContext *s, GetBitContext *bitbuf, +static int svq1_motion_inter_4v_block(HpelDSPContext *hdsp, GetBitContext *bitbuf, uint8_t *current, uint8_t *previous, - int pitch, svq1_pmv *motion, int x, int y) + ptrdiff_t pitch, svq1_pmv *motion, int x, int y, + int width, int height) { uint8_t *src; uint8_t *dst; @@ -420,15 +427,13 @@ static int svq1_motion_inter_4v_block(MpegEncContext *s, GetBitContext *bitbuf, int mvy = pmv[i]->y + (i >> 1) * 16; // FIXME: clipping or padding? - if (y + (mvy >> 1) < 0) - mvy = 0; - if (x + (mvx >> 1) < 0) - mvx = 0; + mvx = av_clip(mvx, -2 * x, 2 * (width - x - 8)); + mvy = av_clip(mvy, -2 * y, 2 * (height - y - 8)); src = &previous[(x + (mvx >> 1)) + (y + (mvy >> 1)) * pitch]; dst = current; - s->dsp.put_pixels_tab[1][((mvy & 1) << 1) | (mvx & 1)](dst, src, pitch, 8); + hdsp->put_pixels_tab[1][((mvy & 1) << 1) | (mvx & 1)](dst, src, pitch, 8); /* select next block */ if (i & 1) @@ -440,9 +445,11 @@ static int svq1_motion_inter_4v_block(MpegEncContext *s, GetBitContext *bitbuf, return 0; } -static int svq1_decode_delta_block(MpegEncContext *s, GetBitContext *bitbuf, +static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp, + GetBitContext *bitbuf, uint8_t *current, uint8_t *previous, - int pitch, svq1_pmv *motion, int x, int y) + ptrdiff_t pitch, svq1_pmv *motion, int x, int y, + int width, int height) { uint32_t block_type; int result = 0; @@ -466,23 +473,22 @@ static int svq1_decode_delta_block(MpegEncContext *s, GetBitContext *bitbuf, break; case SVQ1_BLOCK_INTER: - result = svq1_motion_inter_block(s, bitbuf, current, previous, - pitch, motion, x, y); + result = svq1_motion_inter_block(hdsp, bitbuf, current, previous, + pitch, motion, x, y, width, height); if (result != 0) { - av_dlog(s->avctx, "Error in svq1_motion_inter_block %i\n", result); + ff_dlog(avctx, "Error in svq1_motion_inter_block %i\n", result); break; } result = svq1_decode_block_non_intra(bitbuf, current, pitch); break; case SVQ1_BLOCK_INTER_4V: - result = svq1_motion_inter_4v_block(s, bitbuf, current, previous, - pitch, motion, x, y); + result = svq1_motion_inter_4v_block(hdsp, bitbuf, current, previous, + pitch, motion, x, y, width, height); if (result != 0) { - av_dlog(s->avctx, - "Error in svq1_motion_inter_4v_block %i\n", result); + ff_dlog(avctx, "Error in svq1_motion_inter_4v_block %i\n", result); break; } result = svq1_decode_block_non_intra(bitbuf, current, pitch); @@ -510,36 +516,49 @@ static void svq1_parse_string(GetBitContext *bitbuf, uint8_t *out) } } -static int svq1_decode_frame_header(GetBitContext *bitbuf, MpegEncContext *s) +static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame) { + SVQ1Context *s = avctx->priv_data; + GetBitContext *bitbuf = &s->gb; int frame_size_code; skip_bits(bitbuf, 8); /* temporal_reference */ /* frame type */ - s->pict_type = get_bits(bitbuf, 2) + 1; - if (s->pict_type == 4) - return -1; + s->nonref = 0; + switch (get_bits(bitbuf, 2)) { + case 0: + frame->pict_type = AV_PICTURE_TYPE_I; + break; + case 2: + s->nonref = 1; + case 1: + frame->pict_type = AV_PICTURE_TYPE_P; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid frame type.\n"); + return AVERROR_INVALIDDATA; + } - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (frame->pict_type == AV_PICTURE_TYPE_I) { /* unknown fields */ - if (s->f_code == 0x50 || s->f_code == 0x60) { + if (s->frame_code == 0x50 || s->frame_code == 0x60) { int csum = get_bits(bitbuf, 16); csum = ff_svq1_packet_checksum(bitbuf->buffer, bitbuf->size_in_bits >> 3, csum); - av_dlog(s->avctx, "%s checksum (%02x) for packet data\n", + ff_dlog(avctx, "%s checksum (%02x) for packet data\n", (csum == 0) ? "correct" : "incorrect", csum); } - if ((s->f_code ^ 0x10) >= 0x50) { + if ((s->frame_code ^ 0x10) >= 0x50) { uint8_t msg[256]; svq1_parse_string(bitbuf, msg); - av_log(s->avctx, AV_LOG_INFO, + av_log(avctx, AV_LOG_INFO, "embedded message: \"%s\"\n", (char *)msg); } @@ -556,11 +575,11 @@ static int svq1_decode_frame_header(GetBitContext *bitbuf, MpegEncContext *s) s->height = get_bits(bitbuf, 12); if (!s->width || !s->height) - return -1; + return AVERROR_INVALIDDATA; } else { /* get width, height from table */ - s->width = ff_svq1_frame_size_table[frame_size_code].width; - s->height = ff_svq1_frame_size_table[frame_size_code].height; + s->width = ff_svq1_frame_size_table[frame_size_code][0]; + s->height = ff_svq1_frame_size_table[frame_size_code][1]; } } @@ -570,7 +589,7 @@ static int svq1_decode_frame_header(GetBitContext *bitbuf, MpegEncContext *s) skip_bits1(bitbuf); /* component checksums after image data if (1) */ if (get_bits(bitbuf, 2) != 0) - return -1; + return AVERROR_INVALIDDATA; } if (get_bits1(bitbuf) == 1) { @@ -587,91 +606,99 @@ static int svq1_decode_frame_header(GetBitContext *bitbuf, MpegEncContext *s) } static int svq1_decode_frame(AVCodecContext *avctx, void *data, - int *data_size, AVPacket *avpkt) + int *got_frame, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - MpegEncContext *s = avctx->priv_data; - uint8_t *current, *previous; + SVQ1Context *s = avctx->priv_data; + AVFrame *cur = data; + uint8_t *current; int result, i, x, y, width, height; - AVFrame *pict = data; svq1_pmv *pmv; /* initialize bit buffer */ init_get_bits(&s->gb, buf, buf_size * 8); /* decode frame header */ - s->f_code = get_bits(&s->gb, 22); + s->frame_code = get_bits(&s->gb, 22); - if ((s->f_code & ~0x70) || !(s->f_code & 0x60)) - return -1; + if ((s->frame_code & ~0x70) || !(s->frame_code & 0x60)) + return AVERROR_INVALIDDATA; /* swap some header bytes (why?) */ - if (s->f_code != 0x20) { - uint32_t *src = (uint32_t *)(buf + 4); + if (s->frame_code != 0x20) { + uint32_t *src; + + if (buf_size < 9 * 4) { + av_log(avctx, AV_LOG_ERROR, "Input packet too small\n"); + return AVERROR_INVALIDDATA; + } + + av_fast_padded_malloc(&s->pkt_swapped, + &s->pkt_swapped_allocated, + buf_size); + if (!s->pkt_swapped) + return AVERROR(ENOMEM); + + memcpy(s->pkt_swapped, buf, buf_size); + buf = s->pkt_swapped; + init_get_bits(&s->gb, buf, buf_size * 8); + skip_bits(&s->gb, 22); + + src = (uint32_t *)(s->pkt_swapped + 4); for (i = 0; i < 4; i++) src[i] = ((src[i] << 16) | (src[i] >> 16)) ^ src[7 - i]; } - result = svq1_decode_frame_header(&s->gb, s); + result = svq1_decode_frame_header(avctx, cur); if (result != 0) { - av_dlog(s->avctx, "Error in svq1_decode_frame_header %i\n", result); + ff_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result); return result; } - avcodec_set_dimensions(avctx, s->width, s->height); - /* FIXME: This avoids some confusion for "B frames" without 2 references. - * This should be removed after libavcodec can handle more flexible - * picture types & ordering */ - if (s->pict_type == AV_PICTURE_TYPE_B && s->last_picture_ptr == NULL) - return buf_size; + result = ff_set_dimensions(avctx, s->width, s->height); + if (result < 0) + return result; - if ((avctx->skip_frame >= AVDISCARD_NONREF && - s->pict_type == AV_PICTURE_TYPE_B) || + if ((avctx->skip_frame >= AVDISCARD_NONREF && s->nonref) || (avctx->skip_frame >= AVDISCARD_NONKEY && - s->pict_type != AV_PICTURE_TYPE_I) || + cur->pict_type != AV_PICTURE_TYPE_I) || avctx->skip_frame >= AVDISCARD_ALL) return buf_size; - if (ff_MPV_frame_start(s, avctx) < 0) - return -1; + result = ff_get_buffer(avctx, cur, s->nonref ? 0 : AV_GET_BUFFER_FLAG_REF); + if (result < 0) + return result; pmv = av_malloc((FFALIGN(s->width, 16) / 8 + 3) * sizeof(*pmv)); if (!pmv) - return -1; + return AVERROR(ENOMEM); /* decode y, u and v components */ for (i = 0; i < 3; i++) { - int linesize; + int linesize = cur->linesize[i]; if (i == 0) { width = FFALIGN(s->width, 16); height = FFALIGN(s->height, 16); - linesize = s->linesize; } else { - if (s->flags & CODEC_FLAG_GRAY) + if (avctx->flags & AV_CODEC_FLAG_GRAY) break; width = FFALIGN(s->width / 4, 16); height = FFALIGN(s->height / 4, 16); - linesize = s->uvlinesize; } - current = s->current_picture.f.data[i]; - - if (s->pict_type == AV_PICTURE_TYPE_B) - previous = s->next_picture.f.data[i]; - else - previous = s->last_picture.f.data[i]; + current = cur->data[i]; - if (s->pict_type == AV_PICTURE_TYPE_I) { + if (cur->pict_type == AV_PICTURE_TYPE_I) { /* keyframe */ for (y = 0; y < height; y += 16) { for (x = 0; x < width; x += 16) { result = svq1_decode_block_intra(&s->gb, ¤t[x], linesize); if (result != 0) { - av_log(s->avctx, AV_LOG_INFO, + av_log(avctx, AV_LOG_INFO, "Error in svq1_decode_block %i (keyframe)\n", result); goto err; @@ -681,15 +708,24 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data, } } else { /* delta frame */ + uint8_t *previous = s->prev->data[i]; + if (!previous || + s->prev->width != s->width || s->prev->height != s->height) { + av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); + result = AVERROR_INVALIDDATA; + goto err; + } + memset(pmv, 0, ((width / 8) + 3) * sizeof(svq1_pmv)); for (y = 0; y < height; y += 16) { for (x = 0; x < width; x += 16) { - result = svq1_decode_delta_block(s, &s->gb, ¤t[x], + result = svq1_decode_delta_block(avctx, &s->hdsp, + &s->gb, ¤t[x], previous, linesize, - pmv, x, y); + pmv, x, y, width, height); if (result != 0) { - av_dlog(s->avctx, + ff_dlog(avctx, "Error in svq1_decode_delta_block %i\n", result); goto err; @@ -704,11 +740,14 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data, } } - *pict = s->current_picture.f; - - ff_MPV_frame_end(s); + if (!s->nonref) { + av_frame_unref(s->prev); + result = av_frame_ref(s->prev, cur); + if (result < 0) + goto err; + } - *data_size = sizeof(AVFrame); + *got_frame = 1; result = buf_size; err: @@ -718,22 +757,19 @@ err: static av_cold int svq1_decode_init(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + SVQ1Context *s = avctx->priv_data; int i; int offset = 0; - ff_MPV_decode_defaults(s); + s->prev = av_frame_alloc(); + if (!s->prev) + return AVERROR(ENOMEM); - s->avctx = avctx; s->width = avctx->width + 3 & ~3; s->height = avctx->height + 3 & ~3; - s->codec_id = avctx->codec->id; avctx->pix_fmt = AV_PIX_FMT_YUV410P; - /* Not true, but DP frames and these behave like unidirectional B-frames. */ - avctx->has_b_frames = 1; - s->flags = avctx->flags; - if (ff_MPV_common_init(s) < 0) - return -1; + + ff_hpeldsp_init(&s->hdsp, avctx->flags); INIT_VLC_STATIC(&svq1_block_type, 2, 4, &ff_svq1_block_type_vlc[0][1], 2, 1, @@ -776,23 +812,32 @@ static av_cold int svq1_decode_init(AVCodecContext *avctx) static av_cold int svq1_decode_end(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; + SVQ1Context *s = avctx->priv_data; + + av_frame_free(&s->prev); + av_freep(&s->pkt_swapped); - ff_MPV_common_end(s); return 0; } +static void svq1_flush(AVCodecContext *avctx) +{ + SVQ1Context *s = avctx->priv_data; + + av_frame_unref(s->prev); +} + AVCodec ff_svq1_decoder = { .name = "svq1", + .long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1 / Sorenson Video 1 / SVQ1"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_SVQ1, - .priv_data_size = sizeof(MpegEncContext), + .priv_data_size = sizeof(SVQ1Context), .init = svq1_decode_init, .close = svq1_decode_end, .decode = svq1_decode_frame, - .capabilities = CODEC_CAP_DR1, - .flush = ff_mpeg_flush, - .pix_fmts = (const enum PixelFormat[]) { AV_PIX_FMT_YUV410P, - AV_PIX_FMT_NONE }, - .long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1 / Sorenson Video 1 / SVQ1"), + .capabilities = AV_CODEC_CAP_DR1, + .flush = svq1_flush, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV410P, + AV_PIX_FMT_NONE }, };