diff options
Diffstat (limited to 'libhb/stream.c')
-rwxr-xr-x | libhb/stream.c | 229 |
1 files changed, 126 insertions, 103 deletions
diff --git a/libhb/stream.c b/libhb/stream.c index a4b8ffe67..109864f30 100755 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -108,6 +108,15 @@ static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream, static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title); static off_t align_to_next_packet(FILE* f); +/* + * streams have a bunch of state that's learned during the scan. We don't + * want to throw away the state when scan does a close then relearn + * everything when reader does an open. So we basically ignore + * a stream close, remember the most recent stream we've opened and only + * delete it when a stream of a different name is opened. + */ +static hb_stream_t *current_stream; + static inline int check_ps_sync(const uint8_t *buf) { @@ -177,6 +186,39 @@ static int hb_stream_get_type(hb_stream_t *stream) return 0; } +static void hb_stream_delete( hb_stream_t ** _d ) +{ + hb_stream_t * d = *_d; + + if( d->file_handle ) + { + fclose( d->file_handle ); + d->file_handle = NULL; + } + + int i=0; + for (i = 0; i < kNumDecodeBuffers; i++) + { + if (d->ps_decode_buffer[i].data) + { + free(d->ps_decode_buffer[i].data); + d->ps_decode_buffer[i].data = NULL; + } + } + + for (i = 0; i < kMaxNumberDecodeStreams; i++) + { + if (d->ts_packetbuf[i]) + { + free(d->ts_packetbuf[i]); + d->ts_packetbuf[i] = NULL; + } + } + free( d->path ); + free( d ); + *_d = NULL; +} + /*********************************************************************** * hb_stream_open *********************************************************************** @@ -184,9 +226,16 @@ static int hb_stream_get_type(hb_stream_t *stream) **********************************************************************/ hb_stream_t * hb_stream_open( char * path ) { - hb_stream_t * d; - - d = calloc( sizeof( hb_stream_t ), 1 ); + if (current_stream) + { + if (strcmp( path, current_stream->path ) == 0 ) + { + hb_stream_seek( current_stream, 0. ); + return current_stream; + } + hb_stream_delete( ¤t_stream ); + } + hb_stream_t *d = calloc( sizeof( hb_stream_t ), 1 ); /* open the file and see if it's a type we know about. return a stream * reference structure if we can deal with it & NULL otherwise. */ @@ -195,6 +244,7 @@ hb_stream_t * hb_stream_open( char * path ) d->path = strdup( path ); if (d->path != NULL && hb_stream_get_type( d ) != 0 ) { + current_stream = d; return d; } fclose( d->file_handle ); @@ -213,35 +263,6 @@ hb_stream_t * hb_stream_open( char * path ) **********************************************************************/ void hb_stream_close( hb_stream_t ** _d ) { - hb_stream_t * d = *_d; - - if( d->file_handle ) - { - fclose( d->file_handle ); - d->file_handle = NULL; - } - - int i=0; - for (i = 0; i < kNumDecodeBuffers; i++) - { - if (d->ps_decode_buffer[i].data) - { - free(d->ps_decode_buffer[i].data); - d->ps_decode_buffer[i].data = NULL; - } - } - - for (i = 0; i < kMaxNumberDecodeStreams; i++) - { - if (d->ts_packetbuf[i]) - { - free(d->ts_packetbuf[i]); - d->ts_packetbuf[i] = NULL; - } - } - free( d->path ); - free( d ); - *_d = NULL; } /* when the file was first opened we made entries for all the audio elementary @@ -258,6 +279,8 @@ static void hb_stream_delete_audio_entry(hb_stream_t *stream, int indx) { stream->ts_audio_pids[indx] = stream->ts_audio_pids[i]; stream->ts_audio_stream_type[indx] = stream->ts_audio_stream_type[i]; + stream->ts_streamid[stream->ts_number_video_pids + indx] = + stream->ts_streamid[stream->ts_number_video_pids + i]; ++indx; } --stream->ts_number_audio_pids; @@ -527,9 +550,14 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) // Transport streams are a little more complex - we might be able to just // read from the transport stream conversion buffer (if there's enough data) // or we may need to transfer what's left and fill it again. - if (src_stream->ps_decode_buffer[read_buffer_index].len - src_stream->ps_decode_buffer[read_buffer_index].read_pos > HB_DVD_READ_BUFFER_SIZE) + if (src_stream->ps_decode_buffer[read_buffer_index].len + - src_stream->ps_decode_buffer[read_buffer_index].read_pos + >= HB_DVD_READ_BUFFER_SIZE) { - memcpy(b->data, src_stream->ps_decode_buffer[read_buffer_index].data + src_stream->ps_decode_buffer[read_buffer_index].read_pos,HB_DVD_READ_BUFFER_SIZE); + memcpy(b->data, + src_stream->ps_decode_buffer[read_buffer_index].data + + src_stream->ps_decode_buffer[read_buffer_index].read_pos, + HB_DVD_READ_BUFFER_SIZE); src_stream->ps_decode_buffer[read_buffer_index].read_pos += HB_DVD_READ_BUFFER_SIZE; return 1; } @@ -541,9 +569,9 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) int amt_avail_to_transfer = src_stream->ps_decode_buffer[read_buffer_index].len - src_stream->ps_decode_buffer[read_buffer_index].read_pos; memcpy(b->data, src_stream->ps_decode_buffer[read_buffer_index].data + src_stream->ps_decode_buffer[read_buffer_index].read_pos, amt_avail_to_transfer); transfer_size -= amt_avail_to_transfer; - src_stream->ps_decode_buffer[read_buffer_index].read_pos += amt_avail_to_transfer; - + // Give up this buffer - decoding may well need it, and we're done + src_stream->ps_decode_buffer[read_buffer_index].read_pos = 0; src_stream->ps_decode_buffer[read_buffer_index].write_pos = 0; src_stream->ps_decode_buffer[read_buffer_index].len = 0; @@ -647,16 +675,18 @@ static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream, stream->ts_audio_stream_type[aud_pid_index], audio->id); stream->ts_audio_stream_type[aud_pid_index] = 0x81; + stream->ts_streamid[stream->ts_number_video_pids + aud_pid_index] = buf[3]; } else if ((buf[3] & 0xe0) == 0xc0) { - audio->id = buf[3]; + audio->id = buf[3] | aud_pid_index; audio->codec = HB_ACODEC_MPGA; hb_log("transport stream pid 0x%x (type 0x%x) is MPEG audio id 0x%x", stream->ts_audio_pids[aud_pid_index], stream->ts_audio_stream_type[aud_pid_index], audio->id); stream->ts_audio_stream_type[aud_pid_index] = 0x03; + stream->ts_streamid[stream->ts_number_video_pids + aud_pid_index] = buf[3]; } } fseeko(stream->file_handle, cur_pos, SEEK_SET); @@ -760,14 +790,23 @@ void hb_stream_update_audio(hb_stream_t *stream, hb_audio_t *audio) if (stream->stream_type == hb_stream_type_transport) { - // Find the audio stream info for this PID - int i = (audio->id >> 8) & 0xf; + // Find the audio stream info for this PID. The stream index is + // the subchannel id which is in the bottom four bits for MPEG audio + // and the bottom four bits of the upper byte for everything else. + int i = ( audio->id >= 0xd0 ? audio->id >> 8 : audio->id ) & 0xf; if (i >= stream->ts_number_audio_pids) { hb_log("hb_stream_update_audio: no PID for audio stream 0x%x", audio->id); return; } + if (audio->id < 0xd0) + { + /* XXX fake mpeg audio sample rate & bps */ + stream->a52_info[i].flags = A52_STEREO; + stream->a52_info[i].rate = 48000 /*Hz*/; + stream->a52_info[i].bitrate = 384000 /*Bps*/; + } lang = lang_for_code(stream->a52_info[i].lang_code); if (!audio->rate) @@ -924,7 +963,6 @@ static void hb_ts_stream_init(hb_stream_t *stream) for (i = stream->ts_number_video_pids; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++) { stream->ts_packetbuf[i] = (unsigned char *) malloc(1024 * 1024); - stream->ts_streamid[i] = 0xBD; // Stream 1 is AC-3 Audio } } @@ -1073,24 +1111,24 @@ int decode_program_map(hb_stream_t* stream) { set_buf(stream->pmt_info.tablebuf, stream->pmt_info.tablepos, 0); - unsigned char table_id = get_bits(8); - get_bits(4); - unsigned int section_length = get_bits(12); - stream->pmt_info.section_length = section_length; - - unsigned int program_number = get_bits(16); - stream->pmt_info.program_number = program_number; - get_bits(2); - unsigned char version_number = get_bits(5); - get_bits(1); - unsigned char section_number = get_bits(8); - unsigned char last_section_number = get_bits(8); - get_bits(3); - unsigned int PCR_PID = get_bits(13); - stream->pmt_info.PCR_PID = PCR_PID; - get_bits(4); - unsigned int program_info_length = get_bits(12); - stream->pmt_info.program_info_length = program_info_length; + get_bits(8); // table_id + get_bits(4); + unsigned int section_length = get_bits(12); + stream->pmt_info.section_length = section_length; + + unsigned int program_number = get_bits(16); + stream->pmt_info.program_number = program_number; + get_bits(2); + get_bits(5); // version_number + get_bits(1); + get_bits(8); // section_number + get_bits(8); // last_section_number + get_bits(3); + unsigned int PCR_PID = get_bits(13); + stream->pmt_info.PCR_PID = PCR_PID; + get_bits(4); + unsigned int program_info_length = get_bits(12); + stream->pmt_info.program_info_length = program_info_length; int i=0; unsigned char *descriptor_buf = (unsigned char *) malloc(program_info_length); @@ -1271,14 +1309,14 @@ int decode_PAT(unsigned char *buf, hb_stream_t *stream) set_buf(tablebuf + pos, tablepos - pos, 0); unsigned char section_id = get_bits(8); - get_bits(4); + get_bits(4); unsigned int section_len = get_bits(12); - unsigned int transport_id = get_bits(16); - get_bits(2); - unsigned int version_num = get_bits(5); - unsigned int current_next = get_bits(1); - unsigned int section_num = get_bits(8); - unsigned int last_section = get_bits(8); + get_bits(16); // transport_id + get_bits(2); + get_bits(5); // version_num + get_bits(1); // current_next + get_bits(8); // section_num + get_bits(8); // last_section switch (section_id) { @@ -1297,7 +1335,7 @@ int decode_PAT(unsigned char *buf, hb_stream_t *stream) get_bits(3); // Reserved if (pkt_program_num == 0) { - unsigned int pkt_network_PID = get_bits(13); + get_bits(13); // pkt_network_id } else { @@ -1555,21 +1593,8 @@ int generate_output_data(hb_stream_t *stream, int write_ac3, int curstream, int return 1; } - int index_of_selected_pid = -1; - if ((index_of_selected_pid = index_of_video_pid(pid,stream)) < 0) - { - if ((index_of_selected_pid = index_of_audio_pid(pid,stream)) < 0) - { - hb_log("generate_output_data - cannot find pid 0x%x (%d) in selected audio or video pids", pid, pid); - return 0; - } - else - { - stream->ts_packetbuf[curstream][pos + 3] = stream->ts_streamid[stream->ts_number_video_pids + index_of_selected_pid]; - } - } - else - stream->ts_packetbuf[curstream][pos + 3] = stream->ts_streamid[index_of_selected_pid]; + stream->ts_packetbuf[curstream][pos + 3] = + stream->ts_streamid[curstream]; // Packet length.. // Subtract pack size (14) and pes id and len (6) from lenth @@ -1623,10 +1648,12 @@ int generate_output_data(hb_stream_t *stream, int write_ac3, int curstream, int // Add pes header for next packet pos -= 9; -// make_pes_header(stream->ts_packetbuf[curstream] + pos, (pid == stream->ts_video_pids[0] ? stream->ts_streamid[kVideoStream] : stream->ts_streamid[kAudioStream]), 0, -1, -1); make_pes_header(stream->ts_packetbuf[curstream] + pos, stream->ts_streamid[curstream], 0, -1, -1); } + stream->ts_packetpos[curstream] = 0; + stream->ts_streamcont[curstream] = -1; + // Write padding if ((written % HB_DVD_READ_BUFFER_SIZE) != 0) { @@ -1640,9 +1667,6 @@ int generate_output_data(hb_stream_t *stream, int write_ac3, int curstream, int } } - stream->ts_packetpos[curstream] = 0; - stream->ts_streamcont[curstream] = -1; - return 0; } @@ -1685,9 +1709,7 @@ static int hb_ts_handle_ac3_audio(hb_stream_t *stream, int curstream, unsigned c // Check the next packet to make sure IT starts with a 0x0b77 int plen = 0; -// if (buf[4 + adapt_len] == 0 && buf[4 + adapt_len + 1] == 0 && // Starting with an mpeg header? -// buf[4 + adapt_len + 2] == 1 && buf[4 + adapt_len + 3] == 0xBD) - plen = 9 + buf[4 + adapt_len + 8]; + plen = 9 + buf[4 + adapt_len + 8]; int pstart = 4 + adapt_len + plen; if (buf[pstart] != 0x0b || buf[pstart + 1] != 0x77) { @@ -1968,7 +1990,6 @@ static void hb_ts_stream_decode(hb_stream_t *stream) { stream->ts_skipbad[i] = 1; } - // stream->ts_skipbad[kAudioStream] = stream->ts_skipbad[kVideoStream] = 1; continue; } else if (adaption == 0x2) @@ -1978,19 +1999,19 @@ static void hb_ts_stream_decode(hb_stream_t *stream) adapt_len = buf[4] + 1; if (adapt_len > 184) { - hb_log("hb_ts_stream_decode - Invalid adapt len (was > 183)!"); + hb_log("hb_ts_stream_decode - Invalid adapt len %d", adapt_len); for (i=0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++) { stream->ts_skipbad[i] = 1; } -// stream->ts_skipbad[kAudioStream] = stream->ts_skipbad[kVideoStream] = 1; } } // HBO is slick, it doesn't bother to sync AC3 packets with PES elementary stream packets.. so // we have to swizzle them together! (ARGHH!) -// if (pid == stream->ts_audio_pids[0] && start) - if ((index_of_audio_pid(pid, stream) >= 0) && start) + if (start && curstream >= stream->ts_number_video_pids && + stream->ts_audio_stream_type[curstream - stream->ts_number_video_pids] + != 0x03) { // Is there an AC3 packet start 0b77 code in this packet?? int sync_found = 0; @@ -2008,10 +2029,7 @@ static void hb_ts_stream_decode(hb_stream_t *stream) // Couldn't find an AC3 sync start in this packet.. don't make a PES packet! if (!sync_found) { -// int pos = ftell(fin); -// error("AC3 packet sync not found in start frame"); -// return 1; - adapt_len += 9 + buf[4 + adapt_len + 8]; + adapt_len = 184; start = 0; } } @@ -2022,7 +2040,6 @@ static void hb_ts_stream_decode(hb_stream_t *stream) // Check to see if this is an i_frame (group of picture start) if (pid == stream->ts_video_pids[0]) { -// printf("Found Video Start for pid 0x%x\n", pid); // Look for the Group of Pictures packet.. indicates this is an I-Frame packet.. doing_iframe = 0; unsigned int strid = 0; @@ -2044,8 +2061,6 @@ static void hb_ts_stream_decode(hb_stream_t *stream) // picture_header, let's see if it's an I-frame if (i<187) { -// int pic_start_code = (buf[i+2] >> 3) & 0x07; -// hb_log("hb_ts_stream_decode - picture_start_code header value = 0x%x (%d)", pic_start_code, pic_start_code); // check if picture_coding_type == 1 if ((buf[i+2] & (0x7 << 3)) == (1 << 3)) { @@ -2090,8 +2105,7 @@ static void hb_ts_stream_decode(hb_stream_t *stream) { // Save the substream id block so we can added it to subsequent blocks int write_ac3 = 0; -// if (pid == stream->ts_audio_pids[0] /*&& audstreamid == 0xBD*/) - if (index_of_audio_pid(pid, stream) >= 0) + if (curstream >= stream->ts_number_video_pids) { // Curstream is a zero based index of streams and includes both video and audio streams, so we must subtract the numver of video streams // from the indes value used here since ts_audio_stream_type is indexed only by audio streams. @@ -2110,8 +2124,17 @@ static void hb_ts_stream_decode(hb_stream_t *stream) } // Add the payload for this packet to the current buffer - if (stream->ts_foundfirst[curstream] && (184 - adapt_len) > 0) + if (!stream->ts_skipbad[curstream] && stream->ts_foundfirst[curstream] && + (184 - adapt_len) > 0) { + // XXX this shouldn't happen but we'll be paranoid + if (stream->ts_packetpos[curstream] + 184 - adapt_len > 1024*1024) + { + hb_log("hb_ts_stream_decode: ts_packetbuf overflow, pos = %d ," + "len = %d", stream->ts_packetpos[curstream], + 184 - adapt_len ); + return; + } memcpy(stream->ts_packetbuf[curstream] + stream->ts_packetpos[curstream], buf + 4 + adapt_len, 184 - adapt_len); stream->ts_packetpos[curstream] += 184 - adapt_len; } |