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 TySeqTable {
76 uint64_t timestamp;
77 uint8_t chunk_bitmask[8];
78 } TySeqTable;
79
80 typedef struct TYDemuxContext {
81 unsigned cur_chunk;
82 unsigned cur_chunk_pos;
83 int64_t cur_pos;
84 TiVo_type tivo_type; /* TiVo type (SA / DTiVo) */
85 TiVo_series tivo_series; /* Series1 or Series2 */
86 TiVo_audio audio_type; /* AC3 or MPEG */
87 int pes_length; /* Length of Audio PES header */
88 int pts_offset; /* offset into audio PES of PTS */
89 uint8_t pes_buffer[20]; /* holds incomplete pes headers */
90 int pes_buf_cnt; /* how many bytes in our buffer */
91 size_t ac3_pkt_size; /* length of ac3 pkt we've seen so far */
92 uint64_t last_ty_pts; /* last TY timestamp we've seen */
93 unsigned seq_table_size; /* number of entries in SEQ table */
94
95 int64_t first_audio_pts;
96 int64_t last_audio_pts;
97 int64_t last_video_pts;
98
99 TyRecHdr *rec_hdrs; /* record headers array */
100 int cur_rec; /* current record in this chunk */
101 int num_recs; /* number of recs in this chunk */
102 int seq_rec; /* record number where seq start is */
103 TySeqTable *seq_table; /* table of SEQ entries from mstr chk */
104 int first_chunk;
105
106 uint8_t chunk[CHUNK_SIZE];
107 } TYDemuxContext;
108
ty_probe(const AVProbeData * p)109 static int ty_probe(const AVProbeData *p)
110 {
111 int i;
112
113 for (i = 0; i + 12 < p->buf_size; i += CHUNK_SIZE) {
114 if (AV_RB32(p->buf + i) == TIVO_PES_FILEID &&
115 AV_RB32(p->buf + i + 4) == 0x02 &&
116 AV_RB32(p->buf + i + 8) == CHUNK_SIZE) {
117 return AVPROBE_SCORE_MAX;
118 }
119 }
120
121 return 0;
122 }
123
parse_chunk_headers(const uint8_t * buf,int num_recs)124 static TyRecHdr *parse_chunk_headers(const uint8_t *buf,
125 int num_recs)
126 {
127 TyRecHdr *hdrs, *rec_hdr;
128 int i;
129
130 hdrs = av_calloc(num_recs, sizeof(TyRecHdr));
131 if (!hdrs)
132 return NULL;
133
134 for (i = 0; i < num_recs; i++) {
135 const uint8_t *record_header = buf + (i * 16);
136
137 rec_hdr = &hdrs[i]; /* for brevity */
138 rec_hdr->rec_type = record_header[3];
139 rec_hdr->subrec_type = record_header[2] & 0x0f;
140 if ((record_header[0] & 0x80) == 0x80) {
141 uint8_t b1, b2;
142
143 /* marker bit 2 set, so read extended data */
144 b1 = (((record_header[0] & 0x0f) << 4) |
145 ((record_header[1] & 0xf0) >> 4));
146 b2 = (((record_header[1] & 0x0f) << 4) |
147 ((record_header[2] & 0xf0) >> 4));
148
149 rec_hdr->ex[0] = b1;
150 rec_hdr->ex[1] = b2;
151 rec_hdr->rec_size = 0;
152 rec_hdr->ty_pts = 0;
153 } else {
154 rec_hdr->rec_size = (record_header[0] << 8 |
155 record_header[1]) << 4 |
156 (record_header[2] >> 4);
157 rec_hdr->ty_pts = AV_RB64(&record_header[8]);
158 }
159 }
160 return hdrs;
161 }
162
find_es_header(const uint8_t * header,const uint8_t * buffer,int search_len)163 static int find_es_header(const uint8_t *header,
164 const uint8_t *buffer, int search_len)
165 {
166 int count;
167
168 for (count = 0; count < search_len; count++) {
169 if (!memcmp(&buffer[count], header, 4))
170 return count;
171 }
172 return -1;
173 }
174
analyze_chunk(AVFormatContext * s,const uint8_t * chunk)175 static int analyze_chunk(AVFormatContext *s, const uint8_t *chunk)
176 {
177 TYDemuxContext *ty = s->priv_data;
178 int num_recs, i;
179 TyRecHdr *hdrs;
180 int num_6e0, num_be0, num_9c0, num_3c0;
181
182 /* skip if it's a Part header */
183 if (AV_RB32(&chunk[0]) == TIVO_PES_FILEID)
184 return 0;
185
186 /* number of records in chunk (we ignore high order byte;
187 * rarely are there > 256 chunks & we don't need that many anyway) */
188 num_recs = chunk[0];
189 if (num_recs < 5) {
190 /* try again with the next chunk. Sometimes there are dead ones */
191 return 0;
192 }
193
194 chunk += 4; /* skip past rec count & SEQ bytes */
195 ff_dlog(s, "probe: chunk has %d recs\n", num_recs);
196 hdrs = parse_chunk_headers(chunk, num_recs);
197 if (!hdrs)
198 return AVERROR(ENOMEM);
199
200 /* scan headers.
201 * 1. check video packets. Presence of 0x6e0 means S1.
202 * No 6e0 but have be0 means S2.
203 * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg)
204 * If AC-3, then we have DTivo.
205 * If MPEG, search for PTS offset. This will determine SA vs. DTivo.
206 */
207 num_6e0 = num_be0 = num_9c0 = num_3c0 = 0;
208 for (i = 0; i < num_recs; i++) {
209 switch (hdrs[i].subrec_type << 8 | hdrs[i].rec_type) {
210 case 0x6e0:
211 num_6e0++;
212 break;
213 case 0xbe0:
214 num_be0++;
215 break;
216 case 0x3c0:
217 num_3c0++;
218 break;
219 case 0x9c0:
220 num_9c0++;
221 break;
222 }
223 }
224 ff_dlog(s, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.\n",
225 num_6e0, num_be0);
226
227 /* set up our variables */
228 if (num_6e0 > 0) {
229 ff_dlog(s, "detected Series 1 Tivo\n");
230 ty->tivo_series = TIVO_SERIES1;
231 ty->pes_length = SERIES1_PES_LENGTH;
232 } else if (num_be0 > 0) {
233 ff_dlog(s, "detected Series 2 Tivo\n");
234 ty->tivo_series = TIVO_SERIES2;
235 ty->pes_length = SERIES2_PES_LENGTH;
236 }
237 if (num_9c0 > 0) {
238 ff_dlog(s, "detected AC-3 Audio (DTivo)\n");
239 ty->audio_type = TIVO_AUDIO_AC3;
240 ty->tivo_type = TIVO_TYPE_DTIVO;
241 ty->pts_offset = AC3_PTS_OFFSET;
242 ty->pes_length = AC3_PES_LENGTH;
243 } else if (num_3c0 > 0) {
244 ty->audio_type = TIVO_AUDIO_MPEG;
245 ff_dlog(s, "detected MPEG Audio\n");
246 }
247
248 /* if tivo_type still unknown, we can check PTS location
249 * in MPEG packets to determine tivo_type */
250 if (ty->tivo_type == TIVO_TYPE_UNKNOWN) {
251 uint32_t data_offset = 16 * num_recs;
252
253 for (i = 0; i < num_recs; i++) {
254 if (data_offset + hdrs[i].rec_size > CHUNK_SIZE)
255 break;
256
257 if ((hdrs[i].subrec_type << 8 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) {
258 /* first make sure we're aligned */
259 int pes_offset = find_es_header(ty_MPEGAudioPacket,
260 &chunk[data_offset], 5);
261 if (pes_offset >= 0) {
262 /* pes found. on SA, PES has hdr data at offset 6, not PTS. */
263 if ((chunk[data_offset + 6 + pes_offset] & 0x80) == 0x80) {
264 /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
265 if (ty->tivo_series == TIVO_SERIES1)
266 ff_dlog(s, "detected Stand-Alone Tivo\n");
267 ty->tivo_type = TIVO_TYPE_SA;
268 ty->pts_offset = SA_PTS_OFFSET;
269 } else {
270 if (ty->tivo_series == TIVO_SERIES1)
271 ff_dlog(s, "detected DirecTV Tivo\n");
272 ty->tivo_type = TIVO_TYPE_DTIVO;
273 ty->pts_offset = DTIVO_PTS_OFFSET;
274 }
275 break;
276 }
277 }
278 data_offset += hdrs[i].rec_size;
279 }
280 }
281 av_free(hdrs);
282
283 return 0;
284 }
285
ty_read_header(AVFormatContext * s)286 static int ty_read_header(AVFormatContext *s)
287 {
288 TYDemuxContext *ty = s->priv_data;
289 AVIOContext *pb = s->pb;
290 AVStream *st, *ast;
291 int i, ret = 0;
292
293 ty->first_audio_pts = AV_NOPTS_VALUE;
294 ty->last_audio_pts = AV_NOPTS_VALUE;
295 ty->last_video_pts = AV_NOPTS_VALUE;
296
297 for (i = 0; i < CHUNK_PEEK_COUNT; i++) {
298 avio_read(pb, ty->chunk, CHUNK_SIZE);
299
300 ret = analyze_chunk(s, ty->chunk);
301 if (ret < 0)
302 return ret;
303 if (ty->tivo_series != TIVO_SERIES_UNKNOWN &&
304 ty->audio_type != TIVO_AUDIO_UNKNOWN &&
305 ty->tivo_type != TIVO_TYPE_UNKNOWN)
306 break;
307 }
308
309 if (ty->tivo_series == TIVO_SERIES_UNKNOWN ||
310 ty->audio_type == TIVO_AUDIO_UNKNOWN ||
311 ty->tivo_type == TIVO_TYPE_UNKNOWN)
312 return AVERROR(EIO);
313
314 st = avformat_new_stream(s, NULL);
315 if (!st)
316 return AVERROR(ENOMEM);
317 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
318 st->codecpar->codec_id = AV_CODEC_ID_MPEG2VIDEO;
319 st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
320 avpriv_set_pts_info(st, 64, 1, 90000);
321
322 ast = avformat_new_stream(s, NULL);
323 if (!ast)
324 return AVERROR(ENOMEM);
325 ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
326
327 if (ty->audio_type == TIVO_AUDIO_MPEG) {
328 ast->codecpar->codec_id = AV_CODEC_ID_MP2;
329 ast->need_parsing = AVSTREAM_PARSE_FULL_RAW;
330 } else {
331 ast->codecpar->codec_id = AV_CODEC_ID_AC3;
332 }
333 avpriv_set_pts_info(ast, 64, 1, 90000);
334
335 ty->first_chunk = 1;
336
337 avio_seek(pb, 0, SEEK_SET);
338
339 return 0;
340 }
341
342 /* parse a master chunk, filling the SEQ table and other variables.
343 * We assume the stream is currently pointing to it.
344 */
parse_master(AVFormatContext * s)345 static void parse_master(AVFormatContext *s)
346 {
347 TYDemuxContext *ty = s->priv_data;
348 unsigned map_size; /* size of bitmask, in bytes */
349 unsigned i, j;
350
351 /* Note that the entries in the SEQ table in the stream may have
352 different sizes depending on the bits per entry. We store them
353 all in the same size structure, so we have to parse them out one
354 by one. If we had a dynamic structure, we could simply read the
355 entire table directly from the stream into memory in place. */
356
357 /* clear the SEQ table */
358 av_freep(&ty->seq_table);
359
360 /* parse header info */
361
362 map_size = AV_RB32(ty->chunk + 20); /* size of bitmask, in bytes */
363 i = AV_RB32(ty->chunk + 28); /* size of SEQ table, in bytes */
364
365 ty->seq_table_size = i / (8LL + map_size);
366
367 if (ty->seq_table_size == 0) {
368 ty->seq_table = NULL;
369 return;
370 }
371
372 /* parse all the entries */
373 ty->seq_table = av_calloc(ty->seq_table_size, sizeof(TySeqTable));
374 if (ty->seq_table == NULL) {
375 ty->seq_table_size = 0;
376 return;
377 }
378
379 ty->cur_chunk_pos = 32;
380 for (j = 0; j < ty->seq_table_size; j++) {
381 if (ty->cur_chunk_pos >= CHUNK_SIZE - 8)
382 return;
383 ty->seq_table[j].timestamp = AV_RB64(ty->chunk + ty->cur_chunk_pos);
384 ty->cur_chunk_pos += 8;
385 if (map_size > 8) {
386 av_log(s, AV_LOG_ERROR, "Unsupported SEQ bitmap size in master chunk.\n");
387 ty->cur_chunk_pos += map_size;
388 } else {
389 memcpy(ty->seq_table[j].chunk_bitmask, ty->chunk + ty->cur_chunk_pos, map_size);
390 }
391 }
392 }
393
get_chunk(AVFormatContext * s)394 static int get_chunk(AVFormatContext *s)
395 {
396 TYDemuxContext *ty = s->priv_data;
397 AVIOContext *pb = s->pb;
398 int read_size, num_recs;
399
400 ff_dlog(s, "parsing ty chunk #%d\n", ty->cur_chunk);
401
402 /* if we have left-over filler space from the last chunk, get that */
403 if (avio_feof(pb))
404 return AVERROR_EOF;
405
406 /* read the TY packet header */
407 read_size = avio_read(pb, ty->chunk, CHUNK_SIZE);
408 ty->cur_chunk++;
409
410 if ((read_size < 4) || (AV_RB32(ty->chunk) == 0)) {
411 return AVERROR_EOF;
412 }
413
414 /* check if it's a PART Header */
415 if (AV_RB32(ty->chunk) == TIVO_PES_FILEID) {
416 parse_master(s); /* parse master chunk */
417 return get_chunk(s);
418 }
419
420 /* number of records in chunk (8- or 16-bit number) */
421 if (ty->chunk[3] & 0x80) {
422 /* 16 bit rec cnt */
423 ty->num_recs = num_recs = (ty->chunk[1] << 8) + ty->chunk[0];
424 ty->seq_rec = (ty->chunk[3] << 8) + ty->chunk[2];
425 if (ty->seq_rec != 0xffff) {
426 ty->seq_rec &= ~0x8000;
427 }
428 } else {
429 /* 8 bit reclen - TiVo 1.3 format */
430 ty->num_recs = num_recs = ty->chunk[0];
431 ty->seq_rec = ty->chunk[1];
432 }
433 ty->cur_rec = 0;
434 ty->first_chunk = 0;
435
436 ff_dlog(s, "chunk has %d records\n", num_recs);
437 ty->cur_chunk_pos = 4;
438
439 av_freep(&ty->rec_hdrs);
440
441 if (num_recs * 16 >= CHUNK_SIZE - 4)
442 return AVERROR_INVALIDDATA;
443
444 ty->rec_hdrs = parse_chunk_headers(ty->chunk + 4, num_recs);
445 if (!ty->rec_hdrs)
446 return AVERROR(ENOMEM);
447 ty->cur_chunk_pos += 16 * num_recs;
448
449 return 0;
450 }
451
demux_video(AVFormatContext * s,TyRecHdr * rec_hdr,AVPacket * pkt)452 static int demux_video(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt)
453 {
454 TYDemuxContext *ty = s->priv_data;
455 const int subrec_type = rec_hdr->subrec_type;
456 const int64_t rec_size = rec_hdr->rec_size;
457 int es_offset1, ret;
458 int got_packet = 0;
459
460 if (subrec_type != 0x02 && subrec_type != 0x0c &&
461 subrec_type != 0x08 && rec_size > 4) {
462 /* get the PTS from this packet if it has one.
463 * on S1, only 0x06 has PES. On S2, however, most all do.
464 * Do NOT Pass the PES Header to the MPEG2 codec */
465 es_offset1 = find_es_header(ty_VideoPacket, ty->chunk + ty->cur_chunk_pos, 5);
466 if (es_offset1 != -1) {
467 ty->last_video_pts = ff_parse_pes_pts(
468 ty->chunk + ty->cur_chunk_pos + es_offset1 + VIDEO_PTS_OFFSET);
469 if (subrec_type != 0x06) {
470 /* if we found a PES, and it's not type 6, then we're S2 */
471 /* The packet will have video data (& other headers) so we
472 * chop out the PES header and send the rest */
473 if (rec_size >= VIDEO_PES_LENGTH + es_offset1) {
474 int size = rec_hdr->rec_size - VIDEO_PES_LENGTH - es_offset1;
475
476 ty->cur_chunk_pos += VIDEO_PES_LENGTH + es_offset1;
477 if ((ret = av_new_packet(pkt, size)) < 0)
478 return ret;
479 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, size);
480 ty->cur_chunk_pos += size;
481 pkt->stream_index = 0;
482 got_packet = 1;
483 } else {
484 ff_dlog(s, "video rec type 0x%02x has short PES"
485 " (%"PRId64" bytes)\n", subrec_type, rec_size);
486 /* nuke this block; it's too short, but has PES marker */
487 ty->cur_chunk_pos += rec_size;
488 return 0;
489 }
490 }
491 }
492 }
493
494 if (subrec_type == 0x06) {
495 /* type 6 (S1 DTivo) has no data, so we're done */
496 ty->cur_chunk_pos += rec_size;
497 return 0;
498 }
499
500 if (!got_packet) {
501 if ((ret = av_new_packet(pkt, rec_size)) < 0)
502 return ret;
503 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
504 ty->cur_chunk_pos += rec_size;
505 pkt->stream_index = 0;
506 got_packet = 1;
507 }
508
509 /* if it's not a continue blk, then set PTS */
510 if (subrec_type != 0x02) {
511 if (subrec_type == 0x0c && pkt->size >= 6)
512 pkt->data[5] |= 0x08;
513 if (subrec_type == 0x07) {
514 ty->last_ty_pts = rec_hdr->ty_pts;
515 } else {
516 /* yes I know this is a cheap hack. It's the timestamp
517 used for display and skipping fwd/back, so it
518 doesn't have to be accurate to the millisecond.
519 I adjust it here by roughly one 1/30 sec. Yes it
520 will be slightly off for UK streams, but it's OK.
521 */
522 ty->last_ty_pts += 35000000;
523 //ty->last_ty_pts += 33366667;
524 }
525 /* set PTS for this block before we send */
526 if (ty->last_video_pts > AV_NOPTS_VALUE) {
527 pkt->pts = ty->last_video_pts;
528 /* PTS gets used ONCE.
529 * Any subsequent frames we get BEFORE next PES
530 * header will have their PTS computed in the codec */
531 ty->last_video_pts = AV_NOPTS_VALUE;
532 }
533 }
534
535 return got_packet;
536 }
537
check_sync_pes(AVFormatContext * s,AVPacket * pkt,int32_t offset,int32_t rec_len)538 static int check_sync_pes(AVFormatContext *s, AVPacket *pkt,
539 int32_t offset, int32_t rec_len)
540 {
541 TYDemuxContext *ty = s->priv_data;
542
543 if (offset < 0 || offset + ty->pes_length > rec_len) {
544 /* entire PES header not present */
545 ff_dlog(s, "PES header at %"PRId32" not complete in record. storing.\n", offset);
546 /* save the partial pes header */
547 if (offset < 0) {
548 /* no header found, fake some 00's (this works, believe me) */
549 memset(ty->pes_buffer, 0, 4);
550 ty->pes_buf_cnt = 4;
551 if (rec_len > 4)
552 ff_dlog(s, "PES header not found in record of %"PRId32" bytes!\n", rec_len);
553 return -1;
554 }
555 /* copy the partial pes header we found */
556 memcpy(ty->pes_buffer, pkt->data + offset, rec_len - offset);
557 ty->pes_buf_cnt = rec_len - offset;
558
559 if (offset > 0) {
560 /* PES Header was found, but not complete, so trim the end of this record */
561 pkt->size -= rec_len - offset;
562 return 1;
563 }
564 return -1; /* partial PES, no audio data */
565 }
566 /* full PES header present, extract PTS */
567 ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[ offset + ty->pts_offset]);
568 if (ty->first_audio_pts == AV_NOPTS_VALUE)
569 ty->first_audio_pts = ty->last_audio_pts;
570 pkt->pts = ty->last_audio_pts;
571 memmove(pkt->data + offset, pkt->data + offset + ty->pes_length, rec_len - ty->pes_length);
572 pkt->size -= ty->pes_length;
573 return 0;
574 }
575
demux_audio(AVFormatContext * s,TyRecHdr * rec_hdr,AVPacket * pkt)576 static int demux_audio(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt)
577 {
578 TYDemuxContext *ty = s->priv_data;
579 const int subrec_type = rec_hdr->subrec_type;
580 const int64_t rec_size = rec_hdr->rec_size;
581 int es_offset1, ret;
582
583 if (subrec_type == 2) {
584 int need = 0;
585 /* SA or DTiVo Audio Data, no PES (continued block)
586 * ================================================
587 */
588
589 /* continue PES if previous was incomplete */
590 if (ty->pes_buf_cnt > 0) {
591 need = ty->pes_length - ty->pes_buf_cnt;
592
593 ff_dlog(s, "continuing PES header\n");
594 /* do we have enough data to complete? */
595 if (need >= rec_size) {
596 /* don't have complete PES hdr; save what we have and return */
597 memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, rec_size);
598 ty->cur_chunk_pos += rec_size;
599 ty->pes_buf_cnt += rec_size;
600 return 0;
601 }
602
603 /* we have enough; reconstruct this frame with the new hdr */
604 memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, need);
605 ty->cur_chunk_pos += need;
606 /* get the PTS out of this PES header (MPEG or AC3) */
607 if (ty->audio_type == TIVO_AUDIO_MPEG) {
608 es_offset1 = find_es_header(ty_MPEGAudioPacket,
609 ty->pes_buffer, 5);
610 } else {
611 es_offset1 = find_es_header(ty_AC3AudioPacket,
612 ty->pes_buffer, 5);
613 }
614 if (es_offset1 < 0) {
615 ff_dlog(s, "Can't find audio PES header in packet.\n");
616 } else {
617 ty->last_audio_pts = ff_parse_pes_pts(
618 &ty->pes_buffer[es_offset1 + ty->pts_offset]);
619 pkt->pts = ty->last_audio_pts;
620 }
621 ty->pes_buf_cnt = 0;
622
623 }
624 if ((ret = av_new_packet(pkt, rec_size - need)) < 0)
625 return ret;
626 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size - need);
627 ty->cur_chunk_pos += rec_size - need;
628 pkt->stream_index = 1;
629
630 /* S2 DTivo has AC3 packets with 2 padding bytes at end. This is
631 * not allowed in the AC3 spec and will cause problems. So here
632 * we try to trim things. */
633 /* Also, S1 DTivo has alternating short / long AC3 packets. That
634 * is, one packet is short (incomplete) and the next packet has
635 * the first one's missing data, plus all of its own. Strange. */
636 if (ty->audio_type == TIVO_AUDIO_AC3 &&
637 ty->tivo_series == TIVO_SERIES2) {
638 if (ty->ac3_pkt_size + pkt->size > AC3_PKT_LENGTH) {
639 pkt->size -= 2;
640 ty->ac3_pkt_size = 0;
641 } else {
642 ty->ac3_pkt_size += pkt->size;
643 }
644 }
645 } else if (subrec_type == 0x03) {
646 if ((ret = av_new_packet(pkt, rec_size)) < 0)
647 return ret;
648 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
649 ty->cur_chunk_pos += rec_size;
650 pkt->stream_index = 1;
651 /* MPEG Audio with PES Header, either SA or DTiVo */
652 /* ================================================ */
653 es_offset1 = find_es_header(ty_MPEGAudioPacket, pkt->data, 5);
654
655 /* SA PES Header, No Audio Data */
656 /* ================================================ */
657 if ((es_offset1 == 0) && (rec_size == 16)) {
658 ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[SA_PTS_OFFSET]);
659 if (ty->first_audio_pts == AV_NOPTS_VALUE)
660 ty->first_audio_pts = ty->last_audio_pts;
661 av_packet_unref(pkt);
662 return 0;
663 }
664 /* DTiVo Audio with PES Header */
665 /* ================================================ */
666
667 /* Check for complete PES */
668 if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) {
669 /* partial PES header found, nothing else.
670 * we're done. */
671 av_packet_unref(pkt);
672 return 0;
673 }
674 } else if (subrec_type == 0x04) {
675 /* SA Audio with no PES Header */
676 /* ================================================ */
677 if ((ret = av_new_packet(pkt, rec_size)) < 0)
678 return ret;
679 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
680 ty->cur_chunk_pos += rec_size;
681 pkt->stream_index = 1;
682 pkt->pts = ty->last_audio_pts;
683 } else if (subrec_type == 0x09) {
684 if ((ret = av_new_packet(pkt, rec_size)) < 0)
685 return ret;
686 memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size);
687 ty->cur_chunk_pos += rec_size ;
688 pkt->stream_index = 1;
689
690 /* DTiVo AC3 Audio Data with PES Header */
691 /* ================================================ */
692 es_offset1 = find_es_header(ty_AC3AudioPacket, pkt->data, 5);
693
694 /* Check for complete PES */
695 if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) {
696 /* partial PES header found, nothing else. we're done. */
697 av_packet_unref(pkt);
698 return 0;
699 }
700 /* S2 DTivo has invalid long AC3 packets */
701 if (ty->tivo_series == TIVO_SERIES2) {
702 if (pkt->size > AC3_PKT_LENGTH) {
703 pkt->size -= 2;
704 ty->ac3_pkt_size = 0;
705 } else {
706 ty->ac3_pkt_size = pkt->size;
707 }
708 }
709 } else {
710 /* Unsupported/Unknown */
711 ty->cur_chunk_pos += rec_size;
712 return 0;
713 }
714
715 return 1;
716 }
717
ty_read_packet(AVFormatContext * s,AVPacket * pkt)718 static int ty_read_packet(AVFormatContext *s, AVPacket *pkt)
719 {
720 TYDemuxContext *ty = s->priv_data;
721 AVIOContext *pb = s->pb;
722 TyRecHdr *rec;
723 int64_t rec_size = 0;
724 int ret = 0;
725
726 if (avio_feof(pb))
727 return AVERROR_EOF;
728
729 while (ret <= 0) {
730 if (!ty->rec_hdrs || ty->first_chunk || ty->cur_rec >= ty->num_recs) {
731 if (get_chunk(s) < 0 || ty->num_recs <= 0)
732 return AVERROR_EOF;
733 }
734
735 rec = &ty->rec_hdrs[ty->cur_rec];
736 rec_size = rec->rec_size;
737 ty->cur_rec++;
738
739 if (rec_size <= 0)
740 continue;
741
742 if (ty->cur_chunk_pos + rec->rec_size > CHUNK_SIZE)
743 return AVERROR_INVALIDDATA;
744
745 if (avio_feof(pb))
746 return AVERROR_EOF;
747
748 switch (rec->rec_type) {
749 case VIDEO_ID:
750 ret = demux_video(s, rec, pkt);
751 break;
752 case AUDIO_ID:
753 ret = demux_audio(s, rec, pkt);
754 break;
755 default:
756 ff_dlog(s, "Invalid record type 0x%02x\n", rec->rec_type);
757 case 0x01:
758 case 0x02:
759 case 0x03: /* TiVo data services */
760 case 0x05: /* unknown, but seen regularly */
761 ty->cur_chunk_pos += rec->rec_size;
762 break;
763 }
764 }
765
766 return 0;
767 }
768
ty_read_close(AVFormatContext * s)769 static int ty_read_close(AVFormatContext *s)
770 {
771 TYDemuxContext *ty = s->priv_data;
772
773 av_freep(&ty->seq_table);
774 av_freep(&ty->rec_hdrs);
775
776 return 0;
777 }
778
779 AVInputFormat ff_ty_demuxer = {
780 .name = "ty",
781 .long_name = NULL_IF_CONFIG_SMALL("TiVo TY Stream"),
782 .priv_data_size = sizeof(TYDemuxContext),
783 .read_probe = ty_probe,
784 .read_header = ty_read_header,
785 .read_packet = ty_read_packet,
786 .read_close = ty_read_close,
787 .extensions = "ty,ty+",
788 .flags = AVFMT_TS_DISCONT,
789 };
790