~ubuntu-branches/debian/jessie/tsdecrypt/jessie

« back to all changes in this revision

Viewing changes to libtsfuncs/eit.c

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2012-04-04 09:42:43 UTC
  • Revision ID: package-import@ubuntu.com-20120404094243-qsc40h18oolnxw5r
Tags: upstream-7.0
ImportĀ upstreamĀ versionĀ 7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * EIT table parser and generator
 
3
 * Copyright (C) 2010-2011 Unix Solutions Ltd.
 
4
 *
 
5
 * Released under MIT license.
 
6
 * See LICENSE-MIT.txt for license terms.
 
7
 */
 
8
#include <stdio.h>
 
9
#include <unistd.h>
 
10
#include <netdb.h>
 
11
#include <stdlib.h>
 
12
#include <string.h>
 
13
 
 
14
#include "tsfuncs.h"
 
15
 
 
16
struct ts_eit *ts_eit_alloc() {
 
17
        struct ts_eit *eit = calloc(1, sizeof(struct ts_eit));
 
18
        eit->section_header = ts_section_data_alloc();
 
19
        eit->streams_max = 128;
 
20
        eit->streams = calloc(eit->streams_max, sizeof(void *));
 
21
        return eit;
 
22
}
 
23
 
 
24
static void ts_eit_streams_data_free(struct ts_eit *eit) {
 
25
        int i;
 
26
        for (i=0;i<eit->streams_num;i++) {
 
27
                if (eit->streams[i]) {
 
28
                        FREE(eit->streams[i]->descriptor_data);
 
29
                        FREE(eit->streams[i]);
 
30
                }
 
31
        }
 
32
}
 
33
 
 
34
void ts_eit_clear(struct ts_eit *eit) {
 
35
        if (!eit)
 
36
                return;
 
37
        // save
 
38
        struct ts_section_header *section_header = eit->section_header;
 
39
        struct ts_eit_stream **streams = eit->streams;
 
40
        int streams_max = eit->streams_max;
 
41
        // free
 
42
        ts_eit_streams_data_free(eit);
 
43
        // clear
 
44
        ts_section_data_clear(section_header);
 
45
        memset(eit, 0, sizeof(struct ts_eit));
 
46
        // restore
 
47
        eit->section_header = section_header;
 
48
        eit->streams = streams;
 
49
        eit->streams_max = streams_max;
 
50
}
 
51
 
 
52
void ts_eit_free(struct ts_eit **peit) {
 
53
        struct ts_eit *eit = *peit;
 
54
        if (eit) {
 
55
                ts_section_data_free(&eit->section_header);
 
56
                ts_eit_streams_data_free(eit);
 
57
                FREE(eit->streams);
 
58
                FREE(*peit);
 
59
        }
 
60
}
 
61
 
 
62
struct ts_eit *ts_eit_push_packet(struct ts_eit *eit, uint8_t *ts_packet) {
 
63
        struct ts_header ts_header;
 
64
        memset(&ts_header, 0, sizeof(struct ts_header));
 
65
 
 
66
        if (ts_packet_header_parse(ts_packet, &ts_header)) {
 
67
                // EIT should be with PID 0x12
 
68
                if (ts_header.pid != 0x12)
 
69
                        goto OUT;
 
70
                // Received PUSI packet before table END, clear the table to start gathering new one
 
71
                if (ts_header.pusi && eit->ts_header.pusi)
 
72
                        ts_eit_clear(eit);
 
73
                if (!eit->ts_header.pusi)
 
74
                        eit->ts_header = ts_header;
 
75
        }
 
76
 
 
77
        if (ts_header.pusi) {
 
78
                struct ts_section_header section_header;
 
79
                memset(&section_header, 0, sizeof(struct ts_section_header));
 
80
 
 
81
                uint8_t *section_data = ts_section_header_parse(ts_packet, &eit->ts_header, &section_header);
 
82
                if (!section_data) {
 
83
                        memset(&eit->ts_header, 0, sizeof(struct ts_header));
 
84
                        goto OUT;
 
85
                }
 
86
                // table_id should be 0x4e (event_information_section - actual_transport_stream, present/following)
 
87
                // table_id 0x50 - 0x5f    (event_information_section - actual_transport_stream, schedule)
 
88
                if (section_header.table_id != 0x4e && (section_header.table_id < 0x50 && section_header.table_id > 0x5f)) {
 
89
                        memset(&eit->ts_header, 0, sizeof(struct ts_header));
 
90
                        goto OUT;
 
91
                }
 
92
 
 
93
                // Set correct section_header
 
94
                ts_section_header_parse(ts_packet, &eit->ts_header, eit->section_header);
 
95
        }
 
96
 
 
97
        if (!eit->initialized) {
 
98
                ts_section_add_packet(eit->section_header, &ts_header, ts_packet);
 
99
                if (eit->section_header->initialized) {
 
100
                        if (!ts_eit_parse(eit))
 
101
                                goto ERROR;
 
102
                }
 
103
        }
 
104
 
 
105
OUT:
 
106
        return eit;
 
107
 
 
108
ERROR:
 
109
        ts_eit_clear(eit);
 
110
        return eit;
 
111
}
 
112
 
 
113
 
 
114
int ts_eit_parse(struct ts_eit *eit) {
 
115
        uint8_t *section_data = eit->section_header->data;
 
116
        int section_len = eit->section_header->data_len;
 
117
 
 
118
        /* Table data (6 bytes) */
 
119
        eit->transport_stream_id                        = (section_data[0] << 8) | section_data[1];     // 11111111 11111111
 
120
        eit->original_network_id                        = (section_data[2] << 8) | section_data[3];     // 11111111 11111111
 
121
        eit->segment_last_section_number        = section_data[4];
 
122
        eit->last_table_id                                      = section_data[5];
 
123
 
 
124
        uint8_t *stream_data = section_data + 6;                // +5 is to compensate for the above
 
125
        int stream_len       = section_len - 6 - 4;             // -4 for the CRC at the end
 
126
 
 
127
        while (stream_len > 0) {
 
128
                if (eit->streams_num == eit->streams_max) {
 
129
                        ts_LOGf("!!! Too many streams in EIT, max %d\n", eit->streams_max);
 
130
                        break;
 
131
                }
 
132
 
 
133
                struct ts_eit_stream *sinfo = calloc(1, sizeof(struct ts_eit_stream));
 
134
 
 
135
                sinfo->event_id                  = (stream_data[0] << 8) | stream_data[1];
 
136
                sinfo->start_time_mjd    = (stream_data[2] << 8) | stream_data[3];
 
137
 
 
138
                sinfo->start_time_bcd    = stream_data[4] << 16;
 
139
                sinfo->start_time_bcd   |= stream_data[5] << 8;
 
140
                sinfo->start_time_bcd   |= stream_data[6];
 
141
 
 
142
                sinfo->duration_bcd              = stream_data[7] << 16;
 
143
                sinfo->duration_bcd             |= stream_data[8] << 8;
 
144
                sinfo->duration_bcd             |= stream_data[9];
 
145
 
 
146
                sinfo->running_status    = stream_data[10] >> 5;                                                                // 111xxxxx
 
147
                sinfo->free_CA_mode              = (stream_data[10] &~ 0xE0) >> 4;                                              // xxx1xxxx
 
148
                sinfo->descriptor_size   = ((stream_data[10] &~ 0xF0) << 8) | stream_data[11];  // 1111xxxx xxxxxxxx
 
149
 
 
150
                stream_data += 12; // Compensate for the the above vars
 
151
                stream_len  -= 12 + sinfo->descriptor_size;
 
152
 
 
153
                sinfo->descriptor_data = NULL;
 
154
                if (sinfo->descriptor_size > 0) {
 
155
                        sinfo->descriptor_data = malloc(sinfo->descriptor_size);
 
156
                        memcpy(sinfo->descriptor_data, stream_data, sinfo->descriptor_size);
 
157
                }
 
158
                eit->streams[eit->streams_num] = sinfo;
 
159
                eit->streams_num++;
 
160
 
 
161
                stream_data += sinfo->descriptor_size;
 
162
        }
 
163
 
 
164
        if (!ts_crc32_section_check(eit->section_header, "EIT"))
 
165
                return 0;
 
166
 
 
167
        eit->initialized = 1;
 
168
        return 1;
 
169
}
 
170
 
 
171
void ts_eit_generate(struct ts_eit *eit, uint8_t **ts_packets, int *num_packets) {
 
172
        uint8_t *secdata = ts_section_data_alloc_section();
 
173
        ts_section_header_generate(secdata, eit->section_header, 0);
 
174
        int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
 
175
 
 
176
 
 
177
        secdata[curpos + 0] = eit->transport_stream_id >> 8;                    // xxxxxxxx xxxxxxxx
 
178
        secdata[curpos + 1] = eit->transport_stream_id &~ 0xff00;
 
179
 
 
180
        secdata[curpos + 2] = eit->original_network_id >> 8;                    // xxxxxxxx xxxxxxxx
 
181
        secdata[curpos + 3] = eit->original_network_id &~ 0xff00;
 
182
 
 
183
        secdata[curpos + 4] = eit->segment_last_section_number;
 
184
        secdata[curpos + 5] = eit->last_table_id;
 
185
        curpos += 6; // For the fields above
 
186
 
 
187
        int i;
 
188
        for(i=0;i<eit->streams_num;i++) {
 
189
                struct ts_eit_stream *stream = eit->streams[i];
 
190
                secdata[curpos + 0]  = stream->event_id >> 8;                   // xxxxxxxx xxxxxxxx
 
191
                secdata[curpos + 1]  = stream->event_id &~ 0xff00;
 
192
 
 
193
                secdata[curpos + 2]  = stream->start_time_mjd >> 8;             // xxxxxxxx xxxxxxxx
 
194
                secdata[curpos + 3]  = stream->start_time_mjd &~ 0xff00;
 
195
 
 
196
                secdata[curpos + 4]  = stream->start_time_bcd >> 16;
 
197
                secdata[curpos + 5]  =(stream->start_time_bcd >> 8) &~ 0xff00;
 
198
                secdata[curpos + 6]  = stream->start_time_bcd &~ 0xffff00;
 
199
 
 
200
                secdata[curpos + 7]  = stream->duration_bcd >> 16;
 
201
                secdata[curpos + 8]  =(stream->duration_bcd >> 8) &~ 0xff00;
 
202
                secdata[curpos + 9]  = stream->duration_bcd &~ 0xffff00;
 
203
 
 
204
                secdata[curpos +10]  = stream->running_status << 5;             // 111xxxxx
 
205
                secdata[curpos +10] |= stream->free_CA_mode   << 4;             // xxx1xxxx
 
206
                secdata[curpos +10] |= stream->descriptor_size >> 8;            // 1111xxxx xxxxxxxx
 
207
                secdata[curpos +11]  = stream->descriptor_size &~ 0xff00;
 
208
                curpos += 12; // Compensate for the above
 
209
 
 
210
                if (stream->descriptor_size > 0) {
 
211
                        memcpy(secdata + curpos, stream->descriptor_data, stream->descriptor_size);
 
212
                        curpos += stream->descriptor_size;
 
213
                }
 
214
        }
 
215
        eit->section_header->CRC = ts_section_data_calculate_crc(secdata, curpos);
 
216
        curpos += 4; // CRC
 
217
 
 
218
        ts_section_data_gen_ts_packets(&eit->ts_header, secdata, curpos, eit->section_header->pointer_field, ts_packets, num_packets);
 
219
 
 
220
        FREE(secdata);
 
221
}
 
222
 
 
223
void ts_eit_check_generator(struct ts_eit *eit) {
 
224
        struct ts_eit *eit1 = ts_eit_alloc();
 
225
        int i;
 
226
        for (i=0;i<eit->section_header->num_packets;i++) {
 
227
                eit1 = ts_eit_push_packet(eit1, eit->section_header->packet_data + (i * TS_PACKET_SIZE));
 
228
        }
 
229
        ts_compare_data("EIT (tspacket->struct)",
 
230
                eit1->section_header->packet_data,
 
231
                eit->section_header->packet_data,
 
232
                eit->section_header->num_packets * TS_PACKET_SIZE);
 
233
        ts_eit_free(&eit1);
 
234
 
 
235
        uint8_t *ts_packets;
 
236
        int num_packets;
 
237
        ts_eit_generate(eit, &ts_packets, &num_packets);
 
238
        if (num_packets != eit->section_header->num_packets) {
 
239
                ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, eit->section_header->num_packets);
 
240
        }
 
241
        ts_compare_data("EIT (struct->tspacket)", eit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
 
242
        free(ts_packets);
 
243
}
 
244
 
 
245
void ts_eit_regenerate_packets(struct ts_eit *eit) {
 
246
        uint8_t *ts_packets;
 
247
        int num_packets;
 
248
        ts_eit_generate(eit, &ts_packets, &num_packets);
 
249
        FREE(eit->section_header->packet_data);
 
250
        eit->section_header->packet_data = ts_packets;
 
251
        eit->section_header->num_packets = num_packets;
 
252
}
 
253
 
 
254
struct ts_eit *ts_eit_copy(struct ts_eit *eit) {
 
255
        struct ts_eit *neweit = ts_eit_alloc();
 
256
        int i;
 
257
        for (i=0;i<eit->section_header->num_packets; i++) {
 
258
                neweit = ts_eit_push_packet(neweit, eit->section_header->packet_data + (i * TS_PACKET_SIZE));
 
259
        }
 
260
        if (neweit->initialized) {
 
261
                return neweit;
 
262
        } else {
 
263
                ts_LOGf("Error copying EIT!\n");
 
264
                ts_eit_free(&neweit);
 
265
                return NULL;
 
266
        }
 
267
}
 
268
 
 
269
void ts_eit_dump(struct ts_eit *eit) {
 
270
        struct ts_section_header *sect = eit->section_header;
 
271
        int i;
 
272
 
 
273
        ts_section_dump(sect);
 
274
 
 
275
        ts_LOGf("  * EIT data\n");
 
276
        ts_LOGf("    * PID             : 0x%04x (%d)\n", eit->ts_header.pid, eit->ts_header.pid);
 
277
        ts_LOGf("    * ts_stream_id    : 0x%04x (%d)\n", eit->transport_stream_id, eit->transport_stream_id);
 
278
        ts_LOGf("    * org_network_id  : 0x%04x (%d)\n", eit->original_network_id, eit->original_network_id);
 
279
        ts_LOGf("    * seg_last_sec_num: %d\n", eit->segment_last_section_number);
 
280
        ts_LOGf("    * last_table_id   : 0x%02x (%d)\n", eit->last_table_id, eit->last_table_id);
 
281
        ts_LOGf("    * num_streams     : %d\n", eit->streams_num);
 
282
 
 
283
        for(i=0;i<eit->streams_num;i++) {
 
284
                struct ts_eit_stream *stream = eit->streams[i];
 
285
                int hour, min, sec;
 
286
                struct tm tm;
 
287
                ts_time_decode_mjd(stream->start_time_mjd, stream->start_time_bcd, &tm);
 
288
                ts_time_decode_bcd(stream->duration_bcd, NULL, &hour, &min, &sec);
 
289
                ts_LOGf("    * Event_id [%02d/%02d]\n", i+1, eit->streams_num);
 
290
                ts_LOGf("      - Event_id  : 0x%04x (%d)\n", stream->event_id, stream->event_id);
 
291
                ts_LOGf("      - Start_time: %04d-%02d-%02d %02d:%02d:%02d (0x%04x%06x) ts: %ld\n",
 
292
                        tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
 
293
                        stream->start_time_mjd,
 
294
                        stream->start_time_bcd, timegm(&tm));
 
295
                ts_LOGf("      - Duration  : %02d:%02d:%02d (0x%06x)\n",
 
296
                        hour, min, sec,
 
297
                        stream->duration_bcd);
 
298
                ts_LOGf("      - Running_status: %d free_CA_mode: %d /desc_size: %d/\n",
 
299
                        stream->running_status,
 
300
                        stream->free_CA_mode,
 
301
                        stream->descriptor_size);
 
302
 
 
303
                if (stream->descriptor_data) {
 
304
                        ts_descriptor_dump(stream->descriptor_data, stream->descriptor_size);
 
305
                }
 
306
        }
 
307
 
 
308
        ts_eit_check_generator(eit);
 
309
}
 
310
 
 
311
int ts_eit_is_same(struct ts_eit *eit1, struct ts_eit *eit2) {
 
312
        if (eit1 == eit2) return 1; // Same
 
313
        if ((!eit1 && eit2) || (eit1 && !eit2)) return 0; // Not same (one is NULL)
 
314
        return ts_section_is_same(eit1->section_header, eit2->section_header);
 
315
}