decoder-mp3.c
author nathan
Sat, 29 Dec 2007 14:49:09 +0100
branchtrunk
changeset 2 4c1f7b705009
parent 0 474a1293c3c0
child 25 887faebaba0a
permissions -rw-r--r--
release 0.10.1
     1 /*
     2  * MP3/MPlayer plugin to VDR (C++)
     3  *
     4  * (C) 2001-2005 Stefan Huelswitt <s.huelswitt@gmx.de>
     5  *
     6  * This code is free software; you can redistribute it and/or
     7  * modify it under the terms of the GNU General Public License
     8  * as published by the Free Software Foundation; either version 2
     9  * of the License, or (at your option) any later version.
    10  *
    11  * This code 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 this program; if not, write to the Free Software
    18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    19  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    20  */
    21 
    22 #include <stdlib.h>
    23 #include <stdio.h>
    24 
    25 #include "common.h"
    26 #include "data-mp3.h"
    27 #include "decoder-mp3.h"
    28 #include "stream.h"
    29 
    30 #define MAX_FRAME_ERR 10
    31 
    32 // ----------------------------------------------------------------
    33 
    34 int MadStream(struct mad_stream *stream, cStream *str)
    35 {
    36   unsigned char *data;
    37   unsigned long len;
    38   if(str->Stream(data,len,stream->next_frame)) {
    39     if(len>0) mad_stream_buffer(stream, data, len);
    40     return len;
    41     }
    42   return -1;
    43 }
    44 
    45 // --- cMP3Decoder -------------------------------------------------------------
    46 
    47 cMP3Decoder::cMP3Decoder(const char *Filename, bool preinit)
    48 :cDecoder(Filename)
    49 {
    50   str=0; scan=0; isStream=false;
    51   if(preinit) {
    52     //d(printf("mp3: preinit\n"))
    53     str=new cStream(filename);
    54     scan=new cScanID3(str,&urgentLock);
    55     }
    56   fi=0; stream=0; frame=0; synth=0;
    57 }
    58 
    59 cMP3Decoder::~cMP3Decoder()
    60 {
    61   Clean();
    62   delete scan;
    63   delete str;
    64 }
    65 
    66 bool cMP3Decoder::Valid(void)
    67 {
    68   bool res=false;
    69   if(TryLock()) {
    70     struct mad_stream stream;
    71     struct mad_header header;
    72     mad_stream_init(&stream);
    73     mad_stream_options(&stream,MAD_OPTION_IGNORECRC);
    74     mad_header_init(&header);
    75     if(str->Open() && str->Seek()) {
    76       int count=10;
    77       do {
    78         if(mad_header_decode(&header,&stream)<0) {
    79           if(stream.error==MAD_ERROR_BUFLEN || stream.error==MAD_ERROR_BUFPTR) {
    80             if(MadStream(&stream,str)<=0) break;
    81             }
    82           else if(!MAD_RECOVERABLE(stream.error)) break;
    83           count++;
    84           }
    85         } while(--count);
    86       if(!count) res=true;
    87       }
    88     mad_header_finish(&header);
    89     mad_stream_finish(&stream);
    90     str->Close();
    91     Unlock();
    92     }
    93   return res;
    94 }
    95 
    96 cFileInfo *cMP3Decoder::FileInfo(void)
    97 {
    98   cFileInfo *fi=0;
    99   if(str->HasInfo()) fi=str;
   100   else if(TryLock()){
   101     if(str->Open()) { fi=str; str->Close(); }
   102     Unlock();
   103     }
   104   return fi;
   105 }
   106 
   107 cSongInfo *cMP3Decoder::SongInfo(bool get)
   108 {
   109   cSongInfo *si=0;
   110   if(scan->HasInfo()) si=scan;
   111   else if(get && TryLock()) {
   112     if(scan->DoScan()) si=scan;
   113     Unlock();
   114     }
   115   return si;
   116 }
   117 
   118 cPlayInfo *cMP3Decoder::PlayInfo(void)
   119 {
   120   if(playing) {
   121     pi.Index=mad_timer_count(playtime,MAD_UNITS_SECONDS);
   122     pi.Total=scan->Total;
   123     return &pi;
   124     }
   125   return 0;
   126 }
   127 
   128 void cMP3Decoder::Init(void)
   129 {
   130   Clean();
   131   stream=new struct mad_stream;
   132   mad_stream_init(stream);
   133   mad_stream_options(stream,MAD_OPTION_IGNORECRC);
   134   frame=new struct mad_frame;
   135   mad_frame_init(frame);
   136   synth=new struct mad_synth;
   137   mad_synth_init(synth);
   138   playtime=mad_timer_zero; skiptime=mad_timer_zero;
   139   framenum=framemax=0; mute=errcount=0;
   140 }
   141 
   142 void cMP3Decoder::Clean(void)
   143 {
   144   playing=false;
   145   if(synth) { mad_synth_finish(synth); delete synth; synth=0; }
   146   if(frame) { mad_frame_finish(frame); delete frame; frame=0; }
   147   if(stream) { mad_stream_finish(stream); delete stream; stream=0; }
   148   delete[] fi; fi=0;
   149 }
   150 
   151 bool cMP3Decoder::Start(void)
   152 {
   153   Lock(true);
   154   Init(); playing=true;
   155   if(str->Open() && scan->DoScan(true)) {
   156     if(!isStream) {
   157       str->Seek();
   158       framemax=scan->Frames+20;
   159       fi=new struct FrameInfo[framemax];
   160       if(!fi) esyslog("ERROR: no memory for frame index, rewinding disabled");
   161       }
   162     Unlock();
   163     return true;
   164     }
   165   str->Close();
   166   Clean();
   167   Unlock();
   168   return false;
   169 }
   170 
   171 bool cMP3Decoder::Stop(void)
   172 {
   173   Lock();
   174   if(playing) {
   175     str->Close();
   176     Clean();
   177     }
   178   Unlock();
   179   return true;
   180 }
   181 
   182 struct Decode *cMP3Decoder::Done(eDecodeStatus status)
   183 {
   184   ds.status=status;
   185   ds.index=mad_timer_count(playtime,MAD_UNITS_MILLISECONDS);
   186   ds.pcm=&synth->pcm;
   187   Unlock(); // release the lock from Decode()
   188   return &ds;
   189 }
   190 
   191 eDecodeStatus cMP3Decoder::DecodeError(bool hdr)
   192 {
   193   if(stream->error==MAD_ERROR_BUFLEN || stream->error==MAD_ERROR_BUFPTR) {
   194     int s=MadStream(stream,str);
   195     if(s<0) return dsError;
   196     if(s==0) return dsEof;
   197     }
   198   else if(!MAD_RECOVERABLE(stream->error)) {
   199     d(printf("mad: decode %sfailed, frame=%d: %s\n",hdr?"hdr ":"",framenum,mad_stream_errorstr(stream)))
   200     return dsError;
   201     }
   202   else { 
   203     if(stream->error==MAD_ERROR_LOSTSYNC) { // check for ID3 tags
   204 #ifdef DEBUG
   205       char buf[10];
   206       int buf2[3];
   207       memcpy(buf,stream->this_frame,8); buf[8]=0;
   208       memcpy(buf2,stream->this_frame,8);
   209       printf("mad: lost sync %08x %08x %s\n",buf2[0],buf2[1],buf);
   210 #endif
   211       id3_length_t count=stream->bufend-stream->this_frame;
   212       id3_length_t tagsize=id3_tag_query(stream->this_frame,count);
   213       if(tagsize>0) {
   214         d(printf("mad: skipping over ID3 tag\n"))
   215         if(count>tagsize) count=tagsize;
   216         mad_stream_skip(stream,count);
   217         while(count<tagsize) {
   218           unsigned char *sdata;
   219           unsigned long slen;
   220           if(!str->Stream(sdata,slen)) return dsError;
   221           if(slen<=0) return dsEof;
   222           unsigned long len=min(tagsize-count,slen);
   223           count+=len;
   224           sdata+=len; slen-=len;
   225           if(slen>0) mad_stream_buffer(stream,sdata,slen);
   226           }
   227         return dsOK;
   228         }
   229       }
   230     errcount+=hdr?1:100;
   231     d(printf("mad: decode %serror, frame=%d count=%d: %s\n",hdr?"hdr ":"",framenum,errcount,mad_stream_errorstr(stream)))
   232     }
   233   return dsOK;
   234 }
   235 
   236 struct Decode *cMP3Decoder::Decode(void)
   237 {
   238   Lock(); // this is released in Done()
   239   eDecodeStatus r;
   240   while(playing) {
   241     if(errcount>=MAX_FRAME_ERR*100) {
   242       esyslog("ERROR: excessive decoding errors, aborting file %s",filename);
   243       return Done(dsError);
   244       }
   245 
   246     if(mad_header_decode(&frame->header,stream)<0) {
   247       if((r=DecodeError(true))) return Done(r);
   248       }
   249     else {
   250       if(!isStream) {
   251 #ifdef DEBUG
   252         if(framenum>=framemax) printf("mp3: framenum >= framemax!!!!\n");
   253 #endif
   254         if(fi && framenum<framemax) {
   255           fi[framenum].Pos=str->BufferPos() + (stream->this_frame-stream->buffer);
   256           fi[framenum].Time=playtime;
   257           }
   258         }
   259 
   260       mad_timer_add(&playtime,frame->header.duration); framenum++;
   261 
   262       if(mad_timer_compare(playtime,skiptime)>=0) skiptime=mad_timer_zero;
   263       else return Done(dsSkip);  // skipping, decode next header
   264 
   265       if(mad_frame_decode(frame,stream)<0) {
   266         if((r=DecodeError(false))) return Done(r);
   267         }
   268       else {
   269         errcount=0;
   270         scan->InfoHook(&frame->header);
   271         mad_synth_frame(synth,frame);
   272         if(mute) { mute--; return Done(dsSkip); }
   273         return Done(dsPlay);
   274         }
   275       }
   276     }
   277   return Done(dsError);
   278 }
   279 
   280 void cMP3Decoder::MakeSkipTime(mad_timer_t *skiptime, mad_timer_t playtime, int secs, float bsecs)
   281 {
   282   mad_timer_t time;
   283   *skiptime=playtime;
   284   mad_timer_set(&time,abs(secs),0,0);
   285   if(secs<0) mad_timer_negate(&time);
   286   mad_timer_add(skiptime,time);
   287   int full=(int)bsecs; bsecs-=(float)full;
   288   mad_timer_set(&time,full,(int)(bsecs*1000.0),1000);
   289   mad_timer_negate(&time);
   290   mad_timer_add(skiptime,time);
   291   d(printf("mp3: skip: playtime=%ld secs=%d full=%d bsecs=%f skiptime=%ld\n",
   292            mad_timer_count(playtime,MAD_UNITS_MILLISECONDS),secs,full,bsecs,mad_timer_count(*skiptime,MAD_UNITS_MILLISECONDS)))
   293 }
   294 
   295 bool cMP3Decoder::Skip(int Seconds, float bsecs)
   296 {
   297   Lock();
   298   bool res=false;
   299   if(playing && !isStream) {
   300     if(!mad_timer_compare(skiptime,mad_timer_zero)) { // allow only one skip at any time
   301       mad_timer_t time;
   302       MakeSkipTime(&time,playtime,Seconds,bsecs);
   303 
   304       if(mad_timer_compare(playtime,time)<=0) { // forward skip
   305 #ifdef DEBUG
   306         int i=mad_timer_count(time,MAD_UNITS_SECONDS);
   307         printf("mp3: forward skipping to %02d:%02d\n",i/60,i%60);
   308 #endif
   309         skiptime=time; mute=1;
   310         res=true;
   311         }
   312       else {                                    // backward skip
   313         if(fi) {
   314 #ifdef DEBUG
   315           int i=mad_timer_count(time,MAD_UNITS_SECONDS);
   316           printf("mp3: rewinding to %02d:%02d\n",i/60,i%60);
   317 #endif
   318           while(framenum && mad_timer_compare(time,fi[--framenum].Time)<0) ;
   319           mute=2; if(framenum>=2) framenum-=2;
   320           playtime=fi[framenum].Time;
   321           str->Seek(fi[framenum].Pos);
   322           mad_stream_finish(stream); // reset stream buffer
   323           mad_stream_init(stream);
   324 #ifdef DEBUG
   325           i=mad_timer_count(playtime,MAD_UNITS_MILLISECONDS);
   326           printf("mp3: new playtime=%d framenum=%d filepos=%lld\n",i,framenum,fi[framenum].Pos);
   327 #endif
   328           res=true;
   329           }
   330         }
   331       }
   332     }
   333   Unlock();
   334   return res;
   335 }
   336 
   337 // --- cScanID3 ----------------------------------------------------------------
   338 
   339 // This function was adapted from mad_timer, from the 
   340 // libmad distribution
   341 
   342 #define MIN_SCAN_FRAMES 200 // min. number of frames to scan
   343 
   344 cScanID3::cScanID3(cStream *Str, bool *Urgent)
   345 {
   346   str=Str;
   347   urgent=Urgent;
   348 }
   349 
   350 bool cScanID3::Abort(bool result)
   351 {
   352   if(!keepOpen) str->Close();
   353   return result;
   354 }
   355 
   356 bool cScanID3::DoScan(bool KeepOpen)
   357 {
   358   mad_timer_t duration=mad_timer_zero;
   359   unsigned int bitrate=0, minrate=~0, maxrate=0;
   360   int xframes=0;
   361   unsigned int id3_vers=0;
   362   bool is_vbr=false, has_id3=false;
   363 
   364   keepOpen=KeepOpen;
   365   if(!str->Open()) return Abort(false);
   366   if(HasInfo()) return Abort(true);
   367 
   368   // check the infocache
   369   cCacheData *dat=InfoCache.Search(str);
   370   if(dat) {
   371     Set(dat); dat->Unlock();
   372     if(!DecoderID) {
   373       DecoderID=DEC_MP3;
   374       InfoCache.Cache(this,str);
   375       }
   376     return Abort(true);
   377     }
   378 
   379   Clear();
   380 
   381   // do a initial check for a ID3v1 tag at the end of the file
   382   // to speed up the following scan
   383   if(str->Filesize>=128 && str->Seek(str->Filesize-128)) {
   384     unsigned char *data;
   385     unsigned long len;
   386     if(str->Stream(data,len)) {
   387       struct id3_tag *tag=id3_tag_parse(data,len);
   388       if(tag) {
   389         d(printf("id3-scan: initialy found ID3 V1 tag at EOF\n"))
   390         ParseID3(tag);
   391         has_id3=true; id3_vers=tag->version;
   392         id3_tag_delete(tag);
   393         }
   394       }
   395     }
   396   if(!str->Seek()) return Abort(false);
   397 
   398   // There are three ways of calculating the length of an mp3:
   399   // 1) Constant bitrate: One frame can provide the information
   400   //    needed: # of frames and duration. Just see how long it
   401   //    is and do the division.
   402   // 2) Variable bitrate: Xing tag. It provides the number of 
   403   //    frames. Each frame has the same number of samples, so
   404   //    just use that.
   405   // 3) All: Count up the frames and duration of each frames
   406   //    by decoding each one. We do this if we've no other
   407   //    choice, i.e. if it's a VBR file with no Xing tag.
   408 
   409   struct mad_stream stream;
   410   struct mad_header header;
   411   mad_stream_init(&stream);
   412   mad_stream_options(&stream,MAD_OPTION_IGNORECRC);
   413   mad_header_init(&header);
   414   bool res=true;
   415   int errcount=0;
   416   while(1) {
   417     if(*urgent) {
   418       d(printf("id3-scan: urgent request, aborting!\n"))
   419       res=false; break; // abort scan if there is an urgent request for the decoder lock
   420       }
   421 
   422     if(mad_header_decode(&header,&stream)<0) {
   423       if(stream.error==MAD_ERROR_BUFLEN || stream.error==MAD_ERROR_BUFPTR) {
   424         int s=MadStream(&stream,str);
   425         if(s>0) continue;
   426         if(s<0) res=false;
   427         break;
   428         }
   429       else if(stream.error==MAD_ERROR_LOSTSYNC) { // check for ID3 tags
   430 #ifdef DEBUG
   431         char buf[10];
   432         int buf2[3];
   433         memcpy(buf,stream.this_frame,8); buf[8]=0;
   434         memcpy(buf2,stream.this_frame,8);
   435         printf("id3-scan: lost sync %08x %08x %s\n",buf2[0],buf2[1],buf);
   436 #endif
   437         id3_length_t tagsize=id3_tag_query(stream.this_frame,stream.bufend-stream.this_frame);
   438         if(tagsize>0) {
   439 	  struct id3_tag *tag=GetID3(&stream,tagsize);
   440 	  if(tag) {
   441             unsigned int vers=id3_tag_version(tag);
   442             d(printf("id3-scan: found ID3 %s tag (%d.%d)\n",vers==0x100?"V1":"V2",ID3_TAG_VERSION_MAJOR(vers),ID3_TAG_VERSION_MINOR(vers)))
   443             if(!has_id3 || vers>id3_vers) {
   444               ParseID3(tag);
   445               has_id3=true; id3_vers=vers;
   446               }
   447 	    id3_tag_delete(tag);
   448 	    }
   449           }
   450         continue;
   451         }
   452       else {
   453         d(printf("id3-scan: decode header error (frame %d): %s\n",Frames,mad_stream_errorstr(&stream)))
   454         errcount++;
   455         if(errcount<MAX_FRAME_ERR*100 && MAD_RECOVERABLE(stream.error)) continue;
   456         res=false; break;
   457         }
   458       }
   459     errcount=0;
   460     if(header.bitrate>maxrate) maxrate=header.bitrate;
   461     if(header.bitrate<minrate) minrate=header.bitrate;
   462 
   463     // Limit xing testing to the first frame header
   464     if(!Frames) {
   465       if((xframes=ParseXing(&stream.anc_ptr, stream.anc_bitlen))>=0) {
   466         is_vbr=true;
   467         }
   468       }                
   469     // Test the first n frames to see if this is a VBR file
   470     if(!is_vbr && Frames<MIN_SCAN_FRAMES) {
   471       if(bitrate && header.bitrate!=bitrate) is_vbr=true;
   472       else bitrate=header.bitrate;
   473       }
   474     // We have to assume it's not a VBR file if it hasn't already been
   475     // marked as one and we've checked n frames for different bitrates
   476     else if(!is_vbr && has_id3)
   477       {
   478       break;
   479       }
   480 
   481     Frames++;
   482     mad_timer_add(&duration,header.duration);
   483     }
   484   mad_header_finish(&header);
   485   mad_stream_finish(&stream);
   486 
   487   if(res) {
   488     d(printf("mad: scanned %d frames%s\n",Frames,Frames?"":"(is this really a mp3?)"))
   489     if(Frames) {
   490       SampleFreq=header.samplerate;
   491       Channels=MAD_NCHANNELS(&header);
   492       ChMode=header.mode;
   493       DecoderID=DEC_MP3;
   494       InfoDone();
   495 
   496       if(!is_vbr) {
   497         d(printf("mad: constant birate\n"))
   498         double time = (str->Filesize * 8.0) / (header.bitrate);  // time in seconds
   499         long nsamples = 32 * MAD_NSBSAMPLES(&header);   // samples per frame
   500 
   501         Frames = (long)(time * header.samplerate / nsamples);
   502         Total  = (long)time;
   503         Bitrate= (int)bitrate;
   504         }
   505       else if(xframes>0) {
   506         d(printf("mad: vbr, but has Xing frame\n"))
   507         mad_timer_multiply(&header.duration, xframes);
   508         Frames = xframes;
   509         Total  = mad_timer_count(header.duration,MAD_UNITS_SECONDS);
   510         }
   511       else {
   512         // the durations have been added up, and the number of frames counted. We do nothing here.
   513         d(printf("mad: vbr detected\n"))
   514         Total      = mad_timer_count(duration,MAD_UNITS_SECONDS);
   515         Bitrate    = (int)minrate;
   516         MaxBitrate = (int)maxrate;
   517         }
   518 
   519       if(!has_id3 || !Title) FakeTitle(str->Filename,".mp3");
   520       InfoCache.Cache(this,str);
   521       }
   522     }
   523   return Abort(res);
   524 }
   525 
   526 // This function was adapted from player.c, from the 
   527 // libmad distribution
   528 
   529 struct id3_tag *cScanID3::GetID3(struct mad_stream *stream, id3_length_t tagsize) const
   530 {
   531   struct id3_tag *tag=0;
   532   const id3_byte_t *data;
   533   id3_byte_t *allocated=0;
   534 
   535   id3_length_t count=stream->bufend-stream->this_frame;
   536 
   537   if(count>=tagsize) {
   538     data=stream->this_frame;
   539     mad_stream_skip(stream,tagsize);
   540     }
   541   else {
   542     if(!(allocated=(id3_byte_t *)malloc(tagsize))) {
   543       esyslog("ERROR: not enough memory for id3 tag buffer");
   544       return 0;
   545       }
   546     memcpy(allocated,stream->this_frame,count);
   547     mad_stream_skip(stream,count);
   548 
   549     while(count<tagsize) {
   550       unsigned char *sdata;
   551       unsigned long len, slen;
   552 
   553       if(!str->Stream(sdata,slen) || !slen) {
   554          d(printf("mad: error or eof on ID3 tag parse\n"))
   555          free(allocated);
   556          return 0;
   557          }
   558       len=tagsize-count; if(len>slen) len=slen;
   559       memcpy(allocated+count,sdata,len);
   560       count+=len;
   561       sdata+=len; slen-=len;
   562       if(slen) mad_stream_buffer(stream,sdata,slen);
   563       }
   564     data=allocated;
   565     }
   566 
   567   tag=id3_tag_parse(data,tagsize);
   568   if(allocated) free(allocated);
   569   return tag;
   570 }
   571 
   572 void cScanID3::ParseID3(const struct id3_tag *tag)
   573 {
   574   d(printf("id3-scan: parsing ID3 tag\n"))
   575   ParseStr(tag,ID3_FRAME_TITLE,Title);
   576   ParseStr(tag,ID3_FRAME_ARTIST,Artist);
   577   ParseStr(tag,ID3_FRAME_ALBUM,Album);
   578   char *data=0;
   579   ParseStr(tag,ID3_FRAME_YEAR,data);
   580   if(data) Year=atol(data);
   581   free(data);
   582   //ParseStr(tag,ID3_FRAME_TRACK,Track);
   583   //ParseStr(tag,ID3_FRAME_GENRE,Genre);
   584 }
   585 
   586 /*
   587 void cScanID3::ParsePic(const struct id3_tag *tag, const char *id, char * &name)
   588 {
   589   const struct id3_frame *frame=id3_tag_findframe(tag,id,0);
   590   if(frame) {
   591     id3_length_t len;
   592     const id3_byte_t *data=id3_field_getbinarydata(&frame->fields[1],&len);
   593     if(data && len>0) {
   594       static const char salt[] = { "$1$id3__pic$" };
   595       
   596       }
   597     }
   598 }
   599 */
   600 
   601 // This function was adapted from player.c, from the 
   602 // libmad distribution 
   603 
   604 void cScanID3::ParseStr(const struct id3_tag *tag, const char *id, char * &data)
   605 {
   606   const struct id3_frame *frame=id3_tag_findframe(tag,id,0);
   607   if(!frame) return;
   608 
   609   free(data); data=0;
   610   const union id3_field *field=&frame->fields[1];
   611   if(id3_field_getnstrings(field)>0) {
   612     const id3_ucs4_t *ucs4=id3_field_getstrings(field,0);
   613     if(!ucs4) return;
   614     if(!strcmp(id,ID3_FRAME_GENRE)) ucs4=id3_genre_name(ucs4);
   615 
   616     id3_latin1_t *latin1=id3_ucs4_latin1duplicate(ucs4);
   617     if(!latin1) return;
   618 
   619     data=strdup((char *)latin1);
   620     free(latin1);
   621     }
   622 }
   623 
   624 // XING parsing was adapted from the MAD winamp input plugin,
   625 // from the libmad distribution
   626 
   627 #define XING_MAGIC (('X'<<24) | ('i'<<16) | ('n'<<8) | 'g')
   628 #define XING_FRAMES 0x0001
   629 // #define XING_BYTES  0x0002
   630 // #define XING_TOC    0x0004
   631 // #define XING_SCALE  0x0008
   632 
   633 int cScanID3::ParseXing(struct mad_bitptr *ptr, unsigned int bitlen) const
   634 {
   635   if(bitlen>=64 && mad_bit_read(ptr,32)==XING_MAGIC) {
   636     int flags=mad_bit_read(ptr, 32);
   637     bitlen-=64;
   638     return (bitlen>=32 && (flags & XING_FRAMES)) ? mad_bit_read(ptr,32) : 0;
   639     }
   640   return -1;
   641 }