📄 dec_mpeg.c
字号:
#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 + -