+ block_t *p_block = block_New( p_demux, tk->i_subpacket_size );
+ if( !p_block )
+ return;
+ if( &p_buf[tk->i_subpacket_size] > &p_sys->buffer[p_sys->i_buffer] )
+ return;
+
+ memcpy( p_block->p_buffer, p_buf, tk->i_subpacket_size );
+ p_block->i_dts =
+ p_block->i_pts = 0;
+
+ p_buf += tk->i_subpacket_size;
+
+ int i_index = tk->i_subpacket_h * i +
+ ((tk->i_subpacket_h + 1) / 2) * (y&1) + (y>>1);
+
+ if( tk->p_subpackets[i_index] != NULL )
+ {
+ msg_Dbg(p_demux, "p_subpackets[ %d ] not null!", i_index );
+ block_Release( tk->p_subpackets[i_index] );
+ }
+
+ tk->p_subpackets[i_index] = p_block;
+ if( tk->i_subpacket == 0 )
+ tk->p_subpackets_timecode[0] = i_pts;
+ tk->i_subpacket++;
+ }
+ }
+ else
+ {
+ const int y = tk->i_subpacket / (tk->i_subpacket_h / 2);
+ assert( tk->fmt.i_codec == VLC_FOURCC( '2', '8', '_', '8' ) );
+
+ for( int i = 0; i < tk->i_subpacket_h / 2; i++ )
+ {
+ block_t *p_block = block_New( p_demux, tk->i_coded_frame_size);
+ if( !p_block )
+ return;
+ if( &p_buf[tk->i_coded_frame_size] > &p_sys->buffer[p_sys->i_buffer] )
+ return;
+
+ int i_index = (i * 2 * tk->i_frame_size / tk->i_coded_frame_size) + y;
+
+ memcpy( p_block->p_buffer, p_buf, tk->i_coded_frame_size );
+ p_block->i_dts =
+ p_block->i_pts = i_index == 0 ? i_pts : 0;
+
+ p_buf += tk->i_coded_frame_size;
+
+ if( tk->p_subpackets[i_index] != NULL )
+ {
+ msg_Dbg(p_demux, "p_subpackets[ %d ] not null!", i_index );
+ block_Release( tk->p_subpackets[i_index] );
+ }
+
+ tk->p_subpackets[i_index] = p_block;
+ tk->i_subpacket++;
+ }
+ }
+
+ while( tk->i_out_subpacket != tk->i_subpackets &&
+ tk->p_subpackets[tk->i_out_subpacket] )
+ {
+ block_t *p_block = tk->p_subpackets[tk->i_out_subpacket];
+ tk->p_subpackets[tk->i_out_subpacket] = NULL;
+
+ if( tk->p_subpackets_timecode[tk->i_out_subpacket] )
+ {
+ p_block->i_dts =
+ p_block->i_pts = tk->p_subpackets_timecode[tk->i_out_subpacket];
+
+ tk->p_subpackets_timecode[tk->i_out_subpacket] = 0;
+ }
+ tk->i_out_subpacket++;
+
+ CheckPcr( p_demux, tk, p_block->i_pts );
+ es_out_Send( p_demux->out, tk->p_es, p_block );
+ }
+
+ if( tk->i_subpacket == tk->i_subpackets &&
+ tk->i_out_subpacket != tk->i_subpackets )
+ {
+ msg_Warn( p_demux, "i_subpacket != i_out_subpacket, "
+ "this shouldn't happen" );
+ }
+
+ if( tk->i_subpacket == tk->i_subpackets )
+ {
+ tk->i_subpacket = 0;
+ tk->i_out_subpacket = 0;
+ }
+}
+static void DemuxAudioMethod2( demux_t *p_demux, real_track_t *tk, mtime_t i_pts )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ if( p_sys->i_buffer < 2 )
+ return;
+
+ int i_sub = (p_sys->buffer[1] >> 4)&0x0f;
+ if( p_sys->i_buffer < 2+2*i_sub )
+ return;
+
+ uint8_t *p_sub = &p_sys->buffer[2+2*i_sub];
+
+ for( int i = 0; i < i_sub; i++ )
+ {
+ const int i_sub_size = GetWBE( &p_sys->buffer[2+i*2] );
+ block_t *p_block = block_New( p_demux, i_sub_size );
+ if( !p_block )
+ break;
+
+ if( &p_sub[i_sub_size] > &p_sys->buffer[p_sys->i_buffer] )
+ break;
+
+ memcpy( p_block->p_buffer, p_sub, i_sub_size );
+ p_sub += i_sub_size;
+
+ p_block->i_dts =
+ p_block->i_pts = ( i == 0 ? i_pts : 0 );
+
+ CheckPcr( p_demux, tk, p_block->i_pts );
+ es_out_Send( p_demux->out, tk->p_es, p_block );
+ }
+}
+static void DemuxAudioMethod3( demux_t *p_demux, real_track_t *tk, mtime_t i_pts )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ if( p_sys->i_buffer <= 0 )
+ return;
+
+ block_t *p_block = block_New( p_demux, p_sys->i_buffer );
+ if( !p_block )
+ return;
+
+ if( tk->fmt.i_codec == VLC_FOURCC( 'a', '5', '2', ' ' ) )
+ {
+ uint8_t *p_src = p_sys->buffer;
+ uint8_t *p_dst = p_block->p_buffer;
+
+ /* byte swap data */
+ while( p_dst < &p_block->p_buffer[p_sys->i_buffer - 1])
+ {
+ *p_dst++ = p_src[1];
+ *p_dst++ = p_src[0];
+
+ p_src += 2;
+ }
+ }
+ else
+ {
+ memcpy( p_block->p_buffer, p_sys->buffer, p_sys->i_buffer );
+ }
+ p_block->i_dts =
+ p_block->i_pts = i_pts;
+
+ CheckPcr( p_demux, tk, p_block->i_pts );
+ es_out_Send( p_demux->out, tk->p_es, p_block );
+}
+
+static void DemuxAudio( demux_t *p_demux, real_track_t *tk, mtime_t i_pts, unsigned i_flags )
+{
+ switch( tk->fmt.i_codec )
+ {
+ case VLC_FOURCC( 'c', 'o', 'o', 'k' ):
+ case VLC_FOURCC( 'a', 't', 'r', 'c' ):
+ case VLC_FOURCC( 's', 'i', 'p', 'r' ):
+ case VLC_FOURCC( '2', '8', '_', '8' ):
+ DemuxAudioMethod1( p_demux, tk, i_pts, i_flags );
+ break;
+ case VLC_FOURCC( 'm','p','4','a' ):
+ DemuxAudioMethod2( p_demux, tk, i_pts );
+ break;
+ default:
+ DemuxAudioMethod3( p_demux, tk, i_pts );
+ break;
+ }
+}
+
+/*****************************************************************************
+ * Helpers: seek/control
+ *****************************************************************************/
+static int ControlGoToIndex( demux_t *p_demux, real_index_t *p_index )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ p_sys->b_seek = true;
+ p_sys->i_pcr = INT64_C(1000) * p_index->i_time_offset;
+ for( int i = 0; i < p_sys->i_track; i++ )
+ p_sys->track[i]->i_last_dts = 0;
+ return stream_Seek( p_demux->s, p_index->i_file_offset );
+}
+static int ControlSeekTime( demux_t *p_demux, mtime_t i_time )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ real_index_t *p_index = p_sys->p_index;
+
+ while( p_index->i_file_offset != 0 )
+ {
+ if( p_index->i_time_offset * INT64_C(1000) > i_time )
+ {
+ if( p_index != p_sys->p_index )
+ p_index--;
+ break;