/*******************************************************}

{                                                       }

{       File: demuxer.h                                 }

{       Created by Tsviatko Jongov                      }

{       http://tsviatko.jongov.com                      }

{                                                       }

{       CMpeg2Demux class.                              }

{                                                       }

{*******************************************************/

 

#ifndef __DEMUXER_H__

#define __DEMUXER_H__

 

#include "buffer.h"

#include "output.h"

#include "transport_packet_class.h"

 

#define INPUT_BUFFER_SIZE 1024 * 1024

 

class CMpeg2TSDemux {

private:

    char m_FileName[MAX_PATH];

 

    CBuffer * m_Buffer;

    unsigned long m_PacketLen;

   

    //Output

    COutput * m_output[256];

    int m_output_cnt;

    unsigned int m_output_ids[256];

 

    Ctransport_packet_class * transport_packet_class;

 

    int Process()

    {

        unsigned int Len; 

        int Res;

        unsigned char * P; 

       

        Len = m_Buffer->Len();

        P = m_Buffer->Head();

   

        while (Len >= m_PacketLen)

        {

            if ((P[0] == 0x47) && (((P[m_PacketLen]) == 0x47)))

            {              

                if (transport_packet_class->SetData((void *)P, m_PacketLen))

                {  

                    if (transport_packet_class->m_transport_packet.adaptation_field_control & 0x01 == 0x00)

                    {

                        Len -= m_PacketLen;

                        P += m_PacketLen;

                        continue;

                    }

   

                    if ( (transport_packet_class->m_transport_packet.payload_unit_start_indicator) && (    (*(DWORD *)(&P[transport_packet_class->m_PayloadOffset]) & 0x00FFFFFF) == 0x00010000 ) )

                    {  

                        //Parse PES header here.

                        unsigned long PES_header_data_length = *(unsigned char *)(&P[transport_packet_class->m_PayloadOffset] + 8);     

                        transport_packet_class->m_PayloadOffset += 9 + PES_header_data_length;

                    }

   

                    Res = ReceiveData(transport_packet_class->m_transport_packet.PID, (unsigned char * )(P + transport_packet_class->m_PayloadOffset), 188 - transport_packet_class->m_PayloadOffset);

                    if (Res)

                    {

                        printf("tsv: Error in CMpeg2TSDemux::Process - error processing the file.\n"); 

                        return Res;

                    }

   

                    Len -= m_PacketLen;

                    P += m_PacketLen;

                }

                else

                {

                    printf("tsv: Error in CMpeg2TSDemux::Process - cannot process TS packet.\n");

                    Len--;

                    P++;

                }

            }

            else

            {

                printf("tsv: Warning in CMpeg2TSDemux::Process - corrupted TS stream.\n");

                Len--;

                P++;

            }

        }

   

        m_Buffer->m_First += (m_Buffer->Len() - Len);

        m_Buffer->Compact();

   

        return 0;

    }

   

    int ReceiveData(unsigned int StreamID, unsigned char * Data, unsigned int Size)

    {

        int idx = get_output_index(StreamID);

        if (idx < 0)

        {

            m_output[m_output_cnt] = new COutput();

            m_output[m_output_cnt]->Initialize(StreamID, m_FileName);

            m_output_ids[m_output_cnt] = StreamID;

            idx = m_output_cnt;

            m_output_cnt++;

        }

   

        return m_output[idx]->WriteData(Data, Size);

    }

   

    int get_output_index(int StreamID)

    {

        for (int i = 0; i < m_output_cnt; i++)

        {

            if (m_output_ids[i] == StreamID)

            {

                return i;

            }

        }

   

        return -1;

    }

   

    void free_output()

    {

        for (int i = 0; i < m_output_cnt; i++)

        {

            if (m_output[i])

                delete m_output[i];

        }

    }

   

public:

    CMpeg2TSDemux():

      m_output_cnt(0)

    {

        m_Buffer = new CBuffer(INPUT_BUFFER_SIZE);

        if (!m_Buffer)

        {

            printf("tsv: Error in CMpeg2TSDemux::CMpeg2TSDemux - can not create CBuffer.\n"); 

        }

   

        transport_packet_class = new Ctransport_packet_class();

    }

   

    ~CMpeg2TSDemux()

    {

        delete transport_packet_class;

        delete m_Buffer;

    }

   

    int DemultiplexFile(char * FileName)

    {   

        int res;

   

        if (!IsTS(FileName, &m_PacketLen))

        {

            printf("tsv: Error in CMpeg2TSDemux::DemultiplexFile - not valid transport stream.\n"); 

            return (-1);

        }

   

        strcpy(m_FileName, FileName);

       

        unsigned int read;

        FILE * SourceFile;

        SourceFile = fopen(m_FileName, "rb");

   

        for(;;)

        {

            (size_t)read = fread(m_Buffer->Tail(), sizeof(char), m_Buffer->Size() - m_Buffer->Len(), SourceFile);

            if (read <= 0)

            {

                break;

            }

   

            m_Buffer->m_Last += read;

   

            res = Process();

            if (res)

            {

                fclose(SourceFile);

                return res;

            }

        }

   

        free_output();

   

        fclose(SourceFile);

   

        return 0;

    }

};

   

#endif // __DEMUXER_H__