--- /dev/null
+/**
+ * @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
--- /dev/null
+/**\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