LCOV - code coverage report
Current view: top level - media_tools - mpeg2_ps.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 565 681 83.0 %
Date: 2021-04-29 23:48:07 Functions: 47 48 97.9 %

          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*/

Generated by: LCOV version 1.13