static struct tzinfo * do_read_tzfile(int fd, const char *tzfile, int time_size) { struct tzinfo *tz = NULL; int size, n; bool has_64bit_times = 0; int isstdcnt, isgmtcnt; { char magic[5] = { '\0' }; if (read(fd, magic, 4) != 4) { do_rawlog(LT_ERR, "tz: Unable to read header from %s: %s.\n", tzfile, strerror(errno)); goto error; } if (memcmp(magic, TZMAGIC, 4) != 0) { do_rawlog(LT_ERR, "tz: %s is not a valid tzfile. Wrong magic number.\n", tzfile); goto error; } } { char version[16]; if (read(fd, version, 16) != 16) { do_rawlog(LT_ERR, "tz: Unable to read chunk from %s: %s\n", tzfile, strerror(errno)); goto error; } /* There's a second copy of the data using 64 bit times, following the chunk with 32 bit times. */ if (version[0] == '2') has_64bit_times = 1; } tz = mush_malloc(sizeof *tz, "timezone"); memset(tz, 0, sizeof *tz); { int32_t counts[6]; READ_CHUNK(counts, sizeof counts); isgmtcnt = decode32(counts[0]); isstdcnt = decode32(counts[1]); tz->leapcnt = decode32(counts[2]); tz->timecnt = decode32(counts[3]); tz->typecnt = decode32(counts[4]); tz->charcnt = decode32(counts[5]); } /* Use 64-bit time_t version on such systems. */ if (has_64bit_times && sizeof(time_t) == 8 && time_size == 4) { off_t skip = 44; /* Header and sizes */ skip += tz->timecnt * 5; skip += tz->typecnt * 6; skip += tz->charcnt; skip += tz->leapcnt * (4 + time_size); skip += isgmtcnt + isstdcnt; if (lseek(fd, skip, SEEK_SET) < 0) { do_rawlog(LT_ERR, "tz: Unable to seek to second section of %s: %s\n", tzfile, strerror(errno)); goto error; } mush_free(tz, "timezone"); return do_read_tzfile(fd, tzfile, 8); } #define READ_TRANSITIONS(type, decode) \ do { \ type *buf; \ \ size = tz->timecnt * time_size; \ buf = malloc(size); \ READ_CHUNKF(buf, size); \ \ tz->transitions = calloc(tz->timecnt, sizeof(time_t)); \ for (n = 0; n < tz->timecnt; n += 1) \ tz->transitions[n] = (time_t) decode(buf[n]); \ \ free(buf); \ } while (0) if (time_size == 4) { READ_TRANSITIONS(int32_t, decode32); } else { READ_TRANSITIONS(int64_t, decode64); } tz->offset_indexes = malloc(tz->timecnt); READ_CHUNK(tz->offset_indexes, tz->timecnt); { uint8_t *buf; int m, size = tz->typecnt * 6; buf = malloc(size); READ_CHUNKF(buf, size); tz->offsets = calloc(tz->typecnt, sizeof(struct ttinfo)); for (n = 0, m = 0; n < tz->typecnt; n += 1, m += 6) { int32_t gmtoff; memcpy(&gmtoff, &buf[m], 4); tz->offsets[n].tt_gmtoff = decode32(gmtoff); tz->offsets[n].tt_isdst = buf[m + 4]; tz->offsets[n].tt_abbrind = buf[m + 5]; tz->offsets[n].tt_std = tz->offsets[n].tt_utc = 0; } free(buf); } tz->abbrevs = malloc(tz->charcnt); READ_CHUNK(tz->abbrevs, tz->charcnt); #define READ_LEAPSECS(type, decode) \ do { \ type *buf; \ int m, size = tz->leapcnt * (4 + time_size); \ \ buf = malloc(size); \ READ_CHUNKF(buf, size); \ \ tz->leapsecs = calloc(tz->leapcnt, sizeof(struct ttleapsecs)); \ \ for (n = 0, m = 0; n < tz->leapcnt; n += 1, m += (4 + time_size)) { \ type when; \ int32_t secs; \ \ memcpy(&when, buf, time_size); \ memcpy(&secs, buf + time_size, 4); \ tz->leapsecs[n].tt_when = (time_t) decode(when); \ tz->leapsecs[n].tt_secs = decode32(secs); \ } \ free(buf); \ } while (0) if (tz->leapcnt) { if (time_size == 4) READ_LEAPSECS(int32_t, decode32); else READ_LEAPSECS(int64_t, decode64); } { uint8_t *buf; int n; buf = malloc(isstdcnt); READ_CHUNKF(buf, isstdcnt); for (n = 0; n < isstdcnt; n += 1) tz->offsets[n].tt_std = buf[n]; free(buf); buf = malloc(isgmtcnt); READ_CHUNKF(buf, isgmtcnt); for (n = 0; n < isgmtcnt; n += 1) tz->offsets[n].tt_utc = buf[n]; free(buf); } return tz; error: if (tz) free_tzinfo(tz); return NULL; }
static int decode(quicktime_t *file, int16_t *output_i, float *output_f, long samples, int track, int channel) { int result = 0; int bytes; int i, j; quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_trak_t *trak = track_map->track; quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; long current_position = track_map->current_position; long end_position = current_position + samples; unsigned char *buffer; // End of data in ogg buffer int eos = 0; // End of file int eof = 0; float *pcm; int have_chunk = 0; if(samples > OUTPUT_ALLOCATION) printf("vorbis.c decode: can't read more than %p samples at a time.\n", OUTPUT_ALLOCATION); if(output_i) bzero(output_i, sizeof(int16_t) * samples); if(output_f) bzero(output_f, sizeof(float) * samples); // Seeked outside output buffer's range or not initialized: restart if(current_position < codec->output_position - codec->output_size || current_position > codec->output_position || !codec->decode_initialized) { quicktime_chunk_of_sample(&codec->output_position, &codec->chunk, trak, current_position); // We know the first ogg packet in the chunk has a pcm_offset from the encoding. codec->output_size = 0; codec->output_end = 0; codec->chunk_samples = 0; // Initialize and load initial buffer for decoding if(!codec->decode_initialized) { int init_chunk = 1; codec->decode_initialized = 1; codec->output = malloc(sizeof(float*) * track_map->channels); for(i = 0; i < track_map->channels; i++) { codec->output[i] = malloc(sizeof(float) * OUTPUT_ALLOCATION); } codec->output_allocated = OUTPUT_ALLOCATION; ogg_sync_init(&codec->dec_oy); /* Now we can read pages */ READ_CHUNK(init_chunk); init_chunk++; if(ogg_sync_pageout(&codec->dec_oy, &codec->dec_og)!=1) { fprintf(stderr, "decode: ogg_sync_pageout: Must not be Vorbis data\n"); return 1; } ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og)); vorbis_info_init(&codec->dec_vi); vorbis_comment_init(&codec->dec_vc); if(ogg_stream_pagein(&codec->dec_os, &codec->dec_og) < 0) { fprintf(stderr,"decode: ogg_stream_pagein: stream version mismatch perhaps.\n"); return 1; } if(ogg_stream_packetout(&codec->dec_os, &codec->dec_op) != 1) { fprintf(stderr, "decode: ogg_stream_packetout: Must not be Vorbis data\n"); return 1; } if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0) { fprintf(stderr, "decode: vorbis_synthesis_headerin: not a vorbis header\n"); return 1; } i = 0; while(i < 2) { while(i < 2) { result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og); if(result == 0) break; if(result == 1) { ogg_stream_pagein(&codec->dec_os, &codec->dec_og); while(i < 2) { result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op); if(result == 0) break; if(result < 0) { fprintf(stderr, "decode: ogg_stream_packetout: corrupt secondary header\n"); return 1; } vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op); i++; } } } if(i < 2) { READ_CHUNK(init_chunk); init_chunk++; } // Header should never span more than one chunk so assume it's done here } vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi); vorbis_block_init(&codec->dec_vd, &codec->dec_vb); // Also the first chunk needed in decoding so don't reread after this. if(codec->chunk == init_chunk - 1) { have_chunk = 1; codec->chunk++; } } // Don't already have initial chunk from header if(!have_chunk) { // Get initial chunk for decoding at new location // From vorbisfile.c /* clear out decoding machine state */ ogg_stream_clear(&codec->dec_os); vorbis_dsp_clear(&codec->dec_vd); vorbis_block_clear(&codec->dec_vb); ogg_sync_reset(&codec->dec_oy); ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og)); ogg_sync_init(&codec->dec_oy); vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi); vorbis_block_init(&codec->dec_vd, &codec->dec_vb); READ_CHUNK(codec->chunk); codec->chunk++; have_chunk = 1; } } // Assume the chunk exists by now and rely on libogg to say if it's out of // data. have_chunk = 1; // Read chunks until output buffer is on or after end_position result = 0; while(codec->output_position < end_position) { // Read chunk to decode if it hasn't been read yet. if(!have_chunk) { codec->chunk_samples = 0; READ_CHUNK(codec->chunk); if(result) break; codec->chunk++; } eos = 0; while(!eos) { result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og); // Need more data from chunk if(result == 0) { // End of chunk eos = 1; } else // This stage checks for OggS and a checksum error. // It doesn't tell if it's the end of a chunk. Need to manually parse OggS // pages to figure out how big the chunk is. if(result < 0) { //printf("ogg_sync_pageout=-1\n"); ; } else { ogg_stream_pagein(&codec->dec_os, &codec->dec_og); while(!eos) { //printf("decode 7\n"); result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op); //printf("decode 8 %d\n", result); if(result == 0) { //printf("ogg_stream_packetout=0\n"); // End of page eos = 1; } else // This stage doesn't check for OggS. if(result < 0) { //printf("ogg_stream_packetout=-1\n"); } else { float **pcm; if(vorbis_synthesis(&codec->dec_vb, &codec->dec_op) == 0) { vorbis_synthesis_blockin(&codec->dec_vd, &codec->dec_vb); } while((result = vorbis_synthesis_pcmout(&codec->dec_vd, &pcm)) > 0) { //printf("vorbis_synthesis_pcmout=%x\n", result); for(i = 0; i < track_map->channels; i++) { float *output_channel = codec->output[i]; float *input_channel = pcm[i]; int k = codec->output_end; for(j = 0; j < result; j++) { output_channel[k++] = input_channel[j]; if(k >= codec->output_allocated) k = 0; } if(i == track_map->channels - 1) codec->output_end = k; } //printf("codec->output_end = %d\n", codec->output_end); codec->output_position += result; codec->output_size += result; codec->chunk_samples += result; if(codec->output_size > codec->output_allocated) codec->output_size = codec->output_allocated; vorbis_synthesis_read(&codec->dec_vd, result); } } //printf("decode 11\n"); } // Reset end of page so it isn't interpreted as an end of chunk eos = 0; } } // Next chunk if(eos) { //printf("decode 12 got=%x\n", codec->chunk_samples); have_chunk = 0; } } // Fill silence while(codec->output_position < end_position) { for(i = 0; i < track_map->channels; i++) codec->output[i][codec->output_end] = 0; codec->output_end++; if(codec->output_end >= codec->output_allocated) codec->output_end = 0; codec->output_position++; } //printf("decode 15\n"); //printf("decode 2 codec->output_position=%lld codec->output_end=%d codec->output_size=%d\n", // codec->output_position, codec->output_end, codec->output_size); current_position = track_map->current_position; i = codec->output_end - (codec->output_position - current_position); j = 0; while(i < 0) i += codec->output_allocated; pcm = codec->output[channel]; if(output_i) { for( ; j < samples; j++) { int sample = pcm[i] * 32767; CLAMP(sample, -32768, 32767); output_i[j] = sample; i++; if(i >= codec->output_allocated) i = 0; } } else if(output_f) { for( ; j < samples; j++) { output_f[j] = pcm[i]; i++; if(i >= codec->output_allocated) i = 0; } } //printf("decode 16\n"); return 0; }