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

📄 dec_mpeg.c

📁 Aqualung is an advanced music player primarily targeted for the GNU/Linux operating system, but als
💻 C
📖 第 1 页 / 共 3 页
字号:
		}		for (i = 0; i < 4; i++) {#ifdef MPEG_DEBUG			printf("vsn_counters[%d] = %d\n", i, vsn_counters[i]);#endif /* MPEG_DEBUG */			if (vsn_counters[i] > vsn_counters[max_vsn_index]) {				max_vsn_index = i;			}		}		for (i = 0; i < 3; i++) {#ifdef MPEG_DEBUG			printf("layer_counters[%d] = %d\n", i, layer_counters[i]);#endif /* MPEG_DEBUG */			if (layer_counters[i] > layer_counters[max_layer_index]) {				max_layer_index = i;			}		}#ifdef MPEG_DEBUG		printf("max vsn idx   = %d\n", max_vsn_index);		printf("max layer idx = %d\n", max_layer_index);#endif /* MPEG_DEBUG */		for (i = 0; i < max_headers; i++) {			if ((infos[i].version != max_vsn_index) ||			    (infos[i].layer != max_layer_index) ||			    (infos[i].frequency != ok_freq))				continue;			chmode_counters[infos[i].channel_mode] += 1;		}		for (i = 0; i < 4; i++) {#ifdef MPEG_DEBUG			printf("chmode_counters[%d] = %d\n", i, chmode_counters[i]);#endif /* MPEG_DEBUG */			if (chmode_counters[i] > chmode_counters[max_chmode_index]) {				max_chmode_index = i;			}		}#ifdef MPEG_DEBUG		printf("max chmode idx   = %d\n", max_chmode_index);#endif /* MPEG_DEBUG */		offset = -1;		for (i = 0; i < max_headers; i++) {			if ((infos[i].version == max_vsn_index) &&			    (infos[i].layer == max_layer_index) &&			    (infos[i].channel_mode == max_chmode_index) &&			    (infos[i].frequency == ok_freq)) {				offset = offsets[i];				header = headers[i];				break;			}		}		if (offset == -1) {#ifdef MPEG_DEBUG			printf("MPEG statistical recognition failed 2\n");#endif /* MPEG_DEBUG */			return -2;		}	}#endif /* MPEG_STATISTICAL_RECOGNITION */		lseek(fd, offset, SEEK_SET);	memset(info, 0, sizeof(mp3info_t));	info->start_byteoffset = offset - 4;	info->enc_delay = -1;	info->enc_padding = -1;	if (!mp3headerinfo(info, header))		return -2;#ifdef MPEG_DEBUG	printf("start_byteoffset = %d\n", info->start_byteoffset);#endif 	if (info->frame_size == 0) {		/* free-format MPEG - no VBR allowed.		   we have to find the next frame, so we can determine the frame size & bitrate */		long offset_next;		long header_next;		mp3info_t info_next;		do {			header_next = find_next_frame(fd, &bytecount, 0x100000, 0);			/* Quit if we haven't found a valid header within 1M */			if (header_next == 0)				return -1;						memset(&info_next, 0, sizeof(mp3info_t));						/* These two are needed for proper LAME gapless MP3 playback */			info_next.enc_delay = -1;			info_next.enc_padding = -1;			if (!mp3headerinfo(&info_next, header_next))				return -2;					} while (!vlfc_cmp(info, &info_next));		offset_next = lseek(fd, 0, SEEK_CUR);		info->frame_size = offset_next - offset;		lseek(fd, offset - 4, SEEK_SET); /* go back to beginning of stream */		return bytecount;	}	/* OK, we have the first real frame. Let's see if it has a Xing header */	if ((ret = read(fd, frame, info->frame_size-4)) < 0) {#ifdef MPEG_DEBUG		printf("read(): %s\n", strerror(ret));#endif /* MPEG_DEBUG */		return -3;	}		/* calculate position of VBR header */	if (info->version == MPEG_VERSION1) {		if (info->channel_mode == 3) /* mono */			vbrheader = frame + 17;		else			vbrheader = frame + 32;	} else {		if (info->channel_mode == 3) /* mono */			vbrheader = frame + 9;		else			vbrheader = frame + 17;	}		if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4)) {		int i = 8; /* Where to start parsing info */		#ifdef MPEG_DEBUG		printf("Xing/Info header\n");#endif /* MPEG_DEBUG */				/* Remember where in the file the Xing header is */		info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;				/* We want to skip the Xing frame when playing the stream */		bytecount += info->frame_size;				/* workaround some files that have padding bit set, but frame size is 417 bytes */		if (info->padding) {			lseek(fd, -1, SEEK_CUR);		}		/* Now get the next frame to find out the real info about		   the mp3 stream */		header = find_next_frame(fd, &tmp, 0x20000, 0);		if(header == 0)			return -4;				if(!mp3headerinfo(info, header))			return -5;				/* Is it a VBR file? */		info->is_vbr = info->is_xing_vbr = !memcmp(vbrheader, "Xing", 4);				if (vbrheader[7] & VBR_FRAMES_FLAG) { /* Is the frame count there? */						info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1],						      vbrheader[i+2], vbrheader[i+3]);			if (info->frame_count <= ULONG_MAX / info->ft_num)				info->file_time = info->frame_count * info->ft_num / info->ft_den;			else				info->file_time = info->frame_count / info->ft_den * info->ft_num;			i += 4;		}				if (vbrheader[7] & VBR_BYTES_FLAG) { /* Is byte count there? */			info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1],						     vbrheader[i+2], vbrheader[i+3]);			i += 4;		}				if (info->file_time && info->byte_count) {			if (info->byte_count <= (ULONG_MAX/8))				info->bitrate = info->byte_count * 8 / info->file_time;			else				info->bitrate = info->byte_count / (info->file_time >> 3);		} else {			info->bitrate = 0;		}					if (vbrheader[7] & VBR_TOC_FLAG) { /* Is table-of-contents there? */						memcpy(info->toc, vbrheader+i, 100);			i += 100;		}		if (vbrheader[7] & VBR_QUALITY_FLAG) {			/* We don't care about this, but need to skip it */			i += 4;		}		i += 21;		info->enc_delay = (vbrheader[i] << 4) | (vbrheader[i + 1] >> 4);		info->enc_padding = ((vbrheader[i + 1] & 0x0f) << 8) | vbrheader[i + 2];		if (!(info->enc_delay >= 0 && info->enc_delay <= 1152 && 		      info->enc_padding >= 0 && info->enc_padding <= 2*1152)) {			/* Invalid data */			info->enc_delay = -1;			info->enc_padding = -1;		}	}		if (!memcmp(vbrheader, "VBRI", 4)) {#ifdef MPEG_DEBUG		printf("VBRI header\n");#endif /* MPEG_DEBUG */		    		/* We want to skip the VBRI frame when playing the stream */		bytecount += info->frame_size;				/* Now get the next frame to find out the real info about		   the mp3 stream */		header = find_next_frame(fd, &tmp, 0x20000, 0);		if(header == 0)			return -6;				bytecount += tmp;				if(!mp3headerinfo(info, header))			return -7;#ifdef MPEG_DEBUG				printf("%04x: %04x %04x ", 0, header >> 16, header & 0xffff);		for(i = 4;i < (int)sizeof(frame)-4;i+=2) {			if(i % 16 == 0) {				printf("\n%04x: ", i-4);			}			printf("%04x ", (frame[i-4] << 8) | frame[i-4+1]);		}		printf("\n");#endif /* MPEG_DEBUG */				/* Yes, it is a FhG VBR file */		info->is_vbr = 1;		info->is_vbri_vbr = 1;		info->has_toc = 0; /* We don't parse the TOC (yet) */				info->byte_count = BYTES2INT(vbrheader[10], vbrheader[11],					     vbrheader[12], vbrheader[13]);		info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15],					      vbrheader[16], vbrheader[17]);		if (info->frame_count <= ULONG_MAX / info->ft_num)			info->file_time = info->frame_count * info->ft_num / info->ft_den;		else			info->file_time = info->frame_count / info->ft_den * info->ft_num;				if (info->byte_count <= (ULONG_MAX/8))			info->bitrate = info->byte_count * 8 / info->file_time;		else			info->bitrate = info->byte_count / (info->file_time >> 3);				/* We don't parse the TOC, since we don't yet know how to (FIXME) */		num_offsets = BYTES2INT(0, 0, vbrheader[18], vbrheader[19]);		frames_per_entry = BYTES2INT(0, 0, vbrheader[24], vbrheader[25]);#ifdef MPEG_DEBUG		printf("Frame size (%dkpbs): %d bytes (0x%x)\n",		       info->bitrate, info->frame_size, info->frame_size);		printf("Frame count: %x\n", info->frame_count);		printf("Byte count: %x\n", info->byte_count);		printf("Offsets: %d\n", num_offsets);		printf("Frames/entry: %d\n", frames_per_entry);#endif /* MPEG_DEBUG */				offset = 0;				for(i = 0;i < num_offsets;i++) {			j = BYTES2INT(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);			offset += j;#ifdef MPEG_DEBUG			printf("%03d: %x (%x)\n", i, offset - bytecount, j);#endif /* MPEG_DEBUG */		}	}	return bytecount;}void *build_seek_table_thread(void * args) {	mpeg_pdata_t * pd = (mpeg_pdata_t *) args;	int cnt = 0;	int table_index = 0;	long long sample_offset = 0;	char * bytes = (char *)pd->fdm;	long i;	int div;	long last = 0, last_but_1 = 0;	long limit = pd->filesize-4;	pd->builder_thread_running = 1;	if (pd->mp3info.is_vbr) {		div = pd->mp3info.frame_count / 100;	} else {		unsigned long frame_count = (pd->filesize - pd->mp3info.start_byteoffset)			/ pd->mp3info.frame_size;		div = frame_count / 100;	}#ifdef MPEG_DEBUG	printf("building seek table, div = %d\n", div);#endif /* MPEG_DEBUG */	/* look for id3v1 tag at the end of file */	if (pd->filesize >= 128 + 4) {		if ((bytes[pd->filesize-128] == 'T') &&		    (bytes[pd->filesize-127] == 'A') &&		    (bytes[pd->filesize-126] == 'G')) {#ifdef MPEG_DEBUG			printf("ID3v1 tag found at end of file\n");#endif /* MPEG_DEBUG */			limit -= 128;		}	}	for (i = pd->mp3info.start_byteoffset; i < limit;) {		long header = BYTES2INT(bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);		mp3info_t mp3info;				if (is_mp3frameheader(header)) {			mp3headerinfo(&mp3info, header);			if ((mp3info.layer == pd->mp3info.layer) &&			    (mp3info.version == pd->mp3info.version) &&			    (mp3info.channel_mode == pd->mp3info.channel_mode) &&			    (mp3info.frequency == pd->mp3info.frequency)) {				last_but_1 = last;				last = i;				if ((cnt % div == 0) && (table_index < 100)) {#ifdef MPEG_DEBUG					printf("idx %2d | offset %8ld | sample %9lld\n",					       table_index, i, sample_offset);#endif /* MPEG_DEBUG */					pd->seek_table[table_index].frame = cnt;					pd->seek_table[table_index].sample = sample_offset;					pd->seek_table[table_index].offset = i;					++table_index;				}				sample_offset += mp3info.frame_samples;				if (mp3info.frame_size == 0) {					i += pd->mp3info.frame_size;				} else {					i += mp3info.frame_size;				}				++cnt;			} else {				++i;			}		} else {			++i;		}		if (!pd->builder_thread_running) {			/* we were cancelled by the file decoder main thread */#ifdef MPEG_DEBUG			printf("seek table builder thread cancelled, exiting.\n");#endif /* MPEG_DEBUG */			return NULL;		}	}		if (table_index > 0 && table_index < 100) {		int j;		for (j = table_index; j < 100; j++) {			pd->seek_table[j].frame = pd->seek_table[table_index-1].frame;			pd->seek_table[j].sample = pd->seek_table[table_index-1].sample;			pd->seek_table[j].offset = pd->seek_table[table_index-1].offset;		}	}#ifdef MPEG_DEBUG	{		i = last;		long header = BYTES2INT(bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);		mp3info_t mp3info;		mp3headerinfo(&mp3info, header);		printf("last frame position = %ld\n", limit + 4 - i);		printf("last frame length = %d samp = %d\n",		       mp3info.frame_size, mp3info.frame_samples);	}#endif /* MPEG_DEBUG */	pd->last_frames[1] = last_but_1;	pd->last_frames[0] = last;#ifdef MPEG_DEBUG	printf("seek table builder thread finished, cnt = %d\n", cnt);	printf("last_frames[1] = %ld\n", pd->last_frames[1]);	printf("last_frames[0] = %ld\n", pd->last_frames[0]);#endif /* MPEG_DEBUG */	pd->builder_thread_running = 0;	return NULL;}voidbuild_seek_table(mpeg_pdata_t * pd) {	AQUALUNG_THREAD_CREATE(pd->seek_builder_id, NULL, build_seek_table_thread, pd)}/* MPEG input callback */staticenum mad_flowmpeg_input(void * data, struct mad_stream * stream) {        decoder_t * dec = (decoder_t *)data;	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	size_t size = 0;        if (fstat(pd->fd, &(pd->mpeg_stat)) == -1 || pd->mpeg_stat.st_size == 0)                return MAD_FLOW_STOP;		size = pd->mpeg_stat.st_size;        pd->fdm = mmap(0, size, PROT_READ, MAP_SHARED, pd->fd, 0);        if (pd->fdm == MAP_FAILED)                return MAD_FLOW_STOP;        mad_stream_buffer(stream, pd->fdm + pd->mp3info.start_byteoffset,			  size - pd->mp3info.start_byteoffset);        return MAD_FLOW_CONTINUE;}/* MPEG output callback */staticenum mad_flowmpeg_output(void * data, struct mad_header const * header, struct mad_pcm * pcm) {        decoder_t * dec = (decoder_t *)data;	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	file_decoder_t * fdec = dec->fdec;	long pos_bytes;	int end_count = pcm->length;	int i = 0, j;	unsigned long scale = 322122547; /* (1 << 28) * 1.2 */        int buf[2];        float fbuf[2];	int pad = pd->mp3info.enc_padding;	if (pd->delay_frames > pcm->length) {		pd->delay_frames -= pcm->length;#ifdef MPEG_DEBUG		printf("skipping whole frame as part of encoder delay\n");#endif /* MPEG_DEBUG */		return MAD_FLOW_CONTINUE;	} else if (pd->delay_frames > 0) {		i = pd->delay_frames;		pd->delay_frames = 0;#ifdef MPEG_DEBUG		printf("skipping %d samples of encoder delay\n", i);#endif /* MPEG_DEBUG */			} else {		i = 0;	}	pos_bytes = (pd->mpeg_stream.this_frame - pd->mpeg_stream.buffer) + 10;	if ((pad > 0) && (pd->last_frames[0] != -1) && (pos_bytes >= pd->last_frames[0])) {#ifdef MPEG_DEBUG		printf(" *** last frame len=%d ***\n", pcm->length);

⌨️ 快捷键说明

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