2008-07-29 23:38:23 -07:00
|
|
|
/********************************************************************
|
|
|
|
* *
|
|
|
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
|
|
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
|
|
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
|
|
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
|
|
|
* *
|
|
|
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2007 *
|
2009-01-21 16:00:49 -08:00
|
|
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
2008-07-29 23:38:23 -07:00
|
|
|
* *
|
|
|
|
********************************************************************
|
|
|
|
|
|
|
|
function:
|
2009-01-21 16:00:49 -08:00
|
|
|
last mod: $Id: decode.c 15403 2008-10-16 12:44:05Z tterribe $
|
|
|
|
|
2008-07-29 23:38:23 -07:00
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ogg/ogg.h>
|
|
|
|
#include "decint.h"
|
|
|
|
#if defined(OC_DUMP_IMAGES)
|
|
|
|
# include <stdio.h>
|
|
|
|
# include "png.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*No post-processing.*/
|
|
|
|
#define OC_PP_LEVEL_DISABLED (0)
|
|
|
|
/*Keep track of DC qi for each block only.*/
|
|
|
|
#define OC_PP_LEVEL_TRACKDCQI (1)
|
|
|
|
/*Deblock the luma plane.*/
|
|
|
|
#define OC_PP_LEVEL_DEBLOCKY (2)
|
|
|
|
/*Dering the luma plane.*/
|
|
|
|
#define OC_PP_LEVEL_DERINGY (3)
|
|
|
|
/*Stronger luma plane deringing.*/
|
|
|
|
#define OC_PP_LEVEL_SDERINGY (4)
|
|
|
|
/*Deblock the chroma planes.*/
|
|
|
|
#define OC_PP_LEVEL_DEBLOCKC (5)
|
|
|
|
/*Dering the chroma planes.*/
|
|
|
|
#define OC_PP_LEVEL_DERINGC (6)
|
|
|
|
/*Stronger chroma plane deringing.*/
|
|
|
|
#define OC_PP_LEVEL_SDERINGC (7)
|
|
|
|
/*Maximum valid post-processing level.*/
|
|
|
|
#define OC_PP_LEVEL_MAX (7)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*The mode alphabets for the various mode coding schemes.
|
|
|
|
Scheme 0 uses a custom alphabet, which is not stored in this table.*/
|
|
|
|
static const int OC_MODE_ALPHABETS[7][OC_NMODES]={
|
|
|
|
/*Last MV dominates */
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_MV_LAST,OC_MODE_INTER_MV_LAST2,OC_MODE_INTER_MV,
|
|
|
|
OC_MODE_INTER_NOMV,OC_MODE_INTRA,OC_MODE_GOLDEN_NOMV,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_MV_LAST,OC_MODE_INTER_MV_LAST2,OC_MODE_INTER_NOMV,
|
|
|
|
OC_MODE_INTER_MV,OC_MODE_INTRA,OC_MODE_GOLDEN_NOMV,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_MV_LAST,OC_MODE_INTER_MV,OC_MODE_INTER_MV_LAST2,
|
|
|
|
OC_MODE_INTER_NOMV,OC_MODE_INTRA,OC_MODE_GOLDEN_NOMV,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_MV_LAST,OC_MODE_INTER_MV,OC_MODE_INTER_NOMV,
|
|
|
|
OC_MODE_INTER_MV_LAST2,OC_MODE_INTRA,OC_MODE_GOLDEN_NOMV,
|
|
|
|
OC_MODE_GOLDEN_MV,OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
/*No MV dominates.*/
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_NOMV,OC_MODE_INTER_MV_LAST,OC_MODE_INTER_MV_LAST2,
|
|
|
|
OC_MODE_INTER_MV,OC_MODE_INTRA,OC_MODE_GOLDEN_NOMV,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_NOMV,OC_MODE_GOLDEN_NOMV,OC_MODE_INTER_MV_LAST,
|
|
|
|
OC_MODE_INTER_MV_LAST2,OC_MODE_INTER_MV,OC_MODE_INTRA,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
},
|
|
|
|
/*Default ordering.*/
|
|
|
|
{
|
|
|
|
OC_MODE_INTER_NOMV,OC_MODE_INTRA,OC_MODE_INTER_MV,OC_MODE_INTER_MV_LAST,
|
|
|
|
OC_MODE_INTER_MV_LAST2,OC_MODE_GOLDEN_NOMV,OC_MODE_GOLDEN_MV,
|
|
|
|
OC_MODE_INTER_MV_FOUR
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int oc_sb_run_unpack(oggpack_buffer *_opb){
|
|
|
|
long bits;
|
|
|
|
int ret;
|
|
|
|
/*Coding scheme:
|
|
|
|
Codeword Run Length
|
|
|
|
0 1
|
|
|
|
10x 2-3
|
|
|
|
110x 4-5
|
|
|
|
1110xx 6-9
|
|
|
|
11110xxx 10-17
|
|
|
|
111110xxxx 18-33
|
|
|
|
111111xxxxxxxxxxxx 34-4129*/
|
|
|
|
theorapackB_read1(_opb,&bits);
|
|
|
|
if(bits==0)return 1;
|
|
|
|
theorapackB_read(_opb,2,&bits);
|
|
|
|
if((bits&2)==0)return 2+(int)bits;
|
|
|
|
else if((bits&1)==0){
|
|
|
|
theorapackB_read1(_opb,&bits);
|
|
|
|
return 4+(int)bits;
|
|
|
|
}
|
|
|
|
theorapackB_read(_opb,3,&bits);
|
|
|
|
if((bits&4)==0)return 6+(int)bits;
|
|
|
|
else if((bits&2)==0){
|
|
|
|
ret=10+((bits&1)<<2);
|
|
|
|
theorapackB_read(_opb,2,&bits);
|
|
|
|
return ret+(int)bits;
|
|
|
|
}
|
|
|
|
else if((bits&1)==0){
|
|
|
|
theorapackB_read(_opb,4,&bits);
|
|
|
|
return 18+(int)bits;
|
|
|
|
}
|
|
|
|
theorapackB_read(_opb,12,&bits);
|
|
|
|
return 34+(int)bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int oc_block_run_unpack(oggpack_buffer *_opb){
|
|
|
|
long bits;
|
|
|
|
long bits2;
|
|
|
|
/*Coding scheme:
|
|
|
|
Codeword Run Length
|
|
|
|
0x 1-2
|
|
|
|
10x 3-4
|
|
|
|
110x 5-6
|
|
|
|
1110xx 7-10
|
|
|
|
11110xx 11-14
|
|
|
|
11111xxxx 15-30*/
|
|
|
|
theorapackB_read(_opb,2,&bits);
|
|
|
|
if((bits&2)==0)return 1+(int)bits;
|
|
|
|
else if((bits&1)==0){
|
|
|
|
theorapackB_read1(_opb,&bits);
|
|
|
|
return 3+(int)bits;
|
|
|
|
}
|
|
|
|
theorapackB_read(_opb,2,&bits);
|
|
|
|
if((bits&2)==0)return 5+(int)bits;
|
|
|
|
else if((bits&1)==0){
|
|
|
|
theorapackB_read(_opb,2,&bits);
|
|
|
|
return 7+(int)bits;
|
|
|
|
}
|
|
|
|
theorapackB_read(_opb,3,&bits);
|
|
|
|
if((bits&4)==0)return 11+bits;
|
|
|
|
theorapackB_read(_opb,2,&bits2);
|
|
|
|
return 15+((bits&3)<<2)+bits2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int oc_dec_init(oc_dec_ctx *_dec,const th_info *_info,
|
|
|
|
const th_setup_info *_setup){
|
|
|
|
int qti;
|
|
|
|
int pli;
|
|
|
|
int qi;
|
|
|
|
int ret;
|
|
|
|
ret=oc_state_init(&_dec->state,_info);
|
|
|
|
if(ret<0)return ret;
|
|
|
|
oc_huff_trees_copy(_dec->huff_tables,
|
|
|
|
(const oc_huff_node *const *)_setup->huff_tables);
|
|
|
|
for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){
|
|
|
|
_dec->state.dequant_tables[qti][pli]=
|
|
|
|
_dec->state.dequant_table_data[qti][pli];
|
|
|
|
}
|
|
|
|
oc_dequant_tables_init(_dec->state.dequant_tables,_dec->pp_dc_scale,
|
2009-01-21 16:00:49 -08:00
|
|
|
&_setup->qinfo);
|
2008-07-29 23:38:23 -07:00
|
|
|
for(qi=0;qi<64;qi++){
|
|
|
|
int qsum;
|
|
|
|
qsum=0;
|
|
|
|
for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){
|
|
|
|
qsum+=_dec->state.dequant_tables[qti][pli][qi][18]+
|
|
|
|
_dec->state.dequant_tables[qti][pli][qi][19]+
|
|
|
|
_dec->state.dequant_tables[qti][pli][qi][26]+
|
|
|
|
_dec->state.dequant_tables[qti][pli][qi][27]<<(pli==0);
|
|
|
|
}
|
|
|
|
_dec->pp_sharp_mod[qi]=-(qsum>>11);
|
|
|
|
}
|
|
|
|
_dec->dct_tokens=(unsigned char **)oc_calloc_2d(64,
|
|
|
|
_dec->state.nfrags,sizeof(_dec->dct_tokens[0][0]));
|
|
|
|
_dec->extra_bits=(ogg_uint16_t **)oc_calloc_2d(64,
|
|
|
|
_dec->state.nfrags,sizeof(_dec->extra_bits[0][0]));
|
|
|
|
memcpy(_dec->state.loop_filter_limits,_setup->qinfo.loop_filter_limits,
|
|
|
|
sizeof(_dec->state.loop_filter_limits));
|
|
|
|
_dec->pp_level=OC_PP_LEVEL_DISABLED;
|
|
|
|
_dec->dc_qis=NULL;
|
|
|
|
_dec->variances=NULL;
|
|
|
|
_dec->pp_frame_data=NULL;
|
|
|
|
_dec->stripe_cb.ctx=NULL;
|
|
|
|
_dec->stripe_cb.stripe_decoded=NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oc_dec_clear(oc_dec_ctx *_dec){
|
|
|
|
_ogg_free(_dec->pp_frame_data);
|
|
|
|
_ogg_free(_dec->variances);
|
|
|
|
_ogg_free(_dec->dc_qis);
|
|
|
|
oc_free_2d(_dec->extra_bits);
|
|
|
|
oc_free_2d(_dec->dct_tokens);
|
|
|
|
oc_huff_trees_clear(_dec->huff_tables);
|
|
|
|
oc_state_clear(&_dec->state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int oc_dec_frame_header_unpack(oc_dec_ctx *_dec){
|
|
|
|
long val;
|
|
|
|
/*Check to make sure this is a data packet.*/
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
if(val!=0)return TH_EBADPACKET;
|
|
|
|
/*Read in the frame type (I or P).*/
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
_dec->state.frame_type=(int)val;
|
|
|
|
/*Read in the current qi.*/
|
|
|
|
theorapackB_read(&_dec->opb,6,&val);
|
|
|
|
_dec->state.qis[0]=(int)val;
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
if(!val)_dec->state.nqis=1;
|
|
|
|
else{
|
|
|
|
theorapackB_read(&_dec->opb,6,&val);
|
|
|
|
_dec->state.qis[1]=(int)val;
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
if(!val)_dec->state.nqis=2;
|
|
|
|
else{
|
|
|
|
theorapackB_read(&_dec->opb,6,&val);
|
|
|
|
_dec->state.qis[2]=(int)val;
|
|
|
|
_dec->state.nqis=3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(_dec->state.frame_type==OC_INTRA_FRAME){
|
|
|
|
/*Keyframes have 3 unused configuration bits, holdovers from VP3 days.
|
|
|
|
Most of the other unused bits in the VP3 headers were eliminated.
|
|
|
|
I don't know why these remain.*/
|
|
|
|
/* I wanted to eliminate wasted bits, but not all config wiggle room --Monty */
|
|
|
|
theorapackB_read(&_dec->opb,3,&val);
|
|
|
|
if(val!=0)return TH_EIMPL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Mark all fragments as coded and in OC_MODE_INTRA.
|
|
|
|
This also builds up the coded fragment list (in coded order), and clears the
|
|
|
|
uncoded fragment list.
|
|
|
|
It does not update the coded macro block list, as that is not used when
|
|
|
|
decoding INTRA frames.*/
|
|
|
|
static void oc_dec_mark_all_intra(oc_dec_ctx *_dec){
|
|
|
|
oc_sb *sb;
|
|
|
|
oc_sb *sb_end;
|
|
|
|
int pli;
|
|
|
|
int ncoded_fragis;
|
|
|
|
int prev_ncoded_fragis;
|
|
|
|
prev_ncoded_fragis=ncoded_fragis=0;
|
|
|
|
sb=sb_end=_dec->state.sbs;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
const oc_fragment_plane *fplane;
|
|
|
|
fplane=_dec->state.fplanes+pli;
|
|
|
|
sb_end+=fplane->nsbs;
|
|
|
|
for(;sb<sb_end;sb++){
|
|
|
|
int quadi;
|
|
|
|
for(quadi=0;quadi<4;quadi++)if(sb->quad_valid&1<<quadi){
|
|
|
|
int bi;
|
|
|
|
for(bi=0;bi<4;bi++){
|
|
|
|
int fragi;
|
|
|
|
fragi=sb->map[quadi][bi];
|
|
|
|
if(fragi>=0){
|
|
|
|
oc_fragment *frag;
|
|
|
|
frag=_dec->state.frags+fragi;
|
|
|
|
frag->coded=1;
|
|
|
|
frag->mbmode=OC_MODE_INTRA;
|
|
|
|
_dec->state.coded_fragis[ncoded_fragis++]=fragi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_dec->state.ncoded_fragis[pli]=ncoded_fragis-prev_ncoded_fragis;
|
|
|
|
prev_ncoded_fragis=ncoded_fragis;
|
|
|
|
_dec->state.nuncoded_fragis[pli]=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Decodes the bit flags for whether or not each super block is partially coded
|
|
|
|
or not.
|
|
|
|
Return: The number of partially coded super blocks.*/
|
|
|
|
static int oc_dec_partial_sb_flags_unpack(oc_dec_ctx *_dec){
|
|
|
|
oc_sb *sb;
|
|
|
|
oc_sb *sb_end;
|
|
|
|
long val;
|
|
|
|
int flag;
|
|
|
|
int npartial;
|
|
|
|
int run_count;
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
sb=_dec->state.sbs;
|
|
|
|
sb_end=sb+_dec->state.nsbs;
|
|
|
|
run_count=npartial=0;
|
|
|
|
while(sb<sb_end){
|
|
|
|
int full_run;
|
|
|
|
run_count=oc_sb_run_unpack(&_dec->opb);
|
|
|
|
full_run=run_count>=4129;
|
|
|
|
do{
|
|
|
|
sb->coded_partially=flag;
|
|
|
|
sb->coded_fully=0;
|
|
|
|
npartial+=flag;
|
|
|
|
sb++;
|
|
|
|
}
|
|
|
|
while(--run_count>0&&sb<sb_end);
|
|
|
|
if(full_run&&sb<sb_end){
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
}
|
|
|
|
else flag=!flag;
|
|
|
|
}
|
|
|
|
/*TODO: run_count should be 0 here.
|
|
|
|
If it's not, we should issue a warning of some kind.*/
|
|
|
|
return npartial;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Decodes the bit flags for whether or not each non-partially-coded super
|
|
|
|
block is fully coded or not.
|
|
|
|
This function should only be called if there is at least one
|
|
|
|
non-partially-coded super block.
|
|
|
|
Return: The number of partially coded super blocks.*/
|
|
|
|
static void oc_dec_coded_sb_flags_unpack(oc_dec_ctx *_dec){
|
|
|
|
oc_sb *sb;
|
|
|
|
oc_sb *sb_end;
|
|
|
|
long val;
|
|
|
|
int flag;
|
|
|
|
int run_count;
|
|
|
|
sb=_dec->state.sbs;
|
|
|
|
sb_end=sb+_dec->state.nsbs;
|
|
|
|
/*Skip partially coded super blocks.*/
|
|
|
|
for(;sb->coded_partially;sb++);
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
while(sb<sb_end){
|
|
|
|
int full_run;
|
|
|
|
run_count=oc_sb_run_unpack(&_dec->opb);
|
|
|
|
full_run=run_count>=4129;
|
|
|
|
for(;sb<sb_end;sb++){
|
|
|
|
if(sb->coded_partially)continue;
|
|
|
|
if(run_count--<=0)break;
|
|
|
|
sb->coded_fully=flag;
|
|
|
|
}
|
|
|
|
if(full_run&&sb<sb_end){
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
}
|
|
|
|
else flag=!flag;
|
|
|
|
}
|
|
|
|
/*TODO: run_count should be 0 here.
|
|
|
|
If it's not, we should issue a warning of some kind.*/
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oc_dec_coded_flags_unpack(oc_dec_ctx *_dec){
|
|
|
|
oc_sb *sb;
|
|
|
|
oc_sb *sb_end;
|
|
|
|
long val;
|
|
|
|
int npartial;
|
|
|
|
int pli;
|
|
|
|
int flag;
|
|
|
|
int run_count;
|
|
|
|
int ncoded_fragis;
|
|
|
|
int prev_ncoded_fragis;
|
|
|
|
int nuncoded_fragis;
|
|
|
|
int prev_nuncoded_fragis;
|
|
|
|
npartial=oc_dec_partial_sb_flags_unpack(_dec);
|
|
|
|
if(npartial<_dec->state.nsbs)oc_dec_coded_sb_flags_unpack(_dec);
|
|
|
|
if(npartial>0){
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=!(int)val;
|
|
|
|
}
|
|
|
|
else flag=0;
|
|
|
|
run_count=0;
|
|
|
|
prev_ncoded_fragis=ncoded_fragis=prev_nuncoded_fragis=nuncoded_fragis=0;
|
|
|
|
sb=sb_end=_dec->state.sbs;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
const oc_fragment_plane *fplane;
|
|
|
|
fplane=_dec->state.fplanes+pli;
|
|
|
|
sb_end+=fplane->nsbs;
|
|
|
|
for(;sb<sb_end;sb++){
|
|
|
|
int quadi;
|
|
|
|
for(quadi=0;quadi<4;quadi++)if(sb->quad_valid&1<<quadi){
|
|
|
|
int bi;
|
|
|
|
for(bi=0;bi<4;bi++){
|
|
|
|
int fragi;
|
|
|
|
fragi=sb->map[quadi][bi];
|
|
|
|
if(fragi>=0){
|
|
|
|
oc_fragment *frag;
|
|
|
|
frag=_dec->state.frags+fragi;
|
|
|
|
if(sb->coded_fully)frag->coded=1;
|
|
|
|
else if(!sb->coded_partially)frag->coded=0;
|
|
|
|
else{
|
|
|
|
if(run_count<=0){
|
|
|
|
run_count=oc_block_run_unpack(&_dec->opb);
|
|
|
|
flag=!flag;
|
|
|
|
}
|
|
|
|
run_count--;
|
|
|
|
frag->coded=flag;
|
|
|
|
}
|
|
|
|
if(frag->coded)_dec->state.coded_fragis[ncoded_fragis++]=fragi;
|
|
|
|
else *(_dec->state.uncoded_fragis-++nuncoded_fragis)=fragi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_dec->state.ncoded_fragis[pli]=ncoded_fragis-prev_ncoded_fragis;
|
|
|
|
prev_ncoded_fragis=ncoded_fragis;
|
|
|
|
_dec->state.nuncoded_fragis[pli]=nuncoded_fragis-prev_nuncoded_fragis;
|
|
|
|
prev_nuncoded_fragis=nuncoded_fragis;
|
|
|
|
}
|
|
|
|
/*TODO: run_count should be 0 here.
|
|
|
|
If it's not, we should issue a warning of some kind.*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*oc_mode_unpack_func)(oggpack_buffer *_opb);
|
|
|
|
|
|
|
|
static int oc_vlc_mode_unpack(oggpack_buffer *_opb){
|
|
|
|
long val;
|
|
|
|
int i;
|
|
|
|
for(i=0;i<7;i++){
|
|
|
|
theorapackB_read1(_opb,&val);
|
|
|
|
if(!val)break;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int oc_clc_mode_unpack(oggpack_buffer *_opb){
|
|
|
|
long val;
|
|
|
|
theorapackB_read(_opb,3,&val);
|
|
|
|
return (int)val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Unpacks the list of macro block modes for INTER frames.*/
|
|
|
|
static void oc_dec_mb_modes_unpack(oc_dec_ctx *_dec){
|
|
|
|
oc_mode_unpack_func mode_unpack;
|
|
|
|
oc_mb *mb;
|
|
|
|
oc_mb *mb_end;
|
|
|
|
const int *alphabet;
|
2009-01-21 16:00:49 -08:00
|
|
|
long val;
|
2008-07-29 23:38:23 -07:00
|
|
|
int scheme0_alphabet[8];
|
|
|
|
int mode_scheme;
|
|
|
|
theorapackB_read(&_dec->opb,3,&val);
|
|
|
|
mode_scheme=(int)val;
|
|
|
|
if(mode_scheme==0){
|
|
|
|
int mi;
|
|
|
|
/*Just in case, initialize the modes to something.
|
|
|
|
If the bitstream doesn't contain each index exactly once, it's likely
|
|
|
|
corrupt and the rest of the packet is garbage anyway, but this way we
|
|
|
|
won't crash, and we'll decode SOMETHING.*/
|
|
|
|
/*LOOP VECTORIZES.*/
|
|
|
|
for(mi=0;mi<OC_NMODES;mi++)scheme0_alphabet[mi]=OC_MODE_INTER_NOMV;
|
|
|
|
for(mi=0;mi<OC_NMODES;mi++){
|
|
|
|
theorapackB_read(&_dec->opb,3,&val);
|
|
|
|
scheme0_alphabet[val]=OC_MODE_ALPHABETS[6][mi];
|
|
|
|
}
|
|
|
|
alphabet=scheme0_alphabet;
|
2009-01-21 16:00:49 -08:00
|
|
|
}
|
|
|
|
else alphabet=OC_MODE_ALPHABETS[mode_scheme-1];
|
|
|
|
if(mode_scheme==7)mode_unpack=oc_clc_mode_unpack;
|
|
|
|
else mode_unpack=oc_vlc_mode_unpack;
|
2008-07-29 23:38:23 -07:00
|
|
|
mb=_dec->state.mbs;
|
|
|
|
mb_end=mb+_dec->state.nmbs;
|
2009-01-21 16:00:49 -08:00
|
|
|
for(;mb<mb_end;mb++){
|
2008-07-29 23:38:23 -07:00
|
|
|
if(mb->mode!=OC_MODE_INVALID){
|
|
|
|
int bi;
|
|
|
|
for(bi=0;bi<4;bi++){
|
2009-01-21 16:00:49 -08:00
|
|
|
int fragi;
|
|
|
|
fragi=mb->map[0][bi];
|
|
|
|
if(fragi>=0&&_dec->state.frags[fragi].coded)break;
|
2008-07-29 23:38:23 -07:00
|
|
|
}
|
2009-01-21 16:00:49 -08:00
|
|
|
if(bi<4)mb->mode=alphabet[(*mode_unpack)(&_dec->opb)];
|
|
|
|
else mb->mode=OC_MODE_INTER_NOMV;
|
2008-07-29 23:38:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*oc_mv_comp_unpack_func)(oggpack_buffer *_opb);
|
|
|
|
|
|
|
|
static int oc_vlc_mv_comp_unpack(oggpack_buffer *_opb){
|
|
|
|
long bits;
|
|
|
|
int mvsigned[2];
|
|
|
|
theorapackB_read(_opb,3,&bits);
|
|
|
|
switch(bits){
|
|
|
|
case 0:return 0;
|
|
|
|
case 1:return 1;
|
|
|
|
case 2:return -1;
|
|
|
|
case 3:
|
|
|
|
case 4:{
|
|
|
|
mvsigned[0]=(int)(bits-1);
|
|
|
|
theorapackB_read1(_opb,&bits);
|
|
|
|
}break;
|
|
|
|
/*case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:*/
|
|
|
|
default:{
|
|
|
|
mvsigned[0]=1<<bits-3;
|
|
|
|
theorapackB_read(_opb,bits-2,&bits);
|
|
|
|
mvsigned[0]+=(int)(bits>>1);
|
|
|
|
bits&=1;
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
mvsigned[1]=-mvsigned[0];
|
|
|
|
return mvsigned[bits];
|
|
|
|
}
|
|
|
|
|
|
|
|
static int oc_clc_mv_comp_unpack(oggpack_buffer *_opb){
|
|
|
|
long bits;
|
|
|
|
int mvsigned[2];
|
|
|
|
theorapackB_read(_opb,6,&bits);
|
|
|
|
mvsigned[0]=bits>>1;
|
|
|
|
mvsigned[1]=-mvsigned[0];
|
|
|
|
return mvsigned[bits&1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Unpacks the list of motion vectors for INTER frames, and propagtes the macro
|
|
|
|
block modes and motion vectors to the individual fragments.*/
|
|
|
|
static void oc_dec_mv_unpack_and_frag_modes_fill(oc_dec_ctx *_dec){
|
|
|
|
oc_set_chroma_mvs_func set_chroma_mvs;
|
|
|
|
oc_mv_comp_unpack_func mv_comp_unpack;
|
|
|
|
oc_mb *mb;
|
|
|
|
oc_mb *mb_end;
|
|
|
|
const int *map_idxs;
|
|
|
|
long val;
|
|
|
|
int map_nidxs;
|
|
|
|
oc_mv last_mv[2];
|
|
|
|
oc_mv cbmvs[4];
|
|
|
|
set_chroma_mvs=OC_SET_CHROMA_MVS_TABLE[_dec->state.info.pixel_fmt];
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
mv_comp_unpack=val?oc_clc_mv_comp_unpack:oc_vlc_mv_comp_unpack;
|
|
|
|
map_idxs=OC_MB_MAP_IDXS[_dec->state.info.pixel_fmt];
|
|
|
|
map_nidxs=OC_MB_MAP_NIDXS[_dec->state.info.pixel_fmt];
|
|
|
|
memset(last_mv,0,sizeof(last_mv));
|
|
|
|
mb=_dec->state.mbs;
|
|
|
|
mb_end=mb+_dec->state.nmbs;
|
|
|
|
for(;mb<mb_end;mb++)if(mb->mode!=OC_MODE_INVALID){
|
|
|
|
oc_fragment *frag;
|
|
|
|
oc_mv mbmv;
|
|
|
|
int coded[13];
|
|
|
|
int codedi;
|
|
|
|
int ncoded;
|
|
|
|
int mapi;
|
|
|
|
int mapii;
|
|
|
|
int fragi;
|
|
|
|
int mb_mode;
|
|
|
|
/*Search for at least one coded fragment.*/
|
|
|
|
ncoded=mapii=0;
|
|
|
|
do{
|
|
|
|
mapi=map_idxs[mapii];
|
|
|
|
fragi=mb->map[mapi>>2][mapi&3];
|
|
|
|
if(fragi>=0&&_dec->state.frags[fragi].coded)coded[ncoded++]=mapi;
|
|
|
|
}
|
|
|
|
while(++mapii<map_nidxs);
|
|
|
|
if(ncoded<=0)continue;
|
|
|
|
mb_mode=mb->mode;
|
|
|
|
switch(mb_mode){
|
2009-01-21 16:00:49 -08:00
|
|
|
case OC_MODE_INTER_MV_FOUR:{
|
|
|
|
oc_mv lbmvs[4];
|
|
|
|
int bi;
|
|
|
|
/*Mark the tail of the list, so we don't accidentally go past it.*/
|
|
|
|
coded[ncoded]=-1;
|
|
|
|
for(bi=codedi=0;bi<4;bi++){
|
|
|
|
if(coded[codedi]==bi){
|
|
|
|
codedi++;
|
|
|
|
frag=_dec->state.frags+mb->map[0][bi];
|
|
|
|
frag->mbmode=mb_mode;
|
|
|
|
frag->mv[0]=lbmvs[bi][0]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
|
|
|
frag->mv[1]=lbmvs[bi][1]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
|
|
|
}
|
|
|
|
else lbmvs[bi][0]=lbmvs[bi][1]=0;
|
|
|
|
}
|
|
|
|
if(codedi>0){
|
|
|
|
last_mv[1][0]=last_mv[0][0];
|
|
|
|
last_mv[1][1]=last_mv[0][1];
|
|
|
|
last_mv[0][0]=lbmvs[coded[codedi-1]][0];
|
|
|
|
last_mv[0][1]=lbmvs[coded[codedi-1]][1];
|
|
|
|
}
|
|
|
|
if(codedi<ncoded){
|
|
|
|
(*set_chroma_mvs)(cbmvs,(const oc_mv *)lbmvs);
|
|
|
|
for(;codedi<ncoded;codedi++){
|
|
|
|
mapi=coded[codedi];
|
|
|
|
bi=mapi&3;
|
|
|
|
frag=_dec->state.frags+mb->map[mapi>>2][bi];
|
|
|
|
frag->mbmode=mb_mode;
|
|
|
|
frag->mv[0]=cbmvs[bi][0];
|
|
|
|
frag->mv[1]=cbmvs[bi][1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
case OC_MODE_INTER_MV:{
|
|
|
|
last_mv[1][0]=last_mv[0][0];
|
|
|
|
last_mv[1][1]=last_mv[0][1];
|
|
|
|
mbmv[0]=last_mv[0][0]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
|
|
|
mbmv[1]=last_mv[0][1]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
|
|
|
}break;
|
|
|
|
case OC_MODE_INTER_MV_LAST:{
|
2008-07-29 23:38:23 -07:00
|
|
|
mbmv[0]=last_mv[0][0];
|
|
|
|
mbmv[1]=last_mv[0][1];
|
2009-01-21 16:00:49 -08:00
|
|
|
}break;
|
|
|
|
case OC_MODE_INTER_MV_LAST2:{
|
2008-07-29 23:38:23 -07:00
|
|
|
mbmv[0]=last_mv[1][0];
|
|
|
|
mbmv[1]=last_mv[1][1];
|
|
|
|
last_mv[1][0]=last_mv[0][0];
|
|
|
|
last_mv[1][1]=last_mv[0][1];
|
|
|
|
last_mv[0][0]=mbmv[0];
|
|
|
|
last_mv[0][1]=mbmv[1];
|
2009-01-21 16:00:49 -08:00
|
|
|
}break;
|
|
|
|
case OC_MODE_GOLDEN_MV:{
|
2008-07-29 23:38:23 -07:00
|
|
|
mbmv[0]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
|
|
|
mbmv[1]=(signed char)(*mv_comp_unpack)(&_dec->opb);
|
2009-01-21 16:00:49 -08:00
|
|
|
}break;
|
|
|
|
default:mbmv[0]=mbmv[1]=0;break;
|
2008-07-29 23:38:23 -07:00
|
|
|
}
|
|
|
|
/*4MV mode fills in the fragments itself.
|
|
|
|
For all other modes we can use this common code.*/
|
|
|
|
if(mb_mode!=OC_MODE_INTER_MV_FOUR){
|
|
|
|
for(codedi=0;codedi<ncoded;codedi++){
|
|
|
|
mapi=coded[codedi];
|
|
|
|
fragi=mb->map[mapi>>2][mapi&3];
|
|
|
|
frag=_dec->state.frags+fragi;
|
|
|
|
frag->mbmode=mb_mode;
|
|
|
|
frag->mv[0]=mbmv[0];
|
|
|
|
frag->mv[1]=mbmv[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oc_dec_block_qis_unpack(oc_dec_ctx *_dec){
|
|
|
|
oc_fragment *frag;
|
|
|
|
int *coded_fragi;
|
|
|
|
int *coded_fragi_end;
|
|
|
|
int ncoded_fragis;
|
|
|
|
ncoded_fragis=_dec->state.ncoded_fragis[0]+
|
|
|
|
_dec->state.ncoded_fragis[1]+_dec->state.ncoded_fragis[2];
|
|
|
|
if(ncoded_fragis<=0)return;
|
|
|
|
coded_fragi=_dec->state.coded_fragis;
|
|
|
|
coded_fragi_end=coded_fragi+ncoded_fragis;
|
|
|
|
if(_dec->state.nqis==1){
|
|
|
|
/*If this frame has only a single qi value, then just set it in all coded
|
|
|
|
fragments.*/
|
|
|
|
while(coded_fragi<coded_fragi_end){
|
|
|
|
_dec->state.frags[*coded_fragi++].qi=_dec->state.qis[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
long val;
|
|
|
|
int flag;
|
2009-01-21 16:00:49 -08:00
|
|
|
int nqi1;
|
2008-07-29 23:38:23 -07:00
|
|
|
int run_count;
|
|
|
|
/*Otherwise, we decode a qi index for each fragment, using two passes of
|
|
|
|
the same binary RLE scheme used for super-block coded bits.
|
|
|
|
The first pass marks each fragment as having a qii of 0 or greater than
|
|
|
|
0, and the second pass (if necessary), distinguishes between a qii of
|
|
|
|
1 and 2.
|
|
|
|
At first we just store the qii in the fragment.
|
|
|
|
After all the qii's are decoded, we make a final pass to replace them
|
|
|
|
with the corresponding qi's for this frame.*/
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
2009-01-21 16:00:49 -08:00
|
|
|
run_count=nqi1=0;
|
2008-07-29 23:38:23 -07:00
|
|
|
while(coded_fragi<coded_fragi_end){
|
|
|
|
int full_run;
|
|
|
|
run_count=oc_sb_run_unpack(&_dec->opb);
|
|
|
|
full_run=run_count>=4129;
|
|
|
|
do{
|
|
|
|
_dec->state.frags[*coded_fragi++].qi=flag;
|
2009-01-21 16:00:49 -08:00
|
|
|
nqi1+=flag;
|
2008-07-29 23:38:23 -07:00
|
|
|
}
|
|
|
|
while(--run_count>0&&coded_fragi<coded_fragi_end);
|
|
|
|
if(full_run&&coded_fragi<coded_fragi_end){
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
}
|
|
|
|
else flag=!flag;
|
|
|
|
}
|
|
|
|
/*TODO: run_count should be 0 here.
|
|
|
|
If it's not, we should issue a warning of some kind.*/
|
|
|
|
/*If we have 3 different qi's for this frame, and there was at least one
|
|
|
|
fragment with a non-zero qi, make the second pass.*/
|
2009-01-21 16:00:49 -08:00
|
|
|
if(_dec->state.nqis==3&&nqi1>0){
|
2008-07-29 23:38:23 -07:00
|
|
|
/*Skip qii==0 fragments.*/
|
|
|
|
for(coded_fragi=_dec->state.coded_fragis;
|
|
|
|
_dec->state.frags[*coded_fragi].qi==0;coded_fragi++);
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
while(coded_fragi<coded_fragi_end){
|
|
|
|
int full_run;
|
|
|
|
run_count=oc_sb_run_unpack(&_dec->opb);
|
|
|
|
full_run=run_count>=4129;
|
|
|
|
for(;coded_fragi<coded_fragi_end;coded_fragi++){
|
|
|
|
oc_fragment *frag;
|
|
|
|
frag=_dec->state.frags+*coded_fragi;
|
|
|
|
if(frag->qi==0)continue;
|
|
|
|
if(run_count--<=0)break;
|
|
|
|
frag->qi+=flag;
|
|
|
|
}
|
|
|
|
if(full_run&&coded_fragi<coded_fragi_end){
|
|
|
|
theorapackB_read1(&_dec->opb,&val);
|
|
|
|
flag=(int)val;
|
|
|
|
}
|
|
|
|
else flag=!flag;
|
|
|
|
}
|
|
|
|
/*TODO: run_count should be 0 here.
|
|
|
|
If it's not, we should issue a warning of some kind.*/
|
|
|
|
}
|
|
|
|
/*Finally, translate qii's to qi's.*/
|
|
|
|
for(coded_fragi=_dec->state.coded_fragis;coded_fragi<coded_fragi_end;
|
|
|
|
coded_fragi++){
|
|
|
|
frag=_dec->state.frags+*coded_fragi;
|
|
|
|
frag->qi=_dec->state.qis[frag->qi];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*Returns the decoded value of the given token.
|
|
|
|
It CANNOT be called for any of the EOB tokens.
|
|
|
|
_token: The token value to skip.
|
|
|
|
_extra_bits: The extra bits attached to this token.
|
|
|
|
Return: The decoded coefficient value.*/
|
|
|
|
typedef int (*oc_token_dec1val_func)(int _token,int _extra_bits);
|
|
|
|
|
|
|
|
/*Handles zero run tokens.*/
|
|
|
|
static int oc_token_dec1val_zrl(void){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Handles 1, -1, 2 and -2 tokens.*/
|
|
|
|
static int oc_token_dec1val_const(int _token){
|
|
|
|
static const int CONST_VALS[4]={1,-1,2,-2};
|
|
|
|
return CONST_VALS[_token-OC_NDCT_ZRL_TOKEN_MAX];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Handles DCT value tokens category 2.*/
|
|
|
|
static int oc_token_dec1val_cat2(int _token,int _extra_bits){
|
|
|
|
int valsigned[2];
|
|
|
|
valsigned[0]=_token-OC_DCT_VAL_CAT2+3;
|
|
|
|
valsigned[1]=-valsigned[0];
|
|
|
|
return valsigned[_extra_bits];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Handles DCT value tokens categories 3 through 8.*/
|
|
|
|
static int oc_token_dec1val_cati(int _token,int _extra_bits){
|
|
|
|
static const int VAL_CAT_OFFS[6]={
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+3,
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+5,
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+9,
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+17,
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+33,
|
|
|
|
OC_NDCT_VAL_CAT2_SIZE+65
|
|
|
|
};
|
|
|
|
static const int VAL_CAT_MASKS[6]={
|
|
|
|
0x001,0x003,0x007,0x00F,0x01F,0x1FF
|
|
|
|
};
|
|
|
|
static const int VAL_CAT_SHIFTS[6]={1,2,3,4,5,9};
|
|
|
|
int valsigned[2];
|
|
|
|
int cati;
|
|
|
|
cati=_token-OC_NDCT_VAL_CAT2_MAX;
|
|
|
|
valsigned[0]=VAL_CAT_OFFS[cati]+(_extra_bits&VAL_CAT_MASKS[cati]);
|
|
|
|
valsigned[1]=-valsigned[0];
|
|
|
|
return valsigned[_extra_bits>>VAL_CAT_SHIFTS[cati]&1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*A jump table for compute the first coefficient value the given token value
|
|
|
|
represents.*/
|
|
|
|
static const oc_token_dec1val_func OC_TOKEN_DEC1VAL_TABLE[TH_NDCT_TOKENS-
|
|
|
|
OC_NDCT_EOB_TOKEN_MAX]={
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_const,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_const,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_const,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_const,
|
|
|
|
oc_token_dec1val_cat2,
|
|
|
|
oc_token_dec1val_cat2,
|
|
|
|
oc_token_dec1val_cat2,
|
|
|
|
oc_token_dec1val_cat2,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
oc_token_dec1val_cati,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl,
|
|
|
|
(oc_token_dec1val_func)oc_token_dec1val_zrl
|
|
|
|
};
|
|
|
|
|
|
|
|
/*Returns the decoded value of the given token.
|
|
|
|
It CANNOT be called for any of the EOB tokens.
|
|
|
|
_token: The token value to skip.
|
|
|
|
_extra_bits: The extra bits attached to this token.
|
|
|
|
Return: The decoded coefficient value.*/
|
|
|
|
static int oc_dct_token_dec1val(int _token,int _extra_bits){
|
|
|
|
return (*OC_TOKEN_DEC1VAL_TABLE[_token-OC_NDCT_EOB_TOKEN_MAX])(_token,
|
|
|
|
_extra_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Unpacks the DC coefficient tokens.
|
|
|
|
Unlike when unpacking the AC coefficient tokens, we actually need to decode
|
|
|
|
the DC coefficient values now so that we can do DC prediction.
|
|
|
|
_huff_idx: The index of the Huffman table to use for each color plane.
|
|
|
|
_ntoks_left: The number of tokens left to be decoded in each color plane for
|
|
|
|
each coefficient.
|
|
|
|
This is updated as EOB tokens and zero run tokens are decoded.
|
|
|
|
Return: The length of any outstanding EOB run.*/
|
|
|
|
static int oc_dec_dc_coeff_unpack(oc_dec_ctx *_dec,int _huff_idxs[3],
|
|
|
|
int _ntoks_left[3][64]){
|
|
|
|
long val;
|
|
|
|
int *coded_fragi;
|
|
|
|
int *coded_fragi_end;
|
|
|
|
int run_counts[64];
|
|
|
|
int cfi;
|
|
|
|
int eobi;
|
|
|
|
int eobs;
|
|
|
|
int ti;
|
|
|
|
int ebi;
|
|
|
|
int pli;
|
|
|
|
int rli;
|
|
|
|
eobs=0;
|
|
|
|
ti=ebi=0;
|
|
|
|
coded_fragi_end=coded_fragi=_dec->state.coded_fragis;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
coded_fragi_end+=_dec->state.ncoded_fragis[pli];
|
|
|
|
memset(run_counts,0,sizeof(run_counts));
|
|
|
|
_dec->eob_runs[pli][0]=eobs;
|
|
|
|
/*Continue any previous EOB run, if there was one.*/
|
|
|
|
for(eobi=eobs;eobi-->0&&coded_fragi<coded_fragi_end;){
|
|
|
|
_dec->state.frags[*coded_fragi++].dc=0;
|
|
|
|
}
|
|
|
|
cfi=0;
|
|
|
|
while(eobs<_ntoks_left[pli][0]-cfi){
|
|
|
|
int token;
|
|
|
|
int neb;
|
|
|
|
int eb;
|
|
|
|
int skip;
|
|
|
|
cfi+=eobs;
|
|
|
|
run_counts[63]+=eobs;
|
|
|
|
token=oc_huff_token_decode(&_dec->opb,
|
|
|
|
_dec->huff_tables[_huff_idxs[pli]]);
|
|
|
|
_dec->dct_tokens[0][ti++]=(unsigned char)token;
|
|
|
|
neb=OC_DCT_TOKEN_EXTRA_BITS[token];
|
|
|
|
if(neb){
|
|
|
|
theorapackB_read(&_dec->opb,neb,&val);
|
|
|
|
eb=(int)val;
|
|
|
|
_dec->extra_bits[0][ebi++]=(ogg_uint16_t)eb;
|
|
|
|
}
|
|
|
|
else eb=0;
|
|
|
|
skip=oc_dct_token_skip(token,eb);
|
|
|
|
if(skip<0){
|
|
|
|
eobs=eobi=-skip;
|
|
|
|
while(eobi-->0&&coded_fragi<coded_fragi_end){
|
|
|
|
_dec->state.frags[*coded_fragi++].dc=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
run_counts[skip-1]++;
|
|
|
|
cfi++;
|
|
|
|
eobs=0;
|
|
|
|
_dec->state.frags[*coded_fragi++].dc=oc_dct_token_dec1val(token,eb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_dec->ti0[pli][0]=ti;
|
|
|
|
_dec->ebi0[pli][0]=ebi;
|
|
|
|
/*Set the EOB count to the portion of the last EOB run which extends past
|
|
|
|
this coefficient.*/
|
|
|
|
eobs=eobs+cfi-_ntoks_left[pli][0];
|
|
|
|
/*Add the portion of the last EOB which was included in this coefficient to
|
|
|
|
to the longest run length.*/
|
|
|
|
run_counts[63]+=_ntoks_left[pli][0]-cfi;
|
|
|
|
/*And convert the run_counts array to a moment table.*/
|
|
|
|
for(rli=63;rli-->0;)run_counts[rli]+=run_counts[rli+1];
|
|
|
|
/*Finally, subtract off the number of coefficients that have been
|
|
|
|
accounted for by runs started in this coefficient.*/
|
|
|
|
for(rli=64;rli-->0;)_ntoks_left[pli][rli]-=run_counts[rli];
|
|
|
|
}
|
|
|
|
return eobs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Unpacks the AC coefficient tokens.
|
|
|
|
This can completely discard coefficient values while unpacking, and so is
|
|
|
|
somewhat simpler than unpacking the DC coefficient tokens.
|
|
|
|
_huff_idx: The index of the Huffman table to use for each color plane.
|
|
|
|
_ntoks_left: The number of tokens left to be decoded in each color plane for
|
|
|
|
each coefficient.
|
|
|
|
This is updated as EOB tokens and zero run tokens are decoded.
|
|
|
|
_eobs: The length of any outstanding EOB run from previous
|
|
|
|
coefficients.
|
|
|
|
Return: The length of any outstanding EOB run.*/
|
|
|
|
static int oc_dec_ac_coeff_unpack(oc_dec_ctx *_dec,int _zzi,int _huff_idxs[3],
|
|
|
|
int _ntoks_left[3][64],int _eobs){
|
|
|
|
long val;
|
|
|
|
int run_counts[64];
|
|
|
|
int cfi;
|
|
|
|
int ti;
|
|
|
|
int ebi;
|
|
|
|
int pli;
|
|
|
|
int rli;
|
|
|
|
ti=ebi=0;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
memset(run_counts,0,sizeof(run_counts));
|
|
|
|
_dec->eob_runs[pli][_zzi]=_eobs;
|
|
|
|
cfi=0;
|
|
|
|
while(_eobs<_ntoks_left[pli][_zzi]-cfi){
|
|
|
|
int token;
|
|
|
|
int neb;
|
|
|
|
int eb;
|
|
|
|
int skip;
|
|
|
|
cfi+=_eobs;
|
|
|
|
run_counts[63]+=_eobs;
|
|
|
|
token=oc_huff_token_decode(&_dec->opb,
|
|
|
|
_dec->huff_tables[_huff_idxs[pli]]);
|
|
|
|
_dec->dct_tokens[_zzi][ti++]=(unsigned char)token;
|
|
|
|
neb=OC_DCT_TOKEN_EXTRA_BITS[token];
|
|
|
|
if(neb){
|
|
|
|
theorapackB_read(&_dec->opb,neb,&val);
|
|
|
|
eb=(int)val;
|
|
|
|
_dec->extra_bits[_zzi][ebi++]=(ogg_uint16_t)eb;
|
|
|
|
}
|
|
|
|
else eb=0;
|
|
|
|
skip=oc_dct_token_skip(token,eb);
|
|
|
|
if(skip<0)_eobs=-skip;
|
|
|
|
else{
|
|
|
|
run_counts[skip-1]++;
|
|
|
|
cfi++;
|
|
|
|
_eobs=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_dec->ti0[pli][_zzi]=ti;
|
|
|
|
_dec->ebi0[pli][_zzi]=ebi;
|
|
|
|
/*Set the EOB count to the portion of the last EOB run which extends past
|
|
|
|
this coefficient.*/
|
|
|
|
_eobs=_eobs+cfi-_ntoks_left[pli][_zzi];
|
|
|
|
/*Add the portion of the last EOB which was included in this coefficient to
|
|
|
|
to the longest run length.*/
|
|
|
|
run_counts[63]+=_ntoks_left[pli][_zzi]-cfi;
|
|
|
|
/*And convert the run_counts array to a moment table.*/
|
|
|
|
for(rli=63;rli-->0;)run_counts[rli]+=run_counts[rli+1];
|
|
|
|
/*Finally, subtract off the number of coefficients that have been
|
|
|
|
accounted for by runs started in this coefficient.*/
|
|
|
|
for(rli=64-_zzi;rli-->0;)_ntoks_left[pli][_zzi+rli]-=run_counts[rli];
|
|
|
|
}
|
|
|
|
return _eobs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Tokens describing the DCT coefficients that belong to each fragment are
|
|
|
|
stored in the bitstream grouped by coefficient, not by fragment.
|
|
|
|
|
|
|
|
This means that we either decode all the tokens in order, building up a
|
|
|
|
separate coefficient list for each fragment as we go, and then go back and
|
|
|
|
do the iDCT on each fragment, or we have to create separate lists of tokens
|
|
|
|
for each coefficient, so that we can pull the next token required off the
|
|
|
|
head of the appropriate list when decoding a specific fragment.
|
|
|
|
|
|
|
|
The former was VP3's choice, and it meant 2*w*h extra storage for all the
|
|
|
|
decoded coefficient values.
|
|
|
|
|
|
|
|
We take the second option, which lets us store just one or three bytes per
|
|
|
|
token (generally far fewer than the number of coefficients, due to EOB
|
|
|
|
tokens and zero runs), and which requires us to only maintain a counter for
|
|
|
|
each of the 64 coefficients, instead of a counter for every fragment to
|
|
|
|
determine where the next token goes.
|
|
|
|
|
|
|
|
Actually, we use 3 counters per coefficient, one for each color plane, so we
|
|
|
|
can decode all color planes simultaneously.
|
|
|
|
|
|
|
|
This lets color conversion, etc., be done as soon as a full MCU (one or
|
|
|
|
two super block rows) is decoded, while the image data is still in cache.*/
|
|
|
|
|
|
|
|
static void oc_dec_residual_tokens_unpack(oc_dec_ctx *_dec){
|
|
|
|
static const int OC_HUFF_LIST_MAX[5]={1,6,15,28,64};
|
|
|
|
long val;
|
|
|
|
int ntoks_left[3][64];
|
|
|
|
int huff_idxs[3];
|
|
|
|
int pli;
|
|
|
|
int zzi;
|
|
|
|
int hgi;
|
|
|
|
int huffi_y;
|
|
|
|
int huffi_c;
|
|
|
|
int eobs;
|
|
|
|
for(pli=0;pli<3;pli++)for(zzi=0;zzi<64;zzi++){
|
|
|
|
ntoks_left[pli][zzi]=_dec->state.ncoded_fragis[pli];
|
|
|
|
}
|
|
|
|
theorapackB_read(&_dec->opb,4,&val);
|
|
|
|
huffi_y=(int)val;
|
|
|
|
theorapackB_read(&_dec->opb,4,&val);
|
|
|
|
huffi_c=(int)val;
|
|
|
|
huff_idxs[0]=huffi_y;
|
|
|
|
huff_idxs[1]=huff_idxs[2]=huffi_c;
|
|
|
|
_dec->eob_runs[0][0]=0;
|
|
|
|
eobs=oc_dec_dc_coeff_unpack(_dec,huff_idxs,ntoks_left);
|
|
|
|
theorapackB_read(&_dec->opb,4,&val);
|
|
|
|
huffi_y=(int)val;
|
|
|
|
theorapackB_read(&_dec->opb,4,&val);
|
|
|
|
huffi_c=(int)val;
|
|
|
|
zzi=1;
|
|
|
|
for(hgi=1;hgi<5;hgi++){
|
|
|
|
huff_idxs[0]=huffi_y+(hgi<<4);
|
|
|
|
huff_idxs[1]=huff_idxs[2]=huffi_c+(hgi<<4);
|
|
|
|
for(;zzi<OC_HUFF_LIST_MAX[hgi];zzi++){
|
|
|
|
eobs=oc_dec_ac_coeff_unpack(_dec,zzi,huff_idxs,ntoks_left,eobs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*TODO: eobs should be exactly zero, or 4096 or greater.
|
|
|
|
The second case occurs when an EOB run of size zero is encountered, which
|
|
|
|
gets treated as an infinite EOB run (where infinity is INT_MAX).
|
|
|
|
If neither of these conditions holds, then a warning should be issued.*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*Expands a single token into the given coefficient list.
|
|
|
|
This fills in the zeros for zero runs as well as coefficient values, and
|
|
|
|
updates the index of the current coefficient.
|
|
|
|
It CANNOT be called for any of the EOB tokens.
|
|
|
|
_token: The token value to expand.
|
|
|
|
_extra_bits: The extra bits associated with the token.
|
|
|
|
_dct_coeffs: The current list of coefficients, in zig-zag order.
|
|
|
|
_zzi: A pointer to the zig-zag index of the next coefficient to write
|
|
|
|
to.
|
|
|
|
This is updated before the function returns.*/
|
|
|
|
typedef void (*oc_token_expand_func)(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi);
|
|
|
|
|
|
|
|
/*Expands a zero run token.*/
|
|
|
|
static void oc_token_expand_zrl(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
int zzi;
|
|
|
|
zzi=*_zzi;
|
|
|
|
do _dct_coeffs[zzi++]=0;
|
|
|
|
while(_extra_bits-->0);
|
|
|
|
*_zzi=zzi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Expands a constant, single-value token.*/
|
|
|
|
static void oc_token_expand_const(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
_dct_coeffs[(*_zzi)++]=(ogg_int16_t)oc_token_dec1val_const(_token);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Expands category 2 single-valued tokens.*/
|
|
|
|
static void oc_token_expand_cat2(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
_dct_coeffs[(*_zzi)++]=
|
|
|
|
(ogg_int16_t)oc_token_dec1val_cat2(_token,_extra_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Expands category 3 through 8 single-valued tokens.*/
|
|
|
|
static void oc_token_expand_cati(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
_dct_coeffs[(*_zzi)++]=
|
|
|
|
(ogg_int16_t)oc_token_dec1val_cati(_token,_extra_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Expands a category 1a zero run/value combo token.*/
|
|
|
|
static void oc_token_expand_run_cat1a(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
int zzi;
|
|
|
|
int rl;
|
|
|
|
zzi=*_zzi;
|
|
|
|
/*LOOP VECTORIZES.*/
|
|
|
|
for(rl=_token-OC_DCT_RUN_CAT1A+1;rl-->0;)_dct_coeffs[zzi++]=0;
|
|
|
|
_dct_coeffs[zzi++]=(ogg_int16_t)(1-(_extra_bits<<1));
|
|
|
|
*_zzi=zzi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Expands all other zero run/value combo tokens.*/
|
|
|
|
static void oc_token_expand_run(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t _dct_coeffs[128],int *_zzi){
|
|
|
|
static const int NZEROS_ADJUST[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
6,10,1,2
|
|
|
|
};
|
|
|
|
static const int NZEROS_MASK[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
3,7,0,1
|
|
|
|
};
|
|
|
|
static const int VALUE_SHIFT[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
0,0,0,1
|
|
|
|
};
|
|
|
|
static const int VALUE_MASK[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
0,0,1,1
|
|
|
|
};
|
|
|
|
static const int VALUE_ADJUST[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
1,1,2,2
|
|
|
|
};
|
|
|
|
static const int SIGN_SHIFT[OC_NDCT_RUN_MAX-OC_DCT_RUN_CAT1B]={
|
|
|
|
2,3,1,2
|
|
|
|
};
|
|
|
|
int valsigned[2];
|
|
|
|
int zzi;
|
|
|
|
int rl;
|
|
|
|
_token-=OC_DCT_RUN_CAT1B;
|
|
|
|
rl=(_extra_bits&NZEROS_MASK[_token])+NZEROS_ADJUST[_token];
|
|
|
|
zzi=*_zzi;
|
|
|
|
/*LOOP VECTORIZES.*/
|
|
|
|
while(rl-->0)_dct_coeffs[zzi++]=0;
|
|
|
|
valsigned[0]=VALUE_ADJUST[_token]+
|
|
|
|
(_extra_bits>>VALUE_SHIFT[_token]&VALUE_MASK[_token]);
|
|
|
|
valsigned[1]=-valsigned[0];
|
|
|
|
_dct_coeffs[zzi++]=(ogg_int16_t)valsigned[
|
|
|
|
_extra_bits>>SIGN_SHIFT[_token]];
|
|
|
|
*_zzi=zzi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*A jump table for expanding token values into coefficient values.
|
|
|
|
This reduces all the conditional branches, etc., needed to parse these token
|
|
|
|
values down to one indirect jump.*/
|
|
|
|
static const oc_token_expand_func OC_TOKEN_EXPAND_TABLE[TH_NDCT_TOKENS-
|
|
|
|
OC_NDCT_EOB_TOKEN_MAX]={
|
|
|
|
oc_token_expand_zrl,
|
|
|
|
oc_token_expand_zrl,
|
|
|
|
oc_token_expand_const,
|
|
|
|
oc_token_expand_const,
|
|
|
|
oc_token_expand_const,
|
|
|
|
oc_token_expand_const,
|
|
|
|
oc_token_expand_cat2,
|
|
|
|
oc_token_expand_cat2,
|
|
|
|
oc_token_expand_cat2,
|
|
|
|
oc_token_expand_cat2,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_cati,
|
|
|
|
oc_token_expand_run_cat1a,
|
|
|
|
oc_token_expand_run_cat1a,
|
|
|
|
oc_token_expand_run_cat1a,
|
|
|
|
oc_token_expand_run_cat1a,
|
|
|
|
oc_token_expand_run_cat1a,
|
|
|
|
oc_token_expand_run,
|
|
|
|
oc_token_expand_run,
|
|
|
|
oc_token_expand_run,
|
|
|
|
oc_token_expand_run
|
|
|
|
};
|
|
|
|
|
|
|
|
/*Expands a single token into the given coefficient list.
|
|
|
|
This fills in the zeros for zero runs as well as coefficient values, and
|
|
|
|
updates the index of the current coefficient.
|
|
|
|
It CANNOT be called for any of the EOB tokens.
|
|
|
|
_token: The token value to expand.
|
|
|
|
_extra_bits: The extra bits associated with the token.
|
|
|
|
_dct_coeffs: The current list of coefficients, in zig-zag order.
|
|
|
|
_zzi: A pointer to the zig-zag index of the next coefficient to write
|
|
|
|
to.
|
|
|
|
This is updated before the function returns.*/
|
|
|
|
static void oc_dct_token_expand(int _token,int _extra_bits,
|
|
|
|
ogg_int16_t *_dct_coeffs,int *_zzi){
|
|
|
|
(*OC_TOKEN_EXPAND_TABLE[_token-OC_NDCT_EOB_TOKEN_MAX])(_token,
|
|
|
|
_extra_bits,_dct_coeffs,_zzi);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int oc_dec_postprocess_init(oc_dec_ctx *_dec){
|
|
|
|
/*pp_level 0: disabled; free any memory used and return*/
|
|
|
|
if(_dec->pp_level<=OC_PP_LEVEL_DISABLED){
|
|
|
|
if(_dec->dc_qis!=NULL){
|
|
|
|
_ogg_free(_dec->dc_qis);
|
|
|
|
_dec->dc_qis=NULL;
|
|
|
|
_ogg_free(_dec->variances);
|
|
|
|
_dec->variances=NULL;
|
|
|
|
_ogg_free(_dec->pp_frame_data);
|
|
|
|
_dec->pp_frame_data=NULL;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(_dec->dc_qis==NULL){
|
|
|
|
/*If we haven't been tracking DC quantization indices, there's no point in
|
|
|
|
starting now.*/
|
|
|
|
if(_dec->state.frame_type!=OC_INTRA_FRAME)return 1;
|
|
|
|
_dec->dc_qis=(unsigned char *)_ogg_malloc(
|
|
|
|
_dec->state.nfrags*sizeof(_dec->dc_qis[0]));
|
|
|
|
memset(_dec->dc_qis,_dec->state.qis[0],_dec->state.nfrags);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
int *coded_fragi;
|
|
|
|
int *coded_fragi_end;
|
|
|
|
unsigned char qi0;
|
|
|
|
/*Update the DC quantization index of each coded block.*/
|
|
|
|
qi0=(unsigned char)_dec->state.qis[0];
|
|
|
|
coded_fragi_end=_dec->state.coded_fragis+_dec->state.ncoded_fragis[0]+
|
|
|
|
_dec->state.ncoded_fragis[1]+_dec->state.ncoded_fragis[2];
|
|
|
|
for(coded_fragi=_dec->state.coded_fragis;coded_fragi<coded_fragi_end;
|
|
|
|
coded_fragi++){
|
|
|
|
_dec->dc_qis[*coded_fragi]=qi0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*pp_level 1: Stop after updating DC quantization indices.*/
|
|
|
|
if(_dec->pp_level<=OC_PP_LEVEL_TRACKDCQI){
|
|
|
|
if(_dec->variances!=NULL){
|
|
|
|
_ogg_free(_dec->variances);
|
|
|
|
_dec->variances=NULL;
|
|
|
|
_ogg_free(_dec->pp_frame_data);
|
|
|
|
_dec->pp_frame_data=NULL;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(_dec->variances==NULL||
|
|
|
|
_dec->pp_frame_has_chroma!=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC)){
|
|
|
|
size_t frame_sz;
|
|
|
|
frame_sz=_dec->state.info.frame_width*_dec->state.info.frame_height;
|
|
|
|
if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
|
|
|
|
_dec->variances=(int *)_ogg_realloc(_dec->variances,
|
|
|
|
_dec->state.fplanes[0].nfrags*sizeof(_dec->variances[0]));
|
2009-01-21 16:00:49 -08:00
|
|
|
_dec->pp_frame_data=(unsigned char *)_ogg_realloc(
|
2008-07-29 23:38:23 -07:00
|
|
|
_dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
|
|
|
|
_dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
|
|
|
|
_dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
|
|
|
|
_dec->pp_frame_buf[0].stride=-_dec->pp_frame_buf[0].width;
|
|
|
|
_dec->pp_frame_buf[0].data=_dec->pp_frame_data+
|
|
|
|
(1-_dec->pp_frame_buf[0].height)*_dec->pp_frame_buf[0].stride;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
size_t y_sz;
|
|
|
|
size_t c_sz;
|
|
|
|
int c_w;
|
|
|
|
int c_h;
|
|
|
|
_dec->variances=(int *)_ogg_realloc(_dec->variances,
|
|
|
|
_dec->state.nfrags*sizeof(_dec->variances[0]));
|
|
|
|
y_sz=frame_sz;
|
|
|
|
c_w=_dec->state.info.frame_width>>!(_dec->state.info.pixel_fmt&1);
|
|
|
|
c_h=_dec->state.info.frame_height>>!(_dec->state.info.pixel_fmt&2);
|
|
|
|
c_sz=c_w*c_h;
|
|
|
|
frame_sz+=c_sz<<1;
|
2009-01-21 16:00:49 -08:00
|
|
|
_dec->pp_frame_data=(unsigned char *)_ogg_realloc(
|
2008-07-29 23:38:23 -07:00
|
|
|
_dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
|
|
|
|
_dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
|
|
|
|
_dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
|
|
|
|
_dec->pp_frame_buf[0].stride=_dec->pp_frame_buf[0].width;
|
|
|
|
_dec->pp_frame_buf[0].data=_dec->pp_frame_data;
|
|
|
|
_dec->pp_frame_buf[1].width=c_w;
|
|
|
|
_dec->pp_frame_buf[1].height=c_h;
|
|
|
|
_dec->pp_frame_buf[1].stride=_dec->pp_frame_buf[1].width;
|
|
|
|
_dec->pp_frame_buf[1].data=_dec->pp_frame_buf[0].data+y_sz;
|
|
|
|
_dec->pp_frame_buf[2].width=c_w;
|
|
|
|
_dec->pp_frame_buf[2].height=c_h;
|
|
|
|
_dec->pp_frame_buf[2].stride=_dec->pp_frame_buf[2].width;
|
|
|
|
_dec->pp_frame_buf[2].data=_dec->pp_frame_buf[1].data+c_sz;
|
|
|
|
oc_ycbcr_buffer_flip(_dec->pp_frame_buf,_dec->pp_frame_buf);
|
|
|
|
}
|
|
|
|
_dec->pp_frame_has_chroma=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC);
|
|
|
|
}
|
|
|
|
/*If we're not processing chroma, copy the reference frame's chroma planes.*/
|
|
|
|
if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
|
|
|
|
memcpy(_dec->pp_frame_buf+1,
|
|
|
|
_dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]+1,
|
|
|
|
sizeof(_dec->pp_frame_buf[1])*2);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct{
|
|
|
|
int ti[3][64];
|
|
|
|
int ebi[3][64];
|
|
|
|
int eob_runs[3][64];
|
|
|
|
int bounding_values[256];
|
|
|
|
int *coded_fragis[3];
|
|
|
|
int *uncoded_fragis[3];
|
|
|
|
int fragy0[3];
|
|
|
|
int fragy_end[3];
|
|
|
|
int ncoded_fragis[3];
|
|
|
|
int nuncoded_fragis[3];
|
|
|
|
int pred_last[3][3];
|
|
|
|
int mcu_nvfrags;
|
|
|
|
int loop_filter;
|
|
|
|
int pp_level;
|
|
|
|
}oc_dec_pipeline_state;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*Initialize the main decoding pipeline.*/
|
|
|
|
static void oc_dec_pipeline_init(oc_dec_ctx *_dec,
|
|
|
|
oc_dec_pipeline_state *_pipe){
|
|
|
|
int *coded_fragi_end;
|
|
|
|
int *uncoded_fragi_end;
|
|
|
|
int pli;
|
|
|
|
/*If chroma is sub-sampled in the vertical direction, we have to decode two
|
|
|
|
super block rows of Y' for each super block row of Cb and Cr.*/
|
|
|
|
_pipe->mcu_nvfrags=4<<!(_dec->state.info.pixel_fmt&2);
|
|
|
|
/*Initialize the token and extra bits indices for each plane and
|
|
|
|
coefficient.*/
|
|
|
|
memset(_pipe->ti[0],0,sizeof(_pipe->ti[0]));
|
|
|
|
memset(_pipe->ebi[0],0,sizeof(_pipe->ebi[0]));
|
|
|
|
for(pli=1;pli<3;pli++){
|
|
|
|
memcpy(_pipe->ti[pli],_dec->ti0[pli-1],sizeof(_pipe->ti[0]));
|
|
|
|
memcpy(_pipe->ebi[pli],_dec->ebi0[pli-1],sizeof(_pipe->ebi[0]));
|
|
|
|
}
|
|
|
|
/*Also copy over the initial the EOB run counts.*/
|
|
|
|
memcpy(_pipe->eob_runs,_dec->eob_runs,sizeof(_pipe->eob_runs));
|
|
|
|
/*Set up per-plane pointers to the coded and uncoded fragments lists.*/
|
|
|
|
coded_fragi_end=_dec->state.coded_fragis;
|
|
|
|
uncoded_fragi_end=_dec->state.uncoded_fragis;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
_pipe->coded_fragis[pli]=coded_fragi_end;
|
|
|
|
_pipe->uncoded_fragis[pli]=uncoded_fragi_end;
|
|
|
|
coded_fragi_end+=_dec->state.ncoded_fragis[pli];
|
|
|
|
uncoded_fragi_end-=_dec->state.nuncoded_fragis[pli];
|
|
|
|
}
|
|
|
|
/*Set the previous DC predictor to 0 for all color planes and frame types.*/
|
|
|
|
memset(_pipe->pred_last,0,sizeof(_pipe->pred_last));
|
|
|
|
/*Initialize the bounding value array for the loop filter.*/
|
|
|
|
_pipe->loop_filter=!oc_state_loop_filter_init(&_dec->state,
|
|
|
|
_pipe->bounding_values);
|
|
|
|
/*Initialize any buffers needed for post-processing.
|
|
|
|
We also save the current post-processing level, to guard against the user
|
|
|
|
changing it from a callback.*/
|
|
|
|
if(!oc_dec_postprocess_init(_dec))_pipe->pp_level=_dec->pp_level;
|
|
|
|
/*If we don't have enough information to post-process, disable it, regardless
|
|
|
|
of the user-requested level.*/
|
|
|
|
else{
|
|
|
|
_pipe->pp_level=OC_PP_LEVEL_DISABLED;
|
|
|
|
memcpy(_dec->pp_frame_buf,
|
|
|
|
_dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]],
|
|
|
|
sizeof(_dec->pp_frame_buf[0])*3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Undo the DC prediction in a single plane of an MCU (one or two super block
|
|
|
|
rows).
|
|
|
|
As a side effect, the number of coded and uncoded fragments in this plane of
|
|
|
|
the MCU is also computed.*/
|
|
|
|
static void oc_dec_dc_unpredict_mcu_plane(oc_dec_ctx *_dec,
|
|
|
|
oc_dec_pipeline_state *_pipe,int _pli){
|
|
|
|
/*Undo the DC prediction.*/
|
|
|
|
oc_fragment_plane *fplane;
|
|
|
|
oc_fragment *frag;
|
|
|
|
int *pred_last;
|
|
|
|
int ncoded_fragis;
|
|
|
|
int fragx;
|
|
|
|
int fragy;
|
|
|
|
int fragy0;
|
|
|
|
int fragy_end;
|
|
|
|
/*Compute the first and last fragment row of the current MCU for this
|
|
|
|
plane.*/
|
|
|
|
fplane=_dec->state.fplanes+_pli;
|
|
|
|
fragy0=_pipe->fragy0[_pli];
|
|
|
|
fragy_end=_pipe->fragy_end[_pli];
|
|
|
|
frag=_dec->state.frags+fplane->froffset+(fragy0*fplane->nhfrags);
|
|
|
|
ncoded_fragis=0;
|
|
|
|
pred_last=_pipe->pred_last[_pli];
|
|
|
|
for(fragy=fragy0;fragy<fragy_end;fragy++){
|
|
|
|
for(fragx=0;fragx<fplane->nhfrags;fragx++,frag++){
|
|
|
|
if(!frag->coded)continue;
|
|
|
|
pred_last[OC_FRAME_FOR_MODE[frag->mbmode]]=frag->dc+=
|
|
|
|
oc_frag_pred_dc(frag,fplane,fragx,fragy,pred_last);
|
|
|
|
ncoded_fragis++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_pipe->ncoded_fragis[_pli]=ncoded_fragis;
|
|
|
|
/*Also save the number of uncoded fragments so we know how many to copy.*/
|
|
|
|
_pipe->nuncoded_fragis[_pli]=
|
|
|
|
(fragy_end-fragy0)*fplane->nhfrags-ncoded_fragis;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Reconstructs all coded fragments in a single MCU (one or two super block
|
|
|
|
rows).
|
|
|
|
This requires that each coded fragment have a proper macro block mode and
|
|
|
|
motion vector (if not in INTRA mode), and have it's DC value decoded, with
|
|
|
|
the DC prediction process reversed, and the number of coded and uncoded
|
|
|
|
fragments in this plane of the MCU be counted.
|
|
|
|
The token lists for each color plane and coefficient should also be filled
|
|
|
|
in, along with initial token offsets, extra bits offsets, and EOB run
|
|
|
|
counts.*/
|
|
|
|
static void oc_dec_frags_recon_mcu_plane(oc_dec_ctx *_dec,
|
|
|
|
oc_dec_pipeline_state *_pipe,int _pli){
|
|
|
|
/*Decode the AC coefficients.*/
|
|
|
|
int *ti;
|
|
|
|
int *ebi;
|
|
|
|
int *eob_runs;
|
|
|
|
int *coded_fragi;
|
|
|
|
int *coded_fragi_end;
|
|
|
|
ti=_pipe->ti[_pli];
|
|
|
|
ebi=_pipe->ebi[_pli];
|
|
|
|
eob_runs=_pipe->eob_runs[_pli];
|
|
|
|
coded_fragi_end=coded_fragi=_pipe->coded_fragis[_pli];
|
|
|
|
coded_fragi_end+=_pipe->ncoded_fragis[_pli];
|
|
|
|
for(;coded_fragi<coded_fragi_end;coded_fragi++){
|
|
|
|
oc_fragment *frag;
|
|
|
|
oc_quant_table *iquants;
|
|
|
|
/*This array is made one bigger than necessary so that an invalid zero
|
|
|
|
run cannot cause a buffer overflow.
|
|
|
|
The inverse zig-zag mapping sends all out of range indices to the last
|
|
|
|
entry of this array, where they are ignored.*/
|
|
|
|
ogg_int16_t dct_coeffs[128];
|
|
|
|
int fragi;
|
|
|
|
int zzi;
|
|
|
|
int last_zzi;
|
|
|
|
fragi=*coded_fragi;
|
|
|
|
frag=_dec->state.frags+fragi;
|
|
|
|
for(zzi=0;zzi<64;){
|
|
|
|
int token;
|
|
|
|
int eb;
|
|
|
|
last_zzi=zzi;
|
|
|
|
if(eob_runs[zzi]){
|
|
|
|
eob_runs[zzi]--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
int ebflag;
|
|
|
|
token=_dec->dct_tokens[zzi][ti[zzi]++];
|
|
|
|
ebflag=OC_DCT_TOKEN_EXTRA_BITS[token]!=0;
|
|
|
|
eb=_dec->extra_bits[zzi][ebi[zzi]]&-ebflag;
|
|
|
|
ebi[zzi]+=ebflag;
|
|
|
|
if(token<OC_NDCT_EOB_TOKEN_MAX){
|
|
|
|
eob_runs[zzi]=-oc_dct_token_skip(token,eb);
|
|
|
|
}
|
|
|
|
else oc_dct_token_expand(token,eb,dct_coeffs,&zzi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*TODO: zzi should be exactly 64 here.
|
|
|
|
If it's not, we should report some kind of warning.*/
|
|
|
|
zzi=OC_MINI(zzi,64);
|
|
|
|
dct_coeffs[0]=(ogg_int16_t)frag->dc;
|
|
|
|
iquants=_dec->state.dequant_tables[frag->mbmode!=OC_MODE_INTRA][_pli];
|
|
|
|
/*last_zzi is always initialized.
|
|
|
|
If your compiler thinks otherwise, it is dumb.*/
|
|
|
|
oc_state_frag_recon(&_dec->state,frag,_pli,dct_coeffs,last_zzi,zzi,
|
|
|
|
iquants[_dec->state.qis[0]][0],iquants[frag->qi]);
|
|
|
|
}
|
|
|
|
_pipe->coded_fragis[_pli]=coded_fragi;
|
|
|
|
/*Right now the reconstructed MCU has only the coded blocks in it.*/
|
|
|
|
/*TODO: We make the decision here to always copy the uncoded blocks into it
|
|
|
|
from the reference frame.
|
|
|
|
We could also copy the coded blocks back over the reference frame, if we
|
|
|
|
wait for an additional MCU to be decoded, which might be faster if only a
|
|
|
|
small number of blocks are coded.
|
|
|
|
However, this introduces more latency, creating a larger cache footprint.
|
|
|
|
It's unknown which decision is better, but this one results in simpler
|
|
|
|
code, and the hard case (high bitrate, high resolution) is handled
|
|
|
|
correctly.*/
|
|
|
|
/*Copy the uncoded blocks from the previous reference frame.*/
|
|
|
|
_pipe->uncoded_fragis[_pli]-=_pipe->nuncoded_fragis[_pli];
|
|
|
|
oc_state_frag_copy(&_dec->state,_pipe->uncoded_fragis[_pli],
|
|
|
|
_pipe->nuncoded_fragis[_pli],OC_FRAME_SELF,OC_FRAME_PREV,_pli);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Filter a horizontal block edge.*/
|
|
|
|
static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride,
|
|
|
|
const unsigned char *_src,int _src_ystride,int _qstep,int _flimit,
|
|
|
|
int *_variance0,int *_variance1){
|
|
|
|
unsigned char *rdst;
|
|
|
|
const unsigned char *rsrc;
|
|
|
|
unsigned char *cdst;
|
|
|
|
const unsigned char *csrc;
|
|
|
|
int r[10];
|
|
|
|
int sum0;
|
|
|
|
int sum1;
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
rdst=_dst;
|
|
|
|
rsrc=_src;
|
|
|
|
for(bx=0;bx<8;bx++){
|
|
|
|
cdst=rdst;
|
|
|
|
csrc=rsrc;
|
|
|
|
for(by=0;by<10;by++){
|
|
|
|
r[by]=*csrc;
|
|
|
|
csrc+=_src_ystride;
|
|
|
|
}
|
|
|
|
sum0=sum1=0;
|
|
|
|
for(by=0;by<4;by++){
|
|
|
|
sum0+=abs(r[by+1]-r[by]);
|
|
|
|
sum1+=abs(r[by+5]-r[by+6]);
|
|
|
|
}
|
|
|
|
*_variance0+=OC_MINI(255,sum0);
|
|
|
|
*_variance1+=OC_MINI(255,sum1);
|
|
|
|
if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
|
|
|
|
*cdst=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
*cdst=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
for(by=0;by<4;by++){
|
|
|
|
*cdst=(unsigned char)(r[by]+r[by+1]+r[by+2]+r[by+3]*2+
|
|
|
|
r[by+4]+r[by+5]+r[by+6]+4>>3);
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
}
|
|
|
|
*cdst=(unsigned char)(r[4]+r[5]+r[6]+r[7]*2+r[8]+r[9]*2+4>>3);
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
*cdst=(unsigned char)(r[5]+r[6]+r[7]+r[8]*2+r[9]*3+4>>3);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
for(by=1;by<=8;by++){
|
|
|
|
*cdst=(unsigned char)r[by];
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rdst++;
|
|
|
|
rsrc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Filter a vertical block edge.*/
|
|
|
|
static void oc_filter_vedge(unsigned char *_dst,int _dst_ystride,
|
|
|
|
int _qstep,int _flimit,int *_variances){
|
|
|
|
unsigned char *rdst;
|
|
|
|
const unsigned char *rsrc;
|
|
|
|
unsigned char *cdst;
|
|
|
|
int r[10];
|
|
|
|
int sum0;
|
|
|
|
int sum1;
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
cdst=_dst;
|
|
|
|
for(by=0;by<8;by++){
|
|
|
|
rsrc=cdst-1;
|
|
|
|
rdst=cdst;
|
|
|
|
for(bx=0;bx<10;bx++)r[bx]=*rsrc++;
|
|
|
|
sum0=sum1=0;
|
|
|
|
for(bx=0;bx<4;bx++){
|
|
|
|
sum0+=abs(r[bx+1]-r[bx]);
|
|
|
|
sum1+=abs(r[bx+5]-r[bx+6]);
|
|
|
|
}
|
|
|
|
_variances[0]+=OC_MINI(255,sum0);
|
|
|
|
_variances[1]+=OC_MINI(255,sum1);
|
|
|
|
if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
|
|
|
|
*rdst++=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
|
|
|
|
*rdst++=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
|
|
|
|
for(bx=0;bx<4;bx++){
|
|
|
|
*rdst++=(unsigned char)(r[bx]+r[bx+1]+r[bx+2]+r[bx+3]*2+
|
|
|
|
r[bx+4]+r[bx+5]+r[bx+6]+4>>3);
|
|
|
|
}
|
|
|
|
*rdst++=(unsigned char)(r[4]+r[5]+r[6]+r[7]*2+r[8]+r[9]*2+4>>3);
|
|
|
|
*rdst=(unsigned char)(r[5]+r[6]+r[7]+r[8]*2+r[9]*3+4>>3);
|
|
|
|
}
|
|
|
|
else for(bx=1;bx<=8;bx++)*rdst++=(unsigned char)r[bx];
|
|
|
|
cdst+=_dst_ystride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oc_dec_deblock_frag_rows(oc_dec_ctx *_dec,
|
|
|
|
th_img_plane *_dst,th_img_plane *_src,int _pli,int _fragy0,
|
|
|
|
int _fragy_end){
|
|
|
|
oc_fragment_plane *fplane;
|
|
|
|
int *variance;
|
|
|
|
unsigned char *dc_qi;
|
|
|
|
unsigned char *dst;
|
|
|
|
const unsigned char *src;
|
|
|
|
int notstart;
|
|
|
|
int notdone;
|
|
|
|
int froffset;
|
|
|
|
int flimit;
|
|
|
|
int qstep;
|
|
|
|
int y_end;
|
|
|
|
int y;
|
|
|
|
int x;
|
|
|
|
_dst+=_pli;
|
|
|
|
_src+=_pli;
|
|
|
|
fplane=_dec->state.fplanes+_pli;
|
|
|
|
froffset=fplane->froffset+_fragy0*fplane->nhfrags;
|
|
|
|
variance=_dec->variances+froffset;
|
|
|
|
dc_qi=_dec->dc_qis+froffset;
|
|
|
|
notstart=_fragy0>0;
|
|
|
|
notdone=_fragy_end<fplane->nvfrags;
|
|
|
|
/*We want to clear an extra row of variances, except at the end.*/
|
|
|
|
memset(variance+(fplane->nhfrags&-notstart),0,
|
|
|
|
(_fragy_end+notdone-_fragy0-notstart)*fplane->nhfrags*sizeof(variance[0]));
|
|
|
|
/*Except for the first time, we want to point to the middle of the row.*/
|
|
|
|
y=(_fragy0<<3)+(notstart<<2);
|
|
|
|
dst=_dst->data+y*_dst->stride;
|
|
|
|
src=_src->data+y*_src->stride;
|
|
|
|
for(;y<4;y++){
|
|
|
|
memcpy(dst,src,_dst->width*sizeof(dst[0]));
|
|
|
|
dst+=_dst->stride;
|
|
|
|
src+=_src->stride;
|
|
|
|
}
|
|
|
|
/*We also want to skip the last row in the frame for this loop.*/
|
|
|
|
y_end=_fragy_end-!notdone<<3;
|
|
|
|
for(;y<y_end;y+=8){
|
|
|
|
qstep=_dec->pp_dc_scale[*dc_qi];
|
|
|
|
flimit=(qstep*3)>>2;
|
|
|
|
oc_filter_hedge(dst,_dst->stride,src-_src->stride,_src->stride,
|
|
|
|
qstep,flimit,variance,variance+fplane->nhfrags);
|
|
|
|
variance++;
|
|
|
|
dc_qi++;
|
|
|
|
for(x=8;x<_dst->width;x+=8){
|
|
|
|
qstep=_dec->pp_dc_scale[*dc_qi];
|
|
|
|
flimit=(qstep*3)>>2;
|
|
|
|
oc_filter_hedge(dst+x,_dst->stride,src+x-_src->stride,_src->stride,
|
|
|
|
qstep,flimit,variance,variance+fplane->nhfrags);
|
|
|
|
oc_filter_vedge(dst+x-(_dst->stride<<2)-4,_dst->stride,
|
|
|
|
qstep,flimit,variance-1);
|
|
|
|
variance++;
|
|
|
|
dc_qi++;
|
|
|
|
}
|
|
|
|
dst+=_dst->stride<<3;
|
|
|
|
src+=_src->stride<<3;
|
|
|
|
}
|
|
|
|
/*And finally, handle the last row in the frame, if it's in the range.*/
|
|
|
|
if(!notdone){
|
|
|
|
for(;y<_dst->height;y++){
|
|
|
|
memcpy(dst,src,_dst->width*sizeof(dst[0]));
|
|
|
|
dst+=_dst->stride;
|
|
|
|
src+=_src->stride;
|
|
|
|
}
|
|
|
|
/*Filter the last row of vertical block edges.*/
|
|
|
|
dc_qi++;
|
|
|
|
for(x=8;x<_dst->width;x+=8){
|
|
|
|
qstep=_dec->pp_dc_scale[*dc_qi++];
|
|
|
|
flimit=(qstep*3)>>2;
|
|
|
|
oc_filter_vedge(dst+x-(_dst->stride<<3)-4,_dst->stride,
|
|
|
|
qstep,flimit,variance++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oc_dering_block(unsigned char *_idata,int _ystride,int _b,
|
|
|
|
int _dc_scale,int _sharp_mod,int _strong){
|
2008-09-25 09:08:33 -07:00
|
|
|
static const int OCDB_MOD_MAX[2]={24,32};
|
|
|
|
static const int OCDB_MOD_SHIFT[2]={1,0};
|
2008-07-29 23:38:23 -07:00
|
|
|
const unsigned char *psrc;
|
|
|
|
const unsigned char *src;
|
|
|
|
const unsigned char *nsrc;
|
|
|
|
unsigned char *dst;
|
|
|
|
int vmod[72];
|
|
|
|
int hmod[72];
|
|
|
|
int mod_hi;
|
|
|
|
int by;
|
|
|
|
int bx;
|
2008-09-25 09:08:33 -07:00
|
|
|
mod_hi=OC_MINI(3*_dc_scale,OCDB_MOD_MAX[_strong]);
|
2008-07-29 23:38:23 -07:00
|
|
|
dst=_idata;
|
|
|
|
src=dst;
|
|
|
|
psrc=src-(_ystride&-!(_b&4));
|
|
|
|
for(by=0;by<9;by++){
|
|
|
|
for(bx=0;bx<8;bx++){
|
|
|
|
int mod;
|
2008-09-25 09:08:33 -07:00
|
|
|
mod=32+_dc_scale-(abs(src[bx]-psrc[bx])<<OCDB_MOD_SHIFT[_strong]);
|
2008-07-29 23:38:23 -07:00
|
|
|
vmod[(by<<3)+bx]=mod<-64?_sharp_mod:OC_CLAMPI(0,mod,mod_hi);
|
|
|
|
}
|
|
|
|
psrc=src;
|
|
|
|
src+=_ystride&-(!(_b&8)|by<7);
|
|
|
|
}
|
|
|
|
nsrc=dst;
|
|
|
|
psrc=dst-!(_b&1);
|
|
|
|
for(bx=0;bx<9;bx++){
|
|
|
|
src=nsrc;
|
|
|
|
for(by=0;by<8;by++){
|
|
|
|
int mod;
|
2008-09-25 09:08:33 -07:00
|
|
|
mod=32+_dc_scale-(abs(*src-*psrc)<<OCDB_MOD_SHIFT[_strong]);
|
2008-07-29 23:38:23 -07:00
|
|
|
hmod[(bx<<3)+by]=mod<-64?_sharp_mod:OC_CLAMPI(0,mod,mod_hi);
|
|
|
|
psrc+=_ystride;
|
|
|
|
src+=_ystride;
|
|
|
|
}
|
|
|
|
psrc=nsrc;
|
|
|
|
nsrc+=!(_b&2)|bx<7;
|
|
|
|
}
|
|
|
|
src=dst;
|
|
|
|
psrc=src-(_ystride&-!(_b&4));
|
|
|
|
nsrc=src+_ystride;
|
|
|
|
for(by=0;by<8;by++){
|
|
|
|
int a;
|
|
|
|
int b;
|
|
|
|
int w;
|
|
|
|
a=128;
|
|
|
|
b=64;
|
|
|
|
w=hmod[by];
|
|
|
|
a-=w;
|
|
|
|
b+=w**(src-!(_b&1));
|
|
|
|
w=vmod[(by<<3)];
|
|
|
|
a-=w;
|
|
|
|
b+=w*psrc[0];
|
|
|
|
w=vmod[(by+1<<3)];
|
|
|
|
a-=w;
|
|
|
|
b+=w*nsrc[0];
|
|
|
|
w=hmod[(1<<3)+by];
|
|
|
|
a-=w;
|
|
|
|
b+=w*src[1];
|
|
|
|
dst[0]=OC_CLAMP255(a*src[0]+b>>7);
|
|
|
|
for(bx=1;bx<7;bx++){
|
|
|
|
a=128;
|
|
|
|
b=64;
|
|
|
|
w=hmod[(bx<<3)+by];
|
|
|
|
a-=w;
|
|
|
|
b+=w*src[bx-1];
|
|
|
|
w=vmod[(by<<3)+bx];
|
|
|
|
a-=w;
|
|
|
|
b+=w*psrc[bx];
|
|
|
|
w=vmod[(by+1<<3)+bx];
|
|
|
|
a-=w;
|
|
|
|
b+=w*nsrc[bx];
|
|
|
|
w=hmod[(bx+1<<3)+by];
|
|
|
|
a-=w;
|
|
|
|
b+=w*src[bx+1];
|
|
|
|
dst[bx]=OC_CLAMP255(a*src[bx]+b>>7);
|
|
|
|
}
|
|
|
|
a=128;
|
|
|
|
b=64;
|
|
|
|
w=hmod[(7<<3)+by];
|
|
|
|
a-=w;
|
|
|
|
b+=w*src[6];
|
|
|
|
w=vmod[(by<<3)+7];
|
|
|
|
a-=w;
|
|
|
|
b+=w*psrc[7];
|
|
|
|
w=vmod[(by+1<<3)+7];
|
|
|
|
a-=w;
|
|
|
|
b+=w*nsrc[7];
|
|
|
|
w=hmod[(8<<3)+by];
|
|
|
|
a-=w;
|
|
|
|
b+=w*src[7+!(_b&2)];
|
|
|
|
dst[7]=OC_CLAMP255(a*src[7]+b>>7);
|
|
|
|
dst+=_ystride;
|
|
|
|
psrc=src;
|
|
|
|
src=nsrc;
|
|
|
|
nsrc+=_ystride&-(!(_b&8)|by<6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OC_DERING_THRESH1 (384)
|
|
|
|
#define OC_DERING_THRESH2 (4*OC_DERING_THRESH1)
|
|
|
|
#define OC_DERING_THRESH3 (5*OC_DERING_THRESH1)
|
|
|
|
#define OC_DERING_THRESH4 (10*OC_DERING_THRESH1)
|
|
|
|
|
|
|
|
static void oc_dec_dering_frag_rows(oc_dec_ctx *_dec,th_img_plane *_img,
|
|
|
|
int _pli,int _fragy0,int _fragy_end){
|
2009-01-21 16:00:49 -08:00
|
|
|
th_img_plane *iplane;
|
2008-07-29 23:38:23 -07:00
|
|
|
oc_fragment_plane *fplane;
|
|
|
|
oc_fragment *frag;
|
|
|
|
int *variance;
|
|
|
|
unsigned char *idata;
|
|
|
|
int sthresh;
|
|
|
|
int strong;
|
|
|
|
int froffset;
|
|
|
|
int y_end;
|
|
|
|
int y;
|
|
|
|
int x;
|
|
|
|
iplane=_img+_pli;
|
|
|
|
fplane=_dec->state.fplanes+_pli;
|
|
|
|
froffset=fplane->froffset+_fragy0*fplane->nhfrags;
|
|
|
|
variance=_dec->variances+froffset;
|
|
|
|
frag=_dec->state.frags+froffset;
|
|
|
|
strong=_dec->pp_level>=(_pli?OC_PP_LEVEL_SDERINGC:OC_PP_LEVEL_SDERINGY);
|
|
|
|
sthresh=_pli?OC_DERING_THRESH4:OC_DERING_THRESH3;
|
|
|
|
y=_fragy0<<3;
|
|
|
|
idata=iplane->data+y*iplane->stride;
|
|
|
|
y_end=_fragy_end<<3;
|
|
|
|
for(;y<y_end;y+=8){
|
|
|
|
for(x=0;x<iplane->width;x+=8){
|
|
|
|
int b;
|
|
|
|
int qi;
|
|
|
|
int var;
|
|
|
|
qi=frag->qi;
|
|
|
|
var=*variance;
|
|
|
|
b=(x<=0)|(x+8>=iplane->width)<<1|(y<=0)<<2|(y+8>=iplane->height)<<3;
|
|
|
|
if(strong&&var>sthresh){
|
|
|
|
oc_dering_block(idata+x,iplane->stride,b,
|
|
|
|
_dec->pp_dc_scale[qi],_dec->pp_sharp_mod[qi],1);
|
2009-01-21 16:00:49 -08:00
|
|
|
if(_pli||!(b&1)&&*(variance-1)>OC_DERING_THRESH4||
|
|
|
|
!(b&2)&&variance[1]>OC_DERING_THRESH4||
|
|
|
|
!(b&4)&&*(variance-fplane->nvfrags)>OC_DERING_THRESH4||
|
|
|
|
!(b&8)&&variance[fplane->nvfrags]>OC_DERING_THRESH4){
|
2008-07-29 23:38:23 -07:00
|
|
|
oc_dering_block(idata+x,iplane->stride,b,
|
|
|
|
_dec->pp_dc_scale[qi],_dec->pp_sharp_mod[qi],1);
|
|
|
|
oc_dering_block(idata+x,iplane->stride,b,
|
|
|
|
_dec->pp_dc_scale[qi],_dec->pp_sharp_mod[qi],1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(var>OC_DERING_THRESH2){
|
|
|
|
oc_dering_block(idata+x,iplane->stride,b,
|
|
|
|
_dec->pp_dc_scale[qi],_dec->pp_sharp_mod[qi],1);
|
|
|
|
}
|
|
|
|
else if(var>OC_DERING_THRESH1){
|
|
|
|
oc_dering_block(idata+x,iplane->stride,b,
|
|
|
|
_dec->pp_dc_scale[qi],_dec->pp_sharp_mod[qi],0);
|
|
|
|
}
|
|
|
|
frag++;
|
|
|
|
variance++;
|
|
|
|
}
|
|
|
|
idata+=iplane->stride<<3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
th_dec_ctx *th_decode_alloc(const th_info *_info,
|
|
|
|
const th_setup_info *_setup){
|
|
|
|
oc_dec_ctx *dec;
|
|
|
|
if(_info==NULL||_setup==NULL)return NULL;
|
|
|
|
dec=_ogg_malloc(sizeof(*dec));
|
|
|
|
if(oc_dec_init(dec,_info,_setup)<0){
|
|
|
|
_ogg_free(dec);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dec->state.curframe_num=0;
|
|
|
|
return dec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void th_decode_free(th_dec_ctx *_dec){
|
|
|
|
if(_dec!=NULL){
|
|
|
|
oc_dec_clear(_dec);
|
|
|
|
_ogg_free(_dec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int th_decode_ctl(th_dec_ctx *_dec,int _req,void *_buf,
|
|
|
|
size_t _buf_sz){
|
|
|
|
switch(_req){
|
|
|
|
case TH_DECCTL_GET_PPLEVEL_MAX:{
|
|
|
|
if(_dec==NULL||_buf==NULL)return TH_EFAULT;
|
|
|
|
if(_buf_sz!=sizeof(int))return TH_EINVAL;
|
|
|
|
(*(int *)_buf)=OC_PP_LEVEL_MAX;
|
|
|
|
return 0;
|
|
|
|
}break;
|
|
|
|
case TH_DECCTL_SET_PPLEVEL:{
|
|
|
|
int pp_level;
|
|
|
|
if(_dec==NULL||_buf==NULL)return TH_EFAULT;
|
|
|
|
if(_buf_sz!=sizeof(int))return TH_EINVAL;
|
|
|
|
pp_level=*(int *)_buf;
|
|
|
|
if(pp_level<0||pp_level>OC_PP_LEVEL_MAX)return TH_EINVAL;
|
|
|
|
_dec->pp_level=pp_level;
|
|
|
|
return 0;
|
|
|
|
}break;
|
|
|
|
case TH_DECCTL_SET_GRANPOS:{
|
|
|
|
ogg_int64_t granpos;
|
|
|
|
if(_dec==NULL||_buf==NULL)return TH_EFAULT;
|
|
|
|
if(_buf_sz!=sizeof(ogg_int64_t))return TH_EINVAL;
|
|
|
|
granpos=*(ogg_int64_t *)_buf;
|
|
|
|
if(granpos<0)return TH_EINVAL;
|
|
|
|
_dec->state.granpos=granpos;
|
|
|
|
_dec->state.keyframe_num=
|
|
|
|
granpos>>_dec->state.info.keyframe_granule_shift;
|
|
|
|
_dec->state.curframe_num=_dec->state.keyframe_num+
|
|
|
|
(granpos&(1<<_dec->state.info.keyframe_granule_shift)-1);
|
|
|
|
return 0;
|
|
|
|
}break;
|
|
|
|
case TH_DECCTL_SET_STRIPE_CB:{
|
|
|
|
th_stripe_callback *cb;
|
|
|
|
if(_dec==NULL||_buf==NULL)return TH_EFAULT;
|
|
|
|
if(_buf_sz!=sizeof(th_stripe_callback))return TH_EINVAL;
|
|
|
|
cb=(th_stripe_callback *)_buf;
|
|
|
|
_dec->stripe_cb.ctx=cb->ctx;
|
|
|
|
_dec->stripe_cb.stripe_decoded=cb->stripe_decoded;
|
|
|
|
return 0;
|
|
|
|
}break;
|
|
|
|
default:return TH_EIMPL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int th_decode_packetin(th_dec_ctx *_dec,const ogg_packet *_op,
|
|
|
|
ogg_int64_t *_granpos){
|
|
|
|
int ret;
|
|
|
|
if(_dec==NULL||_op==NULL)return TH_EFAULT;
|
|
|
|
/*A completely empty packet indicates a dropped frame and is treated exactly
|
|
|
|
like an inter frame with no coded blocks.
|
|
|
|
Only proceed if we have a non-empty packet.*/
|
|
|
|
if(_op->bytes!=0){
|
|
|
|
oc_dec_pipeline_state pipe;
|
|
|
|
th_ycbcr_buffer stripe_buf;
|
|
|
|
int stripe_fragy;
|
|
|
|
int refi;
|
|
|
|
int pli;
|
|
|
|
int notstart;
|
|
|
|
int notdone;
|
|
|
|
theorapackB_readinit(&_dec->opb,_op->packet,_op->bytes);
|
|
|
|
ret=oc_dec_frame_header_unpack(_dec);
|
|
|
|
if(ret<0)return ret;
|
|
|
|
/*Select a free buffer to use for the reconstructed version of this
|
|
|
|
frame.*/
|
|
|
|
if(_dec->state.frame_type!=OC_INTRA_FRAME&&
|
|
|
|
(_dec->state.ref_frame_idx[OC_FRAME_GOLD]<0||
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_PREV]<0)){
|
|
|
|
th_info *info;
|
|
|
|
size_t yplane_sz;
|
|
|
|
size_t cplane_sz;
|
|
|
|
int yhstride;
|
|
|
|
int yvstride;
|
|
|
|
int chstride;
|
|
|
|
int cvstride;
|
|
|
|
/*We're decoding an INTER frame, but have no initialized reference
|
|
|
|
buffers (i.e., decoding did not start on a key frame).
|
|
|
|
We initialize them to a solid gray here.*/
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_GOLD]=0;
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_PREV]=0;
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_SELF]=refi=1;
|
|
|
|
info=&_dec->state.info;
|
|
|
|
yhstride=info->frame_width+2*OC_UMV_PADDING;
|
|
|
|
yvstride=info->frame_height+2*OC_UMV_PADDING;
|
|
|
|
chstride=yhstride>>!(info->pixel_fmt&1);
|
|
|
|
cvstride=yvstride>>!(info->pixel_fmt&2);
|
|
|
|
yplane_sz=(size_t)yhstride*yvstride;
|
|
|
|
cplane_sz=(size_t)chstride*cvstride;
|
|
|
|
memset(_dec->state.ref_frame_data,0x80,yplane_sz+2*cplane_sz);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
for(refi=0;refi==_dec->state.ref_frame_idx[OC_FRAME_GOLD]||
|
|
|
|
refi==_dec->state.ref_frame_idx[OC_FRAME_PREV];refi++);
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_SELF]=refi;
|
|
|
|
}
|
|
|
|
if(_dec->state.frame_type==OC_INTRA_FRAME){
|
|
|
|
oc_dec_mark_all_intra(_dec);
|
|
|
|
_dec->state.keyframe_num=_dec->state.curframe_num;
|
|
|
|
}else{
|
|
|
|
oc_dec_coded_flags_unpack(_dec);
|
|
|
|
oc_dec_mb_modes_unpack(_dec);
|
|
|
|
oc_dec_mv_unpack_and_frag_modes_fill(_dec);
|
|
|
|
}
|
|
|
|
oc_dec_block_qis_unpack(_dec);
|
|
|
|
oc_dec_residual_tokens_unpack(_dec);
|
|
|
|
/*Update granule position.
|
|
|
|
This must be done before the striped decode callbacks so that the
|
|
|
|
application knows what to do with the frame data.*/
|
|
|
|
_dec->state.granpos=
|
|
|
|
(_dec->state.keyframe_num<<_dec->state.info.keyframe_granule_shift)+
|
|
|
|
(_dec->state.curframe_num-_dec->state.keyframe_num);
|
|
|
|
_dec->state.curframe_num++;
|
|
|
|
if(_granpos!=NULL)*_granpos=_dec->state.granpos;
|
|
|
|
/*All of the rest of the operations -- DC prediction reversal,
|
|
|
|
reconstructing coded fragments, copying uncoded fragments, loop
|
|
|
|
filtering, extending borders, and out-of-loop post-processing -- should
|
|
|
|
be pipelined.
|
|
|
|
I.e., DC prediction reversal, reconstruction, and uncoded fragment
|
|
|
|
copying are done for one or two super block rows, then loop filtering is
|
|
|
|
run as far as it can, then bordering copying, then post-processing.
|
|
|
|
For 4:2:0 video a Minimum Codable Unit or MCU contains two luma super
|
|
|
|
block rows, and one chroma.
|
|
|
|
Otherwise, an MCU consists of one super block row from each plane.
|
|
|
|
Inside each MCU, we perform all of the steps on one color plane before
|
|
|
|
moving on to the next.
|
|
|
|
After reconstruction, the additional filtering stages introduce a delay
|
|
|
|
since they need some pixels from the next fragment row.
|
|
|
|
Thus the actual number of decoded rows available is slightly smaller for
|
|
|
|
the first MCU, and slightly larger for the last.
|
|
|
|
|
|
|
|
This entire process allows us to operate on the data while it is still in
|
|
|
|
cache, resulting in big performance improvements.
|
|
|
|
An application callback allows further application processing (blitting
|
|
|
|
to video memory, color conversion, etc.) to also use the data while it's
|
|
|
|
in cache.*/
|
|
|
|
oc_dec_pipeline_init(_dec,&pipe);
|
|
|
|
oc_ycbcr_buffer_flip(stripe_buf,_dec->pp_frame_buf);
|
|
|
|
notstart=0;
|
|
|
|
notdone=1;
|
|
|
|
for(stripe_fragy=notstart=0;notdone;stripe_fragy+=pipe.mcu_nvfrags){
|
|
|
|
int avail_fragy0;
|
|
|
|
int avail_fragy_end;
|
|
|
|
avail_fragy0=avail_fragy_end=_dec->state.fplanes[0].nvfrags;
|
|
|
|
notdone=stripe_fragy+pipe.mcu_nvfrags<avail_fragy_end;
|
|
|
|
for(pli=0;pli<3;pli++){
|
|
|
|
oc_fragment_plane *fplane;
|
|
|
|
int frag_shift;
|
|
|
|
int pp_offset;
|
|
|
|
int sdelay;
|
|
|
|
int edelay;
|
|
|
|
fplane=_dec->state.fplanes+pli;
|
|
|
|
/*Compute the first and last fragment row of the current MCU for this
|
|
|
|
plane.*/
|
|
|
|
frag_shift=pli!=0&&!(_dec->state.info.pixel_fmt&2);
|
|
|
|
pipe.fragy0[pli]=stripe_fragy>>frag_shift;
|
|
|
|
pipe.fragy_end[pli]=OC_MINI(fplane->nvfrags,
|
|
|
|
pipe.fragy0[pli]+(pipe.mcu_nvfrags>>frag_shift));
|
|
|
|
oc_dec_dc_unpredict_mcu_plane(_dec,&pipe,pli);
|
|
|
|
oc_dec_frags_recon_mcu_plane(_dec,&pipe,pli);
|
|
|
|
sdelay=edelay=0;
|
|
|
|
if(pipe.loop_filter){
|
|
|
|
sdelay+=notstart;
|
|
|
|
edelay+=notdone;
|
|
|
|
oc_state_loop_filter_frag_rows(&_dec->state,pipe.bounding_values,
|
|
|
|
refi,pli,pipe.fragy0[pli]-sdelay,pipe.fragy_end[pli]-edelay);
|
|
|
|
}
|
|
|
|
/*To fill the borders, we have an additional two pixel delay, since a
|
|
|
|
fragment in the next row could filter its top edge, using two pixels
|
|
|
|
from a fragment in this row.
|
|
|
|
But there's no reason to delay a full fragment between the two.*/
|
|
|
|
oc_state_borders_fill_rows(&_dec->state,refi,pli,
|
|
|
|
(pipe.fragy0[pli]-sdelay<<3)-(sdelay<<1),
|
|
|
|
(pipe.fragy_end[pli]-edelay<<3)-(edelay<<1));
|
|
|
|
/*Out-of-loop post-processing.*/
|
|
|
|
pp_offset=3*(pli!=0);
|
|
|
|
if(pipe.pp_level>=OC_PP_LEVEL_DEBLOCKY+pp_offset){
|
|
|
|
/*Perform de-blocking in one plane.*/
|
|
|
|
sdelay+=notstart;
|
|
|
|
edelay+=notdone;
|
|
|
|
oc_dec_deblock_frag_rows(_dec,_dec->pp_frame_buf,
|
|
|
|
_dec->state.ref_frame_bufs[refi],pli,
|
|
|
|
pipe.fragy0[pli]-sdelay,pipe.fragy_end[pli]-edelay);
|
|
|
|
if(pipe.pp_level>=OC_PP_LEVEL_DERINGY+pp_offset){
|
|
|
|
/*Perform de-ringing in one plane.*/
|
|
|
|
sdelay+=notstart;
|
|
|
|
edelay+=notdone;
|
|
|
|
oc_dec_dering_frag_rows(_dec,_dec->pp_frame_buf,pli,
|
|
|
|
pipe.fragy0[pli]-sdelay,pipe.fragy_end[pli]-edelay);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*If no post-processing is done, we still need to delay a row for the
|
|
|
|
loop filter, thanks to the strange filtering order VP3 chose.*/
|
|
|
|
else if(pipe.loop_filter){
|
|
|
|
sdelay+=notstart;
|
|
|
|
edelay+=notdone;
|
|
|
|
}
|
|
|
|
/*Compute the intersection of the available rows in all planes.
|
|
|
|
If chroma is sub-sampled, the effect of each of its delays is
|
|
|
|
doubled, but luma might have more post-processing filters enabled
|
|
|
|
than chroma, so we don't know up front which one is the limiting
|
|
|
|
factor.*/
|
|
|
|
avail_fragy0=OC_MINI(avail_fragy0,pipe.fragy0[pli]-sdelay<<frag_shift);
|
|
|
|
avail_fragy_end=OC_MINI(avail_fragy_end,
|
|
|
|
pipe.fragy_end[pli]-edelay<<frag_shift);
|
|
|
|
}
|
|
|
|
if(_dec->stripe_cb.stripe_decoded!=NULL){
|
|
|
|
/*Make the callback, ensuring we flip the sense of the "start" and
|
|
|
|
"end" of the available region upside down.*/
|
|
|
|
(*_dec->stripe_cb.stripe_decoded)(_dec->stripe_cb.ctx,stripe_buf,
|
|
|
|
_dec->state.fplanes[0].nvfrags-avail_fragy_end,
|
|
|
|
_dec->state.fplanes[0].nvfrags-avail_fragy0);
|
|
|
|
}
|
|
|
|
notstart=1;
|
|
|
|
}
|
|
|
|
/*Finish filling in the reference frame borders.*/
|
|
|
|
for(pli=0;pli<3;pli++)oc_state_borders_fill_caps(&_dec->state,refi,pli);
|
|
|
|
/*Update the reference frame indices.*/
|
|
|
|
if(_dec->state.frame_type==OC_INTRA_FRAME){
|
|
|
|
/*The new frame becomes both the previous and gold reference frames.*/
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_GOLD]=
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_PREV]=
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_SELF];
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/*Otherwise, just replace the previous reference frame.*/
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_PREV]=
|
|
|
|
_dec->state.ref_frame_idx[OC_FRAME_SELF];
|
|
|
|
}
|
|
|
|
#if defined(OC_DUMP_IMAGES)
|
|
|
|
/*Don't dump images for dropped frames.*/
|
|
|
|
oc_state_dump_frame(&_dec->state,OC_FRAME_SELF,"dec");
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/*Just update the granule position and return.*/
|
|
|
|
_dec->state.granpos=
|
|
|
|
(_dec->state.keyframe_num<<_dec->state.info.keyframe_granule_shift)+
|
|
|
|
(_dec->state.curframe_num-_dec->state.keyframe_num);
|
|
|
|
_dec->state.curframe_num++;
|
|
|
|
if(_granpos!=NULL)*_granpos=_dec->state.granpos;
|
|
|
|
return TH_DUPFRAME;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int th_decode_ycbcr_out(th_dec_ctx *_dec,th_ycbcr_buffer _ycbcr){
|
|
|
|
oc_ycbcr_buffer_flip(_ycbcr,_dec->pp_frame_buf);
|
|
|
|
return 0;
|
|
|
|
}
|