Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
Steve Lhomme
VLC
Commits
1e9df876
Commit
1e9df876
authored
Mar 11, 2005
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Tivo file demuxer
based on patch from Neal Symms <nsymms # redwar.us> with minor cleanups
parent
5f549ab8
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
959 additions
and
1 deletion
+959
-1
configure.ac
configure.ac
+1
-1
modules/demux/Modules.am
modules/demux/Modules.am
+1
-0
modules/demux/ty.c
modules/demux/ty.c
+957
-0
No files found.
configure.ac
View file @
1e9df876
...
...
@@ -983,7 +983,7 @@ VLC_ADD_PLUGINS([trivial_resampler ugly_resampler])
VLC_ADD_PLUGINS([trivial_channel_mixer trivial_mixer])
VLC_ADD_PLUGINS([id3 playlist export sgimb m3u xtag])
VLC_ADD_PLUGINS([i420_rgb rawvideo blend scale image logo])
VLC_ADD_PLUGINS([wav araw subtitle vobsub adpcm a52sys dtssys au voc xa])
VLC_ADD_PLUGINS([wav araw subtitle vobsub adpcm a52sys dtssys au
ty
voc xa])
VLC_ADD_PLUGINS([access_directory access_file access_udp access_tcp])
VLC_ADD_PLUGINS([access_http access_mms access_ftp ipv4])
VLC_ADD_PLUGINS([packetizer_mpegvideo packetizer_h264])
...
...
modules/demux/Modules.am
View file @
1e9df876
...
...
@@ -20,6 +20,7 @@ SOURCES_aiff = aiff.c
SOURCES_sgimb = sgimb.c
SOURCES_mjpeg = mjpeg.c
SOURCES_subtitle = subtitle.c
SOURCES_ty = ty.c
SOURCES_vobsub = vobsub.c
SOURCES_voc = voc.c
SOURCES_xa = xa.c
modules/demux/ty.c
0 → 100644
View file @
1e9df876
/*****************************************************************************
* ty.c - TiVo ty stream video demuxer for VLC
*****************************************************************************
* Copyright (C) 2005 VideoLAN
* Copyright (C) 2005 by Neal Symms (tivo@freakinzoo.com) - February 2005
* based on code by Christopher Wingert for tivo-mplayer
* tivo(at)wingert.org, February 2003
*
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*
* CODE CHANGES:
* v1.0.0 - 24-Feb-2005 - Initial release - Series 1 support ONLY!
* v1.0.1 - 25-Feb-2005 - Added fix for bad GOP headers - Neal
* v1.0.2 - 26-Feb-2005 - No longer require "seekable" input stream - Neal
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "vlc_codec.h"
#define SERIES1_PES_LENGTH (11)
#define SERIES2_PES_LENGTH (16)
#define AC3_PES_LENGTH (14)
#define DTIVO_PTS_OFFSET (6)
#define SA_PTS_OFFSET (9)
#define AC3_PTS_OFFSET (9)
static
const
unsigned
char
ty_VideoPacket
[]
=
{
0x00
,
0x00
,
0x01
,
0xe0
};
static
const
unsigned
char
ty_MPEGAudioPacket
[]
=
{
0x00
,
0x00
,
0x01
,
0xc0
};
static
const
unsigned
char
ty_AC3AudioPacket
[]
=
{
0x00
,
0x00
,
0x01
,
0xbd
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
int
get_chunk_header
(
demux_t
*
);
static
void
setup_audio_streams
(
char
,
demux_t
*
);
static
mtime_t
get_pts
(
unsigned
char
*
buf
);
static
int
find_es_header
(
unsigned
const
char
*
header
,
unsigned
char
*
buffer
,
int
bufferSize
,
int
*
esOffset1
);
static
int
ty_stream_seek
(
demux_t
*
p_demux
,
double
seek_pct
);
static
int
TyOpen
(
vlc_object_t
*
);
static
void
TyClose
(
vlc_object_t
*
);
static
int
TyDemux
(
demux_t
*
);
static
int
Control
(
demux_t
*
,
int
,
va_list
);
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin
();
set_shortname
(
_
(
"TY"
)
);
set_description
(
_
(
"TY Stream audio/video demux"
));
set_category
(
CAT_INPUT
);
set_subcategory
(
SUBCAT_INPUT_DEMUX
);
set_capability
(
"demux2"
,
10
);
set_callbacks
(
TyOpen
,
TyClose
);
add_shortcut
(
"ty"
);
add_shortcut
(
"tivo"
);
vlc_module_end
();
/* packet types for reference:
2/c0: audio data continued
3/c0: audio packet header (PES header)
4/c0: audio data (S/A only?)
9/c0: audio packet header, AC-3 audio
2/e0: video data continued
6/e0: video packet header (PES header)
7/e0: video sequence header start
8/e0: video I-frame header start
a/e0: video P-frame header start
b/e0: video B-frame header start
c/e0: video GOP header start
e/01: closed-caption data
e/02: Extended data services data
e/03: ipreview data ("thumbs up to record" signal)
*/
#define TIVO_PES_FILEID ( 0xf5467abd )
#define TIVO_PART_LENGTH ( 0x20000000 )
/* 536,870,912 bytes */
#define CHUNK_SIZE ( 128 * 1024 )
typedef
struct
{
long
l_rec_size
;
unsigned
char
ex1
,
ex2
;
unsigned
char
rec_type
;
unsigned
char
subrec_type
;
char
b_ext
;
}
ty_rec_hdr_t
;
struct
demux_sys_t
{
es_out_id_t
*
p_video
;
/* ptr to video codec */
es_out_id_t
*
p_audio
;
/* holds either ac3 or mpeg codec ptr */
int
i_chunk_count
;
int
i_stuff_cnt
;
size_t
i_stream_size
;
/* size of input stream (if known) */
vlc_bool_t
b_seekable
;
/* is this stream seekable? */
int
tivoType
;
/* 1 = SA, 2 = DTiVo */
vlc_bool_t
b_mpeg_audio
;
/* true if we're using MPEG audio */
uint8_t
pes_buffer
[
20
];
/* holds incomplete pes headers */
int
i_pes_buf_cnt
;
/* how many bytes in our buffer */
mtime_t
firstAudioPTS
;
mtime_t
lastAudioPTS
;
mtime_t
lastVideoPTS
;
ty_rec_hdr_t
*
rec_hdrs
;
/* record headers array */
int
i_cur_rec
;
/* current record in this chunk */
int
i_num_recs
;
/* number of recs in this chunk */
int
i_seq_rec
;
/* record number where seq start is */
vlc_bool_t
eof
;
vlc_bool_t
b_first_chunk
;
};
/*
* TyOpen: check file and initialize demux structures
*
* here's what we do:
* 1. peek at the first 12 bytes of the stream for the
* magic TiVo PART header & stream type & chunk size
* 2. if it's not there, error with VLC_EGENERIC
* 3. set up video (mpgv) codec
* 4. return VLC_SUCCESS
*/
static
int
TyOpen
(
vlc_object_t
*
p_this
)
{
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
demux_sys_t
*
p_sys
;
vlc_bool_t
b_seekable
;
es_format_t
fmt
;
uint8_t
*
p_peek
;
/* see if this stream is seekable */
stream_Control
(
p_demux
->
s
,
STREAM_CAN_SEEK
,
&
b_seekable
);
/* peek at the first 12 bytes. */
/* for TY streams, they're always the same */
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
12
)
<
12
)
return
VLC_EGENERIC
;
if
(
U32_AT
(
p_peek
)
!=
TIVO_PES_FILEID
||
U32_AT
(
&
p_peek
[
4
])
!=
0x02
||
U32_AT
(
&
p_peek
[
8
])
!=
CHUNK_SIZE
)
{
/* doesn't look like a TY file... */
char
*
psz_ext
=
strrchr
(
p_demux
->
psz_path
,
'.'
);
/* if they specified tydemux, or if the file ends in .ty we try anyway */
if
(
strcmp
(
p_demux
->
psz_demux
,
"tydemux"
)
&&
strcasecmp
(
psz_ext
,
".ty"
))
return
VLC_EGENERIC
;
msg_Warn
(
p_demux
,
"this does not look like a TY file, continuing anyway..."
);
}
/* at this point, we assume we have a valid TY stream */
msg_Dbg
(
p_demux
,
"valid TY stream detected"
);
/* Set exported functions */
p_demux
->
pf_demux
=
TyDemux
;
p_demux
->
pf_control
=
Control
;
/* create our structure that will hold all data */
p_demux
->
p_sys
=
p_sys
=
malloc
(
sizeof
(
demux_sys_t
));
memset
(
p_sys
,
0
,
sizeof
(
demux_sys_t
));
/* set up our struct (most were zero'd out with the memset above) */
p_sys
->
b_first_chunk
=
VLC_TRUE
;
p_sys
->
firstAudioPTS
=
-
1
;
p_sys
->
i_stream_size
=
stream_Size
(
p_demux
->
s
);
p_sys
->
b_mpeg_audio
=
VLC_FALSE
;
p_sys
->
b_seekable
=
b_seekable
;
/* TODO: read first chunk & parse first audio PTS, then (if seekable)
* seek to last chunk & last record; read its PTS and compute
* overall program time. Also determine Tivo type. */
/* NOTE: we wait to create the audio ES until we know what
* audio type we have. */
p_sys
->
p_audio
=
NULL
;
/* register the video stream */
es_format_Init
(
&
fmt
,
VIDEO_ES
,
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
)
);
p_sys
->
p_video
=
es_out_Add
(
p_demux
->
out
,
&
fmt
);
#if 0
/* register the CC decoder */
es_format_Init( &fmt, SPU_ES, VLC_FOURCC('s', 'u', 'b', 't'));
p_sys->p_subt_es = es_out_Add(p_demux->out, &fmt);
#endif
return
VLC_SUCCESS
;
}
/* set up audio codec.
* this will be called once we determine audio type */
static
void
setup_audio_streams
(
char
stream_type
,
demux_t
*
p_demux
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
es_format_t
fmt
;
if
(
stream_type
==
'A'
)
{
/* AC3 audio detected */
es_format_Init
(
&
fmt
,
AUDIO_ES
,
VLC_FOURCC
(
'a'
,
'5'
,
'2'
,
' '
)
);
p_sys
->
tivoType
=
2
;
/* AC3 is only on dtivo */
}
else
{
/* assume MPEG */
es_format_Init
(
&
fmt
,
AUDIO_ES
,
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
)
);
p_sys
->
b_mpeg_audio
=
VLC_TRUE
;
}
/* register the chosen audio output codec */
p_sys
->
p_audio
=
es_out_Add
(
p_demux
->
out
,
&
fmt
);
}
/* =========================================================================== */
/* Compute Presentation Time Stamp (PTS)
* Assume buf points to beginning of PTS */
static
mtime_t
get_pts
(
unsigned
char
*
buf
)
{
mtime_t
i_pts
;
i_pts
=
((
mtime_t
)(
buf
[
0
]
&
0x0e
)
<<
29
)
|
(
mtime_t
)(
buf
[
1
]
<<
22
)
|
((
mtime_t
)(
buf
[
2
]
&
0xfe
)
<<
14
)
|
(
mtime_t
)(
buf
[
3
]
<<
7
)
|
(
mtime_t
)(
buf
[
4
]
>>
1
);
i_pts
*=
100
/
9
;
/* convert PTS (90Khz clock) to microseconds */
return
i_pts
;
}
/* =========================================================================== */
static
int
find_es_header
(
unsigned
const
char
*
header
,
unsigned
char
*
buffer
,
int
bufferSize
,
int
*
esOffset1
)
{
int
count
;
*
esOffset1
=
-
1
;
for
(
count
=
0
;
count
<
bufferSize
;
count
++
)
{
if
(
(
buffer
[
count
+
0
]
==
header
[
0
]
)
&&
(
buffer
[
count
+
1
]
==
header
[
1
]
)
&&
(
buffer
[
count
+
2
]
==
header
[
2
]
)
&&
(
buffer
[
count
+
3
]
==
header
[
3
]
)
)
{
*
esOffset1
=
count
;
return
1
;
}
}
return
(
-
1
);
}
/* =========================================================================== */
/* check if we have a full PES header, if not, then save what we have.
* this is called when audio-start packets are encountered.
* Returns:
* 1 partial PES hdr found, some audio data found (buffer adjusted),
* -1 partial PES hdr found, no audio data found
* 0 otherwise (complete PES found, pts extracted, pts set, buffer adjusted) */
/* TODO: fix it so it works with S2 / SA / DTivo / HD etc... */
static
int
check_sync_pes
(
demux_t
*
p_demux
,
block_t
*
p_block
,
int32_t
offset
,
int32_t
rec_len
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
int
pts_offset
;
int
pes_length
=
p_sys
->
b_mpeg_audio
?
SERIES1_PES_LENGTH
:
AC3_PES_LENGTH
;
if
(
p_sys
->
tivoType
==
1
)
{
/* SA tivo */
pts_offset
=
SA_PTS_OFFSET
;
}
else
{
/* DTivo */
pts_offset
=
p_sys
->
b_mpeg_audio
?
DTIVO_PTS_OFFSET
:
AC3_PTS_OFFSET
;
}
if
(
offset
<
0
||
offset
+
pes_length
>
rec_len
)
{
/* entire PES header not present */
msg_Dbg
(
p_demux
,
"PES header at %d not complete in record. storing."
,
offset
);
/* save the partial pes header */
if
(
offset
<
0
)
{
/* no header found, fake some 00's (this works, believe me) */
memset
(
p_sys
->
pes_buffer
,
4
,
0
);
p_sys
->
i_pes_buf_cnt
=
4
;
if
(
rec_len
>
4
)
msg_Err
(
p_demux
,
"PES header not found in record of %d bytes!"
,
rec_len
);
return
-
1
;
}
/* copy the partial pes header we found */
memcpy
(
p_sys
->
pes_buffer
,
p_block
->
p_buffer
+
offset
,
rec_len
-
offset
);
p_sys
->
i_pes_buf_cnt
=
rec_len
-
offset
;
if
(
offset
>
0
)
{
/* PES Header was found, but not complete, so trim the end of this record */
p_block
->
i_buffer
-=
rec_len
-
offset
;
return
1
;
}
return
-
1
;
/* partial PES, no audio data */
}
/* full PES header present, extract PTS */
p_sys
->
lastAudioPTS
=
get_pts
(
&
p_block
->
p_buffer
[
offset
+
pts_offset
]
);
if
(
p_sys
->
firstAudioPTS
<
0
)
p_sys
->
firstAudioPTS
=
p_sys
->
lastAudioPTS
;
p_block
->
i_pts
=
p_sys
->
lastAudioPTS
;
/*msg_Dbg(p_demux, "Audio PTS %lld", p_sys->lastAudioPTS );*/
/* adjust audio record to remove PES header */
memmove
(
p_block
->
p_buffer
+
offset
,
p_block
->
p_buffer
+
offset
+
pes_length
,
rec_len
-
pes_length
);
p_block
->
i_buffer
-=
pes_length
;
return
0
;
}
/* =========================================================================== */
/* TyDemux: Read & Demux one record from the chunk
*
* Returns -1 in case of error, 0 in case of EOF, 1 otherwise
*
* NOTE: I think we can return the number of packets sent instead of just 1.
* that means we can demux an entire chunk and shoot it back (may be more efficient)
* -- should try that some day :) --
*/
int
TyDemux
(
demux_t
*
p_demux
)
{
int
invalidType
=
0
;
int
recordsDecoded
=
0
;
int
rec_type
;
long
l_rec_size
;
int
i_cur_rec
;
int
subrec_type
;
ty_rec_hdr_t
*
rec_hdr
;
block_t
*
p_block_in
=
NULL
;
int
esOffset1
;
unsigned
char
lastCC
[
16
];
unsigned
char
lastXDS
[
16
];
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
/*msg_Dbg(p_demux, "ty demux processing" );*/
/* did we hit EOF earlier? */
if
(
p_sys
->
eof
)
return
0
;
/*
* what we do (1 record now.. maybe more later):
* - use stream_Read() to read the chunk header & record headers
* - discard entire chunk if it is a PART header chunk
* - parse all the headers into record header array
* - keep a pointer of which record we're on
* - use stream_Block() to fetch each record
* - parse out PTS from PES headers
* - set PTS for data packets
* - pass the data on to the proper codec via es_out_Send()
* if this is the first time or
* if we're at the end of this chunk, start a new one
*/
/* parse the next chunk's record headers */
if
(
p_sys
->
b_first_chunk
||
p_sys
->
i_cur_rec
>=
p_sys
->
i_num_recs
)
if
(
get_chunk_header
(
p_demux
)
==
0
)
return
0
;
/*======================================================================
* parse & send one record of the chunk
*====================================================================== */
i_cur_rec
=
p_sys
->
i_cur_rec
;
recordsDecoded
++
;
rec_hdr
=
&
p_sys
->
rec_hdrs
[
i_cur_rec
];
subrec_type
=
rec_hdr
->
subrec_type
;
rec_type
=
rec_hdr
->
rec_type
;
l_rec_size
=
rec_hdr
->
l_rec_size
;
if
(
!
rec_hdr
->
b_ext
)
{
/*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes",
subrec_type, rec_type, l_rec_size );*/
/* some normal records are 0 length, so check for that... */
if
(
l_rec_size
>
0
)
{
/* read in this record's payload */
if
(
!
(
p_block_in
=
stream_Block
(
p_demux
->
s
,
l_rec_size
)
)
)
{
/* EOF */
p_sys
->
eof
=
1
;
return
0
;
}
/* set these as 'unknown' for now */
p_block_in
->
i_pts
=
p_block_in
->
i_dts
=
0
;
}
else
{
/* no data in payload; we're done */
p_sys
->
i_cur_rec
++
;
return
1
;
}
}
/*else
{
-- don't read any data from the stream, data was in the record header --
msg_Dbg(p_demux,
"Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type,
rec_type, rec_hdr->ex1, rec_hdr->ex2);
}*/
/*================================================================*
* Video Parsing
*================================================================*/
if
(
rec_type
==
0xe0
)
{
if
(
subrec_type
==
0x06
)
{
/* get the PTS from this packet.
* Do NOT Pass this packet (a PES Header) on to the MPEG2 codec */
find_es_header
(
ty_VideoPacket
,
p_block_in
->
p_buffer
,
l_rec_size
,
&
esOffset1
);
if
(
esOffset1
!=
-
1
)
{
/* msg_Dbg(p_demux, "Video PES hdr at offset %d", esOffset1); */
p_sys
->
lastVideoPTS
=
get_pts
(
&
p_block_in
->
p_buffer
[
esOffset1
+
9
]
);
/*msg_Dbg(p_demux, "Video rec %d PTS "I64Fd, p_sys->i_cur_rec,
p_sys->lastVideoPTS );*/
}
block_Release
(
p_block_in
);
}
else
{
#if 0
msg_Dbg(p_demux, "packet buffer has "
"%02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x",
p_block_in->p_buffer[0], p_block_in->p_buffer[1],
p_block_in->p_buffer[2], p_block_in->p_buffer[3],
p_block_in->p_buffer[4], p_block_in->p_buffer[5],
p_block_in->p_buffer[6], p_block_in->p_buffer[7],
p_block_in->p_buffer[8], p_block_in->p_buffer[9],
p_block_in->p_buffer[10], p_block_in->p_buffer[11],
p_block_in->p_buffer[12], p_block_in->p_buffer[13],
p_block_in->p_buffer[14], p_block_in->p_buffer[15]);
#endif
/* if it's not a continue blk, then set PTS */
if
(
subrec_type
!=
0x02
)
{
/*msg_Dbg(p_demux, "Video rec %d type 0x%02X", p_sys->i_cur_rec,
subrec_type);*/
/* if it's a GOP header, make sure it's legal
* (if we have enough data) */
/* Some ty files don't have this bit set
* and it causes problems */
if
(
subrec_type
==
0x0c
&&
l_rec_size
>=
6
)
p_block_in
->
p_buffer
[
5
]
|=
0x08
;
/* set PTS for this block before we send */
if
(
p_sys
->
lastVideoPTS
>
0
)
{
p_block_in
->
i_pts
=
p_sys
->
lastVideoPTS
;
/* PTS gets used ONCE.
* Any subsequent frames we get BEFORE next PES
* header will have their PTS computed in the codec */
p_sys
->
lastVideoPTS
=
0
;
}
}
es_out_Send
(
p_demux
->
out
,
p_sys
->
p_video
,
p_block_in
);
}
}
/* end if video rec type */
/* ================================================================
* Audio Parsing
* ================================================================
* parse PES headers and send the rest to the codec
*/
else
if
(
rec_type
==
0xc0
)
{
#if 0
int i;
printf( "Audio Packet Header " );
for( i = 0 ; i < 24 ; i++ )
printf( "%2.2x ", p_block_in->p_buffer[i] );
printf( "\n" );
#endif
/* load a codec if we haven't yet */
if
(
p_sys
->
p_audio
==
NULL
)
{
if
(
subrec_type
==
0x09
)
{
/* set up for AC-3 audio */
msg_Dbg
(
p_demux
,
"detected AC-3 Audio"
);
setup_audio_streams
(
'A'
,
p_demux
);
}
else
{
/* set up for MPEG audio */
msg_Dbg
(
p_demux
,
"detected MPEG Audio"
);
setup_audio_streams
(
'M'
,
p_demux
);
}
}
/* SA or DTiVo Audio Data, no PES (continued block)
* ================================================
*/
if
(
subrec_type
==
2
)
{
/* continue PES if previous was incomplete */
/* TODO: Make this work for all series & types of tivos */
if
(
p_sys
->
i_pes_buf_cnt
>
0
)
{
int
i_need
=
SERIES1_PES_LENGTH
-
p_sys
->
i_pes_buf_cnt
;
msg_Dbg
(
p_demux
,
"continuing PES header"
);
/* do we have enough data to complete? */
if
(
i_need
<
l_rec_size
)
{
/* we have enough; reconstruct this p_frame with the new hdr */
memcpy
(
&
p_sys
->
pes_buffer
[
p_sys
->
i_pes_buf_cnt
],
p_block_in
->
p_buffer
,
i_need
);
/* advance the block past the PES header (don't want to send it) */
p_block_in
->
p_buffer
+=
i_need
;
p_block_in
->
i_buffer
-=
i_need
;
/* get the PTS out of this PES header (MPEG or AC3) */
if
(
p_sys
->
b_mpeg_audio
)
find_es_header
(
ty_MPEGAudioPacket
,
p_sys
->
pes_buffer
,
10
,
&
esOffset1
);
else
find_es_header
(
ty_AC3AudioPacket
,
p_sys
->
pes_buffer
,
10
,
&
esOffset1
);
if
(
esOffset1
<
0
)
{
/* god help us; something's really wrong */
msg_Err
(
p_demux
,
"can't find audio PES header in packet"
);
}
else
{
p_sys
->
lastAudioPTS
=
get_pts
(
&
p_sys
->
pes_buffer
[
esOffset1
+
DTIVO_PTS_OFFSET
]
);
p_block_in
->
i_pts
=
p_sys
->
lastAudioPTS
;
}
p_sys
->
i_pes_buf_cnt
=
0
;
}
else
{
/* don't have complete PES hdr; save what we have and return */
memcpy
(
&
p_sys
->
pes_buffer
[
p_sys
->
i_pes_buf_cnt
],
p_block_in
->
p_buffer
,
l_rec_size
);
p_sys
->
i_pes_buf_cnt
+=
l_rec_size
;
p_sys
->
i_cur_rec
++
;
block_Release
(
p_block_in
);
return
1
;
}
}
/* set PCR before we send */
/*es_out_Control( p_demux->out, ES_OUT_SET_PCR,
p_block_in->i_pts );*/
es_out_Send
(
p_demux
->
out
,
p_sys
->
p_audio
,
p_block_in
);
}
/* subrec == 2 */
/* MPEG Audio with PES Header, either SA or DTiVo */
/* ================================================ */
if
(
subrec_type
==
0x03
)
{
find_es_header
(
ty_MPEGAudioPacket
,
p_block_in
->
p_buffer
,
l_rec_size
,
&
esOffset1
);
/*msg_Dbg(p_demux, "buffer has %#02x %#02x %#02x %#02x",
p_block_in->p_buffer[0], p_block_in->p_buffer[1],
p_block_in->p_buffer[2], p_block_in->p_buffer[3]);
msg_Dbg(p_demux, "audio ES hdr at offset %d", esOffset1);*/
/* SA PES Header, No Audio Data */
/* ================================================ */
if
(
(
esOffset1
==
0
)
&&
(
l_rec_size
==
16
)
)
{
p_sys
->
tivoType
=
1
;
p_sys
->
lastAudioPTS
=
get_pts
(
&
p_block_in
->
p_buffer
[
SA_PTS_OFFSET
]
);
if
(
p_sys
->
firstAudioPTS
<
0
)
p_sys
->
firstAudioPTS
=
p_sys
->
lastAudioPTS
;
block_Release
(
p_block_in
);
/*msg_Dbg(p_demux, "SA Audio PTS %lld",
p_sys->lastAudioPTS );*/
}
else
/* DTiVo Audio with PES Header */
/* ================================================ */
{
p_sys
->
tivoType
=
2
;