Copy Derf's experimental ptalarbvorm branch to trunk.
[theora.git] / tests / granulepos.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13   function: routines for validating encoder granulepos generation
14   last mod: $Id$
15
16  ********************************************************************/
17
18 #include <stdlib.h>
19 #include <theora/theoraenc.h>
20 #include <math.h>
21
22 #include "tests.h"
23
24 static int ilog(unsigned int v){
25   int ret=0;
26   while(v){
27     ret++;
28     v>>=1;
29   }
30   return(ret);
31 }
32
33 static int
34 granulepos_test_encode (int frequency)
35 {
36   th_info ti;
37   th_enc_ctx *te;
38   int result;
39   int frame, tframe, keyframe, keydist;
40   int shift;
41   double rate, ttime;
42   th_ycbcr_buffer yuv;
43   unsigned char *framedata;
44   ogg_packet op;
45   long long int last_granule = -1;
46
47 /*  INFO ("+ Initializing th_info struct"); */
48   th_info_init (&ti);
49
50   ti.frame_width = 32;
51   ti.frame_height = 32;
52   ti.pic_width = ti.frame_width;
53   ti.pic_height = ti.frame_height;
54   ti.pic_x = 0;
55   ti.pic_y = 0;
56   ti.fps_numerator = 16;
57   ti.fps_denominator = 1;
58   ti.aspect_numerator = 1;
59   ti.aspect_denominator = 1;
60   ti.colorspace = TH_CS_UNSPECIFIED;
61   ti.pixel_fmt = TH_PF_420;
62   ti.quality = 16;
63   ti.keyframe_granule_shift=ilog(frequency);
64
65 /*  INFO ("+ Allocating encoder context"); */
66   te = th_encode_alloc(&ti);
67   if (te == NULL) {
68     INFO ("+ Clearing th_info");
69     th_info_clear(&ti);
70     FAIL ("negative return code initializing encoder");
71   }
72
73 /*  INFO ("+ Setting up dummy 4:2:0 frame data"); */
74   framedata = calloc(ti.frame_height, ti.frame_width);
75   yuv[0].width = ti.frame_width;
76   yuv[0].height = ti.frame_height;
77   yuv[0].stride = ti.frame_width;
78   yuv[0].data = framedata;
79   yuv[1].width = ti.frame_width / 2;
80   yuv[1].height = ti.frame_width / 2;
81   yuv[1].stride = ti.frame_width;
82   yuv[1].data = framedata;
83   yuv[2].width = ti.frame_width / 2;
84   yuv[2].height = ti.frame_width / 2;
85   yuv[2].stride = ti.frame_width;
86   yuv[2].data = framedata;
87
88   INFO ("+ Checking granulepos generation");
89   shift = ti.keyframe_granule_shift;
90   rate = (double)ti.fps_denominator/ti.fps_numerator;
91   for (frame = 0; frame < frequency * 2 + 1; frame++) {
92     result = th_encode_ycbcr_in (te, yuv);
93     if (result < 0) {
94       printf("th_encode_ycbcr_in() returned %d\n", result);
95       FAIL ("negative error code submitting frame for compression");
96     }
97     result = th_encode_packetout (te, frame >= frequency * 2, &op);
98     if (result <= 0) {
99       printf("th_encode_packetout() returned %d\n", result);
100       FAIL("failed to retrieve compressed frame");
101     }
102     if ((long long int)op.granulepos < last_granule)
103       FAIL ("encoder returned a decreasing granulepos value");
104     last_granule = op.granulepos;
105     keyframe = op.granulepos >> shift;
106     keydist = op.granulepos - (keyframe << shift);
107     tframe = th_granule_frame (te, op.granulepos);
108     ttime = th_granule_time(te, op.granulepos);
109 #if DEBUG
110     printf("++ frame %d granulepos %lld %d:%d %d %.3lfs\n",
111         frame, (long long int)op.granulepos, keyframe, keydist,
112         tframe, th_granule_time (te, op.granulepos));
113 #endif
114     /* granulepos stores the frame count */
115     if ((keyframe + keydist) != frame + 1)
116       FAIL ("encoder granulepos does not map to the correct frame number");
117     /* th_granule_frame() returns the frame index */
118     if (tframe != frame)
119       FAIL ("th_granule_frame() returned incorrect results");
120     /* th_granule_time() returns the end time */
121     if (fabs(rate*(frame+1) - ttime) > 1.0e-6)
122       FAIL ("th_granule_time() returned incorrect results");
123   }
124
125   /* clean up */
126 /*  INFO ("+ Freeing dummy frame data"); */
127   free(framedata);
128
129 /*  INFO ("+ Clearing th_info struct"); */
130   th_info_clear(&ti);
131
132 /*  INFO ("+ Freeing encoder context"); */
133   th_encode_free(te);
134
135   return 0;
136 }
137
138 int main(int argc, char *argv[])
139 {
140
141   granulepos_test_encode (1);
142   granulepos_test_encode (2);
143   granulepos_test_encode (3);
144   granulepos_test_encode (4);
145   granulepos_test_encode (8);
146   granulepos_test_encode (64);
147
148   exit (0);
149 }