blob: a17fd37afa583de61ddc357fb7d4f04636b3892c [file] [log] [blame]
Gong Kefa504d72023-04-18 10:23:35 +08001#include <stdio.h>
2#include <string.h>
3#include "ts_indexer.h"
4
5#define TS_PKT_SIZE (188)
6
7//#define TS_INDEXER_DEBUG
8#ifdef TS_INDEXER_DEBUG
9#define INF(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
10#else
11#define INF(fmt, ...)
12#endif
13
14#define ERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
15
16#define NAL_TYPE_IDR 5 // IDR NALU 类型
17#define NAL_TYPE_NON_IDR 1 // 非 IDR NALU 类型
18
Yahui Han63de7082023-07-12 18:30:10 +080019#define HEVC_NALU_BLA_W_LP 16
20#define HEVC_NALU_BLA_W_RADL 17
21#define HEVC_NALU_IDR_W_RADL 19
22#define HEVC_NALU_IDR_N_LP 20
23#define HEVC_NALU_TRAIL_CRA 21
24#define HEVC_NALU_SPS 33
25#define HEVC_NALU_AUD 35
26
Gong Kefa504d72023-04-18 10:23:35 +080027/**
28 * Initialize the TS indexer.
29 * \param ts_indexer The TS indexer to be initialized.
30 * \retval 0 On success.
31 * \retval -1 On error.
32 */
33int
34ts_indexer_init (TS_Indexer_t *ts_indexer)
35{
36 TSParser init_parser;
37
38 if (ts_indexer == NULL) {
39 return -1;
40 }
41
42 memset(&init_parser, 0, sizeof(TSParser));
43 init_parser.pid = 0x1fff;
44 init_parser.format = -1;
45 init_parser.PES.pts = -1;
46 init_parser.PES.offset = 0;
47 init_parser.PES.len = 0;
48 init_parser.PES.state = TS_INDEXER_STATE_INIT;
49
50 memcpy(&ts_indexer->video_parser, &init_parser, sizeof(TSParser));
51 memcpy(&ts_indexer->audio_parser, &init_parser, sizeof(TSParser));
52 ts_indexer->callback = NULL;
53 ts_indexer->offset = 0;
54
55 return 0;
56}
57
58/**
59 * Release the TS indexer.
60 * \param ts_indexer The TS indexer to be released.
61 */
62void
63ts_indexer_destroy (TS_Indexer_t *ts_indexer)
64{
65 return;
66}
67
68/**
69 * Set the video format.
70 * \param ts_indexer The TS indexer.
71 * \param format The stream format.
72 * \retval 0 On success.
73 * \retval -1 On error.
74 */
75int
76ts_indexer_set_video_format (TS_Indexer_t *ts_indexer, TS_Indexer_StreamFormat_t format)
77{
78 if (ts_indexer == NULL)
79 return -1;
80
81 ts_indexer->video_parser.format = format;
82
83 return 0;
84}
85
86/**
87 * Set the video PID.
88 * \param ts_indexer The TS indexer.
89 * \param pid The video PID.
90 * \retval 0 On success.
91 * \retval -1 On error.
92 */
93int
94ts_indexer_set_video_pid (TS_Indexer_t *ts_indexer, int pid)
95{
96 if (ts_indexer == NULL)
97 return -1;
98
99
100 TSParser *parser = &ts_indexer->video_parser;
101 parser->pid = pid;
102 parser->offset = 0;
103 parser->PES.pts = -1;
104 parser->PES.offset = 0;
105 parser->PES.len = 0;
106 parser->PES.state = TS_INDEXER_STATE_INIT;
107
108 return 0;
109}
110
111/**
112 * Set the audio PID.
113 * \param ts_indexer The TS indexer.
114 * \param pid The audio PID.
115 * \retval 0 On success.
116 * \retval -1 On error.
117 */
118int
119ts_indexer_set_audio_pid (TS_Indexer_t *ts_indexer, int pid)
120{
121 if (ts_indexer == NULL)
122 return -1;
123
124 TSParser *parser = &ts_indexer->audio_parser;
125 parser->pid = pid;
126 parser->offset = 0;
127 parser->PES.pts = -1;
128 parser->PES.offset = 0;
129 parser->PES.len = 0;
130 parser->PES.state = TS_INDEXER_STATE_INIT;
131
132 return 0;
133}
134
135/**
136 * Set the event callback function.
137 * \param ts_indexer The TS indexer.
138 * \param callback The event callback function.
139 * \retval 0 On success.
140 * \retval -1 On error.
141 */
142int
143ts_indexer_set_event_callback (TS_Indexer_t *ts_indexer, TS_Indexer_EventCallback_t callback)
144{
145 ts_indexer->callback = callback;
146
147 return 0;
148}
149
150static void find_mpeg(uint8_t *data, int len, TS_Indexer_t *indexer, TSParser *stream)
151{
152 int i;
153 uint32_t needle = 0;
Yahui Han63de7082023-07-12 18:30:10 +0800154 uint32_t needle1 = 0;
Gong Kefa504d72023-04-18 10:23:35 +0800155 uint8_t *haystack = data;
156 int haystack_len = len;
157 int left = len;
158 // start code of picture header
159 uint8_t arr[4] = {0x00, 0x00, 0x01, 0x00};
Yahui Han63de7082023-07-12 18:30:10 +0800160 // start code of sequence header
161 uint8_t arr1[4] = {0x00, 0x00, 0x01, 0xb3};
Gong Kefa504d72023-04-18 10:23:35 +0800162 TS_Indexer_Event_t event;
163
164 /* mpeg header needs at least 4 bytes */
165 if (left < 4) {
166 memcpy(&stream->PES.data[0], &haystack, left);
167 stream->PES.len = left;
168 return;
169 }
170
171 memset(&event, 0, sizeof(event));
172 event.pid = stream->pid;
173 event.offset = stream->offset;
174
175 for (i = 0; i < 4; ++i) {
176 needle += (arr[i] << (8 * i));
177 }
178
Yahui Han63de7082023-07-12 18:30:10 +0800179 for (i = 0; i < 4; ++i) {
180 needle1 += (arr1[i] << (8 * i));
181 }
182
Gong Kefa504d72023-04-18 10:23:35 +0800183 for (i = 0; i < haystack_len - sizeof(needle) + 1;) {
Yahui Han63de7082023-07-12 18:30:10 +0800184 if (left < 5) {
185 INF("MPEG2 picture header across TS Packet\n");
186
187 /* MEPG2 picture header across TS packet, should cache the left data */
188 memcpy(&stream->PES.data[0], haystack + i, left);
189 stream->PES.len = left;
190 return;
191 }
192
Gong Kefa504d72023-04-18 10:23:35 +0800193 if (*(uint32_t *)(haystack + i) == needle) {
194 // picture header found
Yahui Han63de7082023-07-12 18:30:10 +0800195 int frame_type = (haystack[i + 5] >> 3) & 0x7;
196 switch (frame_type) {
197 case 1:
198 INF("I frame found, offset: %lx\n", event.offset);
199 event.type = TS_INDEXER_EVENT_TYPE_MPEG2_I_FRAME;
200 break;
Gong Kefa504d72023-04-18 10:23:35 +0800201
Yahui Han63de7082023-07-12 18:30:10 +0800202 case 2:
203 INF("P frame found, offset: %lx\n", event.offset);
204 event.type = TS_INDEXER_EVENT_TYPE_MPEG2_P_FRAME;
205 break;
206
207 case 3:
208 INF("B frame found, offset: %lx\n", event.offset);
209 event.type = TS_INDEXER_EVENT_TYPE_MPEG2_B_FRAME;
210 break;
211
212 default:
213 i += 5;
214 left -= 5;
215 continue;
216
Gong Kefa504d72023-04-18 10:23:35 +0800217 }
218
Yahui Han63de7082023-07-12 18:30:10 +0800219 event.pts = stream->PES.pts;
220 if (indexer->callback) {
221 indexer->callback(indexer, &event);
222 }
223
224 i += 5;
225 left -= 5;
226 } else if (*(uint32_t *)(haystack + i) == needle1) {
227 // sequence header found
228 event.type = TS_INDEXER_EVENT_TYPE_MPEG2_SEQUENCE;
229 event.pts = stream->PES.pts;
230 if (indexer->callback) {
231 indexer->callback(indexer, &event);
Gong Kefa504d72023-04-18 10:23:35 +0800232 }
233
234 i += 5;
235 left -= 5;
236 } else {
237 i ++;
238 left --;
239 }
240 }
241
242 if (left > 0) {
243 memcpy(&stream->PES.data[0], &haystack[i], left);
244 stream->PES.len = left;
245 } else {
246 stream->PES.len = 0;
247 }
248}
249
250static uint8_t *get_nalu(uint8_t *data, size_t len, size_t *nalu_len)
251{
252 size_t i;
253 uint8_t *p = data;
254
255 if (len == 0)
256 return NULL;
257
258 //INF("%s enter, len:%#lx\n", __func__, len);
259 for (i = 0; i < len - 4; ++i) {
260 if (p[i] == 0x00 && p[i+1] == 0x00 && p[i+2] == 0x01) {
261 uint8_t *frame_data = data + i;
262 size_t frame_data_len = 0;
263
264 //INF("%s start code prefix\n", __func__);
265 for (size_t j = i + 4; j < len - 4; ++j) {
266 if (p[j] == 0x00 && p[j+1] == 0x00 && p[j+2] == 0x01) {
267 frame_data_len = j - i;
268 break;
269 }
270 }
271
272 if (frame_data_len > 0) {
273 *nalu_len = frame_data_len;
274 return frame_data;
275 } else {
276 frame_data_len = len - i;
277 *nalu_len = frame_data_len;
278 return frame_data;
279 }
280 }
281 }
282
283 return NULL;
284}
285
286static void find_h264(uint8_t *data, size_t len, TS_Indexer_t *indexer, TSParser *stream)
287{
288 TS_Indexer_Event_t event;
289 uint8_t *nalu = data;
290 size_t pes_data_len = len;
291 size_t nalu_len;
292
293 memset(&event, 0, sizeof(event));
294 event.pid = stream->pid;
295 event.offset = stream->offset;
296
297 while (1) {
298 int left = pes_data_len - (nalu - data);
Yahui Han63de7082023-07-12 18:30:10 +0800299 if (left <= 5) {
Gong Kefa504d72023-04-18 10:23:35 +0800300 memcpy(&stream->PES.data[0], nalu, left);
301 stream->PES.len = left;
302 break;
303 }
304
305 nalu = get_nalu(nalu, left, &nalu_len);
306 if (nalu == NULL)
307 break;
308
309 if (nalu[0] == 0x00 && nalu[1] == 0x00 && nalu[2] == 0x01) {
310 int nal_type = nalu[3] & 0x1f;
Yahui Han63de7082023-07-12 18:30:10 +0800311
312 event.pts = stream->PES.pts;
313 if (nal_type == NAL_TYPE_IDR) {
314 INF("AVC IDR found\n");
315 event.type = TS_INDEXER_EVENT_TYPE_AVC_I_SLICE;
316 } else if (nal_type == NAL_TYPE_NON_IDR) {
317 int slice_type = (nalu[4] >> 4) & 0x3;
318 if (slice_type == 0 || slice_type == 5) {
319 event.type = TS_INDEXER_EVENT_TYPE_AVC_P_SLICE;
320 } else if (slice_type == 1 || slice_type == 6) {
321 event.type = TS_INDEXER_EVENT_TYPE_AVC_B_SLICE;
322 } else if (slice_type == 2 || slice_type == 7) {
323 event.type = TS_INDEXER_EVENT_TYPE_AVC_I_SLICE;
324 } else if (slice_type == 3 || slice_type == 8) {
325 event.type = TS_INDEXER_EVENT_TYPE_AVC_SP_SLICE;
326 } else if (slice_type == 4 || slice_type == 9) {
327 event.type = TS_INDEXER_EVENT_TYPE_AVC_SI_SLICE;
328 } else {
329 ERR("%s invalid slice_type: %d\n", __func__, slice_type);
Gong Kefa504d72023-04-18 10:23:35 +0800330 }
Yahui Han63de7082023-07-12 18:30:10 +0800331 } else {
332 nalu += nalu_len;
333 continue;
334 }
335
336 if (indexer->callback) {
337 indexer->callback(indexer, &event);
Gong Kefa504d72023-04-18 10:23:35 +0800338 }
339 }
340
341 nalu += nalu_len;
342 }
343
344 stream->PES.len = 0;
345}
346
347static void find_h265(uint8_t *data, int len, TS_Indexer_t *indexer, TSParser *stream)
348{
349 TS_Indexer_Event_t event;
350 uint8_t *nalu = data;
351 size_t pes_data_len = len;
352 size_t nalu_len;
353
354 memset(&event, 0, sizeof(event));
355 event.pid = stream->pid;
356 event.offset = stream->offset;
357
358 while (nalu != NULL) {
359 int left = pes_data_len - (nalu - data);
360 if (left <= 4) {
361 memcpy(&stream->PES.data[0], nalu, left);
362 stream->PES.len = left;
363 break;
364 }
365
366 nalu = get_nalu(nalu, left, &nalu_len);
367 if (nalu == NULL)
368 break;
369
370 if (nalu[0] == 0x00 && nalu[1] == 0x00 && nalu[2] == 0x01) {
371 int nalu_type = (nalu[3] & 0x7E) >> 1;
372 //INF("nalu[3]: %#x, nalu_type: %#x\n", nalu[3], nalu_type);
Yahui Han63de7082023-07-12 18:30:10 +0800373 switch (nalu_type) {
374 case HEVC_NALU_BLA_W_LP:
375 event.type = TS_INDEXER_EVENT_TYPE_HEVC_BLA_W_LP;
376 break;
377
378 case HEVC_NALU_BLA_W_RADL:
379 event.type = TS_INDEXER_EVENT_TYPE_HEVC_BLA_W_RADL;
380 break;
381
382 case HEVC_NALU_IDR_W_RADL:
383 event.type = TS_INDEXER_EVENT_TYPE_HEVC_IDR_W_RADL;
384 //INF("HEVC I-frame found\n");
385 break;
386
387 case HEVC_NALU_IDR_N_LP:
388 event.type = TS_INDEXER_EVENT_TYPE_HEVC_IDR_N_LP;
389 break;
390
391 case HEVC_NALU_TRAIL_CRA:
392 event.type = TS_INDEXER_EVENT_TYPE_HEVC_TRAIL_CRA;
393 break;
394
395 case HEVC_NALU_SPS:
396 event.type = TS_INDEXER_EVENT_TYPE_HEVC_SPS;
397 break;
398
399 case HEVC_NALU_AUD:
400 event.type = TS_INDEXER_EVENT_TYPE_HEVC_AUD;
401 break;
402
403 default:
404 nalu += nalu_len;
405 continue;
406 }
407
408 event.pts = stream->PES.pts;
409 if (indexer->callback) {
410 indexer->callback(indexer, &event);
Gong Kefa504d72023-04-18 10:23:35 +0800411 }
412 }
413
414 nalu += nalu_len;
415 }
Yahui Han63de7082023-07-12 18:30:10 +0800416
Gong Kefa504d72023-04-18 10:23:35 +0800417 stream->PES.len = 0;
418}
419
420/*Parse the PES packet*/
421static void
422pes_packet(TS_Indexer_t *ts_indexer, uint8_t *data, int len, TSParser *stream)
423{
424 uint8_t *p = data;
425 TS_Indexer_t *pi = ts_indexer;
426 int left = len;
427 TS_Indexer_Event_t event;
428
429 memset(&event, 0, sizeof(event));
430 event.pid = stream->pid;
431 event.offset = stream->offset;
432
433 INF("stream: %p, state: %d\n", stream, stream->PES.state);
434 if (stream->PES.state <= TS_INDEXER_STATE_INIT) {
435 INF("%s, invalid state\n", __func__);
436 stream->PES.len = 0;
437 return;
438 }
439
440 /* needs splice two pieces of data together if have cache data */
441 if (stream->PES.len > 0) {
442 INF("%s have cache data %d bytes\n", __func__, stream->PES.len);
443 memcpy(&stream->PES.data[stream->PES.len], data, len);
444 p = &stream->PES.data[0];
445 left = stream->PES.len + len;
446 stream->PES.len = left;
447 }
448
449 if (stream->PES.state == TS_INDEXER_STATE_TS_START) {
450 /* needs cache data if no enough data to parse PES header */
451 if (left < 6) {
452 if (stream->PES.len <= 0) {
453 memcpy(&stream->PES.data[0], p, left);
454 stream->PES.len = left;
455 }
456 INF("not enough ts payload len: %#x\n", left);
457 return;
458 }
459
460 // chect the PES packet start code prefix
461 if ((p[0] != 0) || (p[1] != 0) || (p[2] != 1)) {
462 stream->PES.len = 0;
463 stream->PES.state = TS_INDEXER_STATE_INIT;
464 INF("%s, not the expected start code!\n", __func__);
465 return;
466 }
467
468 p += 6;
469 left -= 6;
470 stream->PES.state = TS_INDEXER_STATE_PES_HEADER;
471 }
472
473 if (stream->PES.state == TS_INDEXER_STATE_PES_HEADER) {
474 if (left < 8) {
475 if (stream->PES.len <= 0) {
476 memcpy(&stream->PES.data[0], p, left);
477 stream->PES.len = left;
478 }
479 INF("not enough optional pes header len: %#x\n", left);
480 return;
481 }
482
483 int header_length = p[2];
484 if (p[1] & 0x80) {
485 // parser pts
486 p += 3;
487 left -= 3;
488 event.pts = stream->PES.pts = (((uint64_t)(p[0] & 0x0E) << 29) |
489 ((uint64_t)p[1] << 22) |
490 ((uint64_t)(p[2] & 0xFE) << 14) |
491 ((uint64_t)p[3] << 7) |
492 (((uint64_t)p[4] & 0xFE) >> 1));
493 INF("pts: %lx, pos:%lx\n", event.pts, event.offset);
494
495 if (stream == &pi->video_parser) {
496 event.type = TS_INDEXER_EVENT_TYPE_VIDEO_PTS;
497 } else {
498 event.type = TS_INDEXER_EVENT_TYPE_AUDIO_PTS;
499 }
500 if (pi->callback) {
501 pi->callback(pi, &event);
502 }
503 }
Yahui Han63de7082023-07-12 18:30:10 +0800504 if (stream->format != -1) {
505 stream->PES.state = TS_INDEXER_STATE_PES_PTS;
Gong Kefa504d72023-04-18 10:23:35 +0800506
Yahui Han63de7082023-07-12 18:30:10 +0800507 p += header_length;
508 left -= header_length;
509 } else {
510 stream->PES.state = TS_INDEXER_STATE_INIT;
511 left = 0;
512 }
Gong Kefa504d72023-04-18 10:23:35 +0800513 }
514
515 stream->PES.len = left;
516 if (left <= 0
517 || stream->PES.state < TS_INDEXER_STATE_PES_PTS) {
518 return;
519 }
520
521 INF("stream->format: %d, left: %d\n", stream->format, left);
522 switch (stream->format) {
523 case TS_INDEXER_VIDEO_FORMAT_MPEG2:
524 find_mpeg(p, left, pi, &pi->video_parser);
525 break;
526
527 case TS_INDEXER_VIDEO_FORMAT_H264:
528 find_h264(p, left, pi, &pi->video_parser);
529 break;
530
531 case TS_INDEXER_VIDEO_FORMAT_HEVC:
532 find_h265(p, left, pi, &pi->video_parser);
533 break;
534
535 default:
Yahui Han63de7082023-07-12 18:30:10 +0800536 stream->PES.state = TS_INDEXER_STATE_INIT;
537 stream->PES.len = 0;
Gong Kefa504d72023-04-18 10:23:35 +0800538 break;
539 }
540}
541
542/*Parse the TS packet.*/
543static void
544ts_packet(TS_Indexer_t *ts_indexer, uint8_t *data)
545{
546 uint16_t pid;
547 uint8_t afc;
548 uint8_t *p = data;
549 TS_Indexer_t *pi = ts_indexer;
550 int len;
551 int is_start;
Yahui Han63de7082023-07-12 18:30:10 +0800552 TS_Indexer_Event_t event;
Gong Kefa504d72023-04-18 10:23:35 +0800553
554 is_start = p[1] & 0x40;
555 pid = ((p[1] & 0x1f) << 8) | p[2];
556 if (pid == 0x1fff)
557 return;
558
559 if ((pid != pi->video_parser.pid) &&
560 (pid != pi->audio_parser.pid)) {
561 return;
562 }
563
564 if (is_start) {
Yahui Han63de7082023-07-12 18:30:10 +0800565 memset(&event, 0, sizeof(event));
566 event.pid = pid;
567 event.offset = pi->offset;
568 event.type = TS_INDEXER_EVENT_TYPE_START_INDICATOR;
569 if (pi->callback) {
570 pi->callback(pi, &event);
571 }
572
Gong Kefa504d72023-04-18 10:23:35 +0800573 if (pid == pi->video_parser.pid) {
574 pi->video_parser.offset = pi->offset;
575 pi->video_parser.PES.state = TS_INDEXER_STATE_TS_START;
576 }
577 else if (pid == pi->audio_parser.pid) {
578 pi->audio_parser.offset = pi->offset;
579 pi->audio_parser.PES.state = TS_INDEXER_STATE_TS_START;
580 }
581 }
582
583 afc = (p[3] >> 4) & 0x03;
584
585 p += 4;
586 len = 184;
587
588 if (afc & 2) {
589 int adp_field_len = p[0];
Yahui Han63de7082023-07-12 18:30:10 +0800590 if (p[1] & 0x80) {
591 memset(&event, 0, sizeof(event));
592 event.pid = pid;
593 event.offset = pi->offset;
594 event.type = TS_INDEXER_EVENT_TYPE_DISCONTINUITY_INDICATOR;
595 if (pi->callback) {
596 pi->callback(pi, &event);
597 }
598 }
Gong Kefa504d72023-04-18 10:23:35 +0800599 p++;
600 len--;
601
602 p += adp_field_len;
603 len -= adp_field_len;
604
605 if (len < 0) {
606 ERR("illegal adaption field length!");
607 return;
608 }
609 }
610
611 // has payload
612 if ((afc & 1) && (len > 0)) {
613 // parser pes packet
614 pes_packet(pi, p, len, (pid == pi->video_parser.pid) ? &pi->video_parser : &pi->audio_parser);
615 }
616}
617
618/**
619 * Parse the TS stream and generate the index data.
620 * \param ts_indexer The TS indexer.
621 * \param data The TS data.
622 * \param len The length of the TS data in bytes.
623 * \return The left TS data length of bytes.
624 */
625int
626ts_indexer_parse (TS_Indexer_t *ts_indexer, uint8_t *data, int len)
627{
628 uint8_t *p = data;
629 int left = len;
630
631 if (ts_indexer == NULL || data == NULL || len <= 0)
632 return -1;
633
634 while (left > 0) {
635 // find the sync byte
636 if (*p == 0x47) {
637 if (left < TS_PKT_SIZE) {
638 INF("%s data length may not be 188-byte aligned\n", __func__);
639 return left;
640 }
641
642 // parse one ts packet
643 ts_packet(ts_indexer, p);
644 p += TS_PKT_SIZE;
645 left -= TS_PKT_SIZE;
646 ts_indexer->offset += TS_PKT_SIZE;
647 } else {
648 p++;
649 left--;
650 ts_indexer->offset++;
651 }
652 }
653
654 return left;
655}