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