File: oggtail.py

package info (click to toggle)
pyogg 1.3%2Brepack-2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 248 kB
  • ctags: 153
  • sloc: ansic: 980; python: 227; makefile: 72; sh: 15
file content (145 lines) | stat: -rw-r--r-- 4,146 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python

#	$Id: oggtail.py,v 1.1 2001/05/02 01:49:11 andrew Exp $

# Send to stdout an ogg stream composed of the last PERCENT percent of
# file OGGFILE.
#
# example:  oggtail.py --percent=PERCENT OGGFILE
#
# (PERCENT is rounded down to the nearest page.  Cutting at the
# nearest packet would be more complicated.)

# First version by Mike Coleman <mkc@mathdogs.com>, April 2001

# TODO: This still doesn't work quite right.  'ogg123' complains with
# a warning if we pipe oggtail's output directly into it, so probably
# there's a minor error in the stream formatting somewhere.


import getopt
import ogg
import sys

_debug = 0

def usage():
    sys.exit("usage: oggtail.py [--debug] --percent=PERCENT OGGFILE")

def debug(s):
    if _debug:
        sys.stderr.write(s)
        sys.stderr.write('\n')


def copy_packets(from_, to_, outstream=None, count=None, start_pageno=0, start_granulepos=0):
    """
    Copy 'count' packets from file 'from_' to file 'to_'.  If 'count'
    is None, copy the rest of 'from_'.  Use 'start_granulepos' as the
    initial granulepos tag for pages.  Bytes will be skipped in
    'from_' to sync, as needed, and copying will stop if a chain
    boundary is encountered.
    """

    # XXX: warn on desync, except at beginning?

    copied = 0
    written = 0
    pageno = start_pageno
    granule_offset = None

    instream = None

    # get it?  insync?  get it?  i'm so funny you can't stand it!
    insync = ogg.OggSyncState()

    while count == None or copied < count:
        b = from_.read(65536)           # size doesn't really matter
        if not b:
            break
        insync.bytesin(b)

        skipped = 1
        while skipped != 0:
            skipped, page = insync.pageseek()
            if skipped > 0:
                if instream and page.serialno() != serialno:
                    # we hit a chain boundary
                    break
                if not instream:
                    serialno = page.serialno()
                    instream = ogg.OggStreamState(serialno)
                    outstream = ogg.OggStreamState(serialno)
                page.pageno = pageno
                debug('*** %s' % page.pageno())
                pageno = pageno + 1
                instream.pagein(page)
                while count == None or copied < count:
                    p = instream.packetout()
                    if not p:
                        break
                    if p.granulepos != -1:
                        if granule_offset == None:
                            granule_offset = p.granulepos
                        p.granulepos = p.granulepos - granule_offset
                    debug('copied %s' % p)
                    outstream.packetin(p)
                    copied = copied + 1
                while 1:
                    pg = outstream.pageout()
                    if not pg:
                        break
                    debug('writing %s' % pg)
                    # FIX: should check success of write
                    written = written + pg.writeout(to_)
            elif skipped < 0:
                print 'skipped', -skipped, 'bytes'

    pg = outstream.flush()
    if pg:
        written = written + pg.writeout(to_)

    return (written, pageno - start_pageno, outstream)
    



opts, pargs = getopt.getopt(sys.argv[1:], '', ['debug', 'percent='])

print sys.argv, opts, pargs
if len(opts) < 1 or len(pargs) != 1:
    usage()

for o, a in opts:
    print o, a
    if o == '--percent':
        try:
            percent = float(a)
        except ValueError:
            usage()
    elif o == '--debug':
        _debug = 1
    else:
        usage()

if not 0.0 <= percent <= 100.0:
    usage()

file = pargs[0]

f = open(file, 'rb')

f.seek(0, 2)
f_size = f.tell()
f.seek(0)

# first copy the three header packets
n, p, os = copy_packets(f, sys.stdout, None, 3)
debug('copied header: %d bytes, %d pages' % (n, p))
debug(str(os))

# then seek to percent and copy out the rest
f.seek(int((100.0 - percent) / 100.0 * f_size))
n, p, os = copy_packets(f, sys.stdout, os)
debug('copied tail: %d bytes, %d pages' % (n, p))
debug(str(os))