1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
9  * by the Xiph.Org Foundation https://xiph.org/                     *
10  *                                                                  *
11  ********************************************************************
12 
13  function: illustrate seeking, and test it too
14 
15  ********************************************************************/
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include "vorbis/codec.h"
20 #include "vorbis/vorbisfile.h"
21 
22 #ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
23 # include <io.h>
24 # include <fcntl.h>
25 #endif
26 
_verify(OggVorbis_File * ov,ogg_int64_t val,ogg_int64_t pcmval,double timeval,ogg_int64_t pcmlength,char * bigassbuffer)27 void _verify(OggVorbis_File *ov,
28              ogg_int64_t val,ogg_int64_t pcmval,double timeval,
29              ogg_int64_t pcmlength,
30              char *bigassbuffer){
31   off_t i;
32   int j;
33   long bread;
34   char buffer[4096];
35   int dummy;
36   ogg_int64_t pos;
37   int hs = ov_halfrate_p(ov);
38 
39   /* verify the raw position, the pcm position and position decode */
40   if(val!=-1 && ov_raw_tell(ov)<val){
41     fprintf(stderr,"raw position out of tolerance: requested %ld, got %ld\n",
42            (long)val,(long)ov_raw_tell(ov));
43     exit(1);
44   }
45   if(pcmval!=-1 && ov_pcm_tell(ov)>pcmval){
46     fprintf(stderr,"pcm position out of tolerance: requested %ld, got %ld\n",
47            (long)pcmval,(long)ov_pcm_tell(ov));
48     exit(1);
49   }
50   if(timeval!=-1 && ov_time_tell(ov)>timeval){
51     fprintf(stderr,"time position out of tolerance: requested %f, got %f\n",
52            timeval,ov_time_tell(ov));
53     exit(1);
54   }
55   pos=ov_pcm_tell(ov);
56   if(pos<0 || pos>pcmlength){
57     fprintf(stderr,"pcm position out of bounds: got %ld\n",(long)pos);
58     exit(1);
59   }
60   bread=ov_read(ov,buffer,4096,1,1,1,&dummy);
61   for(j=0;j<bread;j++){
62     if(buffer[j]!=bigassbuffer[j+((pos>>hs)*2)]){
63       fprintf(stderr,"data after seek doesn't match declared pcm position %ld\n",(long)pos);
64 
65       for(i=0;i<(pcmlength>>hs)*2-bread;i++){
66         for(j=0;j<bread;j++)
67           if(buffer[j] != bigassbuffer[i+j])break;
68         if(j==bread){
69           fprintf(stderr,"data after seek appears to match position %ld\n",(long)((i/2)<<hs));
70         }
71       }
72       {
73         FILE *f=fopen("a.m","w");
74         for(j=0;j<bread;j++)fprintf(f,"%d %d\n",j,(int)buffer[j]);
75         fclose(f);
76         f=fopen("b.m","w");
77         for(j=-4096;j<bread+4096;j++)
78           if(j+((pos*2)>>hs)>=0 && (j+((pos*2)>>hs))<(pcmlength>>hs)*2)
79              fprintf(f,"%d %d\n",j,(int)bigassbuffer[j+((pos*2)>>hs)]);
80         fclose(f);
81       }
82 
83       exit(1);
84     }
85   }
86 }
87 
main()88 int main(){
89   OggVorbis_File ov;
90   int i,ret;
91   ogg_int64_t pcmlength;
92   double timelength;
93   char *bigassbuffer;
94   int dummy;
95   int hs=0;
96 
97 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
98   _setmode( _fileno( stdin ), _O_BINARY );
99 #endif
100 
101 
102   /* open the file/pipe on stdin */
103   if(ov_open_callbacks(stdin,&ov,NULL,-1,OV_CALLBACKS_NOCLOSE)<0){
104     fprintf(stderr,"Could not open input as an OggVorbis file.\n\n");
105     exit(1);
106   }
107 
108 #if 0 /*enable this code to test seeking with halfrate decode */
109   if(ov_halfrate(&ov,1)){
110     fprintf(stderr,"Sorry; unable to set half-rate decode.\n\n");
111     exit(1);
112   }else
113     hs=1;
114 #endif
115 
116   if(ov_seekable(&ov)){
117 
118     /* to simplify our own lives, we want to assume the whole file is
119        stereo.  Verify this to avoid potentially mystifying users
120        (pissing them off is OK, just don't confuse them) */
121     for(i=0;i<ov.links;i++){
122       vorbis_info *vi=ov_info(&ov,i);
123       if(vi->channels!=2){
124         fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n"
125                "that are entirely stereo.\n\n");
126         exit(1);
127       }
128     }
129 
130     /* because we want to do sample-level verification that the seek
131        does what it claimed, decode the entire file into memory */
132     pcmlength=ov_pcm_total(&ov,-1);
133     timelength=ov_time_total(&ov,-1);
134     bigassbuffer=malloc((pcmlength>>hs)*2); /* w00t */
135     i=0;
136     while(i<(pcmlength>>hs)*2){
137       int ret=ov_read(&ov,bigassbuffer+i,((pcmlength>>hs)*2)-i,1,1,1,&dummy);
138       if(ret<0){
139         fprintf(stderr,"Error reading file.\n");
140         exit(1);
141       }
142       if(ret){
143         i+=ret;
144       }else{
145         pcmlength=(i/2)<<hs;
146       }
147       fprintf(stderr,"\rloading.... [%ld left]              ",
148               (long)((pcmlength>>hs)*2-i));
149     }
150 
151     {
152       ogg_int64_t length=ov.end;
153       fprintf(stderr,"\rtesting raw seeking to random places in %ld bytes....\n",
154              (long)length);
155 
156       for(i=0;i<1000;i++){
157         ogg_int64_t val=(double)rand()/RAND_MAX*length;
158         fprintf(stderr,"\r\t%d [raw position %ld]...     ",i,(long)val);
159         ret=ov_raw_seek(&ov,val);
160         if(ret<0){
161           fprintf(stderr,"seek failed: %d\n",ret);
162           exit(1);
163         }
164 
165         _verify(&ov,val,-1,-1.,pcmlength,bigassbuffer);
166 
167       }
168     }
169 
170     fprintf(stderr,"\r");
171     {
172       fprintf(stderr,"testing pcm page seeking to random places in %ld samples....\n",
173              (long)pcmlength);
174 
175       for(i=0;i<1000;i++){
176         ogg_int64_t val= i==0?(ogg_int64_t)0:(double)rand()/RAND_MAX*pcmlength;
177         fprintf(stderr,"\r\t%d [pcm position %ld]...     ",i,(long)val);
178         ret=ov_pcm_seek_page(&ov,val);
179         if(ret<0){
180           fprintf(stderr,"seek failed: %d\n",ret);
181           exit(1);
182         }
183 
184         _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer);
185 
186       }
187     }
188 
189     fprintf(stderr,"\r");
190     {
191       fprintf(stderr,"testing pcm exact seeking to random places in %f seconds....\n",
192              timelength);
193       for(i=0;i<1000;i++){
194         ogg_int64_t val= i==0?(ogg_int64_t)0:(double)rand()/RAND_MAX*pcmlength;
195         fprintf(stderr,"\r\t%d [pcm position %ld]...     ",i,(long)val);
196         ret=ov_pcm_seek(&ov,val);
197         if(ret<0){
198           fprintf(stderr,"seek failed: %d\n",ret);
199           exit(1);
200         }
201         if(ov_pcm_tell(&ov)!=((val>>hs)<<hs)){
202           fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n",
203                  (long)val,(long)ov_pcm_tell(&ov));
204           exit(1);
205         }
206 
207         _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer);
208 
209       }
210     }
211 
212     fprintf(stderr,"\r");
213     {
214       fprintf(stderr,"testing time page seeking to random places in %f seconds....\n",
215              timelength);
216 
217       for(i=0;i<1000;i++){
218         double val=(double)rand()/RAND_MAX*timelength;
219         fprintf(stderr,"\r\t%d [time position %f]...     ",i,val);
220         ret=ov_time_seek_page(&ov,val);
221         if(ret<0){
222           fprintf(stderr,"seek failed: %d\n",ret);
223           exit(1);
224         }
225 
226         _verify(&ov,-1,-1,val,pcmlength,bigassbuffer);
227 
228       }
229     }
230 
231     fprintf(stderr,"\r");
232     {
233       fprintf(stderr,"testing time exact seeking to random places in %f seconds....\n",
234              timelength);
235 
236       for(i=0;i<1000;i++){
237         double val=(double)rand()/RAND_MAX*timelength;
238         fprintf(stderr,"\r\t%d [time position %f]...     ",i,val);
239         ret=ov_time_seek(&ov,val);
240         if(ret<0){
241           fprintf(stderr,"seek failed: %d\n",ret);
242           exit(1);
243         }
244         if(ov_time_tell(&ov)<val-1 || ov_time_tell(&ov)>val+1){
245           fprintf(stderr,"Declared position didn't perfectly match request: %f != %f\n",
246                  val,ov_time_tell(&ov));
247           exit(1);
248         }
249 
250         _verify(&ov,-1,-1,val,pcmlength,bigassbuffer);
251 
252       }
253     }
254 
255     fprintf(stderr,"\r                                           \nOK.\n\n");
256 
257 
258   }else{
259     fprintf(stderr,"Standard input was not seekable.\n");
260   }
261 
262   ov_clear(&ov);
263   return 0;
264 }
265 
266 
267 
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 
278