#
# MPEG handling.
#
# Copyright (C) 2003-2005  Andreas Junghans <aj@lucid-cake.net>
#
#    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-1307  USA
#


import sys


MINSTREAMSIZE = 188
MPEG2STREAMSIZE = 188
MPEG2READSIZE = MPEG2STREAMSIZE * 348
MPEG2WRITESIZE = MPEG2STREAMSIZE * 43-1
MPEG2MINSIZE = 32
MPEG1STREAMSIZE = 2324
MPEG1READSIZE = MPEG1STREAMSIZE * 28
MPEG1WRITESIZE = 3-1
MPEG1MINSIZE = 64

STREAM_TYPE_UNKNOWN = 0
STREAM_TYPE_MPEG1 = 1
STREAM_TYPE_MPEG2_TS = 2
STREAM_SUBTYPE_UNKNOWN = 0
STREAM_SUBTYPE_MPEG4 = 1

PCR_STATE_INIT = 0
PCR_STATE_PTS_FOUND = 1
PCR_STATE_FINISHED = 2

PCR_FILLER = '\xff'*176

NEED_MORE_DATA = "need more data"


def vlc_log2(v):
    """
    Straight translation from VLC C source code.
    """
    n = 0
    vlc_log2_table = [0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3]
    if v & 0xffff0000:
        v = (v >> 16) & 0xffff  # Python has no concept of unsigned types
        n += 16
    if v & 0xff00:
        v >>= 8
        n += 8
    if v & 0xf0:
        v >>= 4
        n += 4
    n += vlc_log2_table[v]
    return n

        
# Class for bitwise reading from a string.

HIGHBITMASKS = [0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01]

class Bitreader:
    
    def __init__(self, source):
        self.source = source
        self.bitIndex = 0


    def read(self, numBits):
        """
        Returns the value of the next [numBits] and advances the
        bit index.

        Exceptions because of buffer overflows are simply passed through!
        """
        bitsToRead = numBits
        result = 0L
        while bitsToRead > 0:
            temp = ord(self.source[self.bitIndex/8]) & HIGHBITMASKS[self.bitIndex%8]
            availableBits = 8 - self.bitIndex%8
            if bitsToRead < availableBits:
                bitsConsumed = bitsToRead
            else:
                bitsConsumed = availableBits
            temp = temp >> (availableBits - bitsConsumed)
            bitsToRead -= bitsConsumed
            self.bitIndex += bitsConsumed
            result |= (long(temp) << bitsToRead)
        return result


    def skip(self, numBits):
        """
        Advances the bit index.
        """
        self.bitIndex += numBits


def getBitrate(packet):
    """
    Returns the bitrate specified in the first packet within the specified
    pack. Since EyeTV seems to always have only a single packet within a pack
    (and the bitrate is the same number in both the video and audio streams),
    this is sufficient for the whole pack.

    The returned rate is in bits/sec.

    This function only works for MPEG1!

    It is assumed that the packet contains at least MINSTREAMSIZE bytes!
    """
    bitrate = (ord(packet[9]) & 0x7f) << 15
    bitrate |= ord(packet[10]) << 7
    bitrate |= (ord(packet[11]) & 0xfe) >> 1
    return bitrate*400


def getTimesMPEG1(packet):
    """
    Gets the system clock reference, the PTS, and the DTS from a packet. The
    return value is a tuple with 3 elements (SCR, PTS, DTS) where any element
    can be None if it's not present in the stream.

    It is assumed that the packet contains at least MINSTREAMSIZE bytes!
    """
    # TODO: make this more robust
    scr = (long(ord(packet[4]) & 0x0e) << 29) | \
          (long(ord(packet[5])) << 22) | \
          (long(ord(packet[6]) & 0xfe) << 14) | \
          (long(ord(packet[7])) << 7) | \
          (long(ord(packet[8]) & 0xfe) >> 1)
    offset = 12+6
    # TODO: make this more robust (especially take care of a system
    #       header if present)
    while packet[offset] == "\xff":
        offset += 1
    if (ord(packet[offset]) & 0xc0) == 0x40:
        offset += 2
    pts = None
    dts = None
    if ord(packet[offset]) & 0x20:
        pts = (long(ord(packet[offset]) & 0x0e) << 29) | \
              (long(ord(packet[offset+1])) << 22) | \
              (long(ord(packet[offset+2]) & 0xfe) << 14) | \
              (long(ord(packet[offset+3])) << 7) | \
              (long(ord(packet[offset+4]) & 0xfe) >> 1)
        if ord(packet[offset]) & 0x10:
            dts = (long(ord(packet[offset+5]) & 0x0e) << 29) | \
                  (long(ord(packet[offset+6])) << 22) | \
                  (long(ord(packet[offset+7]) & 0xfe) << 14) | \
                  (long(ord(packet[offset+8])) << 7) | \
                  (long(ord(packet[offset+9]) & 0xfe) >> 1)
    audioPTS = None
    if ord(packet[15]) & 0xe0 == 0xc0:
        # we have an audio stream
        audioPTS = pts
    return (scr, pts, dts, audioPTS)
    

def setTimesMPEG1(packet, scr, pts, dts, audioPTS, timeHandler):
    """
    Sets the various time stamps in a packet. The system clock reference, PTS,
    and DTS are only set if the respective parameters are not None.

    The return value is a new packet with the same contents as the old one,
    but with the new times inserted.

    It is assumed that the packet contains at least MINSTREAMSIZE bytes!
    """
    # TODO: make this more robust (especially take care of a system
    #       header if present)
    if scr is None:
        retVal = packet[:18]
    else:
        retVal = packet[:4]
        retVal += chr(0x21 | ((scr >> 29) & 0x0e))
        retVal += chr((scr >> 22) & 0xff)
        retVal += chr(0x01 | ((scr >> 14) & 0xfe))
        retVal += chr((scr >> 7) & 0xff)
        retVal += chr(0x01 | ((scr << 1) & 0xfe))
        retVal += packet[9:18]
    offset = 18
    while packet[offset] == "\xff":
        offset += 1
    if (ord(packet[offset]) & 0xc0) == 0x40:
        offset += 2
    if offset > 18:
        retVal += packet[18:offset]
    if (ord(packet[offset]) & 0x20) == 0x20:
        if pts is None:
            retVal += packet[offset:offset+5]
        else:
            byte = ord(packet[offset]) & 0xf1
            retVal += chr(byte | ((pts >> 29) & 0x0e))
            retVal += chr((pts >> 22) & 0xff)
            retVal += chr(0x01 | ((pts >> 14) & 0xfe))
            retVal += chr((pts >> 7) & 0xff)
            retVal += chr(0x01 | ((pts << 1) & 0xfe))
        if (ord(packet[offset]) & 0x10) == 0x10:
            if dts is None:
                retVal += packet[offset+5:offset+10]
            else:
                byte = ord(packet[offset+5]) & 0xf1
                retVal += chr(byte | ((dts >> 29) & 0x0e))
                retVal += chr((dts >> 22) & 0xff)
                retVal += chr(0x01 | ((dts >> 14) & 0xfe))
                retVal += chr((dts >> 7) & 0xff)
                retVal += chr(0x01 | ((dts << 1) & 0xfe))
            offset += 10
        else:
            offset += 5
    return retVal + packet[offset:]


def getTimesMPEG2TS(packet):
    """
    Gets the program clock reference, the PTS, and the DTS from a packet. The
    return value is a tuple with 3 elements (PCR, PTS, DTS) where any element
    can be None if it's not present in the stream.

    This function only returns PTS and DTS values if they are contained in a
    unit start packet.
    
    It is assumed that the packet contains at least MINSTREAMSIZE bytes!
    """
    adaptation_field_control = ord(packet[3]) & 0x30
    if adaptation_field_control & 0x20 and ord(packet[5]) & 0x10:
        pcr = (long(ord(packet[6])) << 25) | \
              (long(ord(packet[7])) << 17) | \
              (long(ord(packet[8])) << 9) | \
              (long(ord(packet[9])) << 1) | \
              (long(ord(packet[10]) & 0x80) >> 7)
    else:
        pcr = None
    pts = None
    dts = None
    audioPTS = None
    if ord(packet[1]) & 0x40:
        # start of a unit: we may have PTS and DTS
        offset = 0
        if adaptation_field_control == 0x10:
            # payload only
            offset = 4  # skip only link header
        elif adaptation_field_control == 0x30:
            # adaptation field + payload
            offset = 5 + ord(packet[4])
        if offset > 0 and offset+18 < MINSTREAMSIZE:
            streamId = ord(packet[offset+3])
            isAudioStream = ((streamId & 0xe0) == 0xc0)
            if isAudioStream or (streamId & 0xf0) == 0xe0:
                # audio or video stream
                if (ord(packet[offset+6]) & 0xc0) == 0x80:    # sanity check
                    if ord(packet[offset+7]) & 0x80:
                        pts = (long(ord(packet[offset+9]) & 0x0e) << 29) | \
                              (long(ord(packet[offset+10])) << 22) | \
                              (long(ord(packet[offset+11]) & 0xfe) << 14) | \
                              (long(ord(packet[offset+12])) << 7) | \
                              (long(ord(packet[offset+13]) & 0xfe) >> 1)
                        if isAudioStream:
                            audioPTS = pts
                        if ord(packet[offset+7]) & 0x40:
                            dts = (long(ord(packet[offset+14]) & 0x0e) << 29) | \
                                  (long(ord(packet[offset+15])) << 22) | \
                                  (long(ord(packet[offset+16]) & 0xfe) << 14) | \
                                  (long(ord(packet[offset+17])) << 7) | \
                                  (long(ord(packet[offset+18]) & 0xfe) >> 1)
    return (pcr, pts, dts, audioPTS)


def setTimesMPEG2TS(packet, pcr, pts, dts, audioPTS, timeHandler):
    """
    Sets the various time stamps in a packet. The program clock reference,
    PTS, and DTS are only set if the respective parameters are not None.

    The return value is a new packet with the same contents as the old one,
    but with the new times inserted.

    This function only replaces PTS and DTS values if they are contained in a
    unit start packet. Note that the optional ESCR of the elementary stream is
    completely ignored!
    
    It is assumed that the packet contains at least MINSTREAMSIZE bytes!

    Extension: This function now also generates PCR packets if needed. If the
    audioPTS parameter is not None, this PTS is used to generate a PCR (if
    necessary).

    TODO: Optimize this function!
    """
    offset = 0
    retVal = ""
    tsStreamId = ((ord(packet[1]) & 0x1f) << 8) | ord(packet[2])
    continuity = ord(packet[3]) & 0x0f
    if timeHandler.pcrId == tsStreamId:
        timeHandler.pcrContinuity = (continuity - (audioPTS and 1 or 0))%16
    if audioPTS is not None:
        if timeHandler.detectPCRState == PCR_STATE_INIT:
            timeHandler.detectPCRState = PCR_STATE_PTS_FOUND
            timeHandler.firstPTS = audioPTS
            timeHandler.lastPTS = audioPTS
            #print "audioPTS found for " + timeHandler.currentFile
            #sys.stdout.flush()
        elif timeHandler.detectPCRState == PCR_STATE_PTS_FOUND:
            if (audioPTS - timeHandler.firstPTS)/900 > 10:
                # if there has been no PCR for 1/10th of
                # a second, give up looking for one
                timeHandler.detectPCRState = PCR_STATE_FINISHED
                timeHandler.generatePCR = 1
                print "generating PCRs for stream '" + timeHandler.currentFile + "'"
                sys.stdout.flush()
        if timeHandler.generatePCR and (ord(packet[1]) & 0x40):
            if continuity == 0:
                #print "writing PCR " + str(timeHandler.pcr-45000)
                retVal += "\x47"
                retVal += chr(0x40 | (timeHandler.pcrId >> 8))
                retVal += chr(timeHandler.pcrId & 0xff)
                retVal += chr(0x20 | timeHandler.pcrContinuity)
                #retVal += chr(183)
                #retVal += chr(0x10)
                retVal += "\xb7\x10"
                audioPTS = pts
                audioPTS -= 45000
                audioPTS = (audioPTS << 15)
                retVal += chr((audioPTS >> 40) & 0xff)
                retVal += chr((audioPTS >> 32) & 0xff)
                retVal += chr((audioPTS >> 24) & 0xff)
                retVal += chr((audioPTS >> 16) & 0xff)
                retVal += chr((audioPTS >> 8) & 0xff)
                retVal += chr(audioPTS & 0xff)
                retVal += PCR_FILLER

    #if timeHandler.generatePCR and timeHandler.pcrId == tsStreamId:
    #    continuity = timeHandler.pcrContinuity
    #    timeHandler.pcrContinuity = (timeHandler.pcrContinuity + 1)%16
    #    retVal += packet[:3]
    #    retVal += chr((ord(packet[3]) & 0xf0) | continuity)
    #    offset = 4

    adaptation_field_control = ord(packet[3]) & 0x30
    if adaptation_field_control & 0x20:
        if ord(packet[5]) & 0x10 and ord(packet[4]) >= 7:
            # PCR is present
            if timeHandler.detectPCRState != PCR_STATE_FINISHED:
                timeHandler.detectPCRState = PCR_STATE_FINISHED
                timeHandler.generatePCR = 0
                #print "PCR is present for " + timeHandler.currentFile
                #sys.stdout.flush()
            if pcr != None:
                retVal += packet[offset:6]
                retVal += chr((pcr >> 25) & 0xff)
                retVal += chr((pcr >> 17) & 0xff)
                retVal += chr((pcr >> 9) & 0xff)
                retVal += chr((pcr >> 1) & 0xff)
                retVal += chr((ord(packet[10]) & 0x7f) | ((pcr << 7) & 0x80))
                offset = 11
        payload_offset = ord(packet[4])+5
        if payload_offset > offset:
            retVal += packet[offset:payload_offset]
            # in case payload_offset goes beyond the end of the packet,
            # python deals with it automatically
            offset = payload_offset
    if ord(packet[1]) & 0x40 and offset+18 < MINSTREAMSIZE:
        # start of a unit: we may have PTS and DTS (or a PMT)
        if adaptation_field_control == 0x10:
            # payload only
            retVal += packet[offset:4]
            offset = 4
            # check whether this is a PMT
            if packet[4:6] == "\x00\x02":
                # PMT found, get PCR id
                timeHandler.pcrId = ((ord(packet[13]) & 0x1f) << 8) | ord(packet[14])
                #print "PCR id found: " + str(timeHandler.pcrId)
                #sys.stdout.flush()
                # Actually, it's better to _set_ the PCR id to a specific one
                #if timeHandler.generatePCR:
                #    retVal += packet[offset:13]
                #    retVal += chr((ord(packet[13]) & 0xe0) | (timeHandler.pcrId >> 8))
                #    retVal += chr(timeHandler.pcrId & 0xff)
                #    offset = 15
                return retVal + packet[offset:]
        elif adaptation_field_control != 0x30:
            # no payload
            return retVal + packet[offset:]
        streamId = ord(packet[offset+3])
        if (streamId & 0xe0) == 0xc0 or (streamId & 0xf0) == 0xe0:
            # audio or video stream
            if (ord(packet[offset+6]) & 0xc0) == 0x80:    # sanity check
                if ord(packet[offset+7]) & 0x80:
                    #if ord(packet[offset]) != 0 or ord(packet[offset+1]) != 0 or ord(packet[offset+2]) != 1:
                    #    print "Problem!"
                    #    sys.stdout.flush()
                    #else:
                    #    print "No problem"
                    #    sys.stdout.flush()
                    if pts is None:
                        retVal += packet[offset:offset+14]
                    else:
                        retVal += packet[offset:offset+9]
                        byte = ord(packet[offset+9]) & 0xf1
                        retVal += chr(byte | ((pts >> 29) & 0x0e))
                        retVal += chr((pts >> 22) & 0xff)
                        retVal += chr(0x01 | ((pts >> 14) & 0xfe))
                        retVal += chr((pts >> 7) & 0xff)
                        retVal += chr(0x01 | ((pts << 1) & 0xfe))
                    if ord(packet[offset+7]) & 0x40:
                        if dts is None:
                            retVal += packet[offset+14:offset+19]
                        else:
                            retVal += chr(0x11 | ((dts >> 29) & 0x0e))
                            retVal += chr((dts >> 22) & 0xff)
                            retVal += chr(0x01 | ((dts >> 14) & 0xfe))
                            retVal += chr((dts >> 7) & 0xff)
                            retVal += chr(0x01 | ((dts << 1) & 0xfe))
                        offset += 19
                    else:
                        offset += 14
    # shortcut
    if offset == 0:
        return packet
    return retVal + packet[offset:]
    

MPEG1ASPECTRATIOS = [0.0, 1.0, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, \
                     0.9157, 0.9815, 1.0255, 1.0695, 1.095, 1.1575, 1.2051, 0.0]

def getSizeMPEG1(packet):
    """
    Prerequisite: A packet with the minimum data size must be
    passed in.
    """
    try:
        offset = 12
        if packet[offset:offset+3] == '\x00\x00\x01' and ord(packet[offset+3]) & 0xf0 == 0xe0:
            # we have a video stream
            offset += 6
            while packet[offset] == "\xff":
                offset += 1
            # TODO: make the above more robust (especially take care of a system
            #       header if present)
            if (ord(packet[offset]) & 0xc0) == 0x40:
                offset += 2
            flags = ord(packet[offset])
            offset += 1
            if flags & 0x20:
                offset += 4
                if flags & 0x10:
                    offset += 5
            if packet[offset:offset+4] == '\x00\x00\x01\xb3':
                # we have a sequence header
                width = ((ord(packet[offset+4])) << 4) | \
                        ((ord(packet[offset+5]) & 0xf0) >> 4)
                height = ((ord(packet[offset+5]) & 0x0f) << 8) | \
                         ((ord(packet[offset+6])))
                pixelAspectRatio = MPEG1ASPECTRATIOS[(ord(packet[offset+7]) & 0xf0) >> 4]
                if pixelAspectRatio != 0.0 and width != 0 and height != 0:
                    displayWidth = round(width/pixelAspectRatio)
                    aspectRatio = round(displayWidth/height, 4)
                    return (width, height, aspectRatio, STREAM_SUBTYPE_UNKNOWN)
        return None
    except IndexError:
        return NEED_MORE_DATA


MPEG2ASPECTRATIOS = [0.0, 1.0, 1.3333, 1.7778, 2.21, 0.0, 0.0, 0.0, \
                     0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
MPEG4ASPECTRATIOS = [0.0, 1.0, 12.0/11.0, 10.0/11.0, 16.0/11.0, 40.0/33.0, 0.0, 0.0, \
                     0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

def getSizeMPEG2(packet):
    try:
        adaptation_field_control = ord(packet[3]) & 0x30
        if ord(packet[1]) & 0x40 and adaptation_field_control & 0x10:
            # start of a unit and payload present: we may have a sequence header
            offset = 0
            if adaptation_field_control == 0x10:
                # payload only
                offset = 4  # skip only link header
            elif adaptation_field_control == 0x30:
                # adaptation field + payload
                offset = 5 + ord(packet[4])
            if packet[offset:offset+3] == '\x00\x00\x01' and (ord(packet[offset+3]) & 0xf0) == 0xe0:
                # we have a video stream, skip PES header
                offset += 9 + ord(packet[offset+8])
                # check for MPEG4
                packet[offset+18]   # raises an IndexError if not enough data is available
                if packet[offset:offset+4] == '\x00\x00\x01\xb0':
                    # find picture dimensions
                    searchOffset = offset+14
                    while searchOffset < MINSTREAMSIZE-100:
                        if packet[searchOffset] == '\x20':
                            if packet[searchOffset-3:searchOffset+1] == '\x00\x00\x01\x20':
                                searchOffset += 1
                                break
                        searchOffset += 1
                    # MPEG 4 (translated from VLC C source code)
                    bitreader = Bitreader(packet[searchOffset:])
                    bitreader.skip(1)
                    vo_type = bitreader.read(8)
                    if bitreader.read(1):
                        vo_ver_id = bitreader.read(4)
                        bitreader.skip(3)
                    else:
                        vo_ver_id = 1
                    ar = bitreader.read(4)
                    if ar == 0x0f:
                        ar_width = bitreader.read(8)
                        ar_height = bitreader.read(8)
                        pixelAspectRatio = float(ar_width)/ar_height
                    else:
                        pixelAspectRatio = MPEG4ASPECTRATIOS[ar]
                    if bitreader.read(1):
                        chroma_format = bitreader.read(2)
                        low_delay = bitreader.read(1)
                        if bitreader.read(1):
                            bitreader.skip(16 + 16 + 16 + 3 + 11 + 1 + 16)
                    shape = bitreader.read(2)
                    if shape == 3 and vo_ver_id != 1:
                        bitreader.skip(4)
                    if bitreader.read(1):
                        # sanity check
                        time_increment_resolution = bitreader.read(16)
                        if bitreader.read(1):
                            # sanity check
                            if bitreader.read(1):
                                time_increment_bits = vlc_log2(time_increment_resolution - 1) + 1
                                if time_increment_bits < 1:
                                    time_increment_bits = 1
                                bitreader.skip(time_increment_bits)
                            if shape == 0:
                                bitreader.skip(1)
                                width = bitreader.read(13)
                                bitreader.skip(1)
                                height = bitreader.read(13)
                                bitreader.skip(1)
                                aspectRatio = float(width)/height*pixelAspectRatio
                                if aspectRatio != 0.0 and width != 0 and height != 0:
                                    return (width, height, aspectRatio, STREAM_SUBTYPE_MPEG4)
                else:
                    sequenceHeaderFound = 0
                    if packet[offset:offset+4] == '\x00\x00\x01\xb3':
                        sequenceHeaderFound = 1
                    else:
                        offset = (offset + 7)/8*8
                        if packet[offset:offset+4] == '\x00\x00\x01\xb3':
                            sequenceHeaderFound = 1
                    if sequenceHeaderFound:
                        # we have a sequence header
                        width = ((ord(packet[offset+4])) << 4) | \
                                ((ord(packet[offset+5]) & 0xf0) >> 4)
                        height = ((ord(packet[offset+5]) & 0x0f) << 8) | \
                                 ((ord(packet[offset+6])))
                        aspectRatio = MPEG2ASPECTRATIOS[(ord(packet[offset+7]) & 0xf0) >> 4]
                        if aspectRatio != 0.0 and width != 0 and height != 0:
                            return (width, height, aspectRatio, STREAM_SUBTYPE_UNKNOWN)
        return None
    except IndexError:
        return NEED_MORE_DATA


def readPacketMPEG1(fileHandle):
    bytes = fileHandle.read(MPEG1STREAMSIZE)
    if len(bytes) < MPEG1STREAMSIZE:
        return ""
    return bytes


def readPacketMPEG2TS(fileHandle):
    bytes = fileHandle.read(MPEG2STREAMSIZE)
    if len(bytes) < MPEG2STREAMSIZE:
        return ""
    return bytes


def readAndWritePacketMPEG1(requestHandler, inFileHandle, outFileHandle, clockOffset):
    #return videotiming.readWriteMPEG1(requestHandler, inFileHandle.fileno(), \
    #                                  outFileHandle.fileno(), clockOffset)
    bytes = inFileHandle.read(MPEG1READSIZE)
    lenRead = len(bytes)
    tooMuch = lenRead % MPEG1STREAMSIZE
    if tooMuch > 0:
        inFileHandle.seek(-tooMuch, 1)
        lenRead -= tooMuch
    if lenRead == 0:
        return 0
    requestHandler.safeForChanging = 1
    if clockOffset is not None:
        outBytes = ""
        for i in range(lenRead/MPEG1STREAMSIZE):
            slice = bytes[i*MPEG1STREAMSIZE:(i+1)*MPEG1STREAMSIZE]
            cr, pts, dts, audioPTS = getTimesMPEG1(slice)
            if cr is not None:
                cr += clockOffset
                #cr = long(cr*2)
            if pts is not None:
                pts += clockOffset
                #pts = long(pts*2)
            if dts is not None:
                dts += clockOffset
                #dts = long(dts*2)
            slice = setTimesMPEG1(slice, cr, pts, dts, audioPTS, requestHandler)
            outBytes += slice
            if len(outBytes) > MPEG1WRITESIZE:
                outFileHandle.write(outBytes)
                outBytes = ""
        if len(outBytes) > 0:
            outFileHandle.write(outBytes)
    else:
        outFileHandle.write(bytes)
    return lenRead


def readAndWritePacketMPEG2(requestHandler, inFileHandle, outFileHandle, clockOffset):
    #return videotiming.readWriteMPEG2TS(requestHandler, inFileHandle.fileno(), \
    #                                  outFileHandle.fileno(), clockOffset)
    bytes = inFileHandle.read(MPEG2READSIZE)
    lenRead = len(bytes)
    tooMuch = lenRead % MPEG2STREAMSIZE
    if tooMuch > 0:
        inFileHandle.seek(-tooMuch, 1)
        lenRead -= tooMuch
    if lenRead == 0:
        return 0
    requestHandler.safeForChanging = 1
    if clockOffset is not None:
        outBytes = ""
        for i in range(lenRead/MPEG2STREAMSIZE):
            slice = bytes[i*MPEG2STREAMSIZE:(i+1)*MPEG2STREAMSIZE]
            cr, pts, dts, audioPTS = getTimesMPEG2TS(slice)
            if cr is not None: cr += clockOffset
            if pts is not None: pts += clockOffset
            if dts is not None: dts += clockOffset
            slice = setTimesMPEG2TS(slice, cr, pts, dts, audioPTS, requestHandler)
            outBytes += slice
            if len(outBytes) > MPEG2WRITESIZE:
                outFileHandle.write(outBytes)
                #if requestHandler.currentFile == "0000000000000001":
                #    outstream.write(outBytes)
                outBytes = ""
        if len(outBytes) > 0:
            outFileHandle.write(outBytes)
            #if requestHandler.currentFile == "0000000000000001":
            #    outstream.write(outBytes)
    else:
        outFileHandle.write(bytes)
        #if requestHandler.currentFile == "0000000000000001":
        #    outstream.write(bytes)
    return lenRead


class MPEGHandler:
    """
    Class responsible for reading and manipulating MPEG streams.
    """
    pass


MPEG1Handler = MPEGHandler()
MPEG1Handler.readPacket = readPacketMPEG1
MPEG1Handler.getTimes = getTimesMPEG1
MPEG1Handler.setTimes = setTimesMPEG1
MPEG1Handler.getSize = getSizeMPEG1
MPEG1Handler.packetSize = MPEG1STREAMSIZE
MPEG1Handler.readSize = MPEG1READSIZE
MPEG1Handler.minSize = MPEG1MINSIZE
MPEG1Handler.readAndWritePacket = readAndWritePacketMPEG1

MPEG2Handler = MPEGHandler()
MPEG2Handler.readPacket = readPacketMPEG2TS
MPEG2Handler.getTimes = getTimesMPEG2TS
MPEG2Handler.setTimes = setTimesMPEG2TS
MPEG2Handler.getSize = getSizeMPEG2
MPEG2Handler.packetSize = MPEG2STREAMSIZE
MPEG2Handler.readSize = MPEG2READSIZE
MPEG2Handler.minSize = MPEG2MINSIZE
MPEG2Handler.readAndWritePacket = readAndWritePacketMPEG2


