diff options
Diffstat (limited to 'Lib/plat-mac/videoreader.py')
-rw-r--r-- | Lib/plat-mac/videoreader.py | 522 |
1 files changed, 261 insertions, 261 deletions
diff --git a/Lib/plat-mac/videoreader.py b/Lib/plat-mac/videoreader.py index 6153287..646c726 100644 --- a/Lib/plat-mac/videoreader.py +++ b/Lib/plat-mac/videoreader.py @@ -13,280 +13,280 @@ from Carbon import Qdoffs from Carbon import QDOffscreen from Carbon import Res try: - import MediaDescr + import MediaDescr except ImportError: - def _audiodescr(data): - return None + def _audiodescr(data): + return None else: - def _audiodescr(data): - return MediaDescr.SoundDescription.decode(data) + def _audiodescr(data): + return MediaDescr.SoundDescription.decode(data) try: - from imgformat import macrgb + from imgformat import macrgb except ImportError: - macrgb = "Macintosh RGB format" + macrgb = "Macintosh RGB format" import os # import audio.format class VideoFormat: - def __init__(self, name, descr, width, height, format): - self.__name = name - self.__descr = descr - self.__width = width - self.__height = height - self.__format = format - - def getname(self): - return self.__name - - def getdescr(self): - return self.__descr - - def getsize(self): - return self.__width, self.__height - - def getformat(self): - return self.__format - + def __init__(self, name, descr, width, height, format): + self.__name = name + self.__descr = descr + self.__width = width + self.__height = height + self.__format = format + + def getname(self): + return self.__name + + def getdescr(self): + return self.__descr + + def getsize(self): + return self.__width, self.__height + + def getformat(self): + return self.__format + class _Reader: - def __init__(self, path): - fd = Qt.OpenMovieFile(path, 0) - self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0) - self.movietimescale = self.movie.GetMovieTimeScale() - try: - self.audiotrack = self.movie.GetMovieIndTrackType(1, - QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic) - self.audiomedia = self.audiotrack.GetTrackMedia() - except Qt.Error: - self.audiotrack = self.audiomedia = None - self.audiodescr = {} - else: - handle = Res.Handle('') - n = self.audiomedia.GetMediaSampleDescriptionCount() - self.audiomedia.GetMediaSampleDescription(1, handle) - self.audiodescr = _audiodescr(handle.data) - self.audiotimescale = self.audiomedia.GetMediaTimeScale() - del handle - - try: - self.videotrack = self.movie.GetMovieIndTrackType(1, - QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic) - self.videomedia = self.videotrack.GetTrackMedia() - except Qt.Error: - self.videotrack = self.videomedia = self.videotimescale = None - if self.videotrack: - self.videotimescale = self.videomedia.GetMediaTimeScale() - x0, y0, x1, y1 = self.movie.GetMovieBox() - self.videodescr = {'width':(x1-x0), 'height':(y1-y0)} - self._initgworld() - self.videocurtime = None - self.audiocurtime = None + def __init__(self, path): + fd = Qt.OpenMovieFile(path, 0) + self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0) + self.movietimescale = self.movie.GetMovieTimeScale() + try: + self.audiotrack = self.movie.GetMovieIndTrackType(1, + QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic) + self.audiomedia = self.audiotrack.GetTrackMedia() + except Qt.Error: + self.audiotrack = self.audiomedia = None + self.audiodescr = {} + else: + handle = Res.Handle('') + n = self.audiomedia.GetMediaSampleDescriptionCount() + self.audiomedia.GetMediaSampleDescription(1, handle) + self.audiodescr = _audiodescr(handle.data) + self.audiotimescale = self.audiomedia.GetMediaTimeScale() + del handle + + try: + self.videotrack = self.movie.GetMovieIndTrackType(1, + QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic) + self.videomedia = self.videotrack.GetTrackMedia() + except Qt.Error: + self.videotrack = self.videomedia = self.videotimescale = None + if self.videotrack: + self.videotimescale = self.videomedia.GetMediaTimeScale() + x0, y0, x1, y1 = self.movie.GetMovieBox() + self.videodescr = {'width':(x1-x0), 'height':(y1-y0)} + self._initgworld() + self.videocurtime = None + self.audiocurtime = None - - def __del__(self): - self.audiomedia = None - self.audiotrack = None - self.videomedia = None - self.videotrack = None - self.movie = None - - def _initgworld(self): - old_port, old_dev = Qdoffs.GetGWorld() - try: - movie_w = self.videodescr['width'] - movie_h = self.videodescr['height'] - movie_rect = (0, 0, movie_w, movie_h) - self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal) - self.pixmap = self.gworld.GetGWorldPixMap() - Qdoffs.LockPixels(self.pixmap) - Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None) - Qd.EraseRect(movie_rect) - self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None) - self.movie.SetMovieBox(movie_rect) - self.movie.SetMovieActive(1) - self.movie.MoviesTask(0) - self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality) - # XXXX framerate - finally: - Qdoffs.SetGWorld(old_port, old_dev) - - def _gettrackduration_ms(self, track): - tracktime = track.GetTrackDuration() - return self._movietime_to_ms(tracktime) - - def _movietime_to_ms(self, time): - value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000) - return value - - def _videotime_to_ms(self, time): - value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000) - return value - - def _audiotime_to_ms(self, time): - value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000) - return value - - def _videotime_to_movietime(self, time): - value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), - self.movietimescale) - return value - - def HasAudio(self): - return not self.audiotrack is None - - def HasVideo(self): - return not self.videotrack is None - - def GetAudioDuration(self): - if not self.audiotrack: - return 0 - return self._gettrackduration_ms(self.audiotrack) + + def __del__(self): + self.audiomedia = None + self.audiotrack = None + self.videomedia = None + self.videotrack = None + self.movie = None + + def _initgworld(self): + old_port, old_dev = Qdoffs.GetGWorld() + try: + movie_w = self.videodescr['width'] + movie_h = self.videodescr['height'] + movie_rect = (0, 0, movie_w, movie_h) + self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal) + self.pixmap = self.gworld.GetGWorldPixMap() + Qdoffs.LockPixels(self.pixmap) + Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None) + Qd.EraseRect(movie_rect) + self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None) + self.movie.SetMovieBox(movie_rect) + self.movie.SetMovieActive(1) + self.movie.MoviesTask(0) + self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality) + # XXXX framerate + finally: + Qdoffs.SetGWorld(old_port, old_dev) + + def _gettrackduration_ms(self, track): + tracktime = track.GetTrackDuration() + return self._movietime_to_ms(tracktime) + + def _movietime_to_ms(self, time): + value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000) + return value + + def _videotime_to_ms(self, time): + value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000) + return value + + def _audiotime_to_ms(self, time): + value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000) + return value + + def _videotime_to_movietime(self, time): + value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), + self.movietimescale) + return value + + def HasAudio(self): + return not self.audiotrack is None + + def HasVideo(self): + return not self.videotrack is None + + def GetAudioDuration(self): + if not self.audiotrack: + return 0 + return self._gettrackduration_ms(self.audiotrack) - def GetVideoDuration(self): - if not self.videotrack: - return 0 - return self._gettrackduration_ms(self.videotrack) - - def GetAudioFormat(self): - if not self.audiodescr: - return None, None, None, None, None - bps = self.audiodescr['sampleSize'] - nch = self.audiodescr['numChannels'] - if nch == 1: - channels = ['mono'] - elif nch == 2: - channels = ['left', 'right'] - else: - channels = map(lambda x: str(x+1), range(nch)) - if bps % 8: - # Funny bits-per sample. We pretend not to understand - blocksize = 0 - fpb = 0 - else: - # QuickTime is easy (for as far as we support it): samples are always a whole - # number of bytes, so frames are nchannels*samplesize, and there's one frame per block. - blocksize = (bps/8)*nch - fpb = 1 - if self.audiodescr['dataFormat'] == 'raw ': - encoding = 'linear-excess' - elif self.audiodescr['dataFormat'] == 'twos': - encoding = 'linear-signed' - else: - encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat'] -## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format', -## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps) - return channels, encoding, blocksize, fpb, bps - - def GetAudioFrameRate(self): - if not self.audiodescr: - return None - return int(self.audiodescr['sampleRate']) - - def GetVideoFormat(self): - width = self.videodescr['width'] - height = self.videodescr['height'] - return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb) - - def GetVideoFrameRate(self): - tv = self.videocurtime - if tv == None: - tv = 0 - flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK - tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0) - dur = self._videotime_to_ms(dur) - return int((1000.0/dur)+0.5) - - def ReadAudio(self, nframes, time=None): - if not time is None: - self.audiocurtime = time - flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK - if self.audiocurtime == None: - self.audiocurtime = 0 - tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0) - if tv < 0 or (self.audiocurtime and tv < self.audiocurtime): - return self._audiotime_to_ms(self.audiocurtime), None - h = Res.Handle('') - desc_h = Res.Handle('') - size, actualtime, sampleduration, desc_index, actualcount, flags = \ - self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes) - self.audiocurtime = actualtime + actualcount*sampleduration - return self._audiotime_to_ms(actualtime), h.data - - def ReadVideo(self, time=None): - if not time is None: - self.videocurtime = time - flags = QuickTime.nextTimeStep - if self.videocurtime == None: - flags = flags | QuickTime.nextTimeEdgeOK - self.videocurtime = 0 - tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0) - if tv < 0 or (self.videocurtime and tv <= self.videocurtime): - return self._videotime_to_ms(self.videocurtime), None - self.videocurtime = tv - moviecurtime = self._videotime_to_movietime(self.videocurtime) - self.movie.SetMovieTimeValue(moviecurtime) - self.movie.MoviesTask(0) - return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent() - - def _getpixmapcontent(self): - """Shuffle the offscreen PixMap data, because it may have funny stride values""" - rowbytes = Qdoffs.GetPixRowBytes(self.pixmap) - width = self.videodescr['width'] - height = self.videodescr['height'] - start = 0 - rv = '' - for i in range(height): - nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4) - start = start + rowbytes - rv = rv + nextline - return rv + def GetVideoDuration(self): + if not self.videotrack: + return 0 + return self._gettrackduration_ms(self.videotrack) + + def GetAudioFormat(self): + if not self.audiodescr: + return None, None, None, None, None + bps = self.audiodescr['sampleSize'] + nch = self.audiodescr['numChannels'] + if nch == 1: + channels = ['mono'] + elif nch == 2: + channels = ['left', 'right'] + else: + channels = map(lambda x: str(x+1), range(nch)) + if bps % 8: + # Funny bits-per sample. We pretend not to understand + blocksize = 0 + fpb = 0 + else: + # QuickTime is easy (for as far as we support it): samples are always a whole + # number of bytes, so frames are nchannels*samplesize, and there's one frame per block. + blocksize = (bps/8)*nch + fpb = 1 + if self.audiodescr['dataFormat'] == 'raw ': + encoding = 'linear-excess' + elif self.audiodescr['dataFormat'] == 'twos': + encoding = 'linear-signed' + else: + encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat'] +## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format', +## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps) + return channels, encoding, blocksize, fpb, bps + + def GetAudioFrameRate(self): + if not self.audiodescr: + return None + return int(self.audiodescr['sampleRate']) + + def GetVideoFormat(self): + width = self.videodescr['width'] + height = self.videodescr['height'] + return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb) + + def GetVideoFrameRate(self): + tv = self.videocurtime + if tv == None: + tv = 0 + flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK + tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0) + dur = self._videotime_to_ms(dur) + return int((1000.0/dur)+0.5) + + def ReadAudio(self, nframes, time=None): + if not time is None: + self.audiocurtime = time + flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK + if self.audiocurtime == None: + self.audiocurtime = 0 + tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0) + if tv < 0 or (self.audiocurtime and tv < self.audiocurtime): + return self._audiotime_to_ms(self.audiocurtime), None + h = Res.Handle('') + desc_h = Res.Handle('') + size, actualtime, sampleduration, desc_index, actualcount, flags = \ + self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes) + self.audiocurtime = actualtime + actualcount*sampleduration + return self._audiotime_to_ms(actualtime), h.data + + def ReadVideo(self, time=None): + if not time is None: + self.videocurtime = time + flags = QuickTime.nextTimeStep + if self.videocurtime == None: + flags = flags | QuickTime.nextTimeEdgeOK + self.videocurtime = 0 + tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0) + if tv < 0 or (self.videocurtime and tv <= self.videocurtime): + return self._videotime_to_ms(self.videocurtime), None + self.videocurtime = tv + moviecurtime = self._videotime_to_movietime(self.videocurtime) + self.movie.SetMovieTimeValue(moviecurtime) + self.movie.MoviesTask(0) + return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent() + + def _getpixmapcontent(self): + """Shuffle the offscreen PixMap data, because it may have funny stride values""" + rowbytes = Qdoffs.GetPixRowBytes(self.pixmap) + width = self.videodescr['width'] + height = self.videodescr['height'] + start = 0 + rv = '' + for i in range(height): + nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4) + start = start + rowbytes + rv = rv + nextline + return rv def reader(url): - try: - rdr = _Reader(url) - except IOError: - return None - return rdr + try: + rdr = _Reader(url) + except IOError: + return None + return rdr def _test(): - import EasyDialogs - try: - import img - except ImportError: - img = None - import MacOS - Qt.EnterMovies() - path = EasyDialogs.AskFileForOpen(message='Video to convert') - if not path: sys.exit(0) - rdr = reader(path) - if not rdr: - sys.exit(1) - dstdir = EasyDialogs.AskFileForSave(message='Name for output folder') - if not dstdir: sys.exit(0) - num = 0 - os.mkdir(dstdir) - videofmt = rdr.GetVideoFormat() - imgfmt = videofmt.getformat() - imgw, imgh = videofmt.getsize() - timestamp, data = rdr.ReadVideo() - while data: - fname = 'frame%04.4d.jpg'%num - num = num+1 - pname = os.path.join(dstdir, fname) - if not img: print 'Not', - print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data)) - if img: - wrt = img.writer(imgfmt, pname) - wrt.width = imgw - wrt.height = imgh - wrt.write(data) - timestamp, data = rdr.ReadVideo() - MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG') - if num > 20: - print 'stopping at 20 frames so your disk does not fill up:-)' - break - print 'Total frames:', num - + import EasyDialogs + try: + import img + except ImportError: + img = None + import MacOS + Qt.EnterMovies() + path = EasyDialogs.AskFileForOpen(message='Video to convert') + if not path: sys.exit(0) + rdr = reader(path) + if not rdr: + sys.exit(1) + dstdir = EasyDialogs.AskFileForSave(message='Name for output folder') + if not dstdir: sys.exit(0) + num = 0 + os.mkdir(dstdir) + videofmt = rdr.GetVideoFormat() + imgfmt = videofmt.getformat() + imgw, imgh = videofmt.getsize() + timestamp, data = rdr.ReadVideo() + while data: + fname = 'frame%04.4d.jpg'%num + num = num+1 + pname = os.path.join(dstdir, fname) + if not img: print 'Not', + print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data)) + if img: + wrt = img.writer(imgfmt, pname) + wrt.width = imgw + wrt.height = imgh + wrt.write(data) + timestamp, data = rdr.ReadVideo() + MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG') + if num > 20: + print 'stopping at 20 frames so your disk does not fill up:-)' + break + print 'Total frames:', num + if __name__ == '__main__': - _test() - sys.exit(1) - + _test() + sys.exit(1) + |