kopia lustrzana https://github.com/F5OEO/tstools
Experimental: this make the TS PCR read-ahead buffer per-file (well, strictly,
per-tsreader), rather than static as it was before. This is a tentative commit, subject to further testing, although the Python code's doctests appear to indicate that it is probably working. --HG-- extra : convert_revision : svn%3Aeff31bef-be4a-0410-a8fe-e47997df2690/trunk%40114issue20
rodzic
b03661d228
commit
6dae7d9049
|
@ -671,6 +671,52 @@ and thus:
|
|||
As I said, not perhaps what I want, but definitely what it is currently
|
||||
expected to do.
|
||||
|
||||
Opening a TSFile (for read) more than once at the same time
|
||||
-----------------------------------------------------------
|
||||
It's not particularly obvious when coding in C, but in Python there seems no
|
||||
reason to expect a problem in opening a TSFile more than once for reading at
|
||||
the same time.
|
||||
|
||||
For instance:
|
||||
|
||||
>>> f1 = TSFile(test_ts_file)
|
||||
>>> p1 = f1.read()
|
||||
>>> f2 = TSFile(test_ts_file)
|
||||
>>> p2 = f2.read()
|
||||
>>> p1 == p2
|
||||
1
|
||||
>>> p1 = f1.read()
|
||||
>>> p1 = f1.read()
|
||||
>>> p1 = f1.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p1 == p2
|
||||
1
|
||||
>>> f1.close()
|
||||
>>> f2.close()
|
||||
|
||||
The same should be true for BufferedTSFile:
|
||||
|
||||
>>> f1 = BufferedTSFile(test_ts_file)
|
||||
>>> p1 = f1.read()
|
||||
>>> f2 = BufferedTSFile(test_ts_file)
|
||||
>>> p2 = f2.read()
|
||||
>>> p1 == p2
|
||||
1
|
||||
>>> p1 = f1.read()
|
||||
>>> p1 = f1.read()
|
||||
>>> p1 = f1.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p2 = f2.read()
|
||||
>>> p1 == p2
|
||||
1
|
||||
>>> f1.close()
|
||||
>>> f2.close()
|
||||
|
||||
(hint: when I first wrote this, I already knew it would not be)
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// tab-width: 8
|
||||
|
|
|
@ -44,7 +44,7 @@ from common cimport PyString_FromStringAndSize, PyString_AsStringAndSize, \
|
|||
PyObject_AsReadBuffer
|
||||
from common cimport uint8_t, uint16_t, uint32_t, uint64_t
|
||||
from common cimport int8_t, int16_t, int32_t, int64_t
|
||||
from common cimport PID, offset_t, byte
|
||||
from common cimport offset_t, byte
|
||||
|
||||
from tstools import TSToolsException
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@ cdef extern from "ts_fns.h":
|
|||
int open_file_for_TS_read(char *filename, TS_reader_p *tsreader)
|
||||
int close_TS_reader(TS_reader_p *tsreader)
|
||||
int seek_using_TS_reader(TS_reader_p tsreader, offset_t posn)
|
||||
int prime_read_buffered_TS_packet(TS_reader_p tsreader, uint32_t pcr_pid)
|
||||
int read_next_TS_packet(TS_reader_p tsreader, byte **packet)
|
||||
int read_first_TS_packet_from_buffer(TS_reader_p tsreader,
|
||||
uint32_t pcr_pid, uint32_t start_count,
|
||||
|
@ -1107,6 +1108,12 @@ cdef class BufferedTSFile(TSFile):
|
|||
self.start_count += num_read
|
||||
self.pcr_pid = PMT.PCR_pid
|
||||
|
||||
# Tell the read mechanism which PCR PID we want to use
|
||||
retval = prime_read_buffered_TS_packet(self.tsreader,self.pcr_pid)
|
||||
if retval == 1:
|
||||
raise TSToolsException,'Error priming PCR read ahead for file %s'%self.name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
if self.name:
|
||||
return "<BufferedTSFile '%s' open for read>"%self.name
|
||||
|
|
276
ts.c
276
ts.c
|
@ -1192,37 +1192,7 @@ static uint64_t TWENTY_SEVEN_MHZ = 27000000;
|
|||
*
|
||||
* Returns 0 if all goes well, 1 if something goes wrong.
|
||||
*/
|
||||
extern int build_TS_reader(int file,
|
||||
TS_reader_p *tsreader)
|
||||
{
|
||||
TS_reader_p new = malloc(SIZEOF_TS_READER);
|
||||
if (new == NULL)
|
||||
{
|
||||
fprintf(stderr,"### Unable to allocate TS read-ahead buffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(new, '\0', SIZEOF_TS_READER);
|
||||
|
||||
new->file = file;
|
||||
new->posn = 0;
|
||||
new->read_ahead_ptr = NULL;
|
||||
new->read_ahead_end = NULL;
|
||||
|
||||
*tsreader = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Build a TS packet reader using the given functions as read() and seek().
|
||||
*
|
||||
* Returns 0 on success, 1 on failure.
|
||||
*/
|
||||
extern int build_TS_reader_with_fns(void *handle,
|
||||
int (*read_fn)(void *, byte *, size_t),
|
||||
int (*seek_fn)(void *, offset_t),
|
||||
TS_reader_p *tsreader)
|
||||
static int new_TS_reader(TS_reader_p *tsreader)
|
||||
{
|
||||
TS_reader_p new = malloc(SIZEOF_TS_READER);
|
||||
if (new == NULL)
|
||||
|
@ -1234,12 +1204,53 @@ extern int build_TS_reader_with_fns(void *handle,
|
|||
memset(new, '\0', SIZEOF_TS_READER);
|
||||
|
||||
new->file = -1;
|
||||
|
||||
*tsreader = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// File handling
|
||||
// ------------------------------------------------------------
|
||||
/*
|
||||
* Build a TS packet reader, including its read-ahead buffer
|
||||
*
|
||||
* - `file` is the file that the TS packets will be read from.
|
||||
* It is assumed that its read position is at its start.
|
||||
*
|
||||
* Returns 0 if all goes well, 1 if something goes wrong.
|
||||
*/
|
||||
extern int build_TS_reader(int file,
|
||||
TS_reader_p *tsreader)
|
||||
{
|
||||
TS_reader_p new;
|
||||
int err = new_TS_reader(&new);
|
||||
if (err) return 1;
|
||||
|
||||
new->file = file;
|
||||
|
||||
*tsreader = new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Build a TS packet reader using the given functions as read() and seek().
|
||||
*
|
||||
* Returns 0 on success, 1 on failure.
|
||||
*/
|
||||
extern int build_TS_reader_with_fns(void *handle,
|
||||
int (*read_fn)(void *, byte *, size_t),
|
||||
int (*seek_fn)(void *, offset_t),
|
||||
TS_reader_p *tsreader)
|
||||
{
|
||||
TS_reader_p new;
|
||||
int err = new_TS_reader(&new);
|
||||
if (err) return 1;
|
||||
|
||||
new->handle = handle;
|
||||
new->read_fn = read_fn;
|
||||
new->seek_fn = seek_fn;
|
||||
new->posn = 0;
|
||||
new->read_ahead_ptr = NULL;
|
||||
new->read_ahead_end = NULL;
|
||||
|
||||
*tsreader = new;
|
||||
return 0;
|
||||
|
@ -1286,6 +1297,8 @@ extern void free_TS_reader(TS_reader_p *tsreader)
|
|||
{
|
||||
if (*tsreader != NULL)
|
||||
{
|
||||
if ((*tsreader)->pcrbuf != NULL)
|
||||
free((*tsreader)->pcrbuf);
|
||||
(*tsreader)->file = -1;
|
||||
free(*tsreader);
|
||||
*tsreader = NULL;
|
||||
|
@ -1307,9 +1320,8 @@ extern int close_TS_reader(TS_reader_p *tsreader)
|
|||
return 0;
|
||||
if ((*tsreader)->file != STDIN_FILENO && (*tsreader)->file != -1)
|
||||
err = close_file((*tsreader)->file);
|
||||
(*tsreader)->file = -1;
|
||||
free(*tsreader);
|
||||
*tsreader = NULL;
|
||||
|
||||
free_TS_reader(tsreader);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1485,46 +1497,28 @@ extern int read_next_TS_packet(TS_reader_p tsreader,
|
|||
// it will be left as-is until something more sophisticated is
|
||||
// needed
|
||||
|
||||
// Let's guess for a maximum number of TS entries we're likely to need
|
||||
// to be able to hold...
|
||||
// XXX
|
||||
// XXX But whatever number we guess here will be too small for some
|
||||
// XXX streams, or so big it's really quite over the top for most
|
||||
// XXX (and more than I'd like). So maybe we should have something
|
||||
// XXX that's likely to cope for most streams, and we should (ideally)
|
||||
// XXX have a way for the user to set the size with a swich, but also
|
||||
// XXX (perhaps) we should allow the reader to continue (using the last
|
||||
// XXX calculated rate) if we can't read ahead? Or perhaps having the
|
||||
// XXX switch is enough, for the nonce... Or maybe we should allow the
|
||||
// XXX buffer to grow (on demand, within some sort of reason) if it
|
||||
// XXX needs to.
|
||||
// XXX
|
||||
#define PCR_READ_AHEAD_SIZE 20000 // a made-up number
|
||||
static byte TS_buffer[PCR_READ_AHEAD_SIZE][TS_PACKET_SIZE];
|
||||
// For convenience (since we'll already have calculated this once),
|
||||
// remember each packets PID
|
||||
static uint32_t TS_buffer_pids[PCR_READ_AHEAD_SIZE];
|
||||
// And the PCR PID we're looking for (we have to assume that's fairly
|
||||
// static, or we couldn't do read-aheads and interpolations)
|
||||
static uint32_t TS_buffer_pcr_pid = 0;
|
||||
// The number of TS entries we've got therein, the *last* of which
|
||||
// has a PCR
|
||||
static int TS_buffer_len = 0;
|
||||
// Which TS packet we should read next...
|
||||
static int TS_buffer_next = 0;
|
||||
// The PCR of that last entry
|
||||
static uint64_t TS_buffer_end_pcr = 0;
|
||||
// And the PCR of the *previous* last entry
|
||||
static uint64_t TS_buffer_prev_pcr = 0;
|
||||
// From which, we can deduce the time per packet
|
||||
static uint64_t TS_buffer_time_per_TS = 0;
|
||||
// For diagnostic purposes, the sequence number of TS_buffer[0]
|
||||
// (and thus, of the overall read-ahead buffer) in the overall file
|
||||
static int TS_buffer_posn = 0;
|
||||
// Did we read an EOF before finding a "second" PCR?
|
||||
// (perhaps we should instead call this "TS_playing_out", but that's
|
||||
// less directly named from how we set it)
|
||||
static int TS_had_EOF = FALSE;
|
||||
|
||||
/* Make sure we've got a PCR buffer allocated, and that
|
||||
* its content is entirely unset (so this also serves as
|
||||
* a "reset" function).
|
||||
*
|
||||
* Returns 0 if all went well, 1 if something went wrong.
|
||||
*/
|
||||
static int start_TS_packet_buffer(TS_reader_p tsreader)
|
||||
{
|
||||
if (tsreader->pcrbuf == NULL)
|
||||
{
|
||||
tsreader->pcrbuf = malloc(SIZEOF_TS_PCR_BUFFER);
|
||||
if (tsreader->pcrbuf == NULL)
|
||||
{
|
||||
fprintf(stderr,"### Unable to allocate TS PCR read-ahead buffer\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
memset(tsreader->pcrbuf, '\0', SIZEOF_TS_PCR_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Fill up the PCR read-ahead buffer with TS entries, until we hit
|
||||
* one (of the correct PID) with a PCR.
|
||||
|
@ -1536,10 +1530,11 @@ static int fill_TS_packet_buffer(TS_reader_p tsreader)
|
|||
int ii;
|
||||
|
||||
// Work out which TS packet we *will* have as our first (zeroth) entry
|
||||
TS_buffer_posn = TS_buffer_posn + TS_buffer_len + 1;
|
||||
tsreader->pcrbuf->TS_buffer_posn = tsreader->pcrbuf->TS_buffer_posn +
|
||||
tsreader->pcrbuf->TS_buffer_len + 1;
|
||||
|
||||
TS_buffer_len = 0;
|
||||
TS_buffer_next = 0;
|
||||
tsreader->pcrbuf->TS_buffer_len = 0;
|
||||
tsreader->pcrbuf->TS_buffer_next = 0;
|
||||
for (ii=0; ii<PCR_READ_AHEAD_SIZE; ii++)
|
||||
{
|
||||
byte *data;
|
||||
|
@ -1565,32 +1560,36 @@ static int fill_TS_packet_buffer(TS_reader_p tsreader)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"### Error (pre)reading TS packet %d\n",TS_buffer_posn+ii);
|
||||
fprintf(stderr,"### Error (pre)reading TS packet %d\n",
|
||||
tsreader->pcrbuf->TS_buffer_posn+ii);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the data into our own read-ahead buffer
|
||||
memcpy(TS_buffer[ii],data,TS_PACKET_SIZE);
|
||||
memcpy(tsreader->pcrbuf->TS_buffer[ii],data,TS_PACKET_SIZE);
|
||||
|
||||
err = split_TS_packet(data,&pid,&payload_unit_start_indicator,
|
||||
&adapt,&adapt_len,&payload,&payload_len);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr,"### Error splitting TS packet %d\n",TS_buffer_posn+ii);
|
||||
fprintf(stderr,"### Error splitting TS packet %d\n",
|
||||
tsreader->pcrbuf->TS_buffer_posn+ii);
|
||||
return 1;
|
||||
}
|
||||
TS_buffer_len ++;
|
||||
tsreader->pcrbuf->TS_buffer_len ++;
|
||||
|
||||
if (pid != TS_buffer_pcr_pid)
|
||||
if (pid != tsreader->pcrbuf->TS_buffer_pcr_pid)
|
||||
continue; // don't care about any PCR it might have
|
||||
|
||||
get_PCR_from_adaptation_field(adapt,adapt_len,&got_pcr,&pcr);
|
||||
if (got_pcr)
|
||||
{
|
||||
TS_buffer_prev_pcr = TS_buffer_end_pcr;
|
||||
TS_buffer_end_pcr = pcr;
|
||||
TS_buffer_time_per_TS = (TS_buffer_end_pcr - TS_buffer_prev_pcr) / TS_buffer_len;
|
||||
tsreader->pcrbuf->TS_buffer_prev_pcr = tsreader->pcrbuf->TS_buffer_end_pcr;
|
||||
tsreader->pcrbuf->TS_buffer_end_pcr = pcr;
|
||||
tsreader->pcrbuf->TS_buffer_time_per_TS = (tsreader->pcrbuf->TS_buffer_end_pcr -
|
||||
tsreader->pcrbuf->TS_buffer_prev_pcr) /
|
||||
tsreader->pcrbuf->TS_buffer_len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1598,15 +1597,37 @@ static int fill_TS_packet_buffer(TS_reader_p tsreader)
|
|||
// with an appropriate grumble
|
||||
fprintf(stderr,"!!! Next PCR not found when reading forwards"
|
||||
" (for %d TS packets, starting at TS packet %d)\n",PCR_READ_AHEAD_SIZE,
|
||||
TS_buffer_posn);
|
||||
tsreader->pcrbuf->TS_buffer_posn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set up the the "looping" buffered TS packet reader and let it know what its
|
||||
* PCR PID is.
|
||||
*
|
||||
* This must be called before any other _buffered_TS_packet function.
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
*
|
||||
* Returns 0 if all went well, 1 if something went wrong (allocating space
|
||||
* for the TS PCR buffer).
|
||||
*/
|
||||
extern int prime_read_buffered_TS_packet(TS_reader_p tsreader,
|
||||
uint32_t pcr_pid)
|
||||
{
|
||||
if (start_TS_packet_buffer(tsreader))
|
||||
return 1;
|
||||
tsreader->pcrbuf->TS_buffer_pcr_pid = pcr_pid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve the first TS packet from the PCR read-ahead buffer,
|
||||
* complete with its calculated PCR time.
|
||||
*
|
||||
* prime_read_buffered_TS_packet() must have been called before this.
|
||||
*
|
||||
* This should be called the first time a TS packet is to be read
|
||||
* using the PCR read-ahead buffer. It "primes" the read-ahead mechanism.
|
||||
* using the PCR read-ahead buffer. It "primes" the read-ahead mechanism
|
||||
* by performing the first actual read-ahead.
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
* - `start_count` is the index of the current (last read) TS entry (which will
|
||||
|
@ -1633,14 +1654,12 @@ extern int read_first_TS_packet_from_buffer(TS_reader_p tsreader,
|
|||
{
|
||||
int err;
|
||||
|
||||
// Reset ourselves
|
||||
TS_buffer_next = 0;
|
||||
TS_buffer_end_pcr = 0;
|
||||
TS_buffer_prev_pcr = 0;
|
||||
TS_buffer_posn = start_count;
|
||||
TS_buffer_len = 0; // this (+1) gets added to TS_buffer_posn
|
||||
TS_buffer_pcr_pid = pcr_pid;
|
||||
TS_had_EOF = FALSE;
|
||||
if (tsreader->pcrbuf == NULL)
|
||||
{
|
||||
fprintf(stderr,"### TS PCR read-ahead buffer has not been set up\n"
|
||||
" Make sure prime_read_buffered_TS_packet() has been called\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read TS packets into our buffer until we find one with a PCR
|
||||
err = fill_TS_packet_buffer(tsreader);
|
||||
|
@ -1648,17 +1667,17 @@ extern int read_first_TS_packet_from_buffer(TS_reader_p tsreader,
|
|||
|
||||
// However, it's only the last packet (the one with the PCR) that
|
||||
// we are actually interested in
|
||||
TS_buffer_next = TS_buffer_len - 1;
|
||||
tsreader->pcrbuf->TS_buffer_next = tsreader->pcrbuf->TS_buffer_len - 1;
|
||||
|
||||
// Why, this is the very packet with its own PCR
|
||||
*pcr = TS_buffer_end_pcr;
|
||||
*pcr = tsreader->pcrbuf->TS_buffer_end_pcr;
|
||||
|
||||
*data = TS_buffer[TS_buffer_next];
|
||||
*pid = TS_buffer_pids[TS_buffer_next];
|
||||
*data = tsreader->pcrbuf->TS_buffer[tsreader->pcrbuf->TS_buffer_next];
|
||||
*pid = tsreader->pcrbuf->TS_buffer_pids[tsreader->pcrbuf->TS_buffer_next];
|
||||
|
||||
*count = start_count + TS_buffer_len;
|
||||
*count = start_count + tsreader->pcrbuf->TS_buffer_len;
|
||||
|
||||
TS_buffer_next ++;
|
||||
tsreader->pcrbuf->TS_buffer_next ++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1682,9 +1701,17 @@ extern int read_next_TS_packet_from_buffer(TS_reader_p tsreader,
|
|||
uint64_t *pcr)
|
||||
{
|
||||
int err;
|
||||
if (TS_buffer_next == TS_buffer_len)
|
||||
|
||||
if (tsreader->pcrbuf == NULL)
|
||||
{
|
||||
if (TS_had_EOF)
|
||||
fprintf(stderr,"### TS PCR read-ahead buffer has not been set up\n"
|
||||
" Make sure read_first_TS_packet_from_buffer() has been called\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tsreader->pcrbuf->TS_buffer_next == tsreader->pcrbuf->TS_buffer_len)
|
||||
{
|
||||
if (tsreader->pcrbuf->TS_had_EOF)
|
||||
{
|
||||
// We'd already run out of look-ahead packets, so just return
|
||||
// our (deferred) end-of-file
|
||||
|
@ -1702,46 +1729,41 @@ extern int read_next_TS_packet_from_buffer(TS_reader_p tsreader,
|
|||
// at the end of the file. This proved unacceptable in practice,
|
||||
// so our second best choice is to "play out" using the last
|
||||
// known PCR rate-of-change.
|
||||
TS_had_EOF = TRUE; // remember we're playing out
|
||||
tsreader->pcrbuf->TS_had_EOF = TRUE; // remember we're playing out
|
||||
}
|
||||
else if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
*data = TS_buffer[TS_buffer_next];
|
||||
*pid = TS_buffer_pids[TS_buffer_next];
|
||||
*data = tsreader->pcrbuf->TS_buffer[tsreader->pcrbuf->TS_buffer_next];
|
||||
*pid = tsreader->pcrbuf->TS_buffer_pids[tsreader->pcrbuf->TS_buffer_next];
|
||||
|
||||
TS_buffer_next ++;
|
||||
tsreader->pcrbuf->TS_buffer_next ++;
|
||||
|
||||
if (TS_buffer_next == TS_buffer_len && !TS_had_EOF)
|
||||
if (tsreader->pcrbuf->TS_buffer_next == tsreader->pcrbuf->TS_buffer_len &&
|
||||
!tsreader->pcrbuf->TS_had_EOF)
|
||||
{
|
||||
// Why, this is the very packet with its own PCR
|
||||
*pcr = TS_buffer_end_pcr;
|
||||
*pcr = tsreader->pcrbuf->TS_buffer_end_pcr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pcr = TS_buffer_prev_pcr + TS_buffer_time_per_TS * TS_buffer_next;
|
||||
*pcr = tsreader->pcrbuf->TS_buffer_prev_pcr +
|
||||
tsreader->pcrbuf->TS_buffer_time_per_TS *
|
||||
tsreader->pcrbuf->TS_buffer_next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Let the "looping" buffered TS packet reader know what its PCR PID is
|
||||
*
|
||||
* Call this before the first call of read_buffered_TS_packet().
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
*/
|
||||
extern void prime_read_buffered_TS_packet(uint32_t pcr_pid)
|
||||
{
|
||||
TS_buffer_pcr_pid = pcr_pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next TS packet, coping with looping, etc.
|
||||
*
|
||||
* prime_read_buffered_TS_packet() should have been called first.
|
||||
*
|
||||
* This is a convenience wrapper around read_first_TS_packet_from_buffer()
|
||||
* and read_next_TS_packet_from_buffer().
|
||||
*
|
||||
* This differs from ``read_TS_packet`` in that it assumes that the
|
||||
* underlying code will already have read to the next PCR, so that
|
||||
* it can know the *actual* (PCR-based) time for each TS packet.
|
||||
|
@ -1805,7 +1827,8 @@ extern int read_buffered_TS_packet(TS_reader_p tsreader,
|
|||
// XXX the first packet with a PCR? Probably more so than that we
|
||||
// XXX should ignore any packets at the end of the file.
|
||||
// XXX
|
||||
err = read_first_TS_packet_from_buffer(tsreader,TS_buffer_pcr_pid,
|
||||
err = read_first_TS_packet_from_buffer(tsreader,
|
||||
tsreader->pcrbuf->TS_buffer_pcr_pid,
|
||||
start_count,data,pid,pcr,count);
|
||||
if (err)
|
||||
{
|
||||
|
@ -1847,7 +1870,8 @@ extern int read_buffered_TS_packet(TS_reader_p tsreader,
|
|||
if (err) return 1;
|
||||
|
||||
*count = start_count;
|
||||
err = read_first_TS_packet_from_buffer(tsreader,TS_buffer_pcr_pid,
|
||||
err = read_first_TS_packet_from_buffer(tsreader,
|
||||
tsreader->pcrbuf->TS_buffer_pcr_pid,
|
||||
start_count,data,pid,pcr,count);
|
||||
if (err)
|
||||
{
|
||||
|
|
56
ts_defns.h
56
ts_defns.h
|
@ -39,6 +39,58 @@
|
|||
// 184 bytes for our payload
|
||||
#define MAX_TS_PAYLOAD_SIZE (TS_PACKET_SIZE-4)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Support for PCR read-ahead buffering
|
||||
// Basically, always ensure that we know have read both the
|
||||
// previous and the next PCR, so we can calculate the actual
|
||||
// PCR for each packet between.
|
||||
|
||||
// Let's guess for a maximum number of TS entries we're likely to need
|
||||
// to be able to hold...
|
||||
//
|
||||
// XXX But whatever number we guess here will be too small for some
|
||||
// XXX streams, or so big it's really quite over the top for most
|
||||
// XXX (and more than I'd like). So maybe we should have something
|
||||
// XXX that's likely to cope for most streams, and we should (ideally)
|
||||
// XXX have a way for the user to set the size with a swich, but also
|
||||
// XXX (perhaps) we should allow the reader to continue (using the last
|
||||
// XXX calculated rate) if we can't read ahead? Or perhaps having the
|
||||
// XXX switch is enough, for the nonce... Or maybe we should allow the
|
||||
// XXX buffer to grow (on demand, within some sort of reason) if it
|
||||
// XXX needs to.
|
||||
#define PCR_READ_AHEAD_SIZE 20000 // a made-up number
|
||||
|
||||
struct _ts_pcr_buffer
|
||||
{
|
||||
byte TS_buffer[PCR_READ_AHEAD_SIZE][TS_PACKET_SIZE];
|
||||
// For convenience (since we'll already have calculated this once),
|
||||
// remember each packets PID
|
||||
uint32_t TS_buffer_pids[PCR_READ_AHEAD_SIZE];
|
||||
// And the PCR PID we're looking for (we have to assume that's fairly
|
||||
// static, or we couldn't do read-aheads and interpolations)
|
||||
uint32_t TS_buffer_pcr_pid;
|
||||
// The number of TS entries we've got therein, the *last* of which
|
||||
// has a PCR
|
||||
int TS_buffer_len;
|
||||
// Which TS packet we should read next...
|
||||
int TS_buffer_next;
|
||||
// The PCR of that last entry
|
||||
uint64_t TS_buffer_end_pcr;
|
||||
// And the PCR of the *previous* last entry
|
||||
uint64_t TS_buffer_prev_pcr;
|
||||
// From which, we can deduce the time per packet
|
||||
uint64_t TS_buffer_time_per_TS;
|
||||
// For diagnostic purposes, the sequence number of TS_buffer[0]
|
||||
// (and thus, of the overall read-ahead buffer) in the overall file
|
||||
int TS_buffer_posn;
|
||||
// Did we read an EOF before finding a "second" PCR?
|
||||
// (perhaps we should instead call this "TS_playing_out", but that's
|
||||
// less directly named from how we set it)
|
||||
int TS_had_EOF;
|
||||
};
|
||||
typedef struct _ts_pcr_buffer *TS_pcr_buffer_p;
|
||||
#define SIZEOF_TS_PCR_BUFFER sizeof(struct _ts_pcr_buffer)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// The number of TS packets to read ahead
|
||||
#define TS_READ_AHEAD_COUNT 1024 // aim for multiple of block boundary -- used to be 50
|
||||
|
@ -65,6 +117,10 @@ struct _ts_reader
|
|||
byte read_ahead[TS_READ_AHEAD_COUNT*TS_PACKET_SIZE];
|
||||
byte *read_ahead_ptr; // location of next packet in said array
|
||||
byte *read_ahead_end; // pointer just after the end of `read_ahead`
|
||||
|
||||
// If we are doing PCR read-ahead (so we have exact PCR values for our
|
||||
// TS packets), then we also need:
|
||||
TS_pcr_buffer_p pcrbuf;
|
||||
};
|
||||
typedef struct _ts_reader *TS_reader_p;
|
||||
#define SIZEOF_TS_READER sizeof(struct _ts_reader)
|
||||
|
|
27
ts_fns.h
27
ts_fns.h
|
@ -386,11 +386,26 @@ extern int read_next_TS_packet(TS_reader_p tsreader,
|
|||
// Keeps a PCR in hand, so that it has accurate timing information
|
||||
// for each TS packet
|
||||
// ------------------------------------------------------------
|
||||
/* Set up the the "looping" buffered TS packet reader and let it know what its
|
||||
* PCR PID is.
|
||||
*
|
||||
* This must be called before any other _buffered_TS_packet function.
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
*
|
||||
* Returns 0 if all went well, 1 if something went wrong (allocating space
|
||||
* for the TS PCR buffer).
|
||||
*/
|
||||
extern int prime_read_buffered_TS_packet(TS_reader_p tsreader,
|
||||
uint32_t pcr_pid);
|
||||
/* Retrieve the first TS packet from the PCR read-ahead buffer,
|
||||
* complete with its calculated PCR time.
|
||||
*
|
||||
* prime_read_buffered_TS_packet() must have been called before this.
|
||||
*
|
||||
* This should be called the first time a TS packet is to be read
|
||||
* using the PCR read-ahead buffer. It "primes" the read-ahead mechanism.
|
||||
* using the PCR read-ahead buffer. It "primes" the read-ahead mechanism
|
||||
* by performing the first actual read-ahead.
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
* - `start_count` is the index of the current (last read) TS entry (which will
|
||||
|
@ -432,18 +447,14 @@ extern int read_next_TS_packet_from_buffer(TS_reader_p tsreader,
|
|||
byte *data[TS_PACKET_SIZE],
|
||||
uint32_t *pid,
|
||||
uint64_t *pcr);
|
||||
/* Let the "looping" buffered TS packet reader know what its PCR PID is
|
||||
*
|
||||
* Call this before the first call of read_buffered_TS_packet().
|
||||
*
|
||||
* - `pcr_pid` is the PID within which we should look for PCR entries
|
||||
*/
|
||||
extern void prime_read_buffered_TS_packet(uint32_t pcr_pid);
|
||||
/*
|
||||
* Read the next TS packet, coping with looping, etc.
|
||||
*
|
||||
* prime_read_buffered_TS_packet() should have been called first.
|
||||
*
|
||||
* This is a convenience wrapper around read_first_TS_packet_from_buffer()
|
||||
* and read_next_TS_packet_from_buffer().
|
||||
*
|
||||
* This differs from ``read_TS_packet`` in that it assumes that the
|
||||
* underlying code will already have read to the next PCR, so that
|
||||
* it can know the *actual* (PCR-based) time for each TS packet.
|
||||
|
|
3
tsplay.c
3
tsplay.c
|
@ -422,7 +422,8 @@ static int play_buffered_TS_packets(TS_reader_p tsreader,
|
|||
}
|
||||
|
||||
// Once we've found that, we're ready to play our data
|
||||
prime_read_buffered_TS_packet(pcr_pid);
|
||||
err = prime_read_buffered_TS_packet(tsreader,pcr_pid);
|
||||
if (err) return 1;
|
||||
|
||||
// If we're looping, remember the location of the first packet of (probable)
|
||||
// data - there's not much point rewinding before that point
|
||||
|
|
Ładowanie…
Reference in New Issue