#include <string.h>
#include "demux.h"

Demux::Demux()
:NullFilter(FORMAT_MASK_PES)
{
  reset();
}

void 
Demux::process()
{
  out_rawdata = rawdata;
  out_size    = 0;

  while (size)
  {
    if (ps.payload_size)
    {
      size_t len = MIN(size, ps.payload_size);

      
      if (!ps.is_audio())
      {
        ps.payload_size -= len;
        rawdata += len;
        size    -= len;
        continue;
      }

      
      if ((stream && stream != ps.stream) ||
          (stream && substream && substream != ps.substream))
        break;

      
      stream     = ps.stream;
      substream  = ps.substream;

      
      
      
      
      
      
      
      out_spk = ps.spk();
      if (out_spk.sample_rate == 0)
        out_spk.sample_rate = spk.sample_rate;

      
      memmove(out_rawdata + out_size, rawdata, len);
      ps.payload_size -= len;
      out_size    += len;
      rawdata     += len;
      size        -= len;
    }
    else
    {
      
      uint8_t *end = rawdata + size;
      ps.parse(&rawdata, end);
      size = end - rawdata;
    }
  }
}

void 
Demux::reset()
{
  NullFilter::reset();

  stream    = 0;
  substream = 0;

  out_spk  = spk_unknown;
  out_size = 0;

  ps.reset();
}

bool
Demux::is_ofdd() const
{
  return true;
}

bool 
Demux::process(const Chunk *_chunk)
{
  
  if (_chunk->is_dummy())
    return true;

  FILTER_SAFE(receive_chunk(_chunk));

  process();

  if (flushing && !stream)
    
    flushing = false;

  return true;
}

Speakers 
Demux::get_output() const
{
  return out_spk;
}

bool
Demux::is_empty() const
{
  return !size && !out_size && !flushing;
}

bool
Demux::get_chunk(Chunk *_chunk)
{
  _chunk->set_rawdata
  (
    out_spk, 
    out_rawdata, out_size, 
    sync, time
  );

  
  if ((stream && stream != ps.stream) ||
      (stream && substream && substream != ps.substream))
  {
    _chunk->eos = true;

    
    stream = 0;
    substream = 0;

    
    
    
    
    
    
    
    out_spk = ps.spk();
    if (out_spk.sample_rate == 0)
      out_spk.sample_rate = spk.sample_rate;
  }

  
  if (!size && flushing)
  {
    _chunk->eos = true;
    flushing = false;

    
    reset();
  }

  sync = false;
  process();
  return true;
}
