#include "../libzmpeg3.h" static class audio_decode_t { pthread_mutex_t zlock; public: audio_decode_t() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutex_init(&zlock, &attr); } ~audio_decode_t() { pthread_mutex_destroy(&zlock); } void lock() { pthread_mutex_lock(&zlock); } void unlock() { pthread_mutex_unlock(&zlock); } } audio_decode; static void toc_error() { zerr( "mpeg3audio: sample accurate seeking without a table of contents \n" "is no longer supported. Use mpeg3toc \n" "to generate a table of contents and load the table of contents instead.\n"); } int zaudio_t:: rewind_audio() { if( track->sample_offsets ) track->demuxer->seek_byte(track->sample_offsets[0]); else track->demuxer->seek_byte(0); track->reset_pts(); packet_position = 0; return 0; } /* Advance to next header and read it. */ int zaudio_t:: read_header() { int count = 0x10000; int got_it = 0; int result = 1; int pos = 0; switch(track->format) { case afmt_AC3: while( count > 0 && !track->demuxer->eof() ) { if( pos >= (int)sizeof(packet_buffer)-8 ) { memmove(packet_buffer, &packet_buffer[pos], packet_position-=pos); pos = 0; } if( packet_position-pos < 8 ) { packet_buffer[packet_position++] = track->demuxer->read_char(); continue; } got_it = ac3_decoder->ac3_header(&packet_buffer[pos]); if( got_it ) break; ++pos; --count; } if( got_it ) { channels = ac3_decoder->channels; samplerate = ac3_decoder->samplerate; framesize = ac3_decoder->framesize; result = 0; } break; case afmt_MPEG: /* Layer 1 not supported */ if( layer_decoder->layer == 1 ) break; /* Load starting bytes and check format when not seekable */ if( !src->seekable && !packet_position && !track->total_sample_offsets ) { if( src->demuxer->payload_unit_start_indicator ) { if( track->demuxer->read_data(packet_buffer,packet_position=4) ) break; /* reject mp4 data */ if( !zaudio_decoder_layer_t::id3_check(packet_buffer) && zaudio_decoder_layer_t::layer_check(packet_buffer) ) { zerrs("bad mp3 header, pid=%04x, track ignored\n", track->pid); track->format = afmt_IGNORE; result = -1; } } } while( count > 0 && !track->demuxer->eof() ) { if( pos >= (int)sizeof(packet_buffer)-4 ) { memmove(packet_buffer, &packet_buffer[pos], packet_position-=pos); pos = 0; } if( packet_position-pos < 4 ) { packet_buffer[packet_position++] = track->demuxer->read_char(); continue; } got_it = layer_decoder->layer3_header(&packet_buffer[pos]); if( got_it ) break; //zmsgs("%d got_it=%d packet=%02x%02x%02x%02x\n", __LINE__, // got_it, (uint8_t)packet_buffer[pos+0], (uint8_t)packet_buffer[pos+1], // (uint8_t)packet_buffer[pos+2], (uint8_t)packet_buffer[pos+3]); ++pos; --count; /* ID3 tags need to reset the count to skip the tags */ if( layer_decoder->id3_state != id3_IDLE ) count = 0x10000; } if( got_it ) { channels = layer_decoder->channels; samplerate = layer_decoder->samplerate; framesize = layer_decoder->framesize; result = 0; } break; case afmt_PCM: while( count > 0 && !track->demuxer->eof() ) { if( pos >= (int)sizeof(packet_buffer)-PCM_HEADERSIZE ) { memmove(packet_buffer, &packet_buffer[pos], packet_position-=pos); pos = 0; } if( packet_position-pos < PCM_HEADERSIZE ) { packet_buffer[packet_position++] = track->demuxer->read_char(); continue; } got_it = pcm_decoder->pcm_header(&packet_buffer[pos]); if( got_it ) break; ++pos; --count; } if( got_it ) { channels = pcm_decoder->channels; samplerate = pcm_decoder->samplerate; framesize = pcm_decoder->framesize; result = 0; } break; default: result = -1; break; } if( pos > 0 ) memmove(packet_buffer, &packet_buffer[pos], packet_position-=pos); if( track->demuxer->error() ) result = 1; if( !result ) { if( channels > track->channels ) track->channels = channels; track->sample_rate = samplerate; } //zmsgs("%d %d %d\n", track->channels, track->sample_rate, framesize); return result; } zaudio_t:: ~audio_t() { if( output ) { for( int i=0; idemuxer; int samples = -1; /* Find and read next header */ int result = read_header(); //if( src->seekable ) { // int64_t app_pos = track->apparent_position(); // int64_t aud_pos = audio_position(); // double atime = track->get_audio_time(); // int64_t pts_pos = atime * track->sample_rate + 0.5; // zmsgs(" apr_pos %jd/%jd + %jd %jd + %jd\n", // app_pos, aud_pos, app_pos-aud_pos, pts_pos, pts_pos-aud_pos); //} if( !result ) { /* Handle changes in channel count, for ATSC */ if( output_channels != channels ) update_channels(); /* try to read rest of frame */ int len = framesize - packet_position; uint8_t *bfr = packet_buffer + packet_position; if( !src->seekable ) { int data_length = demux->zdata.length(); if( data_length < len ) len = data_length; } if( !(result = demux->read_data(bfr, len)) ) packet_position += len; } if( !result && packet_position >= framesize ) { float *out[output_channels]; for( int i=0; iformat) { case afmt_AC3: audio_decode.lock(); /* Liba52 is not reentrant */ samples = ac3_decoder->do_ac3(packet_buffer,framesize,out,render); audio_decode.unlock(); //zmsgs("ac3 %d samples\n", samples); break; case afmt_MPEG: switch( layer_decoder->layer ) { case 2: samples = layer_decoder->do_layer2(packet_buffer,framesize,out,render); break; case 3: samples = layer_decoder->do_layer3(packet_buffer,framesize,out,render); break; } break; case afmt_PCM: samples = pcm_decoder->do_pcm(packet_buffer,framesize,out,render); break; } if( samples > 0 ) output_size += samples; packet_position = 0; } return samples; } /* Get the length. */ /* Use chunksize if demuxer has a table of contents */ /* For elementary streams use sample count over a certain number of */ /* bytes to guess total samples */ /* For program streams use timecode */ int zaudio_t:: get_length() { int result = 0; int samples = 0; int64_t stream_end = track->demuxer->stream_end; int64_t total_bytes = track->demuxer->movie_size(); int64_t stream_max = total_bytes; if( stream_max > 0x1000000 ) stream_max = 0x1000000; track->demuxer->stream_end = stream_max; rewind_audio(); /* Table of contents */ if( track->sample_offsets || !src->is_audio_stream() ) { /* Estimate using multiplexed stream size in seconds */ /* Get stream parameters for header validation */ /* Need a table of contents */ for( int retry=0; retry<100 && samples<=0; ++retry ) { samples = read_frame(0); } result = track->sample_offsets ? track->total_samples : 0; /* : (long)(track->demuxer->length() * track->sample_rate); */ } else { /* Estimate using average bitrate */ long test_bytes = 0; long max_bytes = 0x40000; long test_samples = 0; while( test_bytes < max_bytes ) { int samples = read_frame(0); if( samples <= 0 ) break; test_samples += samples; test_bytes += framesize; } result = (long)(((double)total_bytes / test_bytes) * test_samples + 0.5); } track->demuxer->stream_end = stream_end; output_size = 0; rewind_audio(); return result; } int zatrack_t:: calculate_format(zmpeg3_t *src) { uint8_t header[8]; int result = 0; /* Determine the format of the stream. */ /* If it isn't in the first 8 bytes give up and go to a movie. */ switch( format ) { case afmt_UNKNOWN: /* Need these 8 bytes later on for header parsing */ result = demuxer->read_data(header, sizeof(header)); //zmsgs("%jd\n", demuxer->tell_byte()); if( !result ) format = !zaudio_decoder_ac3_t::ac3_check(header) ? afmt_AC3 : afmt_MPEG; if( audio ) { memcpy(audio->packet_buffer+1, header, sizeof(header)); audio->packet_position = 9; } break; case afmt_IGNORE: result = 1; break; default: break; } return result; } int zaudio_t:: init_audio(zmpeg3_t *zsrc, zatrack_t *ztrack, int zformat) { int result = 0; src = zsrc; track = ztrack; demuxer_t *demux = track->demuxer; byte_seek = -1; sample_seek = -1; track->format = zformat; if( zsrc->seekable ) result = track->calculate_format(src); //zmsgs("%jd\n", demux->tell_byte()); /* get stream parameters */ if( !result && zsrc->seekable ) { switch( track->format ) { case afmt_AC3: ac3_decoder = new audio_decoder_ac3_t(); break; case afmt_MPEG: layer_decoder = new audio_decoder_layer_t(); break; case afmt_PCM: pcm_decoder = new audio_decoder_pcm_t(); break; default: result = 1; } if( !result ) { int64_t stream_end = demux->stream_end; //if( !track->sample_offsets ) { if( zsrc->is_transport_stream() ) demux->stream_end = START_BYTE + MAX_TS_PROBE; else if( src->is_program_stream() ) demux->stream_end = START_BYTE + MAX_PGM_PROBE; } rewind_audio(); result = read_header(); if( !result && src->is_audio_stream() ) start_byte = demux->tell_byte() - zsrc->packet_size; demux->stream_end = stream_end; } //zmsgs("1 %d %d %d start_byte=0x%jx\n", track->format, // layer_decoder->layer, result, start_byte); } return result; } zaudio_t *zmpeg3_t:: new_audio_t(zatrack_t *ztrack, int zformat) { audio_t *new_audio = new audio_t(); int result = new_audio->init_audio(this,ztrack,zformat); /* Calculate Length */ if( !result && seekable ) { new_audio->rewind_audio(); ztrack->total_samples = new_audio->get_length(); } else if( seekable ) { delete new_audio; new_audio = 0; } return new_audio; } int zaudio_t:: seek() { demuxer_t *demux = track->demuxer; int seeked = 0; /* Stream is unseekable */ if( !src->seekable ) return 0; /* Sample seek was requested */ if( sample_seek >= 0 ) { sample_seek += track->nudge; if( sample_seek < 0 ) sample_seek = 0; /* Doesn't work with VBR streams + ID3 tags */ //zmsgs("%d %jd %jd %jd %jd\n", __LINE__, sample_seek, // track->current_position, output_position, audio_position()); /* Don't do anything if the destination is inside the sample buffer */ if( sample_seek < output_position || sample_seek >= audio_position() ) { if( sample_seek != output_position ) { /* Use table of contents */ if( track->sample_offsets ) { int index = sample_seek / AUDIO_CHUNKSIZE; if( index >= track->total_sample_offsets ) index = track->total_sample_offsets - 1; /* incase of padding */ int64_t byte = track->sample_offsets[index]; while( index > 0 && byte == track->sample_offsets[index-1] ) --index; output_position = (int64_t)index * AUDIO_CHUNKSIZE; output_size = 0; demux->seek_byte(byte); } else if( sample_seek > 0 && !src->is_audio_stream() ) { /* Use demuxer */ toc_error(); /* double time_position = (double)sample_seek / track->sample_rate; */ /* result |= mpeg3demux_seek_time(demuxer, time_position); */ output_position = sample_seek; } else { /* Use bitrate for elementary stream */ int64_t total_bytes = demux->movie_size() - start_byte; int64_t byte = (int64_t)(total_bytes * ((double)sample_seek)/track->total_samples) + start_byte; //zmsgs("%d byte=%jd\n", __LINE__, byte); output_position = sample_seek; output_size = 0; demux->seek_byte(byte); } seeked = 1; } } sample_seek = -1; } else if( byte_seek >= 0 ) { output_position = 0; output_size = 0; /* Percentage seek was requested */ demux->seek_byte(byte_seek); /* Scan for pts if we're the first to seek. */ /* if( src->percentage_pts < 0 ) */ /* file->percentage_pts = demux->scan_pts(); */ /* else */ /* demux->goto_pts(src->percentage_pts); */ seeked = 1; byte_seek = -1; } if( seeked ) { packet_position = 0; track->reset_pts(); switch( track->format ) { case afmt_MPEG: layer_decoder->layer_reset(); break; } } return 0; } /* ================================*/ /* ENTRY POINTS */ /* ================================*/ int zaudio_t:: seek_byte(int64_t byte) { byte_seek = byte; return 0; } int zaudio_t:: seek_sample(long sample) { /* Doesn't work for rereading audio during percentage seeking */ /* if(sample > track->total_samples) sample = track->total_samples; */ sample_seek = (int64_t)sample; return 0; } /* Read raw frames for the mpeg3cat utility */ int zaudio_t:: read_raw(uint8_t *output, long *size, long max_size) { *size = 0; switch( track->format ) { case afmt_AC3: /* Just write the AC3 stream */ if( track->demuxer->read_data(output, 0x800) ) return 1; *size = 0x800; break; case afmt_MPEG: /* Fix the mpeg stream */ if( track->demuxer->read_data(output, 0x800) ) return 1; *size = 0x800; break; case afmt_PCM: /* This is required to strip the headers */ if( track->demuxer->read_data(output, framesize) ) return 1; *size = framesize; break; } return 0; #if 0 /* This probably doesn't work. */ result = read_header(audio); switch( track->format ) { case afmt_AC3: /* Just write the AC3 stream */ result = track->demuxer->read_data(output, framesize); *size = framesize; //zmsgs("1 %d\n", framesize); break; case afmt_MPEG: /* Fix the mpeg stream */ if( !result ) { if(track->demuxer->read_data(output, framesize)) return 1; *size += framesize; } break; case afmt_PCM: if(track->demuxer->read_data(output, framesize)) return 1; *size = framesize; break; } return result; #endif } void zaudio_t:: shift_audio(int64_t diff) { int len = diff > 0 ? output_size - diff : 0; if( len > 0 ) { for( int i=0; iaudio_time >= 0 && src->pts_padding > 0 ) { int64_t pts_pos = track->audio_time * track->sample_rate + 0.5; int padding = pts_pos - track->pts_position; if( padding > 0 ) { if( track->askip <= 0 ) { int limit = track->sample_rate/8; if( padding > limit ) { int64_t aud_pos = audio_position(); zmsgs("audio start padding pid %02x @ %12jd (%12.6f) %d samples\n", track->pid, aud_pos, track->get_audio_time(), padding); track->askip = 1; result = 1; } } else if( padding > track->sample_rate ) result = silence = 1; else if( !(++track->askip & 1) ) result = 1; if( result ) { if( padding > AUDIO_MAX_DECODE ) padding = AUDIO_MAX_DECODE; int avail = output_allocated - output_size; if( padding > avail ) padding = avail; if( padding > 0 ) { int n = track->sample_rate/20; if( output_size < n ) silence = 1; if( silence ) { for( int chan=0; chanpts_position += padding; } } } else if( track->askip > 0 ) { int64_t aud_pos = audio_position(); zmsgs("audio end padding pid %02x @ %12jd (%12.6f) %d\n", track->pid, aud_pos, track->get_audio_time(), (1+track->askip)/2); track->askip = 0; } } return result; } int zaudio_t:: audio_pts_skipping(int samples) { int result = 0; if( track->audio_time >= 0 && src->pts_padding > 0 ) { int64_t pts_pos = track->audio_time * track->sample_rate + 0.5; int skipping = track->pts_position - pts_pos; if( skipping > 0 ) { if( track->askip >= 0 ) { int limit = track->sample_rate/8; if( skipping > 3*limit ) { int64_t aud_pos = audio_position(); zmsgs("audio start skipping pid %02x @ %12jd (%12.6f) %d samples\n", track->pid, aud_pos, track->get_audio_time(), skipping); track->askip = -1; result = 1; } } else if( !(--track->askip & 1) || skipping > track->sample_rate ) result = 1; if( result ) { if( samples < skipping ) skipping = samples; if( output_size < skipping ) skipping = output_size; output_size -= skipping; track->pts_position -= skipping; } } else if( track->askip < 0 ) { int64_t aud_pos = audio_position(); zmsgs("audio end skipping pid %02x @ %12jd (%12.6f) %d\n", track->pid, aud_pos, track->get_audio_time(), (1-track->askip)/2); track->askip = 0; } } return result; } void zaudio_t:: update_audio_history() { int64_t diff = track->track_position() - output_position; if( diff ) shift_audio(diff); } /* Channel is 0 to channels - 1 */ /* Always render since now the TOC contains index files. */ int zaudio_t:: decode_audio(void *output_v, int atyp, int channel, int len) { int i, j, k; zdemuxer_t *demux = track->demuxer; //zmsgs("decode_audio(out_pos=%jd-%jd, aud_pos %jd, seek %jd ch=%d, len=%d)\n", // output_position, audio_position(), track->track_position(), // (sample_seek<0 ? sample_seek : sample_seek+track->nudge), channel, len); /* Get header for streaming mode */ if( track->format == afmt_IGNORE ) return 1; if( track->format == afmt_UNKNOWN ) { if( track->calculate_format(src) ) return 1; } if( track->format == afmt_AC3 && !ac3_decoder ) ac3_decoder = new audio_decoder_ac3_t(); else if( track->format == afmt_MPEG && !layer_decoder ) layer_decoder = new audio_decoder_layer_t(); else if( track->format == afmt_PCM && !pcm_decoder ) pcm_decoder = new audio_decoder_pcm_t(); /* Handle seeking requests */ seek(); int64_t end_pos = track->track_position() + len; long new_size = end_pos - output_position + MAXFRAMESAMPLEZ; /* Expand output until enough room exists for new data */ if( new_size > output_allocated ) { for( i=0; itell_byte(), demux->eof()); if( demux->eof() ) break; int needed_history = len > AUDIO_HISTORY ? len : AUDIO_HISTORY; /* if overflowing, shift audio back */ if( src->seekable && output_size > needed_history ) { int diff = demand + output_size - needed_history; shift_audio(diff); } int samples = read_frame(1); if( samples < 0 ) break; if( !samples ) { ++retry; continue; } retry = 0; if( audio_pts_skipping(samples) ) continue; track->update_frame_pts(); track->update_audio_time(); } /* Copy the buffer to the output */ if( !track->channels ) return 1; if( channel >= track->channels ) channel = track->channels - 1; i = 0; j = track->track_position() - output_position; k = output_size - j; if( k > len ) k = len; float *out = j >= 0 && channel < output_channels ? output[channel] + j : 0; /* transmit data in specified format */ switch( atyp ) { case atyp_NONE: break; case atyp_DOUBLE: { double *output_d = (double *)output_v; if( out ) while( i < k ) output_d[i++] = *out++; while( i < len ) output_d[i++] = 0.; break; } case atyp_FLOAT: { float *output_f = (float *)output_v; if( out ) memmove(output_f,out,(i=k)*sizeof(output_f[0])); while( i < len ) output_f[i++] = 0.; break; } case atyp_INT: { int *output_i = (int *)output_v; if( out ) while( i < k ) output_i[i++] = clip((int)(*out++ * 0x7fffff),-0x800000,0x7fffff); while( i < len ) output_i[i++] = 0; break; } case atyp_SHORT: { short *output_s = (short *)output_v; if( out ) while( i < k ) output_s[i++] = clip((int)(*out++ * 0x7fff),-0x8000,0x7fff); while( i < len ) output_s[i++] = 0; break; } default: return 1; } //zmsgs("output_size=%d chan=%d len=%d\n",output_size,channel,len); return output_size > 0 ? 0 : 1; }