kopia lustrzana https://github.com/F5OEO/tstools
252 wiersze
6.8 KiB
ReStructuredText
252 wiersze
6.8 KiB
ReStructuredText
Some tests for the Python binding of the TS tools
|
||
=================================================
|
||
|
||
We shall assume that our standard sample data has been downloaded and expanded
|
||
into our sibling ``data`` directory. See the ``../data/setup.sh`` script.
|
||
|
||
>>> test_es_file = '../data/ed24p_11.video.es'
|
||
|
||
First, check we've got the basics working:
|
||
|
||
>>> from tstools import ESFile
|
||
>>> stream = ESFile(test_es_file)
|
||
|
||
The filename is available as a "readonly" value:
|
||
|
||
>>> stream.name == test_es_file
|
||
True
|
||
|
||
We've opened it for read:
|
||
|
||
>>> stream.is_readable() == True
|
||
True
|
||
>>> stream.is_writable() == False
|
||
True
|
||
>>> stream.mode
|
||
'r'
|
||
|
||
We should be able to iterate over its ES units:
|
||
|
||
>>> count = 0
|
||
>>> es_unit_list = []
|
||
>>> for unit in stream:
|
||
... count += 1
|
||
... print unit
|
||
... es_unit_list.append(unit)
|
||
... if count > 5:
|
||
... break
|
||
ES unit: start code 00, len 9: 00 00 01 00 01 df ff fb b8
|
||
ES unit: start code b5, len 9: 00 00 01 b5 85 45 4b 5d 80
|
||
ES unit: start code 01, len 1645: 00 00 01 01 0a b0 10 09...
|
||
ES unit: start code 02, len 1634: 00 00 01 02 0a b0 10 09...
|
||
ES unit: start code 03, len 16: 00 00 01 03 0a b0 10 07...
|
||
ES unit: start code 04, len 15: 00 00 01 04 0a b0 10 02...
|
||
|
||
From ``hexdump -C`` I get (something that can be written out as)::
|
||
|
||
00 00 01 00 01 df ff fb b8
|
||
00 00 01 b5 85 45 4b 5d 80
|
||
00 00 01 01 0a b0 10 09 1c 56 ec d8 72 94 01 ...
|
||
|
||
which tends to support those results.
|
||
|
||
And close it:
|
||
|
||
>>> stream.close()
|
||
>>> stream.is_writable() == False
|
||
True
|
||
>>> stream.is_readable() == False
|
||
True
|
||
>>> stream.mode is None
|
||
True
|
||
|
||
We can ask an ES unit about itself:
|
||
|
||
>>> unit = es_unit_list[0]
|
||
>>> unit.start_posn
|
||
0+0
|
||
>>> unit.start_code
|
||
0
|
||
>>> unit.PES_had_PTS
|
||
0
|
||
>>> data = unit.data
|
||
>>> len(data)
|
||
9
|
||
>>> data[0]
|
||
'\x00'
|
||
>>> text = 'data:'
|
||
>>> for ii in range(8):
|
||
... text += ' %02x'%ord(data[ii])
|
||
>>> print text
|
||
data: 00 00 01 00 01 df ff fb
|
||
>>> unit.fred
|
||
Traceback (most recent call last):
|
||
...
|
||
AttributeError
|
||
|
||
ES units can be compared for equality (but not order):
|
||
|
||
>>> es_unit_list[0] == es_unit_list[0]
|
||
1
|
||
>>> es_unit_list[0] == es_unit_list[1]
|
||
0
|
||
>>> es_unit_list[0] != es_unit_list[1]
|
||
1
|
||
>>> es_unit_list[0] != es_unit_list[0]
|
||
0
|
||
>>> es_unit_list[0] < es_unit_list[1]
|
||
Traceback (most recent call last):
|
||
...
|
||
TypeError: ESUnit only supports == and != comparisons
|
||
|
||
We can create an ES unit from a Python 'string':
|
||
|
||
>>> from tstools import ESUnit
|
||
>>> print 'old ',repr(es_unit_list[0])
|
||
old ES unit: start code 00, len 9: 00 00 01 00 01 df ff fb b8
|
||
>>> new = ESUnit(es_unit_list[0].data)
|
||
>>> print 'new ',repr(new)
|
||
new ES unit: start code 00, len 9: 00 00 01 00 01 df ff fb b8
|
||
>>> print 'old ',repr(es_unit_list[0])
|
||
old ES unit: start code 00, len 9: 00 00 01 00 01 df ff fb b8
|
||
>>> new == es_unit_list[0]
|
||
True
|
||
|
||
And write another file...
|
||
|
||
>>> import tempfile
|
||
>>> import os
|
||
>>> directory = tempfile.mkdtemp()
|
||
>>> filename = os.path.join(directory,'tstools_test_1.es')
|
||
>>> out = ESFile(filename,'w')
|
||
>>> out.name == filename
|
||
True
|
||
>>> out.is_readable() == False
|
||
True
|
||
>>> out.is_writable() == True
|
||
True
|
||
>>> out.mode
|
||
'w'
|
||
>>> for unit in es_unit_list:
|
||
... out.write(unit)
|
||
>>> out.close()
|
||
|
||
Did that do the right thing? Check that we can read the units back (one by
|
||
one, to test the ``read`` method), and that the units we read back are
|
||
identical to those we wrote.
|
||
|
||
>>> infile = ESFile(filename,'r')
|
||
>>> other_units = []
|
||
>>> for ii in range(0,6):
|
||
... other_units.append(infile.read())
|
||
>>>
|
||
>>> for ii in range(0,6):
|
||
... if es_unit_list[ii] != other_units[ii]:
|
||
... print 'Error: unit %d does not match'%ii
|
||
... break
|
||
|
||
We already saw an ESOffset being returned:
|
||
|
||
>>> es_unit_list[0].start_posn
|
||
0+0
|
||
>>> es_unit_list[1].start_posn
|
||
9+0
|
||
>>> es_unit_list[1].start_posn.report()
|
||
Offset 0 in packet at offset 9 in file
|
||
|
||
Output more like that produced by the C report tools can also be obtained:
|
||
|
||
>>> print es_unit_list[1].start_posn.formatted()
|
||
00000000/00000009
|
||
|
||
We can create our own:
|
||
|
||
>>> from tstools import ESOffset
|
||
>>> offset = ESOffset(59,27)
|
||
>>> offset.report()
|
||
Offset 27 in packet at offset 59 in file
|
||
>>> offset.infile
|
||
59L
|
||
>>> offset.inpacket
|
||
27
|
||
|
||
There are keywords for the arguments, as well, for clarity:
|
||
|
||
>>> ESOffset(infile=59,inpacket=27) == offset
|
||
True
|
||
|
||
And both default to 0:
|
||
|
||
>>> ESOffset(infile=37).report()
|
||
Offset 0 in packet at offset 37 in file
|
||
>>> ESOffset().report()
|
||
Offset 0 in packet at offset 0 in file
|
||
|
||
Files can get very long -- the underlying ``lseek`` call can probably take
|
||
64-bit offsets. With luck, the Pyrex implementation can too:
|
||
|
||
>>> loffset = ESOffset(0x1111111111111111,5)
|
||
>>> loffset.report()
|
||
Offset 5 in packet at offset 1229782938247303441 in file
|
||
|
||
That's why we got the "59L" in an earlier example...
|
||
|
||
And it may be useful to be able to compare them:
|
||
|
||
>>> es_unit_list[1].start_posn > es_unit_list[0].start_posn
|
||
True
|
||
>>> es_unit_list[1].start_posn == es_unit_list[1].start_posn
|
||
True
|
||
>>> es_unit_list[0].start_posn < es_unit_list[1].start_posn
|
||
True
|
||
|
||
Seeking (to the start of an ES unit) is useful. However, the following are
|
||
just testing the three ways of specifying the location to seek to (which may
|
||
be overkill, but all seemed sensible at the time):
|
||
|
||
>>> f = ESFile(test_es_file)
|
||
>>> o = ESOffset(10,20)
|
||
>>> f.seek(o)
|
||
10+20
|
||
>>> f.seek(20)
|
||
20+0
|
||
>>> f.seek(30,40)
|
||
30+40
|
||
>>> f.seek(10,20,30)
|
||
Traceback (most recent call last):
|
||
...
|
||
TypeError: Seek argument must be one integer, two integers or an ESOffset
|
||
>>> f.seek('fred')
|
||
Traceback (most recent call last):
|
||
...
|
||
TypeError: Seek argument must be one integer, two integers or an ESOffset
|
||
>>> f.seek(-1)
|
||
Traceback (most recent call last):
|
||
...
|
||
TSToolsException: Error seeking to (-1,) in file '../data/ed24p_11.video.es'
|
||
|
||
Let's try proper seeking, though:
|
||
|
||
>>> p = f.seek(es_unit_list[-1].start_posn)
|
||
>>> p == es_unit_list[-1].start_posn
|
||
True
|
||
>>> u = f.read()
|
||
>>> u.start_posn == es_unit_list[-1].start_posn
|
||
True
|
||
>>> u == es_unit_list[-1]
|
||
True
|
||
|
||
OK. So ``seek()`` returns a tuple of (infile,inpacket), whilst the
|
||
``start_posn`` attribute is an ``ESOffset``. Which may or may not make sense
|
||
-- but I really would rather the latter had *some* annotation explicit as to
|
||
what each field means, because it *is* impossible to decide rationally which
|
||
order they should come in.
|
||
|
||
|
||
// Local Variables:
|
||
// tab-width: 8
|
||
// indent-tabs-mode: nil
|
||
// c-basic-offset: 2
|
||
// End:
|
||
// vim: set filetype=rst tabstop=8 shiftwidth=2 expandtab:
|