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

📄 dec_mpeg.c

📁 Aqualung is an advanced music player primarily targeted for the GNU/Linux operating system, but als
💻 C
📖 第 1 页 / 共 3 页
字号:
/*                                                     -*- 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 + -