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

📄 dec_mpeg.c

📁 Aqualung is an advanced music player primarily targeted for the GNU/Linux operating system, but als
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif /* MPEG_DEBUG */				if (pad > pcm->length) {#ifdef MPEG_DEBUG			printf("skipping whole frame\n");#endif /* MPEG_DEBUG */			return MAD_FLOW_CONTINUE;		} else {			end_count = pcm->length - pad;#ifdef MPEG_DEBUG			printf("skipping %d samples\n", pad);#endif /* MPEG_DEBUG */		}	} else if ((pad > 0) && (pd->last_frames[1] != -1) && (pos_bytes >= pd->last_frames[1])) {#ifdef MPEG_DEBUG		printf(" *** last but one frame len=%d***\n", pcm->length);#endif /* MPEG_DEBUG */				if (pad > pcm->length) {			pad -= pcm->length;			end_count = pcm->length - pad;#ifdef MPEG_DEBUG			printf("skipping %d samples\n", pad);#endif /* MPEG_DEBUG */		}	}         for (; i < end_count; i++) {                for (j = 0; j < pd->channels; j++) {                        buf[j] = pd->error ? 0 : *(pcm->samples[j] + i);                        fbuf[j] = (double)buf[j] * fdec->voladj_lin / scale;                }                if (rb_write_space(pd->rb) >= pd->channels * sample_size) {                        rb_write(pd->rb, (char *)fbuf, pd->channels * sample_size);		}        }	pd->frame_counter++;        pd->error = 0;        return MAD_FLOW_CONTINUE;}/* MPEG header callback */staticenum mad_flowmpeg_header(void * data, struct mad_header const * header) {        decoder_t * dec = (decoder_t *)data;	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	if (pd->bitrate != header->bitrate) {		pd->bitrate = header->bitrate;	}        return MAD_FLOW_CONTINUE;}/* MPEG error callback */staticenum mad_flowmpeg_error(void * data, struct mad_stream * stream, struct mad_frame * frame) {        decoder_t * dec = (decoder_t *)data;	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;        pd->error = 1;        return MAD_FLOW_CONTINUE;}/* Main decode loop: return 1 if reached end of stream, 0 else */intdecode_mpeg(decoder_t * dec) {	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;        if (mad_header_decode(&(pd->mpeg_frame.header), &(pd->mpeg_stream)) == -1) {                if (pd->mpeg_stream.error == MAD_ERROR_BUFLEN)                        return 1;                if (!MAD_RECOVERABLE(pd->mpeg_stream.error))                        fprintf(stderr, "libMAD: unrecoverable error in MPEG Audio stream\n");                mpeg_error((void *)dec, &(pd->mpeg_stream), &(pd->mpeg_frame));        }        mpeg_header((void *)dec, &(pd->mpeg_frame.header));        if (mad_frame_decode(&(pd->mpeg_frame), &(pd->mpeg_stream)) == -1) {                if (pd->mpeg_stream.error == MAD_ERROR_BUFLEN)                        return 1;                if (!MAD_RECOVERABLE(pd->mpeg_stream.error))                        fprintf(stderr, "libMAD: unrecoverable error in MPEG Audio stream\n");                mpeg_error((void *)dec, &(pd->mpeg_stream), &(pd->mpeg_frame));        }        mad_synth_frame(&(pd->mpeg_synth), &(pd->mpeg_frame));        mpeg_output((void *)dec, &(pd->mpeg_frame.header), &(pd->mpeg_synth.pcm));        return 0;}decoder_t *mpeg_decoder_init(file_decoder_t * fdec) {        decoder_t * dec = NULL;        if ((dec = calloc(1, sizeof(decoder_t))) == NULL) {                fprintf(stderr, "dec_mpeg.c: mpeg_decoder_new() failed: calloc error\n");                return NULL;        }	dec->fdec = fdec;        if ((dec->pdata = calloc(1, sizeof(mpeg_pdata_t))) == NULL) {                fprintf(stderr, "dec_mpeg.c: mpeg_decoder_new() failed: calloc error\n");                return NULL;        }	dec->init = mpeg_decoder_init;	dec->destroy = mpeg_decoder_destroy;	dec->open = mpeg_decoder_open;	dec->close = mpeg_decoder_close;	dec->read = mpeg_decoder_read;	dec->seek = mpeg_decoder_seek;	return dec;}voidmpeg_decoder_destroy(decoder_t * dec) {	free(dec->pdata);	free(dec);}intmpeg_decoder_open(decoder_t * dec, char * filename) {	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	file_decoder_t * fdec = dec->fdec;	int i;	struct stat exp_stat;	if (!is_valid_extension(valid_extensions_mpeg, filename, 0)) {#ifdef MPEG_DEBUG		printf("invalid extension of %s\n", filename);#endif /* MPEG_DEBUG */		return DECODER_OPEN_BADLIB;	}	if ((pd->fd = open(filename, O_RDONLY)) == 0) {		fprintf(stderr, "mpeg_decoder_open: open() failed for MPEG Audio file\n");		return DECODER_OPEN_FERROR;	}	fstat(pd->fd, &exp_stat);	pd->filesize = exp_stat.st_size;	pd->SR = pd->channels = pd->bitrate = pd->mpeg_subformat = 0;	pd->error = 0;	pd->skip_bytes = get_mp3file_info(pd->fd, &pd->mp3info);	close(pd->fd);#ifdef MPEG_DEBUG	printf("skip_bytes = %ld\n\n", pd->skip_bytes);#endif /* MPEG_DEBUG */	if (pd->skip_bytes < 0) {		return DECODER_OPEN_BADLIB;	}#ifdef MPEG_DEBUG	printf("version = %d\n", pd->mp3info.version);	printf("layer = %d\n", pd->mp3info.layer);	printf("bitrate = %d\n", pd->mp3info.bitrate);	printf("frequency = %d\n", pd->mp3info.frequency);	printf("channel_mode = %d\n", pd->mp3info.channel_mode);	printf("mode_extension = %d\n", pd->mp3info.mode_extension);	printf("emphasis = %d\n", pd->mp3info.emphasis);	printf("frame_size = %d\n", pd->mp3info.frame_size);	printf("frame_samples = %d\n", pd->mp3info.frame_samples);	printf("is_vbr = %d\n", pd->mp3info.is_vbr);	printf("has_toc = %d\n", pd->mp3info.has_toc);	printf("frame_count = %ld\n", pd->mp3info.frame_count);	printf("byte_count = %ld\n", pd->mp3info.byte_count);	printf("file_time = %ld\n", pd->mp3info.file_time);	printf("enc_delay = %ld\n", pd->mp3info.enc_delay);	printf("enc_padding = %ld\n", pd->mp3info.enc_padding);#endif /* MPEG_DEBUG */	pd->SR = pd->mp3info.frequency;	pd->bitrate = pd->mp3info.bitrate * 1000;        switch (pd->mp3info.layer) {        case 0: pd->mpeg_subformat |= MPEG_LAYER_I;                break;        case 1: pd->mpeg_subformat |= MPEG_LAYER_II;                break;        case 2: pd->mpeg_subformat |= MPEG_LAYER_III;                break;        }        switch (pd->mp3info.channel_mode) {        case 0: pd->mpeg_subformat |= MPEG_MODE_STEREO;                pd->channels = 2;                break;        case 1: pd->mpeg_subformat |= MPEG_MODE_JOINT;                pd->channels = 2;                break;        case 2: pd->mpeg_subformat |= MPEG_MODE_DUAL;                pd->channels = 2;                break;        case 3: pd->mpeg_subformat |= MPEG_MODE_SINGLE;                pd->channels = 1;                break;        }        switch (pd->mp3info.emphasis) {        case 0: pd->mpeg_subformat |= MPEG_EMPH_NONE;                break;        case 1: pd->mpeg_subformat |= MPEG_EMPH_5015;                break;        case 2: pd->mpeg_subformat |= MPEG_EMPH_RES;                break;        case 3: pd->mpeg_subformat |= MPEG_EMPH_J_17;                break;        }	if ((!pd->SR) || (!pd->channels)) {		return DECODER_OPEN_BADLIB;	}	if ((pd->channels != 1) && (pd->channels != 2)) {		fprintf(stderr,			"mpeg_decoder_open: MPEG Audio file with %d channels "			"is unsupported\n", pd->channels);		return DECODER_OPEN_FERROR;	}		if (pd->mp3info.is_vbr) {		pd->total_samples_est = (double)pd->SR * pd->mp3info.file_time / 1000.0f;		pd->mpeg_subformat |= MPEG_VBR;	} else {		if (pd->bitrate == 0) {			pd->total_samples_est = (long long)(pd->filesize - pd->mp3info.start_byteoffset)				* pd->mp3info.frame_samples / pd->mp3info.frame_size;			pd->bitrate = pd->mp3info.bitrate = 8 *				(double)(pd->filesize - pd->mp3info.start_byteoffset) /				(pd->total_samples_est / pd->SR);			pd->mpeg_subformat |= MPEG_UBR;		} else {			pd->total_samples_est =				(double)(pd->filesize - pd->mp3info.start_byteoffset)				/ pd->bitrate * 8 * pd->SR;		}	}	if (pd->mp3info.enc_delay > 0) {		pd->delay_frames = pd->mp3info.enc_delay + 528 + pd->mp3info.frame_samples;	} else {		pd->delay_frames = 0;	}		/* data init (so when seeking we know if an entry is not yet filled in) */	for (i = 0; i < 100; i++) {		pd->seek_table[i].frame = -1;	}	pd->builder_thread_running = 0;	for (i = 0; i < 2; i++) {		pd->last_frames[i] = -1;	}	pd->error = 0;	pd->is_eos = 0;	pd->seek_table_built = 0;	pd->rb = rb_create(pd->channels * sample_size * RB_MAD_SIZE);	fdec->channels = pd->channels;	fdec->SR = pd->SR;	fdec->file_lib = MAD_LIB;		fdec->fileinfo.total_samples = pd->total_samples_est;	fdec->fileinfo.format_major = FORMAT_MAD;	fdec->fileinfo.format_minor = pd->mpeg_subformat;	fdec->fileinfo.bps = pd->bitrate;	/* setup playback */	pd->fd = open(filename, O_RDONLY);	mad_stream_init(&(pd->mpeg_stream));	mad_frame_init(&(pd->mpeg_frame));	mad_synth_init(&(pd->mpeg_synth));		if (mpeg_input((void *)dec, &(pd->mpeg_stream)) == MAD_FLOW_STOP) {		mad_synth_finish(&(pd->mpeg_synth));		mad_frame_finish(&(pd->mpeg_frame));		mad_stream_finish(&(pd->mpeg_stream));		return DECODER_OPEN_FERROR;	}	pd->frame_counter = 0;#ifdef MPEG_DEBUG	printf("mpeg_decoder_open successful\n");#endif /* MPEG_DEBUG */	return DECODER_OPEN_SUCCESS;}voidmpeg_decoder_close(decoder_t * dec) {	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	/* take care of seek table builder thread, if there is any */	if (pd->builder_thread_running) {		pd->builder_thread_running = 0;#ifdef MPEG_DEBUG		printf("joining seek table builder thread\n");#endif /* MPEG_DEBUG */		AQUALUNG_THREAD_JOIN(pd->seek_builder_id)#ifdef MPEG_DEBUG		printf("joined seek table builder thread\n");#endif /* MPEG_DEBUG */	}	mad_synth_finish(&(pd->mpeg_synth));	mad_frame_finish(&(pd->mpeg_frame));	mad_stream_finish(&(pd->mpeg_stream));	if (munmap(pd->fdm, pd->mpeg_stat.st_size) == -1)		fprintf(stderr, "Error while munmap()'ing MPEG Audio file mapping\n");	close(pd->fd);	rb_free(pd->rb);#ifdef MPEG_DEBUG	printf("mpeg_decoder_close successful\n");#endif /* MPEG_DEBUG */}unsigned intmpeg_decoder_read(decoder_t * dec, float * dest, int num) {	mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	unsigned int numread = 0;	unsigned int n_avail = 0;	if (!pd->seek_table_built) {#ifdef MPEG_DEBUG		printf("first read from mpeg file\n");#endif /* MPEG_DEBUG */		/* read mmap'ed file and build seek table in background thread.		   we do this upon the first read, so it doesn't start when we open		   a mass of files, but don't read any audio (metadata retrieval, etc) */		build_seek_table(pd);			pd->seek_table_built = 1;	}	while ((rb_read_space(pd->rb) < num * pd->channels *		sample_size) && (!pd->is_eos)) {				pd->is_eos = decode_mpeg(dec);	}		n_avail = rb_read_space(pd->rb) / (pd->channels * sample_size);	if (n_avail > num)		n_avail = num;	rb_read(pd->rb, (char *)dest, n_avail * pd->channels * sample_size);	numread = n_avail;	return numread;}voidmpeg_decoder_seek(decoder_t * dec, unsigned long long seek_to_pos) {		mpeg_pdata_t * pd = (mpeg_pdata_t *)dec->pdata;	file_decoder_t * fdec = dec->fdec;	char * bytes = (char *)pd->fdm;	long header;	mp3info_t mp3info;	char flush_dest;	int i;	unsigned long offset;	unsigned long long sample;	if (seek_to_pos < pd->mp3info.frame_samples) {		pd->frame_counter = 0;		pd->mpeg_stream.next_frame = pd->mpeg_stream.buffer;		fdec->samples_left = fdec->fileinfo.total_samples;		goto flush_decoder_rb;	}	/* search for closest preceding entry in seek table */	for (i = 0; i < 99; i++) {		if (pd->seek_table[i].frame == -1) {			/* uninitialized seek table (to the desired position, at least)			   so we fall back on conventional bitstream seeking */#ifdef MPEG_DEBUG			printf("seek table not yet ready, seeking bitstream.\n");#endif /* MPEG_DEBUG */			pd->mpeg_stream.next_frame = pd->mpeg_stream.buffer;			mad_stream_sync(&(pd->mpeg_stream));			mad_stream_skip(&(pd->mpeg_stream),					(pd->filesize - pd->mp3info.start_byteoffset)					* (double)seek_to_pos / pd->total_samples_est);			mad_stream_sync(&(pd->mpeg_stream));						pd->is_eos = decode_mpeg(dec);			/* report the real position of the decoder */			fdec->samples_left = fdec->fileinfo.total_samples -				(pd->mpeg_stream.next_frame - pd->mpeg_stream.buffer)				/ pd->bitrate * 8 * pd->SR;			goto flush_decoder_rb;		}		if (pd->seek_table[i+1].sample > seek_to_pos)			break;	}	offset = pd->seek_table[i].offset;	sample = pd->seek_table[i].sample;	do {		if (offset > pd->filesize - 4) {			offset = pd->filesize-4;			break;		}		header = BYTES2INT(bytes[offset], bytes[offset+1], bytes[offset+2], bytes[offset+3]);		if (is_mp3frameheader(header)) {			mp3headerinfo(&mp3info, header);			if ((mp3info.layer == pd->mp3info.layer) &&			    (mp3info.version == pd->mp3info.version) &&			    (mp3info.frequency == pd->mp3info.frequency)) {								sample += mp3info.frame_samples;				offset += mp3info.frame_size;			} else {				++offset;			}		} else {			++offset;		}	} while (sample + mp3info.frame_samples < seek_to_pos);	pd->mpeg_stream.next_frame = pd->mpeg_stream.buffer - pd->mp3info.start_byteoffset + offset;	fdec->samples_left = fdec->fileinfo.total_samples - sample; flush_decoder_rb:	/* empty mpeg decoder ringbuffer */	while (rb_read_space(pd->rb))		rb_read(pd->rb, &flush_dest, sizeof(char));}#elsedecoder_t *mpeg_decoder_init(file_decoder_t * fdec) {        return NULL;}#endif /* HAVE_MPEG */// vim: shiftwidth=8:tabstop=8:softtabstop=8 :  

⌨️ 快捷键说明

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