]> git.sesse.net Git - ffmpeg/blob - libavformat/ty.c
avformat: Constify all muxer/demuxers
[ffmpeg] / libavformat / ty.c
1 /*
2  * TiVo ty stream demuxer
3  * Copyright (c) 2005 VLC authors and VideoLAN
4  * Copyright (c) 2005 by Neal Symms (tivo@freakinzoo.com) - February 2005
5  * based on code by Christopher Wingert for tivo-mplayer
6  * tivo(at)wingert.org, February 2003
7  * Copyright (c) 2017 Paul B Mahol
8  *
9  * This file is part of FFmpeg.
10  *
11  * FFmpeg is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * FFmpeg is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with FFmpeg; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25
26 #include "libavutil/intreadwrite.h"
27 #include "avformat.h"
28 #include "internal.h"
29 #include "mpeg.h"
30
31 #define SERIES1_PES_LENGTH  11    /* length of audio PES hdr on S1 */
32 #define SERIES2_PES_LENGTH  16    /* length of audio PES hdr on S2 */
33 #define AC3_PES_LENGTH      14    /* length of audio PES hdr for AC3 */
34 #define VIDEO_PES_LENGTH    16    /* length of video PES header */
35 #define DTIVO_PTS_OFFSET    6     /* offs into PES for MPEG PTS on DTivo */
36 #define SA_PTS_OFFSET       9     /* offset into PES for MPEG PTS on SA */
37 #define AC3_PTS_OFFSET      9     /* offset into PES for AC3 PTS on DTivo */
38 #define VIDEO_PTS_OFFSET    9     /* offset into PES for video PTS on all */
39 #define AC3_PKT_LENGTH      1536  /* size of TiVo AC3 pkts (w/o PES hdr) */
40
41 static const uint8_t ty_VideoPacket[]     = { 0x00, 0x00, 0x01, 0xe0 };
42 static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 };
43 static const uint8_t ty_AC3AudioPacket[]  = { 0x00, 0x00, 0x01, 0xbd };
44
45 #define TIVO_PES_FILEID   0xf5467abd
46 #define CHUNK_SIZE        (128 * 1024)
47 #define CHUNK_PEEK_COUNT  3      /* number of chunks to probe */
48
49 typedef struct TyRecHdr {
50     int64_t   rec_size;
51     uint8_t   ex[2];
52     uint8_t   rec_type;
53     uint8_t   subrec_type;
54     uint64_t  ty_pts;            /* TY PTS in the record header */
55 } TyRecHdr;
56
57 typedef enum {
58     TIVO_TYPE_UNKNOWN,
59     TIVO_TYPE_SA,
60     TIVO_TYPE_DTIVO
61 } TiVo_type;
62
63 typedef enum {
64     TIVO_SERIES_UNKNOWN,
65     TIVO_SERIES1,
66     TIVO_SERIES2
67 } TiVo_series;
68
69 typedef enum {
70     TIVO_AUDIO_UNKNOWN,
71     TIVO_AUDIO_AC3,
72     TIVO_AUDIO_MPEG
73 } TiVo_audio;
74
75 typedef struct TYDemuxContext {
76     unsigned        cur_chunk;
77     unsigned        cur_chunk_pos;
78     int64_t         cur_pos;
79     TiVo_type       tivo_type;        /* TiVo type (SA / DTiVo) */
80     TiVo_series     tivo_series;      /* Series1 or Series2 */
81     TiVo_audio      audio_type;       /* AC3 or MPEG */
82     int             pes_length;       /* Length of Audio PES header */
83     int             pts_offset;       /* offset into audio PES of PTS */
84     uint8_t         pes_buffer[20];   /* holds incomplete pes headers */
85     int             pes_buf_cnt;      /* how many bytes in our buffer */
86     size_t          ac3_pkt_size;     /* length of ac3 pkt we've seen so far */
87     uint64_t        last_ty_pts;      /* last TY timestamp we've seen */
88
89     int64_t         first_audio_pts;
90     int64_t         last_audio_pts;
91     int64_t         last_video_pts;
92
93     TyRecHdr       *rec_hdrs;         /* record headers array */
94     int             cur_rec;          /* current record in this chunk */
95     int             num_recs;         /* number of recs in this chunk */
96     int             first_chunk;
97
98     uint8_t         chunk[CHUNK_SIZE];
99 } TYDemuxContext;
100
101 static int ty_probe(const AVProbeData *p)
102 {
103     int i;
104
105     for (i = 0; i + 12 < p->buf_size; i += CHUNK_SIZE) {
106         if (AV_RB32(p->buf + i) == TIVO_PES_FILEID &&
107             AV_RB32(p->buf + i + 4) == 0x02 &&
108             AV_RB32(p->buf + i + 8) == CHUNK_SIZE) {
109             return AVPROBE_SCORE_MAX;
110         }
111     }
112
113     return 0;
114 }
115
116 static TyRecHdr *parse_chunk_headers(const uint8_t *buf,
117                                      int num_recs)
118 {
119     TyRecHdr *hdrs, *rec_hdr;
120     int i;
121
122     hdrs = av_calloc(num_recs, sizeof(TyRecHdr));
123     if (!hdrs)
124         return NULL;
125
126     for (i = 0; i < num_recs; i++) {
127         const uint8_t *record_header = buf + (i * 16);
128
129         rec_hdr = &hdrs[i];     /* for brevity */
130         rec_hdr->rec_type = record_header[3];
131         rec_hdr->subrec_type = record_header[2] & 0x0f;
132         if ((record_header[0] & 0x80) == 0x80) {
133             uint8_t b1, b2;
134
135             /* marker bit 2 set, so read extended data */
136             b1 = (((record_header[0] & 0x0f) << 4) |
137                   ((record_header[1] & 0xf0) >> 4));
138             b2 = (((record_header[1] & 0x0f) << 4) |
139                   ((record_header[2] & 0xf0) >> 4));
140
141             rec_hdr->ex[0] = b1;
142             rec_hdr->ex[1] = b2;
143             rec_hdr->rec_size = 0;
144             rec_hdr->ty_pts = 0;
145         } else {
146             rec_hdr->rec_size = (record_header[0] << 8 |
147                                  record_header[1]) << 4 |
148                                 (record_header[2] >> 4);
149             rec_hdr->ty_pts = AV_RB64(&record_header[8]);
150         }
151     }
152     return hdrs;
153 }
154
155 static int find_es_header(const uint8_t *header,
156                           const uint8_t *buffer, int search_len)
157 {
158     int count;
159
160     for (count = 0; count < search_len; count++) {
161         if (!memcmp(&buffer[count], header, 4))
162             return count;
163     }
164     return -1;
165 }
166
167 static int analyze_chunk(AVFormatContext *s, const uint8_t *chunk)
168 {
169     TYDemuxContext *ty = s->priv_data;
170     int num_recs, i;
171     TyRecHdr *hdrs;
172     int num_6e0, num_be0, num_9c0, num_3c0;
173
174     /* skip if it's a Part header */
175     if (AV_RB32(&chunk[0]) == TIVO_PES_FILEID)
176         return 0;
177
178     /* number of records in chunk (we ignore high order byte;
179      * rarely are there > 256 chunks & we don't need that many anyway) */
180     num_recs = chunk[0];
181     if (num_recs < 5) {
182         /* try again with the next chunk.  Sometimes there are dead ones */
183         return 0;
184     }
185
186     chunk += 4;       /* skip past rec count & SEQ bytes */
187     ff_dlog(s, "probe: chunk has %d recs\n", num_recs);
188     hdrs = parse_chunk_headers(chunk, num_recs);
189     if (!hdrs)
190         return AVERROR(ENOMEM);
191
192     /* scan headers.
193      * 1. check video packets.  Presence of 0x6e0 means S1.
194      *    No 6e0 but have be0 means S2.
195      * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
196      *    If AC-3, then we have DTivo.
197      *    If MPEG, search for PTS offset.  This will determine SA vs. DTivo.
198      */
199     num_6e0 = num_be0 = num_9c0 = num_3c0 = 0;
200     for (i = 0; i < num_recs; i++) {
201         switch (hdrs[i].subrec_type << 8 | hdrs[i].rec_type) {
202         case 0x6e0:
203             num_6e0++;
204             break;
205         case 0xbe0:
206             num_be0++;
207             break;
208         case 0x3c0:
209             num_3c0++;
210             break;
211         case 0x9c0:
212             num_9c0++;
213             break;
214         }
215     }
216     ff_dlog(s, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.\n",
217             num_6e0, num_be0);
218
219     /* set up our variables */
220     if (num_6e0 > 0) {
221         ff_dlog(s, "detected Series 1 Tivo\n");
222         ty->tivo_series = TIVO_SERIES1;
223         ty->pes_length = SERIES1_PES_LENGTH;
224     } else if (num_be0 > 0) {
225         ff_dlog(s, "detected Series 2 Tivo\n");
226         ty->tivo_series = TIVO_SERIES2;
227         ty->pes_length = SERIES2_PES_LENGTH;
228     }
229     if (num_9c0 > 0) {
230         ff_dlog(s, "detected AC-3 Audio (DTivo)\n");
231         ty->audio_type = TIVO_AUDIO_AC3;
232         ty->tivo_type = TIVO_TYPE_DTIVO;
233         ty->pts_offset = AC3_PTS_OFFSET;
234         ty->pes_length = AC3_PES_LENGTH;
235     } else if (num_3c0 > 0) {
236         ty->audio_type = TIVO_AUDIO_MPEG;
237         ff_dlog(s, "detected MPEG Audio\n");
238     }
239
240     /* if tivo_type still unknown, we can check PTS location
241      * in MPEG packets to determine tivo_type */
242     if (ty->tivo_type == TIVO_TYPE_UNKNOWN) {
243         uint32_t data_offset = 16 * num_recs;
244
245         for (i = 0; i < num_recs; i++) {
246             if (data_offset + hdrs[i].rec_size > CHUNK_SIZE)
247                 break;
248
249             if ((hdrs[i].subrec_type << 8 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) {
250                 /* first make sure we're aligned */
251                 int pes_offset = find_es_header(ty_MPEGAudioPacket,
252                         &chunk[data_offset], 5);
253                 if (pes_offset >= 0) {
254                     /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
255                     if ((chunk[data_offset + 6 + pes_offset] & 0x80) == 0x80) {
256                         /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
257                         if (ty->tivo_series == TIVO_SERIES1)
258                             ff_dlog(s, "detected Stand-Alone Tivo\n");
259                         ty->tivo_type = TIVO_TYPE_SA;
260                         ty->pts_offset = SA_PTS_OFFSET;
261                     } else {
262                         if (ty->tivo_series == TIVO_SERIES1)
263                             ff_dlog(s, "detected DirecTV Tivo\n");
264                         ty->tivo_type = TIVO_TYPE_DTIVO;
265                         ty->pts_offset = DTIVO_PTS_OFFSET;
266                     }
267                     break;
268                 }
269             }
270             data_offset += hdrs[i].rec_size;
271         }
272     }
273     av_free(hdrs);
274
275     return 0;
276 }
277
278 static int ty_read_header(AVFormatContext *s)
279 {
280     TYDemuxContext *ty = s->priv_data;
281     AVIOContext *pb = s->pb;
282     AVStream *st, *ast;
283     int i, ret = 0;
284
285     ty->first_audio_pts = AV_NOPTS_VALUE;
286     ty->last_audio_pts = AV_NOPTS_VALUE;
287     ty->last_video_pts = AV_NOPTS_VALUE;
288
289     for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
290         avio_read(pb, ty->chunk, CHUNK_SIZE);
291
292         ret = analyze_chunk(s, ty->chunk);
293         if (ret < 0)
294             return ret;
295         if (ty->tivo_series != TIVO_SERIES_UNKNOWN &&
296             ty->audio_type  != TIVO_AUDIO_UNKNOWN &&
297             ty->tivo_type   != TIVO_TYPE_UNKNOWN)
298             break;
299     }
300
301     if (ty->tivo_series == TIVO_SERIES_UNKNOWN ||
302         ty->audio_type == TIVO_AUDIO_UNKNOWN ||
303         ty->tivo_type == TIVO_TYPE_UNKNOWN)
304         return AVERROR(EIO);
305
306     st = avformat_new_stream(s, NULL);
307     if (!st)
308         return AVERROR(ENOMEM);
309     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
310     st->codecpar->codec_id   = AV_CODEC_ID_MPEG2VIDEO;
311     st->need_parsing         = AVSTREAM_PARSE_FULL_RAW;
312     avpriv_set_pts_info(st, 64, 1, 90000);
313
314     ast = avformat_new_stream(s, NULL);
315     if (!ast)
316         return AVERROR(ENOMEM);
317     ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
318
319     if (ty->audio_type == TIVO_AUDIO_MPEG) {
320         ast->codecpar->codec_id = AV_CODEC_ID_MP2;
321         ast->need_parsing       = AVSTREAM_PARSE_FULL_RAW;
322     } else {
323         ast->codecpar->codec_id = AV_CODEC_ID_AC3;
324     }
325     avpriv_set_pts_info(ast, 64, 1, 90000);
326
327     ty->first_chunk = 1;
328
329     avio_seek(pb, 0, SEEK_SET);
330
331     return 0;
332 }
333
334 static int get_chunk(AVFormatContext *s)
335 {
336     TYDemuxContext *ty = s->priv_data;
337     AVIOContext *pb = s->pb;
338     int read_size, num_recs;
339
340     ff_dlog(s, "parsing ty chunk #%d\n", ty->cur_chunk);
341
342     /* if we have left-over filler space from the last chunk, get that */
343     if (avio_feof(pb))
344         return AVERROR_EOF;
345
346     /* read the TY packet header */
347     read_size = avio_read(pb, ty->chunk, CHUNK_SIZE);
348     ty->cur_chunk++;
349
350     if ((read_size < 4) || (AV_RB32(ty->chunk) == 0)) {
351         return AVERROR_EOF;
352     }
353
354     /* check if it's a PART Header */
355     if (AV_RB32(ty->chunk) == TIVO_PES_FILEID) {
356         /* skip master chunk and read new chunk */
357         return get_chunk(s);
358     }
359
360     /* number of records in chunk (8- or 16-bit number) */
361     if (ty->chunk[3] & 0x80) {
362         /* 16 bit rec cnt */
363         ty->num_recs = num_recs = (ty->chunk[1] << 8) + ty->chunk[0];
364     } else {
365         /* 8 bit reclen - TiVo 1.3 format */
366         ty->num_recs = num_recs = ty->chunk[0];
367     }
368     ty->cur_rec = 0;
369     ty->first_chunk = 0;
370
371     ff_dlog(s, "chunk has %d records\n", num_recs);
372     ty->cur_chunk_pos = 4;
373
374     av_freep(&ty->rec_hdrs);
375
376     if (num_recs * 16 >= CHUNK_SIZE - 4)
377         return AVERROR_INVALIDDATA;
378
379     ty->rec_hdrs = parse_chunk_headers(ty->chunk + 4, num_recs);
380     if (!ty->rec_hdrs)
381         return AVERROR(ENOMEM);
382     ty->cur_chunk_pos += 16 * num_recs;
383
384     return 0;
385 }
386
387 static int demux_video(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt)
388 {
389     TYDemuxContext *ty = s->priv_data;
390     const int subrec_type = rec_hdr->subrec_type;
391     const int64_t rec_size = rec_hdr->rec_size;
392     int es_offset1, ret;
393     int got_packet = 0;
394
395     if (subrec_type != 0x02 && subrec_type != 0x0c &&
396         subrec_type != 0x08 && rec_size > 4) {
397         /* get the PTS from this packet if it has one.
398          * on S1, only 0x06 has PES.  On S2, however, most all do.
399          * Do NOT Pass the PES Header to the MPEG2 codec */
400         es_offset1 = find_es_header(ty_VideoPacket, ty->chunk + ty->cur_chunk_pos, 5);
401         if (es_offset1 != -1) {
402             ty->last_video_pts = ff_parse_pes_pts(
403                     ty->chunk + ty->cur_chunk_pos + es_offset1 + VIDEO_PTS_OFFSET);
404             if (subrec_type != 0x06) {
405                 /* if we found a PES, and it's not type 6, then we're S2 */
406                 /* The packet will have video data (& other headers) so we
407                  * chop out the PES header and send the rest */
408                 if (rec_size >= VIDEO_PES_LENGTH + es_offset1) {
409                     int size = rec_hdr->rec_size - VIDEO_PES_LENGTH - es_offset1;
410
411                     ty->cur_chunk_pos += VIDEO_PES_LENGTH + es_offset1;
412                     if ((ret = av_new_packet(pkt, size)) < 0)
413                         return ret;
414                     memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, size);
415                     ty->cur_chunk_pos += size;
416                     pkt->stream_index = 0;
417                     got_packet = 1;
418                 } else {
419                     ff_dlog(s, "video rec type 0x%02x has short PES"
420                         " (%"PRId64" bytes)\n", subrec_type, rec_size);
421                     /* nuke this block; it's too short, but has PES marker */
422                     ty->cur_chunk_pos += rec_size;
423                     return 0;
424                 }
425             }
426         }
427     }
428
429     if (subrec_type == 0x06) {
430         /* type 6 (S1 DTivo) has no data, so we're done */
431         ty->cur_chunk_pos += rec_size;
432         return 0;
433     }
434
435     if (!got_packet) {
436         if ((ret = av_new_packet(pkt, rec_size)) < 0)
437             return ret;
438         memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
439         ty->cur_chunk_pos += rec_size;
440         pkt->stream_index = 0;
441         got_packet = 1;
442     }
443
444     /* if it's not a continue blk, then set PTS */
445     if (subrec_type != 0x02) {
446         if (subrec_type == 0x0c && pkt->size >= 6)
447             pkt->data[5] |= 0x08;
448         if (subrec_type == 0x07) {
449             ty->last_ty_pts = rec_hdr->ty_pts;
450         } else {
451             /* yes I know this is a cheap hack.  It's the timestamp
452                used for display and skipping fwd/back, so it
453                doesn't have to be accurate to the millisecond.
454                I adjust it here by roughly one 1/30 sec.  Yes it
455                will be slightly off for UK streams, but it's OK.
456              */
457             ty->last_ty_pts += 35000000;
458             //ty->last_ty_pts += 33366667;
459         }
460         /* set PTS for this block before we send */
461         if (ty->last_video_pts > AV_NOPTS_VALUE) {
462             pkt->pts = ty->last_video_pts;
463             /* PTS gets used ONCE.
464              * Any subsequent frames we get BEFORE next PES
465              * header will have their PTS computed in the codec */
466             ty->last_video_pts = AV_NOPTS_VALUE;
467         }
468     }
469
470     return got_packet;
471 }
472
473 static int check_sync_pes(AVFormatContext *s, AVPacket *pkt,
474                           int32_t offset, int32_t rec_len)
475 {
476     TYDemuxContext *ty = s->priv_data;
477
478     if (offset < 0 || offset + ty->pes_length > rec_len) {
479         /* entire PES header not present */
480         ff_dlog(s, "PES header at %"PRId32" not complete in record. storing.\n", offset);
481         /* save the partial pes header */
482         if (offset < 0) {
483             /* no header found, fake some 00's (this works, believe me) */
484             memset(ty->pes_buffer, 0, 4);
485             ty->pes_buf_cnt = 4;
486             if (rec_len > 4)
487                 ff_dlog(s, "PES header not found in record of %"PRId32" bytes!\n", rec_len);
488             return -1;
489         }
490         /* copy the partial pes header we found */
491         memcpy(ty->pes_buffer, pkt->data + offset, rec_len - offset);
492         ty->pes_buf_cnt = rec_len - offset;
493
494         if (offset > 0) {
495             /* PES Header was found, but not complete, so trim the end of this record */
496             pkt->size -= rec_len - offset;
497             return 1;
498         }
499         return -1;    /* partial PES, no audio data */
500     }
501     /* full PES header present, extract PTS */
502     ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[ offset + ty->pts_offset]);
503     if (ty->first_audio_pts == AV_NOPTS_VALUE)
504         ty->first_audio_pts = ty->last_audio_pts;
505     pkt->pts = ty->last_audio_pts;
506     memmove(pkt->data + offset, pkt->data + offset + ty->pes_length, rec_len - ty->pes_length);
507     pkt->size -= ty->pes_length;
508     return 0;
509 }
510
511 static int demux_audio(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt)
512 {
513     TYDemuxContext *ty = s->priv_data;
514     const int subrec_type = rec_hdr->subrec_type;
515     const int64_t rec_size = rec_hdr->rec_size;
516     int es_offset1, ret;
517
518     if (subrec_type == 2) {
519         int need = 0;
520         /* SA or DTiVo Audio Data, no PES (continued block)
521          * ================================================
522          */
523
524         /* continue PES if previous was incomplete */
525         if (ty->pes_buf_cnt > 0) {
526             need = ty->pes_length - ty->pes_buf_cnt;
527
528             ff_dlog(s, "continuing PES header\n");
529             /* do we have enough data to complete? */
530             if (need >= rec_size) {
531                 /* don't have complete PES hdr; save what we have and return */
532                 memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, rec_size);
533                 ty->cur_chunk_pos += rec_size;
534                 ty->pes_buf_cnt += rec_size;
535                 return 0;
536             }
537
538             /* we have enough; reconstruct this frame with the new hdr */
539             memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, need);
540             ty->cur_chunk_pos += need;
541             /* get the PTS out of this PES header (MPEG or AC3) */
542             if (ty->audio_type == TIVO_AUDIO_MPEG) {
543                 es_offset1 = find_es_header(ty_MPEGAudioPacket,
544                         ty->pes_buffer, 5);
545             } else {
546                 es_offset1 = find_es_header(ty_AC3AudioPacket,
547                         ty->pes_buffer, 5);
548             }
549             if (es_offset1 < 0) {
550                 ff_dlog(s, "Can't find audio PES header in packet.\n");
551             } else {
552                 ty->last_audio_pts = ff_parse_pes_pts(
553                     &ty->pes_buffer[es_offset1 + ty->pts_offset]);
554                 pkt->pts = ty->last_audio_pts;
555             }
556             ty->pes_buf_cnt = 0;
557
558         }
559         if ((ret = av_new_packet(pkt, rec_size - need)) < 0)
560             return ret;
561         memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size - need);
562         ty->cur_chunk_pos += rec_size - need;
563         pkt->stream_index = 1;
564
565         /* S2 DTivo has AC3 packets with 2 padding bytes at end.  This is
566          * not allowed in the AC3 spec and will cause problems.  So here
567          * we try to trim things. */
568         /* Also, S1 DTivo has alternating short / long AC3 packets.  That
569          * is, one packet is short (incomplete) and the next packet has
570          * the first one's missing data, plus all of its own.  Strange. */
571         if (ty->audio_type == TIVO_AUDIO_AC3 &&
572                 ty->tivo_series == TIVO_SERIES2) {
573             if (ty->ac3_pkt_size + pkt->size > AC3_PKT_LENGTH) {
574                 pkt->size -= 2;
575                 ty->ac3_pkt_size = 0;
576             } else {
577                 ty->ac3_pkt_size += pkt->size;
578             }
579         }
580     } else if (subrec_type == 0x03) {
581         if ((ret = av_new_packet(pkt, rec_size)) < 0)
582             return ret;
583         memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
584         ty->cur_chunk_pos += rec_size;
585         pkt->stream_index = 1;
586         /* MPEG Audio with PES Header, either SA or DTiVo   */
587         /* ================================================ */
588         es_offset1 = find_es_header(ty_MPEGAudioPacket, pkt->data, 5);
589
590         /* SA PES Header, No Audio Data                     */
591         /* ================================================ */
592         if ((es_offset1 == 0) && (rec_size == 16)) {
593             ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[SA_PTS_OFFSET]);
594             if (ty->first_audio_pts == AV_NOPTS_VALUE)
595                 ty->first_audio_pts = ty->last_audio_pts;
596             av_packet_unref(pkt);
597             return 0;
598         }
599         /* DTiVo Audio with PES Header                      */
600         /* ================================================ */
601
602         /* Check for complete PES */
603         if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) {
604             /* partial PES header found, nothing else.
605              * we're done. */
606             av_packet_unref(pkt);
607             return 0;
608         }
609     } else if (subrec_type == 0x04) {
610         /* SA Audio with no PES Header                      */
611         /* ================================================ */
612         if ((ret = av_new_packet(pkt, rec_size)) < 0)
613             return ret;
614         memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
615         ty->cur_chunk_pos += rec_size;
616         pkt->stream_index = 1;
617         pkt->pts = ty->last_audio_pts;
618     } else if (subrec_type == 0x09) {
619         if ((ret = av_new_packet(pkt, rec_size)) < 0)
620             return ret;
621         memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
622         ty->cur_chunk_pos += rec_size ;
623         pkt->stream_index = 1;
624
625         /* DTiVo AC3 Audio Data with PES Header             */
626         /* ================================================ */
627         es_offset1 = find_es_header(ty_AC3AudioPacket, pkt->data, 5);
628
629         /* Check for complete PES */
630         if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) {
631             /* partial PES header found, nothing else.  we're done. */
632             av_packet_unref(pkt);
633             return 0;
634         }
635         /* S2 DTivo has invalid long AC3 packets */
636         if (ty->tivo_series == TIVO_SERIES2) {
637             if (pkt->size > AC3_PKT_LENGTH) {
638                 pkt->size -= 2;
639                 ty->ac3_pkt_size = 0;
640             } else {
641                 ty->ac3_pkt_size = pkt->size;
642             }
643         }
644     } else {
645         /* Unsupported/Unknown */
646         ty->cur_chunk_pos += rec_size;
647         return 0;
648     }
649
650     return 1;
651 }
652
653 static int ty_read_packet(AVFormatContext *s, AVPacket *pkt)
654 {
655     TYDemuxContext *ty = s->priv_data;
656     AVIOContext *pb = s->pb;
657     TyRecHdr *rec;
658     int64_t rec_size = 0;
659     int ret = 0;
660
661     if (avio_feof(pb))
662         return AVERROR_EOF;
663
664     while (ret <= 0) {
665         if (!ty->rec_hdrs || ty->first_chunk || ty->cur_rec >= ty->num_recs) {
666             if (get_chunk(s) < 0 || ty->num_recs <= 0)
667                 return AVERROR_EOF;
668         }
669
670         rec = &ty->rec_hdrs[ty->cur_rec];
671         rec_size = rec->rec_size;
672         ty->cur_rec++;
673
674         if (rec_size <= 0)
675             continue;
676
677         if (ty->cur_chunk_pos + rec->rec_size > CHUNK_SIZE)
678             return AVERROR_INVALIDDATA;
679
680         if (avio_feof(pb))
681             return AVERROR_EOF;
682
683         switch (rec->rec_type) {
684         case VIDEO_ID:
685             ret = demux_video(s, rec, pkt);
686             break;
687         case AUDIO_ID:
688             ret = demux_audio(s, rec, pkt);
689             break;
690         default:
691             ff_dlog(s, "Invalid record type 0x%02x\n", rec->rec_type);
692         case 0x01:
693         case 0x02:
694         case 0x03: /* TiVo data services */
695         case 0x05: /* unknown, but seen regularly */
696             ty->cur_chunk_pos += rec->rec_size;
697             break;
698         }
699     }
700
701     return 0;
702 }
703
704 static int ty_read_close(AVFormatContext *s)
705 {
706     TYDemuxContext *ty = s->priv_data;
707
708     av_freep(&ty->rec_hdrs);
709
710     return 0;
711 }
712
713 const AVInputFormat ff_ty_demuxer = {
714     .name           = "ty",
715     .long_name      = NULL_IF_CONFIG_SMALL("TiVo TY Stream"),
716     .priv_data_size = sizeof(TYDemuxContext),
717     .read_probe     = ty_probe,
718     .read_header    = ty_read_header,
719     .read_packet    = ty_read_packet,
720     .read_close     = ty_read_close,
721     .extensions     = "ty,ty+",
722     .flags          = AVFMT_TS_DISCONT,
723 };