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