1286 lines · 37.8 KB · C
RawDownload
/* * Amuse Graphics Movie decoder * * Copyright (c) 2018 Paul B Mahol * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <string.h> #define BITSTREAM_READER_LE #include "libavutil/mem.h"#include "libavutil/mem_internal.h" #include "avcodec.h"#include "bytestream.h"#include "codec_internal.h"#include "copy_block.h"#include "decode.h"#include "get_bits.h"#include "idctdsp.h"#include "jpegquanttables.h" typedef struct MotionVector {    int16_t x, y;} MotionVector; typedef struct AGMContext {    const AVClass  *class;    AVCodecContext *avctx;    GetBitContext   gb;    GetByteContext  gbyte;     int key_frame;    int bitstream_size;    int compression;    int blocks_w;    int blocks_h;    int size[3];    int plus;    int dct;    int rgb;    unsigned flags;    unsigned fflags;     uint8_t *output;    unsigned padded_output_size;    unsigned output_size;     MotionVector *mvectors;    unsigned      mvectors_size;     VLC vlc;     AVFrame *prev_frame;     int luma_quant_matrix[64];    int chroma_quant_matrix[64];     uint8_t permutated_scantable[64];    DECLARE_ALIGNED(32, int16_t, block)[64];     int16_t *wblocks;    unsigned wblocks_size;     int      *map;    unsigned  map_size;     IDCTDSPContext idsp;} AGMContext; static int read_code(GetBitContext *gb, int *oskip, int *level, int *map, int mode){    int len = 0, skip = 0, max;     if (get_bits_left(gb) < 2)        return AVERROR_INVALIDDATA;     if (show_bits(gb, 2)) {        switch (show_bits(gb, 4)) {        case 1:        case 9:            len = 1;            skip = 3;            break;        case 2:            len = 3;            skip = 4;            break;        case 3:            len = 7;            skip = 4;            break;        case 5:        case 13:            len = 2;            skip = 3;            break;        case 6:            len = 4;            skip = 4;            break;        case 7:            len = 8;            skip = 4;            break;        case 10:            len = 5;            skip = 4;            break;        case 11:            len = 9;            skip = 4;            break;        case 14:            len = 6;            skip = 4;            break;        case 15:            len = ((show_bits(gb, 5) & 0x10) | 0xA0) >> 4;            skip = 5;            break;        default:            return AVERROR_INVALIDDATA;        }         skip_bits(gb, skip);        *level = get_bits(gb, len);        *map = 1;        *oskip = 0;        max = 1 << (len - 1);        if (*level < max)            *level = -(max + *level);    } else if (show_bits(gb, 3) & 4) {        skip_bits(gb, 3);        if (mode == 1) {            if (show_bits(gb, 4)) {                if (show_bits(gb, 4) == 1) {                    skip_bits(gb, 4);                    *oskip = get_bits(gb, 16);                } else {                    *oskip = get_bits(gb, 4);                }            } else {                skip_bits(gb, 4);                *oskip = get_bits(gb, 10);            }        } else if (mode == 0) {            *oskip = get_bits(gb, 10);        }        *level = 0;    } else {        skip_bits(gb, 3);        if (mode == 0)            *oskip = get_bits(gb, 4);        else if (mode == 1)            *oskip = 0;        *level = 0;    }     return 0;} static int decode_intra_blocks(AGMContext *s, GetBitContext *gb,                               const int *quant_matrix, int *skip, int *dc_level){    const uint8_t *scantable = s->permutated_scantable;    int level, ret, map = 0;     memset(s->wblocks, 0, s->wblocks_size);     for (int i = 0; i < 64; i++) {        int16_t *block = s->wblocks + scantable[i];         for (int j = 0; j < s->blocks_w;) {            if (*skip > 0) {                int rskip;                 rskip = FFMIN(*skip, s->blocks_w - j);                j += rskip;                if (i == 0) {                    for (int k = 0; k < rskip; k++)                        block[64 * k] = *dc_level * quant_matrix[0];                }                block += rskip * 64;                *skip -= rskip;            } else {                ret = read_code(gb, skip, &level, &map, s->flags & 1);                if (ret < 0)                    return ret;                 if (i == 0)                    *dc_level += level;                 block[0] = (i == 0 ? *dc_level : level) * quant_matrix[i];                block += 64;                j++;            }        }    }     return 0;} static int decode_inter_blocks(AGMContext *s, GetBitContext *gb,                               const int *quant_matrix, int *skip,                               int *map){    const uint8_t *scantable = s->permutated_scantable;    int level, ret;     memset(s->wblocks, 0, s->wblocks_size);    memset(s->map, 0, s->map_size);     for (int i = 0; i < 64; i++) {        int16_t *block = s->wblocks + scantable[i];         for (int j = 0; j < s->blocks_w;) {            if (*skip > 0) {                int rskip;                 rskip = FFMIN(*skip, s->blocks_w - j);                j += rskip;                block += rskip * 64;                *skip -= rskip;            } else {                ret = read_code(gb, skip, &level, &map[j], s->flags & 1);                if (ret < 0)                    return ret;                 block[0] = level * quant_matrix[i];                block += 64;                j++;            }        }    }     return 0;} static int decode_intra_block(AGMContext *s, GetBitContext *gb,                              const int *quant_matrix, int *skip, int *dc_level){    const uint8_t *scantable = s->permutated_scantable;    const int offset = s->plus ? 0 : 1024;    int16_t *block = s->block;    int level, ret, map = 0;     memset(block, 0, sizeof(s->block));     if (*skip > 0) {        (*skip)--;    } else {        ret = read_code(gb, skip, &level, &map, s->flags & 1);        if (ret < 0)            return ret;        *dc_level += level;    }    block[scantable[0]] = offset + *dc_level * quant_matrix[0];     for (int i = 1; i < 64;) {        if (*skip > 0) {            int rskip;             rskip = FFMIN(*skip, 64 - i);            i += rskip;            *skip -= rskip;        } else {            ret = read_code(gb, skip, &level, &map, s->flags & 1);            if (ret < 0)                return ret;             block[scantable[i]] = level * quant_matrix[i];            i++;        }    }     return 0;} static int decode_intra_plane(AGMContext *s, GetBitContext *gb, int size,                              const int *quant_matrix, AVFrame *frame,                              int plane){    int ret, skip = 0, dc_level = 0;    const int offset = s->plus ? 0 : 1024;     if ((ret = init_get_bits8(gb, s->gbyte.buffer, size)) < 0)        return ret;     if (s->flags & 1) {        av_fast_padded_malloc(&s->wblocks, &s->wblocks_size,                              64 * s->blocks_w * sizeof(*s->wblocks));        if (!s->wblocks)            return AVERROR(ENOMEM);         for (int y = 0; y < s->blocks_h; y++) {            ret = decode_intra_blocks(s, gb, quant_matrix, &skip, &dc_level);            if (ret < 0)                return ret;             for (int x = 0; x < s->blocks_w; x++) {                s->wblocks[64 * x] += offset;                s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                 frame->linesize[plane], s->wblocks + 64 * x);            }        }    } else {        for (int y = 0; y < s->blocks_h; y++) {            for (int x = 0; x < s->blocks_w; x++) {                ret = decode_intra_block(s, gb, quant_matrix, &skip, &dc_level);                if (ret < 0)                    return ret;                 s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                 frame->linesize[plane], s->block);            }        }    }     align_get_bits(gb);    if (get_bits_left(gb) < 0)        av_log(s->avctx, AV_LOG_WARNING, "overread\n");    if (get_bits_left(gb) > 0)        av_log(s->avctx, AV_LOG_WARNING, "underread: %d\n", get_bits_left(gb));     return 0;} static int decode_inter_block(AGMContext *s, GetBitContext *gb,                              const int *quant_matrix, int *skip,                              int *map){    const uint8_t *scantable = s->permutated_scantable;    int16_t *block = s->block;    int level, ret;     memset(block, 0, sizeof(s->block));     for (int i = 0; i < 64;) {        if (*skip > 0) {            int rskip;             rskip = FFMIN(*skip, 64 - i);            i += rskip;            *skip -= rskip;        } else {            ret = read_code(gb, skip, &level, map, s->flags & 1);            if (ret < 0)                return ret;             block[scantable[i]] = level * quant_matrix[i];            i++;        }    }     return 0;} static int decode_inter_plane(AGMContext *s, GetBitContext *gb, int size,                              const int *quant_matrix, AVFrame *frame,                              AVFrame *prev, int plane){    int ret, skip = 0;     if ((ret = init_get_bits8(gb, s->gbyte.buffer, size)) < 0)        return ret;     if (s->flags == 3) {        av_fast_padded_malloc(&s->wblocks, &s->wblocks_size,                              64 * s->blocks_w * sizeof(*s->wblocks));        if (!s->wblocks)            return AVERROR(ENOMEM);         av_fast_padded_malloc(&s->map, &s->map_size,                              s->blocks_w * sizeof(*s->map));        if (!s->map)            return AVERROR(ENOMEM);         for (int y = 0; y < s->blocks_h; y++) {            ret = decode_inter_blocks(s, gb, quant_matrix, &skip, s->map);            if (ret < 0)                return ret;             for (int x = 0; x < s->blocks_w; x++) {                int shift = plane == 0;                int mvpos = (y >> shift) * (s->blocks_w >> shift) + (x >> shift);                int orig_mv_x = s->mvectors[mvpos].x;                int mv_x = s->mvectors[mvpos].x / (1 + !shift);                int mv_y = s->mvectors[mvpos].y / (1 + !shift);                int h = s->avctx->coded_height >> !shift;                int w = s->avctx->coded_width  >> !shift;                int map = s->map[x];                 if (orig_mv_x >= -32) {                    if (y * 8 + mv_y < 0 || y * 8 + mv_y + 8 > h ||                        x * 8 + mv_x < 0 || x * 8 + mv_x + 8 > w)                        return AVERROR_INVALIDDATA;                     copy_block8(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                prev->data[plane] + ((s->blocks_h - 1 - y) * 8 - mv_y) * prev->linesize[plane] + (x * 8 + mv_x),                                frame->linesize[plane], prev->linesize[plane], 8);                    if (map) {                        s->idsp.idct(s->wblocks + x * 64);                        for (int i = 0; i < 64; i++)                            s->wblocks[i + x * 64] = (s->wblocks[i + x * 64] + 1) & 0xFFFC;                        s->idsp.add_pixels_clamped(&s->wblocks[x*64], frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                                   frame->linesize[plane]);                    }                } else if (map) {                    s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                     frame->linesize[plane], s->wblocks + x * 64);                }            }        }    } else if (s->flags & 2) {        for (int y = 0; y < s->blocks_h; y++) {            for (int x = 0; x < s->blocks_w; x++) {                int shift = plane == 0;                int mvpos = (y >> shift) * (s->blocks_w >> shift) + (x >> shift);                int orig_mv_x = s->mvectors[mvpos].x;                int mv_x = s->mvectors[mvpos].x / (1 + !shift);                int mv_y = s->mvectors[mvpos].y / (1 + !shift);                int h = s->avctx->coded_height >> !shift;                int w = s->avctx->coded_width  >> !shift;                int map = 0;                 ret = decode_inter_block(s, gb, quant_matrix, &skip, &map);                if (ret < 0)                    return ret;                 if (orig_mv_x >= -32) {                    if (y * 8 + mv_y < 0 || y * 8 + mv_y + 8 > h ||                        x * 8 + mv_x < 0 || x * 8 + mv_x + 8 > w)                        return AVERROR_INVALIDDATA;                     copy_block8(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                prev->data[plane] + ((s->blocks_h - 1 - y) * 8 - mv_y) * prev->linesize[plane] + (x * 8 + mv_x),                                frame->linesize[plane], prev->linesize[plane], 8);                    if (map) {                        s->idsp.idct(s->block);                        for (int i = 0; i < 64; i++)                            s->block[i] = (s->block[i] + 1) & 0xFFFC;                        s->idsp.add_pixels_clamped(s->block, frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                                   frame->linesize[plane]);                    }                } else if (map) {                    s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                     frame->linesize[plane], s->block);                }            }        }    } else if (s->flags & 1) {        av_fast_padded_malloc(&s->wblocks, &s->wblocks_size,                              64 * s->blocks_w * sizeof(*s->wblocks));        if (!s->wblocks)            return AVERROR(ENOMEM);         av_fast_padded_malloc(&s->map, &s->map_size,                              s->blocks_w * sizeof(*s->map));        if (!s->map)            return AVERROR(ENOMEM);         for (int y = 0; y < s->blocks_h; y++) {            ret = decode_inter_blocks(s, gb, quant_matrix, &skip, s->map);            if (ret < 0)                return ret;             for (int x = 0; x < s->blocks_w; x++) {                if (!s->map[x])                    continue;                s->idsp.idct_add(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8,                                 frame->linesize[plane], s->wblocks + 64 * x);            }        }    } else {        for (int y = 0; y < s->blocks_h; y++) {            for (int x = 0; x < s->blocks_w; x++) {                int map = 0;                 ret = decode_inter_block(s, gb, quant_matrix, &skip, &map);                if (ret < 0)                    return ret;                 if (!map)

Lines 1–500 of 1286.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t