diff --git a/modules/demux/ts.c b/modules/demux/ts.c
index 7673e79..93903c7 100644
--- a/modules/demux/ts.c
+++ b/modules/demux/ts.c
@@ -251,7 +251,7 @@ typedef struct
     int         i_data_size;
     int         i_data_gathered;
     block_t     *p_data;
-    block_t     **pp_last;
+    block_t     *p_last;
 
     es_mpeg4_descriptor_t *p_mpeg4desc;
 
@@ -362,14 +362,14 @@ static inline int PIDGet( block_t *p )
     return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
 }
 
-static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
+static bool GatherData( demux_t *p_demux, ts_pid_t *pid, uint8_t *p_buffer );
 
-static block_t* ReadTSPacket( demux_t *p_demux );
+static block_t* ReadTSPacket( demux_t *p_demux, int i_packet );
 static int Seek( demux_t *p_demux, double f_percent );
 static void GetFirstPCR( demux_t *p_demux );
 static void GetLastPCR( demux_t *p_demux );
 static void CheckPCR( demux_t *p_demux );
-static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
+static void PCRHandle( demux_t *p_demux, ts_pid_t *, const uint8_t *p );
 
 static void              IODFree( iod_descriptor_t * );
 
@@ -385,6 +385,35 @@ static void SetPrgFilter( demux_t *, int i_prg, bool b_selected );
 #define TS_PACKET_SIZE_MAX 204
 #define TS_TOPFIELD_HEADER 1320
 
+static void EsAppend( ts_es_t *p_es, const uint8_t *p_buffer, int i_buffer)
+{
+    /* append to last block ? */
+    if( p_es->p_last) {
+      if( p_es->p_last->i_size > p_es->p_last->i_buffer + i_buffer ) {
+        memcpy( p_es->p_last->p_buffer + p_es->p_last->i_buffer, p_buffer, i_buffer );
+        p_es->p_last->i_buffer += i_buffer;
+        return;
+      }
+    }
+
+    /* allocate new block */
+    int      i_alloc = p_es->i_data_size > 0 ? p_es->i_data_size : 16384;
+    block_t *p_block = block_Alloc( i_alloc );
+    if( p_block == NULL )
+        return;
+
+    memcpy( p_block->p_buffer, p_buffer, i_buffer );
+    p_block->i_buffer = i_buffer;
+
+    /* and append it to the chain */
+    if (p_es->p_last) {
+        p_es->p_last->p_next = p_block;
+    } else {
+        p_es->p_data = p_block;
+    }
+    p_es->p_last = p_block;
+}
+
 static int DetectPacketSize( demux_t *p_demux, int *pi_header_size )
 {
     const uint8_t *p_peek;
@@ -908,15 +937,17 @@ static int Demux( demux_t *p_demux )
     demux_sys_t *p_sys = p_demux->p_sys;
     bool b_wait_es = p_sys->i_pmt_es <= 0;
 
+    /* TODO: read 32 packets to stack-allocated buffer ? */
+    block_t     *p_pkt;
+    if( !(p_pkt = ReadTSPacket( p_demux, p_sys->i_ts_read )) )
+    {
+	return 0;
+    }
+
     /* We read at most 100 TS packet or until a frame is completed */
-    for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
+    while (p_pkt->i_buffer >= 188 && p_pkt->p_buffer[0] == 0x47 ) /* 188 is min. ts packet size, first HDMV header is already removed */
     {
         bool         b_frame = false;
-        block_t     *p_pkt;
-        if( !(p_pkt = ReadTSPacket( p_demux )) )
-        {
-            return 0;
-        }
 
         if( p_sys->b_start_record )
         {
@@ -944,11 +975,10 @@ static int Demux( demux_t *p_demux )
                                            p_pkt->p_buffer );
                     }
                 }
-                block_Release( p_pkt );
             }
             else
             {
-                b_frame = GatherData( p_demux, p_pid, p_pkt );
+                b_frame = GatherData( p_demux, p_pid, p_pkt->p_buffer );
             }
         }
         else
@@ -958,15 +988,24 @@ static int Demux( demux_t *p_demux )
                 msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
             }
             /* We have to handle PCR if present */
-            PCRHandle( p_demux, p_pid, p_pkt );
-            block_Release( p_pkt );
+            PCRHandle( p_demux, p_pid, p_pkt->p_buffer );
         }
         p_pid->b_seen = true;
-
+#if 0
+        // we need to handle all read packets even if frame is ready earlier
         if( b_frame || ( b_wait_es && p_sys->i_pmt_es > 0 ) )
             break;
+#endif
+        // TODO - simplify loop end condition
+	p_pkt->p_buffer += p_sys->i_packet_size;
+	if (p_pkt->i_buffer < p_sys->i_packet_size)
+          p_pkt->i_buffer = 0;
+        else
+          p_pkt->i_buffer -= p_sys->i_packet_size;
     }
 
+    block_Release( p_pkt );
+
     demux_UpdateTitleFromStream( p_demux );
     return 1;
 }
@@ -1439,7 +1478,6 @@ static void PIDInit( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner )
 
         es_format_Init( &pid->es->fmt, UNKNOWN_ES, 0 );
         pid->es->data_type = TS_ES_DATA_PES;
-        pid->es->pp_last = &pid->es->p_data;
     }
 }
 
@@ -1664,7 +1702,6 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes )
         if( p_pes->i_buffer <= i_skip )
         {
             block_t *p_next = p_pes->p_next;
-
             i_skip -= p_pes->i_buffer;
             block_Release( p_pes );
             p_pes = p_next;
@@ -1798,7 +1835,7 @@ static void ParseData( demux_t *p_demux, ts_pid_t *pid )
     pid->es->p_data = NULL;
     pid->es->i_data_size = 0;
     pid->es->i_data_gathered = 0;
-    pid->es->pp_last = &pid->es->p_data;
+    pid->es->p_last = NULL;
 
     if( pid->es->data_type == TS_ES_DATA_PES )
     {
@@ -1814,14 +1851,14 @@ static void ParseData( demux_t *p_demux, ts_pid_t *pid )
     }
 }
 
-static block_t* ReadTSPacket( demux_t *p_demux )
+static block_t* ReadTSPacket( demux_t *p_demux, int i_packet )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
 
     block_t     *p_pkt;
 
     /* Get a new TS packet */
-    if( !( p_pkt = stream_Block( p_demux->s, p_sys->i_packet_size ) ) )
+    if( !( p_pkt = stream_Block( p_demux->s, p_sys->i_packet_size * i_packet ) ) )
     {
         msg_Dbg( p_demux, "eof ?" );
         return NULL;
@@ -1899,9 +1936,9 @@ static mtime_t AdjustPCRWrapAround( demux_t *p_demux, mtime_t i_pcr )
     return i_pcr + i_adjust;
 }
 
-static mtime_t GetPCR( block_t *p_pkt )
+static mtime_t GetPCR( const uint8_t *p_buffer )
 {
-    const uint8_t *p = p_pkt->p_buffer;
+    const uint8_t *p = p_buffer;
 
     mtime_t i_pcr = -1;
 
@@ -1940,13 +1977,13 @@ static int SeekToPCR( demux_t *p_demux, int64_t i_pos )
     {
         block_t *p_pkt;
 
-        if( !( p_pkt = ReadTSPacket( p_demux ) ) )
+        if( !( p_pkt = ReadTSPacket( p_demux, 1 ) ) )
         {
             break;
         }
         if( PIDGet( p_pkt ) == p_sys->i_pid_ref_pcr )
         {
-            i_pcr = GetPCR( p_pkt );
+            i_pcr = GetPCR( p_pkt->p_buffer );
         }
         block_Release( p_pkt );
         if( i_pcr >= 0 )
@@ -2049,11 +2086,11 @@ static void GetFirstPCR( demux_t *p_demux )
     {
         block_t     *p_pkt;
 
-        if( !( p_pkt = ReadTSPacket( p_demux ) ) )
+        if( !( p_pkt = ReadTSPacket( p_demux, 1 ) ) )
         {
             break;
         }
-        mtime_t i_pcr = GetPCR( p_pkt );
+        mtime_t i_pcr = GetPCR( p_pkt->p_buffer );
         if( i_pcr >= 0 )
         {
             p_sys->i_pid_ref_pcr = PIDGet( p_pkt );
@@ -2152,14 +2189,14 @@ static void CheckPCR( demux_t *p_demux )
     p_sys->i_current_pcr = i_initial_pcr;
 }
 
-static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
+static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_buffer )
 {
     demux_sys_t   *p_sys = p_demux->p_sys;
 
     if( p_sys->i_pmt_es <= 0 )
         return;
 
-    mtime_t i_pcr = GetPCR( p_bk );
+    mtime_t i_pcr = GetPCR( p_buffer );
     if( i_pcr < 0 )
         return;
 
@@ -2179,9 +2216,9 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             }
 }
 
-static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
+static bool GatherData( demux_t *p_demux, ts_pid_t *pid, uint8_t *p_buffer )
 {
-    const uint8_t *p = p_bk->p_buffer;
+    const uint8_t *p = p_buffer;
     const bool b_unit_start = p[1]&0x40;
     const bool b_scrambled  = p[3]&0x80;
     const bool b_adaptation = p[3]&0x20;
@@ -2190,6 +2227,7 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     bool       b_discontinuity = false;  /* discontinuity */
 
     /* transport_scrambling_control is ignored */
+    int         i_buffer;
     int         i_skip = 0;
     bool        i_ret  = false;
 
@@ -2201,7 +2239,7 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 
     /* For now, ignore additional error correction
      * TODO: handle Reed-Solomon 204,188 error correction */
-    p_bk->i_buffer = TS_PACKET_SIZE_188;
+    i_buffer = TS_PACKET_SIZE_188;
 
     if( p[1]&0x80 )
     {
@@ -2214,7 +2252,7 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     if( p_demux->p_sys->csa )
     {
         vlc_mutex_lock( &p_demux->p_sys->csa_lock );
-        csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer, p_demux->p_sys->i_csa_pkt_size );
+        csa_Decrypt( p_demux->p_sys->csa, p_buffer, p_demux->p_sys->i_csa_pkt_size );
         vlc_mutex_unlock( &p_demux->p_sys->csa_lock );
     }
 
@@ -2280,11 +2318,10 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
         }
     }
 
-    PCRHandle( p_demux, pid, p_bk );
+    PCRHandle( p_demux, pid, p_buffer );
 
     if( i_skip >= 188 || pid->es->id == NULL )
     {
-        block_Release( p_bk );
         return i_ret;
     }
 
@@ -2306,23 +2343,18 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     }
 
     /* We have to gather it */
-    p_bk->p_buffer += i_skip;
-    p_bk->i_buffer -= i_skip;
+    p_buffer += i_skip;
+    i_buffer -= i_skip;
 
     if( b_unit_start )
     {
-        if( pid->es->data_type == TS_ES_DATA_TABLE_SECTION && p_bk->i_buffer > 0 )
+        if( pid->es->data_type == TS_ES_DATA_TABLE_SECTION && i_buffer > 0 )
         {
-            int i_pointer_field = __MIN( p_bk->p_buffer[0], p_bk->i_buffer - 1 );
-            block_t *p = block_Duplicate( p_bk );
-            if( p )
-            {
-                p->i_buffer = i_pointer_field;
-                p->p_buffer++;
-                block_ChainLastAppend( &pid->es->pp_last, p );
-            }
-            p_bk->i_buffer -= 1 + i_pointer_field;
-            p_bk->p_buffer += 1 + i_pointer_field;
+            // TODO - why this branch is here ?
+            int i_pointer_field = __MIN( p_buffer[0], i_buffer - 1 );
+	    EsAppend( pid->es, p_buffer + 1, i_pointer_field );
+            i_buffer -= 1 + i_pointer_field;
+            p_buffer += 1 + i_pointer_field;
         }
         if( pid->es->p_data )
         {
@@ -2330,12 +2362,11 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             i_ret = true;
         }
 
-        block_ChainLastAppend( &pid->es->pp_last, p_bk );
         if( pid->es->data_type == TS_ES_DATA_PES )
         {
-            if( p_bk->i_buffer > 6 )
+            if( i_buffer > 6 )
             {
-                pid->es->i_data_size = GetWBE( &p_bk->p_buffer[4] );
+                pid->es->i_data_size = GetWBE( &p_buffer[4] );
                 if( pid->es->i_data_size > 0 )
                 {
                     pid->es->i_data_size += 6;
@@ -2344,12 +2375,15 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
         }
         else if( pid->es->data_type == TS_ES_DATA_TABLE_SECTION )
         {
-            if( p_bk->i_buffer > 3 && p_bk->p_buffer[0] != 0xff )
+            if( i_buffer > 3 && p_buffer[0] != 0xff )
             {
-                pid->es->i_data_size = 3 + (((p_bk->p_buffer[1] & 0xf) << 8) | p_bk->p_buffer[2]);
+                pid->es->i_data_size = 3 + (((p_buffer[1] & 0xf) << 8) | p_buffer[2]);
             }
         }
-        pid->es->i_data_gathered += p_bk->i_buffer;
+
+        // TODO: simplify, duplicate code
+        EsAppend( pid->es, p_buffer, i_buffer );
+        pid->es->i_data_gathered += i_buffer;
         if( pid->es->i_data_size > 0 &&
             pid->es->i_data_gathered >= pid->es->i_data_size )
         {
@@ -2362,12 +2396,12 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
         if( pid->es->p_data == NULL )
         {
             /* msg_Dbg( p_demux, "broken packet" ); */
-            block_Release( p_bk );
         }
         else
         {
-            block_ChainLastAppend( &pid->es->pp_last, p_bk );
-            pid->es->i_data_gathered += p_bk->i_buffer;
+            // TODO: simplify, duplicate code
+            EsAppend( pid->es, p_buffer, i_buffer );
+            pid->es->i_data_gathered += i_buffer;
 
             if( pid->es->i_data_size > 0 &&
                 pid->es->i_data_gathered >= pid->es->i_data_size )
@@ -2472,6 +2506,7 @@ static int  IODDescriptorLength( int *pi_data, uint8_t **pp_data )
 
     } while( i_b&0x80 && *pi_data > 0 );
 
+    // warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     if (i_len > *pi_data)
         i_len = *pi_data;
 
@@ -3487,7 +3522,7 @@ static void PMTSetupEsTeletext( demux_t *p_demux, ts_pid_t *pid,
                 p_es->p_data  = NULL;
                 p_es->i_data_size = 0;
                 p_es->i_data_gathered = 0;
-                p_es->pp_last = &p_es->p_data;
+                p_es->p_last  = NULL;
                 p_es->data_type = TS_ES_DATA_PES;
                 p_es->p_mpeg4desc = NULL;
 
@@ -3572,7 +3607,7 @@ static void PMTSetupEsDvbSubtitle( demux_t *p_demux, ts_pid_t *pid,
                 p_es->p_data   = NULL;
                 p_es->i_data_size = 0;
                 p_es->i_data_gathered = 0;
-                p_es->pp_last = &p_es->p_data;
+                p_es->p_last = NULL;
                 p_es->data_type = TS_ES_DATA_PES;
                 p_es->p_mpeg4desc = NULL;
 
