📄 dec_mpeg.c
字号:
/* -*- linux-c -*- Copyright (C) 2005 Tom Szilagyi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: dec_mpeg.c,v 1.24 2006/09/21 20:36:52 pasp Exp $*/#include <config.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <limits.h>#include <string.h>#ifdef _WIN32#include <glib.h>#else#include <pthread.h>#endif /* _WIN32 */#ifdef HAVE_MOD#include "dec_mod.h"#endif /* HAVE_MOD */#include "dec_mpeg.h"extern size_t sample_size;#ifdef HAVE_MPEG/* Uncomment this to get debug printouts *//* #define MPEG_DEBUG *//* use the first MAX_STAT_HEADERS number of headers to gather * statistical info if needed */#define MAX_STAT_HEADERS 256#define BYTES2INT(b1,b2,b3,b4) (((long)(b1 & 0xFF) << (3*8)) | \ ((long)(b2 & 0xFF) << (2*8)) | \ ((long)(b3 & 0xFF) << (1*8)) | \ ((long)(b4 & 0xFF) << (0*8)))#define SYNC_MASK (0x7ffL << 21)#define VERSION_MASK (3L << 19)#define LAYER_MASK (3L << 17)#define PROTECTION_MASK (1L << 16)#define BITRATE_MASK (0xfL << 12)#define SAMPLERATE_MASK (3L << 10)#define PADDING_MASK (1L << 9)#define PRIVATE_MASK (1L << 8)#define CHANNELMODE_MASK (3L << 6)#define MODE_EXT_MASK (3L << 4)#define COPYRIGHT_MASK (1L << 3)#define ORIGINAL_MASK (1L << 2)#define EMPHASIS_MASK 3L/* list of accepted file extensions */char * valid_extensions_mpeg[] = { "mp3", "mpa", "mpga", "mpega", "abs", "mp2", "mp2a", "mpa2", "mp1", NULL};/* MPEG Version table, sorted by version index */static const signed char version_table[4] = { MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1};/* Bitrate table for mpeg audio, indexed by row index and birate index */static const short bitrates[5][16] = { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */ {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */ {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */ {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */ {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */};/* Bitrate pointer table, indexed by version and layer */static const short *bitrate_table[3][3] = { {bitrates[0], bitrates[1], bitrates[2]}, {bitrates[3], bitrates[4], bitrates[4]}, {bitrates[3], bitrates[4], bitrates[4]}};/* Sampling frequency table, indexed by version and frequency index */static const long freq_table[3][3] = { {44100, 48000, 32000}, /* MPEG Version 1 */ {22050, 24000, 16000}, /* MPEG version 2 */ {11025, 12000, 8000}, /* MPEG version 2.5 */};/* check if 'head' is a valid mp3 frame header */static intis_mp3frameheader(unsigned long head) { if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */ return 0; if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */ return 0; if (!(head & LAYER_MASK)) /* no layer? */ return 0; if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */ return 0; if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */ return 0; return 1;}static intmp3headerinfo(mp3info_t *info, unsigned long header) { int bitindex, freqindex; /* MPEG Audio Version */ info->version = version_table[(header & VERSION_MASK) >> 19]; if (info->version < 0) return 0; /* Layer */ info->layer = 3 - ((header & LAYER_MASK) >> 17); if (info->layer == 3) return 0; info->protection = (header & PROTECTION_MASK) ? 1 : 0; /* Bitrate */ bitindex = (header & BITRATE_MASK) >> 12; info->bitrate = bitrate_table[info->version][info->layer][bitindex]; /* Sampling frequency */ freqindex = (header & SAMPLERATE_MASK) >> 10; if (freqindex == 3) return 0; info->frequency = freq_table[info->version][freqindex]; info->padding = (header & PADDING_MASK) ? 1 : 0; /* Calculate number of bytes, calculation depends on layer */ if (info->layer == 0) { info->frame_samples = 384; if (info->bitrate == 0) { info->frame_size = 0; } else { info->frame_size = (12000 * info->bitrate / info->frequency + info->padding) * 4; } } else { if ((info->version > MPEG_VERSION1) && (info->layer == 2)) { info->frame_samples = 576; } else { info->frame_samples = 1152; } if (info->bitrate == 0) { info->frame_size = 0; } else { info->frame_size = (1000/8) * info->frame_samples * info->bitrate / info->frequency + info->padding; } } /* Frametime fraction calculation. This fraction is reduced as far as possible. */ if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */ /* integer number of milliseconds, denominator == 1 */ info->ft_num = 1000 * info->frame_samples / info->frequency; info->ft_den = 1; } else { /* 44.1/22.05/11.025 kHz */ if (info->layer == 0) { info->ft_num = 147000 * 384 / info->frequency; info->ft_den = 147; } else { info->ft_num = 49000 * info->frame_samples / info->frequency; info->ft_den = 49; } } info->channel_mode = (header & CHANNELMODE_MASK) >> 6; info->mode_extension = (header & MODE_EXT_MASK) >> 4; info->emphasis = header & EMPHASIS_MASK;#ifdef MPEG_DEBUG/* printf( "Header: %08x, Ver %d, lay %d, bitr %d, freq %ld, " "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n", header, info->version, info->layer+1, info->bitrate, info->frequency, info->channel_mode, info->mode_extension, info->emphasis, info->frame_size, info->ft_num, info->ft_den);*/#endif /* MPEG_DEBUG */ return 1;}static unsigned long__find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header, int(*getfunc)(int fd, unsigned char *c)) { unsigned long header=0; unsigned char tmp; int i; long pos = 0; /* We remember the last header we found, to use as a template to see if the header we find has the same frequency, layer etc */ last_header &= 0xffff0c00; /* Fill up header with first 24 bits */ for(i = 0; i < 3; i++) { header <<= 8; if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; } do { header <<= 8; if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; if (max_offset > 0 && pos > max_offset) return 0; } while(!is_mp3frameheader(header) || (last_header?((header & 0xffff0c00) != last_header):0)); *offset = pos - 4;#ifdef MPEG_DEBUG/* if(*offset) printf("Warning: skipping %d bytes of garbage\n", *offset);*/#endif /* MPEG_DEBUG */ return header;}static intfileread(int fd, unsigned char *c) { return read(fd, c, 1);}unsigned longfind_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) { return __find_next_frame(fd, offset, max_offset, last_header, fileread);}/* compare two headers according to version, layer, frequency, channel_mode */intvlfc_cmp(mp3info_t *info1, mp3info_t *info2) { if (info1->version != info2->version) return 0; if (info1->layer != info2->layer) return 0; if (info1->frequency != info2->frequency) return 0; if (info1->channel_mode != info2->channel_mode) return 0; return 1;}voidskip_id3v2_header(int fd) { char buffer[12]; long id3_length = 0; if (read(fd, buffer, 10) != 10) { lseek(fd, 0, SEEK_SET); return; } if ((buffer[0] != 'I') || (buffer[1] != 'D') || (buffer[2] != '3')) { lseek(fd, 0, SEEK_SET); return; } id3_length = (((long)(buffer[6] & 0x7F) << (3*7)) | ((long)(buffer[7] & 0x7F) << (2*7)) | ((long)(buffer[8] & 0x7F) << (1*7)) | ((long)(buffer[9] & 0x7F) << (0*7))); id3_length += 10; /* add 10 byte header */#ifdef MPEG_DEBUG printf("id3_length = %ld\n", id3_length);#endif /* MPEG_DEBUG */ lseek(fd, id3_length, SEEK_SET);}intget_mp3file_info(int fd, mp3info_t *info) { unsigned long headers[MAX_STAT_HEADERS]; mp3info_t infos[MAX_STAT_HEADERS]; long offsets[MAX_STAT_HEADERS]; int vsn_counters[4]; int layer_counters[3]; int freq_counters[7]; int chmode_counters[4]; long offset; unsigned long header = 0; unsigned char frame[1800]; unsigned char *vbrheader; long bytecount = 0; int num_offsets; int frames_per_entry; int i; int j; long tmp; int ret; for (i = 0; i < 3; i++) { vsn_counters[i] = 0; layer_counters[i] = 0; freq_counters[i] = 0; chmode_counters[i] = 0; } vsn_counters[3] = 0; freq_counters[3] = 0; chmode_counters[3] = 0; for (i = 4; i < 7; i++) { freq_counters[i] = 0; } /* skip ID3v2 header, if present */ skip_id3v2_header(fd);#ifndef MPEG_STATREC /* use first valid mpeg frame header to retrieve stream info */ headers[0] = find_next_frame(fd, &bytecount, 0x100000, 0); /* Quit if we haven't found a valid header within 1M */ if (headers[0] == 0) return -1; memset(&infos[0], 0, sizeof(mp3info_t)); /* These two are needed for proper LAME gapless MP3 playback */ infos[0].enc_delay = -1; infos[0].enc_padding = -1; if (!mp3headerinfo(&infos[0], headers[0])) return -2; offsets[0] = lseek(fd, 0, SEEK_CUR); offset = offsets[0]; header = headers[0];#else /* more sophisticated approach - but slower as well. */ for (i = 0; i < 4; i++) { headers[i] = find_next_frame(fd, &bytecount, 0x100000, 0); /* Quit if we haven't found a valid header within 1M */ if (headers[i] == 0) return -1; memset(&infos[i], 0, sizeof(mp3info_t)); /* These two are needed for proper LAME gapless MP3 playback */ infos[i].enc_delay = -1; infos[i].enc_padding = -1; if (!mp3headerinfo(&infos[i], headers[i])) return -2; offsets[i] = lseek(fd, 0, SEEK_CUR); } if (vlfc_cmp(&infos[0], &infos[1]) && vlfc_cmp(&infos[1], &infos[2]) && vlfc_cmp(&infos[2], &infos[3])) {#ifdef MPEG_DEBUG printf("first 4 frames OK!\n");#endif /* MPEG_DEBUG */ offset = offsets[0]; header = headers[0]; } else { int max_vsn_index = 0; int max_layer_index = 0; int max_freq_index = 0; int max_chmode_index = 0; int ok_freq; int max_headers = MAX_STAT_HEADERS;#ifdef MPEG_DEBUG printf("first 4 frames differ, gathering stats...\n");#endif /* MPEG_DEBUG */ for (i = 4; i < max_headers; i++) { headers[i] = find_next_frame(fd, &bytecount, 0x100000, 0); /* Quit if we haven't found a valid header within 1M */ if (headers[i] == 0) break; memset(&infos[i], 0, sizeof(mp3info_t)); /* These two are needed for proper LAME gapless MP3 playback */ infos[i].enc_delay = -1; infos[i].enc_padding = -1; if (!mp3headerinfo(&infos[i], headers[i])) return -2; offsets[i] = lseek(fd, 0, SEEK_CUR); } max_headers = i; for (i = 0; i < max_headers; i++) { switch (infos[i].frequency) { case 48000: freq_counters[0] += 1; break; case 44100: freq_counters[1] += 1; break; case 32000: freq_counters[2] += 1; break; case 24000: freq_counters[3] += 1; break; case 22050: freq_counters[4] += 1; break; case 16000: freq_counters[5] += 1; break; default : freq_counters[6] += 1; break; } } for (i = 0; i < 7; i++) {#ifdef MPEG_DEBUG printf("freq_counters[%d] = %d\n", i, freq_counters[i]);#endif /* MPEG_DEBUG */ if (freq_counters[i] > freq_counters[max_freq_index]) { max_freq_index = i; } }#ifdef MPEG_DEBUG printf("max freq idx = %d\n", max_freq_index);#endif /* MPEG_DEBUG */ switch (max_freq_index) { case 0 : ok_freq = 48000; break; case 1 : ok_freq = 44100; break; case 2 : ok_freq = 32000; break; case 3 : ok_freq = 24000; break; case 4 : ok_freq = 22050; break; case 5 : ok_freq = 16000; break; default:#ifdef MPEG_DEBUG printf("MPEG statistical recognition failed 1\n");#endif /* MPEG_DEBUG */ return -2; break; } for (i = 0; i < max_headers; i++) { if (infos[i].frequency != ok_freq) continue; vsn_counters[infos[i].version] += 1; layer_counters[infos[i].layer] += 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -