OSDN Git Service

EPG解析再考中...
authorosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Thu, 31 Mar 2016 14:54:29 +0000 (23:54 +0900)
committerosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Thu, 31 Mar 2016 14:54:29 +0000 (23:54 +0900)
src/mpeg2/ts/Demultiplexer.cpp [new file with mode: 0644]
src/mpeg2/ts/Demultiplexer.h [new file with mode: 0644]
src/ry0/iPTd/Analyzer.cpp [new file with mode: 0644]
src/ry0/iPTd/Analyzer.h [new file with mode: 0644]

diff --git a/src/mpeg2/ts/Demultiplexer.cpp b/src/mpeg2/ts/Demultiplexer.cpp
new file mode 100644 (file)
index 0000000..995df77
--- /dev/null
@@ -0,0 +1,204 @@
+/**
+ * @file Demultiplexer.cpp
+ *
+ */
+
+#include "mpeg2/ts/Demultiplexer.h"
+
+namespace MPEG2
+{
+namespace TS
+{
+
+Demultiplexer::Demultiplexer()
+{
+    MPEG2_MUTEX_INIT;
+
+    _flag = 0;
+
+    _continuity_counter_sdt  = 0xFF;
+    _continuity_counter_0012 = 0xFF;
+    _continuity_counter_0026 = 0xFF;
+    _continuity_counter_0027 = 0xFF;
+}
+
+Demultiplexer::~Demultiplexer()
+{
+    MPEG2_MUTEX_DESTROY;
+}
+
+void Demultiplexer::setListener(Listener *listener)
+{
+    MPEG2_LOCK;
+    _listener = listener;
+    MPEG2_UNLOCK;
+}
+
+void Demultiplexer::setFlag(uint32_t flag, bool onoff)
+{
+    MPEG2_LOCK;
+    if (onoff)
+    {
+        _flag |= flag;
+    }
+    else
+    {
+        _flag &= ~flag;
+    }
+    MPEG2_UNLOCK;
+}
+
+void Demultiplexer::putSDT(Header *header, uint8_t *packet)
+{
+    if (_continuity_counter_sdt != 0xFF)
+    {
+        if (((_continuity_counter_sdt + 1) & 0x0F) != header->_continuity_counter)
+        {
+            printf("packet loss\n");
+            _sdt.reset();
+            ((Table *)&_sdt)->reset();
+        }
+        _continuity_counter_sdt = header->_continuity_counter;
+    }
+    if (_sdt.decode(header, packet))
+    {
+        if ((_listener) && ((_flag & FLG_SDT) == FLG_SDT))
+        {
+            _listener->detect(&_sdt);
+        }
+        _sdt.reset();
+    }
+}
+
+void Demultiplexer::putEIT(Header *header, uint8_t *packet)
+{
+    switch (header->_pid)
+    {
+    case PID_EIT_0012:
+        if (_continuity_counter_0012 != 0xFF)
+        {
+            if (((_continuity_counter_0012 + 1) & 0x0F) != header->_continuity_counter)
+            {
+                printf("packet loss\n");
+                _eit_0012.reset();
+                ((Table *)&_eit_0012)->reset();
+            }
+        }
+        _continuity_counter_0012 = header->_continuity_counter;
+        break;
+
+    case PID_EIT_0026:
+        if (_continuity_counter_0026 != 0xFF)
+        {
+            if (((_continuity_counter_0026 + 1) & 0x0F) != header->_continuity_counter)
+            {
+                printf("packet loss\n");
+                _eit_0026.reset();
+                ((Table *)&_eit_0026)->reset();
+            }
+        }
+        _continuity_counter_0026 = header->_continuity_counter;
+        break;
+
+    case PID_EIT_0027:
+        if (_continuity_counter_0027 != 0xFF)
+        {
+            if (((_continuity_counter_0027 + 1) & 0x0F) != header->_continuity_counter)
+            {
+                printf("packet loss\n");
+                _eit_0027.reset();
+                ((Table *)&_eit_0027)->reset();
+            }
+        }
+        _continuity_counter_0027 = header->_continuity_counter;
+        break;
+    }
+
+    switch (header->_pid)
+    {
+    case PID_EIT_0012:
+        if (_eit_0012.decode(header, packet))
+        {
+            if ((_listener) && ((_flag & FLG_EIT) == FLG_EIT))
+            {
+                _listener->detect(&_eit_0012);
+            }
+            _eit_0012.reset();
+        }
+        break;
+    case PID_EIT_0026:
+        if (_eit_0026.decode(header, packet))
+        {
+            if ((_listener) && ((_flag & FLG_EIT) == FLG_EIT))
+            {
+                _listener->detect(&_eit_0026);
+            }
+            _eit_0026.reset();
+        }
+        break;
+    case PID_EIT_0027:
+        if (_eit_0027.decode(header, packet))
+        {
+            if ((_listener) && ((_flag & FLG_EIT) == FLG_EIT))
+            {
+                _listener->detect(&_eit_0027);
+            }
+            _eit_0027.reset();
+        }
+        break;
+    }
+}
+
+void Demultiplexer::put(uint8_t *buffer, uint32_t size)
+{
+    uint32_t offset = 0;
+    while (offset < size)
+    {
+        if (buffer[offset] != SYNC_BYTE)
+        {
+            break;
+        }
+
+        MPEG2_LOCK;
+
+        Header header(&buffer[offset]);
+        if (!header._transport_error)
+        {
+            switch (header._pid)
+            {
+            case PID_PAT:
+                break;
+
+            case PID_CAT:
+                break;
+
+            case PID_NIT:
+                break;
+
+            case PID_SDT_BAT:
+                putSDT(&header, &buffer[offset]);
+                break;
+
+            case PID_EIT_0012:
+            case PID_EIT_0026:
+            case PID_EIT_0027:
+                putEIT(&header, &buffer[offset]);
+                break;
+
+            case PID_RST:
+                break;
+
+            case PID_TDT:
+                break;
+            }
+        }
+
+        MPEG2_UNLOCK;
+
+        offset += PACKET_SIZE;
+    }
+}
+
+
+} // TS
+} // MPEG2
diff --git a/src/mpeg2/ts/Demultiplexer.h b/src/mpeg2/ts/Demultiplexer.h
new file mode 100644 (file)
index 0000000..c10e484
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+ * @file Demultiplexer.h
+ *
+ */
+
+#pragma once
+
+#include "mpeg2/ts/Header.h"
+#include "mpeg2/ts/PAT.h"
+#include "mpeg2/ts/PMT.h"
+#include "mpeg2/ts/SDT.h"
+#include "mpeg2/ts/EIT.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#define MPEG2_MUTEX                 CRITICAL_SECTION
+#define MPEG2_MUTEX_INIT            InitializeCriticalSection(&_lock)
+#define MPEG2_MUTEX_DESTROY         DeleteCriticalSection(&_lock)
+#define MPEG2_LOCK                  DeleteCriticalSection(&_lock)
+#define MPEG2_UNLOCK                LeaveCriticalSection(&_lock)
+#else
+#include <pthread.h>
+#define MPEG2_MUTEX                 pthread_mutex_t
+#define MPEG2_MUTEX_INIT            pthread_mutex_init(&_lock, NULL)
+#define MPEG2_MUTEX_DESTROY         pthread_mutex_destroy(&_lock)
+#define MPEG2_LOCK                  pthread_mutex_lock(&_lock)
+#define MPEG2_UNLOCK                pthread_mutex_unlock(&_lock)
+#endif
+
+namespace MPEG2
+{
+namespace TS
+{
+
+class Demultiplexer
+{
+public:
+    enum
+    {
+        FLG_PAT     = 0x00000001,
+        FLG_SDT     = 0x00000002,
+        FLG_EIT     = 0x00000004,
+    };
+    class Listener
+    {
+    public:
+        virtual void detect(SDT *sdt) = 0;
+        virtual void detect(EIT *eit) = 0;
+    };
+
+private:
+    MPEG2_MUTEX     _lock;
+    uint32_t        _flag;
+    Listener *      _listener;
+
+    uint8_t _continuity_counter_sdt;
+    SDT     _sdt;
+
+    uint8_t _continuity_counter_0012;
+    EIT     _eit_0012;
+
+    uint8_t _continuity_counter_0026;
+    EIT     _eit_0026;
+
+    uint8_t _continuity_counter_0027;
+    EIT     _eit_0027;
+
+    void putSDT(Header *header, uint8_t *packet);
+    void putEIT(Header *header, uint8_t *packet);
+
+
+public:
+    Demultiplexer();
+    ~Demultiplexer();
+
+    void setListener(Listener *listener);
+    void setFlag(uint32_t flag, bool onoff);
+
+    void put(uint8_t *buffer, uint32_t size);
+};
+
+} // TS
+} // MPEG2
diff --git a/src/ry0/iPTd/Analyzer.cpp b/src/ry0/iPTd/Analyzer.cpp
new file mode 100644 (file)
index 0000000..2310be9
--- /dev/null
@@ -0,0 +1,442 @@
+/**\r
+ * @file Analyzer.cpp\r
+ *\r
+ */\r
+\r
+#include <time.h>\r
+\r
+#include "Raym/Raym.h"\r
+#include "b25/aribstr.h"\r
+#include "ry0/iPTd/Analyzer.h"\r
+\r
+using namespace Raym;\r
+\r
+namespace ry0\r
+{\r
+namespace iPTd\r
+{\r
+\r
+Analyzer::Analyzer()\r
+{\r
+    _sdt = NULL;\r
+    _eit = NULL;\r
+    _demux.setListener(this);\r
+}\r
+\r
+Analyzer::~Analyzer()\r
+{\r
+    if (_sdt != NULL)\r
+    {\r
+        delete _sdt;\r
+    }\r
+}\r
+\r
+Analyzer *Analyzer::alloc()\r
+{\r
+    return new Analyzer();\r
+}\r
+\r
+Analyzer *Analyzer::init()\r
+{\r
+    return this;\r
+}\r
+\r
+Dictionary *Analyzer::stationInfo()\r
+{\r
+    Dictionary *result = NULL;\r
+\r
+    _demux.setFlag(MPEG2::TS::Demultiplexer::FLG_SDT, true);\r
+\r
+    RaymLock(this);\r
+\r
+    uint8_t count = 0;\r
+    while ((result == NULL) && (count++ < 32))\r
+    {\r
+        while (_sdt == NULL)\r
+        {\r
+            RaymCondWait(this);\r
+        }\r
+\r
+        if (_sdt->_table_id == 0x42)\r
+        {\r
+            result = Dictionary::dictionaryWithCapacity(0);\r
+            Array *services = Array::arrayWithCapacity(0);\r
+            result->setObject(services, KEY_SERVICES);\r
+            for (uint32_t i = 0; i < _sdt->_service_count; ++i)\r
+            {\r
+                Dictionary *service = Dictionary::dictionaryWithCapacity(0);\r
+                services->addObject(service);\r
+                char tmp[32];\r
+                sprintf_s(tmp, "%d", _sdt->_services[i]._service_id);\r
+                service->setString(tmp, KEY_SERVICE_ID);\r
+                sprintf_s(tmp, "%d", _sdt->_services[i]._desc->service_type);\r
+                service->setString(tmp, KEY_SERVICE_TYPE);\r
+                if (_sdt->_services[i]._desc->service_name_length > 0)\r
+                {\r
+                    String *name = String::stringWithCString(_sdt->_services[i]._desc->service_name, ShiftJISStringEncoding);\r
+                    service->setString(name, KEY_NAME);\r
+                    if (i == 0)\r
+                    {\r
+                        result->setString(name, KEY_NAME);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        delete _sdt;\r
+        _sdt = NULL;\r
+    }\r
+\r
+    RaymUnlock(this);\r
+\r
+    _demux.setFlag(MPEG2::TS::Demultiplexer::FLG_SDT, false);\r
+\r
+    return result;\r
+}\r
+\r
+static Array *eit2epgs(MPEG2::TS::EIT *eit)\r
+{\r
+    Array *result = Array::arrayWithCapacity(0);\r
+\r
+printf("    | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");\r
+printf("----+------------------------------------------------\n");\r
+for (int ii = 0; ii < eit->_section_length - 0x0e; ++ii)\r
+{\r
+    if (ii % 16 == 0)\r
+    {\r
+        printf("%04x: ", ii);\r
+    }\r
+    printf("%02x ", eit->_event_data[ii]);\r
+    if (ii % 16 == 15)\r
+    {\r
+        printf("\n");\r
+    }\r
+}\r
+printf("\n");\r
+    while (true)\r
+    {\r
+        MPEG2::TS::EIT::Event *event = eit->nextEvent();\r
+        if (event == NULL)\r
+        {\r
+        DebugLog0("event is null\n");\r
+            break;\r
+        }\r
+\r
+        DebugLog0("eit -> epg: start\n");\r
+\r
+        Dictionary *epg = Dictionary::dictionaryWithCapacity(0);\r
+\r
+        char tmp[32];\r
+#ifdef _WIN32\r
+        sprintf_s(tmp, "%d", eit->_service_id);\r
+#else\r
+        sprintf(tmp, "%d", eit->_service_id);\r
+#endif\r
+        epg->setString(tmp, KEY_EPG_SERVICE_ID);\r
+\r
+#ifdef _WIN32\r
+        sprintf_s(tmp, "%d", event->_event_id);\r
+#else\r
+        sprintf(tmp, "%d", event->_event_id);\r
+#endif\r
+        epg->setString(tmp, KEY_EPG_EVENT_ID);\r
+\r
+        char date[16];\r
+#ifdef _WIN32\r
+        sprintf_s(date, sizeof(date), "%02d/%02d/%02d", event->_st_year, event->_st_month, event->_st_day);\r
+#else\r
+        sprintf(date, "%02d/%02d/%02d", event->_st_year, event->_st_month, event->_st_day);\r
+#endif\r
+        epg->setString(date, KEY_EPG_DATE);\r
+\r
+        char start[16];\r
+#ifdef _WIN32\r
+        sprintf_s(start, sizeof(start), "%02d:%02d:%02d", event->_st_hour, event->_st_min, event->_st_sec);\r
+#else\r
+        sprintf(start, "%02d:%02d:%02d", event->_st_hour, event->_st_min, event->_st_sec);\r
+#endif\r
+        epg->setString(start, KEY_EPG_START);\r
+\r
+        int hour = event->_st_hour + event->_dur_hour;\r
+        int min = event->_st_min + event->_dur_min;\r
+        int sec = event->_st_sec + event->_dur_sec;\r
+        if (sec >= 60)\r
+        {\r
+            min += 1;\r
+            sec -= 60;\r
+        }\r
+        if (min >= 60)\r
+        {\r
+            hour += 1;\r
+            min -= 60;\r
+        }\r
+        char end[16];\r
+#ifdef _WIN32\r
+        sprintf_s(end, sizeof(end), "%02d:%02d:%02d", hour, min, sec);\r
+#else\r
+        sprintf(end, "%02d:%02d:%02d", hour, min, sec);\r
+#endif\r
+        epg->setString(end, KEY_EPG_END);\r
+\r
+        Data *data = Data::dataWithCapacity(0);\r
+\r
+        DebugLog0("eit -> epg: check 000\n");\r
+        while (true)\r
+        {\r
+            MPEG2::TS::Descriptor *desc = event->nextDescriptor();\r
+            if (desc == NULL)\r
+            {\r
+        DebugLog0("eit -> epg: check 001\n");\r
+                break;\r
+            }\r
+        DebugLog0("eit -> epg: check 002\n");\r
+\r
+            switch (desc->descriptor_tag)\r
+            {\r
+            case MPEG2::TS::TAG_BOUQUET_NAME_DESCRIPTOR:\r
+                DebugLog0("TAG_BOUQUET_NAME_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_SERVICE_DESCRIPTOR:\r
+                DebugLog0("TAG_SERVICE_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_SHORT_EVENT_DESCRIPTOR:\r
+                DebugLog0("TAG_SHORT_EVENT_DESCRIPTOR\n");\r
+                if (desc->short_event.event_name_length > 0)\r
+                {\r
+DebugLog0("event_name_length: %d\n", desc->short_event.event_name_length);\r
+                    char *tmp = (char *)malloc(desc->short_event.event_name_length * 2 + 1);\r
+                    if (tmp)\r
+                    {\r
+                        AribToString(tmp, (const char *)desc->short_event.event_name, desc->short_event.event_name_length);\r
+DebugLog0("event_name: %s\n", tmp);\r
+                        String *event_name = String::stringWithCString(tmp, ShiftJISStringEncoding);\r
+                        if (event_name)\r
+                        {\r
+DebugLog0("event_name: %s\n", event_name->cString());\r
+                            epg->setString(event_name, KEY_EPG_TITLE);\r
+                        }\r
+                        else\r
+                        {\r
+                            printf("stringWithCString() NG.\n");\r
+                        }\r
+\r
+                        free(tmp);\r
+                    }\r
+                    else\r
+                    {\r
+                        printf("malloc NG.\n");\r
+                    }\r
+                }\r
+                else\r
+                {\r
+DebugLog0("event_name_length ng: %d\n", desc->short_event.event_name_length);\r
+                }\r
+                if (desc->short_event.text_length > 0)\r
+                {\r
+DebugLog0("text_length: %d\n", desc->short_event.text_length);\r
+                    char *tmp = (char *)malloc(desc->short_event.text_length * 2 + 1);\r
+                    if (tmp)\r
+                    {\r
+                        AribToString(tmp, (const char *)desc->short_event.text, desc->short_event.text_length);\r
+                        String *text = String::stringWithCString(tmp, ShiftJISStringEncoding);\r
+                        if (text)\r
+                        {\r
+                            epg->setString(text, KEY_EPG_DESCRIPTION);\r
+                        }\r
+                        else\r
+                        {\r
+                            printf("stringWithCString() NG.\n");\r
+                        }\r
+                        free(tmp);\r
+                    }\r
+                    else\r
+                    {\r
+                        printf("mallco NG.\n");\r
+                    }\r
+                }\r
+                else\r
+                {\r
+DebugLog0("text_length ng: %d\n", desc->short_event.text_length);\r
+                }\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_EXTENDED_EVENT_DESCRIPTOR:\r
+                printf("TAG_EXTENDED_EVENT_DESCRIPTOR\n");\r
+                for (int i = 0; i < desc->extended_event.item_count; ++i)\r
+                {\r
+\r
+                    // item_description と item を繋げてしまうと正しく読めない場合がある\r
+                    // 現状は item_description は捨てる\r
+                    // どうやって扱うか、今後の課題\r
+\r
+                    if (desc->extended_event.items[i].item_description_length > 0)\r
+                    {\r
+                        char *tmp = (char *)malloc(desc->extended_event.items[i].item_description_length * 2 + 1);\r
+                        if (tmp)\r
+                        {\r
+                            AribToString(tmp, (const char *)desc->extended_event.items[i].item_description, desc->extended_event.items[i].item_description_length);\r
+                            String *item_description = String::stringWithCString(tmp, ShiftJISStringEncoding);\r
+                            if (item_description)\r
+                            {\r
+                                DebugLog0("item_description: %s\n", item_description->cString());\r
+                            }\r
+                            free(tmp);\r
+                        }\r
+//                            data->appendBytes(desc->extended_event.items[i].item_description, \r
+//                                            desc->extended_event.items[i].item_description_length);\r
+                    }\r
+\r
+\r
+                    if (desc->extended_event.items[i].item_length > 0)\r
+                    {\r
+                        data->appendBytes(desc->extended_event.items[i].item,\r
+                                          desc->extended_event.items[i].item_length);\r
+                    }\r
+                }\r
+                if (desc->extended_event.text_length > 0)\r
+                {\r
+                    DebugLog0("TAG_EXTENDED_EVENT_DESCRIPTOR\n");\r
+                    DebugLog0("  text: %s\n", desc->extended_event.text);\r
+                    data->appendBytes(desc->extended_event.text, desc->extended_event.text_length);\r
+                }\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_CONTENT_DESCRIPTOR:\r
+                DebugLog0("TAG_CONTENT_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_SERIES_DESCRIPTOR:\r
+                DebugLog0("TAG_SERIES_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_EVENT_GROUP_DESCRIPTOR:\r
+                DebugLog0("TAG_EVENT_GROUP_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_COMPONENT_DESCRIPTOR:\r
+                DebugLog0("TAG_COMPONENT_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_DIGITAL_COPY_CONTROL_DESCRIPTOR:\r
+                DebugLog0("TAG_DIGITAL_COPY_CONTROL_DESCRIPTOR\n");\r
+                break;\r
+\r
+            case MPEG2::TS::TAG_AUDIO_COMPONENT_DESCRIPTOR:\r
+                DebugLog0("TAG_AUDIO_COMPONENT_DESCRIPTOR\n");\r
+                break;\r
+\r
+//                case MPEG2::TS::TAG_17: // 不明\r
+\r
+            default:\r
+                DebugLog0("Unknown descriptor: 0x%02X\n", desc->descriptor_tag);\r
+                break;\r
+            }\r
+        }\r
+\r
+        if (data->length())\r
+        {\r
+            char *tmp = (char *)malloc(data->length() * 2);\r
+            if (tmp)\r
+            {\r
+                AribToString(tmp, (const char *)data->bytes(), data->length());\r
+                String *desc = String::stringWithCString(tmp, ShiftJISStringEncoding);\r
+                if (desc)\r
+                {\r
+                    epg->setString(desc, KEY_EPG_DESCRIPTION);\r
+                }\r
+                free(tmp);\r
+            }\r
+        }\r
+\r
+        result->addObject(epg);\r
+\r
+        DebugLog0("eit -> epg: done\n");\r
+        DebugLog0("%s\n", epg->toString().c_str());\r
+    }\r
+\r
+\r
+    DebugLog0("eit2epg done.\n");\r
+    return result;\r
+}\r
+\r
+Array *Analyzer::collectEPGs(time_t limit)\r
+{\r
+    _demux.setFlag(MPEG2::TS::Demultiplexer::FLG_EIT, true);\r
+\r
+    std::vector<MPEG2::TS::EIT *> eits;\r
+\r
+    DebugLog0("b lock\n");\r
+    RaymLock(this);\r
+    DebugLog0("a lock\n");\r
+\r
+    time_t start = time(NULL);\r
+    while (time(NULL) < start + limit)\r
+    {\r
+        while (_eit == NULL)\r
+        {\r
+            DebugLog0("b wait\n");\r
+            RaymCondWait(this);\r
+            DebugLog0("a wait\n");\r
+        }\r
+\r
+        eits.push_back(_eit);\r
+        _eit = NULL;\r
+    }\r
+\r
+    DebugLog0("b unlock\n");\r
+    RaymUnlock(this);\r
+    DebugLog0("a unlock\n");\r
+\r
+    _demux.setFlag(MPEG2::TS::Demultiplexer::FLG_EIT, false);\r
+\r
+    Array *result = Array::arrayWithCapacity(0);\r
+\r
+    std::vector<MPEG2::TS::EIT *>::iterator it;\r
+    for (it = eits.begin(); it != eits.end(); ++it)\r
+    {\r
+        result->addObjectsFromArray(eit2epgs(*it));\r
+        delete *it;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+void Analyzer::put(uint8_t *buffer, uint32_t size)\r
+{\r
+    _demux.put(buffer, size);\r
+}\r
+\r
+void Analyzer::detect(MPEG2::TS::SDT *sdt)\r
+{\r
+    RaymLock(this);\r
+    if (_sdt != NULL)\r
+    {\r
+        delete _sdt;\r
+        _sdt = NULL;\r
+    }\r
+    _sdt = new MPEG2::TS::SDT(*sdt);\r
+    RaymCondSignal(this);\r
+    RaymUnlock(this);\r
+}\r
+\r
+void Analyzer::detect(MPEG2::TS::EIT *eit)\r
+{\r
+    DebugLog0("b lock: detect\n");\r
+    RaymLock(this);\r
+    DebugLog0("a lock: detect\n");\r
+    if (_eit != NULL)\r
+    {\r
+        delete _eit;\r
+        _eit = NULL;\r
+    }\r
+    _eit = new MPEG2::TS::EIT(*eit);\r
+    RaymCondSignal(this);\r
+    DebugLog0("b unlock: detect\n");\r
+    RaymUnlock(this);\r
+    DebugLog0("a unlock: detect\n");\r
+}\r
+\r
+} // iPTd\r
+} // ry0\r
diff --git a/src/ry0/iPTd/Analyzer.h b/src/ry0/iPTd/Analyzer.h
new file mode 100644 (file)
index 0000000..1edb2ef
--- /dev/null
@@ -0,0 +1,46 @@
+/**\r
+ * @file Analyzer.h\r
+ *\r
+ */\r
+\r
+#pragma once\r
+\r
+#include "Raym/Raym.h"\r
+#include "ry0/device/Tuner.h"\r
+#include "mpeg2/ts/Demultiplexer.h"\r
+\r
+namespace ry0\r
+{\r
+namespace iPTd\r
+{\r
+\r
+class Analyzer : public Raym::Object,\r
+                 public ry0::device::Tuner::Listener,\r
+                 public MPEG2::TS::Demultiplexer::Listener\r
+{\r
+private:\r
+    MPEG2::TS::Demultiplexer    _demux;\r
+    MPEG2::TS::SDT *            _sdt;\r
+    MPEG2::TS::EIT *            _eit;\r
+\r
+protected:\r
+    Analyzer();\r
+    ~Analyzer();\r
+\r
+public:\r
+    static Analyzer *alloc();\r
+    Analyzer *init();\r
+\r
+    Raym::Dictionary *stationInfo();\r
+    Raym::Array *collectEPGs(time_t limit);\r
+\r
+    // ry0::device::Tuner::Listener\r
+    void put(uint8_t *buffer, uint32_t size);\r
+\r
+    // MPEG2::TS::Demultiplexer::Listener\r
+    void detect(MPEG2::TS::SDT *sdt);\r
+    void detect(MPEG2::TS::EIT *eit);\r
+};\r
+\r
+} // iPTd\r
+} // ry0\r