ยปCore Development>Code coverage>Lib/plat-mac/videoreader.py

Python code coverage for Lib/plat-mac/videoreader.py

#countcontent
1n/a# Video file reader, using QuickTime
2n/a#
3n/a# This module was quickly ripped out of another software package, so there is a good
4n/a# chance that it does not work as-is and it needs some hacking.
5n/a#
6n/a# Jack Jansen, August 2000
7n/a#
8n/a
9n/afrom warnings import warnpy3k
10n/awarnpy3k("In 3.x, the videoreader module is removed.", stacklevel=2)
11n/a
12n/a
13n/aimport sys
14n/afrom Carbon import Qt
15n/afrom Carbon import QuickTime
16n/afrom Carbon import Qd
17n/afrom Carbon import Qdoffs
18n/afrom Carbon import QDOffscreen
19n/afrom Carbon import Res
20n/atry:
21n/a from Carbon import MediaDescr
22n/aexcept ImportError:
23n/a def _audiodescr(data):
24n/a return None
25n/aelse:
26n/a def _audiodescr(data):
27n/a return MediaDescr.SoundDescription.decode(data)
28n/atry:
29n/a from imgformat import macrgb
30n/aexcept ImportError:
31n/a macrgb = "Macintosh RGB format"
32n/aimport os
33n/a# import audio.format
34n/a
35n/aclass VideoFormat:
36n/a def __init__(self, name, descr, width, height, format):
37n/a self.__name = name
38n/a self.__descr = descr
39n/a self.__width = width
40n/a self.__height = height
41n/a self.__format = format
42n/a
43n/a def getname(self):
44n/a return self.__name
45n/a
46n/a def getdescr(self):
47n/a return self.__descr
48n/a
49n/a def getsize(self):
50n/a return self.__width, self.__height
51n/a
52n/a def getformat(self):
53n/a return self.__format
54n/a
55n/aclass _Reader:
56n/a def __init__(self, path):
57n/a fd = Qt.OpenMovieFile(path, 0)
58n/a self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0)
59n/a self.movietimescale = self.movie.GetMovieTimeScale()
60n/a try:
61n/a self.audiotrack = self.movie.GetMovieIndTrackType(1,
62n/a QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic)
63n/a self.audiomedia = self.audiotrack.GetTrackMedia()
64n/a except Qt.Error:
65n/a self.audiotrack = self.audiomedia = None
66n/a self.audiodescr = {}
67n/a else:
68n/a handle = Res.Handle('')
69n/a n = self.audiomedia.GetMediaSampleDescriptionCount()
70n/a self.audiomedia.GetMediaSampleDescription(1, handle)
71n/a self.audiodescr = _audiodescr(handle.data)
72n/a self.audiotimescale = self.audiomedia.GetMediaTimeScale()
73n/a del handle
74n/a
75n/a try:
76n/a self.videotrack = self.movie.GetMovieIndTrackType(1,
77n/a QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic)
78n/a self.videomedia = self.videotrack.GetTrackMedia()
79n/a except Qt.Error:
80n/a self.videotrack = self.videomedia = self.videotimescale = None
81n/a if self.videotrack:
82n/a self.videotimescale = self.videomedia.GetMediaTimeScale()
83n/a x0, y0, x1, y1 = self.movie.GetMovieBox()
84n/a self.videodescr = {'width':(x1-x0), 'height':(y1-y0)}
85n/a self._initgworld()
86n/a self.videocurtime = None
87n/a self.audiocurtime = None
88n/a
89n/a
90n/a def __del__(self):
91n/a self.audiomedia = None
92n/a self.audiotrack = None
93n/a self.videomedia = None
94n/a self.videotrack = None
95n/a self.movie = None
96n/a
97n/a def _initgworld(self):
98n/a old_port, old_dev = Qdoffs.GetGWorld()
99n/a try:
100n/a movie_w = self.videodescr['width']
101n/a movie_h = self.videodescr['height']
102n/a movie_rect = (0, 0, movie_w, movie_h)
103n/a self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal)
104n/a self.pixmap = self.gworld.GetGWorldPixMap()
105n/a Qdoffs.LockPixels(self.pixmap)
106n/a Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None)
107n/a Qd.EraseRect(movie_rect)
108n/a self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None)
109n/a self.movie.SetMovieBox(movie_rect)
110n/a self.movie.SetMovieActive(1)
111n/a self.movie.MoviesTask(0)
112n/a self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality)
113n/a # XXXX framerate
114n/a finally:
115n/a Qdoffs.SetGWorld(old_port, old_dev)
116n/a
117n/a def _gettrackduration_ms(self, track):
118n/a tracktime = track.GetTrackDuration()
119n/a return self._movietime_to_ms(tracktime)
120n/a
121n/a def _movietime_to_ms(self, time):
122n/a value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000)
123n/a return value
124n/a
125n/a def _videotime_to_ms(self, time):
126n/a value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000)
127n/a return value
128n/a
129n/a def _audiotime_to_ms(self, time):
130n/a value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000)
131n/a return value
132n/a
133n/a def _videotime_to_movietime(self, time):
134n/a value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None),
135n/a self.movietimescale)
136n/a return value
137n/a
138n/a def HasAudio(self):
139n/a return not self.audiotrack is None
140n/a
141n/a def HasVideo(self):
142n/a return not self.videotrack is None
143n/a
144n/a def GetAudioDuration(self):
145n/a if not self.audiotrack:
146n/a return 0
147n/a return self._gettrackduration_ms(self.audiotrack)
148n/a
149n/a def GetVideoDuration(self):
150n/a if not self.videotrack:
151n/a return 0
152n/a return self._gettrackduration_ms(self.videotrack)
153n/a
154n/a def GetAudioFormat(self):
155n/a if not self.audiodescr:
156n/a return None, None, None, None, None
157n/a bps = self.audiodescr['sampleSize']
158n/a nch = self.audiodescr['numChannels']
159n/a if nch == 1:
160n/a channels = ['mono']
161n/a elif nch == 2:
162n/a channels = ['left', 'right']
163n/a else:
164n/a channels = map(lambda x: str(x+1), range(nch))
165n/a if bps % 8:
166n/a # Funny bits-per sample. We pretend not to understand
167n/a blocksize = 0
168n/a fpb = 0
169n/a else:
170n/a # QuickTime is easy (for as far as we support it): samples are always a whole
171n/a # number of bytes, so frames are nchannels*samplesize, and there's one frame per block.
172n/a blocksize = (bps/8)*nch
173n/a fpb = 1
174n/a if self.audiodescr['dataFormat'] == 'raw ':
175n/a encoding = 'linear-excess'
176n/a elif self.audiodescr['dataFormat'] == 'twos':
177n/a encoding = 'linear-signed'
178n/a else:
179n/a encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat']
180n/a## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format',
181n/a## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps)
182n/a return channels, encoding, blocksize, fpb, bps
183n/a
184n/a def GetAudioFrameRate(self):
185n/a if not self.audiodescr:
186n/a return None
187n/a return int(self.audiodescr['sampleRate'])
188n/a
189n/a def GetVideoFormat(self):
190n/a width = self.videodescr['width']
191n/a height = self.videodescr['height']
192n/a return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb)
193n/a
194n/a def GetVideoFrameRate(self):
195n/a tv = self.videocurtime
196n/a if tv is None:
197n/a tv = 0
198n/a flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
199n/a tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0)
200n/a dur = self._videotime_to_ms(dur)
201n/a return int((1000.0/dur)+0.5)
202n/a
203n/a def ReadAudio(self, nframes, time=None):
204n/a if not time is None:
205n/a self.audiocurtime = time
206n/a flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
207n/a if self.audiocurtime is None:
208n/a self.audiocurtime = 0
209n/a tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0)
210n/a if tv < 0 or (self.audiocurtime and tv < self.audiocurtime):
211n/a return self._audiotime_to_ms(self.audiocurtime), None
212n/a h = Res.Handle('')
213n/a desc_h = Res.Handle('')
214n/a size, actualtime, sampleduration, desc_index, actualcount, flags = \
215n/a self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes)
216n/a self.audiocurtime = actualtime + actualcount*sampleduration
217n/a return self._audiotime_to_ms(actualtime), h.data
218n/a
219n/a def ReadVideo(self, time=None):
220n/a if not time is None:
221n/a self.videocurtime = time
222n/a flags = QuickTime.nextTimeStep
223n/a if self.videocurtime is None:
224n/a flags = flags | QuickTime.nextTimeEdgeOK
225n/a self.videocurtime = 0
226n/a tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0)
227n/a if tv < 0 or (self.videocurtime and tv <= self.videocurtime):
228n/a return self._videotime_to_ms(self.videocurtime), None
229n/a self.videocurtime = tv
230n/a moviecurtime = self._videotime_to_movietime(self.videocurtime)
231n/a self.movie.SetMovieTimeValue(moviecurtime)
232n/a self.movie.MoviesTask(0)
233n/a return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent()
234n/a
235n/a def _getpixmapcontent(self):
236n/a """Shuffle the offscreen PixMap data, because it may have funny stride values"""
237n/a rowbytes = Qdoffs.GetPixRowBytes(self.pixmap)
238n/a width = self.videodescr['width']
239n/a height = self.videodescr['height']
240n/a start = 0
241n/a rv = []
242n/a for i in range(height):
243n/a nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4)
244n/a start = start + rowbytes
245n/a rv.append(nextline)
246n/a return ''.join(rv)
247n/a
248n/adef reader(url):
249n/a try:
250n/a rdr = _Reader(url)
251n/a except IOError:
252n/a return None
253n/a return rdr
254n/a
255n/adef _test():
256n/a import EasyDialogs
257n/a try:
258n/a from PIL import Image
259n/a except ImportError:
260n/a Image = None
261n/a import MacOS
262n/a Qt.EnterMovies()
263n/a path = EasyDialogs.AskFileForOpen(message='Video to convert')
264n/a if not path: sys.exit(0)
265n/a rdr = reader(path)
266n/a if not rdr:
267n/a sys.exit(1)
268n/a dstdir = EasyDialogs.AskFileForSave(message='Name for output folder')
269n/a if not dstdir: sys.exit(0)
270n/a num = 0
271n/a os.mkdir(dstdir)
272n/a videofmt = rdr.GetVideoFormat()
273n/a imgfmt = videofmt.getformat()
274n/a imgw, imgh = videofmt.getsize()
275n/a timestamp, data = rdr.ReadVideo()
276n/a while data:
277n/a fname = 'frame%04.4d.jpg'%num
278n/a num = num+1
279n/a pname = os.path.join(dstdir, fname)
280n/a if not Image: print 'Not',
281n/a print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data))
282n/a if Image:
283n/a img = Image.fromstring("RGBA", (imgw, imgh), data)
284n/a img.save(pname, 'JPEG')
285n/a timestamp, data = rdr.ReadVideo()
286n/a MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG')
287n/a if num > 20:
288n/a print 'stopping at 20 frames so your disk does not fill up:-)'
289n/a break
290n/a print 'Total frames:', num
291n/a
292n/aif __name__ == '__main__':
293n/a _test()
294n/a sys.exit(1)