Logo Search packages:      
Sourcecode: ncdt version File versions  Download package

ncdt_mp3.c

/*
 * NcdT -- directory tree printer with extended capabilities
 * (C) 1999-2001 by Pawel Wiecek <coven@vmh.net>
 * See Copying file for licence.
 * 
 * MP3 handler
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include "ncdt.h"

static int tabsel_123[2][3][16]={
 {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
  {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
  {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}},
 {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
  {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
  {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}}
};
static long freqs[9]={44100,48000,32000,22050,24000,16000,11025,12000,8000};
static char modes[4]="SJDM";

void mp3info(char *fname, struct TREE *p) {
 char buf[1024], *ptr;
 int ri, id, fd, vbr, vbroff;
 unsigned char head[4], th2[3], vbh[4];
 unsigned char mpeg25, lsf, layer, errp, bitrate, freq, pad, ext, mode,
               modext, copy, orig, emph, freq_;
 long fs, sfd, secs, off, len;
 unsigned vflags, vframes=0, vbytes=0;

 fd=open(fname,O_RDONLY);
 off=id=0;
 if(fd>=0) {
  read(fd,head,4);
  ri=!strncmp(head,"RIFF",4);
  if(ri) {  /* This is messy... RIFF headers might have various length (!)
               and we of course don't know how to figure it out (actually
               this shouldn't be very hard to do I guess -- RIFF is a
               fairly simple format. Unless the difference is in the
               format of the last chunk, which is of course entirely
               possible). So all we can do is to scan the file until we
               find its end... Hopefully it's within the first 1024 bytes
               (1032 actually). Anyway, mpg123 does this in the same way
               as we do. */
   read(fd,buf,1024);
   for(ptr=buf;(ptr<buf+1020)&&strncmp(ptr,"data",4);ptr++);
   if(!strncmp(ptr,"data",4)) {
    off=lseek(fd,ptr-buf+12,SEEK_SET);
    read(fd,head,4);
   }
  }
  if(!strncmp(head,"ID3\3",4)) {
   id=2;
   lseek(fd,2,SEEK_CUR);
   read(fd,head,4);
   /* what a messy way to encode tag length! */
   off=lseek(fd,(head[0]<<21)|(head[1]<<14)|(head[2]<<7)|(head[3]),SEEK_CUR);
   read(fd,head,4);
  }
  ri=!strncmp(head,"RIFF",4);
  if(ri) {  /* Might also happen here */
   read(fd,buf,1024);
   for(ptr=buf;(ptr<buf+1020)&&strncmp(ptr,"data",4);ptr++);
   if(!strncmp(ptr,"data",4)) {
    off=lseek(fd,off+ptr-buf+12,SEEK_SET);
    read(fd,head,4);
   }
  }
  if((head[0]==0xff)&&((head[1]&0xe0)==0xe0)) {
   mpeg25=(head[1]>>4)&1;
   if(mpeg25) lsf=(head[1]>>3)&1;
         else lsf=0;
   layer=(head[1]>>1)&3;
   errp=head[1]&1;
   bitrate=(head[2]>>4)&15;
   freq=(head[2]>>2)&3;
   pad=(head[2]>>1)&1;
   ext=head[2]&1;
   mode=(head[3]>>6)&3;
   modext=(head[3]>>4)&3;
   copy=(head[3]>>3)&1;
   orig=(head[3]>>2)&1;
   emph=head[3]&3;
   vbroff=((head[1]>>3)&1)?((mode==3)?17:32):((mode==3)?9:17);
   lseek(fd,vbroff,SEEK_CUR);
   read(fd,vbh,4);
   if(!strncmp(vbh,"Xing",4)) {
    vbr=1;
    read(fd,vbh,4);
    vflags=(vbh[0]<<24)|(vbh[1]<<16)|(vbh[2])<<8|vbh[3];
    if(vflags&1) {
     read(fd,vbh,4);
     vframes=(vbh[0]<<24)|(vbh[1]<<16)|(vbh[2])<<8|vbh[3];
    } else {
     vframes=1;
    }
    if(vflags&2) {
     read(fd,vbh,4);
     vbytes=(vbh[0]<<24)|(vbh[1]<<16)|(vbh[2])<<8|vbh[3];
    } else {
     vbytes=0;
    }
   } else {
    vbr=0;
   }
   len=lseek(fd,-128,SEEK_END)-off;
   read(fd,th2,3);
   if(!strncmp(th2,"TAG",3)) {
    if(!id) id=1;
   } else {
    len+=128;
   }
   freq_=mpeg25?(freq+3*!lsf):(6+freq);
   if(vbr) {
    p->brmin=(vbytes?vbytes:len)/vframes*freqs[freq_]/144000;
    sfd=freqs[freq_]*(2-lsf);
    secs=((vframes)*((layer==2)?384:1152)+sfd/2)/sfd;
   } else {
    p->brmin=tabsel_123[!lsf][3-layer][bitrate];
    fs=((((long)p->brmin*((layer==2)?12000:144000))/
       (freqs[freq_]<<((!lsf)&&(layer==1)))+pad)<<(2*(layer==2)));
    sfd=freqs[freq_]*(2-lsf);
    secs=((len/fs)*((layer==2)?384:1152)+sfd/2)/sfd;
   }
   p->name=realloc(p->name,strlen(p->name)+24);
   sprintf(p->name+strlen(p->name),"  <%s %s%d%c%s%s>",nicetime(secs),
         vbr?"v":"",p->brmin,modes[mode],ri?"R":"",id?((id==2)?"+":""):"-");
   p->time=secs;
   p->brmax=p->brmin;
  }
  close(fd);
 }
}

Generated by  Doxygen 1.6.0   Back to index