]> git.vomp.tv Git - vompclient-marten.git/blob - demuxeraudio.cc
Fix symbol and font gradients
[vompclient-marten.git] / demuxeraudio.cc
1 /*
2     Copyright 2006 Mark Calderbank, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "demuxeraudio.h"
22 #include "audio.h"
23 #include "i18n.h"
24 #include "log.h"
25
26 #define HDRBYTE1 0xff
27 #define HDRBYTE2 0xe0
28 #define HDRBYTE2MASK 0xe0
29
30
31
32 class PacketBuffer {
33   
34   public:
35     PacketBuffer(Stream *as,UCHAR strtype) {
36       log=Log::getInstance();
37       audio=as;
38       streamtype=strtype;
39       newStream();
40     }
41     //just handle the data (do not deal with headers)
42     int putInternal(UCHAR* buf,int len,unsigned int &packetnum);
43     void reset(){
44       partPacket=0;
45       bytesWritten=0;
46       framelen=DemuxerAudio::PACKET_SIZE;
47     }
48     void newStream() {
49       reset();
50       numpackets=0;
51       numbytes=0;
52                         skipfactor=0;
53                         numskip=0;
54     }
55     bool bufferFull() {
56       return (partPacket>=framelen);
57     }
58     //can we write a new packet?
59     bool bufferEmpty() {
60       return partPacket==0;
61     }
62     //only set this, if buffer empty
63     //otherwise ignored!
64     bool setFramelen(int len) {
65       if (! bufferEmpty() ) return false;
66       if (len > (int)DemuxerAudio::PACKET_SIZE) return false;
67       framelen=len;
68       return true;
69     }
70     //how much bytes do we need to fill the packet?
71     int bytesMissing() {
72       return framelen-partPacket;
73     }
74     int getFramelen() {
75       return framelen;
76     }
77                 void setSkipFactor(int factor) {
78                         skipfactor=factor;
79                         numskip=0;
80                 }
81   private:
82     void packetWritten() {
83       numbytes+=framelen;
84       //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes);
85       numpackets++;
86       reset();
87     }
88                 bool doSkip();
89     UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets
90     int partPacket;    // Length of partial packet stored from previous put()
91     int bytesWritten;  //if they are !=0 and != framelength the stream is full...
92     int framelen;
93     Log * log;
94     Stream * audio;
95     UCHAR streamtype;
96     //global counters
97     ULONG numpackets;
98     ULONG numbytes;
99                 int skipfactor;
100                 int numskip;
101 };
102
103
104 DemuxerAudio::DemuxerAudio(int p_vID, int p_aID)
105 {
106   inSync=false;
107   isStarting=true;
108   log=Log::getInstance();
109   readHeaders=0;
110   streamtype=Audio::MP3;
111   buffer=new PacketBuffer(&audiostream,streamtype);
112 //  buffer=new PacketBuffer(&teststream,streamtype);
113   globalBytesWritten=0;
114   packetnum=0;
115   id3=NULL;
116   info=NULL;
117         vbr=NULL;
118   reset();
119 }
120
121 DemuxerAudio::~DemuxerAudio() {
122   delete buffer;
123   if(info) delete info;
124   if(id3) delete id3;
125         if (vbr) delete vbr;
126 }
127
128 void DemuxerAudio::flush()
129 {
130   Demuxer::flushAudio();
131   buffer->newStream();
132   tmpFill=0;
133 }
134
135 void DemuxerAudio::reset() {
136   buffer->newStream();
137   tmpFill=0;
138   readHeaders=0;
139   packetnum=0;
140   outOfSync=0;
141   globalBytesWritten=0;
142   if (id3) delete id3;
143   id3=NULL;
144   if (info) delete info;
145   info=NULL;
146         if (vbr) delete vbr;
147         vbr=NULL;
148   inSync=false;
149   hasHdrInfo=false;
150   hasVBRInfo=false;
151   isStarting=true;
152   hdrBitrate=128000;
153   hdrSamplingRate=44100;
154   avrBitrate=0;
155   hdrFramelen=0;
156   isStarting=true;
157 }
158
159 int DemuxerAudio::scan(UCHAR *buf, int len)
160 {
161   //no differend pids here
162   return 0;
163 }
164
165 void DemuxerAudio::setVID(int p_vID)
166 {
167 }
168
169 void DemuxerAudio::setAID(int p_aID,int type)
170 {
171 }
172
173 static const char * id3_1_genre[] = {
174   "Blueshhh",
175   "Classic Rock",
176   "Country",
177   "Dance",
178   "Disco",
179   "Funk",
180   "Grunge",
181   "Hip-Hop",
182   "Jazz",
183   "Metal",
184   "New Age",
185   "Oldies",
186   "Other",
187   "Pop",
188   "R&B",
189   "Rap",
190   "Reggae",
191   "Rock",
192   "Techno",
193   "Industrial",
194   "Alternative",
195   "Ska",
196   "Death Metal",
197   "Pranks",
198   "Soundtrack",
199   "Euro-Techno",
200   "Ambient",
201   "Trip-Hop",
202   "Vocal",
203   "Jazz+Funk",
204   "Fusion",
205   "Trance",
206   "Classical",
207   "Instrumental",
208   "Acid",
209   "House",
210   "Game",
211   "Sound Clip",
212   "Gospel",
213   "Noise",
214   "AlternRock",
215   "Bass",
216   "Soul",
217   "Punk",
218   "Space",
219   "Meditative",
220   "Instrumental Pop",
221   "Instrumental Rock",
222   "Ethnic",
223   "Gothic",
224   "Darkwave",
225   "Techno-Industrial",
226   "Electronic",
227   "Pop-Folk",
228   "Eurodance",
229   "Dream",
230   "Southern Rock",
231   "Comedy",
232   "Cult",
233   "Gangsta",
234   "Top 40",
235   "Christian Rap",
236   "Pop/Funk",
237   "Jungle",
238   "Native American",
239   "Cabaret",
240   "New Wave",
241   "Psychadelic",
242   "Rave",
243   "Showtunes",
244   "Trailer",
245   "Lo-Fi",
246   "Tribal",
247   "Acid Punk",
248   "Acid Jazz",
249   "Polka",
250   "Retro",
251   "Musical",
252   "Rock & Roll",
253   "Hard Rock"
254 };
255
256
257
258 static int bitrateTable[16][5]={
259 /*        L1,L2,L3,2L1,2L2 */
260 /*0000*/ {-1,-1,-1,-1,-1},
261 /*0001*/ {32,32,32,32,8},
262 /*0010*/ {64,48,40,48,16},
263 /*0011*/ {96,56,48,56,24},
264 /*0100*/ {128,64,56,64,32},
265 /*0101*/ {160,80,64,80,40},
266 /*0110*/ {192,96,80,96,48},
267 /*0111*/ {224,112,96,112,56},
268 /*1000*/ {256,128,112,128,64},
269 /*1001*/ {288,160,128,144,80},
270 /*1010*/ {320,192,160,160,96},
271 /*1011*/ {352,224,192,176,112},
272 /*1100*/ {384,256,224,192,128},
273 /*1101*/ {416,320,256,224,144},
274 /*1110*/ {448,384,320,256,160},
275 /*1111*/ {-1,-1,-1,-1,-1} };
276
277 static int  samplingRateTable[4][3]={
278 /*00*/ {44100,22050,11025},
279 /*01*/ {48000,24000,12000},
280 /*10*/ {32000,16000,8000},
281 /*11*/ {-1,-1,-1}};
282
283 //max 7 char!
284 static const char * mpegString(UCHAR code) {
285   switch(code) {
286     case 0:
287       return "MPEG2.5";
288     case 1:
289       return "RESERV";
290     case 2:
291       return "MPEG 2";
292     case 3:
293       return "MPEG 1";
294   }
295   return "UNKNOWN";
296 }
297
298 static const char * layerString(UCHAR code) {
299   switch(code) {
300     case 0:
301       return "Layer reserved";
302     case 1:
303       return "Layer III";
304     case 2:
305       return "Layer II";
306     case 3:
307       return "Layer I";
308   }
309   return "Layer UNKNOWN";
310 }
311 /**
312   * parse an id3 Header
313   * provided by Brian Walton
314   * @returns -1 of nothing found
315   */
316   
317 int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame)
318 {
319   if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1;
320   frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 |  (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F);
321   if (frame->size == 0) return -1;
322   //TODO. clearify flags against:
323   //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
324   frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7;
325   frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6;
326   frame->flags.readOnly = (buf[8] & 0x20) >> 5;
327   frame->flags.groupId = (buf[9] & 0x20) >> 5;
328   frame->flags.compression = (buf[9] & 0x80) >> 7;
329   frame->flags.encryption = (buf[9] & 0x40) >> 6;
330   frame->flags.unsync = 0;
331   frame->flags.dataLen = 0;
332   return 0;
333 }
334
335  /**
336   * parse an id3 Header
337   * provided by Brian Walton
338   * @returns -1 of nothing found
339   */
340   
341 int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame)
342 {
343   if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1;
344   frame->size = (buf[3] & 0x7F) << 14 |  (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F);
345   if (frame->size == 0) return -1;
346   return 0;
347 }
348
349
350 //fill an id3tag from a frame payload
351 //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b
352 //http://id3.org/id3v2-00
353 static struct tagid {
354   const char * bytes;
355   int index;
356 } knownFrames[]= {
357   //ID3V2.3
358   {"TIT2",1}, //title
359   {"TPE1",2}, //artist
360   {"TCON",3}, //genre
361   {"TRCK",6}, //track
362   {"TYER",4}, //year
363   {"TALB",5}, //album
364   {"TCOM",7}, //composer
365   {"COMM",8}, //comment
366               //Text encoding           $xx
367               //Language                $xx xx xx
368               //Short content descrip.  <text string according to encoding> $00 (00)
369               //The actual text         <full text string according to encoding>
370   //ID3V2.0
371   {"TT2",1 },
372   {"TP1",2 },
373   {"TCM",7 },
374   {"TCO",3 }, //(genreNumber)
375   {"TAL",5 },
376   {"TRK",6 },
377   {"TYE",4 },
378   {"COM",8 }
379 };
380 #define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0]))
381
382 /*fill in infos
383   from an ID3 V2.x, V2.3 frame into the tags structure
384   frameData must point to the header
385   framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x)
386   */
387
388 #define MAXLEN(tagtype) ((UINT)frameLen<sizeof(tag->tagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1)
389 bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) {
390   int tl=v23?4:3;
391   int tagIndex=-1;
392   if (tag == NULL) return false;
393   if (frameLen < 2) return false;
394   for (UINT i=0;i< NUMKNOWN;i++) {
395     if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) {
396       tagIndex=knownFrames[i].index;
397       break;
398     }
399   }
400   if (tagIndex < 0) return false;
401   UCHAR encoding=*(frameData+dataOffset);
402   dataOffset++;
403   frameLen--;
404   if (encoding != 0) {
405     log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding,
406         knownFrames[tagIndex].bytes);
407     return false;
408   }
409   switch(tagIndex) {
410     case 1:  //title
411       strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title));
412       tag->title[MAXLEN(title)]=0;
413       break;
414     case 2:  //artist
415       strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist));
416       tag->artist[MAXLEN(artist)]=0;
417       break;
418     case 3:  //genre
419       {
420       UCHAR * st=frameData+dataOffset;
421       int genre=0;
422       if (*st=='(') {
423         genre=atoi((const char *)(st+1)) && 31;
424         st=(UCHAR *)id3_1_genre[genre];
425       }
426       strncpy(tag->genre,(char*)st,MAXLEN(genre));
427       tag->genre[MAXLEN(genre)]=0;
428       break;
429       }
430     case 4:  //year
431       strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year));
432       tag->year[MAXLEN(year)]=0;
433       break;
434     case 5:  //album
435       strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album));
436       tag->album[MAXLEN(album)]=0;
437       break;
438     case 6:  //track
439       strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track));
440       tag->track[MAXLEN(track)]=0;
441       break;
442     case 7:  //composer
443       strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer));
444       tag->composer[MAXLEN(composer)]=0;
445       break;
446     case 8:  //comment
447       strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment));
448       tag->comment[MAXLEN(comment)]=0;
449       break;
450     default:
451       return false;
452   }
453
454   return true;
455 }
456
457 /**
458   * parse an id3 Header
459   * based on code provided by Brian Walton
460   * @returns -1 of nothing found
461   *  otherwise the id3 info is filled
462   */
463
464 int DemuxerAudio::parseID3V2(UCHAR *data, int len) {
465   int debug=0;
466   UCHAR * start=data;
467   id3_header id3header;
468   id3_frame id3frame;
469   id3_tag * id3tag=NULL;
470   //len = read(fd, data, 10);
471   if (len < 10) {
472     delete id3tag;
473     return -1;
474   }
475   len-=10;
476   if(data[0]=='I' && data[1]=='D' && data[2]=='3')
477   {
478     id3tag=new id3_tag();
479     id3header.major = data[3];
480     id3header.minor = data[4];
481     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor);
482     id3header.flags.unsynchronisation = (data[5] & 0x80)>>7;
483     id3header.flags.extended_header = (data[5] & 0x40)>>6;
484     id3header.flags.experimental = (data[5] & 0x20)>>5;
485     id3header.flags.footer = (data[5] & 0x10)>>4;
486     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation);
487     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header);
488     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental);
489     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer);
490     id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 |  (data[8] & 0x7F) << 7 | (data[9] & 0x7F);
491     if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size);
492     data=start+10;
493     if (len <= id3header.size) {
494       if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len);
495       delete id3tag;
496       return -1;
497     }
498     if (id3header.flags.extended_header)
499     {
500       int extended_hdr_hdr=4;  //still to be discussed (id3.org...)
501       //read extended header size
502       if (len < extended_hdr_hdr) {
503         if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n");
504         delete id3tag;
505         return -1;
506       }
507       if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len);
508       id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 |  (data[2] & 0x7F) << 7 | (data[3] & 0x7F);
509       if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size);
510       if (len <= id3header.extended_header.size+extended_hdr_hdr) {
511       if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len);
512         delete id3tag;
513         return -1;
514       }
515       //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR);
516       data+=id3header.extended_header.size+extended_hdr_hdr;
517       len-=id3header.extended_header.size+extended_hdr_hdr;
518     }
519     //set the end of the header
520     UCHAR * eob=start+id3header.size+10;
521     bool readNext=true;
522     while (data < eob && readNext)
523     {
524       //skip over some padding - found this in lame MCDI tag...
525       if (*data == 0) {
526         data++;
527         continue;
528       }
529       readNext=false;
530       switch(id3header.major)
531       {
532         case 2: //ID3 V2.2.x
533           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2));
534           if (data + 6 >= eob)
535           {
536             break;
537           }
538           if (id3_2_2_FrameParse(data, &id3frame) < 0)
539           {
540             break;
541           }
542           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size);
543           fillId3Tag(id3tag,data,id3frame.size,6,false);
544           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1);
545           data+=6+id3frame.size;
546           readNext=true;
547           break;
548         case 3: //ID3 V2.3.x
549           {
550           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start,
551               *data,*(data+1),*(data+2),*(data+3));
552           if (data + 10 >= eob)
553           {
554             break;
555           }
556           if (id3_2_3_FrameParse(data, &id3frame) <0)
557           {
558             break;
559           }
560           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size);
561           int dataOffset=10;
562           if (id3frame.flags.groupId)
563           {
564             dataOffset++;
565             if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]);
566           }
567           if (id3frame.flags.compression)
568           {
569             if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression);
570           }
571           if (id3frame.flags.encryption)
572           {
573             dataOffset+=1;
574             if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]);
575           }
576           fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true);
577           if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1);
578           data+=10+id3frame.size;
579           readNext=true;
580           break;
581           }
582         default:
583           //don't support this version
584           delete id3tag;
585           return -1;
586       }
587     }
588
589     data=eob;
590     //store the found tag
591     if (id3) delete id3;
592     id3=id3tag;
593     return data-start;
594   }
595   return -1;
596 }
597
598 /**
599   * parse an id3v1 Header
600   * based on code provided by Brian Walton
601   * @returns -1 of nothing found
602   *  otherwise the id3 info is filled
603   */
604 #define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1<len?sizeof(tag->type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;}
605
606 int DemuxerAudio::parseID3V1(UCHAR *data, int len) {
607   int debug=1;
608   if (len < 128) return -1;
609   if(data[0]=='T' && data[1]=='A' && data[2]=='G')
610   {
611     id3_tag * tag=new id3_tag();
612     if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n");
613     MEMCPY(title,30,3);
614     MEMCPY(artist,30,33);
615     MEMCPY(album,30,63);
616     MEMCPY(year,4,93);
617     if (data[125]==0 && data[126]!=0)
618     { //ID3 V1.1
619       if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n");
620       MEMCPY(comment,29,97);
621       sprintf(tag->track, "%d", data[126]);
622     } else {
623       if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n");
624       MEMCPY(comment,30,97);
625     }
626     if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0]))
627     {
628       sprintf(tag->genre, id3_1_genre[data[127]]);
629     }
630     if (id3) delete id3;
631     id3=tag;
632     return 0;
633   }
634   return -1;
635 }
636
637 //infos from http://www.multiweb.cz/twoinches/MP3inside.htm
638 int DemuxerAudio::parseVBR(UCHAR *data, int len) {
639         UCHAR *hdr=findHeader(data,len);
640         //we expect the header exactly here
641         if (hdr != data) return -1;
642         const static char * VBRHDR="Xing";
643         int vbridpos=36;
644   UCHAR mpgtype=(data[1] & 0x18)>>3;
645   UCHAR chmode=(data[2] & 0xc0) >> 6;
646   UCHAR layer=(data[2] & 0x06) >>1;
647         if ( mpgtype == 3 && chmode == 11) vbridpos=21;
648         if ( mpgtype != 3 && chmode != 11) vbridpos=21;
649         if ( mpgtype != 3 && chmode == 11) vbridpos=13;
650         //check for the header ID
651         if (vbridpos+(int)strlen(VBRHDR)+4 >= len) {
652                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len);
653                 return -1;
654         }
655         for (int i=4;i<vbridpos;i++) {
656                 if (data[i] != 0) {
657                   Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i);
658                         return -1;
659                 }
660         }
661         if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) {
662                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos);
663                 return -1;
664         }
665         int framedata=vbridpos+strlen(VBRHDR);
666         int expectedLen=0;
667         //OK we should now have a valid vbr header
668         bool hasFramenum=data[framedata+3] & 1;
669         bool hasBytes=data[framedata+3] & 0x2;
670         bool hasTOC=data[framedata+3] & 0x4;
671         expectedLen+=8;
672         if (hasTOC) expectedLen+=100;
673         if (framedata+expectedLen > len) {
674                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d",
675                                 len,framedata+expectedLen);
676                 return -1;
677         }
678         if (!hasFramenum || ! hasBytes || ! hasTOC) {
679                 //not usefull for us..
680                 Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore");
681                 return -1;
682         }
683         framedata+=4;
684         if (vbr) delete vbr;
685         vbr=new vbrInfo();
686         vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16|
687                         data[framedata+2]<<8 |data[framedata+3];
688         framedata+=4;
689         vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16|
690                         data[framedata+2]<<8 |data[framedata+3];
691         framedata+=4;
692         for (int ti=0;ti<100;ti++) {
693                 vbr->table[ti]=data[framedata+ti];
694         }
695         //compute file size in seconds
696         //should be (#of frames -1) *samplesPerFrame / sampleRate
697         //TODO: difference for Mono?
698         ULONG samplesPerFrame=384; //layer1
699         if (layer != 3) samplesPerFrame=1152;
700         vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate;
701         Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec",
702                         vbr->numBytes,vbr->numFrames,vbr->fileSeconds);
703         return hdrFramelen;
704 }
705
706
707
708
709
710
711
712 UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) {
713   while (len >= 3) //assume hdr+crc
714   {
715     UCHAR pattern=*buf;
716     buf++; len--;
717     if (pattern != HDRBYTE1 ) continue;
718     if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue;
719     if (readHeader((buf-1),4,writeInfo) != 0) continue;
720     return buf-1;
721   }
722   return NULL;
723 }
724
725
726
727 int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) {
728   int curFramelen=0;
729   int curBitrate=0;
730   int curSamplingRate=0;
731   if (*hbuf != HDRBYTE1) return -1;
732   hbuf++;
733   if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1;
734   UCHAR mpgtype=(*hbuf & 0x18)>>3;
735   if (mpgtype == 1) {
736     log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i",
737         mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2));
738     return 1;
739   }
740   UCHAR layer=(*hbuf & 0x06) >>1;
741   //bool hasCRC=!(*hbuf & 1);
742   hbuf++;
743   UCHAR bitrateCode=(*hbuf & 0xf0) >>4;
744   UCHAR samplingCode=(*hbuf & 0x0c) >> 2;
745   bool padding=*hbuf & 0x02;
746   hbuf++;
747   //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono
748   UCHAR chmode=(*hbuf & 0xc0) >> 6;
749   //UCHAR extension=(*hbuf & 0x30) >> 4;
750
751   //layercode: 1-L3, 2-L2, 3-L1
752   //columns 0,1,2 for MPEG1
753   UCHAR bitrateColumn=3-layer;
754   if (bitrateColumn > 2) {
755     log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i",
756         layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf);
757     return 1;
758   }
759   if (mpgtype != 3) bitrateColumn+=3;
760   if (bitrateColumn>4) bitrateColumn=4;
761   curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn];
762   UCHAR sampleRateColumn=0;
763   if (mpgtype == 10) sampleRateColumn=1;
764   if (mpgtype == 0) sampleRateColumn=2;
765   curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn];
766   if (curSamplingRate < 0 || curBitrate < 0) {
767     log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i",
768         curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf);
769     return 1;
770   }
771   int padbytes=0;
772   if (padding) {
773     if (layer == 3) padbytes=4;
774     else padbytes=1;
775   }
776   if (layer == 3) {
777     //Layer 1
778     //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
779     curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4;
780   }
781   else {
782     //Layer 2/3
783     //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
784     curFramelen=144*curBitrate/curSamplingRate+padbytes;
785   }
786   //the header itself
787   if (curFramelen < 32) {
788   log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i",
789       readHeaders,mpegString(mpgtype),layerString(layer),
790       curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
791       return 1;
792   }
793   if (writeInfo || isStarting){
794   log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i",
795       readHeaders,mpegString(mpgtype),layerString(layer),
796       curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf);
797     if (info) delete info;
798     info=new mpegInfo();
799     strcpy(info->mpegVersion,mpegString(mpgtype));
800     info->mpegLayer=4-layer;
801     info->bitRate=curBitrate;
802     info->avrBitrate=curBitrate;
803     info->sampleRate=curSamplingRate;
804     const char *chmodStr=tr("Stereo");
805     switch (chmode) {
806       case 1: chmodStr=tr("JointStereo");break;
807       case 2: chmodStr=tr("Dual");break;
808       case 3: chmodStr=tr("Mono");break;
809     }
810     SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr);
811   }
812         if (isStarting) avrBitrate=curBitrate;
813   isStarting=false;
814   readHeaders++;
815   //moving average F=0.005
816   avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024);
817   hdrBitrate=curBitrate;
818   hdrFramelen=curFramelen;
819   hdrSamplingRate=curSamplingRate;
820         hasHdrInfo=true;
821   return 0;
822 }
823
824 int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest)
825 {
826   //we have no PTS number ...
827   *dest=0;
828   return (findHeader(buf,len) != NULL)?1:0;
829 }
830
831 bool PacketBuffer::doSkip() {
832         if (!bufferFull()) return false;
833         if (skipfactor == 0) return false;
834         numskip++;
835         if (numskip >= skipfactor) {
836                 //sent at least always 2 packets
837                 if (numskip > skipfactor) numskip=0;
838                 return false;
839         }
840         packetWritten();
841         return true;
842 }
843         
844 // just handle the real stream without dealing with the header
845 int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum)
846 {
847    /* Important, the type passed to stream must be a mediapacket type as defined in 
848        Draintarget.h and not the device setting of the mvp, so we have to translate it here,
849        in order to get it working on windows
850        --MR */
851   UCHAR mptype=0;
852   switch (streamtype) {
853         case Audio::MPEG1_PES: //?
854         case Audio::MPEG2_PES: //Important, this must be a PES !
855             mptype=MPTYPE_MPEG_AUDIO; break;
856         default:
857         case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES
858            mptype=MPTYPE_MPEG_AUDIO_LAYER3;break;
859   };
860   if (bufferFull()) {
861 #ifndef WIN32
862                 if (doSkip()) return 0;//NoSkip on Windows
863 #endif
864     //we are still full - so try to write
865     int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++;
866     //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten );
867     if (sent < (framelen - bytesWritten)) {
868       //packet still not written
869       bytesWritten+=sent;
870       return 0;
871     }
872     packetWritten();
873     //let the demuxer come back with the rest - need to check header first
874     return 0;
875   }
876   if (partPacket+len >= framelen) {
877     //now we have at least a complete packet
878     int bytesConsumed=framelen-partPacket;
879     memcpy(store+partPacket,wbuf,bytesConsumed);
880     partPacket=framelen;
881     //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio );
882 #ifndef WIN32 //No Skip on Windows
883                 if (doSkip()) return bytesConsumed;
884 #endif
885     int sent=audio->put(store,framelen,mptype,packetnum);packetnum++;
886     bytesWritten+=sent;
887     //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent );
888     if (bytesWritten < framelen) {
889       //still not completely written
890       return bytesConsumed;
891     }
892     packetWritten();
893     //let the player come back...
894     return bytesConsumed;
895   }
896   //OK packet still not complete
897   if (len == 0) return 0;
898   int bytesConsumed=len;
899   memcpy(store+partPacket,wbuf,bytesConsumed);
900   partPacket+=bytesConsumed;
901   return bytesConsumed;
902 }
903
904 /**
905   major entry for data from a player
906   the demuxer is either in the state headerSearch (packet written or
907   just at the beginning), writing garbage (inSync=false) or
908   handling data (none set)
909   A header is expected at the first byte after the previous packet -
910   otherwise we switch to garbage where we always search for a header
911   (but anyway provide the data to the underlying device - it's probably
912   more intelligent then we are...
913   We only loose a correct position display.
914   */
915 int DemuxerAudio::put(UCHAR* wbuf, int len)
916 {
917   //return audiostream.put(wbuf,len,streamtype);
918   int framelen=PACKET_SIZE;
919   UCHAR *hdr;
920   int bytesConsumed=0;
921   int oldBytes=0;
922   if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) {
923     //OK we have to copy everything to the tmp buffer
924     int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill);
925     memcpy(&tmpBuffer[tmpFill],wbuf,cp);
926     oldBytes=tmpFill;
927     tmpFill+=cp;
928     wbuf=tmpBuffer;
929     len=tmpFill;
930     //if there is no header here and our buffer
931     //is empty - just wait for the next header
932     if (len < HDRLEN && buffer->bufferEmpty()) {
933       log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
934       return cp;
935     }
936   }
937   while (bytesConsumed < len ) {
938     if (buffer->bufferFull()) {
939       //if this is the first part of the loop, try to write to the stream
940       if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum);
941       //if the buffer is full, no need to continue
942       if (buffer->bufferFull()) break;
943     }
944     //either we are in a packet (buffer != full && buffer != empty)
945     //or we are searching a header
946     if (buffer->bufferEmpty()) {
947       if (len-bytesConsumed < HDRLEN) {
948         // we cannot  still search
949         if (tmpFill != 0) {
950           //we are already working at the buffer
951           break;
952         }
953         memcpy(tmpBuffer,wbuf,len-bytesConsumed);
954         tmpFill=len-bytesConsumed;
955         log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten);
956         return len;
957       }
958
959       int lastFramelen=hdrFramelen;
960       //if the header has been valid before and we are searching
961       //it should be here
962       int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE;
963       hdr=findHeader(wbuf,maxsearch);
964       if (hdr != NULL) {
965         //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf);
966         }
967       //hdr now points to the new header
968       if (hdr !=  wbuf) {
969         //still at least bytes before the header
970         inSync=false;
971         outOfSync++;
972         int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch;
973         //we consider the garbage now as an own packet
974         //we can consume at most our buffer
975         //basically the buffer should be empty here (we are
976         //in header search - and we fill up each garbage
977
978         int nframesize=garbageBytes;
979         if (nframesize > (int)PACKET_SIZE) {
980           nframesize=(int)PACKET_SIZE;
981         }
982         if (! buffer->bufferEmpty()) {
983            log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store");
984            //at the end no big problem, we only write the remaining bytes that we have...
985         }
986         else {
987           buffer->setFramelen(nframesize);
988         }
989         log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, "
990             "framelen set to %d (last fl=%d)",
991             readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen);
992 #ifndef WIN32        
993         //hmm - we assume that he low level driver is more intelligent
994         //and give him the data "as is"
995         int written=buffer->putInternal(wbuf,garbageBytes,packetnum);
996         globalBytesWritten+=written;
997         bytesConsumed+=written;
998         if (written != garbageBytes || hdr == NULL ) {
999           break;
1000         }
1001 #else //DS is not intelligent
1002         globalBytesWritten+=garbageBytes;
1003         bytesConsumed+=garbageBytes;
1004 #endif
1005         //OK either all the "garbage" is written  or
1006         //we found the next header as expected
1007         //continue with the next package
1008         wbuf=hdr;
1009       }
1010       //we have to wait now until the buffer is 
1011       //free for the next package
1012       if ( ! buffer->bufferEmpty()) return bytesConsumed;
1013       //this is the place where we start a new packet
1014       framelen=hdrFramelen;
1015       if ( !buffer->setFramelen(framelen) ) {
1016         log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d",
1017             framelen,buffer->getFramelen());
1018             }
1019       inSync=true;
1020     }
1021     //now we are surely within a packet
1022     int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum);
1023     //update the status
1024     globalBytesWritten+=written;
1025     wbuf+=written;
1026     bytesConsumed+=written;
1027     if (written == 0) {
1028       //stream is full
1029       break;
1030     }
1031     //OK - handle the rest
1032   }
1033   if (bytesConsumed >= oldBytes) {
1034     //if we consumed more than the old bytes - OK the buffer
1035     //can be thrown away
1036     tmpFill=0;
1037     return bytesConsumed-oldBytes;
1038   }
1039   else {
1040     //only consumed bytes from the buffer
1041     if (bytesConsumed == 0) {
1042       //restore the buffer
1043       tmpFill=oldBytes;
1044       return 0;
1045     }
1046     //shift bytes in buffer
1047     for (int i=0;i<oldBytes-bytesConsumed;i++) {
1048       tmpBuffer[i]=tmpBuffer[i+bytesConsumed];
1049     }
1050     tmpFill=oldBytes-bytesConsumed;
1051     return 0;
1052   }
1053 }
1054
1055 //info functions
1056 const id3_tag * DemuxerAudio::getId3Tag() {
1057   return id3;
1058
1059 }
1060 const DemuxerAudio::mpegInfo * DemuxerAudio::getMpegInfo() {
1061   if (! hasHdrInfo) return NULL;
1062         info->avrBitrate=avrBitrate;
1063         info->bitRate=hdrBitrate;
1064   return info;
1065 }
1066
1067 const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() {
1068         return vbr;
1069 }
1070
1071 int DemuxerAudio::checkStart(UCHAR *b, int len) {
1072   UCHAR *start=b;
1073   int id3len=parseID3V2(b,len);
1074   if (id3len > 0) {
1075     char * str=id3->toString();
1076     log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len);
1077     log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str);
1078     delete str;
1079     b+=id3len;
1080     len-=id3len;
1081   }
1082         int vbrlen=parseVBR(b,len);
1083         if (vbrlen > 0 ) {
1084                 hasVBRInfo=true;
1085                 b+=vbrlen;
1086                 len-=vbrlen;
1087         }
1088   UCHAR * hdr=findHeader(b,len,true);
1089   if (hdr == NULL) return -1;
1090   return hdr-start;
1091 }
1092
1093 int DemuxerAudio::checkID3(UCHAR *b, int len) {
1094   if (len != 128) return -1;
1095   int rt=parseID3V1(b,len);
1096   if (rt >= 0) {
1097     char * str=id3->toString();
1098     log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str);
1099     delete str;
1100   }
1101   return rt;
1102 }
1103
1104 bool DemuxerAudio::isSync() {
1105   return inSync;
1106 }
1107
1108 UINT DemuxerAudio::getSyncErrors() {
1109   return outOfSync;
1110 }
1111
1112 ULONG DemuxerAudio::getBytesPerSecond()
1113 {
1114   ULONG bps=hdrBitrate;
1115   if (! hasHdrInfo) return 0;
1116   if (hdrBitrate != avrBitrate) {
1117     //we seem to have vbr
1118     if (hasVBRInfo) {
1119       //vbr stuff TODO
1120       bps=avrBitrate;
1121     }
1122     else {
1123       //some guessing
1124       bps=avrBitrate;
1125     }
1126   }
1127   bps=bps/8;
1128   return bps;
1129 }
1130
1131 ULONG DemuxerAudio::getSecondsFromLen(ULONG len) {
1132   if (! hasHdrInfo) return 0;
1133         if (vbr) {
1134                 //first find the index where we are between
1135                 //rough starting point:
1136                 ULONG idx=100*len/vbr->numBytes;
1137                 if (idx >= 100) idx=99;
1138                 ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256;
1139                 ULONG pbefore=idxPos;
1140                 ULONG pafter=idxPos;
1141                 //OK now we know whether we have to go up or down
1142                 if (idxPos > len) {
1143                         //down
1144                         while (idxPos > len && idx > 0) {
1145                                 pafter=idxPos;
1146                                 idx--;
1147                                 idxPos=(vbr->table[idx]) * vbr->numBytes/256;
1148                                 pbefore=idxPos;
1149                         }
1150                         //OK we are now before our postion
1151                 }
1152                 else {
1153                         //up
1154                         while (idxPos < len && idx < 100 ) {
1155                                 pbefore=idxPos;
1156                                 idx++;
1157                                 idxPos=(vbr->table[idx]) * vbr->numBytes/256;
1158                                 pafter=idxPos;
1159                         }
1160                         //after our position
1161                         if (idx > 0) idx --;
1162                 }
1163                 //idx is now the index before our position
1164                 //approximate between the 2 points
1165                 ULONG idxTime=idx * vbr->fileSeconds/100;
1166                 if (pafter == pbefore) return idxTime;
1167                 ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ;
1168                 if (rt > vbr -> fileSeconds) return vbr->fileSeconds;
1169                 if (rt < idxTime) return idxTime;
1170                 return rt;
1171         }
1172         else {
1173                 ULONG bps=getBytesPerSecond();
1174                 if (bps == 0) return 0;
1175                 return len/bps;
1176         }
1177 }
1178   
1179 ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) {
1180   if (! hasHdrInfo) return 0;
1181         if (vbr) {
1182                 ULONG idx=seconds*100/vbr->fileSeconds;
1183                 if (idx > 99) idx=99;
1184                 ULONG idxPos=vbr->table[idx] * vbr->numBytes/256;
1185                 ULONG idx2=idx;
1186                 if (idx < 99) idx2++;
1187                 ULONG nextPos=vbr->table[idx] * vbr->numBytes/256;
1188                 ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256);
1189                 if (rt < idxPos) return idxPos;
1190                 if ( rt > vbr->numBytes) return vbr->numBytes;
1191                 return rt;
1192         }
1193         else {
1194                 ULONG bps=getBytesPerSecond();
1195                 return bps*seconds;
1196         }
1197 }
1198
1199 int id3_tag::stringlen(bool withTitle) const {
1200         if (!withTitle)
1201    return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
1202     strlen(track)+strlen(composer)+strlen(comment)+8+3+
1203     90; //30 chars for each name...
1204         else
1205    return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+
1206     strlen(track)+strlen(composer)+strlen(comment)+8+3+
1207     120; //30 chars for each name...
1208 }
1209 //create a string out of the id3 tag info
1210 //delete this string afterwards if you did not provide the buffer
1211 char * id3_tag::toString(char *b, int len, bool withTitle) const {
1212   const char *ta=tr("Artist");
1213 //char *tg=tr("Genre");
1214 //char *ty=tr("Year");
1215   const char *tx=tr("Album");
1216 //char *to=tr("Composer");
1217 //char *tc=tr("Comment");
1218   const char *tn=tr("Track");
1219   /* in the moment:
1220      Title: 
1221      Artist:
1222      Album: year - name
1223      Track:
1224      */
1225   if (b == NULL) {
1226     len=stringlen(withTitle);
1227     b=new char[len];
1228   }
1229         const char * del=" - ";
1230         if (strlen(year) == 0) del="";
1231         if (withTitle){
1232  const char *tt=tr("Title");
1233                 SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s",
1234                                 tt,title,ta,artist,tx,year,del,album,tn,track);
1235         }
1236         else {
1237 SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s",
1238                                 ta,artist,tx,year,del,album,tn,track);
1239         }
1240   b[len-1]=0;
1241   return b;
1242 }
1243
1244 void DemuxerAudio::setSkipFactor(int factor) {
1245         Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor);
1246         buffer->setSkipFactor(factor);
1247 }
1248