media/libtheora/lib/state.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /********************************************************************
michael@0 2 * *
michael@0 3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
michael@0 4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
michael@0 5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
michael@0 6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
michael@0 7 * *
michael@0 8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
michael@0 9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
michael@0 10 * *
michael@0 11 ********************************************************************
michael@0 12
michael@0 13 function:
michael@0 14 last mod: $Id: state.c 17576 2010-10-29 01:07:51Z tterribe $
michael@0 15
michael@0 16 ********************************************************************/
michael@0 17
michael@0 18 #include <stdlib.h>
michael@0 19 #include <string.h>
michael@0 20 #include "state.h"
michael@0 21 #if defined(OC_DUMP_IMAGES)
michael@0 22 # include <stdio.h>
michael@0 23 # include "png.h"
michael@0 24 #endif
michael@0 25
michael@0 26 /*The function used to fill in the chroma plane motion vectors for a macro
michael@0 27 block when 4 different motion vectors are specified in the luma plane.
michael@0 28 This version is for use with chroma decimated in the X and Y directions
michael@0 29 (4:2:0).
michael@0 30 _cbmvs: The chroma block-level motion vectors to fill in.
michael@0 31 _lbmvs: The luma block-level motion vectors.*/
michael@0 32 static void oc_set_chroma_mvs00(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]){
michael@0 33 int dx;
michael@0 34 int dy;
michael@0 35 dx=OC_MV_X(_lbmvs[0])+OC_MV_X(_lbmvs[1])
michael@0 36 +OC_MV_X(_lbmvs[2])+OC_MV_X(_lbmvs[3]);
michael@0 37 dy=OC_MV_Y(_lbmvs[0])+OC_MV_Y(_lbmvs[1])
michael@0 38 +OC_MV_Y(_lbmvs[2])+OC_MV_Y(_lbmvs[3]);
michael@0 39 _cbmvs[0]=OC_MV(OC_DIV_ROUND_POW2(dx,2,2),OC_DIV_ROUND_POW2(dy,2,2));
michael@0 40 }
michael@0 41
michael@0 42 /*The function used to fill in the chroma plane motion vectors for a macro
michael@0 43 block when 4 different motion vectors are specified in the luma plane.
michael@0 44 This version is for use with chroma decimated in the Y direction.
michael@0 45 _cbmvs: The chroma block-level motion vectors to fill in.
michael@0 46 _lbmvs: The luma block-level motion vectors.*/
michael@0 47 static void oc_set_chroma_mvs01(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]){
michael@0 48 int dx;
michael@0 49 int dy;
michael@0 50 dx=OC_MV_X(_lbmvs[0])+OC_MV_X(_lbmvs[2]);
michael@0 51 dy=OC_MV_Y(_lbmvs[0])+OC_MV_Y(_lbmvs[2]);
michael@0 52 _cbmvs[0]=OC_MV(OC_DIV_ROUND_POW2(dx,1,1),OC_DIV_ROUND_POW2(dy,1,1));
michael@0 53 dx=OC_MV_X(_lbmvs[1])+OC_MV_X(_lbmvs[3]);
michael@0 54 dy=OC_MV_Y(_lbmvs[1])+OC_MV_Y(_lbmvs[3]);
michael@0 55 _cbmvs[1]=OC_MV(OC_DIV_ROUND_POW2(dx,1,1),OC_DIV_ROUND_POW2(dy,1,1));
michael@0 56 }
michael@0 57
michael@0 58 /*The function used to fill in the chroma plane motion vectors for a macro
michael@0 59 block when 4 different motion vectors are specified in the luma plane.
michael@0 60 This version is for use with chroma decimated in the X direction (4:2:2).
michael@0 61 _cbmvs: The chroma block-level motion vectors to fill in.
michael@0 62 _lbmvs: The luma block-level motion vectors.*/
michael@0 63 static void oc_set_chroma_mvs10(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]){
michael@0 64 int dx;
michael@0 65 int dy;
michael@0 66 dx=OC_MV_X(_lbmvs[0])+OC_MV_X(_lbmvs[1]);
michael@0 67 dy=OC_MV_Y(_lbmvs[0])+OC_MV_Y(_lbmvs[1]);
michael@0 68 _cbmvs[0]=OC_MV(OC_DIV_ROUND_POW2(dx,1,1),OC_DIV_ROUND_POW2(dy,1,1));
michael@0 69 dx=OC_MV_X(_lbmvs[2])+OC_MV_X(_lbmvs[3]);
michael@0 70 dy=OC_MV_Y(_lbmvs[2])+OC_MV_Y(_lbmvs[3]);
michael@0 71 _cbmvs[2]=OC_MV(OC_DIV_ROUND_POW2(dx,1,1),OC_DIV_ROUND_POW2(dy,1,1));
michael@0 72 }
michael@0 73
michael@0 74 /*The function used to fill in the chroma plane motion vectors for a macro
michael@0 75 block when 4 different motion vectors are specified in the luma plane.
michael@0 76 This version is for use with no chroma decimation (4:4:4).
michael@0 77 _cbmvs: The chroma block-level motion vectors to fill in.
michael@0 78 _lmbmv: The luma macro-block level motion vector to fill in for use in
michael@0 79 prediction.
michael@0 80 _lbmvs: The luma block-level motion vectors.*/
michael@0 81 static void oc_set_chroma_mvs11(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]){
michael@0 82 _cbmvs[0]=_lbmvs[0];
michael@0 83 _cbmvs[1]=_lbmvs[1];
michael@0 84 _cbmvs[2]=_lbmvs[2];
michael@0 85 _cbmvs[3]=_lbmvs[3];
michael@0 86 }
michael@0 87
michael@0 88 /*A table of functions used to fill in the chroma plane motion vectors for a
michael@0 89 macro block when 4 different motion vectors are specified in the luma
michael@0 90 plane.*/
michael@0 91 const oc_set_chroma_mvs_func OC_SET_CHROMA_MVS_TABLE[TH_PF_NFORMATS]={
michael@0 92 (oc_set_chroma_mvs_func)oc_set_chroma_mvs00,
michael@0 93 (oc_set_chroma_mvs_func)oc_set_chroma_mvs01,
michael@0 94 (oc_set_chroma_mvs_func)oc_set_chroma_mvs10,
michael@0 95 (oc_set_chroma_mvs_func)oc_set_chroma_mvs11
michael@0 96 };
michael@0 97
michael@0 98
michael@0 99
michael@0 100 /*Returns the fragment index of the top-left block in a macro block.
michael@0 101 This can be used to test whether or not the whole macro block is valid.
michael@0 102 _sb_map: The super block map.
michael@0 103 _quadi: The quadrant number.
michael@0 104 Return: The index of the fragment of the upper left block in the macro
michael@0 105 block, or -1 if the block lies outside the coded frame.*/
michael@0 106 static ptrdiff_t oc_sb_quad_top_left_frag(oc_sb_map_quad _sb_map[4],int _quadi){
michael@0 107 /*It so happens that under the Hilbert curve ordering described below, the
michael@0 108 upper-left block in each macro block is at index 0, except in macro block
michael@0 109 3, where it is at index 2.*/
michael@0 110 return _sb_map[_quadi][_quadi&_quadi<<1];
michael@0 111 }
michael@0 112
michael@0 113 /*Fills in the mapping from block positions to fragment numbers for a single
michael@0 114 color plane.
michael@0 115 This function also fills in the "valid" flag of each quadrant in the super
michael@0 116 block flags.
michael@0 117 _sb_maps: The array of super block maps for the color plane.
michael@0 118 _sb_flags: The array of super block flags for the color plane.
michael@0 119 _frag0: The index of the first fragment in the plane.
michael@0 120 _hfrags: The number of horizontal fragments in a coded frame.
michael@0 121 _vfrags: The number of vertical fragments in a coded frame.*/
michael@0 122 static void oc_sb_create_plane_mapping(oc_sb_map _sb_maps[],
michael@0 123 oc_sb_flags _sb_flags[],ptrdiff_t _frag0,int _hfrags,int _vfrags){
michael@0 124 /*Contains the (macro_block,block) indices for a 4x4 grid of
michael@0 125 fragments.
michael@0 126 The pattern is a 4x4 Hilbert space-filling curve.
michael@0 127 A Hilbert curve has the nice property that as the curve grows larger, its
michael@0 128 fractal dimension approaches 2.
michael@0 129 The intuition is that nearby blocks in the curve are also close spatially,
michael@0 130 with the previous element always an immediate neighbor, so that runs of
michael@0 131 blocks should be well correlated.*/
michael@0 132 static const int SB_MAP[4][4][2]={
michael@0 133 {{0,0},{0,1},{3,2},{3,3}},
michael@0 134 {{0,3},{0,2},{3,1},{3,0}},
michael@0 135 {{1,0},{1,3},{2,0},{2,3}},
michael@0 136 {{1,1},{1,2},{2,1},{2,2}}
michael@0 137 };
michael@0 138 ptrdiff_t yfrag;
michael@0 139 unsigned sbi;
michael@0 140 int y;
michael@0 141 sbi=0;
michael@0 142 yfrag=_frag0;
michael@0 143 for(y=0;;y+=4){
michael@0 144 int imax;
michael@0 145 int x;
michael@0 146 /*Figure out how many columns of blocks in this super block lie within the
michael@0 147 image.*/
michael@0 148 imax=_vfrags-y;
michael@0 149 if(imax>4)imax=4;
michael@0 150 else if(imax<=0)break;
michael@0 151 for(x=0;;x+=4,sbi++){
michael@0 152 ptrdiff_t xfrag;
michael@0 153 int jmax;
michael@0 154 int quadi;
michael@0 155 int i;
michael@0 156 /*Figure out how many rows of blocks in this super block lie within the
michael@0 157 image.*/
michael@0 158 jmax=_hfrags-x;
michael@0 159 if(jmax>4)jmax=4;
michael@0 160 else if(jmax<=0)break;
michael@0 161 /*By default, set all fragment indices to -1.*/
michael@0 162 memset(_sb_maps[sbi],0xFF,sizeof(_sb_maps[sbi]));
michael@0 163 /*Fill in the fragment map for this super block.*/
michael@0 164 xfrag=yfrag+x;
michael@0 165 for(i=0;i<imax;i++){
michael@0 166 int j;
michael@0 167 for(j=0;j<jmax;j++){
michael@0 168 _sb_maps[sbi][SB_MAP[i][j][0]][SB_MAP[i][j][1]]=xfrag+j;
michael@0 169 }
michael@0 170 xfrag+=_hfrags;
michael@0 171 }
michael@0 172 /*Mark which quadrants of this super block lie within the image.*/
michael@0 173 for(quadi=0;quadi<4;quadi++){
michael@0 174 _sb_flags[sbi].quad_valid|=
michael@0 175 (oc_sb_quad_top_left_frag(_sb_maps[sbi],quadi)>=0)<<quadi;
michael@0 176 }
michael@0 177 }
michael@0 178 yfrag+=_hfrags<<2;
michael@0 179 }
michael@0 180 }
michael@0 181
michael@0 182 /*Fills in the Y plane fragment map for a macro block given the fragment
michael@0 183 coordinates of its upper-left hand corner.
michael@0 184 _mb_map: The macro block map to fill.
michael@0 185 _fplane: The description of the Y plane.
michael@0 186 _xfrag0: The X location of the upper-left hand fragment in the luma plane.
michael@0 187 _yfrag0: The Y location of the upper-left hand fragment in the luma plane.*/
michael@0 188 static void oc_mb_fill_ymapping(oc_mb_map_plane _mb_map[3],
michael@0 189 const oc_fragment_plane *_fplane,int _xfrag0,int _yfrag0){
michael@0 190 int i;
michael@0 191 int j;
michael@0 192 for(i=0;i<2;i++)for(j=0;j<2;j++){
michael@0 193 _mb_map[0][i<<1|j]=(_yfrag0+i)*(ptrdiff_t)_fplane->nhfrags+_xfrag0+j;
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 /*Fills in the chroma plane fragment maps for a macro block.
michael@0 198 This version is for use with chroma decimated in the X and Y directions
michael@0 199 (4:2:0).
michael@0 200 _mb_map: The macro block map to fill.
michael@0 201 _fplanes: The descriptions of the fragment planes.
michael@0 202 _xfrag0: The X location of the upper-left hand fragment in the luma plane.
michael@0 203 _yfrag0: The Y location of the upper-left hand fragment in the luma plane.*/
michael@0 204 static void oc_mb_fill_cmapping00(oc_mb_map_plane _mb_map[3],
michael@0 205 const oc_fragment_plane _fplanes[3],int _xfrag0,int _yfrag0){
michael@0 206 ptrdiff_t fragi;
michael@0 207 _xfrag0>>=1;
michael@0 208 _yfrag0>>=1;
michael@0 209 fragi=_yfrag0*(ptrdiff_t)_fplanes[1].nhfrags+_xfrag0;
michael@0 210 _mb_map[1][0]=fragi+_fplanes[1].froffset;
michael@0 211 _mb_map[2][0]=fragi+_fplanes[2].froffset;
michael@0 212 }
michael@0 213
michael@0 214 /*Fills in the chroma plane fragment maps for a macro block.
michael@0 215 This version is for use with chroma decimated in the Y direction.
michael@0 216 _mb_map: The macro block map to fill.
michael@0 217 _fplanes: The descriptions of the fragment planes.
michael@0 218 _xfrag0: The X location of the upper-left hand fragment in the luma plane.
michael@0 219 _yfrag0: The Y location of the upper-left hand fragment in the luma plane.*/
michael@0 220 static void oc_mb_fill_cmapping01(oc_mb_map_plane _mb_map[3],
michael@0 221 const oc_fragment_plane _fplanes[3],int _xfrag0,int _yfrag0){
michael@0 222 ptrdiff_t fragi;
michael@0 223 int j;
michael@0 224 _yfrag0>>=1;
michael@0 225 fragi=_yfrag0*(ptrdiff_t)_fplanes[1].nhfrags+_xfrag0;
michael@0 226 for(j=0;j<2;j++){
michael@0 227 _mb_map[1][j]=fragi+_fplanes[1].froffset;
michael@0 228 _mb_map[2][j]=fragi+_fplanes[2].froffset;
michael@0 229 fragi++;
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 /*Fills in the chroma plane fragment maps for a macro block.
michael@0 234 This version is for use with chroma decimated in the X direction (4:2:2).
michael@0 235 _mb_map: The macro block map to fill.
michael@0 236 _fplanes: The descriptions of the fragment planes.
michael@0 237 _xfrag0: The X location of the upper-left hand fragment in the luma plane.
michael@0 238 _yfrag0: The Y location of the upper-left hand fragment in the luma plane.*/
michael@0 239 static void oc_mb_fill_cmapping10(oc_mb_map_plane _mb_map[3],
michael@0 240 const oc_fragment_plane _fplanes[3],int _xfrag0,int _yfrag0){
michael@0 241 ptrdiff_t fragi;
michael@0 242 int i;
michael@0 243 _xfrag0>>=1;
michael@0 244 fragi=_yfrag0*(ptrdiff_t)_fplanes[1].nhfrags+_xfrag0;
michael@0 245 for(i=0;i<2;i++){
michael@0 246 _mb_map[1][i<<1]=fragi+_fplanes[1].froffset;
michael@0 247 _mb_map[2][i<<1]=fragi+_fplanes[2].froffset;
michael@0 248 fragi+=_fplanes[1].nhfrags;
michael@0 249 }
michael@0 250 }
michael@0 251
michael@0 252 /*Fills in the chroma plane fragment maps for a macro block.
michael@0 253 This version is for use with no chroma decimation (4:4:4).
michael@0 254 This uses the already filled-in luma plane values.
michael@0 255 _mb_map: The macro block map to fill.
michael@0 256 _fplanes: The descriptions of the fragment planes.*/
michael@0 257 static void oc_mb_fill_cmapping11(oc_mb_map_plane _mb_map[3],
michael@0 258 const oc_fragment_plane _fplanes[3]){
michael@0 259 int k;
michael@0 260 for(k=0;k<4;k++){
michael@0 261 _mb_map[1][k]=_mb_map[0][k]+_fplanes[1].froffset;
michael@0 262 _mb_map[2][k]=_mb_map[0][k]+_fplanes[2].froffset;
michael@0 263 }
michael@0 264 }
michael@0 265
michael@0 266 /*The function type used to fill in the chroma plane fragment maps for a
michael@0 267 macro block.
michael@0 268 _mb_map: The macro block map to fill.
michael@0 269 _fplanes: The descriptions of the fragment planes.
michael@0 270 _xfrag0: The X location of the upper-left hand fragment in the luma plane.
michael@0 271 _yfrag0: The Y location of the upper-left hand fragment in the luma plane.*/
michael@0 272 typedef void (*oc_mb_fill_cmapping_func)(oc_mb_map_plane _mb_map[3],
michael@0 273 const oc_fragment_plane _fplanes[3],int _xfrag0,int _yfrag0);
michael@0 274
michael@0 275 /*A table of functions used to fill in the chroma plane fragment maps for a
michael@0 276 macro block for each type of chrominance decimation.*/
michael@0 277 static const oc_mb_fill_cmapping_func OC_MB_FILL_CMAPPING_TABLE[4]={
michael@0 278 oc_mb_fill_cmapping00,
michael@0 279 oc_mb_fill_cmapping01,
michael@0 280 oc_mb_fill_cmapping10,
michael@0 281 (oc_mb_fill_cmapping_func)oc_mb_fill_cmapping11
michael@0 282 };
michael@0 283
michael@0 284 /*Fills in the mapping from macro blocks to their corresponding fragment
michael@0 285 numbers in each plane.
michael@0 286 _mb_maps: The list of macro block maps.
michael@0 287 _mb_modes: The list of macro block modes; macro blocks completely outside
michael@0 288 the coded region are marked invalid.
michael@0 289 _fplanes: The descriptions of the fragment planes.
michael@0 290 _pixel_fmt: The chroma decimation type.*/
michael@0 291 static void oc_mb_create_mapping(oc_mb_map _mb_maps[],
michael@0 292 signed char _mb_modes[],const oc_fragment_plane _fplanes[3],int _pixel_fmt){
michael@0 293 oc_mb_fill_cmapping_func mb_fill_cmapping;
michael@0 294 unsigned sbi;
michael@0 295 int y;
michael@0 296 mb_fill_cmapping=OC_MB_FILL_CMAPPING_TABLE[_pixel_fmt];
michael@0 297 /*Loop through the luma plane super blocks.*/
michael@0 298 for(sbi=y=0;y<_fplanes[0].nvfrags;y+=4){
michael@0 299 int x;
michael@0 300 for(x=0;x<_fplanes[0].nhfrags;x+=4,sbi++){
michael@0 301 int ymb;
michael@0 302 /*Loop through the macro blocks in each super block in display order.*/
michael@0 303 for(ymb=0;ymb<2;ymb++){
michael@0 304 int xmb;
michael@0 305 for(xmb=0;xmb<2;xmb++){
michael@0 306 unsigned mbi;
michael@0 307 int mbx;
michael@0 308 int mby;
michael@0 309 mbi=sbi<<2|OC_MB_MAP[ymb][xmb];
michael@0 310 mbx=x|xmb<<1;
michael@0 311 mby=y|ymb<<1;
michael@0 312 /*Initialize fragment indices to -1.*/
michael@0 313 memset(_mb_maps[mbi],0xFF,sizeof(_mb_maps[mbi]));
michael@0 314 /*Make sure this macro block is within the encoded region.*/
michael@0 315 if(mbx>=_fplanes[0].nhfrags||mby>=_fplanes[0].nvfrags){
michael@0 316 _mb_modes[mbi]=OC_MODE_INVALID;
michael@0 317 continue;
michael@0 318 }
michael@0 319 /*Fill in the fragment indices for the luma plane.*/
michael@0 320 oc_mb_fill_ymapping(_mb_maps[mbi],_fplanes,mbx,mby);
michael@0 321 /*Fill in the fragment indices for the chroma planes.*/
michael@0 322 (*mb_fill_cmapping)(_mb_maps[mbi],_fplanes,mbx,mby);
michael@0 323 }
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327 }
michael@0 328
michael@0 329 /*Marks the fragments which fall all or partially outside the displayable
michael@0 330 region of the frame.
michael@0 331 _state: The Theora state containing the fragments to be marked.*/
michael@0 332 static void oc_state_border_init(oc_theora_state *_state){
michael@0 333 oc_fragment *frag;
michael@0 334 oc_fragment *yfrag_end;
michael@0 335 oc_fragment *xfrag_end;
michael@0 336 oc_fragment_plane *fplane;
michael@0 337 int crop_x0;
michael@0 338 int crop_y0;
michael@0 339 int crop_xf;
michael@0 340 int crop_yf;
michael@0 341 int pli;
michael@0 342 int y;
michael@0 343 int x;
michael@0 344 /*The method we use here is slow, but the code is dead simple and handles
michael@0 345 all the special cases easily.
michael@0 346 We only ever need to do it once.*/
michael@0 347 /*Loop through the fragments, marking those completely outside the
michael@0 348 displayable region and constructing a border mask for those that straddle
michael@0 349 the border.*/
michael@0 350 _state->nborders=0;
michael@0 351 yfrag_end=frag=_state->frags;
michael@0 352 for(pli=0;pli<3;pli++){
michael@0 353 fplane=_state->fplanes+pli;
michael@0 354 /*Set up the cropping rectangle for this plane.*/
michael@0 355 crop_x0=_state->info.pic_x;
michael@0 356 crop_xf=_state->info.pic_x+_state->info.pic_width;
michael@0 357 crop_y0=_state->info.pic_y;
michael@0 358 crop_yf=_state->info.pic_y+_state->info.pic_height;
michael@0 359 if(pli>0){
michael@0 360 if(!(_state->info.pixel_fmt&1)){
michael@0 361 crop_x0=crop_x0>>1;
michael@0 362 crop_xf=crop_xf+1>>1;
michael@0 363 }
michael@0 364 if(!(_state->info.pixel_fmt&2)){
michael@0 365 crop_y0=crop_y0>>1;
michael@0 366 crop_yf=crop_yf+1>>1;
michael@0 367 }
michael@0 368 }
michael@0 369 y=0;
michael@0 370 for(yfrag_end+=fplane->nfrags;frag<yfrag_end;y+=8){
michael@0 371 x=0;
michael@0 372 for(xfrag_end=frag+fplane->nhfrags;frag<xfrag_end;frag++,x+=8){
michael@0 373 /*First check to see if this fragment is completely outside the
michael@0 374 displayable region.*/
michael@0 375 /*Note the special checks for an empty cropping rectangle.
michael@0 376 This guarantees that if we count a fragment as straddling the
michael@0 377 border below, at least one pixel in the fragment will be inside
michael@0 378 the displayable region.*/
michael@0 379 if(x+8<=crop_x0||crop_xf<=x||y+8<=crop_y0||crop_yf<=y||
michael@0 380 crop_x0>=crop_xf||crop_y0>=crop_yf){
michael@0 381 frag->invalid=1;
michael@0 382 }
michael@0 383 /*Otherwise, check to see if it straddles the border.*/
michael@0 384 else if(x<crop_x0&&crop_x0<x+8||x<crop_xf&&crop_xf<x+8||
michael@0 385 y<crop_y0&&crop_y0<y+8||y<crop_yf&&crop_yf<y+8){
michael@0 386 ogg_int64_t mask;
michael@0 387 int npixels;
michael@0 388 int i;
michael@0 389 mask=npixels=0;
michael@0 390 for(i=0;i<8;i++){
michael@0 391 int j;
michael@0 392 for(j=0;j<8;j++){
michael@0 393 if(x+j>=crop_x0&&x+j<crop_xf&&y+i>=crop_y0&&y+i<crop_yf){
michael@0 394 mask|=(ogg_int64_t)1<<(i<<3|j);
michael@0 395 npixels++;
michael@0 396 }
michael@0 397 }
michael@0 398 }
michael@0 399 /*Search the fragment array for border info with the same pattern.
michael@0 400 In general, there will be at most 8 different patterns (per
michael@0 401 plane).*/
michael@0 402 for(i=0;;i++){
michael@0 403 if(i>=_state->nborders){
michael@0 404 _state->nborders++;
michael@0 405 _state->borders[i].mask=mask;
michael@0 406 _state->borders[i].npixels=npixels;
michael@0 407 }
michael@0 408 else if(_state->borders[i].mask!=mask)continue;
michael@0 409 frag->borderi=i;
michael@0 410 break;
michael@0 411 }
michael@0 412 }
michael@0 413 else frag->borderi=-1;
michael@0 414 }
michael@0 415 }
michael@0 416 }
michael@0 417 }
michael@0 418
michael@0 419 static int oc_state_frarray_init(oc_theora_state *_state){
michael@0 420 int yhfrags;
michael@0 421 int yvfrags;
michael@0 422 int chfrags;
michael@0 423 int cvfrags;
michael@0 424 ptrdiff_t yfrags;
michael@0 425 ptrdiff_t cfrags;
michael@0 426 ptrdiff_t nfrags;
michael@0 427 unsigned yhsbs;
michael@0 428 unsigned yvsbs;
michael@0 429 unsigned chsbs;
michael@0 430 unsigned cvsbs;
michael@0 431 unsigned ysbs;
michael@0 432 unsigned csbs;
michael@0 433 unsigned nsbs;
michael@0 434 size_t nmbs;
michael@0 435 int hdec;
michael@0 436 int vdec;
michael@0 437 int pli;
michael@0 438 /*Figure out the number of fragments in each plane.*/
michael@0 439 /*These parameters have already been validated to be multiples of 16.*/
michael@0 440 yhfrags=_state->info.frame_width>>3;
michael@0 441 yvfrags=_state->info.frame_height>>3;
michael@0 442 hdec=!(_state->info.pixel_fmt&1);
michael@0 443 vdec=!(_state->info.pixel_fmt&2);
michael@0 444 chfrags=yhfrags+hdec>>hdec;
michael@0 445 cvfrags=yvfrags+vdec>>vdec;
michael@0 446 yfrags=yhfrags*(ptrdiff_t)yvfrags;
michael@0 447 cfrags=chfrags*(ptrdiff_t)cvfrags;
michael@0 448 nfrags=yfrags+2*cfrags;
michael@0 449 /*Figure out the number of super blocks in each plane.*/
michael@0 450 yhsbs=yhfrags+3>>2;
michael@0 451 yvsbs=yvfrags+3>>2;
michael@0 452 chsbs=chfrags+3>>2;
michael@0 453 cvsbs=cvfrags+3>>2;
michael@0 454 ysbs=yhsbs*yvsbs;
michael@0 455 csbs=chsbs*cvsbs;
michael@0 456 nsbs=ysbs+2*csbs;
michael@0 457 nmbs=(size_t)ysbs<<2;
michael@0 458 /*Check for overflow.
michael@0 459 We support the ridiculous upper limits of the specification (1048560 by
michael@0 460 1048560, or 3 TB frames) if the target architecture has 64-bit pointers,
michael@0 461 but for those with 32-bit pointers (or smaller!) we have to check.
michael@0 462 If the caller wants to prevent denial-of-service by imposing a more
michael@0 463 reasonable upper limit on the size of attempted allocations, they must do
michael@0 464 so themselves; we have no platform independent way to determine how much
michael@0 465 system memory there is nor an application-independent way to decide what a
michael@0 466 "reasonable" allocation is.*/
michael@0 467 if(yfrags/yhfrags!=yvfrags||2*cfrags<cfrags||nfrags<yfrags||
michael@0 468 ysbs/yhsbs!=yvsbs||2*csbs<csbs||nsbs<ysbs||nmbs>>2!=ysbs){
michael@0 469 return TH_EIMPL;
michael@0 470 }
michael@0 471 /*Initialize the fragment array.*/
michael@0 472 _state->fplanes[0].nhfrags=yhfrags;
michael@0 473 _state->fplanes[0].nvfrags=yvfrags;
michael@0 474 _state->fplanes[0].froffset=0;
michael@0 475 _state->fplanes[0].nfrags=yfrags;
michael@0 476 _state->fplanes[0].nhsbs=yhsbs;
michael@0 477 _state->fplanes[0].nvsbs=yvsbs;
michael@0 478 _state->fplanes[0].sboffset=0;
michael@0 479 _state->fplanes[0].nsbs=ysbs;
michael@0 480 _state->fplanes[1].nhfrags=_state->fplanes[2].nhfrags=chfrags;
michael@0 481 _state->fplanes[1].nvfrags=_state->fplanes[2].nvfrags=cvfrags;
michael@0 482 _state->fplanes[1].froffset=yfrags;
michael@0 483 _state->fplanes[2].froffset=yfrags+cfrags;
michael@0 484 _state->fplanes[1].nfrags=_state->fplanes[2].nfrags=cfrags;
michael@0 485 _state->fplanes[1].nhsbs=_state->fplanes[2].nhsbs=chsbs;
michael@0 486 _state->fplanes[1].nvsbs=_state->fplanes[2].nvsbs=cvsbs;
michael@0 487 _state->fplanes[1].sboffset=ysbs;
michael@0 488 _state->fplanes[2].sboffset=ysbs+csbs;
michael@0 489 _state->fplanes[1].nsbs=_state->fplanes[2].nsbs=csbs;
michael@0 490 _state->nfrags=nfrags;
michael@0 491 _state->frags=_ogg_calloc(nfrags,sizeof(*_state->frags));
michael@0 492 _state->frag_mvs=_ogg_malloc(nfrags*sizeof(*_state->frag_mvs));
michael@0 493 _state->nsbs=nsbs;
michael@0 494 _state->sb_maps=_ogg_malloc(nsbs*sizeof(*_state->sb_maps));
michael@0 495 _state->sb_flags=_ogg_calloc(nsbs,sizeof(*_state->sb_flags));
michael@0 496 _state->nhmbs=yhsbs<<1;
michael@0 497 _state->nvmbs=yvsbs<<1;
michael@0 498 _state->nmbs=nmbs;
michael@0 499 _state->mb_maps=_ogg_calloc(nmbs,sizeof(*_state->mb_maps));
michael@0 500 _state->mb_modes=_ogg_calloc(nmbs,sizeof(*_state->mb_modes));
michael@0 501 _state->coded_fragis=_ogg_malloc(nfrags*sizeof(*_state->coded_fragis));
michael@0 502 if(_state->frags==NULL||_state->frag_mvs==NULL||_state->sb_maps==NULL||
michael@0 503 _state->sb_flags==NULL||_state->mb_maps==NULL||_state->mb_modes==NULL||
michael@0 504 _state->coded_fragis==NULL){
michael@0 505 return TH_EFAULT;
michael@0 506 }
michael@0 507 /*Create the mapping from super blocks to fragments.*/
michael@0 508 for(pli=0;pli<3;pli++){
michael@0 509 oc_fragment_plane *fplane;
michael@0 510 fplane=_state->fplanes+pli;
michael@0 511 oc_sb_create_plane_mapping(_state->sb_maps+fplane->sboffset,
michael@0 512 _state->sb_flags+fplane->sboffset,fplane->froffset,
michael@0 513 fplane->nhfrags,fplane->nvfrags);
michael@0 514 }
michael@0 515 /*Create the mapping from macro blocks to fragments.*/
michael@0 516 oc_mb_create_mapping(_state->mb_maps,_state->mb_modes,
michael@0 517 _state->fplanes,_state->info.pixel_fmt);
michael@0 518 /*Initialize the invalid and borderi fields of each fragment.*/
michael@0 519 oc_state_border_init(_state);
michael@0 520 return 0;
michael@0 521 }
michael@0 522
michael@0 523 static void oc_state_frarray_clear(oc_theora_state *_state){
michael@0 524 _ogg_free(_state->coded_fragis);
michael@0 525 _ogg_free(_state->mb_modes);
michael@0 526 _ogg_free(_state->mb_maps);
michael@0 527 _ogg_free(_state->sb_flags);
michael@0 528 _ogg_free(_state->sb_maps);
michael@0 529 _ogg_free(_state->frag_mvs);
michael@0 530 _ogg_free(_state->frags);
michael@0 531 }
michael@0 532
michael@0 533
michael@0 534 /*Initializes the buffers used for reconstructed frames.
michael@0 535 These buffers are padded with 16 extra pixels on each side, to allow
michael@0 536 unrestricted motion vectors without special casing the boundary.
michael@0 537 If chroma is decimated in either direction, the padding is reduced by a
michael@0 538 factor of 2 on the appropriate sides.
michael@0 539 _nrefs: The number of reference buffers to init; must be in the range 3...6.*/
michael@0 540 static int oc_state_ref_bufs_init(oc_theora_state *_state,int _nrefs){
michael@0 541 th_info *info;
michael@0 542 unsigned char *ref_frame_data;
michael@0 543 size_t ref_frame_data_sz;
michael@0 544 size_t ref_frame_sz;
michael@0 545 size_t yplane_sz;
michael@0 546 size_t cplane_sz;
michael@0 547 int yhstride;
michael@0 548 int yheight;
michael@0 549 int chstride;
michael@0 550 int cheight;
michael@0 551 ptrdiff_t align;
michael@0 552 ptrdiff_t yoffset;
michael@0 553 ptrdiff_t coffset;
michael@0 554 ptrdiff_t *frag_buf_offs;
michael@0 555 ptrdiff_t fragi;
michael@0 556 int hdec;
michael@0 557 int vdec;
michael@0 558 int rfi;
michael@0 559 int pli;
michael@0 560 if(_nrefs<3||_nrefs>6)return TH_EINVAL;
michael@0 561 info=&_state->info;
michael@0 562 /*Compute the image buffer parameters for each plane.*/
michael@0 563 hdec=!(info->pixel_fmt&1);
michael@0 564 vdec=!(info->pixel_fmt&2);
michael@0 565 yhstride=info->frame_width+2*OC_UMV_PADDING;
michael@0 566 yheight=info->frame_height+2*OC_UMV_PADDING;
michael@0 567 /*Require 16-byte aligned rows in the chroma planes.*/
michael@0 568 chstride=(yhstride>>hdec)+15&~15;
michael@0 569 cheight=yheight>>vdec;
michael@0 570 yplane_sz=yhstride*(size_t)yheight;
michael@0 571 cplane_sz=chstride*(size_t)cheight;
michael@0 572 yoffset=OC_UMV_PADDING+OC_UMV_PADDING*(ptrdiff_t)yhstride;
michael@0 573 coffset=(OC_UMV_PADDING>>hdec)+(OC_UMV_PADDING>>vdec)*(ptrdiff_t)chstride;
michael@0 574 /*Although we guarantee the rows of the chroma planes are a multiple of 16
michael@0 575 bytes, the initial padding on the first row may only be 8 bytes.
michael@0 576 Compute the offset needed to the actual image data to a multiple of 16.*/
michael@0 577 align=-coffset&15;
michael@0 578 ref_frame_sz=yplane_sz+2*cplane_sz+16;
michael@0 579 ref_frame_data_sz=_nrefs*ref_frame_sz;
michael@0 580 /*Check for overflow.
michael@0 581 The same caveats apply as for oc_state_frarray_init().*/
michael@0 582 if(yplane_sz/yhstride!=(size_t)yheight||2*cplane_sz+16<cplane_sz||
michael@0 583 ref_frame_sz<yplane_sz||ref_frame_data_sz/_nrefs!=ref_frame_sz){
michael@0 584 return TH_EIMPL;
michael@0 585 }
michael@0 586 ref_frame_data=oc_aligned_malloc(ref_frame_data_sz,16);
michael@0 587 frag_buf_offs=_state->frag_buf_offs=
michael@0 588 _ogg_malloc(_state->nfrags*sizeof(*frag_buf_offs));
michael@0 589 if(ref_frame_data==NULL||frag_buf_offs==NULL){
michael@0 590 _ogg_free(frag_buf_offs);
michael@0 591 oc_aligned_free(ref_frame_data);
michael@0 592 return TH_EFAULT;
michael@0 593 }
michael@0 594 /*Set up the width, height and stride for the image buffers.*/
michael@0 595 _state->ref_frame_bufs[0][0].width=info->frame_width;
michael@0 596 _state->ref_frame_bufs[0][0].height=info->frame_height;
michael@0 597 _state->ref_frame_bufs[0][0].stride=yhstride;
michael@0 598 _state->ref_frame_bufs[0][1].width=_state->ref_frame_bufs[0][2].width=
michael@0 599 info->frame_width>>hdec;
michael@0 600 _state->ref_frame_bufs[0][1].height=_state->ref_frame_bufs[0][2].height=
michael@0 601 info->frame_height>>vdec;
michael@0 602 _state->ref_frame_bufs[0][1].stride=_state->ref_frame_bufs[0][2].stride=
michael@0 603 chstride;
michael@0 604 for(rfi=1;rfi<_nrefs;rfi++){
michael@0 605 memcpy(_state->ref_frame_bufs[rfi],_state->ref_frame_bufs[0],
michael@0 606 sizeof(_state->ref_frame_bufs[0]));
michael@0 607 }
michael@0 608 _state->ref_frame_handle=ref_frame_data;
michael@0 609 /*Set up the data pointers for the image buffers.*/
michael@0 610 for(rfi=0;rfi<_nrefs;rfi++){
michael@0 611 _state->ref_frame_bufs[rfi][0].data=ref_frame_data+yoffset;
michael@0 612 ref_frame_data+=yplane_sz+align;
michael@0 613 _state->ref_frame_bufs[rfi][1].data=ref_frame_data+coffset;
michael@0 614 ref_frame_data+=cplane_sz;
michael@0 615 _state->ref_frame_bufs[rfi][2].data=ref_frame_data+coffset;
michael@0 616 ref_frame_data+=cplane_sz+(16-align);
michael@0 617 /*Flip the buffer upside down.
michael@0 618 This allows us to decode Theora's bottom-up frames in their natural
michael@0 619 order, yet return a top-down buffer with a positive stride to the user.*/
michael@0 620 oc_ycbcr_buffer_flip(_state->ref_frame_bufs[rfi],
michael@0 621 _state->ref_frame_bufs[rfi]);
michael@0 622 }
michael@0 623 _state->ref_ystride[0]=-yhstride;
michael@0 624 _state->ref_ystride[1]=_state->ref_ystride[2]=-chstride;
michael@0 625 /*Initialize the fragment buffer offsets.*/
michael@0 626 ref_frame_data=_state->ref_frame_bufs[0][0].data;
michael@0 627 fragi=0;
michael@0 628 for(pli=0;pli<3;pli++){
michael@0 629 th_img_plane *iplane;
michael@0 630 oc_fragment_plane *fplane;
michael@0 631 unsigned char *vpix;
michael@0 632 ptrdiff_t stride;
michael@0 633 ptrdiff_t vfragi_end;
michael@0 634 int nhfrags;
michael@0 635 iplane=_state->ref_frame_bufs[0]+pli;
michael@0 636 fplane=_state->fplanes+pli;
michael@0 637 vpix=iplane->data;
michael@0 638 vfragi_end=fplane->froffset+fplane->nfrags;
michael@0 639 nhfrags=fplane->nhfrags;
michael@0 640 stride=iplane->stride;
michael@0 641 while(fragi<vfragi_end){
michael@0 642 ptrdiff_t hfragi_end;
michael@0 643 unsigned char *hpix;
michael@0 644 hpix=vpix;
michael@0 645 for(hfragi_end=fragi+nhfrags;fragi<hfragi_end;fragi++){
michael@0 646 frag_buf_offs[fragi]=hpix-ref_frame_data;
michael@0 647 hpix+=8;
michael@0 648 }
michael@0 649 vpix+=stride<<3;
michael@0 650 }
michael@0 651 }
michael@0 652 /*Initialize the reference frame pointers and indices.*/
michael@0 653 _state->ref_frame_idx[OC_FRAME_GOLD]=
michael@0 654 _state->ref_frame_idx[OC_FRAME_PREV]=
michael@0 655 _state->ref_frame_idx[OC_FRAME_GOLD_ORIG]=
michael@0 656 _state->ref_frame_idx[OC_FRAME_PREV_ORIG]=
michael@0 657 _state->ref_frame_idx[OC_FRAME_SELF]=
michael@0 658 _state->ref_frame_idx[OC_FRAME_IO]=-1;
michael@0 659 _state->ref_frame_data[OC_FRAME_GOLD]=
michael@0 660 _state->ref_frame_data[OC_FRAME_PREV]=
michael@0 661 _state->ref_frame_data[OC_FRAME_GOLD_ORIG]=
michael@0 662 _state->ref_frame_data[OC_FRAME_PREV_ORIG]=
michael@0 663 _state->ref_frame_data[OC_FRAME_SELF]=
michael@0 664 _state->ref_frame_data[OC_FRAME_IO]=NULL;
michael@0 665 return 0;
michael@0 666 }
michael@0 667
michael@0 668 static void oc_state_ref_bufs_clear(oc_theora_state *_state){
michael@0 669 _ogg_free(_state->frag_buf_offs);
michael@0 670 oc_aligned_free(_state->ref_frame_handle);
michael@0 671 }
michael@0 672
michael@0 673
michael@0 674 void oc_state_accel_init_c(oc_theora_state *_state){
michael@0 675 _state->cpu_flags=0;
michael@0 676 #if defined(OC_STATE_USE_VTABLE)
michael@0 677 _state->opt_vtable.frag_copy=oc_frag_copy_c;
michael@0 678 _state->opt_vtable.frag_copy_list=oc_frag_copy_list_c;
michael@0 679 _state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_c;
michael@0 680 _state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_c;
michael@0 681 _state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_c;
michael@0 682 _state->opt_vtable.idct8x8=oc_idct8x8_c;
michael@0 683 _state->opt_vtable.state_frag_recon=oc_state_frag_recon_c;
michael@0 684 _state->opt_vtable.loop_filter_init=oc_loop_filter_init_c;
michael@0 685 _state->opt_vtable.state_loop_filter_frag_rows=
michael@0 686 oc_state_loop_filter_frag_rows_c;
michael@0 687 _state->opt_vtable.restore_fpu=oc_restore_fpu_c;
michael@0 688 #endif
michael@0 689 _state->opt_data.dct_fzig_zag=OC_FZIG_ZAG;
michael@0 690 }
michael@0 691
michael@0 692
michael@0 693 int oc_state_init(oc_theora_state *_state,const th_info *_info,int _nrefs){
michael@0 694 int ret;
michael@0 695 /*First validate the parameters.*/
michael@0 696 if(_info==NULL)return TH_EFAULT;
michael@0 697 /*The width and height of the encoded frame must be multiples of 16.
michael@0 698 They must also, when divided by 16, fit into a 16-bit unsigned integer.
michael@0 699 The displayable frame offset coordinates must fit into an 8-bit unsigned
michael@0 700 integer.
michael@0 701 Note that the offset Y in the API is specified on the opposite side from
michael@0 702 how it is specified in the bitstream, because the Y axis is flipped in
michael@0 703 the bitstream.
michael@0 704 The displayable frame must fit inside the encoded frame.
michael@0 705 The color space must be one known by the encoder.*/
michael@0 706 if((_info->frame_width&0xF)||(_info->frame_height&0xF)||
michael@0 707 _info->frame_width<=0||_info->frame_width>=0x100000||
michael@0 708 _info->frame_height<=0||_info->frame_height>=0x100000||
michael@0 709 _info->pic_x+_info->pic_width>_info->frame_width||
michael@0 710 _info->pic_y+_info->pic_height>_info->frame_height||
michael@0 711 _info->pic_x>255||_info->frame_height-_info->pic_height-_info->pic_y>255||
michael@0 712 /*Note: the following <0 comparisons may generate spurious warnings on
michael@0 713 platforms where enums are unsigned.
michael@0 714 We could cast them to unsigned and just use the following >= comparison,
michael@0 715 but there are a number of compilers which will mis-optimize this.
michael@0 716 It's better to live with the spurious warnings.*/
michael@0 717 _info->colorspace<0||_info->colorspace>=TH_CS_NSPACES||
michael@0 718 _info->pixel_fmt<0||_info->pixel_fmt>=TH_PF_NFORMATS){
michael@0 719 return TH_EINVAL;
michael@0 720 }
michael@0 721 memset(_state,0,sizeof(*_state));
michael@0 722 memcpy(&_state->info,_info,sizeof(*_info));
michael@0 723 /*Invert the sense of pic_y to match Theora's right-handed coordinate
michael@0 724 system.*/
michael@0 725 _state->info.pic_y=_info->frame_height-_info->pic_height-_info->pic_y;
michael@0 726 _state->frame_type=OC_UNKWN_FRAME;
michael@0 727 oc_state_accel_init(_state);
michael@0 728 ret=oc_state_frarray_init(_state);
michael@0 729 if(ret>=0)ret=oc_state_ref_bufs_init(_state,_nrefs);
michael@0 730 if(ret<0){
michael@0 731 oc_state_frarray_clear(_state);
michael@0 732 return ret;
michael@0 733 }
michael@0 734 /*If the keyframe_granule_shift is out of range, use the maximum allowable
michael@0 735 value.*/
michael@0 736 if(_info->keyframe_granule_shift<0||_info->keyframe_granule_shift>31){
michael@0 737 _state->info.keyframe_granule_shift=31;
michael@0 738 }
michael@0 739 _state->keyframe_num=0;
michael@0 740 _state->curframe_num=-1;
michael@0 741 /*3.2.0 streams mark the frame index instead of the frame count.
michael@0 742 This was changed with stream version 3.2.1 to conform to other Ogg
michael@0 743 codecs.
michael@0 744 We add an extra bias when computing granule positions for new streams.*/
michael@0 745 _state->granpos_bias=TH_VERSION_CHECK(_info,3,2,1);
michael@0 746 return 0;
michael@0 747 }
michael@0 748
michael@0 749 void oc_state_clear(oc_theora_state *_state){
michael@0 750 oc_state_ref_bufs_clear(_state);
michael@0 751 oc_state_frarray_clear(_state);
michael@0 752 }
michael@0 753
michael@0 754
michael@0 755 /*Duplicates the pixels on the border of the image plane out into the
michael@0 756 surrounding padding for use by unrestricted motion vectors.
michael@0 757 This function only adds the left and right borders, and only for the fragment
michael@0 758 rows specified.
michael@0 759 _refi: The index of the reference buffer to pad.
michael@0 760 _pli: The color plane.
michael@0 761 _y0: The Y coordinate of the first row to pad.
michael@0 762 _yend: The Y coordinate of the row to stop padding at.*/
michael@0 763 void oc_state_borders_fill_rows(oc_theora_state *_state,int _refi,int _pli,
michael@0 764 int _y0,int _yend){
michael@0 765 th_img_plane *iplane;
michael@0 766 unsigned char *apix;
michael@0 767 unsigned char *bpix;
michael@0 768 unsigned char *epix;
michael@0 769 int stride;
michael@0 770 int hpadding;
michael@0 771 hpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&1));
michael@0 772 iplane=_state->ref_frame_bufs[_refi]+_pli;
michael@0 773 stride=iplane->stride;
michael@0 774 apix=iplane->data+_y0*(ptrdiff_t)stride;
michael@0 775 bpix=apix+iplane->width-1;
michael@0 776 epix=iplane->data+_yend*(ptrdiff_t)stride;
michael@0 777 /*Note the use of != instead of <, which allows the stride to be negative.*/
michael@0 778 while(apix!=epix){
michael@0 779 memset(apix-hpadding,apix[0],hpadding);
michael@0 780 memset(bpix+1,bpix[0],hpadding);
michael@0 781 apix+=stride;
michael@0 782 bpix+=stride;
michael@0 783 }
michael@0 784 }
michael@0 785
michael@0 786 /*Duplicates the pixels on the border of the image plane out into the
michael@0 787 surrounding padding for use by unrestricted motion vectors.
michael@0 788 This function only adds the top and bottom borders, and must be called after
michael@0 789 the left and right borders are added.
michael@0 790 _refi: The index of the reference buffer to pad.
michael@0 791 _pli: The color plane.*/
michael@0 792 void oc_state_borders_fill_caps(oc_theora_state *_state,int _refi,int _pli){
michael@0 793 th_img_plane *iplane;
michael@0 794 unsigned char *apix;
michael@0 795 unsigned char *bpix;
michael@0 796 unsigned char *epix;
michael@0 797 int stride;
michael@0 798 int hpadding;
michael@0 799 int vpadding;
michael@0 800 int fullw;
michael@0 801 hpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&1));
michael@0 802 vpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&2));
michael@0 803 iplane=_state->ref_frame_bufs[_refi]+_pli;
michael@0 804 stride=iplane->stride;
michael@0 805 fullw=iplane->width+(hpadding<<1);
michael@0 806 apix=iplane->data-hpadding;
michael@0 807 bpix=iplane->data+(iplane->height-1)*(ptrdiff_t)stride-hpadding;
michael@0 808 epix=apix-stride*(ptrdiff_t)vpadding;
michael@0 809 while(apix!=epix){
michael@0 810 memcpy(apix-stride,apix,fullw);
michael@0 811 memcpy(bpix+stride,bpix,fullw);
michael@0 812 apix-=stride;
michael@0 813 bpix+=stride;
michael@0 814 }
michael@0 815 }
michael@0 816
michael@0 817 /*Duplicates the pixels on the border of the given reference image out into
michael@0 818 the surrounding padding for use by unrestricted motion vectors.
michael@0 819 _state: The context containing the reference buffers.
michael@0 820 _refi: The index of the reference buffer to pad.*/
michael@0 821 void oc_state_borders_fill(oc_theora_state *_state,int _refi){
michael@0 822 int pli;
michael@0 823 for(pli=0;pli<3;pli++){
michael@0 824 oc_state_borders_fill_rows(_state,_refi,pli,0,
michael@0 825 _state->ref_frame_bufs[_refi][pli].height);
michael@0 826 oc_state_borders_fill_caps(_state,_refi,pli);
michael@0 827 }
michael@0 828 }
michael@0 829
michael@0 830 /*Determines the offsets in an image buffer to use for motion compensation.
michael@0 831 _state: The Theora state the offsets are to be computed with.
michael@0 832 _offsets: Returns the offset for the buffer(s).
michael@0 833 _offsets[0] is always set.
michael@0 834 _offsets[1] is set if the motion vector has non-zero fractional
michael@0 835 components.
michael@0 836 _pli: The color plane index.
michael@0 837 _mv: The motion vector.
michael@0 838 Return: The number of offsets returned: 1 or 2.*/
michael@0 839 int oc_state_get_mv_offsets(const oc_theora_state *_state,int _offsets[2],
michael@0 840 int _pli,oc_mv _mv){
michael@0 841 /*Here is a brief description of how Theora handles motion vectors:
michael@0 842 Motion vector components are specified to half-pixel accuracy in
michael@0 843 undecimated directions of each plane, and quarter-pixel accuracy in
michael@0 844 decimated directions.
michael@0 845 Integer parts are extracted by dividing (not shifting) by the
michael@0 846 appropriate amount, with truncation towards zero.
michael@0 847 These integer values are used to calculate the first offset.
michael@0 848
michael@0 849 If either of the fractional parts are non-zero, then a second offset is
michael@0 850 computed.
michael@0 851 No third or fourth offsets are computed, even if both components have
michael@0 852 non-zero fractional parts.
michael@0 853 The second offset is computed by dividing (not shifting) by the
michael@0 854 appropriate amount, always truncating _away_ from zero.*/
michael@0 855 #if 0
michael@0 856 /*This version of the code doesn't use any tables, but is slower.*/
michael@0 857 int ystride;
michael@0 858 int xprec;
michael@0 859 int yprec;
michael@0 860 int xfrac;
michael@0 861 int yfrac;
michael@0 862 int offs;
michael@0 863 int dx;
michael@0 864 int dy;
michael@0 865 ystride=_state->ref_ystride[_pli];
michael@0 866 /*These two variables decide whether we are in half- or quarter-pixel
michael@0 867 precision in each component.*/
michael@0 868 xprec=1+(_pli!=0&&!(_state->info.pixel_fmt&1));
michael@0 869 yprec=1+(_pli!=0&&!(_state->info.pixel_fmt&2));
michael@0 870 dx=OC_MV_X(_mv);
michael@0 871 dy=OC_MV_Y(_mv);
michael@0 872 /*These two variables are either 0 if all the fractional bits are zero or -1
michael@0 873 if any of them are non-zero.*/
michael@0 874 xfrac=OC_SIGNMASK(-(dx&(xprec|1)));
michael@0 875 yfrac=OC_SIGNMASK(-(dy&(yprec|1)));
michael@0 876 offs=(dx>>xprec)+(dy>>yprec)*ystride;
michael@0 877 if(xfrac||yfrac){
michael@0 878 int xmask;
michael@0 879 int ymask;
michael@0 880 xmask=OC_SIGNMASK(dx);
michael@0 881 ymask=OC_SIGNMASK(dy);
michael@0 882 yfrac&=ystride;
michael@0 883 _offsets[0]=offs-(xfrac&xmask)+(yfrac&ymask);
michael@0 884 _offsets[1]=offs-(xfrac&~xmask)+(yfrac&~ymask);
michael@0 885 return 2;
michael@0 886 }
michael@0 887 else{
michael@0 888 _offsets[0]=offs;
michael@0 889 return 1;
michael@0 890 }
michael@0 891 #else
michael@0 892 /*Using tables simplifies the code, and there's enough arithmetic to hide the
michael@0 893 latencies of the memory references.*/
michael@0 894 static const signed char OC_MVMAP[2][64]={
michael@0 895 {
michael@0 896 -15,-15,-14,-14,-13,-13,-12,-12,-11,-11,-10,-10, -9, -9, -8,
michael@0 897 -8, -7, -7, -6, -6, -5, -5, -4, -4, -3, -3, -2, -2, -1, -1, 0,
michael@0 898 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
michael@0 899 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15
michael@0 900 },
michael@0 901 {
michael@0 902 -7, -7, -7, -7, -6, -6, -6, -6, -5, -5, -5, -5, -4, -4, -4,
michael@0 903 -4, -3, -3, -3, -3, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0,
michael@0 904 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
michael@0 905 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7
michael@0 906 }
michael@0 907 };
michael@0 908 static const signed char OC_MVMAP2[2][64]={
michael@0 909 {
michael@0 910 -1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1,
michael@0 911 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1,
michael@0 912 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
michael@0 913 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
michael@0 914 },
michael@0 915 {
michael@0 916 -1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1,
michael@0 917 0,-1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1,
michael@0 918 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
michael@0 919 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
michael@0 920 }
michael@0 921 };
michael@0 922 int ystride;
michael@0 923 int qpx;
michael@0 924 int qpy;
michael@0 925 int mx;
michael@0 926 int my;
michael@0 927 int mx2;
michael@0 928 int my2;
michael@0 929 int offs;
michael@0 930 int dx;
michael@0 931 int dy;
michael@0 932 ystride=_state->ref_ystride[_pli];
michael@0 933 qpy=_pli!=0&&!(_state->info.pixel_fmt&2);
michael@0 934 dx=OC_MV_X(_mv);
michael@0 935 dy=OC_MV_Y(_mv);
michael@0 936 my=OC_MVMAP[qpy][dy+31];
michael@0 937 my2=OC_MVMAP2[qpy][dy+31];
michael@0 938 qpx=_pli!=0&&!(_state->info.pixel_fmt&1);
michael@0 939 mx=OC_MVMAP[qpx][dx+31];
michael@0 940 mx2=OC_MVMAP2[qpx][dx+31];
michael@0 941 offs=my*ystride+mx;
michael@0 942 if(mx2||my2){
michael@0 943 _offsets[1]=offs+my2*ystride+mx2;
michael@0 944 _offsets[0]=offs;
michael@0 945 return 2;
michael@0 946 }
michael@0 947 _offsets[0]=offs;
michael@0 948 return 1;
michael@0 949 #endif
michael@0 950 }
michael@0 951
michael@0 952 void oc_state_frag_recon_c(const oc_theora_state *_state,ptrdiff_t _fragi,
michael@0 953 int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
michael@0 954 unsigned char *dst;
michael@0 955 ptrdiff_t frag_buf_off;
michael@0 956 int ystride;
michael@0 957 int refi;
michael@0 958 /*Apply the inverse transform.*/
michael@0 959 /*Special case only having a DC component.*/
michael@0 960 if(_last_zzi<2){
michael@0 961 ogg_int16_t p;
michael@0 962 int ci;
michael@0 963 /*We round this dequant product (and not any of the others) because there's
michael@0 964 no iDCT rounding.*/
michael@0 965 p=(ogg_int16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
michael@0 966 /*LOOP VECTORIZES.*/
michael@0 967 for(ci=0;ci<64;ci++)_dct_coeffs[64+ci]=p;
michael@0 968 }
michael@0 969 else{
michael@0 970 /*First, dequantize the DC coefficient.*/
michael@0 971 _dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
michael@0 972 oc_idct8x8(_state,_dct_coeffs+64,_dct_coeffs,_last_zzi);
michael@0 973 }
michael@0 974 /*Fill in the target buffer.*/
michael@0 975 frag_buf_off=_state->frag_buf_offs[_fragi];
michael@0 976 refi=_state->frags[_fragi].refi;
michael@0 977 ystride=_state->ref_ystride[_pli];
michael@0 978 dst=_state->ref_frame_data[OC_FRAME_SELF]+frag_buf_off;
michael@0 979 if(refi==OC_FRAME_SELF)oc_frag_recon_intra(_state,dst,ystride,_dct_coeffs+64);
michael@0 980 else{
michael@0 981 const unsigned char *ref;
michael@0 982 int mvoffsets[2];
michael@0 983 ref=_state->ref_frame_data[refi]+frag_buf_off;
michael@0 984 if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
michael@0 985 _state->frag_mvs[_fragi])>1){
michael@0 986 oc_frag_recon_inter2(_state,
michael@0 987 dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,_dct_coeffs+64);
michael@0 988 }
michael@0 989 else{
michael@0 990 oc_frag_recon_inter(_state,dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
michael@0 991 }
michael@0 992 }
michael@0 993 }
michael@0 994
michael@0 995 static void loop_filter_h(unsigned char *_pix,int _ystride,signed char *_bv){
michael@0 996 int y;
michael@0 997 _pix-=2;
michael@0 998 for(y=0;y<8;y++){
michael@0 999 int f;
michael@0 1000 f=_pix[0]-_pix[3]+3*(_pix[2]-_pix[1]);
michael@0 1001 /*The _bv array is used to compute the function
michael@0 1002 f=OC_CLAMPI(OC_MINI(-_2flimit-f,0),f,OC_MAXI(_2flimit-f,0));
michael@0 1003 where _2flimit=_state->loop_filter_limits[_state->qis[0]]<<1;*/
michael@0 1004 f=*(_bv+(f+4>>3));
michael@0 1005 _pix[1]=OC_CLAMP255(_pix[1]+f);
michael@0 1006 _pix[2]=OC_CLAMP255(_pix[2]-f);
michael@0 1007 _pix+=_ystride;
michael@0 1008 }
michael@0 1009 }
michael@0 1010
michael@0 1011 static void loop_filter_v(unsigned char *_pix,int _ystride,signed char *_bv){
michael@0 1012 int x;
michael@0 1013 _pix-=_ystride*2;
michael@0 1014 for(x=0;x<8;x++){
michael@0 1015 int f;
michael@0 1016 f=_pix[x]-_pix[_ystride*3+x]+3*(_pix[_ystride*2+x]-_pix[_ystride+x]);
michael@0 1017 /*The _bv array is used to compute the function
michael@0 1018 f=OC_CLAMPI(OC_MINI(-_2flimit-f,0),f,OC_MAXI(_2flimit-f,0));
michael@0 1019 where _2flimit=_state->loop_filter_limits[_state->qis[0]]<<1;*/
michael@0 1020 f=*(_bv+(f+4>>3));
michael@0 1021 _pix[_ystride+x]=OC_CLAMP255(_pix[_ystride+x]+f);
michael@0 1022 _pix[_ystride*2+x]=OC_CLAMP255(_pix[_ystride*2+x]-f);
michael@0 1023 }
michael@0 1024 }
michael@0 1025
michael@0 1026 /*Initialize the bounding values array used by the loop filter.
michael@0 1027 _bv: Storage for the array.
michael@0 1028 _flimit: The filter limit as defined in Section 7.10 of the spec.*/
michael@0 1029 void oc_loop_filter_init_c(signed char _bv[256],int _flimit){
michael@0 1030 int i;
michael@0 1031 memset(_bv,0,sizeof(_bv[0])*256);
michael@0 1032 for(i=0;i<_flimit;i++){
michael@0 1033 if(127-i-_flimit>=0)_bv[127-i-_flimit]=(signed char)(i-_flimit);
michael@0 1034 _bv[127-i]=(signed char)(-i);
michael@0 1035 _bv[127+i]=(signed char)(i);
michael@0 1036 if(127+i+_flimit<256)_bv[127+i+_flimit]=(signed char)(_flimit-i);
michael@0 1037 }
michael@0 1038 }
michael@0 1039
michael@0 1040 /*Apply the loop filter to a given set of fragment rows in the given plane.
michael@0 1041 The filter may be run on the bottom edge, affecting pixels in the next row of
michael@0 1042 fragments, so this row also needs to be available.
michael@0 1043 _bv: The bounding values array.
michael@0 1044 _refi: The index of the frame buffer to filter.
michael@0 1045 _pli: The color plane to filter.
michael@0 1046 _fragy0: The Y coordinate of the first fragment row to filter.
michael@0 1047 _fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
michael@0 1048 void oc_state_loop_filter_frag_rows_c(const oc_theora_state *_state,
michael@0 1049 signed char *_bv,int _refi,int _pli,int _fragy0,int _fragy_end){
michael@0 1050 const oc_fragment_plane *fplane;
michael@0 1051 const oc_fragment *frags;
michael@0 1052 const ptrdiff_t *frag_buf_offs;
michael@0 1053 unsigned char *ref_frame_data;
michael@0 1054 ptrdiff_t fragi_top;
michael@0 1055 ptrdiff_t fragi_bot;
michael@0 1056 ptrdiff_t fragi0;
michael@0 1057 ptrdiff_t fragi0_end;
michael@0 1058 int ystride;
michael@0 1059 int nhfrags;
michael@0 1060 _bv+=127;
michael@0 1061 fplane=_state->fplanes+_pli;
michael@0 1062 nhfrags=fplane->nhfrags;
michael@0 1063 fragi_top=fplane->froffset;
michael@0 1064 fragi_bot=fragi_top+fplane->nfrags;
michael@0 1065 fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
michael@0 1066 fragi0_end=fragi_top+_fragy_end*(ptrdiff_t)nhfrags;
michael@0 1067 ystride=_state->ref_ystride[_pli];
michael@0 1068 frags=_state->frags;
michael@0 1069 frag_buf_offs=_state->frag_buf_offs;
michael@0 1070 ref_frame_data=_state->ref_frame_data[_refi];
michael@0 1071 /*The following loops are constructed somewhat non-intuitively on purpose.
michael@0 1072 The main idea is: if a block boundary has at least one coded fragment on
michael@0 1073 it, the filter is applied to it.
michael@0 1074 However, the order that the filters are applied in matters, and VP3 chose
michael@0 1075 the somewhat strange ordering used below.*/
michael@0 1076 while(fragi0<fragi0_end){
michael@0 1077 ptrdiff_t fragi;
michael@0 1078 ptrdiff_t fragi_end;
michael@0 1079 fragi=fragi0;
michael@0 1080 fragi_end=fragi+nhfrags;
michael@0 1081 while(fragi<fragi_end){
michael@0 1082 if(frags[fragi].coded){
michael@0 1083 unsigned char *ref;
michael@0 1084 ref=ref_frame_data+frag_buf_offs[fragi];
michael@0 1085 if(fragi>fragi0)loop_filter_h(ref,ystride,_bv);
michael@0 1086 if(fragi0>fragi_top)loop_filter_v(ref,ystride,_bv);
michael@0 1087 if(fragi+1<fragi_end&&!frags[fragi+1].coded){
michael@0 1088 loop_filter_h(ref+8,ystride,_bv);
michael@0 1089 }
michael@0 1090 if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
michael@0 1091 loop_filter_v(ref+(ystride<<3),ystride,_bv);
michael@0 1092 }
michael@0 1093 }
michael@0 1094 fragi++;
michael@0 1095 }
michael@0 1096 fragi0+=nhfrags;
michael@0 1097 }
michael@0 1098 }
michael@0 1099
michael@0 1100 #if defined(OC_DUMP_IMAGES)
michael@0 1101 int oc_state_dump_frame(const oc_theora_state *_state,int _frame,
michael@0 1102 const char *_suf){
michael@0 1103 /*Dump a PNG of the reconstructed image.*/
michael@0 1104 png_structp png;
michael@0 1105 png_infop info;
michael@0 1106 png_bytep *image;
michael@0 1107 FILE *fp;
michael@0 1108 char fname[16];
michael@0 1109 unsigned char *y_row;
michael@0 1110 unsigned char *u_row;
michael@0 1111 unsigned char *v_row;
michael@0 1112 unsigned char *y;
michael@0 1113 unsigned char *u;
michael@0 1114 unsigned char *v;
michael@0 1115 ogg_int64_t iframe;
michael@0 1116 ogg_int64_t pframe;
michael@0 1117 int y_stride;
michael@0 1118 int u_stride;
michael@0 1119 int v_stride;
michael@0 1120 int framei;
michael@0 1121 int width;
michael@0 1122 int height;
michael@0 1123 int imgi;
michael@0 1124 int imgj;
michael@0 1125 width=_state->info.frame_width;
michael@0 1126 height=_state->info.frame_height;
michael@0 1127 iframe=_state->granpos>>_state->info.keyframe_granule_shift;
michael@0 1128 pframe=_state->granpos-(iframe<<_state->info.keyframe_granule_shift);
michael@0 1129 sprintf(fname,"%08i%s.png",(int)(iframe+pframe),_suf);
michael@0 1130 fp=fopen(fname,"wb");
michael@0 1131 if(fp==NULL)return TH_EFAULT;
michael@0 1132 image=(png_bytep *)oc_malloc_2d(height,6*width,sizeof(**image));
michael@0 1133 if(image==NULL){
michael@0 1134 fclose(fp);
michael@0 1135 return TH_EFAULT;
michael@0 1136 }
michael@0 1137 png=png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
michael@0 1138 if(png==NULL){
michael@0 1139 oc_free_2d(image);
michael@0 1140 fclose(fp);
michael@0 1141 return TH_EFAULT;
michael@0 1142 }
michael@0 1143 info=png_create_info_struct(png);
michael@0 1144 if(info==NULL){
michael@0 1145 png_destroy_write_struct(&png,NULL);
michael@0 1146 oc_free_2d(image);
michael@0 1147 fclose(fp);
michael@0 1148 return TH_EFAULT;
michael@0 1149 }
michael@0 1150 if(setjmp(png_jmpbuf(png))){
michael@0 1151 png_destroy_write_struct(&png,&info);
michael@0 1152 oc_free_2d(image);
michael@0 1153 fclose(fp);
michael@0 1154 return TH_EFAULT;
michael@0 1155 }
michael@0 1156 framei=_state->ref_frame_idx[_frame];
michael@0 1157 y_row=_state->ref_frame_bufs[framei][0].data;
michael@0 1158 u_row=_state->ref_frame_bufs[framei][1].data;
michael@0 1159 v_row=_state->ref_frame_bufs[framei][2].data;
michael@0 1160 y_stride=_state->ref_frame_bufs[framei][0].stride;
michael@0 1161 u_stride=_state->ref_frame_bufs[framei][1].stride;
michael@0 1162 v_stride=_state->ref_frame_bufs[framei][2].stride;
michael@0 1163 /*Chroma up-sampling is just done with a box filter.
michael@0 1164 This is very likely what will actually be used in practice on a real
michael@0 1165 display, and also removes one more layer to search in for the source of
michael@0 1166 artifacts.
michael@0 1167 As an added bonus, it's dead simple.*/
michael@0 1168 for(imgi=height;imgi-->0;){
michael@0 1169 int dc;
michael@0 1170 y=y_row;
michael@0 1171 u=u_row;
michael@0 1172 v=v_row;
michael@0 1173 for(imgj=0;imgj<6*width;){
michael@0 1174 float yval;
michael@0 1175 float uval;
michael@0 1176 float vval;
michael@0 1177 unsigned rval;
michael@0 1178 unsigned gval;
michael@0 1179 unsigned bval;
michael@0 1180 /*This is intentionally slow and very accurate.*/
michael@0 1181 yval=(*y-16)*(1.0F/219);
michael@0 1182 uval=(*u-128)*(2*(1-0.114F)/224);
michael@0 1183 vval=(*v-128)*(2*(1-0.299F)/224);
michael@0 1184 rval=OC_CLAMPI(0,(int)(65535*(yval+vval)+0.5F),65535);
michael@0 1185 gval=OC_CLAMPI(0,(int)(65535*(
michael@0 1186 yval-uval*(0.114F/0.587F)-vval*(0.299F/0.587F))+0.5F),65535);
michael@0 1187 bval=OC_CLAMPI(0,(int)(65535*(yval+uval)+0.5F),65535);
michael@0 1188 image[imgi][imgj++]=(unsigned char)(rval>>8);
michael@0 1189 image[imgi][imgj++]=(unsigned char)(rval&0xFF);
michael@0 1190 image[imgi][imgj++]=(unsigned char)(gval>>8);
michael@0 1191 image[imgi][imgj++]=(unsigned char)(gval&0xFF);
michael@0 1192 image[imgi][imgj++]=(unsigned char)(bval>>8);
michael@0 1193 image[imgi][imgj++]=(unsigned char)(bval&0xFF);
michael@0 1194 dc=(y-y_row&1)|(_state->info.pixel_fmt&1);
michael@0 1195 y++;
michael@0 1196 u+=dc;
michael@0 1197 v+=dc;
michael@0 1198 }
michael@0 1199 dc=-((height-1-imgi&1)|_state->info.pixel_fmt>>1);
michael@0 1200 y_row+=y_stride;
michael@0 1201 u_row+=dc&u_stride;
michael@0 1202 v_row+=dc&v_stride;
michael@0 1203 }
michael@0 1204 png_init_io(png,fp);
michael@0 1205 png_set_compression_level(png,Z_BEST_COMPRESSION);
michael@0 1206 png_set_IHDR(png,info,width,height,16,PNG_COLOR_TYPE_RGB,
michael@0 1207 PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
michael@0 1208 switch(_state->info.colorspace){
michael@0 1209 case TH_CS_ITU_REC_470M:{
michael@0 1210 png_set_gAMA(png,info,2.2);
michael@0 1211 png_set_cHRM_fixed(png,info,31006,31616,
michael@0 1212 67000,32000,21000,71000,14000,8000);
michael@0 1213 }break;
michael@0 1214 case TH_CS_ITU_REC_470BG:{
michael@0 1215 png_set_gAMA(png,info,2.67);
michael@0 1216 png_set_cHRM_fixed(png,info,31271,32902,
michael@0 1217 64000,33000,29000,60000,15000,6000);
michael@0 1218 }break;
michael@0 1219 default:break;
michael@0 1220 }
michael@0 1221 png_set_pHYs(png,info,_state->info.aspect_numerator,
michael@0 1222 _state->info.aspect_denominator,0);
michael@0 1223 png_set_rows(png,info,image);
michael@0 1224 png_write_png(png,info,PNG_TRANSFORM_IDENTITY,NULL);
michael@0 1225 png_write_end(png,info);
michael@0 1226 png_destroy_write_struct(&png,&info);
michael@0 1227 oc_free_2d(image);
michael@0 1228 fclose(fp);
michael@0 1229 return 0;
michael@0 1230 }
michael@0 1231 #endif
michael@0 1232
michael@0 1233
michael@0 1234
michael@0 1235 ogg_int64_t th_granule_frame(void *_encdec,ogg_int64_t _granpos){
michael@0 1236 oc_theora_state *state;
michael@0 1237 state=(oc_theora_state *)_encdec;
michael@0 1238 if(_granpos>=0){
michael@0 1239 ogg_int64_t iframe;
michael@0 1240 ogg_int64_t pframe;
michael@0 1241 iframe=_granpos>>state->info.keyframe_granule_shift;
michael@0 1242 pframe=_granpos-(iframe<<state->info.keyframe_granule_shift);
michael@0 1243 /*3.2.0 streams store the frame index in the granule position.
michael@0 1244 3.2.1 and later store the frame count.
michael@0 1245 We return the index, so adjust the value if we have a 3.2.1 or later
michael@0 1246 stream.*/
michael@0 1247 return iframe+pframe-TH_VERSION_CHECK(&state->info,3,2,1);
michael@0 1248 }
michael@0 1249 return -1;
michael@0 1250 }
michael@0 1251
michael@0 1252 double th_granule_time(void *_encdec,ogg_int64_t _granpos){
michael@0 1253 oc_theora_state *state;
michael@0 1254 state=(oc_theora_state *)_encdec;
michael@0 1255 if(_granpos>=0){
michael@0 1256 return (th_granule_frame(_encdec, _granpos)+1)*(
michael@0 1257 (double)state->info.fps_denominator/state->info.fps_numerator);
michael@0 1258 }
michael@0 1259 return -1;
michael@0 1260 }

mercurial