All pastes #942151 Raw Edit

someone

public text v1 · immutable
·published 2008-03-14 08:28 UTC
rendered paste body
Index: libhb/reader.c===================================================================--- libhb/reader.c	(revision 1336)+++ libhb/reader.c	(working copy)@@ -17,6 +17,10 @@     hb_stream_t  * stream;      uint           sequence;+    int            saw_video;+    int64_t        scr_offset;+    int64_t        last_scr;+    int            scr_changes;  } hb_reader_t; @@ -163,8 +167,73 @@         {             hb_list_rem( list, buf );             fifos = GetFifoForId( r->job, buf->id );++            if ( ! r->saw_video )+            {+                /* The first video packet defines 'time zero' so discard+                   data until we get a video packet with a PTS */+                if ( buf->id == 0xE0 && buf->start != -1 )+                {+                    r->saw_video = 1;+                    r->scr_offset = buf->start;+                    r->last_scr = buf->stop;+                    hb_log( "reader: first SCR %llu scr_offset %llu",+                            r->last_scr, r->scr_offset );+                }+                else+                {+                    fifos = NULL;+                }+            }             if( fifos )             {+                /*+                 * This section of code implements the timing model of+                 * the "Standard Target Decoder" (STD) of the MPEG2 standard+                 * (specified in ISO 13818-1 sections 2.4.2, 2.5.2 & Annex D).+                 * The STD removes and corrects for clock discontinuities so+                 * that the time stamps on the video, audio & other media+                 * streams can be used for cross-media synchronization. To do+                 * this the STD has its own timestamp value, the System Clock+                 * Reference or SCR, in the PACK header. Clock discontinuities+                 * are detected using the SCR & and the adjustment needed+                 * to correct post-discontinuity timestamps to be contiguous+                 * with pre-discontinuity timestamps is computed from pre- and+                 * post-discontinuity values of the SCR. Then this adjustment+                 * is applied to every media timestamp (PTS).+                 *+                 * hb_demux_ps left the SCR for this pack in buf->stop.+                 * ISO 13818-1 says there must be an SCR at least every 700ms+                 * (100ms for Transport Streams) so if the difference between+                 * this SCR & the previous is >700ms it's a discontinuity.+                 * If the difference is negative it's non-physical (time doesn't+                 * go backward) and must also be a discontinuity. When we find a+                 * discontinuity we adjust the scr_offset so that the SCR of the+                 * new packet lines up with that of the previous packet.+                 */+                int64_t scr_delta = buf->stop - r->last_scr;+                if ( scr_delta > 67500 || scr_delta < -900 )+                {+                    ++r->scr_changes;+                    r->scr_offset += scr_delta - 1;+                }+                r->last_scr = buf->stop;+                buf->stop = -1;++                /*+                 * The last section detected discontinuites and computed the+                 * appropriate correction to remove them. The next couple of+                 * lines apply the correction to the media timestamps so the+                 * code downstream of us sees only timestamps relative to the+                 * same, continuous clock with time zero on that clock being+                 * the time of the first video packet.+                 */+                if ( buf->start != -1 )+                {+                    /* this packet has a PTS - correct it for the initial+                       video time offset & any timing discontinuities. */+                    buf->start -= r->scr_offset;+                }                 buf->sequence = r->sequence++;                 for( n = 0; fifos[n] != NULL; n++)                 {@@ -212,10 +281,10 @@       hb_stream_close(&r->stream);     } +    hb_log( "reader: done. %d scr changes", r->scr_changes );+     free( r );     _r = NULL;--    hb_log( "reader: done" ); }  /***********************************************************************Index: libhb/deca52.c===================================================================--- libhb/deca52.c	(revision 1336)+++ libhb/deca52.c	(working copy)@@ -213,6 +213,10 @@      /* Get the whole frame */     hb_list_getbytes( pv->list, pv->frame, pv->size, &pts, &pos );+    if (pts == -1)+    {+        pts = pv->next_expected_pts;+    }      /* AC3 passthrough: don't decode the AC3 frame */     if( pv->job->acodec & HB_ACODEC_AC3 ||@@ -222,6 +226,7 @@         memcpy( buf->data, pv->frame, pv->size );         buf->start = pts + ( pos / pv->size ) * 6 * 256 * 90000 / pv->rate;         buf->stop  = buf->start + 6 * 256 * 90000 / pv->rate;+        pv->next_expected_pts = buf->stop;         pv->sync = 0;         return buf;     }@@ -236,10 +241,6 @@      /* 6 blocks per frame, 256 samples per block, channelsused channels */     buf        = hb_buffer_init( 6 * 256 * pv->out_discrete_channels * sizeof( float ) );-    if (pts == -1)-    {-      pts = pv->next_expected_pts;-    }     buf->start = pts + ( pos / pv->size ) * 6 * 256 * 90000 / pv->rate;     buf->stop  = buf->start + 6 * 256 * 90000 / pv->rate; Index: libhb/stream.c===================================================================--- libhb/stream.c	(revision 1336)+++ libhb/stream.c	(working copy)@@ -17,12 +17,8 @@ #define kMaxNumberVideoPIDS 1 #define kMaxNumberAudioPIDS 16 #define kMaxNumberDecodeStreams (kMaxNumberVideoPIDS+kMaxNumberAudioPIDS)-#define kNumDecodeBuffers 2 #define kMaxNumberPMTStreams 32 -#define CLOCKRATE		((int64_t)27000000)			// MPEG System clock rate-#define STREAMRATE		((int64_t)2401587)			// Original HD stream rate 19.2 Mbps-#define DEMUX			(((int)STREAMRATE * 8) / 50)// Demux value for HD content STREAMRATE / 50  struct hb_stream_s {@@ -30,39 +26,36 @@ 	FILE		 * file_handle; 	hb_stream_type_t stream_type; -	int				 ps_current_write_buffer_index;-	int				 ps_current_read_buffer_index;+    int              frames;            /* video frames so far */+    int              errors;            /* total errors so far */+    int              last_error_frame;  /* frame # at last error message */+    int              last_error_count;  /* # errors at last error message */ -	struct {-		int				 size;-		int				 len;-		int				 read_pos;-		int				 write_pos;-		unsigned char *  data;-	} ps_decode_buffer[kNumDecodeBuffers];+    int64_t          ts_lastpcr;    /* the last pcr we found in the TS stream */+    int64_t          ts_nextpcr;    /* the next pcr to put in a PS packet */ -	struct {-		int lang_code;-		int flags;-		int rate;-		int bitrate;-	} a52_info[kMaxNumberAudioPIDS];- 	int				 ts_video_pids[kMaxNumberVideoPIDS]; 	int				 ts_audio_pids[kMaxNumberAudioPIDS];  	int				 ts_number_video_pids; 	int				 ts_number_audio_pids; -	unsigned char*	 ts_packetbuf[kMaxNumberDecodeStreams];-	int				 ts_packetpos[kMaxNumberDecodeStreams];-//	int				 ts_bufpackets[kMaxNumberDecodeStreams];-	int				 ts_foundfirst[kMaxNumberDecodeStreams];-	int				 ts_skipbad[kMaxNumberDecodeStreams];-	int				 ts_streamcont[kMaxNumberDecodeStreams];+	uint8_t         *ts_buf[kMaxNumberDecodeStreams];+	int				 ts_pos[kMaxNumberDecodeStreams]; 	int				 ts_streamid[kMaxNumberDecodeStreams];-	int				 ts_audio_stream_type[kMaxNumberAudioPIDS];+	int				 ts_audio_stream_type[kMaxNumberDecodeStreams];+	int8_t           ts_foundfirst[kMaxNumberDecodeStreams];+	int8_t           ts_skipbad[kMaxNumberDecodeStreams];+	int8_t           ts_streamcont[kMaxNumberDecodeStreams];+	int8_t           ts_start[kMaxNumberDecodeStreams]; +	struct {+		int lang_code;+		int flags;+		int rate;+		int bitrate;+	} a52_info[kMaxNumberAudioPIDS];+ 	struct 	{ 		unsigned short program_number;@@ -98,9 +91,8 @@ static void hb_stream_duration(hb_stream_t *stream, hb_title_t *inTitle); static void hb_ts_stream_init(hb_stream_t *stream); static void hb_ts_stream_find_pids(hb_stream_t *stream);-static void hb_ts_stream_decode(hb_stream_t *stream);+static int hb_ts_stream_decode(hb_stream_t *stream, uint8_t *obuf); static void hb_ts_stream_reset(hb_stream_t *stream);-static void hb_stream_put_back(hb_stream_t *stream, int i); static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream,                                                        int aud_pid_index); static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title);@@ -195,21 +187,13 @@     }  	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])+		if (d->ts_buf[i]) 		{-			free(d->ts_packetbuf[i]);-			d->ts_packetbuf[i] = NULL;+			free(d->ts_buf[i]);+			d->ts_buf[i] = NULL; 		} 	}     free( d->path );@@ -261,6 +245,13 @@  **********************************************************************/ void hb_stream_close( hb_stream_t ** _d ) {+    hb_stream_t *stream = * _d;+    if ( stream->frames )+    {+        hb_log( "stream: %d good frames, %d errors (%.0f%%)", stream->frames,+                stream->errors, (double)stream->errors * 100. / +                (double)stream->frames );+    } }  /* when the file was first opened we made entries for all the audio elementary@@ -276,14 +267,27 @@     for (i = indx+1; i < stream->ts_number_audio_pids; ++i)     {         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];+        stream->ts_audio_stream_type[1 + indx] = stream->ts_audio_stream_type[1+i];+        stream->ts_streamid[1 + indx] = stream->ts_streamid[1 + i];         ++indx;     }     --stream->ts_number_audio_pids; } +static int index_of_pid(int pid, hb_stream_t *stream)+{+    int i;++    if ( pid == stream->ts_video_pids[0] )+        return 0;++    for ( i = 0; i < stream->ts_number_audio_pids; ++i )+        if ( pid == stream->ts_audio_pids[i] )+            return i + 1;++    return -1;+}+ /***********************************************************************  * hb_ps_stream_title_scan  ***********************************************************************@@ -340,6 +344,13 @@                 --i;             }         }++        // add the PCR PID if we don't already have it+        if ( index_of_pid( stream->pmt_info.PCR_PID, stream ) < 0 )+        {+            stream->ts_audio_pids[stream->ts_number_audio_pids++] =+                stream->pmt_info.PCR_PID;+        } 	}     else     {@@ -537,7 +548,7 @@     for ( i = 0; i < n-1; ++i )     {         // Bias the median filter by not including pairs that are "far"-        // frome one another. This is to handle cases where the file is+        // from one another. This is to handle cases where the file is         // made of roughly equal size pieces where a symmetric choice of         // pairs results in having the same number of intra-piece &         // inter-piece rate estimates. This would mean that the median@@ -595,68 +606,13 @@  **********************************************************************/ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) {-  if (src_stream->stream_type == hb_stream_type_program)-  {-	  size_t amt_read;-	  amt_read = fread(b->data, HB_DVD_READ_BUFFER_SIZE, 1, src_stream->file_handle);-	  if (amt_read > 0)-		return 1;-	  else-		return 0;-  }-  else if  (src_stream->stream_type == hb_stream_type_transport)-  {-	int read_buffer_index = src_stream->ps_current_read_buffer_index;--	// 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)-	{-		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;-	}-	else-	{-		// Not quite enough data in the buffer - transfer what is present, fill the buffer and then-		// transfer what's still needed.-		int transfer_size = HB_DVD_READ_BUFFER_SIZE;-		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;--		// 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;--		// Fill the buffer-		hb_ts_stream_decode(src_stream);--		// Decoding will almost certainly have changed the current read buffer index-		read_buffer_index = src_stream->ps_current_read_buffer_index;--		if (src_stream->ps_decode_buffer[read_buffer_index].len == 0)-		{-			hb_log("hb_stream_read - buffer after decode has zero length data");-			return 0;-		}--		// Read the bit we still need-		memcpy(b->data+amt_avail_to_transfer, src_stream->ps_decode_buffer[read_buffer_index].data + src_stream->ps_decode_buffer[read_buffer_index].read_pos,transfer_size);-		src_stream->ps_decode_buffer[read_buffer_index].read_pos += transfer_size;--		return 1;-	}-  }-  else-	return 0;+    if ( src_stream->stream_type == hb_stream_type_program )+    {+        size_t amt_read = fread(b->data, HB_DVD_READ_BUFFER_SIZE, 1,+                                src_stream->file_handle);+        return (amt_read > 0);+    }+    return hb_ts_stream_decode( src_stream, b->data ); }  /***********************************************************************@@ -688,28 +644,6 @@ 	hb_ts_stream_reset(src_stream);   } -  // Now we must scan forwards for a valid start code (0x000001BA)-  int done = 0;-  hb_buffer_t *buf = hb_buffer_init(HB_DVD_READ_BUFFER_SIZE);-  while (!done)-  {-    if (hb_stream_read(src_stream,buf) == 1)-    {-      int i=0;-      for (i=0; (i <= HB_DVD_READ_BUFFER_SIZE-4) && (!done); i++)-      {-        if ((buf->data[i] == 0x00) && (buf->data[i+1] == 0x00) && (buf->data[i+2] == 0x01) && (buf->data[i+3] == 0xba))-        {-          done = 1;-		  // 'Put Back' the data we've just read (up to this point)-		  hb_stream_put_back(src_stream, i);-        }-      }-    }-    else-      done = 1;    // End of data;-  }-  hb_buffer_close(&buf);   return 1; } @@ -733,10 +667,10 @@             audio->codec = HB_ACODEC_AC3;             hb_log("transport stream pid 0x%x (type 0x%x) is AC-3 audio id 0x%x",                    stream->ts_audio_pids[aud_pid_index],-                   stream->ts_audio_stream_type[aud_pid_index],+                   stream->ts_audio_stream_type[1 + 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];+            stream->ts_audio_stream_type[1 + aud_pid_index] = 0x81;+            stream->ts_streamid[1 + aud_pid_index] = buf[3];         }         else if ((buf[3] & 0xe0) == 0xc0)         {@@ -744,10 +678,10 @@             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],+                   stream->ts_audio_stream_type[1 + 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];+            stream->ts_audio_stream_type[1 + aud_pid_index] = 0x03;+            stream->ts_streamid[1 + aud_pid_index] = buf[3];         }     }     fseeko(stream->file_handle, cur_pos, SEEK_SET);@@ -755,7 +689,7 @@     {         hb_log("transport stream pid 0x%x (type 0x%x) isn't audio",                 stream->ts_audio_pids[aud_pid_index],-                stream->ts_audio_stream_type[aud_pid_index]);+                stream->ts_audio_stream_type[1 + aud_pid_index]); 	}     return audio; }@@ -949,81 +883,41 @@ 			HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->input_channel_layout)); 	} -	hb_log( "hb_stream_update_audio: id=%x, lang=%s, 3cc=%s, rate = %d, bitrate = %d, flags = 0x%x (%d)", audio->id, audio->lang, audio->iso639_2, audio->rate, audio->bitrate, audio->ac3flags, audio->ac3flags );+	hb_log( "stream: audio %x: lang %s, rate %d, bitrate %d, "+            "flags = 0x%x", audio->id, audio->lang, audio->rate,+            audio->bitrate, audio->ac3flags );  }  /***********************************************************************- * hb_stream_put_back- ***********************************************************************- *- **********************************************************************/-static void hb_stream_put_back(hb_stream_t *stream, int i)-{-	if (stream->stream_type == hb_stream_type_program)-	{-		// Program streams are pretty easy - we just reposition the source file-		// pointer-		fseeko(stream->file_handle, -(HB_DVD_READ_BUFFER_SIZE-i), SEEK_CUR);-	}-	else if (stream->stream_type == hb_stream_type_transport)-	{-		int read_buffer_index = stream->ps_current_read_buffer_index;--		// Transport streams are a little more tricky - so long as the-		// amount to back up is still within the current decode buffer-		// we can just adjust the read pos.-		if (stream->ps_decode_buffer[read_buffer_index].read_pos - i > 0)-		{-			stream->ps_decode_buffer[read_buffer_index].read_pos -= i;-		}-		else-		  hb_error("hb_stream_put_back - trying to step beyond the start of the buffer, read_pos = %d amt to put back = %d\n", stream->ps_decode_buffer[read_buffer_index].read_pos, i);-	}-}---/***********************************************************************  * hb_ts_stream_init  ***********************************************************************  *  **********************************************************************/- #define PS_DECODE_BUFFER_SIZE ( 1024 * 1024 * 4)  static void hb_ts_stream_init(hb_stream_t *stream) {-	// Output Program Stream-	int i=0;-	for (i=0; i < kNumDecodeBuffers; i++)-	{-		stream->ps_decode_buffer[i].data = (unsigned char *) malloc(PS_DECODE_BUFFER_SIZE);-		stream->ps_decode_buffer[i].read_pos = 0;-		stream->ps_decode_buffer[i].size = PS_DECODE_BUFFER_SIZE;-		stream->ps_decode_buffer[i].len = 0;-		stream->ps_decode_buffer[i].write_pos = 0;-	}+	int i;  	for (i=0; i < kMaxNumberDecodeStreams; i++) 	{ 		stream->ts_streamcont[i] = -1; 	}+	stream->ts_video_pids[0] = -1;+    for ( i = 0; i < stream->ts_number_audio_pids; i++ )+    {+        stream-> ts_audio_pids[i] = -1;+    } -	stream->ps_current_write_buffer_index = 0;-	stream->ps_current_read_buffer_index = 1;- 	// Find the audio and video pids in the stream 	hb_ts_stream_find_pids(stream); -	for (i=0; i < stream->ts_number_video_pids; i++)-	{-		// In progress audio/video data during the transport stream -> program stream processing-		stream->ts_packetbuf[i] = (unsigned char *) malloc(1024 * 1024);-		stream->ts_streamid[i] = 0xE0;		// Stream is Video-	}+    stream->ts_streamid[0] = 0xE0;		// stream 0 must be video -	for (i = stream->ts_number_video_pids; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++)+	for (i = 0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++) 	{-		stream->ts_packetbuf[i] = (unsigned char *) malloc(1024 * 1024);+        // demuxing buffer for TS to PS conversion+		stream->ts_buf[i] = malloc( HB_DVD_READ_BUFFER_SIZE ); 	} } @@ -1233,7 +1127,7 @@         if (i < kMaxNumberAudioPIDS)             stream->ts_number_audio_pids++;         stream->ts_audio_pids[i] = elementary_PID;-        stream->ts_audio_stream_type[i] = stream_type;+        stream->ts_audio_stream_type[1 + i] = stream_type;  		if (ES_info_length > 0) 		{@@ -1426,391 +1320,6 @@     return 1; } -static int flushbuf(hb_stream_t *stream)-{-	int old_write_index = stream->ps_current_write_buffer_index;--	// Flip the buffers and start moving on to the next-	stream->ps_current_write_buffer_index++;-	if (stream->ps_current_write_buffer_index > kNumDecodeBuffers-1)-		stream->ps_current_write_buffer_index = 0;--	if ( (stream->ps_decode_buffer[stream->ps_current_write_buffer_index].len != 0) || (stream->ps_decode_buffer[stream->ps_current_write_buffer_index].write_pos != 0) )-	{-		hb_log("flushbuf - new buffer (index %d) has non zero length and write position !", stream->ps_current_write_buffer_index);-		return 0;-	}--	stream->ps_current_read_buffer_index = old_write_index;-	stream->ps_decode_buffer[stream->ps_current_read_buffer_index].read_pos = 0;--	return 1;-}--static int fwrite64(void* buf, int elsize, int elnum, hb_stream_t* stream)-{-	int size = elsize;-	if (elnum > 1)-		size *= elnum;--	int written = 0;-	int current_write_index = stream->ps_current_write_buffer_index;--	if (size <= stream->ps_decode_buffer[current_write_index].size - stream->ps_decode_buffer[current_write_index].write_pos)-	{-		memcpy(stream->ps_decode_buffer[current_write_index].data + stream->ps_decode_buffer[current_write_index].write_pos, buf, size);-		stream->ps_decode_buffer[current_write_index].write_pos += size;-		stream->ps_decode_buffer[current_write_index].len = stream->ps_decode_buffer[current_write_index].write_pos;-		written = size;-	}-	else-	{-		memcpy(stream->ps_decode_buffer[current_write_index].data + stream->ps_decode_buffer[current_write_index].write_pos, buf, stream->ps_decode_buffer[current_write_index].size - stream->ps_decode_buffer[current_write_index].write_pos);-		written += stream->ps_decode_buffer[current_write_index].size - stream->ps_decode_buffer[current_write_index].write_pos;-		stream->ps_decode_buffer[current_write_index].write_pos += stream->ps_decode_buffer[current_write_index].size - stream->ps_decode_buffer[current_write_index].write_pos;-		stream->ps_decode_buffer[current_write_index].len = stream->ps_decode_buffer[current_write_index].write_pos;--		if (flushbuf(stream))-		{-			// FLushing the buffer will have change the current write buffer-			current_write_index = stream->ps_current_write_buffer_index;--			memcpy(stream->ps_decode_buffer[current_write_index].data, (unsigned char*)buf + written, size - written);-			stream->ps_decode_buffer[current_write_index].write_pos += size - written;-			stream->ps_decode_buffer[current_write_index].len = stream->ps_decode_buffer[current_write_index].write_pos;-			written += size - written;-		}-	}---	if (elnum == 1 && written == size)-		return 1;-	else-		return written / elsize;-}--static int write_pack(hb_stream_t* stream, int64_t time)-{-	unsigned char buf[64];-	set_buf(buf, 64, 1);						// clear buffer--	int64_t ext_time = time % 300;-	time = time / 300;--	set_bits(0x000001ba, 32);					// pack id								32-	set_bits(1, 2);								// 0x01									2-	set_bits((unsigned int)(time >> 30), 3);	// system_clock_reference_base			3-	set_bits(1, 1);								// marker_bit							1-	set_bits((unsigned int)(time >> 15), 15);	// system_clock_reference_base			15-	set_bits(1, 1);								// marker_bit							1-	set_bits((unsigned int)time, 15);			// system_clock_reference_base1			15-	set_bits(1, 1);								// marker_bit							1-	set_bits((unsigned int)ext_time, 9);		// system_clock_reference_extension		9-	set_bits(1, 1);								// marker_bit							1-	set_bits(DEMUX, 22);						// program_mux_rate						22-	set_bits(1, 1);								// marker_bit							1-	set_bits(1, 1);								// marker_bit							1-	set_bits(31, 5);							// reserved								5-	set_bits(0, 3);								// pack_stuffing_length					3--	return fwrite64(buf, buf_size(), 1, stream) == 1;-}--static int pad_buffer(hb_stream_t *stream, int pad)-{-	pad -= 6;--	char buf[6];-	buf[0] = '\x0'; buf[1] = '\x0'; buf[2] = '\x1'; buf[3] = '\xbe';-	buf[4] = pad >> 8; buf[5] = pad & 0xff;--	if (fwrite64(buf, 6, 1, stream) != 1)-		return 0;--	unsigned char padbyte = 0xff;-	int i=0;-	for (i = 0; i < pad; i++)-	{-		if (fwrite64(&padbyte, 1, 1, stream) != 1)-			return 0;-	}--	return 1;-}--int make_pes_header(unsigned char* buf, int streamid, int len, int64_t PTS, int64_t DTS)-{-	int hdrlen = 0;-	int PTS_DTS_flags = 0;-	if (PTS != -1)-	{-		if (DTS != -1)-		{-			PTS_DTS_flags = 3;-			hdrlen += 10;-		}-		else-		{-			PTS_DTS_flags = 2;-			hdrlen += 5;-		}-	}--	set_buf(buf, 9 + hdrlen, 1);				// clear the buffer--	set_bits(0x000001, 24);						// packet_start_code_prefix				24-	set_bits((unsigned int)streamid, 8);		// directory_stream_id					8-	set_bits(len, 16);							// PES_packet_length					16-	set_bits(0x2, 2);							// '10'									2-	set_bits(0, 2);								// PES_scrambling_control				2-	set_bits(1, 1);								// PES_priority							1-	set_bits(0, 1);								// data_alignment_indicator				1-	set_bits(0, 1);								// copyright							1-	set_bits(0, 1);								// original_or_copy						1-	set_bits(PTS_DTS_flags, 2);					// PTS_DTS_flags						2-	set_bits(0, 1);								// ESCR_flag							1-	set_bits(0, 1);								// ES_rate_flag							1-	set_bits(0, 1);								// DSM_trick_mode_flag					1-	set_bits(0, 1);								// additional_copy_info_flag			1-	set_bits(0, 1);								// PES_CRC_flag							1-	set_bits(0, 1);								// PES_extension_flag					1-	set_bits(hdrlen, 8);						// PES_header_data_length				8--	if (PTS_DTS_flags == 2)-	{-		set_bits(2, 4);								// '0010'							4-		set_bits((unsigned int)(PTS >> 30), 3);		// PTS [32..30]						3-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)(PTS >> 15), 15);	// PTS [29..15]						15-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)PTS, 15);			// PTS [14..0]						15-		set_bits(1, 1);								// marker bit						1-	}-	else if (PTS_DTS_flags == 3)-	{-		set_bits(3, 4);								// '0011'							4-		set_bits((unsigned int)(PTS >> 30), 3);		// PTS [32..30]						3-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)(PTS >> 15), 15);	// PTS [29..15]						15-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)PTS, 15);			// PTS [14..0]						15-		set_bits(1, 1);								// marker bit						1-		set_bits(1, 4);								// '0001'							4-		set_bits((unsigned int)(DTS >> 30), 3);		// DTS [32..30]						3-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)(DTS >> 15), 15);	// DTS [29..15]						15-		set_bits(1, 1);								// marker bit						1-		set_bits((unsigned int)DTS, 15);			// DTS [14..0]						15-		set_bits(1, 1);								// marker bit						1-	}--	return buf_size();-}--int generate_output_data(hb_stream_t *stream, int write_ac3, int curstream, int pid)-{-			unsigned char ac3_substream_id[4];-			int ac3len = 0;--			if (write_ac3)-			{-                // Make a four byte DVD ac3 stream header-                int ssid = (curstream - stream->ts_number_video_pids) & 0xf;-                ac3_substream_id[0] = 0x80 | ssid;  // substream id-                ac3_substream_id[1] = 0x01;         // number of sync words-                ac3_substream_id[2] = 0x00;         // first offset (16 bits)-                ac3_substream_id[3] = 0x02;-                ac3len = 4;-			}--			int written = 0;	// Bytes we've written to output file-			int pos = 0;		// Position in PES packet buffer--			for (;;)-			{-				if ((stream->ps_decode_buffer[stream->ps_current_write_buffer_index].len % HB_DVD_READ_BUFFER_SIZE) != 0)-				{-					hb_log("write_output_stream - Packet's not falling on read buffer size boundries!");-					return 1;-				}--				// Get total length of this pack-				int len = min(14 + ac3len + stream->ts_packetpos[curstream] - pos, HB_DVD_READ_BUFFER_SIZE);--				// Figure out stuffing (if we have less than 16 bytes left)-				int stuffing = 0;-				if (len < HB_DVD_READ_BUFFER_SIZE && HB_DVD_READ_BUFFER_SIZE - len < 16)-				{-					stuffing = HB_DVD_READ_BUFFER_SIZE - len;-					len += stuffing;-				}--				// Write out pack header-				off_t file_offset = ftello(stream->file_handle);-				int64_t packet_time = (file_offset * CLOCKRATE / STREAMRATE) + 0 /*file_time*/;-				if (!write_pack(stream, packet_time))-				{-					hb_log("write_output_stream - Couldn't write pack header!");-					return 1;-				}--                stream->ts_packetbuf[curstream][pos + 3] =-                    stream->ts_streamid[curstream];--				// Packet length..-				// Subtract pack size (14) and pes id and len (6) from lenth-				stream->ts_packetbuf[curstream][pos + 4] = (len - 6 - 14) >> 8; stream->ts_packetbuf[curstream][pos + 5] = (len - 6 - 14) & 0xFF;--				// Add any stuffing bytes to header extra len-				int hdrsize = 9 + stream->ts_packetbuf[curstream][pos + 8];-				stream->ts_packetbuf[curstream][pos + 8] += stuffing;					// Add stuffing to header bytes--				// Write out id, streamid, len-				if (fwrite64(stream->ts_packetbuf[curstream] + pos, hdrsize, 1, stream) != 1)	// Write pes id, streamid, and len-				{-					hb_log("write_output_stream - Failed to write output file!");-					return 1;-				}--				// Write stuffing-				int i=0;-				for (i = 0; i < stuffing; i++)				// Write any stuffing bytes-				{-					unsigned char stuff = 0xff;-					if (fwrite64(&stuff, 1, 1, stream) != 1)-					{-						hb_log("write_output_stream - Failed to write output file!");-						return 1;-					}-				}--				// Write ac3 streamid-				if (ac3len != 0)-				{-					if (fwrite64(ac3_substream_id, ac3len, 1, stream) != 1)-					{-						hb_log("write_output_stream - Failed to write output file!");-						return 1;-					}-				}--				// Write rest of data len minus headersize (9) stuffing, and pack size (14)-				if (fwrite64(stream->ts_packetbuf[curstream] + pos + hdrsize, len - hdrsize - 14 - stuffing - ac3len, 1, stream) != 1)	// Write data bytes-				{-					hb_log("write_output_stream - Failed to write output file!");-					return 1;-				}-				written += len;--				// Add len minus stuff we added like the pack (14) and the stuffing.-				pos += len - 14 - stuffing - ac3len;-				if (pos == stream->ts_packetpos[curstream])-					break;--				// Add pes header for next packet-				pos -= 9;-				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)-			{-				int left = HB_DVD_READ_BUFFER_SIZE - (written % HB_DVD_READ_BUFFER_SIZE);--				// Pad out to HB_DVD_READ_BUFFER_SIZE bytes-				if (!pad_buffer(stream, left))-				{-					hb_log("write_output_stream - Couldn't write pad buffer!");-					return 1;-				}-			}--	return 0;-}--static void hb_ts_handle_mpeg_audio(hb_stream_t *stream, int curstream, unsigned char* buf, int adapt_len )-{-	// Although we don't have AC3/A52 audio here we can still use the same structure to record this useful information.--	stream->a52_info[curstream - stream->ts_number_video_pids].flags = A52_STEREO;-	stream->a52_info[curstream - stream->ts_number_video_pids].rate = 48000 /*Hz*/;-	stream->a52_info[curstream - stream->ts_number_video_pids].bitrate = 384000 /*Bps*/;-}--static int hb_ts_handle_ac3_audio(hb_stream_t *stream, int curstream, unsigned char* buf, int adapt_len )-{-	int spos, dpos;--	// Make sure we start with 0x0b77-	if (stream->ts_packetbuf[curstream][9 + stream->ts_packetbuf[curstream][8]] != 0x0b || stream->ts_packetbuf[curstream][9 + stream->ts_packetbuf[curstream][8] + 1] != 0x77)-	{-		spos = 9 + stream->ts_packetbuf[curstream][8];-		dpos = 9 + stream->ts_packetbuf[curstream][8];-		while (spos <= stream->ts_packetpos[curstream] - 2 && !(stream->ts_packetbuf[curstream][spos] == 0x0b && stream->ts_packetbuf[curstream][spos + 1] == 0x77))-			spos++;--		if (!(stream->ts_packetbuf[curstream][spos] == 0x0b && stream->ts_packetbuf[curstream][spos + 1] == 0x77))-		{-			hb_log("hb_ts_stream_decode - Couldn't sync AC3 packet!");-			stream->ts_skipbad[curstream] = 1;-			return 0;-		}--		while (spos < stream->ts_packetpos[curstream])-		{-			stream->ts_packetbuf[curstream][dpos] = stream->ts_packetbuf[curstream][spos];-			spos++;-			dpos++;-		}-		stream->ts_packetpos[curstream] = dpos;-	}--	// Check the next packet to make sure IT starts with a 0x0b77-	int plen = 0;-    plen = 9 + buf[4 + adapt_len + 8];-	int pstart = 4 + adapt_len + plen;-	if (buf[pstart] != 0x0b || buf[pstart + 1] != 0x77)-	{-		spos = pstart;-		while (spos < 188 - 2 && !(buf[spos] == 0x0b && buf[spos + 1] == 0x77))-		{-			stream->ts_packetbuf[curstream][stream->ts_packetpos[curstream]] = buf[spos];-			stream->ts_packetpos[curstream]++;-			spos++;-		}--		if (!(buf[spos] == 0x0b && buf[spos + 1] == 0x77))-		{-			hb_log("hb_ts_stream_decode - Couldn't sync AC3 packet!");-			stream->ts_skipbad[curstream] = 1;-			return 0;-		}--		adapt_len = spos - 4 - plen;--		dpos = spos - 1;-		spos = pstart - 1;-		while (spos >= pstart - plen)-		{-			buf[dpos] = buf[spos];-			spos--;-			dpos--;-		}-	}--	int flags, rate, bitrate;-	if( a52_syncinfo( &buf[pstart], &flags, &rate, &bitrate ) )-	{-		stream->a52_info[curstream - stream->ts_number_video_pids].flags = flags;-		stream->a52_info[curstream - stream->ts_number_video_pids].rate = rate;-		stream->a52_info[curstream - stream->ts_number_video_pids].bitrate = bitrate;-	}-	return 1;-}- static void hb_ts_stream_find_pids(hb_stream_t *stream) { 	unsigned char buf[188];@@ -1843,10 +1352,16 @@ 		// Check sync byte 		if ((buf[0] != 0x47) && (buf[0] != 0x72) && (buf[0] != 0x29)) 		{-			hb_log("hb_ts_stream_find_pids - Bad transport packet (no sync byte 0x47)!");-			int i = 0;-			for (i=0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++)-				stream->ts_skipbad[i] = 1;+            off_t pos = ftello(stream->file_handle) - 188;+            off_t pos2 = align_to_next_packet(stream->file_handle);+            if ( pos2 == 0 )+            {+                hb_log( "hb_ts_stream_find_pids: eof while re-establishing sync @ %lld",+                        pos );+                break;+            }+            hb_log("hb_ts_stream_decode: sync lost @%lld, regained after %lld bytes",+                    pos, pos2 ); 			continue; 		} @@ -1898,82 +1413,325 @@ 	}  } -int index_of_video_pid(int pid, hb_stream_t *stream)++static uint8_t *fwrite_buf;+static uint8_t *fwrite_buf_orig;++static void set_fwrite_buf( uint8_t *obuf ) {-	int found_pid = -1, i = 0;+    fwrite_buf = obuf;+    fwrite_buf_orig = obuf;+} -	for (i = 0; (i < stream->ts_number_video_pids) && (found_pid < 0); i++)-	{-		if (pid == stream->ts_video_pids[i])-			found_pid = i;-	}-	return found_pid;+static void fwrite64( void* buf, int size )+{+    if ( (fwrite_buf - fwrite_buf_orig) + size > 2048 )+    {+        hb_log( "steam fwrite64 buffer overflow - writing %d with %d already",+                size, fwrite_buf - fwrite_buf_orig );+        return;+    }+    memcpy( fwrite_buf, buf, size );+    fwrite_buf += size; } -int index_of_audio_pid(int pid, hb_stream_t *stream)+static void write_pack(hb_stream_t* stream, uint64_t time, int stuffing) {-	int i = 0, found_pid = -1;+	uint8_t buf[64];+	set_buf(buf, 64, 1);			// clear buffer -	for (i = 0; (i < stream->ts_number_audio_pids) && (found_pid < 0); i++)-	{-		if (pid == stream->ts_audio_pids[i])-			found_pid = i;+	set_bits(0x000001ba, 32);		// pack id								32+	set_bits(1, 2);					// 0x01									2+	set_bits(time >> 30, 3);	    // system_clock_reference_base			3+	set_bits(1, 1);					// marker_bit							1+	set_bits(time >> 15, 15);   	// system_clock_reference_base			15+	set_bits(1, 1);					// marker_bit							1+	set_bits(time, 15); 			// system_clock_reference_base1			15+	set_bits(1, 1);					// marker_bit							1+	set_bits(0, 9);		            // system_clock_reference_extension		9+	set_bits(1, 1);					// marker_bit							1+	set_bits(384000, 22);			// program_mux_rate						22+	set_bits(1, 1);					// marker_bit							1+	set_bits(1, 1);					// marker_bit							1+	set_bits(31, 5);				// reserved								5+	set_bits(stuffing, 3);			// pack_stuffing_length					3+    while ( --stuffing >= 0 )+    {+        set_bits(0xff, 8 );+    }+	fwrite64(buf, buf_size());+}++static void pad_buffer(int pad)+{+	pad -= 6;++	uint8_t buf[6];+	buf[0] = 0;+    buf[1] = 0;+    buf[2] = 0;+    buf[3] = 0xbe;+	buf[4] = pad >> 8;+    buf[5] = pad;++	fwrite64(buf, 6);++	buf[0] = 0xff;+    while ( --pad >= 0 )+    {+		fwrite64(buf, 1); 	}-	return found_pid; } -int index_of_pid(int pid, hb_stream_t *stream)+static void make_pes_header(int len, uint8_t streamid) {-	int found_pid = -1;+	uint8_t buf[9];+	set_buf(buf, 9, 1);		            // clear the buffer -	if ((found_pid = index_of_video_pid(pid, stream)) >= 0)-		return found_pid;+	set_bits(0x000001, 24);				// packet_start_code_prefix				24+	set_bits(streamid, 8);          	// directory_stream_id					8+	set_bits(len + 3, 16);				// PES_packet_length					16+	set_bits(0x2, 2);					// '10'									2+	set_bits(0, 2);						// PES_scrambling_control				2+	set_bits(1, 1);						// PES_priority							1+	set_bits(0, 1);						// data_alignment_indicator				1+	set_bits(0, 1);						// copyright							1+	set_bits(0, 1);						// original_or_copy						1+	set_bits(0, 2);    					// PTS_DTS_flags						2+	set_bits(0, 1);						// ESCR_flag							1+	set_bits(0, 1);						// ES_rate_flag							1+	set_bits(0, 1);						// DSM_trick_mode_flag					1+	set_bits(0, 1);						// additional_copy_info_flag			1+	set_bits(0, 1);						// PES_CRC_flag							1+	set_bits(0, 1);						// PES_extension_flag					1+	set_bits(0, 8);						// PES_header_data_length				8 -	if ((found_pid = index_of_audio_pid(pid, stream)) >= 0)-		return found_pid;+    fwrite64(buf, 9);+} -	return found_pid;+static void generate_output_data(hb_stream_t *stream, int curstream)+{+    uint8_t *tdat = stream->ts_buf[curstream];+    int len;++    // we always ship a PACK header plus all the data in our demux buf.+    // AC3 audio also always needs it substream header.+    len = 14 + stream->ts_pos[curstream];+    if ( stream->ts_audio_stream_type[curstream] == 0x81)+    {+        len += 4;+    }++    if ( ! stream->ts_start[curstream] )+    {+        // we're in the middle of a chunk of PES data - we need to add+        // a 'continuation' PES header after the PACK header.+        len += 9;+    }++    // Write out pack header+    // If we don't have 2048 bytes we need to pad to 2048. We can+    // add a padding frame after our data but we need at least 7+    // bytes of space to do it (6 bytes of header & 1 of pad). If+    // we have fewer than 7 bytes left we need to fill the excess+    // space with stuffing bytes added to the pack header.+    int stuffing = 0;+    if ( len > HB_DVD_READ_BUFFER_SIZE )+    {+        hb_log( "stream ts length botch %d", len );+    }+    if ( HB_DVD_READ_BUFFER_SIZE - len < 8)+    {+        stuffing = HB_DVD_READ_BUFFER_SIZE - len;+    }+    write_pack(stream, stream->ts_nextpcr, stuffing );+    stream->ts_nextpcr += 10;++    if ( stream->ts_start[curstream] )+    {+        // Start frames already have a PES header but we have modify it+        // to map from TS PID to PS stream id. Also, if the stream is AC3+        // audio we have to insert an AC3 stream header between the end of+        // the PES header and the start of the stream data.++        stream->ts_start[curstream] = 0;+        tdat[3] = stream->ts_streamid[curstream];++        uint16_t plen = stream->ts_pos[curstream] - 6;+        if ( stream->ts_audio_stream_type[curstream] == 0x81)+        {+            // We have to add an AC3 header in front of the data. Add its+            // size to the PES packet length.+            plen += 4;+            tdat[4] = plen >> 8;+            tdat[5] = plen;++            // Write out the PES header+            int hdrsize = 9 + tdat[8];+            fwrite64(tdat, hdrsize);++            // add a four byte DVD ac3 stream header+            uint8_t ac3_substream_id[4];+            int ssid = (curstream - stream->ts_number_video_pids) & 0xf;+            ac3_substream_id[0] = 0x80 | ssid;  // substream id+            ac3_substream_id[1] = 0x01;         // number of sync words+            ac3_substream_id[2] = 0x00;         // first offset (16 bits)+            ac3_substream_id[3] = 0x02;+            fwrite64(ac3_substream_id, 4);++            // add the rest of the data+            fwrite64(tdat + hdrsize, stream->ts_pos[curstream] - hdrsize);+        }+        else+        {+            // not audio - don't need to modify the stream so write what we've got+            tdat[4] = plen >> 8;+            tdat[5] = plen;+            fwrite64( tdat, stream->ts_pos[curstream] );+        }+    }+    else+    {+        // data without a PES start header needs a simple 'continuation'+        // PES header. AC3 audio also needs its substream header.+        if ( stream->ts_audio_stream_type[curstream] != 0x81)+        {+            make_pes_header(stream->ts_pos[curstream],+                            stream->ts_streamid[curstream]);+        }+        else+        {+            make_pes_header(stream->ts_pos[curstream] + 4,+                            stream->ts_streamid[curstream]);++            // add a four byte DVD ac3 stream header+            uint8_t ac3_substream_id[4];+            int ssid = (curstream - stream->ts_number_video_pids) & 0xf;+            ac3_substream_id[0] = 0x80 | ssid;  // substream id+            ac3_substream_id[1] = 0x01;         // number of sync words+            ac3_substream_id[2] = 0x00;         // first offset (16 bits)+            ac3_substream_id[3] = 0x02;+            fwrite64(ac3_substream_id, 4);+        }+        fwrite64( tdat, stream->ts_pos[curstream] );+    }++    // Write padding+    int left = HB_DVD_READ_BUFFER_SIZE - len;+    if ( left >= 8 )+    {+        pad_buffer(left);+    }++    stream->ts_pos[curstream] = 0; } +static void ts_warn_helper( hb_stream_t *stream, char *log, va_list args )+{+    // limit error printing to at most one per minute of video (at 30fps)+    ++stream->errors;+    if ( stream->frames - stream->last_error_frame >= 30*60 )+    {+        char msg[256];++        vsnprintf( msg, sizeof(msg), log, args );++        if ( stream->errors - stream->last_error_count < 10 )+        {+            hb_log( "stream: error near frame %d: %s", stream->frames, msg );+        }+        else+        {+            int Edelta = stream->errors - stream->last_error_count;+            double Epcnt = (double)Edelta * 100. /+                            (stream->frames - stream->last_error_frame);+            hb_log( "stream: %d new errors (%.0f%%) up to frame %d: %s",+                    Edelta, Epcnt, stream->frames, msg );+        }+        stream->last_error_frame = stream->frames;+        stream->last_error_count = stream->errors;+    }+}++static void ts_warn( hb_stream_t *stream, char *log, ... )+{+    va_list     args;+    va_start( args, log );+    ts_warn_helper( stream, log, args );+    va_end( args );+}++static void ts_err( hb_stream_t *stream, int curstream, char *log, ... )+{+    va_list     args;+    va_start( args, log );+    ts_warn_helper( stream, log, args );+    va_end( args );++    stream->ts_skipbad[curstream] = 1;+    stream->ts_pos[curstream] = 0;+    stream->ts_streamcont[curstream] = -1;+}++static int isIframe( const uint8_t *buf, int adapt_len )+{+    // Look for the Group of Pictures packet+    int i;+    uint32_t strid = 0;++    for (i = 4 + adapt_len; i < 188; i++)+    {+        strid = (strid << 8) | buf[i];+        switch ( strid )+        {+            case 0x000001B8: // group_start_code (GOP header)+            case 0x000001B3: // sequence_header code+                return 1;++            case 0x00000100: // picture_start_code+                // picture_header, let's see if it's an I-frame+                if (i<185)+                {+                    // check if picture_coding_type == 1+                    if ((buf[i+2] & (0x7 << 3)) == (1 << 3))+                    {+                        // found an I-frame picture+                        return 1;+                    }+                }+                break;+        }+    }+    // didn't find an I frame+    return 0;+}+ /***********************************************************************  * hb_ts_stream_decode  ***********************************************************************  *  **********************************************************************/-static void hb_ts_stream_decode(hb_stream_t *stream)+static int hb_ts_stream_decode( hb_stream_t *stream, uint8_t *obuf ) {-	unsigned char buf[188];+    int64_t pcr = stream->ts_lastpcr; 	int curstream;-	int doing_iframe;+	uint8_t buf[188]; -	int i = 0;-	for (i=0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++)-	{-		stream->ts_skipbad[i] = 0;-	}+    set_fwrite_buf( obuf ); -	doing_iframe = 0;--	if ((stream->ts_number_video_pids == 0) || (stream->ts_number_audio_pids == 0))+	// spin until we get a packet of data from some stream or hit eof+	while ( 1 ) 	{-		hb_log("hb_ts_stream_decode  - no Video or Audio PID selected, cannot decode transport stream");-		return;-	}--	int curr_write_buffer_index = stream->ps_current_write_buffer_index;--	// Write output data until a buffer switch occurs.-	while (curr_write_buffer_index == stream->ps_current_write_buffer_index)-	{-      if ((fread(buf, 188, 1, stream->file_handle)) != 1)+        if ((fread(buf, 188, 1, stream->file_handle)) != 1) 		{             // end of file - we didn't finish filling our ps write buffer             // so just discard the remainder (the partial buffer is useless)             hb_log("hb_ts_stream_decode - eof");-            stream->ps_decode_buffer[stream->ps_current_write_buffer_index].len = 0;-            return;+            return 0; 		} +        /* This next section validates the packet */+ 		// Check sync byte 		if ((buf[0] != 0x47) && (buf[0] != 0x72) && (buf[0] != 0x29)) 		{@@ -1985,81 +1743,32 @@             {                 hb_log( "hb_ts_stream_decode: eof while re-establishing sync @ %lld",                         pos );-                stream->ps_decode_buffer[stream->ps_current_write_buffer_index].len = 0;-                return;+                return 0;             }-            hb_log("hb_ts_stream_decode: sync lost @%lld, regained after %lld bytes",-                    pos, pos2 );-			for (i=0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++)-			{-				stream->ts_skipbad[i] = 1;-			}+            ts_warn( stream, "hb_ts_stream_decode: sync lost @%lld, "+                     "regained after %lld bytes", pos, pos2 ); 			continue; 		} -		// Get pid-		int pid = (((buf[1] & 0x1F) << 8) | buf[2]) & 0x1FFF;+		// Get pid and use it to find stream state.+		int pid = ((buf[1] & 0x1F) << 8) | buf[2];+        if ( ( curstream = index_of_pid( pid, stream ) ) < 0 )+            continue; -		// Get the pos and buf - we organize our streams as 'n' video streams then 'm' audio streams-      int index_of_selected_pid;-		if ((index_of_selected_pid = index_of_video_pid(pid,stream)) < 0)-		{-			// Not a video PID perhaps audio ?-			if ((index_of_selected_pid = index_of_audio_pid(pid,stream)) < 0)-			{-            // not a pid we want-				continue;-			}-			else-			{-				curstream = stream->ts_number_video_pids + index_of_selected_pid;-			}-		}-		else-			curstream = index_of_selected_pid;--		// Get start code-		int start;-		start = (buf[1] & 0x40) != 0;--		if (!start && stream->ts_skipbad[curstream])-			continue;- 		// Get error 		int errorbit = (buf[1] & 0x80) != 0; 		if (errorbit) 		{-			hb_log("hb_ts_stream_decode - Error bit set in packet");-			stream->ts_skipbad[curstream] = 1;+			ts_err( stream, curstream,  "packet error bit set"); 			continue; 		}  		// Get adaption header info 		int adaption = (buf[3] & 0x30) >> 4; 		int adapt_len = 0;--		// Get continuity-        // Continuity only increments for adaption values of 0x3 or 0x01-		int continuity = (buf[3] & 0xF);-        if ((stream->ts_streamcont[curstream] != -1) && ((adaption & 0x01) != 0))-		{-			if (continuity != ((stream->ts_streamcont[curstream] + 1) & 0xF))-			{-				hb_log("hb_ts_stream_decode - Bad continuity code in packet");-				stream->ts_skipbad[curstream] = 1;-				continue;-			}-			stream->ts_streamcont[curstream] = continuity;-		}--		// Get adaption header size 		if (adaption == 0) 		{-			hb_log("hb_ts_stream_decode - Bad adaption code (code was 0)!");-			for (i=0; i < stream->ts_number_video_pids + stream->ts_number_audio_pids; i++)-			{-				stream->ts_skipbad[i] = 1;-			}+			ts_err( stream, curstream,  "adaptation code 0"); 			continue; 		} 		else if (adaption == 0x2)@@ -2069,161 +1778,136 @@ 			adapt_len = buf[4] + 1; 			if (adapt_len > 184) 			{-				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;-				}+				ts_err( stream, curstream,  "invalid adapt len %d", adapt_len);+                continue; 			} 		} -		// 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 (start && curstream >= stream->ts_number_video_pids &&-            stream->ts_audio_stream_type[curstream - stream->ts_number_video_pids]-              != 0x03)+        // if there's an adaptation header & PCR_flag is set+        // get the PCR (Program Clock Reference)+        if ( adapt_len > 7 && ( buf[5] & 0x10 ) != 0 )+        {+            pcr = ( (uint64_t)buf[6] << (33 - 8) ) |+                  ( (uint64_t)buf[7] << (33 - 16) ) |+                  ( (uint64_t)buf[8] << (33 - 24) ) |+                  ( (uint64_t)buf[9] << (33 - 32) ) |+                  ( buf[10] >> 7 );+            stream->ts_nextpcr = pcr;++            // remember the pcr across calls to this routine+            stream->ts_lastpcr = pcr;+        }+		+		if ( pcr == -1 ) 		{-			// Is there an AC3 packet start 0b77 code in this packet??-			int sync_found = 0;-			unsigned char *p = buf + 4 + adapt_len;-			while (p <= buf + 186)-			{-				if (p[0] == 0x0b && p[1] == 0x77)-				{-					sync_found = 1;-					break;-				}-				p++;-			}+            // don't accumulate data until we get a pcr+		    continue;+		} -			// Couldn't find an AC3 sync start in this packet.. don't make a PES packet!-			if (!sync_found)+		// Get continuity+        // Continuity only increments for adaption values of 0x3 or 0x01+        // and is not checked for start packets.++		int start = (buf[1] & 0x40) != 0;++        if ( (adaption & 0x01) != 0 )+		{+            int continuity = (buf[3] & 0xF);+            if ( continuity == stream->ts_streamcont[curstream] )+            {+                // we got a duplicate packet (usually used to introduce+                // a PCR when one is needed). The only thing that can+                // change in the dup is the PCR which we grabbed above+                // so ignore the rest.+                continue;+            }+            if ( !start && (stream->ts_streamcont[curstream] != -1) && +                 (continuity != ( (stream->ts_streamcont[curstream] + 1) & 0xf ) ) ) 			{-				adapt_len = 184;-				start = 0;+				ts_err( stream, curstream,  "continuity error: got %d expected %d",+                        (int)continuity,+                        (stream->ts_streamcont[curstream] + 1) & 0xf );+                stream->ts_streamcont[curstream] = continuity;+				continue; 			}+			stream->ts_streamcont[curstream] = continuity; 		} -		// Found a random access point (now we can start a frame/audio packet..)-		if (start)-		{-			// Check to see if this is an i_frame (group of picture start)-			if (pid == stream->ts_video_pids[0])-			{-				// Look for the Group of Pictures packet.. indicates this is an I-Frame packet..-				doing_iframe = 0;-				unsigned int strid = 0;-				int i = 4;-				for (i = 4 + adapt_len; i < 188; i++)-				{-					strid = (strid << 8) | buf[i];-					if (strid == 0x000001B8) // group_start_code-					{-						// found a Group of Pictures header, subsequent picture must be an I-frame-						doing_iframe = 1;-					}-					else if (strid == 0x000001B3) // sequence_header code-					{-						doing_iframe = 1;-					}-					else if (strid == 0x00000100) // picture_start_code-					{-						// picture_header, let's see if it's an I-frame-						if (i<187)-						{-							// check if picture_coding_type == 1-							if ((buf[i+2] & (0x7 << 3)) == (1 << 3))-							{-								// found an I-frame picture-								doing_iframe = 1;-							}-						}-					}+        /* If we get here the packet is valid - process its data */ -					if (doing_iframe)-					{-						if (!stream->ts_foundfirst[curstream])-						{-							stream->ts_foundfirst[curstream] = 1;-//							first_video_PCR = PCR;-						}-						break;-					}-				}-			}-			else if (index_of_audio_pid(pid, stream) >= 0)-			{-			    if (stream->ts_foundfirst[0])  // Set audio found first ONLY after first video frame found. There's an assumption here that stream '0' is a video stream-				{-					stream->ts_foundfirst[curstream] |= 1;-				}-			}+        if ( start )+        {+            // Found a random access point (now we can start a frame/audio packet..)  			// If we were skipping a bad packet, start fresh on this new PES packet.. 			if (stream->ts_skipbad[curstream] == 1) 			{+                // video skips to an iframe after a bad packet to minimize+                // screen corruption+                if ( curstream == 0 && !isIframe( buf, adapt_len ) )+                {+                    continue;+                } 				stream->ts_skipbad[curstream] = 0;-				stream->ts_packetpos[curstream] = 0; 			} -			// Get the continuity code of this packet-			stream->ts_streamcont[curstream] = continuity;-		}--		// Write a 2048 byte program stream packet..-		if (start && stream->ts_packetpos[curstream] > 0 && stream->ts_foundfirst[curstream] && !stream->ts_skipbad[curstream])-		{-			// Save the substream id block so we can added it to subsequent blocks-			int write_ac3 = 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.-                if (stream->ts_audio_stream_type[curstream - stream->ts_number_video_pids] == 0x03)-				{-					hb_ts_handle_mpeg_audio(stream, curstream, buf, adapt_len);-				}-				else-				{-                    write_ac3 = hb_ts_handle_ac3_audio(stream, curstream, buf, adapt_len);-				}+			// If we don't have video yet, check to see if this is an +            // i_frame (group of picture start)+			if ( curstream == 0 )+            {+                if ( !stream->ts_foundfirst[0] )+                {+                    if ( !isIframe( buf, adapt_len ) )+                    {+                        // didn't find an I frame+                        continue;+                    }+                    stream->ts_foundfirst[0] = 1;+                }+                ++stream->frames;+            }+			else if ( ! stream->ts_foundfirst[curstream] )+            {+                // start other streams only after first video frame found.+                if ( ! stream->ts_foundfirst[0] )+                {+                    continue;+                }+                stream->ts_foundfirst[curstream] = 1; 			} -		if (generate_output_data(stream, write_ac3, curstream, pid) != 0)-			return ;-		}+            // If we have some data already on this stream, turn it into+            // a program stream packet. Then add the payload for this+            // packet to the current pid's buffer.+            if ( stream->ts_pos[curstream] )+            {+                generate_output_data(stream, curstream);+                stream->ts_start[curstream] = 1;+                memcpy(stream->ts_buf[curstream],+                       buf + 4 + adapt_len, 184 - adapt_len);+                stream->ts_pos[curstream] = 184 - adapt_len;+                return 1;+            }+            stream->ts_start[curstream] = 1;+        }  		// Add the payload for this packet to the current buffer 		if (!stream->ts_skipbad[curstream] && stream->ts_foundfirst[curstream] &&             (184 - adapt_len) > 0) 		{-            if (stream->ts_packetpos[curstream] + 184 - adapt_len > 1024*1024)+			memcpy(stream->ts_buf[curstream] + stream->ts_pos[curstream],+                   buf + 4 + adapt_len, 184 - adapt_len);+			stream->ts_pos[curstream] += 184 - adapt_len;++            // if the next TS packet could possibly overflow our 2K output buffer+            // we need to generate a packet now. Overflow would be 184 bytes of+            // data + the 9 byte PES hdr + the 14 byte PACK hdr = 211 bytes.+            if ( stream->ts_pos[curstream] >= (HB_DVD_READ_BUFFER_SIZE - 216) )             {-                int aindx = curstream - stream->ts_number_video_pids;-                if ( aindx >= 0 && stream->ts_audio_stream_type[aindx] == 0x81)-                {-                    /* we've searched through a megabyte & didn't find an AC3-                     * sync frame so this probably isn't AC3. (DVB standard-                     * teletext uses the same code points as ATSC AC3 so we-                     * could easily have guessed wrong.) Delete this pid from-                     * the audio list so we don't waste any more time on it. */-                    hb_log("hb_ts_stream_decode: removing pid 0x%x - "-                           "it isn't an AC3 stream.", stream->ts_audio_pids[aindx]);-                    hb_stream_delete_audio_entry( stream, aindx );-                }-                else-                {-                    hb_log("hb_ts_stream_decode: pid 0x%x ts_packetbuf overflow "-                           "pos %d len = %d",-                           aindx < 0 ? stream->ts_video_pids[curstream] :-                                       stream->ts_audio_pids[aindx],-                           stream->ts_packetpos[curstream], 184 - adapt_len );-                }-                stream->ts_packetpos[curstream] = 0;-                continue;+                // we have enough data to make a PS packet+                generate_output_data(stream, curstream);+                return 1;             }-			memcpy(stream->ts_packetbuf[curstream] + stream->ts_packetpos[curstream], buf + 4 + adapt_len, 184 - adapt_len);-			stream->ts_packetpos[curstream] += 184 - adapt_len; 		} 	} }@@ -2235,22 +1919,25 @@  **********************************************************************/ static void hb_ts_stream_reset(hb_stream_t *stream) {-	int i=0;-	for (i=0; i < kNumDecodeBuffers; i++)-	{-		stream->ps_decode_buffer[i].read_pos = 0;-		stream->ps_decode_buffer[i].write_pos = 0;-		stream->ps_decode_buffer[i].len = 0;-	}+	int i;  	for (i=0; i < kMaxNumberDecodeStreams; i++) 	{+		stream->ts_pos[i] = 0;+		stream->ts_foundfirst[i] = 0;+		stream->ts_skipbad[i] = 0; 		stream->ts_streamcont[i] = -1;+		stream->ts_start[i] = 0; 	} -	stream->ps_current_write_buffer_index = 0;-	stream->ps_current_read_buffer_index = 1;+    stream->ts_lastpcr = -1;+    stream->ts_nextpcr = -1; +    stream->frames = 0;+    stream->errors = 0;+    stream->last_error_frame = -10000;+    stream->last_error_count = 0;+ 	align_to_next_packet(stream->file_handle); } Index: libhb/demuxmpeg.c===================================================================--- libhb/demuxmpeg.c	(revision 1336)+++ libhb/demuxmpeg.c	(working copy)@@ -11,10 +11,9 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es ) {     hb_buffer_t * buf_es;-    int           pos;+    int           pos = 0;+    int64_t       scr; -    pos = 0;- #define d (buf_ps->data)      /* pack_header */@@ -26,6 +25,14 @@         return 0;     }     pos += 4;                    /* pack_start_code */+    /* extract the system clock reference (scr) */+    scr = ((uint64_t)(d[pos] & 0x38) << 27) |+          ((uint64_t)(d[pos] & 0x03) << 28) |+          ((uint64_t)(d[pos+1]) << 20) |+          ((uint64_t)(d[pos+2] >> 3) << 15) |+          ((uint64_t)(d[pos+2] & 3) << 13) |+          ((uint64_t)(d[pos+3]) << 5) |+          (d[pos+4] >> 3);     pos += 9;                    /* pack_header */     pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */ @@ -112,6 +119,7 @@          buf_es->id       = id;         buf_es->start    = pts;+        buf_es->stop     = scr;         if (id == 0xE0) {             // Consume a chapter break, and apply it to the ES.             buf_es->new_chap = buf_ps->new_chap;Index: libhb/sync.c===================================================================--- libhb/sync.c	(revision 1336)+++ libhb/sync.c	(working copy)@@ -19,8 +19,14 @@ typedef struct {     hb_audio_t * audio;-    int64_t      count_frames; +    int64_t      next_start;    /* start time of next output frame */+    int64_t      next_pts;      /* start time of next input frame */+    int64_t      start_silence; /* if we're inserting silence, the time we started */+    int64_t      first_drop;    /* PTS of first 'went backwards' frame dropped */+    int          drop_count;    /* count of 'time went backwards' drops */+    int          inserting_silence;+     /* Raw */     SRC_STATE  * state;     SRC_DATA     data;@@ -39,11 +45,13 @@     /* Video */     hb_subtitle_t * subtitle;     int64_t pts_offset;-    int64_t pts_offset_old;-    int64_t next_start;-    int64_t count_frames;-    int64_t count_frames_max;-    int64_t video_sequence;+    int64_t next_start;         /* start time of next output frame */+    int64_t next_pts;           /* start time of next input frame */+    int64_t first_drop;         /* PTS of first 'went backwards' frame dropped */+    int drop_count;             /* count of 'time went backwards' drops */+    int video_sequence;+    int count_frames;+    int count_frames_max;     hb_buffer_t * cur; /* The next picture to process */      /* Audio */@@ -56,11 +64,6 @@     uint64_t st_counts[4];     uint64_t st_dates[4];     uint64_t st_first;--    /* Throttle message flags */-    int   trashing_audio;-    int   inserting_silence;-    int   way_out_of_sync; };  /***********************************************************************@@ -69,8 +72,8 @@ static void InitAudio( hb_work_object_t * w, int i ); static int  SyncVideo( hb_work_object_t * w ); static void SyncAudio( hb_work_object_t * w, int i );-static int  NeedSilence( hb_work_object_t * w, hb_audio_t * );-static void InsertSilence( hb_work_object_t * w, int i );+static int  NeedSilence( hb_work_object_t * w, hb_audio_t *, int i );+static void InsertSilence( hb_work_object_t * w, int i, int64_t d ); static void UpdateState( hb_work_object_t * w );  /***********************************************************************@@ -91,15 +94,10 @@      pv->job            = job;     pv->pts_offset     = INT64_MIN;-    pv->pts_offset_old = INT64_MIN;     pv->count_frames   = 0;      pv->discontinuity = 0; -    pv->trashing_audio = 0;-    pv->inserting_silence = 0;-    pv->way_out_of_sync = 0;-     /* Calculate how many video frames we are expecting */     duration = 0;     for( i = job->chapter_start; i <= job->chapter_end; i++ )@@ -111,7 +109,7 @@         /* 1 second safety so we're sure we won't miss anything */     pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000; -    hb_log( "sync: expecting %lld video frames", pv->count_frames_max );+    hb_log( "sync: expecting %d video frames", pv->count_frames_max );      /* Initialize libsamplerate for every audio track we have */     for( i = 0; i < hb_list_count( title->list_audio ); i++ )@@ -144,6 +142,13 @@      for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {+        if ( pv->sync_audio[i].start_silence )+        {+            hb_log( "sync: added %d ms of silence to audio %d",+                    (int)((pv->sync_audio[i].next_pts -+                              pv->sync_audio[i].start_silence) / 90), i );+        }+         if( job->acodec & HB_ACODEC_AC3 ||             job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )         {@@ -268,8 +273,6 @@     hb_work_private_t * pv = w->private_data;     hb_buffer_t * cur, * next, * sub = NULL;     hb_job_t * job = pv->job;-    int64_t pts_expected;-    int chap_break;      if( pv->done )     {@@ -282,7 +285,7 @@     {         /* All video data has been processed already, we won't get            more */-        hb_log( "sync: got %lld frames, %lld expected",+        hb_log( "sync: got %d frames, %d expected",                 pv->count_frames, pv->count_frames_max );         pv->done = 1; @@ -306,7 +309,7 @@     /* At this point we have a frame to process. Let's check         1) if we will be able to push into the fifo ahead         2) if the next frame is there already, since we need it to-           know whether we'll have to repeat the current frame or not */+           compute the duration of the current frame*/     while( !hb_fifo_is_full( job->fifo_sync ) &&            ( next = hb_fifo_see( job->fifo_raw ) ) )     {@@ -315,74 +318,60 @@         if( pv->pts_offset == INT64_MIN )         {             /* This is our first frame */-            hb_log( "sync: first pts is %lld", cur->start );-            pv->pts_offset = cur->start;+            pv->pts_offset = 0;+            if ( cur->start != 0 )+            {+                /*+                 * The first pts from a dvd should always be zero but+                 * can be non-zero with a transport or program stream since+                 * we're not guaranteed to start on an IDR frame. If we get+                 * a non-zero initial PTS extend its duration so it behaves+                 * as if it started at zero so that our audio timing will+                 * be in sync.+                 */+                hb_log( "sync: first pts is %lld", cur->start );+                cur->start = 0;+            }         }          /*-         * Track the video sequence number localy so that we can sync the audio-         * to it using the sequence number as well as the PTS.+         * since the first frame is always 0 and the upstream reader code+         * is taking care of adjusting for pts discontinuities, we just have+         * to deal with the next frame's start being in the past. This can+         * happen when the PTS is adjusted after data loss but video frame+         * reordering causes some frames with the old clock to appear after+         * the clock change. This creates frames that overlap in time which+         * looks to us like time going backward. The downstream muxing code+         * can deal with overlaps of up to a frame time but anything larger+         * we handle by dropping frames here.          */-        pv->video_sequence = cur->sequence;--        /* Check for PTS jumps over 0.5 second */-        if( next->start < cur->start - PTS_DISCONTINUITY_TOLERANCE ||-            next->start > cur->start + PTS_DISCONTINUITY_TOLERANCE )+        if ( pv->next_pts - next->start > 1000 )         {-	    hb_log( "Sync: Video PTS discontinuity %s (current buffer start=%lld, next buffer start=%lld)",-                    pv->discontinuity ? "second" : "first", cur->start, next->start );--            /*-             * Do we need to trash the subtitle, is it from the next->start period-             * or is it from our old position. If the latter then trash it.-             */-            if( pv->subtitle )+            if ( pv->first_drop == 0 )             {-                while( ( sub = hb_fifo_see( pv->subtitle->fifo_raw ) ) )-                {-                    if( ( sub->start > ( cur->start - PTS_DISCONTINUITY_TOLERANCE ) ) &&-                        ( sub->start < ( cur->start + PTS_DISCONTINUITY_TOLERANCE ) ) )-                    {-                        /*-                         * The subtitle is from our current time region which we are-                         * jumping from. So trash it as we are about to jump backwards-                         * or forwards and don't want it blocking the subtitle fifo.-                         */-                        hb_log("Trashing subtitle 0x%x due to PTS discontinuity", sub);-                        sub = hb_fifo_get( pv->subtitle->fifo_raw );-                        hb_buffer_close( &sub );-                    } else {-                        break;-                    }-                }+                pv->first_drop = next->start;             }--            /* Trash current picture */-            /* Also, make sure we don't trash a chapter break */-            chap_break = cur->new_chap;-            hb_buffer_close( &cur );-            pv->cur = cur = hb_fifo_get( job->fifo_raw );-            cur->new_chap |= chap_break; // Don't stomp existing chapter breaks--            /* Calculate new offset */-            pv->pts_offset_old = pv->pts_offset;-            if ( job->vfr )-            {-                pv->pts_offset = cur->start - pv->next_start;-            } else {-                pv->pts_offset = cur->start --                    pv->count_frames * pv->job->vrate_base / 300;-            }--            if( !pv->discontinuity )-            {-                pv->discontinuity = 1;-            }--            pv->video_sequence = cur->sequence;+            ++pv->drop_count;+            buf_tmp = hb_fifo_get( job->fifo_raw );+            hb_buffer_close( &buf_tmp );             continue;         }+        if ( pv->first_drop )+        {+            hb_log( "sync: video time went backwards %d ms, dropped %d frames "+                    "(frame %lld, expected %lld)",+                    (int)( pv->next_pts - pv->first_drop ) / 90, pv->drop_count,+                    pv->first_drop, pv->next_pts );+            pv->first_drop = 0;+            pv->drop_count = 0;+        } +        /*+         * Track the video sequence number localy so that we can sync the audio+         * to it using the sequence number as well as the PTS.+         */+        pv->video_sequence = cur->sequence;+         /* Look for a subtitle for this frame */         if( pv->subtitle )         {@@ -418,23 +407,6 @@                      */                     break;                 }-                else-                {-                    /*-                     * The stop time is in the past. But is it due to-                     * it having been played already, or has the PTS-                     * been reset to 0?-                     */-                    if( ( cur->start - sub->stop ) > PTS_DISCONTINUITY_TOLERANCE ) {-                        /*-                         * There is a lot of time between our current-                         * video and where this subtitle is ending,-                         * assume that we are about to reset the PTS-                         * and do not throw away this subtitle.-                         */-                        break;-                    }-                }                  /*                  * The subtitle is older than this picture, trash it@@ -533,73 +505,27 @@             }         } -        if ( job->vfr )-        {-            /*-             * adjust the pts of the current frame so that it's contiguous-             * with the previous frame. pts_offset tracks the time difference-             * between the pts values in the input content (which start at some-             * random time) and our timestamps (which start at zero). We don't-             * make any adjustments to the source timestamps other than removing-             * the clock offsets (which also removes pts discontinuities).-             * This means we automatically encode at the source's frame rate.-             * MP2 uses an implicit duration (frames end when the next frame-             * starts) but more advanced containers like MP4 use an explicit-             * duration. Since we're looking ahead one frame we set the-             * explicit stop time from the start time of the next frame.-             */-            buf_tmp = cur;-            pv->cur = cur = hb_fifo_get( job->fifo_raw );-            buf_tmp->start = pv->next_start;-            pv->next_start = next->start - pv->pts_offset;-            buf_tmp->stop = pv->next_start;-        }-        else-        {-            /* The PTS of the frame we are expecting now */-            pts_expected = pv->pts_offset +-                pv->count_frames * pv->job->vrate_base / 300;+        /*+         * Adjust the pts of the current frame so that it's contiguous+         * with the previous frame. The start time of the current frame+         * has to be the end time of the previous frame and the stop+         * time has to be the start of the next frame.  We don't+         * make any adjustments to the source timestamps other than removing+         * the clock offsets (which also removes pts discontinuities).+         * This means we automatically encode at the source's frame rate.+         * MP2 uses an implicit duration (frames end when the next frame+         * starts) but more advanced containers like MP4 use an explicit+         * duration. Since we're looking ahead one frame we set the+         * explicit stop time from the start time of the next frame.+         */+        buf_tmp = cur;+        pv->cur = cur = hb_fifo_get( job->fifo_raw );+        pv->next_pts = next->start;+        int64_t duration = next->start - buf_tmp->start;+        buf_tmp->start = pv->next_start;+        pv->next_start += duration;+        buf_tmp->stop = pv->next_start; -            //hb_log("Video expecting PTS %lld, current frame: %lld, next frame: %lld, cf: %lld",-            //       pts_expected, cur->start, next->start, pv->count_frames * pv->job->vrate_base / 300 );--            if( cur->start < pts_expected - pv->job->vrate_base / 300 / 2 &&-                next->start < pts_expected + pv->job->vrate_base / 300 / 2 )-            {-                /* The current frame is too old but the next one matches,-                   let's trash */-                /* Also, make sure we don't trash a chapter break */-                chap_break = cur->new_chap;-                hb_buffer_close( &cur );-                pv->cur = cur = hb_fifo_get( job->fifo_raw );-                cur->new_chap |= chap_break; // Make sure we don't stomp the existing one.--                continue;-            }--            if( next->start > pts_expected + 3 * pv->job->vrate_base / 300 / 2 )-            {-                /* We'll need the current frame more than one time. Make a-                   copy of it and keep it */-                buf_tmp = hb_buffer_init( cur->size );-                memcpy( buf_tmp->data, cur->data, cur->size );-                buf_tmp->sequence = cur->sequence;-            }-            else-            {-                /* The frame has the expected date and won't have to be-                   duplicated, just put it through */-                buf_tmp = cur;-                pv->cur = cur = hb_fifo_get( job->fifo_raw );-            }--            /* Replace those MPEG-2 dates with our dates */-            buf_tmp->start = (uint64_t) pv->count_frames *-                pv->job->vrate_base / 300;-            buf_tmp->stop  = (uint64_t) ( pv->count_frames + 1 ) *-                pv->job->vrate_base / 300;-        }-         /* If we have a subtitle for this picture, copy it */         /* FIXME: we should avoid this memcpy */         if( sub )@@ -621,7 +547,7 @@         /* Make sure we won't get more frames then expected */         if( pv->count_frames >= pv->count_frames_max * 2)         {-            hb_log( "sync: got too many frames (%lld), exiting early", pv->count_frames );+            hb_log( "sync: got too many frames (%d), exiting early", pv->count_frames );             pv->done = 1;             // Drop an empty buffer into our output to ensure that things@@ -636,6 +562,68 @@     return HB_WORK_OK; } +static void OutputAudioFrame( hb_job_t *job, hb_audio_t *audio, hb_buffer_t *buf,+                              hb_sync_audio_t *sync, hb_fifo_t *fifo, int i )+{+    int64_t start = sync->next_start;+    int64_t duration = buf->stop - buf->start;+    if (duration <= 0 || +        duration > ( 90000 * AC3_SAMPLES_PER_FRAME ) / audio->rate )+    {+        hb_log("sync: audio %d weird duration %lld, start %lld, stop %lld, next %lld",+               i, duration, buf->start, buf->stop, sync->next_pts);+        if ( duration <= 0 )+        {+            duration = ( 90000 * AC3_SAMPLES_PER_FRAME ) / audio->rate;+            buf->stop = buf->start + duration;+        }+    }+    sync->next_pts += duration;++    if( /* audio->rate == job->arate || This should work but doesn't */+        job->acodec & HB_ACODEC_AC3 ||+        job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+    {+        /*+         * If we don't have to do sample rate conversion or this audio is AC3+         * pass-thru just send the input buffer downstream after adjusting+         * its timestamps to make the output stream continuous.+         */+    }+    else+    {+        /* Not pass-thru - do sample rate conversion */+        int count_in, count_out;+        hb_buffer_t * buf_raw = buf;+        int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) *+                            sizeof( float );++        count_in  = buf_raw->size / channel_count;+        count_out = ( buf_raw->stop - buf_raw->start ) * job->arate / 90000;++        sync->data.input_frames = count_in;+        sync->data.output_frames = count_out;+        sync->data.src_ratio = (double)count_out / (double)count_in;++        buf = hb_buffer_init( count_out * channel_count );+        sync->data.data_in  = (float *) buf_raw->data;+        sync->data.data_out = (float *) buf->data;+        if( src_process( sync->state, &sync->data ) )+        {+            /* XXX If this happens, we're screwed */+            hb_log( "sync: audio %d src_process failed", i );+        }+        hb_buffer_close( &buf_raw );++        buf->size = sync->data.output_frames_gen * channel_count;+    }+    buf->start = start;+    buf->stop  = start + duration;+    buf->frametype = HB_FRAME_AUDIO;+    sync->next_start = start + duration;+    hb_fifo_push( fifo, buf );+}+ /***********************************************************************  * SyncAudio  ***********************************************************************@@ -644,21 +632,13 @@ static void SyncAudio( hb_work_object_t * w, int i ) {     hb_work_private_t * pv = w->private_data;-    hb_job_t        * job;-    hb_audio_t      * audio;+    hb_job_t        * job = pv->job;+    hb_sync_audio_t * sync = &pv->sync_audio[i];+    hb_audio_t      * audio = sync->audio;     hb_buffer_t     * buf;-    hb_sync_audio_t * sync;-     hb_fifo_t       * fifo;     int               rate; -    int64_t           pts_expected;-    int64_t           start;--    job    = pv->job;-    sync   = &pv->sync_audio[i];-    audio  = sync->audio;-     if( job->acodec & HB_ACODEC_AC3 ||         job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )     {@@ -671,230 +651,90 @@         rate = job->arate;     } -    while( !hb_fifo_is_full( fifo ) &&-           ( buf = hb_fifo_see( audio->fifo_raw ) ) )+    while( !hb_fifo_is_full( fifo ) && ( buf = hb_fifo_see( audio->fifo_raw ) ) )     {-        /* The PTS of the samples we are expecting now */-        pts_expected = pv->pts_offset + sync->count_frames * 90000 / rate;--        // hb_log("Video Sequence: %lld, Audio Sequence: %lld", pv->video_sequence, buf->sequence);--        /*-         * Using the same logic as the Video have we crossed a VOB-         * boundary as detected by the expected PTS and the PTS of our-         * audio being out by more than the tolerance value.-         */-        if( buf->start > pts_expected + PTS_DISCONTINUITY_TOLERANCE ||-            buf->start < pts_expected - PTS_DISCONTINUITY_TOLERANCE )+        if ( sync->next_pts - buf->start > 500 )         {-            /* There has been a PTS discontinuity, and this frame might-               be from before the discontinuity*/--            if( pv->discontinuity )-            {-                /*-                 * There is an outstanding discontinuity, so use the offset from-                 * that discontinuity.-                 */-                pts_expected = pv->pts_offset_old + sync->count_frames *-                    90000 / rate;-            }-            else-            {-                /*-                 * No outstanding discontinuity, so the audio must be leading the-                 * video (or the PTS values are really stuffed). So lets mark this-                 * as a discontinuity ourselves for the audio to use until-                 * the video also crosses the discontinuity.-                 *-                 * pts_offset is used when we are in the same time space as the video-                 * pts_offset_old when in a discontinuity.-                 *-                 * Therefore set the pts_offset_old given the new pts_offset for this-                 * current buffer.-                 */-                pv->discontinuity = 1;-                pv->pts_offset_old = buf->start - sync->count_frames *-                    90000 / rate;-                pts_expected = pv->pts_offset_old + sync->count_frames *-                    90000 / rate;--                hb_log("Sync: Audio discontinuity (sequence: vid %lld aud %lld) (pts %lld < %lld < %lld)",-                       pv->video_sequence, buf->sequence,-                       pts_expected - PTS_DISCONTINUITY_TOLERANCE, buf->start,-                       pts_expected + PTS_DISCONTINUITY_TOLERANCE );-            }-             /*-             * Is the audio from a valid period given the previous-             * Video PTS. I.e. has there just been a video PTS-             * discontinuity and this audio belongs to the vdeo from-             * before?+             * audio time went backwards by more than a frame time (this can+             * happen when we reset the PTS because of lost data).+             * Discard data that's in the past.              */-            if( buf->start > pts_expected + PTS_DISCONTINUITY_TOLERANCE ||-                buf->start < pts_expected - PTS_DISCONTINUITY_TOLERANCE )+            if ( sync->first_drop == 0 )             {-                /*-                 * It's outside of our tolerance for where the video-                 * is now, and it's outside of the tolerance for-                 * where we have been in the case of a VOB change.-                 * Try and reconverge regardless. so continue on to-                 * our convergence code below which will kick in as-                 * it will be more than 100ms out.-                 *-                 * Note that trashing the Audio could make things-                 * worse if the Audio is in front because we will end-                 * up diverging even more. We need to hold on to the-                 * audio until the video catches up.-                 */-                if( !pv->way_out_of_sync )-                {-                    hb_log("Sync: Audio is way out of sync, attempt to reconverge from current video PTS");-                    pv->way_out_of_sync = 1;-                }--                /*-                 * It wasn't from the old place, so we must be from-                 * the new, but just too far out. So attempt to-                 * reconverge by resetting the point we want to be to-                 * where we are currently wanting to be.-                 */-		pts_expected = pv->pts_offset + sync->count_frames * 90000 / rate;-                start = pts_expected - pv->pts_offset;-	    } else {-                 /* Use the older offset */-                start = pts_expected - pv->pts_offset_old;-	    }-        }-        else-        {-            start = pts_expected - pv->pts_offset;--            if( pv->discontinuity )-            {-                /*-                 * The Audio is tracking the Video again using the normal pts_offset, so the-                 * discontinuity is over.-                 */-                hb_log( "Sync: Audio joined Video after discontinuity at PTS %lld", buf->start );-                pv->discontinuity = 0;+                sync->first_drop = buf->start;             }-        }--        /* Tolerance: 100 ms */-        if( buf->start < pts_expected - 9000 )-        {-            if( !pv->trashing_audio )-            {-                /* Audio is behind the Video, trash it, can't use it now. */-                hb_log( "Sync: Audio PTS (%lld) < Video PTS (%lld) by greater than 100ms, trashing audio to reconverge",-                        buf->start, pts_expected);-                pv->trashing_audio = 1;-            }+            ++sync->drop_count;             buf = hb_fifo_get( audio->fifo_raw );             hb_buffer_close( &buf );             continue;         }-        else if( buf->start > pts_expected + 9000 )+        if ( sync->first_drop )         {-            /* Audio is ahead of the Video, insert silence until we catch up*/-            if( !pv->inserting_silence )-            {-                hb_log("Sync: Audio PTS (%lld) >  Video PTS (%lld) by greater than 100ms insert silence until reconverged", buf->start, pts_expected);-                pv->inserting_silence = 1;-            }-            InsertSilence( w, i );-            continue;+            hb_log( "sync: audio %d time went backwards %d ms, dropped %d frames "+                    "(frame %lld, expected %lld)", i,+                    (int)( sync->next_pts - sync->first_drop ) / 90,+                    sync->drop_count, sync->first_drop, sync->next_pts );+            sync->first_drop = 0;+            sync->drop_count = 0;         }-        else++        if ( sync->inserting_silence && buf->start - sync->next_pts > 0 )         {-            if( pv->trashing_audio || pv->inserting_silence )+            /*+             * if we're within one frame time of the amount of silence+             * we need, insert just what we need otherwise insert a frame time.+             */+            int64_t framedur = buf->stop - buf->start;+            if ( buf->start - sync->next_pts <= framedur )             {-                hb_log( "Sync: Audio back in Sync at PTS %lld", buf->start );-                pv->trashing_audio = 0;-                pv->inserting_silence = 0;+                InsertSilence( w, i, buf->start - sync->next_pts );+                sync->inserting_silence = 0;             }-            if( pv->way_out_of_sync )+            else             {-                hb_log( "Sync: Audio no longer way out of sync at PTS %lld",-                        buf->start );-                pv->way_out_of_sync = 0;+                InsertSilence( w, i, framedur );             }+            continue;         }--        if( job->acodec & HB_ACODEC_AC3 ||-            job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+        if ( buf->start - sync->next_pts >= (90 * 100) )         {-            buf        = hb_fifo_get( audio->fifo_raw );-            buf->start = start;-            buf->stop  = start + 90000 * AC3_SAMPLES_PER_FRAME / rate;--            sync->count_frames += AC3_SAMPLES_PER_FRAME;-        }-        else-        {-            hb_buffer_t * buf_raw = hb_fifo_get( audio->fifo_raw );--            int count_in, count_out;--            count_in  = buf_raw->size / HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) / sizeof( float );-            count_out = ( buf_raw->stop - buf_raw->start ) * job->arate / 90000;-            if( buf->start < pts_expected - 1500 )-                count_out--;-            else if( buf->start > pts_expected + 1500 )-                count_out++;--            sync->data.data_in      = (float *) buf_raw->data;-            sync->data.input_frames = count_in;-            sync->data.output_frames = count_out;--            sync->data.src_ratio = (double) sync->data.output_frames /-                                   (double) sync->data.input_frames;--            buf = hb_buffer_init( sync->data.output_frames * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) *-                                  sizeof( float ) );-            sync->data.data_out = (float *) buf->data;-            if( src_process( sync->state, &sync->data ) )+            /*+             * there's a gap of at least 100ms between the last+             * frame we processed & the next. Fill it with silence.+             */+            if ( ! sync->inserting_silence )             {-                /* XXX If this happens, we're screwed */-                hb_log( "sync: src_process failed" );+                hb_log( "sync: adding %d ms of silence to audio %d"+                        "  start %lld, next %lld",+                        (int)((buf->start - sync->next_pts) / 90),+                        i, buf->start, sync->next_pts );+                sync->inserting_silence = 1;             }-            hb_buffer_close( &buf_raw );--            buf->size = sync->data.output_frames_gen * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) * sizeof( float );--            /* Set dates for resampled data */-            buf->start = start;-            buf->stop  = start + sync->data.output_frames_gen *-                            90000 / job->arate;--            sync->count_frames += sync->data.output_frames_gen;+            InsertSilence( w, i, buf->stop - buf->start );+            continue;         } -        buf->frametype = HB_FRAME_AUDIO;-        hb_fifo_push( fifo, buf );-    }--    if( hb_fifo_is_full( fifo ) &&-        pv->way_out_of_sync )-    {         /*-         * Trash the top audio packet to avoid dead lock as we reconverge.+         * When we get here we've taken care of all the dups and gaps in the+         * audio stream and are ready to inject the next input frame into+         * the output stream.          */-        if ( (buf = hb_fifo_get( audio->fifo_raw ) ) != NULL)-            hb_buffer_close( &buf );+        buf = hb_fifo_get( audio->fifo_raw );+        OutputAudioFrame( job, audio, buf, sync, fifo, i );     } -    if( NeedSilence( w, audio ) )+    if( NeedSilence( w, audio, i ) )     {-        InsertSilence( w, i );+        InsertSilence( w, i, (90000 * AC3_SAMPLES_PER_FRAME) / sync->audio->rate );     } } -static int NeedSilence( hb_work_object_t * w, hb_audio_t * audio )+static int NeedSilence( hb_work_object_t * w, hb_audio_t * audio, int i ) {     hb_work_private_t * pv = w->private_data;     hb_job_t * job = pv->job;+    hb_sync_audio_t * sync = &pv->sync_audio[i];      if( hb_fifo_size( audio->fifo_in ) ||         hb_fifo_size( audio->fifo_raw ) ||@@ -911,7 +751,11 @@     {         /* We might miss some audio to complete encoding and muxing            the video track */-	hb_log("Reader has exited early, inserting silence.");+        if ( sync->start_silence == 0 )+        {+            hb_log("sync: reader has exited, adding silence to audio %d", i);+            sync->start_silence = sync->next_pts;+        }         return 1;     } @@ -921,51 +765,47 @@         hb_fifo_is_full( job->fifo_render ) &&         hb_fifo_is_full( job->fifo_mpeg4 ) )     {-        /* Too much video and no audio, oh-oh */-	hb_log("Still got some video - and nothing in the audio fifo, insert silence");+        if ( sync->start_silence == 0 )+        {+            /* Too much video and no audio, oh-oh */+            hb_log("sync: have video but no audio, adding silence to audio %d", i);+            sync->start_silence = sync->next_pts;+        }         return 1;     } +    if ( sync->start_silence )+    {+        hb_log( "sync: added %d ms of silence to audio %d",+                (int)((sync->next_pts - sync->start_silence) / 90), i );+        sync->start_silence = 0;+    }     return 0; } -static void InsertSilence( hb_work_object_t * w, int i )+static void InsertSilence( hb_work_object_t * w, int i, int64_t duration ) {     hb_work_private_t * pv = w->private_data;-    hb_job_t        * job;-    hb_sync_audio_t * sync;-    hb_buffer_t     * buf;+    hb_job_t        *job = pv->job;+    hb_sync_audio_t *sync = &pv->sync_audio[i];+    hb_buffer_t     *buf; -    job    = pv->job;-    sync   = &pv->sync_audio[i];--    if( job->acodec & HB_ACODEC_AC3 ||-        job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+    if( job->acodec & HB_ACODEC_AC3 || job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )     {         buf        = hb_buffer_init( sync->ac3_size );-        buf->start = sync->count_frames * 90000 / sync->audio->rate;-        buf->stop  = buf->start + 90000 * AC3_SAMPLES_PER_FRAME /-                     sync->audio->rate;+        buf->start = sync->next_pts;+        buf->stop  = buf->start + duration;         memcpy( buf->data, sync->ac3_buf, buf->size );--        hb_log( "sync: adding a silent AC-3 frame for track %x",-                sync->audio->id );-        hb_fifo_push( sync->audio->fifo_out, buf );--        sync->count_frames += AC3_SAMPLES_PER_FRAME;-+        OutputAudioFrame( job, sync->audio, buf, sync, sync->audio->fifo_out, i );     }     else     {-        buf        = hb_buffer_init( HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown) * job->arate / 20 *-                                     sizeof( float ) );-        buf->start = sync->count_frames * 90000 / job->arate;-        buf->stop  = buf->start + 90000 / 20;+        buf = hb_buffer_init( duration * sizeof( float ) *+                    HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown) );+        buf->start = sync->next_pts;+        buf->stop  = buf->start + duration;         memset( buf->data, 0, buf->size );--        hb_fifo_push( sync->audio->fifo_sync, buf );--        sync->count_frames += job->arate / 20;+        OutputAudioFrame( job, sync->audio, buf, sync, sync->audio->fifo_sync, i );     } }