📄 mp3s.c
字号:
/* 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 + -