1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is MPEG4IP.
13 *
14 * The Initial Developer of the Original Code is Cisco Systems Inc.
15 * Portions created by Cisco Systems Inc. are
16 * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved.
17 *
18 * Contributor(s):
19 * Bill May wmay@cisco.com
20 */
21
22 /*
23 * mpeg2ps.c - parse program stream and vob files
24 */
25 #include "mpeg2_ps.h"
26
27 #ifndef GPAC_DISABLE_MPEG2PS
28
29
convert16(u8 * p)30 static GFINLINE u16 convert16 (u8 *p)
31 {
32 #ifdef GPAC_BIG_ENDIAN
33 return *(u16 *)p;
34 #else
35 u16 val = p[0];
36 val <<= 8;
37 return (val | p[1]);
38 #endif
39 }
40
convert32(u8 * p)41 static GFINLINE u32 convert32 (u8 *p)
42 {
43 #ifdef GPAC_BIG_ENDIAN
44 return *(u32 *)p;
45 #else
46 u32 val;
47 val = p[0];
48 val <<= 8;
49 val |= p[1];
50 val <<= 8;
51 val |= p[2];
52 val <<= 8;
53 val |= p[3];
54 return val;
55 #endif
56 }
57
58 #define FDNULL 0
59
60 /*
61 * structure for passing timestamps around
62 */
63 typedef struct mpeg2ps_ts_t
64 {
65 Bool have_pts;
66 Bool have_dts;
67 u64 pts;
68 u64 dts;
69 } mpeg2ps_ts_t;
70
71 typedef struct mpeg2ps_record_pes_t
72 {
73 struct mpeg2ps_record_pes_t *next_rec;
74 u64 dts;
75 u64 location;
76 } mpeg2ps_record_pes_t;
77
78 /*
79 * information about reading a stream
80 */
81 typedef struct mpeg2ps_stream_t
82 {
83 mpeg2ps_record_pes_t *record_first, *record_last;
84 FILE *m_fd;
85 Bool is_video;
86 u8 m_stream_id; // program stream id
87 u8 m_substream_id; // substream, for program stream id == 0xbd
88
89 mpeg2ps_ts_t next_pes_ts, frame_ts;
90 u32 frames_since_last_ts;
91 u64 last_ts;
92
93 Bool have_frame_loaded;
94 /*
95 * pes_buffer processing. this contains the raw elementary stream data
96 */
97 u8 *pes_buffer;
98 u32 pes_buffer_size;
99 u32 pes_buffer_size_max;
100 u32 pes_buffer_on;
101 u32 frame_len;
102 u32 pict_header_offset; // for mpeg video
103
104 // timing information and locations.
105 s64 first_pes_loc;
106 u64 start_dts;
107 Bool first_pes_has_dts;
108 s64 end_dts_loc;
109 u64 end_dts;
110 // audio stuff
111 u32 freq;
112 u32 channels;
113 u32 bitrate;
114 u32 samples_per_frame;
115 u32 layer;
116 // video stuff
117 u32 h, w, par;
118 Double frame_rate;
119 s32 have_mpeg2;
120 Double bit_rate;
121 u64 ticks_per_frame;
122
123 } mpeg2ps_stream_t;
124
125 /*
126 * main interface structure - contains stream pointers and other
127 * information
128 */
129 struct mpeg2ps_ {
130 mpeg2ps_stream_t *video_streams[16];
131 mpeg2ps_stream_t *audio_streams[32];
132 char *filename;
133 FILE *fd;
134 u64 first_dts;
135 u32 audio_cnt, video_cnt;
136 s64 end_loc;
137 u64 max_dts;
138 u64 max_time; // time is in msec.
139 };
140
141 /*************************************************************************
142 * File access routines. Could all be inlined
143 *************************************************************************/
file_open(const char * name)144 static FILE *file_open (const char *name)
145 {
146 return gf_fopen(name, "rb");
147 }
148
file_okay(FILE * fd)149 static Bool file_okay (FILE *fd)
150 {
151 return (fd!=NULL) ? 1 : 0;
152 }
153
file_close(FILE * fd)154 static void file_close (FILE *fd)
155 {
156 gf_fclose(fd);
157 }
158
file_read_bytes(FILE * fd,u8 * buffer,u32 len)159 static Bool file_read_bytes(FILE *fd,
160 u8 *buffer,
161 u32 len)
162 {
163 u32 readval = (u32) gf_fread(buffer, len, fd);
164 return readval == len;
165 }
166
167 // note: len could be negative.
file_skip_bytes(FILE * fd,s32 len)168 static void file_skip_bytes (FILE *fd, s32 len)
169 {
170 gf_fseek(fd, len, SEEK_CUR);
171 }
172
173 #define file_location(__f) gf_ftell(__f)
174 #define file_seek_to(__f, __off) gf_fseek(__f, __off, SEEK_SET)
175
file_size(FILE * fd)176 static u64 file_size(FILE *fd)
177 {
178 return gf_fsize(fd);
179 }
180
create_record(s64 loc,u64 ts)181 static mpeg2ps_record_pes_t *create_record (s64 loc, u64 ts)
182 {
183 mpeg2ps_record_pes_t *ret;
184 GF_SAFEALLOC(ret, mpeg2ps_record_pes_t);
185 if (!ret) return NULL;
186 ret->next_rec = NULL;
187 ret->dts = ts;
188 ret->location = loc;
189 return ret;
190 }
191
192 #define MPEG2PS_RECORD_TIME ((u64) (5 * 90000))
mpeg2ps_record_pts(mpeg2ps_stream_t * sptr,s64 location,mpeg2ps_ts_t * pTs)193 void mpeg2ps_record_pts (mpeg2ps_stream_t *sptr, s64 location, mpeg2ps_ts_t *pTs)
194 {
195 u64 ts;
196 mpeg2ps_record_pes_t *p, *q;
197 if (sptr->is_video) {
198 if (pTs->have_dts == 0) return;
199 ts = pTs->dts;
200 } else {
201 if (pTs->have_pts == 0) return;
202 ts = pTs->pts;
203 }
204
205 if (sptr->record_first == NULL) {
206 sptr->record_first = sptr->record_last = create_record(location, ts);
207 return;
208 }
209 if (ts > sptr->record_last->dts) {
210 if (ts < MPEG2PS_RECORD_TIME + sptr->record_last->dts) return;
211 sptr->record_last->next_rec = create_record(location, ts);
212 sptr->record_last = sptr->record_last->next_rec;
213 return;
214 }
215 if (ts < sptr->record_first->dts) {
216 if (ts < MPEG2PS_RECORD_TIME + sptr->record_first->dts) return;
217 p = create_record(location, ts);
218 p->next_rec = sptr->record_first;
219 sptr->record_first = p;
220 return;
221 }
222 p = sptr->record_first;
223 q = p->next_rec;
224
225 while (q != NULL && q->dts < ts) {
226 p = q;
227 q = q->next_rec;
228 }
229 if (q) {
230 if (p->dts + MPEG2PS_RECORD_TIME <= ts &&
231 ts + MPEG2PS_RECORD_TIME <= q->dts) {
232 p->next_rec = create_record(location, ts);
233 p->next_rec->next_rec = q;
234 }
235 }
236 }
237 static Double mpeg12_frame_rate_table[16] =
238 {
239 0.0, /* Pad */
240 24000.0/1001.0, /* Official frame rates */
241 24.0,
242 25.0,
243 30000.0/1001.0,
244 30.0,
245 50.0,
246 ((60.0*1000.0)/1001.0),
247 60.0,
248
249 1, /* Unofficial economy rates */
250 5,
251 10,
252 12,
253 15,
254 0,
255 0,
256 };
257
258 #define SEQ_ID 1
MPEG12_ParseSeqHdr(unsigned char * pbuffer,u32 buflen,s32 * have_mpeg2,u32 * height,u32 * width,Double * frame_rate,Double * bitrate,u32 * aspect_ratio)259 int MPEG12_ParseSeqHdr(unsigned char *pbuffer, u32 buflen, s32 *have_mpeg2, u32 *height, u32 *width,
260 Double *frame_rate, Double *bitrate, u32 *aspect_ratio)
261 {
262 u32 aspect_code;
263 u32 framerate_code;
264 u32 bitrate_int;
265 u32 bitrate_ext;
266 u32 scode, ix;
267 s32 found = -1;
268 *have_mpeg2 = 0;
269 buflen -= 6;
270 bitrate_int = 0;
271 for (ix = 0; ix < buflen; ix++, pbuffer++) {
272 scode = ((u32)pbuffer[0] << 24) | (pbuffer[1] << 16) | (pbuffer[2] << 8) |
273 pbuffer[3];
274
275 if (scode == MPEG12_SEQUENCE_START_CODE) {
276 pbuffer += sizeof(u32);
277 *width = (pbuffer[0]);
278 *width <<= 4;
279 *width |= ((pbuffer[1] >> 4) &0xf);
280 *height = (pbuffer[1] & 0xf);
281 *height <<= 8;
282 *height |= pbuffer[2];
283 aspect_code = (pbuffer[3] >> 4) & 0xf;
284 if (aspect_ratio != NULL) {
285 u32 par = 0;
286 switch (aspect_code) {
287 default:
288 *aspect_ratio = 0;
289 break;
290 case 2:
291 par = 4;
292 par<<=16;
293 par |= 3;
294 break;
295 case 3:
296 par = 16;
297 par<<=16;
298 par |= 9;
299 break;
300 case 4:
301 par = 2;
302 par<<=16;
303 par |= 21;
304 break;
305 }
306 *aspect_ratio = par;
307 }
308
309
310 framerate_code = pbuffer[3] & 0xf;
311 *frame_rate = mpeg12_frame_rate_table[framerate_code];
312 // 18 bits
313 bitrate_int = (pbuffer[4] << 10) |
314 (pbuffer[5] << 2) |
315 ((pbuffer[6] >> 6) & 0x3);
316 *bitrate = bitrate_int;
317 *bitrate *= 400.0;
318 ix += sizeof(u32) + 7;
319 pbuffer += 7;
320 found = 0;
321 } else if (found == 0) {
322 if (scode == MPEG12_EXT_START_CODE) {
323 pbuffer += sizeof(u32);
324 ix += sizeof(u32);
325 switch ((pbuffer[0] >> 4) & 0xf) {
326 case SEQ_ID:
327 *have_mpeg2 = 1;
328 *height = ((pbuffer[1] & 0x1) << 13) |
329 ((pbuffer[2] & 0x80) << 5) |
330 (*height & 0x0fff);
331 *width = (((pbuffer[2] >> 5) & 0x3) << 12) | (*width & 0x0fff);
332 bitrate_ext = (pbuffer[2] & 0x1f) << 7;
333 bitrate_ext |= (pbuffer[3] >> 1) & 0x7f;
334 bitrate_int |= (bitrate_ext << 18);
335 *bitrate = bitrate_int;
336 *bitrate *= 400.0;
337 break;
338 default:
339 break;
340 }
341 pbuffer++;
342 ix++;
343 } else if (scode == MPEG12_PICTURE_START_CODE) {
344 return found;
345 }
346 }
347 }
348 return found;
349 }
350
351
MPEG12_PictHdrType(unsigned char * pbuffer)352 s32 MPEG12_PictHdrType (unsigned char *pbuffer)
353 {
354 pbuffer += sizeof(u32);
355 return ((pbuffer[1] >> 3) & 0x7);
356 }
357
358 #if 0 //unused
359 u16 MPEG12_PictHdrTempRef(unsigned char *pbuffer)
360 {
361 pbuffer += sizeof(u32);
362 return ((pbuffer[0] << 2) | ((pbuffer[1] >> 6) & 0x3));
363 }
364 #endif
365
366
read_pts(u8 * pak)367 static u64 read_pts (u8 *pak)
368 {
369 u64 pts;
370 u16 temp;
371
372 pts = ((pak[0] >> 1) & 0x7);
373 pts <<= 15;
374 temp = convert16(&pak[1]) >> 1;
375 pts |= temp;
376 pts <<= 15;
377 temp = convert16(&pak[3]) >> 1;
378 pts |= temp;
379 return pts;
380 }
381
382
mpeg2ps_stream_create(u8 stream_id,u8 substream)383 static mpeg2ps_stream_t *mpeg2ps_stream_create (u8 stream_id,
384 u8 substream)
385 {
386 mpeg2ps_stream_t *ptr;
387 GF_SAFEALLOC(ptr, mpeg2ps_stream_t);
388 if (!ptr) return NULL;
389 ptr->m_stream_id = stream_id;
390 ptr->m_substream_id = substream;
391 ptr->is_video = stream_id >= 0xe0;
392 ptr->pes_buffer = (u8 *)gf_malloc(4*4096);
393 ptr->pes_buffer_size_max = 4 * 4096;
394 return ptr;
395 }
396
mpeg2ps_stream_destroy(mpeg2ps_stream_t * sptr)397 static void mpeg2ps_stream_destroy (mpeg2ps_stream_t *sptr)
398 {
399 mpeg2ps_record_pes_t *p;
400 while (sptr->record_first != NULL) {
401 p = sptr->record_first;
402 sptr->record_first = p->next_rec;
403 gf_free(p);
404 }
405 if (sptr->m_fd != FDNULL) {
406 file_close(sptr->m_fd);
407 sptr->m_fd = FDNULL;
408 }
409 if (sptr->pes_buffer) gf_free(sptr->pes_buffer);
410 gf_free(sptr);
411 }
412
413
414 /*
415 * adv_past_pack_hdr - read the pack header, advance past it
416 * we don't do anything with the data
417 */
adv_past_pack_hdr(FILE * fd,u8 * pak,u32 read_from_start)418 static void adv_past_pack_hdr (FILE *fd,
419 u8 *pak,
420 u32 read_from_start)
421 {
422 u8 stuffed;
423 u8 readbyte;
424 u8 val;
425 if (read_from_start < 5) {
426 file_skip_bytes(fd, 5 - read_from_start);
427 file_read_bytes(fd, &readbyte, 1);
428 val = readbyte;
429 } else {
430 val = pak[4];
431 }
432
433 // we've read 6 bytes
434 if ((val & 0xc0) != 0x40) {
435 // mpeg1
436 file_skip_bytes(fd, 12 - read_from_start); // skip 6 more bytes
437 return;
438 }
439 file_skip_bytes(fd, 13 - read_from_start);
440 file_read_bytes(fd, &readbyte, 1);
441 stuffed = readbyte & 0x7;
442 file_skip_bytes(fd, stuffed);
443 }
444
445 /*
446 * find_pack_start
447 * look for the pack start code in the file - read 512 bytes at a time,
448 * searching for that code.
449 * Note: we may also be okay looking for >= 00 00 01 bb
450 */
find_pack_start(FILE * fd,u8 * saved,u32 len)451 static Bool find_pack_start (FILE *fd,
452 u8 *saved,
453 u32 len)
454 {
455 u8 buffer[512];
456 u32 buffer_on = 0, new_offset, scode;
457 memcpy(buffer, saved, len);
458 if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == 0) {
459 return 0;
460 }
461 while (1) {
462 if (gf_mv12_next_start_code(buffer + buffer_on,
463 sizeof(buffer) - buffer_on,
464 &new_offset,
465 &scode) >= 0) {
466 buffer_on += new_offset;
467 if (scode == MPEG2_PS_PACKSTART) {
468 file_skip_bytes(fd, buffer_on - 512); // go back to header
469 return 1;
470 }
471 buffer_on += 1;
472 } else {
473 len = 0;
474 if (buffer[sizeof(buffer) - 3] == 0 &&
475 buffer[sizeof(buffer) - 2] == 0 &&
476 buffer[sizeof(buffer) - 1] == 1) {
477 buffer[0] = 0;
478 buffer[1] = 0;
479 buffer[2] = 1;
480 len = 3;
481 } else if (*(u16 *)(buffer + sizeof(buffer) - 2) == 0) {
482 buffer[0] = 0;
483 buffer[1] = 0;
484 len = 2;
485 } else if (buffer[sizeof(buffer) - 1] == 0) {
486 buffer[0] = 0;
487 len = 1;
488 }
489 if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == 0) {
490 return 0;
491 }
492 buffer_on = 0;
493 }
494 }
495 return 0;
496 }
497
498 /*
499 * copy_bytes_to_pes_buffer - read pes_len bytes into the buffer,
500 * adjusting it if we need it
501 */
copy_bytes_to_pes_buffer(mpeg2ps_stream_t * sptr,u16 pes_len)502 static void copy_bytes_to_pes_buffer (mpeg2ps_stream_t *sptr,
503 u16 pes_len)
504 {
505 u32 to_move;
506
507 if (sptr->pes_buffer_size + pes_len > sptr->pes_buffer_size_max) {
508 // if no room in the buffer, we'll move it - otherwise, just fill
509 // note - we might want a better strategy about moving the buffer -
510 // right now, we might be moving a number of bytes if we have a large
511 // followed by large frame.
512 to_move = sptr->pes_buffer_size - sptr->pes_buffer_on;
513 memmove(sptr->pes_buffer,
514 sptr->pes_buffer + sptr->pes_buffer_on,
515 to_move);
516 sptr->pes_buffer_size = to_move;
517 sptr->pes_buffer_on = 0;
518 if (to_move + pes_len > sptr->pes_buffer_size_max) {
519 sptr->pes_buffer = (u8 *)gf_realloc(sptr->pes_buffer,
520 to_move + pes_len + 2048);
521 sptr->pes_buffer_size_max = to_move + pes_len + 2048;
522 }
523 }
524 file_read_bytes(sptr->m_fd, sptr->pes_buffer + sptr->pes_buffer_size, pes_len);
525 sptr->pes_buffer_size += pes_len;
526 }
527
528 /*
529 * read_to_next_pes_header - read the file, look for the next valid
530 * pes header. We will skip over PACK headers, but not over any of the
531 * headers listed in 13818-1, table 2-18 - basically, anything with the
532 * 00 00 01 and the next byte > 0xbb.
533 * We return the pes len to read, and the "next byte"
534 */
read_to_next_pes_header(FILE * fd,u8 * stream_id,u16 * pes_len)535 static Bool read_to_next_pes_header (FILE *fd,
536 u8 *stream_id,
537 u16 *pes_len)
538 {
539 u32 hdr;
540 u8 local[6];
541
542 while (1) {
543 // read the pes header
544 if (file_read_bytes(fd, local, 6) == 0) {
545 return 0;
546 }
547
548 hdr = convert32(local);
549 // if we're not a 00 00 01, read until we get the next pack start
550 // we might want to also read until next PES - look into that.
551 if (((hdr & MPEG2_PS_START_MASK) != MPEG2_PS_START) ||
552 (hdr < MPEG2_PS_END)) {
553 if (find_pack_start(fd, local, 6) == 0) {
554 return 0;
555 }
556 continue;
557 }
558 if (hdr == MPEG2_PS_PACKSTART) {
559 // pack start code - we can skip down
560 adv_past_pack_hdr(fd, local, 6);
561 continue;
562 }
563 if (hdr == MPEG2_PS_END) {
564 file_skip_bytes(fd, -2);
565 continue;
566 }
567
568 // we should have a valid stream and pes_len here...
569 *stream_id = hdr & 0xff;
570 *pes_len = convert16(local + 4);
571 return 1;
572 }
573 return 0;
574 }
575
576 /*
577 * read_pes_header_data
578 * this should read past the pes header for the audio and video streams
579 * it will store the timestamps if it reads them
580 */
read_pes_header_data(FILE * fd,u16 orig_pes_len,u16 * pes_left,Bool * have_ts,mpeg2ps_ts_t * ts)581 static Bool read_pes_header_data (FILE *fd,
582 u16 orig_pes_len,
583 u16 *pes_left,
584 Bool *have_ts,
585 mpeg2ps_ts_t *ts)
586 {
587 u16 pes_len = orig_pes_len;
588 u8 local[10];
589 u32 hdr_len;
590
591 ts->have_pts = 0;
592 ts->have_dts = 0;
593 if (have_ts) *have_ts = 0;
594 if (file_read_bytes(fd, local, 1) == 0) {
595 return 0;
596 }
597 pes_len--; // remove this first byte from length
598 while (*local == 0xff) {
599 if (file_read_bytes(fd, local, 1) == 0) {
600 return 0;
601 }
602 pes_len--;
603 if (pes_len == 0) {
604 *pes_left = 0;
605 return 1;
606 }
607 }
608 if ((*local & 0xc0) == 0x40) {
609 // buffer scale & size
610 file_skip_bytes(fd, 1);
611 if (file_read_bytes(fd, local, 1) == 0) {
612 return 0;
613 }
614 pes_len -= 2;
615 }
616
617 if ((*local & 0xf0) == 0x20) {
618 // mpeg-1 with pts
619 if (file_read_bytes(fd, local + 1, 4) == 0) {
620 return 0;
621 }
622 ts->have_pts = 1;
623 ts->pts = ts->dts = read_pts(local);
624 *have_ts = 1;
625 pes_len -= 4;
626 } else if ((*local & 0xf0) == 0x30) {
627 // have mpeg 1 pts and dts
628 if (file_read_bytes(fd, local + 1, 9) == 0) {
629 return 0;
630 }
631 ts->have_pts = 1;
632 ts->have_dts = 1;
633 *have_ts = 1;
634 ts->pts = read_pts(local);
635 ts->dts = read_pts(local + 5);
636 pes_len -= 9;
637 } else if ((*local & 0xc0) == 0x80) {
638 // mpeg2 pes header - we're pointing at the flags field now
639 if (file_read_bytes(fd, local + 1, 2) == 0) {
640 return 0;
641 }
642 hdr_len = local[2];
643 pes_len -= hdr_len + 2; // first byte removed already
644 if ((local[1] & 0xc0) == 0x80) {
645 // just pts
646 ts->have_pts = 1;
647 file_read_bytes(fd, local, 5);
648 ts->pts = ts->dts = read_pts(local);
649 *have_ts = 1;
650 hdr_len -= 5;
651 } else if ((local[1] & 0xc0) == 0xc0) {
652 // pts and dts
653 ts->have_pts = 1;
654 ts->have_dts = 1;
655 *have_ts = 1;
656 file_read_bytes(fd, local, 10);
657 ts->pts = read_pts(local);
658 ts->dts = read_pts(local + 5);
659 hdr_len -= 10;
660 }
661 file_skip_bytes(fd, hdr_len);
662 } else if (*local != 0xf) {
663 file_skip_bytes(fd, pes_len);
664 pes_len = 0;
665 }
666 *pes_left = pes_len;
667 return 1;
668 }
669
search_for_next_pes_header(mpeg2ps_stream_t * sptr,u16 * pes_len,Bool * have_ts,s64 * found_loc)670 static Bool search_for_next_pes_header (mpeg2ps_stream_t *sptr,
671 u16 *pes_len,
672 Bool *have_ts,
673 s64 *found_loc)
674 {
675 u8 stream_id;
676 u8 local;
677 s64 loc;
678 while (1) {
679 // this will read until we find the next pes. We don't know if the
680 // stream matches - this will read over pack headers
681 if (read_to_next_pes_header(sptr->m_fd, &stream_id, pes_len) == 0) {
682 return 0;
683 }
684
685 if (stream_id != sptr->m_stream_id) {
686 file_skip_bytes(sptr->m_fd, *pes_len);
687 continue;
688 }
689 loc = file_location(sptr->m_fd) - 6;
690 // advance past header, reading pts
691 if (read_pes_header_data(sptr->m_fd,
692 *pes_len,
693 pes_len,
694 have_ts,
695 &sptr->next_pes_ts) == 0) {
696 return 0;
697 }
698
699 // If we're looking at a private stream, make sure that the sub-stream
700 // matches.
701 if (sptr->m_stream_id == 0xbd) {
702 // ac3 or pcm
703 file_read_bytes(sptr->m_fd, &local, 1);
704 *pes_len -= 1;
705 if (local != sptr->m_substream_id) {
706 file_skip_bytes(sptr->m_fd, *pes_len);
707 continue; // skip to the next one
708 }
709 *pes_len -= 3;
710 file_skip_bytes(sptr->m_fd, 3); // 4 bytes - we don't need now...
711 // we need more here...
712 }
713 if (have_ts) {
714 mpeg2ps_record_pts(sptr, loc, &sptr->next_pes_ts);
715 }
716 if (found_loc != NULL) *found_loc = loc;
717 return 1;
718 }
719 return 0;
720 }
721
722 /*
723 * mpeg2ps_stream_read_next_pes_buffer - for the given stream,
724 * go forward in the file until the next PES for the stream is read. Read
725 * the header (pts, dts), and read the data into the pes_buffer pointer
726 */
mpeg2ps_stream_read_next_pes_buffer(mpeg2ps_stream_t * sptr)727 static Bool mpeg2ps_stream_read_next_pes_buffer (mpeg2ps_stream_t *sptr)
728 {
729 u16 pes_len;
730 Bool have_ts;
731
732 if (search_for_next_pes_header(sptr, &pes_len, &have_ts, NULL) == 0) {
733 return 0;
734 }
735
736 copy_bytes_to_pes_buffer(sptr, pes_len);
737
738 return 1;
739 }
740
741
742 /***************************************************************************
743 * Frame reading routine. For each stream, the fd's should be different.
744 * we will read from the pes stream, and save it in the stream's pes buffer.
745 * This will give us raw data that we can search through for frame headers,
746 * and the like. We shouldn't read more than we need - when we need to read,
747 * we'll put the whole next pes buffer in the buffer
748 *
749 * Audio routines are of the format:
750 * look for header
751 * determine length
752 * make sure length is in buffer
753 *
754 * Video routines
755 * look for start header (GOP, SEQ, Picture)
756 * look for pict header
757 * look for next start (END, GOP, SEQ, Picture)
758 *
759 ***************************************************************************/
760 #define IS_MPEG_START(a) ((a) == 0xb3 || (a) == 0x00 || (a) == 0xb8)
761
762 static Bool
mpeg2ps_stream_find_mpeg_video_frame(mpeg2ps_stream_t * sptr)763 mpeg2ps_stream_find_mpeg_video_frame (mpeg2ps_stream_t *sptr)
764 {
765 u32 offset, scode;
766 Bool have_pict;
767 Bool started_new_pes = 0;
768 u32 start;
769 /*
770 * First thing - determine if we have enough bytes to read the header.
771 * if we do, we have the correct timestamp. If not, we read the new
772 * pes, so we'd want to use the timestamp we read.
773 */
774 sptr->frame_ts = sptr->next_pes_ts;
775 if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 4) {
776 if (sptr->pes_buffer_size != sptr->pes_buffer_on)
777 started_new_pes = 1;
778 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
779 return 0;
780 }
781 }
782 while (gf_mv12_next_start_code(sptr->pes_buffer + sptr->pes_buffer_on,
783 sptr->pes_buffer_size - sptr->pes_buffer_on,
784 &offset,
785 &scode) < 0 ||
786 (!IS_MPEG_START(scode & 0xff))) {
787 if (sptr->pes_buffer_size > 3)
788 sptr->pes_buffer_on = sptr->pes_buffer_size - 3;
789 else {
790 sptr->pes_buffer_on = sptr->pes_buffer_size;
791 started_new_pes = 1;
792 }
793 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
794 return 0;
795 }
796 }
797 sptr->pes_buffer_on += offset;
798 if (offset == 0 && started_new_pes) {
799 // nothing... we've copied the timestamp already.
800 } else {
801 // we found the new start, but we pulled in a new pes header before
802 // starting. So, we want to use the header that we read.
803 sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching
804 // clear timestamp indication
805 sptr->next_pes_ts.have_pts = sptr->next_pes_ts.have_dts = 0;
806 }
807
808 if (scode == MPEG12_PICTURE_START_CODE) {
809 sptr->pict_header_offset = sptr->pes_buffer_on;
810 have_pict = 1;
811 } else have_pict = 0;
812
813 start = 4 + sptr->pes_buffer_on;
814 while (1) {
815
816 if (gf_mv12_next_start_code(sptr->pes_buffer + start,
817 sptr->pes_buffer_size - start,
818 &offset,
819 &scode) < 0) {
820 start = sptr->pes_buffer_size - 3;
821 start -= sptr->pes_buffer_on;
822 sptr->pict_header_offset -= sptr->pes_buffer_on;
823 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
824 return 0;
825 }
826 start += sptr->pes_buffer_on;
827 sptr->pict_header_offset += sptr->pes_buffer_on;
828 } else {
829 start += offset;
830 if (have_pict == 0) {
831 if (scode == MPEG12_PICTURE_START_CODE) {
832 have_pict = 1;
833 sptr->pict_header_offset = start;
834 }
835 } else {
836 if (IS_MPEG_START(scode & 0xff) ||
837 scode == MPEG12_SEQUENCE_END_START_CODE) {
838 sptr->frame_len = start - sptr->pes_buffer_on;
839 sptr->have_frame_loaded = 1;
840 return 1;
841 }
842 }
843 start += 4;
844 }
845 }
846 return 0;
847 }
848
mpeg2ps_stream_find_ac3_frame(mpeg2ps_stream_t * sptr)849 static Bool mpeg2ps_stream_find_ac3_frame (mpeg2ps_stream_t *sptr)
850 {
851 u32 diff;
852 Bool started_new_pes = 0;
853 GF_AC3Header hdr;
854 memset(&hdr, 0, sizeof(GF_AC3Header));
855 sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching
856 if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 6) {
857 if (sptr->pes_buffer_size != sptr->pes_buffer_on)
858 started_new_pes = 1;
859 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
860 return 0;
861 }
862 }
863 while (gf_ac3_parser(sptr->pes_buffer + sptr->pes_buffer_on,
864 sptr->pes_buffer_size - sptr->pes_buffer_on,
865 &diff,
866 &hdr, 0) <= 0) {
867 // don't have frame
868 if (sptr->pes_buffer_size > 6) {
869 sptr->pes_buffer_on = sptr->pes_buffer_size - 6;
870 started_new_pes = 1;
871 } else {
872 sptr->pes_buffer_on = sptr->pes_buffer_size;
873 }
874 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
875 return 0;
876 }
877 }
878 sptr->frame_len = hdr.framesize;
879 sptr->pes_buffer_on += diff;
880 if (diff == 0 && started_new_pes) {
881 // we might have a new PTS - but it's not here
882 } else {
883 sptr->frame_ts = sptr->next_pes_ts;
884 sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
885 }
886 while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {
887 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
888 return 0;
889 }
890 }
891 sptr->have_frame_loaded = 1;
892 return 1;
893 }
894
mpeg2ps_stream_find_mp3_frame(mpeg2ps_stream_t * sptr)895 static Bool mpeg2ps_stream_find_mp3_frame (mpeg2ps_stream_t *sptr)
896 {
897 u32 diff, hdr;
898 Bool started_new_pes = 0;
899
900 sptr->frame_ts = sptr->next_pes_ts;
901 if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 4) {
902 if (sptr->pes_buffer_size != sptr->pes_buffer_on)
903 started_new_pes = 1;
904 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
905 return 0;
906 }
907 }
908 while ((hdr=gf_mp3_get_next_header_mem(sptr->pes_buffer + sptr->pes_buffer_on,
909 sptr->pes_buffer_size - sptr->pes_buffer_on,
910 &diff) ) == 0) {
911 // don't have frame
912 if (sptr->pes_buffer_size > 3) {
913 if (sptr->pes_buffer_on != sptr->pes_buffer_size) {
914 sptr->pes_buffer_on = sptr->pes_buffer_size - 3;
915 }
916 started_new_pes = 1; // we have left over bytes...
917 } else {
918 sptr->pes_buffer_on = sptr->pes_buffer_size;
919 }
920 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
921 return 0;
922 }
923 }
924 // have frame.
925 sptr->frame_len = gf_mp3_frame_size(hdr);
926 sptr->pes_buffer_on += diff;
927 if (diff == 0 && started_new_pes) {
928
929 } else {
930 sptr->frame_ts = sptr->next_pes_ts;
931 sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
932 }
933 while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {
934 if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
935 return 0;
936 }
937 }
938 sptr->have_frame_loaded = 1;
939 return 1;
940 }
941
942 /*
943 * mpeg2ps_stream_read_frame. read the correct frame based on stream type.
944 * advance_pointers is 0 when we want to use the data
945 */
mpeg2ps_stream_read_frame(mpeg2ps_stream_t * sptr,u8 ** buffer,u32 * buflen,Bool advance_pointers)946 static Bool mpeg2ps_stream_read_frame (mpeg2ps_stream_t *sptr,
947 u8 **buffer,
948 u32 *buflen,
949 Bool advance_pointers)
950 {
951 // Bool done = 0;
952 if (sptr->is_video) {
953 if (mpeg2ps_stream_find_mpeg_video_frame(sptr)) {
954 *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
955 *buflen = sptr->frame_len;
956 if (advance_pointers) {
957 sptr->pes_buffer_on += sptr->frame_len;
958 }
959 return 1;
960 }
961 return 0;
962 } else if (sptr->m_stream_id == 0xbd) {
963 // would need to handle LPCM here
964 if (mpeg2ps_stream_find_ac3_frame(sptr)) {
965 *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
966 *buflen = sptr->frame_len;
967 if (advance_pointers)
968 sptr->pes_buffer_on += sptr->frame_len;
969 return 1;
970 }
971 return 0;
972 } else if (mpeg2ps_stream_find_mp3_frame(sptr)) {
973 *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
974 *buflen = sptr->frame_len;
975 if (advance_pointers)
976 sptr->pes_buffer_on += sptr->frame_len;
977 return 1;
978 }
979 return 0;
980 }
981
982 /*
983 * get_info_from_frame - we have a frame, get the info from it.
984 */
get_info_from_frame(mpeg2ps_stream_t * sptr,u8 * buffer,u32 buflen)985 static void get_info_from_frame (mpeg2ps_stream_t *sptr,
986 u8 *buffer,
987 u32 buflen)
988 {
989 if (sptr->is_video) {
990 if (MPEG12_ParseSeqHdr(buffer, buflen,
991 &sptr->have_mpeg2,
992 &sptr->h,
993 &sptr->w,
994 &sptr->frame_rate,
995 &sptr->bit_rate,
996 &sptr->par) < 0) {
997 sptr->m_stream_id = 0;
998 sptr->m_fd = FDNULL;
999 }
1000 sptr->ticks_per_frame = (u64)(90000.0 / sptr->frame_rate);
1001 return;
1002 }
1003
1004 if (sptr->m_stream_id >= 0xc0) {
1005 // mpeg audio
1006 u32 hdr = GF_4CC((u32)buffer[0],buffer[1],buffer[2],buffer[3]);
1007
1008 sptr->channels = gf_mp3_num_channels(hdr);
1009 sptr->freq = gf_mp3_sampling_rate(hdr);
1010 sptr->samples_per_frame = gf_mp3_window_size(hdr);
1011 sptr->bitrate = gf_mp3_bit_rate(hdr) * 1000; // give bps, not kbps
1012 sptr->layer = gf_mp3_layer(hdr);
1013 } else if (sptr->m_stream_id == 0xbd) {
1014 if (sptr->m_substream_id >= 0xa0) {
1015 // PCM - ???
1016 } else if (sptr->m_substream_id >= 0x80) {
1017 u32 pos;
1018 GF_AC3Header hdr;
1019 memset(&hdr, 0, sizeof(GF_AC3Header));
1020 gf_ac3_parser(buffer, buflen, &pos, &hdr, 0);
1021 sptr->bitrate = hdr.bitrate;
1022 sptr->freq = hdr.sample_rate;
1023 sptr->channels = hdr.channels;
1024 sptr->samples_per_frame = 256 * 6;
1025 } else {
1026 return;
1027 }
1028 } else {
1029 return;
1030 }
1031 }
1032
1033 /*
1034 * clear_stream_buffer - called when we seek to clear out any data in
1035 * the buffers
1036 */
clear_stream_buffer(mpeg2ps_stream_t * sptr)1037 static void clear_stream_buffer (mpeg2ps_stream_t *sptr)
1038 {
1039 sptr->pes_buffer_on = sptr->pes_buffer_size = 0;
1040 sptr->frame_len = 0;
1041 sptr->have_frame_loaded = 0;
1042 sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
1043 sptr->frame_ts.have_dts = sptr->frame_ts.have_pts = 0;
1044 }
1045
1046 /*
1047 * convert_to_msec - convert ts (at 90000) to msec, based on base_ts and
1048 * frames_since_last_ts.
1049 */
convert_ts(mpeg2ps_stream_t * sptr,mpeg2ps_ts_type_t ts_type,u64 ts,u64 base_ts,u32 frames_since_ts)1050 static u64 convert_ts (mpeg2ps_stream_t *sptr,
1051 mpeg2ps_ts_type_t ts_type,
1052 u64 ts,
1053 u64 base_ts,
1054 u32 frames_since_ts)
1055 {
1056 u64 ret, calc;
1057 ret = ts - base_ts;
1058 if (sptr->is_video) {
1059 // video
1060 ret += frames_since_ts * sptr->ticks_per_frame;
1061 } else if (sptr->freq) {
1062 // audio
1063 calc = (frames_since_ts * 90000 * sptr->samples_per_frame) / sptr->freq;
1064 ret += calc;
1065 }
1066 if (ts_type == TS_MSEC)
1067 ret /= (u64) (90); // * 1000 / 90000
1068
1069 return ret;
1070 }
1071
1072 /*
1073 * find_stream_from_id - given the stream, get the sptr.
1074 * only used in inital set up, really. APIs use index into
1075 * video_streams and audio_streams arrays.
1076 */
find_stream_from_id(mpeg2ps_t * ps,u8 stream_id,u8 substream)1077 static mpeg2ps_stream_t *find_stream_from_id (mpeg2ps_t *ps,
1078 u8 stream_id,
1079 u8 substream)
1080 {
1081 u8 ix;
1082 if (stream_id >= 0xe0) {
1083 for (ix = 0; ix < ps->video_cnt; ix++) {
1084 if (ps->video_streams[ix]->m_stream_id == stream_id) {
1085 return ps->video_streams[ix];
1086 }
1087 }
1088 } else {
1089 for (ix = 0; ix < ps->audio_cnt; ix++) {
1090 if (ps->audio_streams[ix]->m_stream_id == stream_id &&
1091 (stream_id != 0xbd ||
1092 substream == ps->audio_streams[ix]->m_substream_id)) {
1093 return ps->audio_streams[ix];
1094 }
1095 }
1096 }
1097 return NULL;
1098 }
1099
1100 /*
1101 * add_stream - add a new stream
1102 */
add_stream(mpeg2ps_t * ps,u8 stream_id,u8 substream,s64 first_loc,mpeg2ps_ts_t * ts)1103 static Bool add_stream (mpeg2ps_t *ps,
1104 u8 stream_id,
1105 u8 substream,
1106 s64 first_loc,
1107 mpeg2ps_ts_t *ts)
1108 {
1109 mpeg2ps_stream_t *sptr;
1110
1111 sptr = find_stream_from_id(ps, stream_id, substream);
1112 if (sptr != NULL) return 0;
1113
1114 // need to add
1115
1116 sptr = mpeg2ps_stream_create(stream_id, substream);
1117 sptr->first_pes_loc = first_loc;
1118 if (ts == NULL ||
1119 (ts->have_dts == 0 && ts->have_pts == 0)) {
1120 sptr->first_pes_has_dts = 0;
1121 } else {
1122 sptr->start_dts = ts->have_dts ? ts->dts : ts->pts;
1123 sptr->first_pes_has_dts = 1;
1124 }
1125 if (sptr->is_video) {
1126 // can't be more than 16 - e0 to ef...
1127 ps->video_streams[ps->video_cnt] = sptr;
1128 ps->video_cnt++;
1129 } else {
1130 if (ps->audio_cnt >= 32) {
1131 mpeg2ps_stream_destroy(sptr);
1132 return 0;
1133 }
1134 ps->audio_streams[ps->audio_cnt] = sptr;
1135 ps->audio_cnt++;
1136 }
1137 return 1;
1138 }
1139
check_fd_for_stream(mpeg2ps_t * ps,mpeg2ps_stream_t * sptr)1140 static void check_fd_for_stream (mpeg2ps_t *ps,
1141 mpeg2ps_stream_t *sptr)
1142 {
1143 if (sptr->m_fd != FDNULL) return;
1144
1145 sptr->m_fd = file_open(ps->filename);
1146 }
1147
1148 /*
1149 * advance_frame - when we're reading frames, this indicates that we're
1150 * done. We will call this when we read a frame, but not when we
1151 * seek. It allows us to leave the last frame we're seeking in the
1152 * buffer
1153 */
advance_frame(mpeg2ps_stream_t * sptr)1154 static void advance_frame (mpeg2ps_stream_t *sptr)
1155 {
1156 sptr->pes_buffer_on += sptr->frame_len;
1157 sptr->have_frame_loaded = 0;
1158 if (sptr->frame_ts.have_dts || sptr->frame_ts.have_pts) {
1159 if (sptr->frame_ts.have_dts)
1160 sptr->last_ts = sptr->frame_ts.dts;
1161 else
1162 sptr->last_ts = sptr->frame_ts.pts;
1163 sptr->frames_since_last_ts = 0;
1164 } else {
1165 sptr->frames_since_last_ts++;
1166 }
1167 }
1168 /*
1169 * get_info_for_all_streams - loop through found streams - read an
1170 * figure out the info
1171 */
get_info_for_all_streams(mpeg2ps_t * ps)1172 static void get_info_for_all_streams (mpeg2ps_t *ps)
1173 {
1174 u8 stream_ix, max_ix, av;
1175 mpeg2ps_stream_t *sptr;
1176 u8 *buffer;
1177 u32 buflen;
1178
1179 file_seek_to(ps->fd, 0);
1180
1181 // av will be 0 for video streams, 1 for audio streams
1182 // av is just so I don't have to dup a lot of code that does the
1183 // same thing.
1184 for (av = 0; av < 2; av++) {
1185 if (av == 0) max_ix = ps->video_cnt;
1186 else max_ix = ps->audio_cnt;
1187 for (stream_ix = 0; stream_ix < max_ix; stream_ix++) {
1188 if (av == 0) sptr = ps->video_streams[stream_ix];
1189 else sptr = ps->audio_streams[stream_ix];
1190
1191 // we don't open a separate file descriptor yet (only when they
1192 // start reading or seeking). Use the one from the ps.
1193 sptr->m_fd = ps->fd; // for now
1194 clear_stream_buffer(sptr);
1195 if (mpeg2ps_stream_read_frame(sptr,
1196 &buffer,
1197 &buflen,
1198 0) == 0) {
1199 sptr->m_stream_id = 0;
1200 sptr->m_fd = FDNULL;
1201 continue;
1202 }
1203 get_info_from_frame(sptr, buffer, buflen);
1204 // here - if (sptr->first_pes_has_dts == 0) should be processed
1205 if (sptr->first_pes_has_dts == 0) {
1206 u32 frames_from_beg = 0;
1207 Bool have_frame;
1208 do {
1209 advance_frame(sptr);
1210 have_frame =
1211 mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, 0);
1212 frames_from_beg++;
1213 } while (have_frame &&
1214 sptr->frame_ts.have_dts == 0 &&
1215 sptr->frame_ts.have_pts == 0 &&
1216 frames_from_beg < 1000);
1217 if (have_frame == 0 ||
1218 (sptr->frame_ts.have_dts == 0 &&
1219 sptr->frame_ts.have_pts == 0)) {
1220 } else {
1221 sptr->start_dts = sptr->frame_ts.have_dts ? sptr->frame_ts.dts :
1222 sptr->frame_ts.pts;
1223 if (sptr->is_video) {
1224 sptr->start_dts -= frames_from_beg * sptr->ticks_per_frame;
1225 } else {
1226 u64 conv;
1227 conv = sptr->samples_per_frame * 90000;
1228 conv /= (u64)sptr->freq;
1229 sptr->start_dts -= conv;
1230 }
1231 }
1232 }
1233 clear_stream_buffer(sptr);
1234 sptr->m_fd = FDNULL;
1235 }
1236 }
1237 }
1238
1239 /*
1240 * mpeg2ps_scan_file - read file, grabbing all the information that
1241 * we can out of it (what streams exist, timing, etc).
1242 */
mpeg2ps_scan_file(mpeg2ps_t * ps)1243 static void mpeg2ps_scan_file (mpeg2ps_t *ps)
1244 {
1245 u8 stream_id, stream_ix, substream, av_ix, max_cnt;
1246 u16 pes_len, pes_left;
1247 mpeg2ps_ts_t ts;
1248 s64 loc, first_video_loc = 0, first_audio_loc = 0;
1249 s64 check, orig_check;
1250 mpeg2ps_stream_t *sptr;
1251 Bool valid_stream;
1252 u8 *buffer;
1253 u32 buflen;
1254 Bool have_ts;
1255
1256 ps->end_loc = file_size(ps->fd);
1257 orig_check = check = MAX(ps->end_loc / 50, 200 * 1024);
1258
1259 /*
1260 * This part reads and finds the streams. We check up until we
1261 * find audio and video plus a little, with a max of either 200K or
1262 * the file size / 50
1263 */
1264 loc = 0;
1265 while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len) &&
1266 loc < check) {
1267 pes_left = pes_len;
1268 if (stream_id >= 0xbd && stream_id < 0xf0) {
1269 loc = file_location(ps->fd) - 6;
1270 if (read_pes_header_data(ps->fd,
1271 pes_len,
1272 &pes_left,
1273 &have_ts,
1274 &ts) == 0) {
1275 return;
1276 }
1277 valid_stream = 0;
1278 substream = 0;
1279 if (stream_id == 0xbd) {
1280 if (file_read_bytes(ps->fd, &substream, 1) == 0) {
1281 return;
1282 }
1283 pes_left--; // remove byte we just read
1284 if ((substream >= 0x80 && substream < 0x90) ||
1285 (substream >= 0xa0 && substream < 0xb0)) {
1286 valid_stream = 1;
1287 }
1288 } else if (stream_id >= 0xc0) {
1289 // audio and video
1290 valid_stream = 1;
1291 }
1292 if (valid_stream) {
1293 if (add_stream(ps, stream_id, substream, loc, &ts)) {
1294 // added
1295 if (stream_id >= 0xe0) {
1296 if (ps->video_cnt == 1) {
1297 first_video_loc = loc;
1298 }
1299 } else if (ps->audio_cnt == 1) {
1300 first_audio_loc = loc;
1301 }
1302 if (ps->audio_cnt > 0 && ps->video_cnt > 0) {
1303 s64 diff;
1304 if (first_audio_loc > first_video_loc)
1305 diff = first_audio_loc - first_video_loc;
1306 else
1307 diff = first_video_loc - first_audio_loc;
1308 diff *= 2;
1309 diff += first_video_loc;
1310 if (diff < check) {
1311 check = diff;
1312 }
1313 }
1314 }
1315 }
1316 }
1317 file_skip_bytes(ps->fd, pes_left);
1318 }
1319 if (ps->video_cnt == 0 && ps->audio_cnt == 0) {
1320 return;
1321 }
1322 /*
1323 * Now, we go to close to the end, and try to find the last
1324 * dts that we can
1325 */
1326 file_seek_to(ps->fd, ps->end_loc - orig_check);
1327
1328 while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len)) {
1329 loc = file_location(ps->fd) - 6;
1330 if (stream_id == 0xbd || (stream_id >= 0xc0 && stream_id < 0xf0)) {
1331 if (read_pes_header_data(ps->fd,
1332 pes_len,
1333 &pes_left,
1334 &have_ts,
1335 &ts) == 0) {
1336 return;
1337 }
1338 if (stream_id == 0xbd) {
1339 if (file_read_bytes(ps->fd, &substream, 1) == 0) {
1340 return;
1341 }
1342 pes_left--; // remove byte we just read
1343 if (!((substream >= 0x80 && substream < 0x90) ||
1344 (substream >= 0xa0 && substream < 0xb0))) {
1345 file_skip_bytes(ps->fd, pes_left);
1346 continue;
1347 }
1348 } else {
1349 substream = 0;
1350 }
1351 sptr = find_stream_from_id(ps, stream_id, substream);
1352 if (sptr == NULL) {
1353 add_stream(ps, stream_id, substream, 0, NULL);
1354 sptr = find_stream_from_id(ps, stream_id, substream);
1355 }
1356 if (sptr != NULL && have_ts) {
1357 sptr->end_dts = ts.have_dts ? ts.dts : ts.pts;
1358 sptr->end_dts_loc = loc;
1359 }
1360 file_skip_bytes(ps->fd, pes_left);
1361 }
1362 }
1363
1364 /*
1365 * Now, get the info for all streams, so we can use it again
1366 * we could do this before the above, I suppose
1367 */
1368 get_info_for_all_streams(ps);
1369
1370 ps->first_dts = (u64) -1;
1371
1372 /*
1373 * we need to find the earliest start pts - we use that to calc
1374 * the rest of the timing, so we're 0 based.
1375 */
1376 for (av_ix = 0; av_ix < 2; av_ix++) {
1377 if (av_ix == 0) max_cnt = ps->video_cnt;
1378 else max_cnt = ps->audio_cnt;
1379
1380 for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {
1381 sptr = av_ix == 0 ? ps->video_streams[stream_ix] :
1382 ps->audio_streams[stream_ix];
1383 if (sptr != NULL && sptr->start_dts < ps->first_dts) {
1384 ps->first_dts = sptr->start_dts;
1385 }
1386 }
1387 }
1388
1389 /*
1390 * Now, for each thread, we'll start at the last pts location, and
1391 * read the number of frames. This will give us a max time
1392 */
1393 for (av_ix = 0; av_ix < 2; av_ix++) {
1394 if (av_ix == 0) max_cnt = ps->video_cnt;
1395 else max_cnt = ps->audio_cnt;
1396 for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {
1397 u32 frame_cnt_since_last;
1398 sptr = av_ix == 0 ? ps->video_streams[stream_ix] :
1399 ps->audio_streams[stream_ix];
1400
1401 // pick up here - find the final time...
1402 if (sptr && (sptr->end_dts_loc != 0)) {
1403 file_seek_to(ps->fd, sptr->end_dts_loc);
1404 sptr->m_fd = ps->fd;
1405 frame_cnt_since_last = 0;
1406 clear_stream_buffer(sptr);
1407 while (mpeg2ps_stream_read_frame(sptr,
1408 &buffer,
1409 &buflen,
1410 1)) {
1411 frame_cnt_since_last++;
1412 }
1413 sptr->m_fd = FDNULL;
1414 clear_stream_buffer(sptr);
1415 ps->max_time = MAX(ps->max_time,
1416 convert_ts(sptr,
1417 TS_MSEC,
1418 sptr->end_dts,
1419 ps->first_dts,
1420 frame_cnt_since_last));
1421 }
1422 }
1423 }
1424
1425 ps->max_dts = (ps->max_time * 90) + ps->first_dts;
1426 file_seek_to(ps->fd, 0);
1427 }
1428
1429 /*************************************************************************
1430 * API routines
1431 *************************************************************************/
mpeg2ps_get_max_time_msec(mpeg2ps_t * ps)1432 u64 mpeg2ps_get_max_time_msec (mpeg2ps_t *ps)
1433 {
1434 return ps->max_time;
1435 }
1436
mpeg2ps_get_video_stream_count(mpeg2ps_t * ps)1437 u32 mpeg2ps_get_video_stream_count (mpeg2ps_t *ps)
1438 {
1439 return ps->video_cnt;
1440 }
1441
1442 #define NUM_ELEMENTS_IN_ARRAY(name) ((sizeof((name))) / (sizeof(*(name))))
1443
1444 // routine to check stream number passed.
invalid_video_streamno(mpeg2ps_t * ps,u32 streamno)1445 static Bool invalid_video_streamno (mpeg2ps_t *ps, u32 streamno)
1446 {
1447 if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->video_streams)) return 1;
1448 if (ps->video_streams[streamno] == NULL) return 1;
1449 return 0;
1450 }
1451
1452 #if 0 //unused
1453 const char *mpeg2ps_get_video_stream_name (mpeg2ps_t *ps, u32 streamno)
1454 {
1455 if (invalid_video_streamno(ps, streamno)) {
1456 return 0;
1457 }
1458 if (ps->video_streams[streamno]->have_mpeg2) {
1459 return "Mpeg-2";
1460 }
1461 return "Mpeg-1";
1462 }
1463 #endif
1464
mpeg2ps_get_video_stream_type(mpeg2ps_t * ps,u32 streamno)1465 mpeg2ps_video_type_t mpeg2ps_get_video_stream_type (mpeg2ps_t *ps,
1466 u32 streamno)
1467 {
1468 if (invalid_video_streamno(ps, streamno)) {
1469 return MPEG_VIDEO_UNKNOWN;
1470 }
1471 return ps->video_streams[streamno]->have_mpeg2 ? MPEG_VIDEO_MPEG2 : MPEG_VIDEO_MPEG1;
1472 }
1473
mpeg2ps_get_video_stream_width(mpeg2ps_t * ps,u32 streamno)1474 u32 mpeg2ps_get_video_stream_width (mpeg2ps_t *ps, u32 streamno)
1475 {
1476 if (invalid_video_streamno(ps, streamno)) {
1477 return 0;
1478 }
1479 return ps->video_streams[streamno]->w;
1480 }
1481
mpeg2ps_get_video_stream_height(mpeg2ps_t * ps,u32 streamno)1482 u32 mpeg2ps_get_video_stream_height (mpeg2ps_t *ps, u32 streamno)
1483 {
1484 if (invalid_video_streamno(ps, streamno)) {
1485 return 0;
1486 }
1487 return ps->video_streams[streamno]->h;
1488 }
1489
mpeg2ps_get_video_stream_aspect_ratio(mpeg2ps_t * ps,u32 streamno)1490 u32 mpeg2ps_get_video_stream_aspect_ratio (mpeg2ps_t *ps, u32 streamno)
1491 {
1492 if (invalid_video_streamno(ps, streamno)) {
1493 return 0;
1494 }
1495 return ps->video_streams[streamno]->par;
1496 }
1497
mpeg2ps_get_video_stream_bitrate(mpeg2ps_t * ps,u32 streamno)1498 Double mpeg2ps_get_video_stream_bitrate (mpeg2ps_t *ps, u32 streamno)
1499 {
1500 if (invalid_video_streamno(ps, streamno)) {
1501 return 0;
1502 }
1503 return ps->video_streams[streamno]->bit_rate;
1504 }
1505
mpeg2ps_get_video_stream_framerate(mpeg2ps_t * ps,u32 streamno)1506 Double mpeg2ps_get_video_stream_framerate (mpeg2ps_t *ps, u32 streamno)
1507 {
1508 if (invalid_video_streamno(ps, streamno)) {
1509 return 0;
1510 }
1511 return ps->video_streams[streamno]->frame_rate;
1512 }
1513
mpeg2ps_get_video_stream_id(mpeg2ps_t * ps,u32 streamno)1514 u32 mpeg2ps_get_video_stream_id(mpeg2ps_t *ps, u32 streamno)
1515 {
1516 if (invalid_video_streamno(ps, streamno)) {
1517 return 0;
1518 }
1519 return ps->video_streams[streamno]->m_stream_id;
1520 }
1521
invalid_audio_streamno(mpeg2ps_t * ps,u32 streamno)1522 static Bool invalid_audio_streamno (mpeg2ps_t *ps, u32 streamno)
1523 {
1524 if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->audio_streams)) return 1;
1525 if (ps->audio_streams[streamno] == NULL) return 1;
1526 return 0;
1527 }
1528
mpeg2ps_get_audio_stream_count(mpeg2ps_t * ps)1529 u32 mpeg2ps_get_audio_stream_count (mpeg2ps_t *ps)
1530 {
1531 return ps->audio_cnt;
1532 }
1533
1534 #if 0 //unused
1535 const char *mpeg2ps_get_audio_stream_name (mpeg2ps_t *ps,
1536 u32 streamno)
1537 {
1538 if (invalid_audio_streamno(ps, streamno)) {
1539 return "none";
1540 }
1541 if (ps->audio_streams[streamno]->m_stream_id >= 0xc0) {
1542 switch (ps->audio_streams[streamno]->layer) {
1543 case 1:
1544 return "MP1";
1545 case 2:
1546 return "MP2";
1547 case 3:
1548 return "MP3";
1549 }
1550 return "unknown mpeg layer";
1551 }
1552 if (ps->audio_streams[streamno]->m_substream_id >= 0x80 &&
1553 ps->audio_streams[streamno]->m_substream_id < 0x90)
1554 return "AC3";
1555
1556 return "LPCM";
1557 }
1558 #endif
1559
mpeg2ps_get_audio_stream_type(mpeg2ps_t * ps,u32 streamno)1560 mpeg2ps_audio_type_t mpeg2ps_get_audio_stream_type (mpeg2ps_t *ps,
1561 u32 streamno)
1562 {
1563 if (invalid_audio_streamno(ps, streamno)) {
1564 return MPEG_AUDIO_UNKNOWN;
1565 }
1566 if (ps->audio_streams[streamno]->m_stream_id >= 0xc0) {
1567 return MPEG_AUDIO_MPEG;
1568 }
1569 if (ps->audio_streams[streamno]->m_substream_id >= 0x80 &&
1570 ps->audio_streams[streamno]->m_substream_id < 0x90)
1571 return MPEG_AUDIO_AC3;
1572
1573 return MPEG_AUDIO_LPCM;
1574 }
1575
mpeg2ps_get_audio_stream_sample_freq(mpeg2ps_t * ps,u32 streamno)1576 u32 mpeg2ps_get_audio_stream_sample_freq (mpeg2ps_t *ps, u32 streamno)
1577 {
1578 if (invalid_audio_streamno(ps, streamno)) {
1579 return 0;
1580 }
1581 return ps->audio_streams[streamno]->freq;
1582 }
1583
mpeg2ps_get_audio_stream_channels(mpeg2ps_t * ps,u32 streamno)1584 u32 mpeg2ps_get_audio_stream_channels (mpeg2ps_t *ps, u32 streamno)
1585 {
1586 if (invalid_audio_streamno(ps, streamno)) {
1587 return 0;
1588 }
1589 return ps->audio_streams[streamno]->channels;
1590 }
1591
mpeg2ps_get_audio_stream_bitrate(mpeg2ps_t * ps,u32 streamno)1592 u32 mpeg2ps_get_audio_stream_bitrate (mpeg2ps_t *ps, u32 streamno)
1593 {
1594 if (invalid_audio_streamno(ps, streamno)) {
1595 return 0;
1596 }
1597 return ps->audio_streams[streamno]->bitrate;
1598 }
1599
mpeg2ps_get_audio_stream_id(mpeg2ps_t * ps,u32 streamno)1600 u32 mpeg2ps_get_audio_stream_id (mpeg2ps_t *ps, u32 streamno)
1601 {
1602 if (invalid_audio_streamno(ps, streamno)) {
1603 return 0;
1604 }
1605 return ps->audio_streams[streamno]->m_stream_id;
1606 }
1607
1608
mpeg2ps_init(const char * filename)1609 mpeg2ps_t *mpeg2ps_init (const char *filename)
1610 {
1611 mpeg2ps_t *ps;
1612 GF_SAFEALLOC(ps, mpeg2ps_t);
1613
1614 if (ps == NULL) {
1615 return NULL;
1616 }
1617 memset(ps, 0, sizeof(*ps));
1618 ps->fd = file_open(filename);
1619 if (file_okay(ps->fd) == 0) {
1620 gf_free(ps);
1621 return NULL;
1622 }
1623
1624 ps->filename = gf_strdup(filename);
1625 mpeg2ps_scan_file(ps);
1626 if (ps->video_cnt == 0 && ps->audio_cnt == 0) {
1627 mpeg2ps_close(ps);
1628 return NULL;
1629 }
1630 return ps;
1631 }
1632
mpeg2ps_close(mpeg2ps_t * ps)1633 void mpeg2ps_close (mpeg2ps_t *ps)
1634 {
1635 u32 ix;
1636 if (ps == NULL) return;
1637 for (ix = 0; ix < ps->video_cnt; ix++) {
1638 mpeg2ps_stream_destroy(ps->video_streams[ix]);
1639 ps->video_streams[ix] = NULL;
1640 }
1641 for (ix = 0; ix < ps->audio_cnt; ix++) {
1642 mpeg2ps_stream_destroy(ps->audio_streams[ix]);
1643 ps->audio_streams[ix] = NULL;
1644 }
1645
1646 if (ps->filename) gf_free(ps->filename);
1647 if (ps->fd) file_close(ps->fd);
1648 gf_free(ps);
1649 }
1650
1651 /*
1652 * check_fd_for_stream will make sure we have a fd for the stream we're
1653 * trying to read - we use a different fd for each stream
1654 */
1655
1656 /*
1657 * stream_convert_frame_ts_to_msec - given a "read" frame, we'll
1658 * calculate the msec and freq timestamps. This can be called more
1659 * than 1 time, if needed, without changing any variables, such as
1660 * frames_since_last_ts, which gets updated in advance_frame
1661 */
stream_convert_frame_ts_to_msec(mpeg2ps_stream_t * sptr,mpeg2ps_ts_type_t ts_type,u64 base_dts,u32 * freq_ts)1662 static u64 stream_convert_frame_ts_to_msec (mpeg2ps_stream_t *sptr,
1663 mpeg2ps_ts_type_t ts_type,
1664 u64 base_dts,
1665 u32 *freq_ts)
1666 {
1667 u64 calc_ts;
1668 u32 frames_since_last = 0;
1669 u64 freq_conv;
1670
1671 calc_ts = sptr->last_ts;
1672 if (sptr->frame_ts.have_dts) calc_ts = sptr->frame_ts.dts;
1673 else if (sptr->frame_ts.have_pts) calc_ts = sptr->frame_ts.dts;
1674 else frames_since_last = sptr->frames_since_last_ts + 1;
1675
1676 if (freq_ts != NULL) {
1677 freq_conv = calc_ts - base_dts;
1678 freq_conv *= sptr->freq;
1679 freq_conv /= 90000;
1680 freq_conv += frames_since_last * sptr->samples_per_frame;
1681 *freq_ts = (u32) (freq_conv & 0xffffffff);
1682 }
1683 return convert_ts(sptr, ts_type, calc_ts, base_dts, frames_since_last);
1684 }
1685
1686 /*
1687 * mpeg2ps_get_video_frame - gets the next frame
1688 */
mpeg2ps_get_video_frame(mpeg2ps_t * ps,u32 streamno,u8 ** buffer,u32 * buflen,u8 * frame_type,mpeg2ps_ts_type_t ts_type,u64 * decode_timestamp,u64 * compose_timestamp)1689 Bool mpeg2ps_get_video_frame(mpeg2ps_t *ps, u32 streamno,
1690 u8 **buffer,
1691 u32 *buflen,
1692 u8 *frame_type,
1693 mpeg2ps_ts_type_t ts_type,
1694 u64 *decode_timestamp, u64 *compose_timestamp)
1695 {
1696 u64 dts, cts;
1697 mpeg2ps_stream_t *sptr;
1698 if (invalid_video_streamno(ps, streamno)) return 0;
1699
1700 sptr = ps->video_streams[streamno];
1701 check_fd_for_stream(ps, sptr);
1702
1703 if (sptr->have_frame_loaded == 0) {
1704 // if we don't have the frame in the buffer (like after a seek),
1705 // read the next frame
1706 if (mpeg2ps_stream_find_mpeg_video_frame(sptr) == 0) {
1707 return 0;
1708 }
1709 }
1710 *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
1711 *buflen = sptr->frame_len;
1712 // determine frame type
1713 if (frame_type != NULL) {
1714 *frame_type = MPEG12_PictHdrType(sptr->pes_buffer +
1715 sptr->pict_header_offset);
1716 }
1717
1718 // set the timestamps
1719 if (sptr->frame_ts.have_pts)
1720 cts = sptr->frame_ts.pts;
1721 else
1722 cts = sptr->last_ts + (1+sptr->frames_since_last_ts) * sptr->ticks_per_frame;
1723 if (sptr->frame_ts.have_dts)
1724 dts = sptr->frame_ts.dts;
1725 else
1726 dts = cts;
1727
1728 if (decode_timestamp) *decode_timestamp = dts;
1729 if (compose_timestamp) *compose_timestamp = cts;
1730
1731 //indicate that we read this frame - get ready for the next one.
1732 advance_frame(sptr);
1733
1734
1735 return 1;
1736 }
1737
1738
1739 // see above comments
mpeg2ps_get_audio_frame(mpeg2ps_t * ps,u32 streamno,u8 ** buffer,u32 * buflen,mpeg2ps_ts_type_t ts_type,u32 * freq_timestamp,u64 * timestamp)1740 Bool mpeg2ps_get_audio_frame(mpeg2ps_t *ps, u32 streamno,
1741 u8 **buffer,
1742 u32 *buflen,
1743 mpeg2ps_ts_type_t ts_type,
1744 u32 *freq_timestamp,
1745 u64 *timestamp)
1746 {
1747 mpeg2ps_stream_t *sptr;
1748 if (invalid_audio_streamno(ps, streamno)) return 0;
1749
1750 sptr = ps->audio_streams[streamno];
1751 check_fd_for_stream(ps, sptr);
1752
1753 if (sptr->have_frame_loaded == 0) {
1754 if (mpeg2ps_stream_read_frame(sptr, buffer, buflen, 0) == 0)
1755 return 0;
1756 }
1757
1758 if (freq_timestamp) {
1759 /*ts = */stream_convert_frame_ts_to_msec(sptr,
1760 ts_type,
1761 ps->first_dts,
1762 freq_timestamp);
1763 }
1764 if (timestamp != NULL) {
1765 *timestamp = sptr->frame_ts.have_pts ? sptr->frame_ts.pts : sptr->frame_ts.dts;
1766 }
1767 advance_frame(sptr);
1768 return 1;
1769 }
1770
1771 #if 0 //unused
1772 u64 mpeg2ps_get_ps_size(mpeg2ps_t *ps)
1773 {
1774 return file_size(ps->fd);
1775 }
1776 s64 mpeg2ps_get_video_pos(mpeg2ps_t *ps, u32 streamno)
1777 {
1778 if (invalid_video_streamno(ps, streamno)) return 0;
1779 return gf_ftell(ps->video_streams[streamno]->m_fd);
1780 }
1781 s64 mpeg2ps_get_audio_pos(mpeg2ps_t *ps, u32 streamno)
1782 {
1783 if (invalid_audio_streamno(ps, streamno)) return 0;
1784 return gf_ftell(ps->audio_streams[streamno]->m_fd);
1785 }
1786 #endif
1787
1788
1789 /***************************************************************************
1790 * seek routines
1791 ***************************************************************************/
1792 /*
1793 * mpeg2ps_binary_seek - look for a pts that's close to the one that
1794 * we're looking for. We have a start ts and location, an end ts and
1795 * location, and what we're looking for
1796 */
mpeg2ps_binary_seek(mpeg2ps_t * ps,mpeg2ps_stream_t * sptr,u64 search_dts,u64 start_dts,u64 start_loc,u64 end_dts,u64 end_loc)1797 static void mpeg2ps_binary_seek (mpeg2ps_t *ps,
1798 mpeg2ps_stream_t *sptr,
1799 u64 search_dts,
1800 u64 start_dts,
1801 u64 start_loc,
1802 u64 end_dts,
1803 u64 end_loc)
1804 {
1805 u64 dts_perc;
1806 u64 loc;
1807 u16 pes_len;
1808 Bool have_ts = GF_FALSE;
1809 u64 found_loc;
1810 u64 found_dts;
1811
1812 while (1) {
1813 /*
1814 * It's not a binary search as much as using a percentage between
1815 * the start and end dts to start. We subtract off a bit, so we
1816 * approach from the beginning of the file - we're more likely to
1817 * hit a pts that way
1818 */
1819 dts_perc = (search_dts - start_dts) * 1000 / (end_dts - start_dts);
1820 dts_perc -= dts_perc % 10;
1821
1822 loc = ((end_loc - start_loc) * dts_perc) / 1000;
1823
1824 if (loc == start_loc || loc == end_loc) return;
1825
1826 clear_stream_buffer(sptr);
1827 file_seek_to(sptr->m_fd, start_loc + loc);
1828
1829 // we'll look for the next pes header for this stream that has a ts.
1830 do {
1831 if (search_for_next_pes_header(sptr,
1832 &pes_len,
1833 &have_ts,
1834 &found_loc) == GF_FALSE) {
1835 return;
1836 }
1837 if (have_ts == GF_FALSE) {
1838 file_skip_bytes(sptr->m_fd, pes_len);
1839 }
1840 } while (have_ts == GF_FALSE);
1841
1842 // record that spot...
1843 mpeg2ps_record_pts(sptr, found_loc, &sptr->next_pes_ts);
1844
1845 found_dts = sptr->next_pes_ts.have_dts ?
1846 sptr->next_pes_ts.dts : sptr->next_pes_ts.pts;
1847 /*
1848 * Now, if we're before the search ts, and within 5 seconds,
1849 * we'll say we're close enough
1850 */
1851 if (found_dts + (5 * 90000) > search_dts &&
1852 found_dts < search_dts) {
1853 file_seek_to(sptr->m_fd, found_loc);
1854 return; // found it - we can seek from here
1855 }
1856 /*
1857 * otherwise, move the head or the tail (most likely the head).
1858 */
1859 if (found_dts > search_dts) {
1860 if (found_dts >= end_dts) {
1861 file_seek_to(sptr->m_fd, found_loc);
1862 return;
1863 }
1864 end_loc = found_loc;
1865 end_dts = found_dts;
1866 } else {
1867 if (found_dts <= start_dts) {
1868 file_seek_to(sptr->m_fd, found_loc);
1869 return;
1870 }
1871 start_loc = found_loc;
1872 start_dts = found_dts;
1873 }
1874 }
1875 }
1876
1877
1878
search_for_ts(mpeg2ps_stream_t * sptr,u64 dts)1879 static mpeg2ps_record_pes_t *search_for_ts (mpeg2ps_stream_t *sptr,
1880 u64 dts)
1881 {
1882 mpeg2ps_record_pes_t *p, *q;
1883 u64 p_diff, q_diff;
1884 if (sptr->record_last == NULL) return NULL;
1885
1886 if (dts > sptr->record_last->dts) return sptr->record_last;
1887
1888 if (dts < sptr->record_first->dts) return NULL;
1889 if (dts == sptr->record_first->dts) return sptr->record_first;
1890
1891 p = sptr->record_first;
1892 q = p->next_rec;
1893
1894 while (q != NULL && q->dts > dts) {
1895 p = q;
1896 q = q->next_rec;
1897 }
1898 if (q == NULL) {
1899 return sptr->record_last;
1900 }
1901
1902 p_diff = dts - p->dts;
1903 q_diff = q->dts - dts;
1904
1905 if (p_diff < q_diff) return p;
1906 if (q_diff > 90000) return p;
1907
1908 return q;
1909 }
1910
1911
1912 /*
1913 * mpeg2ps_seek_frame - seek to the next timestamp after the search timestamp
1914 * First, find a close DTS (usually minus 5 seconds or closer), then
1915 * read frames until we get the frame after the timestamp.
1916 */
mpeg2ps_seek_frame(mpeg2ps_t * ps,mpeg2ps_stream_t * sptr,u64 search_msec_timestamp)1917 static Bool mpeg2ps_seek_frame (mpeg2ps_t *ps,
1918 mpeg2ps_stream_t *sptr,
1919 u64 search_msec_timestamp)
1920 {
1921 u64 dts;
1922 mpeg2ps_record_pes_t *rec;
1923 u64 msec_ts;
1924 u8 *buffer;
1925 u32 buflen;
1926
1927 check_fd_for_stream(ps, sptr);
1928 clear_stream_buffer(sptr);
1929
1930 if (search_msec_timestamp <= 1000) { // first second, start from begin...
1931 file_seek_to(sptr->m_fd, sptr->first_pes_loc);
1932 return GF_TRUE;
1933 }
1934 dts = search_msec_timestamp * 90; // 1000 timescale to 90000 timescale
1935 dts += ps->first_dts;
1936
1937 /*
1938 * see if the recorded data has anything close
1939 */
1940 rec = search_for_ts(sptr, dts);
1941 if (rec != NULL) {
1942 // see if it is close
1943 // if we're plus or minus a second, seek to that.
1944 if (rec->dts + 90000 >= dts && rec->dts <= dts + 90000) {
1945 file_seek_to(sptr->m_fd, rec->location);
1946 return GF_TRUE;
1947 }
1948 // at this point, rec is > a distance. If within 5 or so seconds,
1949
1950 if (rec->dts + (5 * 90000) < dts) {
1951 // more than 5 seconds away - skip and search
1952 if (rec->next_rec == NULL) {
1953 mpeg2ps_binary_seek(ps, sptr, dts,
1954 rec->dts, rec->location,
1955 sptr->end_dts, sptr->end_dts_loc);
1956 } else {
1957 mpeg2ps_binary_seek(ps, sptr, dts,
1958 rec->dts, rec->location,
1959 rec->next_rec->dts, rec->next_rec->location);
1960 }
1961 }
1962 // otherwise, frame by frame search...
1963 } else {
1964 // we weren't able to find anything from the recording
1965 mpeg2ps_binary_seek(ps, sptr, dts,
1966 sptr->start_dts, sptr->first_pes_loc,
1967 sptr->end_dts, sptr->end_dts_loc);
1968 }
1969 /*
1970 * Now, the fun part - read frames until we're just past the time
1971 */
1972 clear_stream_buffer(sptr); // clear out any data, so we can read it
1973 do {
1974 if (mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, GF_FALSE) == GF_FALSE)
1975 return GF_FALSE;
1976
1977 msec_ts = stream_convert_frame_ts_to_msec(sptr, TS_MSEC,
1978 ps->first_dts, NULL);
1979
1980 if (msec_ts < search_msec_timestamp) {
1981 // only advance the frame if we're not greater than the timestamp
1982 advance_frame(sptr);
1983 }
1984 } while (msec_ts < search_msec_timestamp);
1985
1986 return GF_TRUE;
1987 }
1988
1989
1990 /*
1991 * mpeg2ps_seek_video_frame - seek to the location that we're interested
1992 * in, then scroll up to the next I frame
1993 */
mpeg2ps_seek_video_frame(mpeg2ps_t * ps,u32 streamno,u64 msec_timestamp)1994 Bool mpeg2ps_seek_video_frame (mpeg2ps_t *ps, u32 streamno,
1995 u64 msec_timestamp)
1996 {
1997 mpeg2ps_stream_t *sptr;
1998
1999 if (invalid_video_streamno(ps, streamno)) return GF_FALSE;
2000
2001 sptr = ps->video_streams[streamno];
2002 if (mpeg2ps_seek_frame(ps,
2003 sptr,
2004 msec_timestamp)
2005 == GF_FALSE) return GF_FALSE;
2006
2007 if (sptr->have_frame_loaded == GF_FALSE) {
2008 return GF_FALSE;
2009 }
2010 return GF_TRUE;
2011 }
2012 /*
2013 * mpeg2ps_seek_audio_frame - go to the closest audio frame after the
2014 * timestamp
2015 */
mpeg2ps_seek_audio_frame(mpeg2ps_t * ps,u32 streamno,u64 msec_timestamp)2016 Bool mpeg2ps_seek_audio_frame (mpeg2ps_t *ps,
2017 u32 streamno,
2018 u64 msec_timestamp)
2019 {
2020 // off_t closest_pes;
2021 mpeg2ps_stream_t *sptr;
2022
2023 if (invalid_audio_streamno(ps, streamno)) return GF_FALSE;
2024
2025 sptr = ps->audio_streams[streamno];
2026 if (mpeg2ps_seek_frame(ps,
2027 sptr,
2028 msec_timestamp) == GF_FALSE) return GF_FALSE;
2029
2030 return GF_TRUE;
2031 }
2032
mpeg2ps_get_first_cts(mpeg2ps_t * ps)2033 u64 mpeg2ps_get_first_cts(mpeg2ps_t *ps)
2034 {
2035 return ps->first_dts;
2036 }
2037
2038
2039 #endif /*GPAC_DISABLE_MPEG2PS*/
2040