F5OEO-tstools/tstools.pyx

181 wiersze
5.6 KiB
Cython

"""tstools.pyx -- Pyrex bindings for the TS tools
"""
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the MPEG TS, PS and ES tools.
#
# The Initial Developer of the Original Code is Amino Communications Ltd.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Tibs (tibs@berlios.de)
#
# ***** END LICENSE BLOCK *****
# If we're going to use definitions like this in more than one pyx file, we'll
# need to define the shared types in a .pxd file and use cimport to import
# them.
cdef extern from "stdio.h":
ctypedef struct FILE:
int _fileno
cdef enum:
EOF = -1
cdef FILE *stdout
cdef extern from "compat.h":
# We don't need to define 'offset_t' exactly, just to let Pyrex
# know it's vaguely int-like
ctypedef int offset_t
ctypedef char byte
cdef extern from 'es_defns.h':
# The reader for an ES file
struct elementary_stream:
pass
ctypedef elementary_stream ES
ctypedef elementary_stream *ES_p
# A location within said stream
struct _ES_offset:
offset_t infile # as used by lseek
int inpacket # in PES file, offset within PES packet
ctypedef _ES_offset ES_offset
# An actual ES unit
struct ES_unit:
ES_offset start_posn
byte *data
unsigned data_len
unsigned data_size
byte start_code
byte PES_had_PTS
ctypedef ES_unit *ES_unit_p
cdef extern from 'es_fns.h':
int open_elementary_stream(char *filename, ES_p *es)
void close_elementary_stream(ES_p *es)
int find_and_build_next_ES_unit(ES_p es, ES_unit_p *unit)
void free_ES_unit(ES_unit_p *unit)
void report_ES_unit(FILE *stream, ES_unit_p unit)
int seek_ES(ES_p es, ES_offset where)
int compare_ES_offsets(ES_offset offset1, ES_offset offset2)
# Is this the best thing to do?
class TSToolsException(Exception):
pass
cdef class ESUnit:
"""A Python class representing an ES unit.
"""
cdef ES_unit_p unit
# It appears to be recommended to make __cinit__ expand to take more
# arguments (if __init__ ever gains them), since both get the same
# things passed to them. Hmm, normally I'd trust myself, but let's
# try the recommended route
def __cinit__(self, *args,**kwargs):
pass
def __init__(self):
pass
def report(self):
"""Report (briefly) on an ES unit. This write to C stdout, which means
that Python has no control over the output. A proper Python version of
this will be provided eventually.
"""
report_ES_unit(stdout, self.unit)
#def _set_unit(self, ES_unit_p unit):
# if self.unit:
# raise TSToolsException,'ESUnit already has an ES unit associated'
# else:
# self.unit = unit
def __dealloc__(self):
free_ES_unit(&self.unit)
def __repr__(self):
return 'ES unit: start code %02x'%self.unit.start_code
cdef __set_es_unit(self, ES_unit_p unit):
if self.unit == NULL:
raise ValueError,'ES unit already defined'
else:
self.unit = unit
# Is this the simplest way? Since it appears that a class method
# doesn't want to take a non-Python item as an argument...
cdef _next_ESUnit(ES_p stream, filename):
cdef ES_unit_p unit
retval = find_and_build_next_ES_unit(stream, &unit)
if retval == EOF:
raise StopIteration
elif retval != 0:
raise TSToolsException,'Error getting next ES unit from file %s'%filename
# From http://www.philhassey.com/blog/2007/12/05/pyrex-from-confusion-to-enlightenment/
# Pyrex doesn't do type inference, so it doesn't detect that 'u' is allowed
# to hold an ES_unit_p. It's up to us to *tell* it, specifically, what type
# 'u' is going to be.
cdef ESUnit u
u = ESUnit()
u.unit = unit
#u._set_unit(unit)
return u
cdef class ESStream:
"""A Python class representing an ES stream, readable from a file.
"""
cdef ES_p stream
cdef readonly object filename
# It appears to be recommended to make __cinit__ expand to take more
# arguments (if __init__ ever gains them), since both get the same
# things passed to them. Hmm, normally I'd trust myself, but let's
# try the recommended route
def __cinit__(self,filename,*args,**kwargs):
retval = open_elementary_stream(filename,&self.stream)
if retval != 0:
raise TSToolsException,'Error opening ES file %s'%filename
def __init__(self,filename):
# The __cinit__ method will already have *used* the filename,
# but it may be useful to remember it for later on
self.filename = filename
def __dealloc__(self):
close_elementary_stream(&self.stream)
def __iter__(self):
return self
# For Pyrex classes, we define a __next__ instead of a next method
# in order to form our iterator
def __next__(self):
"""Our iterator interface retrieves the ES units from the stream.
"""
return _next_ESUnit(self.stream,self.filename)