⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3s.c

📁 P2P NAP的C实现 P2P在网络应用中越来越流行
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2000  Kevin Sullivan <nite@gis.net> * * Please refer to the COPYRIGHT file for more information. *//* the main functions in this file are mp3info and ogginfo. They   extract information such as file size, bitrate, sample frequency,   and md5 hash from a named file */#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include "alias.h"#include "md5.h"#include "mp3s.h"#include "defines.h"#ifdef MEMWATCH  #include "memwatch.h"#endif/* arrays are indexed using id & bitrate fields from frame header *//* 1st row is for MPEG-2 (id=0) Layer III, 2nd for MPEG-1 (id=1) Layer III */int bratetab[2][16] =   {    { 0,  8, 16, 24, 32, 40, 48, 56,  64,  80,  96, 112, 128, 144, 160, -1 },    { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }  };int freqtab[2][4] =  {    { 22050, 24000, 16000, 50000 }, /* MPEG-2 */    { 44100, 48000, 32000, 50000 }  /* MPEG-1 */  }; /* check for valid mp3 header. Return 1 if ok. */int checkhdr(hdr_t *h){  if (h->sync != 0xfff ||      h->layer != 1 ||      h->brate == 15 ||      h->freq == 3 ||      h->emph == 2)    return(0);    return(1);}/* get "real" header info from an mp3 file. The stream f is already   positioned to skip any id3v2 header, if present */int getrhdr(int f, hdr_t *r){  unsigned char bw[4];  int n;  n = read(f, bw, sizeof(bw));  if (n < 4) { /* e.g. near EOF */    return(0);  }  buf4tohdr(bw, r);  if (!checkhdr(r))  {    return(0);  }    return(1);}/* convert an array of four bytes into a frame header (hdr_t) structure */void buf4tohdr(unsigned char *bw, hdr_t *r){  /* Note: to ensure portability, use explicit assignments and shift     operators, rather than writing binary data directly into the hdr_t     structure. The difference in efficiency is negligible. -PS */  r->emph      = (bw[3] & 0x03) >> 0;    r->original  = (bw[3] & 0x04) >> 2;    r->copyright = (bw[3] & 0x08) >> 3;    r->mode_ext  = (bw[3] & 0x30) >> 4;  r->mode      = (bw[3] & 0xc0) >> 6;  r->pvt       = (bw[2] & 0x01) >> 0;  r->pad       = (bw[2] & 0x02) >> 1;  r->freq      = (bw[2] & 0x0c) >> 2;  r->brate     = (bw[2] & 0xf0) >> 4;  r->prot      = (bw[1] & 0x01) >> 0;  r->layer     = (bw[1] & 0x06) >> 1;  r->id        = (bw[1] & 0x08) >> 3;  r->sync      = (bw[1] & 0xf0) >> 4;  r->sync     |= (bw[0] & 0xff) << 4;}/* bitmasks for Xing flags */#define XING_FRAMES     0x0001 #define XING_BYTES      0x0002#define XING_TOC        0x0004#define XING_VBR_SCALE  0x0008/* check if the frame with header h at startpos is an Xing VBR info frame * if yes, return 1 and calculate the length of the bitstream in seconds and * the average bitrate. * The Xing VBR info frame is "documented" in LAME's VbrTag.[ch] files. * It looks like a normal mp3 frame (it starts with a valid frame header) * but instead of containing bitstream data, it contains information on the * VBR bitsteam. It can be identified by the string "Xing" immediately * following the frame's side info. The next four bytes give flags identifying * what information is available in the frame. Usually, the info frame * provides the number of frames, the number of bytes in the bitstream * (excluding ID3 tags etc.), a 100-byte table of contents (TOC) array to * help an mp3 player seek within a VBR file, and a "VBR scale". We only care * about the first two items. */int checkxing(int f, hdr_t h, int startpos, size_t sz1, 	      int *seconds, int *avgbrate){  unsigned char buf[16];  unsigned char *p;  int bpsi, n, spf;  unsigned long flags, numframes, numbytes;    /* determine number of bytes of side info + optional 16-bit CRC */  if (h.id == 1)    bpsi = (h.mode == 3) ? 17 : 32;  else    bpsi = (h.mode == 3) ? 9 : 17;  if (h.prot == 0) /* 16-bit CRC follows frame header */    bpsi += 2;    /* skip header, CRC, and side info */  lseek(f, startpos+4+bpsi, SEEK_SET);   n = read(f, buf, sizeof(buf));  if (n < 16) {    return 0;  }  if (strncmp(buf, "Xing", 4) != 0) {    return 0;  }  /* this frame is an Xing info frame; next four bytes are the Xing flags */  p = buf+4;  flags = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \          (unsigned long)p[2] << 8  | (unsigned long)p[3];  if (flags & XING_FRAMES) { /* next four bytes give number of frames */    p = buf+8;    numframes = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \                (unsigned long)p[2] << 8  | (unsigned long)p[3];  } else {    /* Xing frame doesn't even tell us how many frames there are! */    return 0;  }  if (flags & XING_BYTES) {    /* next 4 bytes give number of bytes in bitstream */    p = buf+12;    numbytes = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \               (unsigned long)p[2] << 8  | (unsigned long)p[3];  } else {    /* just use what we already know about the bitstream size */    numbytes = sz1;  }  if ((numframes == 0) || (numbytes == 0)) { /* broken Xing frame? */      return 0;  }  /* number of seconds = numframes * (seconds per frame)    * seconds per frame = (samples/frame)*(seconds/sample) = spf * (1/freq)   * spf = 1152 (MPEG-1 Layer III) or 576 (MPEG-2 Layer III) (576*2=1152) */  spf = (h.id) ? 1152 : 576;  *seconds = numframes * spf / freqtab[h.id][h.freq];  *avgbrate = numbytes * 8 / (*seconds * 1000);  return 1;}/* check if two frame headers have same id, layer, prot, freq, mode fields */int samestream(hdr_t a, hdr_t b) {   if ((a.id == b.id) && (a.layer == b.layer) && (a.prot == b.prot) &&        (a.freq == b.freq) && (a.mode == b.mode)) {     return(1);   }   return(0);}/* The frame length is calculated as follows: * bpf = bytes per frame (including frame header) *     = bits/second * bytes/bit * samples/frame * seconds/sample *     = 1000 * kbps * 1/8 * spf * (1/freq) *     = kbps * 125 * spf * (1/freq) * spf = 1152 (MPEG-1 Layer III) or 576 (MPEG-2 Layer III)  *    * Note that freq doesn't evenly divide into kbps*spf*125 when freq is * 22050 or 44100. It seems that encoders deal with the remainder by adding * an extra byte to some of the frames and setting the pad bit in the frame * header. We must add one to bpf if a frame header's pad bit is 1.  */ int framesize(hdr_t h){  int kbps, freq, bpf, spf;    kbps = bratetab[h.id][h.brate];  freq = freqtab[h.id][h.freq];  spf = (h.id) ? 1152 : 576;  bpf = (kbps * spf * 125 / freq) + h.pad;  return(bpf);}/* return 1 if it looks like the file has a variable bitrate *   startpos is the position in file f where the mp3 stream starts,  *   size is the size of f in bytes * If there is no Xing VBR info frame,  * the only way to know for sure if a file is VBR is to read every single * frame header. This takes a relatively long time, so we use an approximate * method borrowed from Cedric Tefft's mp3info. The idea is to sample a few * frame headers throughout the file to see if they have the same bitrate as * the first header in the file. Although this works well in practice, * it is not fail-proof: * 1) some VBR files might not be recognized as VBR if the set of  *    headers sampled happen to have the same bitrate * 2) because we jump into the middle of the file and look for a frame header, *    it is possible that what looks like a frame header is actually frame *    data. If this false frame header happens to have a bitrate field that *    differs from that of the first header, a non-VBR file might be  *    incorrectly identified as VBR. As a result, the file will be unneccessarily *    fully scanned in mp3info. */int checkvbr(int f, int startpos, int size, hdr_t firsthdr){  int stepsize, i, j, isvbr, headerfound, bpf;  unsigned char buf[4];  hdr_t h, h2;  isvbr = 0;  stepsize = (size - startpos)/4;  /* sample up to three headers throughout the file and compare the   * header's bitrate to that of the first header */  for (i = 1; i < 4; i++) {    lseek(f, startpos + i*stepsize, SEEK_SET);    headerfound = 0;    /* get first four bytes at this position */    if (read(f, buf, 4) < 4)      break;      /* scan for frame header. Limit search to max frame size (1440 bytes) */    for (j = 0; j < 1440; j++) {       buf4tohdr(buf, &h);      if (checkhdr(&h) && samestream(firsthdr, h)) {        /* id, layer, prot, freq, and mode match first header */        /* if h is really a header, there should also be a header following         * this frame */        bpf = framesize(h);        lseek(f, bpf-4, SEEK_CUR);        if (read(f, buf, 4) < 4)          break;        buf4tohdr(buf, &h2);        if (checkhdr(&h2) && samestream(firsthdr, h2)) {          /* found two consecutive frame headers that match first header's           * id, layer, prot, freq, and mode. h is probably a real header. */          headerfound = 1;          break;        }        /* h2 is not a valid header, so neither is h. Rewind. */        lseek(f, -bpf, SEEK_CUR);      }      /* h is not a valid header; continue searching */      buf[0] = buf[1];      buf[1] = buf[2];      buf[2] = buf[3];      if (!read(f, &buf[3], 1))         break;     } /* end for j */    if (!headerfound) {      /* there's something wrong (couldn't find a valid header)       * but we pretend not to notice (act as if the file were CBR) */      break;     }    if (firsthdr.brate != h.brate) { /* bitrates differ */      isvbr = 1;      break;    }    /* bitrates matched, try a header in another section of the file */  } /* end for */  return(isvbr);}/* get the mp3 information (bitrate, frequency, length in seconds,   size in bytes, and checksum) from the named mp3 file. */mhdr_t *mp3info(char *fn){  hdr_t m;  mhdr_t *r;  int f;  size_t size = 0;  struct stat st;  id3v2_t tag;  char rdt[3];  size_t id3size, endtagsize;  int numframes, bpf, spf;  int seconds, avgbrate;  hdr_t h;  int res;  f = open(fn, O_RDONLY);  if (f == -1)    return(NULL);    /* first check whether there is an id3v2 header. Let id3size be its     length. */  id3size = 0;  memset(rdt, 0, sizeof(rdt));  read(f, &rdt, 3);  if (!strncmp(rdt, "ID3", 3))  /* found id3v2 header */  {    lseek(f, 0, SEEK_SET);    read(f, &tag, sizeof(tag));    /* corrected a bug here: according to id3v2 spec, the size is

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -