annotate src/opusfile-0.9/examples/opusfile_example.c @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 4664ac0c1032
children
rev   line source
cannam@154 1 /********************************************************************
cannam@154 2 * *
cannam@154 3 * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
cannam@154 4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
cannam@154 5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
cannam@154 6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
cannam@154 7 * *
cannam@154 8 * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
cannam@154 9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
cannam@154 10 * *
cannam@154 11 ********************************************************************/
cannam@154 12 #ifdef HAVE_CONFIG_H
cannam@154 13 #include "config.h"
cannam@154 14 #endif
cannam@154 15
cannam@154 16 /*For fileno()*/
cannam@154 17 #if !defined(_POSIX_SOURCE)
cannam@154 18 # define _POSIX_SOURCE 1
cannam@154 19 #endif
cannam@154 20 #include <stdio.h>
cannam@154 21 #include <stdlib.h>
cannam@154 22 #include <errno.h>
cannam@154 23 #include <string.h>
cannam@154 24 #include <opusfile.h>
cannam@154 25 #if defined(_WIN32)
cannam@154 26 # include "win32utf8.h"
cannam@154 27 # undef fileno
cannam@154 28 # define fileno _fileno
cannam@154 29 #endif
cannam@154 30
cannam@154 31 static void print_duration(FILE *_fp,ogg_int64_t _nsamples,int _frac){
cannam@154 32 ogg_int64_t seconds;
cannam@154 33 ogg_int64_t minutes;
cannam@154 34 ogg_int64_t hours;
cannam@154 35 ogg_int64_t days;
cannam@154 36 ogg_int64_t weeks;
cannam@154 37 _nsamples+=_frac?24:24000;
cannam@154 38 seconds=_nsamples/48000;
cannam@154 39 _nsamples-=seconds*48000;
cannam@154 40 minutes=seconds/60;
cannam@154 41 seconds-=minutes*60;
cannam@154 42 hours=minutes/60;
cannam@154 43 minutes-=hours*60;
cannam@154 44 days=hours/24;
cannam@154 45 hours-=days*24;
cannam@154 46 weeks=days/7;
cannam@154 47 days-=weeks*7;
cannam@154 48 if(weeks)fprintf(_fp,"%liw",(long)weeks);
cannam@154 49 if(weeks||days)fprintf(_fp,"%id",(int)days);
cannam@154 50 if(weeks||days||hours){
cannam@154 51 if(weeks||days)fprintf(_fp,"%02ih",(int)hours);
cannam@154 52 else fprintf(_fp,"%ih",(int)hours);
cannam@154 53 }
cannam@154 54 if(weeks||days||hours||minutes){
cannam@154 55 if(weeks||days||hours)fprintf(_fp,"%02im",(int)minutes);
cannam@154 56 else fprintf(_fp,"%im",(int)minutes);
cannam@154 57 fprintf(_fp,"%02i",(int)seconds);
cannam@154 58 }
cannam@154 59 else fprintf(_fp,"%i",(int)seconds);
cannam@154 60 if(_frac)fprintf(_fp,".%03i",(int)(_nsamples/48));
cannam@154 61 fprintf(_fp,"s");
cannam@154 62 }
cannam@154 63
cannam@154 64 static void print_size(FILE *_fp,opus_int64 _nbytes,int _metric,
cannam@154 65 const char *_spacer){
cannam@154 66 static const char SUFFIXES[7]={' ','k','M','G','T','P','E'};
cannam@154 67 opus_int64 val;
cannam@154 68 opus_int64 den;
cannam@154 69 opus_int64 round;
cannam@154 70 int base;
cannam@154 71 int shift;
cannam@154 72 base=_metric?1000:1024;
cannam@154 73 round=0;
cannam@154 74 den=1;
cannam@154 75 for(shift=0;shift<6;shift++){
cannam@154 76 if(_nbytes<den*base-round)break;
cannam@154 77 den*=base;
cannam@154 78 round=den>>1;
cannam@154 79 }
cannam@154 80 val=(_nbytes+round)/den;
cannam@154 81 if(den>1&&val<10){
cannam@154 82 if(den>=1000000000)val=(_nbytes+(round/100))/(den/100);
cannam@154 83 else val=(_nbytes*100+round)/den;
cannam@154 84 fprintf(_fp,"%li.%02i%s%c",(long)(val/100),(int)(val%100),
cannam@154 85 _spacer,SUFFIXES[shift]);
cannam@154 86 }
cannam@154 87 else if(den>1&&val<100){
cannam@154 88 if(den>=1000000000)val=(_nbytes+(round/10))/(den/10);
cannam@154 89 else val=(_nbytes*10+round)/den;
cannam@154 90 fprintf(_fp,"%li.%i%s%c",(long)(val/10),(int)(val%10),
cannam@154 91 _spacer,SUFFIXES[shift]);
cannam@154 92 }
cannam@154 93 else fprintf(_fp,"%li%s%c",(long)val,_spacer,SUFFIXES[shift]);
cannam@154 94 }
cannam@154 95
cannam@154 96 static void put_le32(unsigned char *_dst,opus_uint32 _x){
cannam@154 97 _dst[0]=(unsigned char)(_x&0xFF);
cannam@154 98 _dst[1]=(unsigned char)(_x>>8&0xFF);
cannam@154 99 _dst[2]=(unsigned char)(_x>>16&0xFF);
cannam@154 100 _dst[3]=(unsigned char)(_x>>24&0xFF);
cannam@154 101 }
cannam@154 102
cannam@154 103 /*Make a header for a 48 kHz, stereo, signed, 16-bit little-endian PCM WAV.*/
cannam@154 104 static void make_wav_header(unsigned char _dst[44],ogg_int64_t _duration){
cannam@154 105 /*The chunk sizes are set to 0x7FFFFFFF by default.
cannam@154 106 Many, though not all, programs will interpret this to mean the duration is
cannam@154 107 "undefined", and continue to read from the file so long as there is actual
cannam@154 108 data.*/
cannam@154 109 static const unsigned char WAV_HEADER_TEMPLATE[44]={
cannam@154 110 'R','I','F','F',0xFF,0xFF,0xFF,0x7F,
cannam@154 111 'W','A','V','E','f','m','t',' ',
cannam@154 112 0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
cannam@154 113 0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00,
cannam@154 114 0x04,0x00,0x10,0x00,'d','a','t','a',
cannam@154 115 0xFF,0xFF,0xFF,0x7F
cannam@154 116 };
cannam@154 117 memcpy(_dst,WAV_HEADER_TEMPLATE,sizeof(WAV_HEADER_TEMPLATE));
cannam@154 118 if(_duration>0){
cannam@154 119 if(_duration>0x1FFFFFF6){
cannam@154 120 fprintf(stderr,"WARNING: WAV output would be larger than 2 GB.\n");
cannam@154 121 fprintf(stderr,
cannam@154 122 "Writing non-standard WAV header with invalid chunk sizes.\n");
cannam@154 123 }
cannam@154 124 else{
cannam@154 125 opus_uint32 audio_size;
cannam@154 126 audio_size=(opus_uint32)(_duration*4);
cannam@154 127 put_le32(_dst+4,audio_size+36);
cannam@154 128 put_le32(_dst+40,audio_size);
cannam@154 129 }
cannam@154 130 }
cannam@154 131 }
cannam@154 132
cannam@154 133 int main(int _argc,const char **_argv){
cannam@154 134 OggOpusFile *of;
cannam@154 135 ogg_int64_t duration;
cannam@154 136 unsigned char wav_header[44];
cannam@154 137 int ret;
cannam@154 138 int is_ssl;
cannam@154 139 int output_seekable;
cannam@154 140 #if defined(_WIN32)
cannam@154 141 win32_utf8_setup(&_argc,&_argv);
cannam@154 142 #endif
cannam@154 143 if(_argc!=2){
cannam@154 144 fprintf(stderr,"Usage: %s <file.opus>\n",_argv[0]);
cannam@154 145 return EXIT_FAILURE;
cannam@154 146 }
cannam@154 147 is_ssl=0;
cannam@154 148 if(strcmp(_argv[1],"-")==0){
cannam@154 149 OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
cannam@154 150 of=op_open_callbacks(op_fdopen(&cb,fileno(stdin),"rb"),&cb,NULL,0,&ret);
cannam@154 151 }
cannam@154 152 else{
cannam@154 153 OpusServerInfo info;
cannam@154 154 /*Try to treat the argument as a URL.*/
cannam@154 155 of=op_open_url(_argv[1],&ret,OP_GET_SERVER_INFO(&info),NULL);
cannam@154 156 #if 0
cannam@154 157 if(of==NULL){
cannam@154 158 OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
cannam@154 159 void *fp;
cannam@154 160 /*For debugging: force a file to not be seekable.*/
cannam@154 161 fp=op_fopen(&cb,_argv[1],"rb");
cannam@154 162 cb.seek=NULL;
cannam@154 163 cb.tell=NULL;
cannam@154 164 of=op_open_callbacks(fp,&cb,NULL,0,NULL);
cannam@154 165 }
cannam@154 166 #else
cannam@154 167 if(of==NULL)of=op_open_file(_argv[1],&ret);
cannam@154 168 #endif
cannam@154 169 else{
cannam@154 170 if(info.name!=NULL){
cannam@154 171 fprintf(stderr,"Station name: %s\n",info.name);
cannam@154 172 }
cannam@154 173 if(info.description!=NULL){
cannam@154 174 fprintf(stderr,"Station description: %s\n",info.description);
cannam@154 175 }
cannam@154 176 if(info.genre!=NULL){
cannam@154 177 fprintf(stderr,"Station genre: %s\n",info.genre);
cannam@154 178 }
cannam@154 179 if(info.url!=NULL){
cannam@154 180 fprintf(stderr,"Station homepage: %s\n",info.url);
cannam@154 181 }
cannam@154 182 if(info.bitrate_kbps>=0){
cannam@154 183 fprintf(stderr,"Station bitrate: %u kbps\n",
cannam@154 184 (unsigned)info.bitrate_kbps);
cannam@154 185 }
cannam@154 186 if(info.is_public>=0){
cannam@154 187 fprintf(stderr,"%s\n",
cannam@154 188 info.is_public?"Station is public.":"Station is private.");
cannam@154 189 }
cannam@154 190 if(info.server!=NULL){
cannam@154 191 fprintf(stderr,"Server software: %s\n",info.server);
cannam@154 192 }
cannam@154 193 if(info.content_type!=NULL){
cannam@154 194 fprintf(stderr,"Content-Type: %s\n",info.content_type);
cannam@154 195 }
cannam@154 196 is_ssl=info.is_ssl;
cannam@154 197 opus_server_info_clear(&info);
cannam@154 198 }
cannam@154 199 }
cannam@154 200 if(of==NULL){
cannam@154 201 fprintf(stderr,"Failed to open file '%s': %i\n",_argv[1],ret);
cannam@154 202 return EXIT_FAILURE;
cannam@154 203 }
cannam@154 204 duration=0;
cannam@154 205 output_seekable=fseek(stdout,0,SEEK_CUR)!=-1;
cannam@154 206 if(op_seekable(of)){
cannam@154 207 opus_int64 size;
cannam@154 208 fprintf(stderr,"Total number of links: %i\n",op_link_count(of));
cannam@154 209 duration=op_pcm_total(of,-1);
cannam@154 210 fprintf(stderr,"Total duration: ");
cannam@154 211 print_duration(stderr,duration,3);
cannam@154 212 fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
cannam@154 213 size=op_raw_total(of,-1);
cannam@154 214 fprintf(stderr,"Total size: ");
cannam@154 215 print_size(stderr,size,0,"");
cannam@154 216 fprintf(stderr,"\n");
cannam@154 217 }
cannam@154 218 else if(!output_seekable){
cannam@154 219 fprintf(stderr,"WARNING: Neither input nor output are seekable.\n");
cannam@154 220 fprintf(stderr,
cannam@154 221 "Writing non-standard WAV header with invalid chunk sizes.\n");
cannam@154 222 }
cannam@154 223 make_wav_header(wav_header,duration);
cannam@154 224 if(!fwrite(wav_header,sizeof(wav_header),1,stdout)){
cannam@154 225 fprintf(stderr,"Error writing WAV header: %s\n",strerror(errno));
cannam@154 226 ret=EXIT_FAILURE;
cannam@154 227 }
cannam@154 228 else{
cannam@154 229 ogg_int64_t pcm_offset;
cannam@154 230 ogg_int64_t pcm_print_offset;
cannam@154 231 ogg_int64_t nsamples;
cannam@154 232 opus_int32 bitrate;
cannam@154 233 int prev_li;
cannam@154 234 prev_li=-1;
cannam@154 235 nsamples=0;
cannam@154 236 pcm_offset=op_pcm_tell(of);
cannam@154 237 if(pcm_offset!=0){
cannam@154 238 fprintf(stderr,"Non-zero starting PCM offset: %li\n",(long)pcm_offset);
cannam@154 239 }
cannam@154 240 pcm_print_offset=pcm_offset-48000;
cannam@154 241 bitrate=0;
cannam@154 242 for(;;){
cannam@154 243 ogg_int64_t next_pcm_offset;
cannam@154 244 opus_int16 pcm[120*48*2];
cannam@154 245 unsigned char out[120*48*2*2];
cannam@154 246 int li;
cannam@154 247 int si;
cannam@154 248 /*Although we would generally prefer to use the float interface, WAV
cannam@154 249 files with signed, 16-bit little-endian samples are far more
cannam@154 250 universally supported, so that's what we output.*/
cannam@154 251 ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm));
cannam@154 252 if(ret==OP_HOLE){
cannam@154 253 fprintf(stderr,"\nHole detected! Corrupt file segment?\n");
cannam@154 254 continue;
cannam@154 255 }
cannam@154 256 else if(ret<0){
cannam@154 257 fprintf(stderr,"\nError decoding '%s': %i\n",_argv[1],ret);
cannam@154 258 if(is_ssl)fprintf(stderr,"Possible truncation attack?\n");
cannam@154 259 ret=EXIT_FAILURE;
cannam@154 260 break;
cannam@154 261 }
cannam@154 262 li=op_current_link(of);
cannam@154 263 if(li!=prev_li){
cannam@154 264 const OpusHead *head;
cannam@154 265 const OpusTags *tags;
cannam@154 266 int binary_suffix_len;
cannam@154 267 int ci;
cannam@154 268 /*We found a new link.
cannam@154 269 Print out some information.*/
cannam@154 270 fprintf(stderr,"Decoding link %i: \n",li);
cannam@154 271 head=op_head(of,li);
cannam@154 272 fprintf(stderr," Channels: %i\n",head->channel_count);
cannam@154 273 if(op_seekable(of)){
cannam@154 274 ogg_int64_t duration;
cannam@154 275 opus_int64 size;
cannam@154 276 duration=op_pcm_total(of,li);
cannam@154 277 fprintf(stderr," Duration: ");
cannam@154 278 print_duration(stderr,duration,3);
cannam@154 279 fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
cannam@154 280 size=op_raw_total(of,li);
cannam@154 281 fprintf(stderr," Size: ");
cannam@154 282 print_size(stderr,size,0,"");
cannam@154 283 fprintf(stderr,"\n");
cannam@154 284 }
cannam@154 285 if(head->input_sample_rate){
cannam@154 286 fprintf(stderr," Original sampling rate: %lu Hz\n",
cannam@154 287 (unsigned long)head->input_sample_rate);
cannam@154 288 }
cannam@154 289 tags=op_tags(of,li);
cannam@154 290 fprintf(stderr," Encoded by: %s\n",tags->vendor);
cannam@154 291 for(ci=0;ci<tags->comments;ci++){
cannam@154 292 const char *comment;
cannam@154 293 comment=tags->user_comments[ci];
cannam@154 294 if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,comment)==0){
cannam@154 295 OpusPictureTag pic;
cannam@154 296 int err;
cannam@154 297 err=opus_picture_tag_parse(&pic,comment);
cannam@154 298 fprintf(stderr," %.23s",comment);
cannam@154 299 if(err>=0){
cannam@154 300 fprintf(stderr,"%u|%s|%s|%ux%ux%u",pic.type,pic.mime_type,
cannam@154 301 pic.description,pic.width,pic.height,pic.depth);
cannam@154 302 if(pic.colors!=0)fprintf(stderr,"/%u",pic.colors);
cannam@154 303 if(pic.format==OP_PIC_FORMAT_URL){
cannam@154 304 fprintf(stderr,"|%s\n",pic.data);
cannam@154 305 }
cannam@154 306 else{
cannam@154 307 fprintf(stderr,"|<%u bytes of image data>\n",pic.data_length);
cannam@154 308 }
cannam@154 309 opus_picture_tag_clear(&pic);
cannam@154 310 }
cannam@154 311 else fprintf(stderr,"<error parsing picture tag>\n");
cannam@154 312 }
cannam@154 313 else fprintf(stderr," %s\n",tags->user_comments[ci]);
cannam@154 314 }
cannam@154 315 if(opus_tags_get_binary_suffix(tags,&binary_suffix_len)!=NULL){
cannam@154 316 fprintf(stderr,"<%u bytes of unknown binary metadata>\n",
cannam@154 317 binary_suffix_len);
cannam@154 318 }
cannam@154 319 fprintf(stderr,"\n");
cannam@154 320 if(!op_seekable(of)){
cannam@154 321 pcm_offset=op_pcm_tell(of)-ret;
cannam@154 322 if(pcm_offset!=0){
cannam@154 323 fprintf(stderr,"Non-zero starting PCM offset in link %i: %li\n",
cannam@154 324 li,(long)pcm_offset);
cannam@154 325 }
cannam@154 326 }
cannam@154 327 }
cannam@154 328 if(li!=prev_li||pcm_offset>=pcm_print_offset+48000){
cannam@154 329 opus_int32 next_bitrate;
cannam@154 330 opus_int64 raw_offset;
cannam@154 331 next_bitrate=op_bitrate_instant(of);
cannam@154 332 if(next_bitrate>=0)bitrate=next_bitrate;
cannam@154 333 raw_offset=op_raw_tell(of);
cannam@154 334 fprintf(stderr,"\r ");
cannam@154 335 print_size(stderr,raw_offset,0,"");
cannam@154 336 fprintf(stderr," ");
cannam@154 337 print_duration(stderr,pcm_offset,0);
cannam@154 338 fprintf(stderr," (");
cannam@154 339 print_size(stderr,bitrate,1," ");
cannam@154 340 fprintf(stderr,"bps) \r");
cannam@154 341 pcm_print_offset=pcm_offset;
cannam@154 342 fflush(stderr);
cannam@154 343 }
cannam@154 344 next_pcm_offset=op_pcm_tell(of);
cannam@154 345 if(pcm_offset+ret!=next_pcm_offset){
cannam@154 346 fprintf(stderr,"\nPCM offset gap! %li+%i!=%li\n",
cannam@154 347 (long)pcm_offset,ret,(long)next_pcm_offset);
cannam@154 348 }
cannam@154 349 pcm_offset=next_pcm_offset;
cannam@154 350 if(ret<=0){
cannam@154 351 ret=EXIT_SUCCESS;
cannam@154 352 break;
cannam@154 353 }
cannam@154 354 /*Ensure the data is little-endian before writing it out.*/
cannam@154 355 for(si=0;si<2*ret;si++){
cannam@154 356 out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
cannam@154 357 out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
cannam@154 358 }
cannam@154 359 if(!fwrite(out,sizeof(*out)*4*ret,1,stdout)){
cannam@154 360 fprintf(stderr,"\nError writing decoded audio data: %s\n",
cannam@154 361 strerror(errno));
cannam@154 362 ret=EXIT_FAILURE;
cannam@154 363 break;
cannam@154 364 }
cannam@154 365 nsamples+=ret;
cannam@154 366 prev_li=li;
cannam@154 367 }
cannam@154 368 if(ret==EXIT_SUCCESS){
cannam@154 369 fprintf(stderr,"\nDone: played ");
cannam@154 370 print_duration(stderr,nsamples,3);
cannam@154 371 fprintf(stderr," (%li samples @ 48 kHz).\n",(long)nsamples);
cannam@154 372 }
cannam@154 373 if(op_seekable(of)&&nsamples!=duration){
cannam@154 374 fprintf(stderr,"\nWARNING: "
cannam@154 375 "Number of output samples does not match declared file duration.\n");
cannam@154 376 if(!output_seekable)fprintf(stderr,"Output WAV file will be corrupt.\n");
cannam@154 377 }
cannam@154 378 if(output_seekable&&nsamples!=duration){
cannam@154 379 make_wav_header(wav_header,nsamples);
cannam@154 380 if(fseek(stdout,0,SEEK_SET)||
cannam@154 381 !fwrite(wav_header,sizeof(wav_header),1,stdout)){
cannam@154 382 fprintf(stderr,"Error rewriting WAV header: %s\n",strerror(errno));
cannam@154 383 ret=EXIT_FAILURE;
cannam@154 384 }
cannam@154 385 }
cannam@154 386 }
cannam@154 387 op_free(of);
cannam@154 388 return ret;
cannam@154 389 }