Line data Source code
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 :
30 : static GFINLINE u16 convert16 (u8 *p)
31 : {
32 : #ifdef GPAC_BIG_ENDIAN
33 : return *(u16 *)p;
34 : #else
35 22829 : u16 val = p[0];
36 22829 : val <<= 8;
37 22829 : return (val | p[1]);
38 : #endif
39 : }
40 :
41 : static GFINLINE u32 convert32 (u8 *p)
42 : {
43 : #ifdef GPAC_BIG_ENDIAN
44 : return *(u32 *)p;
45 : #else
46 : u32 val;
47 26986 : val = p[0];
48 26986 : val <<= 8;
49 26986 : val |= p[1];
50 26986 : val <<= 8;
51 26986 : val |= p[2];
52 26986 : val <<= 8;
53 26986 : 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 : *************************************************************************/
144 : static FILE *file_open (const char *name)
145 : {
146 19 : return gf_fopen(name, "rb");
147 : }
148 :
149 : static Bool file_okay (FILE *fd)
150 : {
151 : return (fd!=NULL) ? 1 : 0;
152 : }
153 :
154 : static void file_close (FILE *fd)
155 : {
156 19 : gf_fclose(fd);
157 : }
158 :
159 : static Bool file_read_bytes(FILE *fd,
160 : u8 *buffer,
161 : u32 len)
162 : {
163 96347 : u32 readval = (u32) gf_fread(buffer, len, fd);
164 : return readval == len;
165 : }
166 :
167 : // note: len could be negative.
168 : static void file_skip_bytes (FILE *fd, s32 len)
169 : {
170 27457 : 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 :
176 : static u64 file_size(FILE *fd)
177 : {
178 7 : return gf_fsize(fd);
179 : }
180 :
181 72 : static mpeg2ps_record_pes_t *create_record (s64 loc, u64 ts)
182 : {
183 : mpeg2ps_record_pes_t *ret;
184 72 : GF_SAFEALLOC(ret, mpeg2ps_record_pes_t);
185 72 : if (!ret) return NULL;
186 72 : ret->next_rec = NULL;
187 72 : ret->dts = ts;
188 72 : ret->location = loc;
189 72 : return ret;
190 : }
191 :
192 : #define MPEG2PS_RECORD_TIME ((u64) (5 * 90000))
193 6241 : 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 6241 : if (sptr->is_video) {
198 5251 : if (pTs->have_dts == 0) return;
199 748 : ts = pTs->dts;
200 : } else {
201 990 : if (pTs->have_pts == 0) return;
202 989 : ts = pTs->pts;
203 : }
204 :
205 1737 : if (sptr->record_first == NULL) {
206 12 : sptr->record_first = sptr->record_last = create_record(location, ts);
207 12 : return;
208 : }
209 1725 : if (ts > sptr->record_last->dts) {
210 749 : if (ts < MPEG2PS_RECORD_TIME + sptr->record_last->dts) return;
211 32 : sptr->record_last->next_rec = create_record(location, ts);
212 32 : sptr->record_last = sptr->record_last->next_rec;
213 32 : return;
214 : }
215 976 : if (ts < sptr->record_first->dts) {
216 5 : if (ts < MPEG2PS_RECORD_TIME + sptr->record_first->dts) return;
217 0 : p = create_record(location, ts);
218 0 : p->next_rec = sptr->record_first;
219 0 : sptr->record_first = p;
220 0 : return;
221 : }
222 : p = sptr->record_first;
223 971 : q = p->next_rec;
224 :
225 5302 : while (q != NULL && q->dts < ts) {
226 : p = q;
227 3360 : q = q->next_rec;
228 : }
229 971 : if (q) {
230 997 : if (p->dts + MPEG2PS_RECORD_TIME <= ts &&
231 32 : ts + MPEG2PS_RECORD_TIME <= q->dts) {
232 28 : p->next_rec = create_record(location, ts);
233 28 : 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
259 5 : 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 5 : *have_mpeg2 = 0;
269 5 : buflen -= 6;
270 : bitrate_int = 0;
271 805 : for (ix = 0; ix < buflen; ix++, pbuffer++) {
272 1610 : scode = ((u32)pbuffer[0] << 24) | (pbuffer[1] << 16) | (pbuffer[2] << 8) |
273 805 : pbuffer[3];
274 :
275 805 : if (scode == MPEG12_SEQUENCE_START_CODE) {
276 : pbuffer += sizeof(u32);
277 5 : *width = (pbuffer[0]);
278 5 : *width <<= 4;
279 5 : *width |= ((pbuffer[1] >> 4) &0xf);
280 5 : *height = (pbuffer[1] & 0xf);
281 5 : *height <<= 8;
282 5 : *height |= pbuffer[2];
283 5 : aspect_code = (pbuffer[3] >> 4) & 0xf;
284 5 : 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 5 : *aspect_ratio = par;
307 : }
308 :
309 :
310 5 : framerate_code = pbuffer[3] & 0xf;
311 5 : *frame_rate = mpeg12_frame_rate_table[framerate_code];
312 : // 18 bits
313 15 : bitrate_int = (pbuffer[4] << 10) |
314 10 : (pbuffer[5] << 2) |
315 5 : ((pbuffer[6] >> 6) & 0x3);
316 5 : *bitrate = bitrate_int;
317 5 : *bitrate *= 400.0;
318 5 : ix += sizeof(u32) + 7;
319 5 : pbuffer += 7;
320 : found = 0;
321 800 : } else if (found == 0) {
322 800 : if (scode == MPEG12_EXT_START_CODE) {
323 : pbuffer += sizeof(u32);
324 : ix += sizeof(u32);
325 0 : switch ((pbuffer[0] >> 4) & 0xf) {
326 0 : case SEQ_ID:
327 0 : *have_mpeg2 = 1;
328 0 : *height = ((pbuffer[1] & 0x1) << 13) |
329 0 : ((pbuffer[2] & 0x80) << 5) |
330 0 : (*height & 0x0fff);
331 0 : *width = (((pbuffer[2] >> 5) & 0x3) << 12) | (*width & 0x0fff);
332 0 : bitrate_ext = (pbuffer[2] & 0x1f) << 7;
333 0 : bitrate_ext |= (pbuffer[3] >> 1) & 0x7f;
334 0 : bitrate_int |= (bitrate_ext << 18);
335 0 : *bitrate = bitrate_int;
336 0 : *bitrate *= 400.0;
337 0 : break;
338 : default:
339 : break;
340 : }
341 0 : pbuffer++;
342 0 : ix++;
343 800 : } else if (scode == MPEG12_PICTURE_START_CODE) {
344 : return found;
345 : }
346 : }
347 : }
348 : return found;
349 : }
350 :
351 :
352 0 : s32 MPEG12_PictHdrType (unsigned char *pbuffer)
353 : {
354 : pbuffer += sizeof(u32);
355 3825 : 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 :
367 : static u64 read_pts (u8 *pak)
368 : {
369 : u64 pts;
370 : u16 temp;
371 :
372 4662 : pts = ((pak[0] >> 1) & 0x7);
373 4662 : pts <<= 15;
374 4662 : temp = convert16(&pak[1]) >> 1;
375 4662 : pts |= temp;
376 4662 : pts <<= 15;
377 4662 : temp = convert16(&pak[3]) >> 1;
378 4662 : pts |= temp;
379 : return pts;
380 : }
381 :
382 :
383 12 : static mpeg2ps_stream_t *mpeg2ps_stream_create (u8 stream_id,
384 : u8 substream)
385 : {
386 : mpeg2ps_stream_t *ptr;
387 12 : GF_SAFEALLOC(ptr, mpeg2ps_stream_t);
388 12 : if (!ptr) return NULL;
389 12 : ptr->m_stream_id = stream_id;
390 12 : ptr->m_substream_id = substream;
391 12 : ptr->is_video = stream_id >= 0xe0;
392 12 : ptr->pes_buffer = (u8 *)gf_malloc(4*4096);
393 12 : ptr->pes_buffer_size_max = 4 * 4096;
394 12 : return ptr;
395 : }
396 :
397 12 : static void mpeg2ps_stream_destroy (mpeg2ps_stream_t *sptr)
398 : {
399 : mpeg2ps_record_pes_t *p;
400 96 : while (sptr->record_first != NULL) {
401 : p = sptr->record_first;
402 72 : sptr->record_first = p->next_rec;
403 72 : gf_free(p);
404 : }
405 12 : if (sptr->m_fd != FDNULL) {
406 : file_close(sptr->m_fd);
407 12 : sptr->m_fd = FDNULL;
408 : }
409 12 : if (sptr->pes_buffer) gf_free(sptr->pes_buffer);
410 12 : gf_free(sptr);
411 12 : }
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 : */
418 13425 : 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 13425 : if (read_from_start < 5) {
426 0 : file_skip_bytes(fd, 5 - read_from_start);
427 : file_read_bytes(fd, &readbyte, 1);
428 0 : val = readbyte;
429 : } else {
430 13425 : val = pak[4];
431 : }
432 :
433 : // we've read 6 bytes
434 13425 : if ((val & 0xc0) != 0x40) {
435 : // mpeg1
436 13395 : file_skip_bytes(fd, 12 - read_from_start); // skip 6 more bytes
437 13395 : return;
438 : }
439 30 : file_skip_bytes(fd, 13 - read_from_start);
440 : file_read_bytes(fd, &readbyte, 1);
441 30 : 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 : */
451 56 : 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 56 : memcpy(buffer, saved, len);
458 112 : if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == 0) {
459 : return 0;
460 : }
461 : while (1) {
462 236 : if (gf_mv12_next_start_code(buffer + buffer_on,
463 : sizeof(buffer) - buffer_on,
464 : &new_offset,
465 : &scode) >= 0) {
466 76 : buffer_on += new_offset;
467 76 : if (scode == MPEG2_PS_PACKSTART) {
468 51 : file_skip_bytes(fd, buffer_on - 512); // go back to header
469 51 : return 1;
470 : }
471 25 : buffer_on += 1;
472 : } else {
473 : len = 0;
474 160 : if (buffer[sizeof(buffer) - 3] == 0 &&
475 0 : buffer[sizeof(buffer) - 2] == 0 &&
476 0 : buffer[sizeof(buffer) - 1] == 1) {
477 0 : buffer[0] = 0;
478 0 : buffer[1] = 0;
479 0 : buffer[2] = 1;
480 0 : len = 3;
481 160 : } else if (*(u16 *)(buffer + sizeof(buffer) - 2) == 0) {
482 0 : buffer[0] = 0;
483 0 : buffer[1] = 0;
484 : len = 2;
485 160 : } else if (buffer[sizeof(buffer) - 1] == 0) {
486 0 : buffer[0] = 0;
487 : len = 1;
488 : }
489 320 : 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 : */
502 6232 : static void copy_bytes_to_pes_buffer (mpeg2ps_stream_t *sptr,
503 : u16 pes_len)
504 : {
505 : u32 to_move;
506 :
507 6232 : 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 721 : to_move = sptr->pes_buffer_size - sptr->pes_buffer_on;
513 721 : memmove(sptr->pes_buffer,
514 721 : sptr->pes_buffer + sptr->pes_buffer_on,
515 : to_move);
516 721 : sptr->pes_buffer_size = to_move;
517 721 : sptr->pes_buffer_on = 0;
518 721 : if (to_move + pes_len > sptr->pes_buffer_size_max) {
519 7 : sptr->pes_buffer = (u8 *)gf_realloc(sptr->pes_buffer,
520 : to_move + pes_len + 2048);
521 7 : sptr->pes_buffer_size_max = to_move + pes_len + 2048;
522 : }
523 : }
524 6232 : file_read_bytes(sptr->m_fd, sptr->pes_buffer + sptr->pes_buffer_size, pes_len);
525 6232 : sptr->pes_buffer_size += pes_len;
526 6232 : }
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 : */
535 15436 : 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 28912 : 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 26986 : if (((hdr & MPEG2_PS_START_MASK) != MPEG2_PS_START) ||
552 : (hdr < MPEG2_PS_END)) {
553 56 : if (find_pack_start(fd, local, 6) == 0) {
554 : return 0;
555 : }
556 51 : continue;
557 : }
558 26930 : if (hdr == MPEG2_PS_PACKSTART) {
559 : // pack start code - we can skip down
560 13425 : adv_past_pack_hdr(fd, local, 6);
561 13425 : continue;
562 : }
563 13505 : if (hdr == MPEG2_PS_END) {
564 : file_skip_bytes(fd, -2);
565 0 : continue;
566 : }
567 :
568 : // we should have a valid stream and pes_len here...
569 13505 : *stream_id = hdr & 0xff;
570 13505 : *pes_len = convert16(local + 4);
571 13505 : 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 : */
581 6733 : 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 6733 : ts->have_pts = 0;
592 6733 : ts->have_dts = 0;
593 6733 : if (have_ts) *have_ts = 0;
594 6733 : if (file_read_bytes(fd, local, 1) == 0) {
595 : return 0;
596 : }
597 6733 : pes_len--; // remove this first byte from length
598 57079 : while (*local == 0xff) {
599 43617 : if (file_read_bytes(fd, local, 1) == 0) {
600 : return 0;
601 : }
602 43617 : pes_len--;
603 43617 : if (pes_len == 0) {
604 4 : *pes_left = 0;
605 4 : return 1;
606 : }
607 : }
608 6729 : if ((*local & 0xc0) == 0x40) {
609 : // buffer scale & size
610 : file_skip_bytes(fd, 1);
611 6700 : if (file_read_bytes(fd, local, 1) == 0) {
612 : return 0;
613 : }
614 6700 : pes_len -= 2;
615 : }
616 :
617 6729 : if ((*local & 0xf0) == 0x20) {
618 : // mpeg-1 with pts
619 3035 : if (file_read_bytes(fd, local + 1, 4) == 0) {
620 : return 0;
621 : }
622 3035 : ts->have_pts = 1;
623 3035 : ts->pts = ts->dts = read_pts(local);
624 3035 : *have_ts = 1;
625 3035 : pes_len -= 4;
626 3694 : } else if ((*local & 0xf0) == 0x30) {
627 : // have mpeg 1 pts and dts
628 803 : if (file_read_bytes(fd, local + 1, 9) == 0) {
629 : return 0;
630 : }
631 803 : ts->have_pts = 1;
632 803 : ts->have_dts = 1;
633 803 : *have_ts = 1;
634 803 : ts->pts = read_pts(local);
635 803 : ts->dts = read_pts(local + 5);
636 803 : pes_len -= 9;
637 2891 : } else if ((*local & 0xc0) == 0x80) {
638 : // mpeg2 pes header - we're pointing at the flags field now
639 24 : if (file_read_bytes(fd, local + 1, 2) == 0) {
640 : return 0;
641 : }
642 24 : hdr_len = local[2];
643 24 : pes_len -= hdr_len + 2; // first byte removed already
644 24 : if ((local[1] & 0xc0) == 0x80) {
645 : // just pts
646 21 : ts->have_pts = 1;
647 : file_read_bytes(fd, local, 5);
648 21 : ts->pts = ts->dts = read_pts(local);
649 21 : *have_ts = 1;
650 21 : hdr_len -= 5;
651 3 : } else if ((local[1] & 0xc0) == 0xc0) {
652 : // pts and dts
653 0 : ts->have_pts = 1;
654 0 : ts->have_dts = 1;
655 0 : *have_ts = 1;
656 : file_read_bytes(fd, local, 10);
657 0 : ts->pts = read_pts(local);
658 0 : ts->dts = read_pts(local + 5);
659 0 : hdr_len -= 10;
660 : }
661 24 : file_skip_bytes(fd, hdr_len);
662 2867 : } else if (*local != 0xf) {
663 : file_skip_bytes(fd, pes_len);
664 : pes_len = 0;
665 : }
666 6729 : *pes_left = pes_len;
667 6729 : return 1;
668 : }
669 :
670 8162 : 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 14872 : if (read_to_next_pes_header(sptr->m_fd, &stream_id, pes_len) == 0) {
682 : return 0;
683 : }
684 :
685 12950 : if (stream_id != sptr->m_stream_id) {
686 6710 : file_skip_bytes(sptr->m_fd, *pes_len);
687 6710 : continue;
688 : }
689 6240 : loc = file_location(sptr->m_fd) - 6;
690 : // advance past header, reading pts
691 12480 : if (read_pes_header_data(sptr->m_fd,
692 6240 : *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 6240 : if (sptr->m_stream_id == 0xbd) {
702 : // ac3 or pcm
703 10 : file_read_bytes(sptr->m_fd, &local, 1);
704 10 : *pes_len -= 1;
705 10 : if (local != sptr->m_substream_id) {
706 0 : file_skip_bytes(sptr->m_fd, *pes_len);
707 0 : continue; // skip to the next one
708 : }
709 10 : *pes_len -= 3;
710 10 : file_skip_bytes(sptr->m_fd, 3); // 4 bytes - we don't need now...
711 : // we need more here...
712 : }
713 6240 : if (have_ts) {
714 6240 : mpeg2ps_record_pts(sptr, loc, &sptr->next_pes_ts);
715 : }
716 6240 : 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 : */
727 8154 : static Bool mpeg2ps_stream_read_next_pes_buffer (mpeg2ps_stream_t *sptr)
728 : {
729 : u16 pes_len;
730 : Bool have_ts;
731 :
732 8154 : if (search_for_next_pes_header(sptr, &pes_len, &have_ts, NULL) == 0) {
733 : return 0;
734 : }
735 :
736 6232 : copy_bytes_to_pes_buffer(sptr, pes_len);
737 :
738 6232 : 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
763 5341 : 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 5341 : sptr->frame_ts = sptr->next_pes_ts;
775 5341 : if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 4) {
776 1515 : if (sptr->pes_buffer_size != sptr->pes_buffer_on)
777 : started_new_pes = 1;
778 1515 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
779 : return 0;
780 : }
781 : }
782 3841 : while (gf_mv12_next_start_code(sptr->pes_buffer + sptr->pes_buffer_on,
783 3841 : sptr->pes_buffer_size - sptr->pes_buffer_on,
784 : &offset,
785 3841 : &scode) < 0 ||
786 4094 : (!IS_MPEG_START(scode & 0xff))) {
787 0 : if (sptr->pes_buffer_size > 3)
788 0 : sptr->pes_buffer_on = sptr->pes_buffer_size - 3;
789 : else {
790 0 : sptr->pes_buffer_on = sptr->pes_buffer_size;
791 : started_new_pes = 1;
792 : }
793 0 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
794 : return 0;
795 : }
796 : }
797 3841 : sptr->pes_buffer_on += offset;
798 3841 : 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 3841 : sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching
804 : // clear timestamp indication
805 3841 : sptr->next_pes_ts.have_pts = sptr->next_pes_ts.have_dts = 0;
806 : }
807 :
808 3841 : if (scode == MPEG12_PICTURE_START_CODE) {
809 3579 : sptr->pict_header_offset = sptr->pes_buffer_on;
810 : have_pict = 1;
811 : } else have_pict = 0;
812 :
813 3841 : start = 4 + sptr->pes_buffer_on;
814 : while (1) {
815 :
816 13189 : if (gf_mv12_next_start_code(sptr->pes_buffer + start,
817 13189 : sptr->pes_buffer_size - start,
818 : &offset,
819 : &scode) < 0) {
820 5227 : start = sptr->pes_buffer_size - 3;
821 5227 : start -= sptr->pes_buffer_on;
822 5227 : sptr->pict_header_offset -= sptr->pes_buffer_on;
823 5227 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
824 : return 0;
825 : }
826 5227 : start += sptr->pes_buffer_on;
827 5227 : sptr->pict_header_offset += sptr->pes_buffer_on;
828 : } else {
829 7962 : start += offset;
830 7962 : if (have_pict == 0) {
831 280 : if (scode == MPEG12_PICTURE_START_CODE) {
832 : have_pict = 1;
833 262 : sptr->pict_header_offset = start;
834 : }
835 : } else {
836 7682 : if (IS_MPEG_START(scode & 0xff) ||
837 : scode == MPEG12_SEQUENCE_END_START_CODE) {
838 3841 : sptr->frame_len = start - sptr->pes_buffer_on;
839 3841 : sptr->have_frame_loaded = 1;
840 3841 : return 1;
841 : }
842 : }
843 4121 : start += 4;
844 : }
845 : }
846 : return 0;
847 : }
848 :
849 35 : static Bool mpeg2ps_stream_find_ac3_frame (mpeg2ps_stream_t *sptr)
850 : {
851 : u32 diff;
852 : Bool started_new_pes = 0;
853 : GF_AC3Config hdr;
854 : memset(&hdr, 0, sizeof(GF_AC3Config));
855 35 : sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching
856 35 : if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 6) {
857 5 : if (sptr->pes_buffer_size != sptr->pes_buffer_on)
858 : started_new_pes = 1;
859 5 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
860 : return 0;
861 : }
862 : }
863 34 : while (gf_ac3_parser(sptr->pes_buffer + sptr->pes_buffer_on,
864 34 : sptr->pes_buffer_size - sptr->pes_buffer_on,
865 : &diff,
866 : &hdr, 0) <= 0) {
867 : // don't have frame
868 0 : if (sptr->pes_buffer_size > 6) {
869 0 : sptr->pes_buffer_on = sptr->pes_buffer_size - 6;
870 : started_new_pes = 1;
871 : } else {
872 0 : sptr->pes_buffer_on = sptr->pes_buffer_size;
873 : }
874 0 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
875 : return 0;
876 : }
877 : }
878 34 : sptr->frame_len = hdr.framesize;
879 34 : sptr->pes_buffer_on += diff;
880 34 : if (diff == 0 && started_new_pes) {
881 : // we might have a new PTS - but it's not here
882 : } else {
883 34 : sptr->frame_ts = sptr->next_pes_ts;
884 34 : sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
885 : }
886 40 : while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {
887 6 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
888 : return 0;
889 : }
890 : }
891 34 : sptr->have_frame_loaded = 1;
892 34 : return 1;
893 : }
894 :
895 6675 : static Bool mpeg2ps_stream_find_mp3_frame (mpeg2ps_stream_t *sptr)
896 : {
897 : u32 diff, hdr;
898 : Bool started_new_pes = 0;
899 :
900 6675 : sptr->frame_ts = sptr->next_pes_ts;
901 6675 : if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 4) {
902 444 : if (sptr->pes_buffer_size != sptr->pes_buffer_on)
903 : started_new_pes = 1;
904 444 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
905 : return 0;
906 : }
907 : }
908 6254 : while ((hdr=gf_mp3_get_next_header_mem(sptr->pes_buffer + sptr->pes_buffer_on,
909 6254 : sptr->pes_buffer_size - sptr->pes_buffer_on,
910 : &diff) ) == 0) {
911 : // don't have frame
912 0 : if (sptr->pes_buffer_size > 3) {
913 0 : if (sptr->pes_buffer_on != sptr->pes_buffer_size) {
914 0 : sptr->pes_buffer_on = sptr->pes_buffer_size - 3;
915 : }
916 : started_new_pes = 1; // we have left over bytes...
917 : } else {
918 0 : sptr->pes_buffer_on = sptr->pes_buffer_size;
919 : }
920 0 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
921 : return 0;
922 : }
923 : }
924 : // have frame.
925 6254 : sptr->frame_len = gf_mp3_frame_size(hdr);
926 6254 : sptr->pes_buffer_on += diff;
927 6254 : if (diff == 0 && started_new_pes) {
928 :
929 : } else {
930 6246 : sptr->frame_ts = sptr->next_pes_ts;
931 6246 : sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
932 : }
933 7211 : while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {
934 957 : if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) {
935 : return 0;
936 : }
937 : }
938 6254 : sptr->have_frame_loaded = 1;
939 6254 : 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 : */
946 6732 : 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 6732 : if (sptr->is_video) {
953 22 : if (mpeg2ps_stream_find_mpeg_video_frame(sptr)) {
954 17 : *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
955 17 : *buflen = sptr->frame_len;
956 17 : if (advance_pointers) {
957 5 : sptr->pes_buffer_on += sptr->frame_len;
958 : }
959 : return 1;
960 : }
961 : return 0;
962 6710 : } else if (sptr->m_stream_id == 0xbd) {
963 : // would need to handle LPCM here
964 35 : if (mpeg2ps_stream_find_ac3_frame(sptr)) {
965 34 : *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
966 34 : *buflen = sptr->frame_len;
967 34 : if (advance_pointers)
968 0 : sptr->pes_buffer_on += sptr->frame_len;
969 : return 1;
970 : }
971 : return 0;
972 6675 : } else if (mpeg2ps_stream_find_mp3_frame(sptr)) {
973 6254 : *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
974 6254 : *buflen = sptr->frame_len;
975 6254 : if (advance_pointers)
976 10 : 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 : */
985 12 : static void get_info_from_frame (mpeg2ps_stream_t *sptr,
986 : u8 *buffer,
987 : u32 buflen)
988 : {
989 12 : if (sptr->is_video) {
990 5 : 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 0 : sptr->m_stream_id = 0;
998 0 : sptr->m_fd = FDNULL;
999 : }
1000 5 : sptr->ticks_per_frame = (u64)(90000.0 / sptr->frame_rate);
1001 5 : return;
1002 : }
1003 :
1004 7 : if (sptr->m_stream_id >= 0xc0) {
1005 : // mpeg audio
1006 5 : u32 hdr = GF_4CC((u32)buffer[0],buffer[1],buffer[2],buffer[3]);
1007 :
1008 5 : sptr->channels = gf_mp3_num_channels(hdr);
1009 5 : sptr->freq = gf_mp3_sampling_rate(hdr);
1010 5 : sptr->samples_per_frame = gf_mp3_window_size(hdr);
1011 5 : sptr->bitrate = gf_mp3_bit_rate(hdr) * 1000; // give bps, not kbps
1012 5 : sptr->layer = gf_mp3_layer(hdr);
1013 2 : } else if (sptr->m_stream_id == 0xbd) {
1014 2 : if (sptr->m_substream_id >= 0xa0) {
1015 : // PCM - ???
1016 2 : } else if (sptr->m_substream_id >= 0x80) {
1017 : u32 pos;
1018 : GF_AC3Config hdr;
1019 : memset(&hdr, 0, sizeof(GF_AC3Config));
1020 2 : gf_ac3_parser(buffer, buflen, &pos, &hdr, 0);
1021 2 : sptr->bitrate = hdr.bitrate;
1022 2 : sptr->freq = hdr.sample_rate;
1023 2 : sptr->channels = hdr.channels;
1024 2 : 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 : */
1037 : static void clear_stream_buffer (mpeg2ps_stream_t *sptr)
1038 : {
1039 49 : sptr->pes_buffer_on = sptr->pes_buffer_size = 0;
1040 49 : sptr->frame_len = 0;
1041 49 : sptr->have_frame_loaded = 0;
1042 49 : sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0;
1043 49 : 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 : */
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 400 : ret = ts - base_ts;
1058 410 : if (sptr->is_video) {
1059 : // video
1060 17 : ret += frames_since_ts * sptr->ticks_per_frame;
1061 393 : } else if (sptr->freq) {
1062 : // audio
1063 393 : calc = (frames_since_ts * 90000 * sptr->samples_per_frame) / sptr->freq;
1064 393 : ret += calc;
1065 : }
1066 390 : if (ts_type == TS_MSEC)
1067 410 : 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 : */
1077 484 : static mpeg2ps_stream_t *find_stream_from_id (mpeg2ps_t *ps,
1078 : u8 stream_id,
1079 : u8 substream)
1080 : {
1081 : u8 ix;
1082 484 : if (stream_id >= 0xe0) {
1083 0 : for (ix = 0; ix < ps->video_cnt; ix++) {
1084 385 : if (ps->video_streams[ix]->m_stream_id == stream_id) {
1085 : return ps->video_streams[ix];
1086 : }
1087 : }
1088 : } else {
1089 0 : for (ix = 0; ix < ps->audio_cnt; ix++) {
1090 87 : if (ps->audio_streams[ix]->m_stream_id == stream_id &&
1091 12 : (stream_id != 0xbd ||
1092 12 : 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 : */
1103 29 : 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 29 : sptr = find_stream_from_id(ps, stream_id, substream);
1112 29 : if (sptr != NULL) return 0;
1113 :
1114 : // need to add
1115 :
1116 12 : sptr = mpeg2ps_stream_create(stream_id, substream);
1117 12 : sptr->first_pes_loc = first_loc;
1118 24 : if (ts == NULL ||
1119 12 : (ts->have_dts == 0 && ts->have_pts == 0)) {
1120 0 : sptr->first_pes_has_dts = 0;
1121 : } else {
1122 12 : sptr->start_dts = ts->have_dts ? ts->dts : ts->pts;
1123 12 : sptr->first_pes_has_dts = 1;
1124 : }
1125 12 : if (sptr->is_video) {
1126 : // can't be more than 16 - e0 to ef...
1127 5 : ps->video_streams[ps->video_cnt] = sptr;
1128 5 : ps->video_cnt++;
1129 : } else {
1130 7 : if (ps->audio_cnt >= 32) {
1131 0 : mpeg2ps_stream_destroy(sptr);
1132 0 : return 0;
1133 : }
1134 7 : ps->audio_streams[ps->audio_cnt] = sptr;
1135 7 : ps->audio_cnt++;
1136 : }
1137 : return 1;
1138 : }
1139 :
1140 : static void check_fd_for_stream (mpeg2ps_t *ps,
1141 : mpeg2ps_stream_t *sptr)
1142 : {
1143 11628 : if (sptr->m_fd != FDNULL) return;
1144 :
1145 24 : 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 : */
1154 : static void advance_frame (mpeg2ps_stream_t *sptr)
1155 : {
1156 10102 : sptr->pes_buffer_on += sptr->frame_len;
1157 10102 : sptr->have_frame_loaded = 0;
1158 10102 : if (sptr->frame_ts.have_dts || sptr->frame_ts.have_pts) {
1159 3548 : if (sptr->frame_ts.have_dts)
1160 738 : sptr->last_ts = sptr->frame_ts.dts;
1161 : else
1162 2810 : sptr->last_ts = sptr->frame_ts.pts;
1163 3548 : sptr->frames_since_last_ts = 0;
1164 : } else {
1165 6554 : 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 : */
1172 7 : 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 7 : 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 21 : for (av = 0; av < 2; av++) {
1185 14 : if (av == 0) max_ix = ps->video_cnt;
1186 7 : else max_ix = ps->audio_cnt;
1187 26 : for (stream_ix = 0; stream_ix < max_ix; stream_ix++) {
1188 12 : if (av == 0) sptr = ps->video_streams[stream_ix];
1189 7 : 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 12 : sptr->m_fd = ps->fd; // for now
1194 : clear_stream_buffer(sptr);
1195 12 : if (mpeg2ps_stream_read_frame(sptr,
1196 : &buffer,
1197 : &buflen,
1198 : 0) == 0) {
1199 0 : sptr->m_stream_id = 0;
1200 0 : sptr->m_fd = FDNULL;
1201 0 : continue;
1202 : }
1203 12 : get_info_from_frame(sptr, buffer, buflen);
1204 : // here - if (sptr->first_pes_has_dts == 0) should be processed
1205 12 : if (sptr->first_pes_has_dts == 0) {
1206 : u32 frames_from_beg = 0;
1207 : Bool have_frame;
1208 : do {
1209 : advance_frame(sptr);
1210 0 : have_frame =
1211 : mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, 0);
1212 0 : frames_from_beg++;
1213 : } while (have_frame &&
1214 0 : sptr->frame_ts.have_dts == 0 &&
1215 0 : sptr->frame_ts.have_pts == 0 &&
1216 0 : frames_from_beg < 1000);
1217 0 : if (have_frame == 0 ||
1218 0 : (sptr->frame_ts.have_dts == 0 &&
1219 : sptr->frame_ts.have_pts == 0)) {
1220 : } else {
1221 0 : sptr->start_dts = sptr->frame_ts.have_dts ? sptr->frame_ts.dts :
1222 : sptr->frame_ts.pts;
1223 0 : if (sptr->is_video) {
1224 0 : sptr->start_dts -= frames_from_beg * sptr->ticks_per_frame;
1225 : } else {
1226 : u64 conv;
1227 0 : conv = sptr->samples_per_frame * 90000;
1228 0 : conv /= (u64)sptr->freq;
1229 0 : sptr->start_dts -= conv;
1230 : }
1231 : }
1232 : }
1233 : clear_stream_buffer(sptr);
1234 12 : sptr->m_fd = FDNULL;
1235 : }
1236 : }
1237 7 : }
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 : */
1243 7 : 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 14 : ps->end_loc = file_size(ps->fd);
1257 7 : 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 59 : while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len) &&
1266 : loc < check) {
1267 45 : pes_left = pes_len;
1268 45 : if (stream_id >= 0xbd && stream_id < 0xf0) {
1269 38 : loc = file_location(ps->fd) - 6;
1270 38 : if (read_pes_header_data(ps->fd,
1271 : pes_len,
1272 : &pes_left,
1273 : &have_ts,
1274 : &ts) == 0) {
1275 0 : return;
1276 : }
1277 : valid_stream = 0;
1278 38 : substream = 0;
1279 38 : if (stream_id == 0xbd) {
1280 28 : if (file_read_bytes(ps->fd, &substream, 1) == 0) {
1281 : return;
1282 : }
1283 14 : pes_left--; // remove byte we just read
1284 14 : if ((substream >= 0x80 && substream < 0x90) ||
1285 : (substream >= 0xa0 && substream < 0xb0)) {
1286 : valid_stream = 1;
1287 : }
1288 24 : } else if (stream_id >= 0xc0) {
1289 : // audio and video
1290 : valid_stream = 1;
1291 : }
1292 : if (valid_stream) {
1293 29 : if (add_stream(ps, stream_id, substream, loc, &ts)) {
1294 : // added
1295 12 : if (stream_id >= 0xe0) {
1296 5 : if (ps->video_cnt == 1) {
1297 : first_video_loc = loc;
1298 : }
1299 7 : } else if (ps->audio_cnt == 1) {
1300 : first_audio_loc = loc;
1301 : }
1302 12 : if (ps->audio_cnt > 0 && ps->video_cnt > 0) {
1303 : s64 diff;
1304 5 : if (first_audio_loc > first_video_loc)
1305 5 : diff = first_audio_loc - first_video_loc;
1306 : else
1307 0 : diff = first_video_loc - first_audio_loc;
1308 5 : diff *= 2;
1309 5 : diff += first_video_loc;
1310 5 : if (diff < check) {
1311 : check = diff;
1312 : }
1313 : }
1314 : }
1315 : }
1316 : }
1317 45 : file_skip_bytes(ps->fd, pes_left);
1318 : }
1319 7 : 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 7 : file_seek_to(ps->fd, ps->end_loc - orig_check);
1327 :
1328 519 : while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len)) {
1329 505 : loc = file_location(ps->fd) - 6;
1330 505 : if (stream_id == 0xbd || (stream_id >= 0xc0 && stream_id < 0xf0)) {
1331 455 : if (read_pes_header_data(ps->fd,
1332 : pes_len,
1333 : &pes_left,
1334 : &have_ts,
1335 : &ts) == 0) {
1336 : return;
1337 : }
1338 455 : if (stream_id == 0xbd) {
1339 0 : if (file_read_bytes(ps->fd, &substream, 1) == 0) {
1340 : return;
1341 : }
1342 0 : pes_left--; // remove byte we just read
1343 0 : if (!((substream >= 0x80 && substream < 0x90) ||
1344 : (substream >= 0xa0 && substream < 0xb0))) {
1345 0 : file_skip_bytes(ps->fd, pes_left);
1346 0 : continue;
1347 : }
1348 : } else {
1349 455 : substream = 0;
1350 : }
1351 455 : sptr = find_stream_from_id(ps, stream_id, substream);
1352 455 : if (sptr == NULL) {
1353 0 : add_stream(ps, stream_id, substream, 0, NULL);
1354 0 : sptr = find_stream_from_id(ps, stream_id, substream);
1355 : }
1356 455 : if (sptr != NULL && have_ts) {
1357 260 : sptr->end_dts = ts.have_dts ? ts.dts : ts.pts;
1358 260 : sptr->end_dts_loc = loc;
1359 : }
1360 455 : 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 7 : get_info_for_all_streams(ps);
1369 :
1370 7 : 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 21 : for (av_ix = 0; av_ix < 2; av_ix++) {
1377 14 : if (av_ix == 0) max_cnt = ps->video_cnt;
1378 7 : else max_cnt = ps->audio_cnt;
1379 :
1380 26 : for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {
1381 19 : sptr = av_ix == 0 ? ps->video_streams[stream_ix] :
1382 7 : ps->audio_streams[stream_ix];
1383 12 : if (sptr != NULL && sptr->start_dts < ps->first_dts) {
1384 7 : 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 14 : for (av_ix = 0; av_ix < 2; av_ix++) {
1394 14 : if (av_ix == 0) max_cnt = ps->video_cnt;
1395 7 : else max_cnt = ps->audio_cnt;
1396 26 : for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {
1397 : u32 frame_cnt_since_last;
1398 19 : sptr = av_ix == 0 ? ps->video_streams[stream_ix] :
1399 7 : ps->audio_streams[stream_ix];
1400 :
1401 : // pick up here - find the final time...
1402 12 : if (sptr && (sptr->end_dts_loc != 0)) {
1403 10 : file_seek_to(ps->fd, sptr->end_dts_loc);
1404 10 : sptr->m_fd = ps->fd;
1405 : frame_cnt_since_last = 0;
1406 : clear_stream_buffer(sptr);
1407 25 : while (mpeg2ps_stream_read_frame(sptr,
1408 : &buffer,
1409 : &buflen,
1410 : 1)) {
1411 15 : frame_cnt_since_last++;
1412 : }
1413 10 : sptr->m_fd = FDNULL;
1414 : clear_stream_buffer(sptr);
1415 30 : 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 7 : ps->max_dts = (ps->max_time * 90) + ps->first_dts;
1426 7 : file_seek_to(ps->fd, 0);
1427 : }
1428 :
1429 : /*************************************************************************
1430 : * API routines
1431 : *************************************************************************/
1432 7 : u64 mpeg2ps_get_max_time_msec (mpeg2ps_t *ps)
1433 : {
1434 7 : return ps->max_time;
1435 : }
1436 :
1437 7 : u32 mpeg2ps_get_video_stream_count (mpeg2ps_t *ps)
1438 : {
1439 7 : 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.
1445 : static Bool invalid_video_streamno (mpeg2ps_t *ps, u32 streamno)
1446 : {
1447 5356 : if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->video_streams)) return 1;
1448 5356 : 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 :
1465 5 : 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 5 : return ps->video_streams[streamno]->have_mpeg2 ? MPEG_VIDEO_MPEG2 : MPEG_VIDEO_MPEG1;
1472 : }
1473 :
1474 5 : u32 mpeg2ps_get_video_stream_width (mpeg2ps_t *ps, u32 streamno)
1475 : {
1476 : if (invalid_video_streamno(ps, streamno)) {
1477 : return 0;
1478 : }
1479 5 : return ps->video_streams[streamno]->w;
1480 : }
1481 :
1482 5 : u32 mpeg2ps_get_video_stream_height (mpeg2ps_t *ps, u32 streamno)
1483 : {
1484 : if (invalid_video_streamno(ps, streamno)) {
1485 : return 0;
1486 : }
1487 5 : return ps->video_streams[streamno]->h;
1488 : }
1489 :
1490 5 : 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 5 : return ps->video_streams[streamno]->par;
1496 : }
1497 :
1498 5 : Double mpeg2ps_get_video_stream_bitrate (mpeg2ps_t *ps, u32 streamno)
1499 : {
1500 : if (invalid_video_streamno(ps, streamno)) {
1501 : return 0;
1502 : }
1503 5 : return ps->video_streams[streamno]->bit_rate;
1504 : }
1505 :
1506 5 : Double mpeg2ps_get_video_stream_framerate (mpeg2ps_t *ps, u32 streamno)
1507 : {
1508 : if (invalid_video_streamno(ps, streamno)) {
1509 : return 0;
1510 : }
1511 5 : return ps->video_streams[streamno]->frame_rate;
1512 : }
1513 :
1514 5 : u32 mpeg2ps_get_video_stream_id(mpeg2ps_t *ps, u32 streamno)
1515 : {
1516 : if (invalid_video_streamno(ps, streamno)) {
1517 : return 0;
1518 : }
1519 5 : return ps->video_streams[streamno]->m_stream_id;
1520 : }
1521 :
1522 : static Bool invalid_audio_streamno (mpeg2ps_t *ps, u32 streamno)
1523 : {
1524 6349 : if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->audio_streams)) return 1;
1525 6349 : if (ps->audio_streams[streamno] == NULL) return 1;
1526 : return 0;
1527 : }
1528 :
1529 7 : u32 mpeg2ps_get_audio_stream_count (mpeg2ps_t *ps)
1530 : {
1531 7 : 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 :
1560 14 : 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 14 : if (ps->audio_streams[streamno]->m_stream_id >= 0xc0) {
1567 : return MPEG_AUDIO_MPEG;
1568 : }
1569 4 : 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 0 : return MPEG_AUDIO_LPCM;
1574 : }
1575 :
1576 7 : 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 7 : return ps->audio_streams[streamno]->freq;
1582 : }
1583 :
1584 7 : u32 mpeg2ps_get_audio_stream_channels (mpeg2ps_t *ps, u32 streamno)
1585 : {
1586 : if (invalid_audio_streamno(ps, streamno)) {
1587 : return 0;
1588 : }
1589 7 : return ps->audio_streams[streamno]->channels;
1590 : }
1591 :
1592 7 : u32 mpeg2ps_get_audio_stream_bitrate (mpeg2ps_t *ps, u32 streamno)
1593 : {
1594 : if (invalid_audio_streamno(ps, streamno)) {
1595 : return 0;
1596 : }
1597 7 : return ps->audio_streams[streamno]->bitrate;
1598 : }
1599 :
1600 7 : u32 mpeg2ps_get_audio_stream_id (mpeg2ps_t *ps, u32 streamno)
1601 : {
1602 : if (invalid_audio_streamno(ps, streamno)) {
1603 : return 0;
1604 : }
1605 7 : return ps->audio_streams[streamno]->m_stream_id;
1606 : }
1607 :
1608 :
1609 7 : mpeg2ps_t *mpeg2ps_init (const char *filename)
1610 : {
1611 : mpeg2ps_t *ps;
1612 7 : GF_SAFEALLOC(ps, mpeg2ps_t);
1613 :
1614 7 : if (ps == NULL) {
1615 : return NULL;
1616 : }
1617 : memset(ps, 0, sizeof(*ps));
1618 7 : ps->fd = file_open(filename);
1619 7 : if (file_okay(ps->fd) == 0) {
1620 0 : gf_free(ps);
1621 0 : return NULL;
1622 : }
1623 :
1624 7 : ps->filename = gf_strdup(filename);
1625 7 : mpeg2ps_scan_file(ps);
1626 7 : if (ps->video_cnt == 0 && ps->audio_cnt == 0) {
1627 0 : mpeg2ps_close(ps);
1628 0 : return NULL;
1629 : }
1630 : return ps;
1631 : }
1632 :
1633 7 : void mpeg2ps_close (mpeg2ps_t *ps)
1634 : {
1635 : u32 ix;
1636 7 : if (ps == NULL) return;
1637 5 : for (ix = 0; ix < ps->video_cnt; ix++) {
1638 5 : mpeg2ps_stream_destroy(ps->video_streams[ix]);
1639 5 : ps->video_streams[ix] = NULL;
1640 : }
1641 7 : for (ix = 0; ix < ps->audio_cnt; ix++) {
1642 7 : mpeg2ps_stream_destroy(ps->audio_streams[ix]);
1643 7 : ps->audio_streams[ix] = NULL;
1644 : }
1645 :
1646 7 : if (ps->filename) gf_free(ps->filename);
1647 7 : if (ps->fd) file_close(ps->fd);
1648 7 : 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 : */
1662 390 : 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 390 : calc_ts = sptr->last_ts;
1672 390 : if (sptr->frame_ts.have_dts) calc_ts = sptr->frame_ts.dts;
1673 387 : else if (sptr->frame_ts.have_pts) calc_ts = sptr->frame_ts.dts;
1674 325 : else frames_since_last = sptr->frames_since_last_ts + 1;
1675 :
1676 390 : if (freq_ts != NULL) {
1677 0 : freq_conv = calc_ts - base_dts;
1678 0 : freq_conv *= sptr->freq;
1679 0 : freq_conv /= 90000;
1680 0 : freq_conv += frames_since_last * sptr->samples_per_frame;
1681 0 : *freq_ts = (u32) (freq_conv & 0xffffffff);
1682 : }
1683 390 : 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 : */
1689 5320 : 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 5320 : 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 5319 : if (mpeg2ps_stream_find_mpeg_video_frame(sptr) == 0) {
1707 : return 0;
1708 : }
1709 : }
1710 3825 : *buffer = sptr->pes_buffer + sptr->pes_buffer_on;
1711 3825 : *buflen = sptr->frame_len;
1712 : // determine frame type
1713 3825 : if (frame_type != NULL) {
1714 11475 : *frame_type = MPEG12_PictHdrType(sptr->pes_buffer +
1715 3825 : sptr->pict_header_offset);
1716 : }
1717 :
1718 : // set the timestamps
1719 3825 : if (sptr->frame_ts.have_pts)
1720 2568 : cts = sptr->frame_ts.pts;
1721 : else
1722 1257 : cts = sptr->last_ts + (1+sptr->frames_since_last_ts) * sptr->ticks_per_frame;
1723 3825 : if (sptr->frame_ts.have_dts)
1724 736 : dts = sptr->frame_ts.dts;
1725 : else
1726 : dts = cts;
1727 :
1728 3825 : if (decode_timestamp) *decode_timestamp = dts;
1729 3825 : 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
1740 6306 : 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 6306 : if (sptr->have_frame_loaded == 0) {
1754 6305 : if (mpeg2ps_stream_read_frame(sptr, buffer, buflen, 0) == 0)
1755 : return 0;
1756 : }
1757 :
1758 5889 : if (freq_timestamp) {
1759 0 : /*ts = */stream_convert_frame_ts_to_msec(sptr,
1760 : ts_type,
1761 : ps->first_dts,
1762 : freq_timestamp);
1763 : }
1764 5889 : if (timestamp != NULL) {
1765 5889 : *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 : */
1797 1 : 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 1 : 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 1 : dts_perc = (search_dts - start_dts) * 1000 / (end_dts - start_dts);
1820 1 : dts_perc -= dts_perc % 10;
1821 :
1822 1 : loc = ((end_loc - start_loc) * dts_perc) / 1000;
1823 :
1824 1 : if (loc == start_loc || loc == end_loc) return;
1825 :
1826 : clear_stream_buffer(sptr);
1827 1 : 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 8 : if (search_for_next_pes_header(sptr,
1832 : &pes_len,
1833 : &have_ts,
1834 : &found_loc) == GF_FALSE) {
1835 : return;
1836 : }
1837 8 : if (have_ts == GF_FALSE) {
1838 7 : file_skip_bytes(sptr->m_fd, pes_len);
1839 : }
1840 8 : } while (have_ts == GF_FALSE);
1841 :
1842 : // record that spot...
1843 1 : mpeg2ps_record_pts(sptr, found_loc, &sptr->next_pes_ts);
1844 :
1845 1 : found_dts = sptr->next_pes_ts.have_dts ?
1846 1 : 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 1 : if (found_dts + (5 * 90000) > search_dts &&
1852 : found_dts < search_dts) {
1853 1 : 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 0 : if (found_dts > search_dts) {
1860 0 : if (found_dts >= end_dts) {
1861 0 : file_seek_to(sptr->m_fd, found_loc);
1862 : return;
1863 : }
1864 0 : end_loc = found_loc;
1865 : end_dts = found_dts;
1866 : } else {
1867 0 : if (found_dts <= start_dts) {
1868 0 : file_seek_to(sptr->m_fd, found_loc);
1869 : return;
1870 : }
1871 0 : start_loc = found_loc;
1872 : start_dts = found_dts;
1873 : }
1874 : }
1875 : }
1876 :
1877 :
1878 :
1879 2 : 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 2 : if (sptr->record_last == NULL) return NULL;
1885 :
1886 2 : if (dts > sptr->record_last->dts) return sptr->record_last;
1887 :
1888 1 : if (dts < sptr->record_first->dts) return NULL;
1889 1 : if (dts == sptr->record_first->dts) return sptr->record_first;
1890 :
1891 : p = sptr->record_first;
1892 1 : q = p->next_rec;
1893 :
1894 2 : while (q != NULL && q->dts > dts) {
1895 : p = q;
1896 1 : q = q->next_rec;
1897 : }
1898 1 : if (q == NULL) {
1899 : return sptr->record_last;
1900 : }
1901 :
1902 0 : p_diff = dts - p->dts;
1903 0 : q_diff = q->dts - dts;
1904 :
1905 0 : if (p_diff < q_diff) return p;
1906 0 : 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 : */
1917 2 : 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 2 : if (search_msec_timestamp <= 1000) { // first second, start from begin...
1931 0 : file_seek_to(sptr->m_fd, sptr->first_pes_loc);
1932 0 : return GF_TRUE;
1933 : }
1934 2 : dts = search_msec_timestamp * 90; // 1000 timescale to 90000 timescale
1935 2 : dts += ps->first_dts;
1936 :
1937 : /*
1938 : * see if the recorded data has anything close
1939 : */
1940 2 : rec = search_for_ts(sptr, dts);
1941 2 : if (rec != NULL) {
1942 : // see if it is close
1943 : // if we're plus or minus a second, seek to that.
1944 2 : if (rec->dts + 90000 >= dts && rec->dts <= dts + 90000) {
1945 0 : file_seek_to(sptr->m_fd, rec->location);
1946 0 : return GF_TRUE;
1947 : }
1948 : // at this point, rec is > a distance. If within 5 or so seconds,
1949 :
1950 2 : if (rec->dts + (5 * 90000) < dts) {
1951 : // more than 5 seconds away - skip and search
1952 1 : if (rec->next_rec == NULL) {
1953 1 : mpeg2ps_binary_seek(ps, sptr, dts,
1954 : rec->dts, rec->location,
1955 1 : sptr->end_dts, sptr->end_dts_loc);
1956 : } else {
1957 0 : 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 0 : mpeg2ps_binary_seek(ps, sptr, dts,
1966 0 : sptr->start_dts, sptr->first_pes_loc,
1967 0 : 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 390 : if (mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, GF_FALSE) == GF_FALSE)
1975 : return GF_FALSE;
1976 :
1977 390 : msec_ts = stream_convert_frame_ts_to_msec(sptr, TS_MSEC,
1978 : ps->first_dts, NULL);
1979 :
1980 390 : 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 390 : } 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 : */
1994 1 : 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 1 : if (mpeg2ps_seek_frame(ps,
2003 : sptr,
2004 : msec_timestamp)
2005 : == GF_FALSE) return GF_FALSE;
2006 :
2007 1 : if (sptr->have_frame_loaded == GF_FALSE) {
2008 : return GF_FALSE;
2009 : }
2010 1 : return GF_TRUE;
2011 : }
2012 : /*
2013 : * mpeg2ps_seek_audio_frame - go to the closest audio frame after the
2014 : * timestamp
2015 : */
2016 1 : 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 1 : if (mpeg2ps_seek_frame(ps,
2027 : sptr,
2028 : msec_timestamp) == GF_FALSE) return GF_FALSE;
2029 :
2030 1 : return GF_TRUE;
2031 : }
2032 :
2033 7 : u64 mpeg2ps_get_first_cts(mpeg2ps_t *ps)
2034 : {
2035 7 : return ps->first_dts;
2036 : }
2037 :
2038 :
2039 : #endif /*GPAC_DISABLE_MPEG2PS*/
|