diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2003-08-22 14:59:04 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2003-08-22 14:59:04 +0000 |
commit | c3bf0288c9bc119e41818fc4b94290d54c4bc5cb (patch) | |
tree | ca55f5f69dce47cfc8f4d7af4359afcedca282f1 | |
parent | a6aec9c94fe379068b6e959ea93779b3c2b5b73d (diff) | |
download | ffmpeg-c3bf0288c9bc119e41818fc4b94290d54c4bc5cb.tar.gz |
PSX MDEC decoder, based upon some code from Sebastian Jedruszkiewicz <elf at frogger dot rules dot pl>
note: completly untested, no demuxer yet
Originally committed as revision 2134 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 7 | ||||
-rw-r--r-- | libavcodec/mdec.c | 292 | ||||
-rw-r--r-- | libavcodec/mpeg12.c | 23 | ||||
-rw-r--r-- | libavcodec/mpegvideo.h | 6 |
5 files changed, 315 insertions, 14 deletions
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f14844200d..d5f16660ed 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -116,6 +116,7 @@ void avcodec_register_all(void) register_avcodec(&vcr1_decoder); register_avcodec(&cljr_decoder); register_avcodec(&fourxm_decoder); + register_avcodec(&mdec_decoder); #ifdef CONFIG_AC3 register_avcodec(&ac3_decoder); #endif diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 4872054eb1..f049cb1931 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -15,8 +15,8 @@ extern "C" { #define LIBAVCODEC_VERSION_INT 0x000406 #define LIBAVCODEC_VERSION "0.4.6" -#define LIBAVCODEC_BUILD 4673 -#define LIBAVCODEC_BUILD_STR "4673" +#define LIBAVCODEC_BUILD 4674 +#define LIBAVCODEC_BUILD_STR "4674" #define LIBAVCODEC_IDENT "FFmpeg" LIBAVCODEC_VERSION "b" LIBAVCODEC_BUILD_STR @@ -63,6 +63,7 @@ enum CodecID { CODEC_ID_4XM, CODEC_ID_VCR1, CODEC_ID_CLJR, + CODEC_ID_MDEC, /* various pcm "codecs" */ CODEC_ID_PCM_S16LE, @@ -1283,6 +1284,7 @@ extern AVCodec h264_encoder; extern AVCodec asv1_encoder; extern AVCodec vcr1_encoder; extern AVCodec ffv1_encoder; +extern AVCodec mdec_encoder; extern AVCodec h263_decoder; extern AVCodec mpeg4_decoder; @@ -1323,6 +1325,7 @@ extern AVCodec vcr1_decoder; extern AVCodec cljr_decoder; extern AVCodec ffv1_decoder; extern AVCodec fourxm_decoder; +extern AVCodec mdec_decoder; extern AVCodec ra_144_decoder; extern AVCodec ra_288_decoder; diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c new file mode 100644 index 0000000000..176ee9b8f7 --- /dev/null +++ b/libavcodec/mdec.c @@ -0,0 +1,292 @@ +/* + * PSX MDEC codec + * Copyright (c) 2003 Michael Niedermayer + * + * This library 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 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * based upon code from Sebastian Jedruszkiewicz <elf@frogger.rules.pl> + */ + +/** + * @file mdec.c + * PSX MDEC codec. + * This is very similar to intra only MPEG1. + */ + +#include "avcodec.h" +#include "dsputil.h" +#include "mpegvideo.h" + +//#undef NDEBUG +//#include <assert.h> + +typedef struct MDECContext{ + AVCodecContext *avctx; + DSPContext dsp; + AVFrame picture; + PutBitContext pb; + GetBitContext gb; + ScanTable scantable; + int version; + int qscale; + int last_dc[3]; + int mb_width; + int mb_height; + int mb_x, mb_y; + DCTELEM __align8 block[6][64]; + uint16_t __align8 intra_matrix[64]; + int __align8 q_intra_matrix[64]; + uint8_t *bitstream_buffer; + int bitstream_buffer_size; + int block_last_index[6]; +} MDECContext; + +//very similar to mpeg1 +static inline int mdec_decode_block_intra(MDECContext *a, DCTELEM *block, int n) +{ + int level, diff, i, j, run; + int component; + RLTable *rl = &rl_mpeg1; + uint8_t * const scantable= a->scantable.permutated; + const uint16_t *quant_matrix= ff_mpeg1_default_intra_matrix; + const int qscale= a->qscale; + + /* DC coef */ + if(a->version==2){ + block[0]= get_sbits(&a->gb, 11); + }else{ + component = (n <= 3 ? 0 : n - 4 + 1); + diff = decode_dc(&a->gb, component); + if (diff >= 0xffff) + return -1; + a->last_dc[component]+= diff; + block[0] = a->last_dc[component]<<3; + } + + i = 0; + { + OPEN_READER(re, &a->gb); + /* now quantify & encode AC coefs */ + for(;;) { + UPDATE_CACHE(re, &a->gb); + GET_RL_VLC(level, run, re, &a->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2); + + if(level == 127){ + break; + } else if(level != 0) { + i += run; + j = scantable[i]; + level= (level*qscale*quant_matrix[j])>>3; + level= (level-1)|1; + level = (level ^ SHOW_SBITS(re, &a->gb, 1)) - SHOW_SBITS(re, &a->gb, 1); + LAST_SKIP_BITS(re, &a->gb, 1); + } else { + /* escape */ + run = SHOW_UBITS(re, &a->gb, 6)+1; LAST_SKIP_BITS(re, &a->gb, 6); + UPDATE_CACHE(re, &a->gb); + level = SHOW_SBITS(re, &a->gb, 8); SKIP_BITS(re, &a->gb, 8); + if (level == -128) { + level = SHOW_UBITS(re, &a->gb, 8) - 256; LAST_SKIP_BITS(re, &a->gb, 8); + } else if (level == 0) { + level = SHOW_UBITS(re, &a->gb, 8) ; LAST_SKIP_BITS(re, &a->gb, 8); + } + i += run; + j = scantable[i]; +/* if(level<0){ + level= -level; + level= (level*qscale*quant_matrix[j])>>4; + level= (level-1)|1; + level= -level; + }else{*/ + level= (level*qscale*quant_matrix[j])>>4; +/* level= (level-1)|1; + }*/ + } + if (i > 63){ + fprintf(stderr, "ac-tex damaged at %d %d\n", a->mb_x, a->mb_y); + return -1; + } + + block[j] = level; + } + CLOSE_READER(re, &a->gb); + } + a->block_last_index[n] = i; + return 0; +} + +static inline int decode_mb(MDECContext *a, DCTELEM block[6][64]){ + int i; + + a->dsp.clear_blocks(block[0]); + + for(i=5; i>=0; i--){ + if( mdec_decode_block_intra(a, block[i], i) < 0) + return -1; + } + return 0; +} + +static inline void idct_put(MDECContext *a, int mb_x, int mb_y){ + DCTELEM (*block)[64]= a->block; + int linesize= a->picture.linesize[0]; + + uint8_t *dest_y = a->picture.data[0] + (mb_y * 16* linesize ) + mb_x * 16; + uint8_t *dest_cb = a->picture.data[1] + (mb_y * 8 * a->picture.linesize[1]) + mb_x * 8; + uint8_t *dest_cr = a->picture.data[2] + (mb_y * 8 * a->picture.linesize[2]) + mb_x * 8; + + a->dsp.idct_put(dest_y , linesize, block[0]); + a->dsp.idct_put(dest_y + 8, linesize, block[1]); + a->dsp.idct_put(dest_y + 8*linesize , linesize, block[2]); + a->dsp.idct_put(dest_y + 8*linesize + 8, linesize, block[3]); + + if(!(a->avctx->flags&CODEC_FLAG_GRAY)){ + a->dsp.idct_put(dest_cb, a->picture.linesize[1], block[4]); + a->dsp.idct_put(dest_cr, a->picture.linesize[2], block[5]); + } +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + MDECContext * const a = avctx->priv_data; + AVFrame *picture = data; + AVFrame * const p= (AVFrame*)&a->picture; + int i; + + *data_size = 0; + + /* special case for last picture */ + if (buf_size == 0) { + return 0; + } + + if(p->data[0]) + avctx->release_buffer(avctx, p); + + p->reference= 0; + if(avctx->get_buffer(avctx, p) < 0){ + fprintf(stderr, "get_buffer() failed\n"); + return -1; + } + p->pict_type= I_TYPE; + p->key_frame= 1; + a->last_dc[0]= + a->last_dc[1]= + a->last_dc[2]= 0; + + a->bitstream_buffer= av_fast_realloc(a->bitstream_buffer, &a->bitstream_buffer_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE); + for(i=0; 2*i<buf_size; i+=2){ + ((uint16_t*)a->bitstream_buffer)[i] = ((uint16_t*)buf)[i+1]; + ((uint16_t*)a->bitstream_buffer)[i+1]= ((uint16_t*)buf)[i ]; + } +// a->dsp.bswap_buf((uint32_t*)a->bitstream_buffer, (uint32_t*)buf, buf_size/4); + init_get_bits(&a->gb, a->bitstream_buffer, buf_size*8); + + a->qscale= get_bits(&a->gb, 16); + a->version= get_bits(&a->gb, 16); + skip_bits(&a->gb, 8*8); + + printf("qscale:%d, version:%d\n", a->qscale, a->version); + + for(a->mb_y=0; a->mb_y<a->mb_height; a->mb_y++){ + for(a->mb_x=0; a->mb_x<a->mb_width; a->mb_x++){ + if( decode_mb(a, a->block) <0) + return -1; + + idct_put(a, a->mb_x, a->mb_y); + } + } + +#if 0 +int i; +printf("%d %d\n", 8*buf_size, get_bits_count(&a->gb)); +for(i=get_bits_count(&a->gb); i<8*buf_size; i++){ + printf("%d", get_bits1(&a->gb)); +} + +for(i=0; i<s->avctx->extradata_size; i++){ + printf("%c\n", ((uint8_t*)s->avctx->extradata)[i]); +} +#endif + +// p->quality= (32 + a->inv_qscale/2)/a->inv_qscale; +// memset(p->qscale_table, p->quality, p->qstride*a->mb_height); + + *picture= *(AVFrame*)&a->picture; + *data_size = sizeof(AVPicture); + + emms_c(); + + return (get_bits_count(&a->gb)+31)/32*4; +} + +static void mdec_common_init(AVCodecContext *avctx){ + MDECContext * const a = avctx->priv_data; + + dsputil_init(&a->dsp, avctx); + + a->mb_width = (avctx->width + 15) / 16; + a->mb_height = (avctx->height + 15) / 16; + + avctx->coded_frame= (AVFrame*)&a->picture; + a->avctx= avctx; +} + +static int decode_init(AVCodecContext *avctx){ + MDECContext * const a = avctx->priv_data; + AVFrame *p= (AVFrame*)&a->picture; + int i; + + mdec_common_init(avctx); + init_vlcs(); + ff_init_scantable(a->dsp.idct_permutation, &a->scantable, ff_zigzag_direct); +/* + for(i=0; i<64; i++){ + int index= ff_zigzag_direct[i]; + a->intra_matrix[i]= 64*ff_mpeg1_default_intra_matrix[index] / a->inv_qscale; + } +*/ + p->qstride= a->mb_width; + p->qscale_table= av_mallocz( p->qstride * a->mb_height); + + return 0; +} + +static int decode_end(AVCodecContext *avctx){ + MDECContext * const a = avctx->priv_data; + + av_freep(&a->bitstream_buffer); + av_freep(&a->picture.qscale_table); + a->bitstream_buffer_size=0; + + avcodec_default_free_buffers(avctx); + + return 0; +} + +AVCodec mdec_decoder = { + "mdec", + CODEC_TYPE_VIDEO, + CODEC_ID_MDEC, + sizeof(MDECContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, +}; + diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 287846f2d4..438e709799 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -819,7 +819,7 @@ static VLC mb_ptype_vlc; static VLC mb_btype_vlc; static VLC mb_pat_vlc; -static void init_vlcs(MpegEncContext *s) +static void init_vlcs() { static int done = 0; @@ -1227,23 +1227,23 @@ static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) return val; } -static inline int decode_dc(MpegEncContext *s, int component) +static inline int decode_dc(GetBitContext *gb, int component) { int code, diff; if (component == 0) { - code = get_vlc2(&s->gb, dc_lum_vlc.table, DC_VLC_BITS, 2); + code = get_vlc2(gb, dc_lum_vlc.table, DC_VLC_BITS, 2); } else { - code = get_vlc2(&s->gb, dc_chroma_vlc.table, DC_VLC_BITS, 2); + code = get_vlc2(gb, dc_chroma_vlc.table, DC_VLC_BITS, 2); } if (code < 0){ - fprintf(stderr, "invalid dc code at %d %d\n", s->mb_x, s->mb_y); + fprintf(stderr, "invalid dc code at\n"); return 0xffff; } if (code == 0) { diff = 0; } else { - diff = get_xbits(&s->gb, code); + diff = get_xbits(gb, code); } return diff; } @@ -1261,7 +1261,7 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s, /* DC coef */ component = (n <= 3 ? 0 : n - 4 + 1); - diff = decode_dc(s, component); + diff = decode_dc(&s->gb, component); if (diff >= 0xffff) return -1; dc = s->last_dc[component]; @@ -1498,7 +1498,7 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, quant_matrix = s->chroma_intra_matrix; component = n - 3; } - diff = decode_dc(s, component); + diff = decode_dc(&s->gb, component); if (diff >= 0xffff) return -1; dc = s->last_dc[component]; @@ -1570,7 +1570,7 @@ static int mpeg_decode_init(AVCodecContext *avctx) s->mpeg_enc_ctx.flags= avctx->flags; common_init(&s->mpeg_enc_ctx); - init_vlcs(&s->mpeg_enc_ctx); + init_vlcs(); s->mpeg_enc_ctx_allocated = 0; s->mpeg_enc_ctx.picture_number = 0; @@ -2477,3 +2477,8 @@ AVCodec mpeg_xvmc_decoder = { }; #endif + +/* this is ugly i know, but the alternative is too make + hundreds of vars global and prefix them with ff_mpeg1_ + which is far uglier. */ +#include "mdec.c" diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index a0f5d4c0b6..23b93b7905 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -648,7 +648,7 @@ typedef struct MpegEncContext { int full_pel[2]; int interlaced_dct; int first_slice; - int first_field; + int first_field; ///< is 1 for the first field of a field picture 0 otherwise /* RTP specific */ /* These are explained on avcodec.h */ @@ -662,8 +662,8 @@ typedef struct MpegEncContext { int (*decode_mb)(struct MpegEncContext *s, DCTELEM block[6][64]); // used by some codecs to avoid a switch() #define SLICE_OK 0 #define SLICE_ERROR -1 -#define SLICE_END -2 //end marker found -#define SLICE_NOEND -3 //no end marker or error found but mb count exceeded +#define SLICE_END -2 ///<end marker found +#define SLICE_NOEND -3 ///<no end marker or error found but mb count exceeded void (*dct_unquantize_mpeg1)(struct MpegEncContext *s, DCTELEM *block/*align 16*/, int n, int qscale); |