/******************************************************************** * * * 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-2009 * * by the Xiph.Org Foundation http://www.xiph.org/ * * * ******************************************************************** function: routines for validating encoder granulepos generation last mod: $Id: granulepos.c 16503 2009-08-22 18:14:02Z giles $ ********************************************************************/ #include #include #include #include "tests.h" static int ilog(unsigned int v){ int ret=0; while(v){ ret++; v>>=1; } return(ret); } static int granulepos_test_encode (int frequency) { th_info ti; th_enc_ctx *te; int result; int frame, tframe, keyframe, keydist; int shift; double rate, ttime; th_ycbcr_buffer yuv; unsigned char *framedata; ogg_packet op; long long int last_granule = -1; /* INFO ("+ Initializing th_info struct"); */ th_info_init (&ti); ti.frame_width = 32; ti.frame_height = 32; ti.pic_width = ti.frame_width; ti.pic_height = ti.frame_height; ti.pic_x = 0; ti.pic_y = 0; ti.fps_numerator = 16; ti.fps_denominator = 1; ti.aspect_numerator = 1; ti.aspect_denominator = 1; ti.colorspace = TH_CS_UNSPECIFIED; ti.pixel_fmt = TH_PF_420; ti.quality = 16; ti.keyframe_granule_shift=ilog(frequency); /* INFO ("+ Allocating encoder context"); */ te = th_encode_alloc(&ti); if (te == NULL) { INFO ("+ Clearing th_info"); th_info_clear(&ti); FAIL ("negative return code initializing encoder"); } /* INFO ("+ Setting up dummy 4:2:0 frame data"); */ framedata = calloc(ti.frame_height, ti.frame_width); yuv[0].width = ti.frame_width; yuv[0].height = ti.frame_height; yuv[0].stride = ti.frame_width; yuv[0].data = framedata; yuv[1].width = ti.frame_width / 2; yuv[1].height = ti.frame_width / 2; yuv[1].stride = ti.frame_width; yuv[1].data = framedata; yuv[2].width = ti.frame_width / 2; yuv[2].height = ti.frame_width / 2; yuv[2].stride = ti.frame_width; yuv[2].data = framedata; INFO ("+ Checking granulepos generation"); shift = ti.keyframe_granule_shift; rate = (double)ti.fps_denominator/ti.fps_numerator; for (frame = 0; frame < frequency * 2 + 1; frame++) { result = th_encode_ycbcr_in (te, yuv); if (result < 0) { printf("th_encode_ycbcr_in() returned %d\n", result); FAIL ("negative error code submitting frame for compression"); } result = th_encode_packetout (te, frame >= frequency * 2, &op); if (result <= 0) { printf("th_encode_packetout() returned %d\n", result); FAIL("failed to retrieve compressed frame"); } if ((long long int)op.granulepos < last_granule) FAIL ("encoder returned a decreasing granulepos value"); last_granule = op.granulepos; keyframe = op.granulepos >> shift; keydist = op.granulepos - (keyframe << shift); tframe = th_granule_frame (te, op.granulepos); ttime = th_granule_time(te, op.granulepos); #if DEBUG printf("++ frame %d granulepos %lld %d:%d %d %.3lfs\n", frame, (long long int)op.granulepos, keyframe, keydist, tframe, th_granule_time (te, op.granulepos)); #endif /* granulepos stores the frame count */ if ((keyframe + keydist) != frame + 1) FAIL ("encoder granulepos does not map to the correct frame number"); /* th_granule_frame() returns the frame index */ if (tframe != frame) FAIL ("th_granule_frame() returned incorrect results"); /* th_granule_time() returns the end time */ if (fabs(rate*(frame+1) - ttime) > 1.0e-6) FAIL ("th_granule_time() returned incorrect results"); } /* clean up */ /* INFO ("+ Freeing dummy frame data"); */ free(framedata); /* INFO ("+ Clearing th_info struct"); */ th_info_clear(&ti); /* INFO ("+ Freeing encoder context"); */ th_encode_free(te); return 0; } int main(int argc, char *argv[]) { granulepos_test_encode (1); granulepos_test_encode (2); granulepos_test_encode (3); granulepos_test_encode (4); granulepos_test_encode (8); granulepos_test_encode (64); exit (0); }