def get_text(self, name = 'PRIMARY'): # get pasteboard item count item_count = ItemCount() _oscheck(carbon.PasteboardGetItemCount(self.pasteboard, byref(item_count))) item_id = PasteboardItemID() flavor_type_array = CFArrayRef() flavor_data = CFDataRef() for item_index in range(1, item_count.value + 1): # get pasteboard item _oscheck(carbon.PasteboardGetItemIdentifier(self.pasteboard, item_index, byref(item_id))) # get pasteboard item flavor type array _oscheck(carbon.PasteboardCopyItemFlavors(self.pasteboard, item_id, byref(flavor_type_array))) flavor_count = carbon.CFArrayGetCount(flavor_type_array) try: # Look for UTF-16 value first for flavor_index in range(flavor_count): flavor_type = carbon.CFArrayGetValueAtIndex( flavor_type_array, flavor_index) if carbon.UTTypeConformsTo(flavor_type, utf16_plain_text): # get flavor data _oscheck(carbon.PasteboardCopyItemFlavorData( self.pasteboard, item_id, flavor_type, byref(flavor_data))) try: data = carbon.CFDataGetBytePtr(flavor_data) length = carbon.CFDataGetLength(flavor_data) s = str(data[:length]) if sys.byteorder == 'big': return s.decode('utf_16_be') else: return s.decode('utf_16_le') # explicit endian avoids BOM finally: carbon.CFRelease (flavor_data) # Look for TEXT value if no UTF-16 value for flavor_index in range(flavor_count): flavor_type = carbon.CFArrayGetValueAtIndex( flavor_type_array, flavor_index) if carbon.UTTypeConformsTo(flavor_type, traditional_mac_plain_text): # get flavor data _oscheck(carbon.PasteboardCopyItemFlavorData( self.pasteboard, item_id, flavor_type, byref(flavor_data))) try: data = carbon.CFDataGetBytePtr(flavor_data) length = carbon.CFDataGetLength(flavor_data) return str(data[:length]) finally: carbon.CFRelease (flavor_data) finally: carbon.CFRelease(flavor_type_array) return None
def get_buffer(self, bytes): '''Fill and return an OpenAL buffer''' frames = ctypes.c_uint(bytes / self.bytes_per_frame) flags = ctypes.c_uint() buffer = (ctypes.c_byte * bytes)() audio_buffer_list = AudioBufferList() audio_buffer_list.mNumberBuffers = 1 audio_buffer_list.mBuffers[0].mNumberChannels = self.channels audio_buffer_list.mBuffers[0].mDataByteSize = bytes audio_buffer_list.mBuffers[0].mData = \ ctypes.cast(buffer, ctypes.c_void_p) result = quicktime.MovieAudioExtractionFillBuffer( self.extraction_session_ref, ctypes.byref(frames), ctypes.byref(audio_buffer_list), ctypes.byref(flags)) _oscheck(result) if frames.value == 0: return None size = audio_buffer_list.mBuffers[0].mDataByteSize albuffer = openal.buffer_pool.get(self.time) al.alBufferData(albuffer, self.format, audio_buffer_list.mBuffers[0].mData, size, int(self.sample_rate)) self.time += self.seconds_per_byte * size return albuffer
def add_font_data(cls, data): container = c_void_p() r = carbon.ATSFontActivateFromMemory(data, len(data), kATSFontContextLocal, kATSFontFormatUnspecified, None, 0, byref(container)) _oscheck(r)
def _tablet_event(self, ev): '''Process tablet event and return True if some event was processed. Return True if no tablet event found. ''' event_type = ctypes.c_uint32() r = carbon.GetEventParameter(ev, kEventParamTabletEventType, typeUInt32, None, ctypes.sizeof(event_type), None, ctypes.byref(event_type)) if r != noErr: return False if event_type.value == kEventTabletProximity: proximity_rec = TabletProximityRec() _oscheck( carbon.GetEventParameter(ev, kEventParamTabletProximityRec, typeTabletProximityRec, None, ctypes.sizeof(proximity_rec), None, ctypes.byref(proximity_rec))) print( proximity_rec.vendorID, proximity_rec.tabletID, proximity_rec.pointerID, proximity_rec.deviceID, proximity_rec.systemTabletID, proximity_rec.vendorPointerType, proximity_rec.pointerSerialNumber, proximity_rec.uniqueID, proximity_rec.capabilityMask, 't', proximity_rec.pointerType, proximity_rec.enterProximity, ) if event_type.value == kEventTabletPoint: point_rec = TabletPointRec() _oscheck( carbon.GetEventParameter(ev, kEventParamTabletPointRec, typeTabletPointRec, None, ctypes.sizeof(point_rec), None, ctypes.byref(point_rec))) print( point_rec.absX, point_rec.absY, point_rec.absZ, point_rec.buttons, point_rec.pressure, point_rec.tiltX, point_rec.tiltY, point_rec.rotation, point_rec.tangentialPressure, point_rec.deviceID, point_rec.vendor1, point_rec.vendor2, point_rec.vendor3, ) return True
def _tablet_event(self, ev): '''Process tablet event and return True if some event was processed. Return True if no tablet event found. ''' event_type = ctypes.c_uint32() r = carbon.GetEventParameter(ev, kEventParamTabletEventType, typeUInt32, None, ctypes.sizeof(event_type), None, ctypes.byref(event_type)) if r != noErr: return False if event_type.value == kEventTabletProximity: proximity_rec = TabletProximityRec() _oscheck( carbon.GetEventParameter(ev, kEventParamTabletProximityRec, typeTabletProximityRec, None, ctypes.sizeof(proximity_rec), None, ctypes.byref(proximity_rec)) ) print (proximity_rec.vendorID, proximity_rec.tabletID, proximity_rec.pointerID, proximity_rec.deviceID, proximity_rec.systemTabletID, proximity_rec.vendorPointerType, proximity_rec.pointerSerialNumber, proximity_rec.uniqueID, proximity_rec.capabilityMask, 't', proximity_rec.pointerType, proximity_rec.enterProximity, ) if event_type.value == kEventTabletPoint: point_rec = TabletPointRec() _oscheck( carbon.GetEventParameter(ev, kEventParamTabletPointRec, typeTabletPointRec, None, ctypes.sizeof(point_rec), None, ctypes.byref(point_rec)) ) print (point_rec.absX, point_rec.absY, point_rec.absZ, point_rec.buttons, point_rec.pressure, point_rec.tiltX, point_rec.tiltY, point_rec.rotation, point_rec.tangentialPressure, point_rec.deviceID, point_rec.vendor1, point_rec.vendor2, point_rec.vendor3, ) return True
def set_layout_attributes(layout, attributes): if attributes: # attributes is a dict of ATSUAttributeTag => ctypes value tags, values = list(zip(*list(attributes.items()))) tags = (c_int * len(tags))(*tags) sizes = (c_uint * len(values))(*[sizeof(v) for v in values]) values = (c_void_p * len(values))(*[cast(pointer(v), c_void_p) \ for v in values]) r = carbon.ATSUSetLayoutControls(layout, len(tags), tags, sizes, values) _oscheck(r)
def __init__(self, sound, medium): self._medium = medium self._movie = medium.movie self.sound = sound # Get CGL context and pixel format (10.4 only) agl_context = gl.get_current_context()._context agl_pixelformat = gl.get_current_context()._pixelformat cgl_context = ctypes.c_void_p() agl.aglGetCGLContext(agl_context, ctypes.byref(cgl_context)) cgl_pixelformat = ctypes.c_void_p() agl.aglGetCGLPixelFormat( agl_pixelformat, ctypes.byref(cgl_pixelformat)) # No attributes on texture contexts, only pixel buffer, according to # apple docs ref'd in class docstring. textureContextAttributes = None self.context = ctypes.c_void_p() r = quicktime.QTOpenGLTextureContextCreate( None, cgl_context, cgl_pixelformat, textureContextAttributes, ctypes.byref(self.context)) _oscheck(r) if textureContextAttributes: quicktime.CFRelease(textureContextAttributes) # Get dimensions of video rect = Rect() quicktime.GetMovieBox(self._movie, ctypes.byref(rect)) self.width = rect.right - rect.left self.height = rect.bottom - rect.top # Set to null before setting real context to disassocate from # automatically created gworld. quicktime.SetMovieVisualContext(self._movie, None) quicktime.SetMovieVisualContext(self._movie, self.context) # Dummy texture object to hold id and target of textures returned by # corevideo. XXX need to cleanup texture data after first frame # retrieved. self._texture = image.Texture.create_for_size(GL_TEXTURE_2D, self.width, self.height) self._last_cv_image = None
def _layout_callback(self, operation, line, ref, extra, callback_status): records = c_void_p() n_records = c_uint() r = carbon.ATSUDirectGetLayoutDataArrayPtrFromLineRef( line, kATSUDirectDataLayoutRecordATSLayoutRecordVersion1, 0, byref(records), byref(n_records)) _oscheck(r) records = cast(records, POINTER(ATSLayoutRecord * n_records.value)).contents self._glyph_advance = fix2float(records[-1].realPos) callback_status.contents = kATSULayoutOperationCallbackStatusContinue return 0
def _setup_post_event_handler(self): # Handler for PYGL events (interrupt from post_event) # TODO remove later? application_target = carbon.GetApplicationEventTarget() self._post_event_target = ctypes.c_void_p(application_target) proc = EventHandlerProcPtr(self._post_event_handler) self._proc = proc upp = carbon.NewEventHandlerUPP(proc) event_types = types.EventTypeSpec() event_types.eventClass = POST_EVENT_CLASS event_types.eventKind = POST_EVENT_KIND handler_ref = types.EventHandlerRef() _oscheck( carbon.InstallEventHandler(application_target, upp, 1, ctypes.byref(event_types), ctypes.c_void_p(), ctypes.byref(handler_ref)))
def _layout_callback(self, operation, line, ref, extra, callback_status): records = c_void_p() n_records = c_uint() r = carbon.ATSUDirectGetLayoutDataArrayPtrFromLineRef(line, kATSUDirectDataLayoutRecordATSLayoutRecordVersion1, 0, byref(records), byref(n_records)) _oscheck(r) records = cast(records, POINTER(ATSLayoutRecord * n_records.value)).contents self._glyph_advance = fix2float(records[-1].realPos) callback_status.contents = kATSULayoutOperationCallbackStatusContinue return 0
def _playMovie(self, timestamp): if not timestamp: quicktime.GoToBeginningOfMovie(self.medium.movie) elif timestamp > self._duration: quicktime.SetMovieTimeValue(self.medium.movie, self._duration) else: quicktime.SetMovieTimeValue(self.medium.movie, timestamp) # now force redraw and processing of first frame result = quicktime.GetMoviesError() if result == noErr: # force redraw result = quicktime.UpdateMovie(self.medium.movie) if result == noErr: # process movie quicktime.MoviesTask(self.medium.movie, 0) result = quicktime.GetMoviesError() _oscheck(result)
def dispatch_events(self): ''' draw to the texture ''' if self._seek_to is not None: ts = int(self._seek_to * self.medium._time_scale) self._seek_to = None quicktime.SetMovieTimeValue(self.medium.movie, ts) # play the movie quicktime.MoviesTask(self.medium.movie, 0) _oscheck(quicktime.GetMoviesError()) self.finished = quicktime.IsMovieDone(self.medium.movie) if self.finished: # examples nudge one last time to make sure last frame is drawn self._playMovie(quicktime.GetMovieTime(self.medium.movie, 0)) # copy to the texture texture = self.texture glBindTexture(texture.target, texture.id) self._image.blit_to_texture(texture.target, 0, 0, 0, 0)
def _setup_post_event_handler(self): # Handler for PYGL events (interrupt from post_event) # TODO remove later? application_target = carbon.GetApplicationEventTarget() self._post_event_target = ctypes.c_void_p(application_target) proc = EventHandlerProcPtr(self._post_event_handler) self._proc = proc upp = carbon.NewEventHandlerUPP(proc) event_types = types.EventTypeSpec() event_types.eventClass = POST_EVENT_CLASS event_types.eventKind = POST_EVENT_KIND handler_ref = types.EventHandlerRef() _oscheck( carbon.InstallEventHandler(application_target, upp, 1, ctypes.byref(event_types), ctypes.c_void_p(), ctypes.byref(handler_ref)) )
def post_event(self, dispatcher, event, *args): self._post_event_queue.put((dispatcher, event, args)) if not self._running: return event_class = POST_EVENT_CLASS event_kind = POST_EVENT_KIND event_ref = ctypes.c_void_p() _oscheck( carbon.CreateEvent(None, event_class, event_kind, 0, kEventAttributeUserEvent, ctypes.byref(event_ref)) ) _oscheck( carbon.SetEventParameter(event_ref, kEventParamPostTarget, typeEventTargetRef, ctypes.sizeof(ctypes.c_void_p), ctypes.byref(self._post_event_target)) ) _oscheck( carbon.PostEventToQueue(self._event_queue, event_ref, kEventPriorityStandard) ) carbon.ReleaseEvent(event_ref)
def _get_data_ref(self, file, filename): self._data_hold = data = create_string_buffer(file.read()) dataref = carbon.NewHandle(sizeof(PointerDataRefRecord)) datarec = cast(dataref, POINTER( POINTER(PointerDataRefRecord))).contents.contents datarec.data = addressof(data) datarec.dataLength = len(data) self._data_handler_holder = data_handler = ComponentInstance() r = quicktime.OpenADataHandler(dataref, PointerDataHandlerSubType, None, 0, None, kDataHCanRead, byref(data_handler)) _oscheck(r) extension_handle = Handle() self._filename_hold = filename = Str255(filename) r = carbon.PtrToHand(filename, byref(extension_handle), len(filename)) r = quicktime.DataHSetDataRefExtension(data_handler, extension_handle, kDataRefExtensionFileName) _oscheck(r) quicktime.DisposeHandle(extension_handle) quicktime.DisposeHandle(dataref) dataref = c_void_p() r = quicktime.DataHGetDataRef(data_handler, byref(dataref)) _oscheck(r) quicktime.CloseComponent(data_handler) return dataref
def _get_data_ref(self, file, filename): self._data_hold = data = create_string_buffer(file.read()) dataref = carbon.NewHandle(sizeof(PointerDataRefRecord)) datarec = cast(dataref, POINTER(POINTER(PointerDataRefRecord))).contents.contents datarec.data = addressof(data) datarec.dataLength = len(data) self._data_handler_holder = data_handler = ComponentInstance() r = quicktime.OpenADataHandler(dataref, PointerDataHandlerSubType, None, 0, None, kDataHCanRead, byref(data_handler)) _oscheck(r) extension_handle = Handle() self._filename_hold = filename = Str255(filename) r = carbon.PtrToHand(filename, byref(extension_handle), len(filename)) r = quicktime.DataHSetDataRefExtension(data_handler, extension_handle, kDataRefExtensionFileName) _oscheck(r) quicktime.DisposeHandle(extension_handle) quicktime.DisposeHandle(dataref) dataref = c_void_p() r = quicktime.DataHGetDataRef(data_handler, byref(dataref)) _oscheck(r) quicktime.CloseComponent(data_handler) return dataref
def __init__(self, movie): self.extraction_session_ref = ctypes.c_void_p() result = quicktime.MovieAudioExtractionBegin( movie, 0, ctypes.byref(self.extraction_session_ref)) _oscheck(result) asbd = AudioStreamBasicDescription() result = quicktime.MovieAudioExtractionGetProperty( self.extraction_session_ref, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, ctypes.sizeof(asbd), ctypes.byref(asbd), None) _oscheck(result) self.channels = asbd.mChannelsPerFrame self.sample_rate = asbd.mSampleRate if not self.channels or not self.sample_rate: raise MediaException('No audio in media file') # Always signed 16-bit interleaved asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | \ kAudioFormatFlagIsPacked | \ kAudioFormatFlagsNativeEndian asbd.mBitsPerChannel = 16 asbd.mBytesPerFrame = 2 * asbd.mChannelsPerFrame asbd.mBytesPerPacket = asbd.mBytesPerFrame self.bytes_per_frame = asbd.mBytesPerFrame # For calculating timestamps self.seconds_per_byte = 1. / self.sample_rate / self.channels / 2 self.time = 0. result = quicktime.MovieAudioExtractionSetProperty( self.extraction_session_ref, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, ctypes.sizeof(asbd), ctypes.byref(asbd)); _oscheck(result) if self.channels == 1: self.format = al.AL_FORMAT_MONO16 elif self.channels == 2: self.format = al.AL_FORMAT_STEREO16 else: raise NotImplementedError('not mono or stereo')
def put_text(self, text): if not text: return # clear pasteboard _oscheck(carbon.PasteboardClear(self.pasteboard)) sync_flags = carbon.PasteboardSynchronize(self.pasteboard) if sync_flags & kPasteboardModified: raise ValueError("Pasteboard not synchronized after clear") if not sync_flags & kPasteboardClientIsOwner: raise ValueError("Pasteboard not owned after clear") if sys.byteorder == 'big': utf16_data = text.encode('utf_16_be') else: utf16_data = text.encode('utf_16_le') # explicit endian avoids BOM data_ref = carbon.CFDataCreate(None, utf16_data, len(utf16_data)) if not data_ref: raise ValueError("Can't create unicode data for pasteboard") # put unicode to pasteboard try: _oscheck( carbon.PasteboardPutItemFlavor(self.pasteboard, 1, utf16_plain_text, data_ref, 0)) finally: carbon.CFRelease(data_ref) ascii_data = text.encode('ascii', 'replace') data_ref = carbon.CFDataCreate(None, ascii_data, len(ascii_data)) if not data_ref: raise ValueError("Can't create text data for pasteboard") # put text to pasteboard try: _oscheck( carbon.PasteboardPutItemFlavor(self.pasteboard, 1, traditional_mac_plain_text, data_ref, 0)) finally: carbon.CFRelease(data_ref)
def set_text(self, text, name = 'PRIMARY'): if not text: return # clear pasteboard _oscheck(carbon.PasteboardClear(self.pasteboard)) sync_flags = carbon.PasteboardSynchronize(self.pasteboard) if sync_flags & kPasteboardModified: raise ValueError, "Pasteboard not synchronized after clear" if not sync_flags & kPasteboardClientIsOwner: raise ValueError, "Pasteboard not owned after clear" if sys.byteorder == 'big': utf16_data = text.encode('utf_16_be') else: utf16_data = text.encode('utf_16_le') # explicit endian avoids BOM data_ref = carbon.CFDataCreate(None, utf16_data, len(utf16_data)) if not data_ref: raise ValueError, "Can't create unicode data for pasteboard" # put unicode to pasteboard try: _oscheck(carbon.PasteboardPutItemFlavor(self.pasteboard, 1, utf16_plain_text, data_ref, 0)) finally: carbon.CFRelease(data_ref) ascii_data = text.encode('ascii', 'replace') data_ref = carbon.CFDataCreate(None, ascii_data, len(ascii_data)) if not data_ref: raise ValueError, "Can't create text data for pasteboard" # put text to pasteboard try: _oscheck(carbon.PasteboardPutItemFlavor(self.pasteboard, 1, traditional_mac_plain_text, data_ref, 0)) finally: carbon.CFRelease(data_ref)
def get_text(self): # get pasteboard item count item_count = ItemCount() _oscheck( carbon.PasteboardGetItemCount(self.pasteboard, byref(item_count))) item_id = PasteboardItemID() flavor_type_array = CFArrayRef() flavor_data = CFDataRef() for item_index in range(1, item_count.value + 1): # get pasteboard item _oscheck( carbon.PasteboardGetItemIdentifier(self.pasteboard, item_index, byref(item_id))) # get pasteboard item flavor type array _oscheck( carbon.PasteboardCopyItemFlavors(self.pasteboard, item_id, byref(flavor_type_array))) flavor_count = carbon.CFArrayGetCount(flavor_type_array) try: # Look for UTF-16 value first for flavor_index in range(flavor_count): flavor_type = carbon.CFArrayGetValueAtIndex( flavor_type_array, flavor_index) if carbon.UTTypeConformsTo(flavor_type, utf16_plain_text): # get flavor data _oscheck( carbon.PasteboardCopyItemFlavorData( self.pasteboard, item_id, flavor_type, byref(flavor_data))) try: data = carbon.CFDataGetBytePtr(flavor_data) length = carbon.CFDataGetLength(flavor_data) s = str(data[:length]) if sys.byteorder == 'big': return s.decode('utf_16_be') else: return s.decode( 'utf_16_le') # explicit endian avoids BOM finally: carbon.CFRelease(flavor_data) # Look for TEXT value if no UTF-16 value for flavor_index in range(flavor_count): flavor_type = carbon.CFArrayGetValueAtIndex( flavor_type_array, flavor_index) if carbon.UTTypeConformsTo(flavor_type, traditional_mac_plain_text): # get flavor data _oscheck( carbon.PasteboardCopyItemFlavorData( self.pasteboard, item_id, flavor_type, byref(flavor_data))) try: data = carbon.CFDataGetBytePtr(flavor_data) length = carbon.CFDataGetLength(flavor_data) return str(data[:length]) finally: carbon.CFRelease(flavor_data) finally: carbon.CFRelease(flavor_type_array) return None
def decode_animation(self, file, filename): # TODO: Stop playing chicken with the GC # TODO: Cleanup in errors quicktime.EnterMovies() data_ref = self._get_data_ref(file, filename) if not data_ref: raise ImageDecodeException(filename or file) movie = c_void_p() id = c_short() result = quicktime.NewMovieFromDataRef(byref(movie), newMovieActive, 0, data_ref, PointerDataHandlerSubType) if not movie: #_oscheck(result) raise ImageDecodeException(filename or file) quicktime.GoToBeginningOfMovie(movie) time_scale = float(quicktime.GetMovieTimeScale(movie)) format, qtformat = self._get_formats() # Get movie width and height rect = Rect() quicktime.GetMovieBox(movie, byref(rect)) width = rect.right height = rect.bottom pitch = len(format) * width # Set gworld buffer = (c_byte * (width * height * len(format)))() world = GWorldPtr() quicktime.QTNewGWorldFromPtr(byref(world), qtformat, byref(rect), c_void_p(), c_void_p(), 0, buffer, len(format) * width) quicktime.SetGWorld(world, 0) quicktime.SetMovieGWorld(movie, world, 0) visual = quicktime.GetMovieIndTrackType(movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic) if not visual: raise ImageDecodeException('No video track') time = 0 interesting_time = c_int() quicktime.GetTrackNextInterestingTime( visual, nextTimeMediaSample, time, 1, byref(interesting_time), None) duration = interesting_time.value / time_scale frames = [] while time >= 0: result = quicktime.GetMoviesError() if result == noErr: # force redraw result = quicktime.UpdateMovie(movie) if result == noErr: # process movie quicktime.MoviesTask(movie, 0) result = quicktime.GetMoviesError() _oscheck(result) buffer_copy = (c_byte * len(buffer))() memmove(buffer_copy, buffer, len(buffer)) image = ImageData(width, height, format, buffer_copy, -pitch) frames.append(AnimationFrame(image, duration)) interesting_time = c_int() duration = c_int() quicktime.GetTrackNextInterestingTime( visual, nextTimeMediaSample, time, 1, byref(interesting_time), byref(duration)) quicktime.SetMovieTimeValue(movie, interesting_time) time = interesting_time.value duration = duration.value / time_scale if duration <= 0.01: duration = 0.1 quicktime.DisposeMovie(movie) carbon.DisposeHandle(data_ref) quicktime.ExitMovies() return Animation(frames)
def decode_animation(self, file, filename): # TODO: Stop playing chicken with the GC # TODO: Cleanup in errors quicktime.EnterMovies() data_ref = self._get_data_ref(file, filename) if not data_ref: raise ImageDecodeException(filename or file) movie = c_void_p() id = c_short() result = quicktime.NewMovieFromDataRef(byref(movie), newMovieActive, 0, data_ref, PointerDataHandlerSubType) if not movie: #_oscheck(result) raise ImageDecodeException(filename or file) quicktime.GoToBeginningOfMovie(movie) time_scale = float(quicktime.GetMovieTimeScale(movie)) format, qtformat = self._get_formats() # Get movie width and height rect = Rect() quicktime.GetMovieBox(movie, byref(rect)) width = rect.right height = rect.bottom pitch = len(format) * width # Set gworld buffer = (c_byte * (width * height * len(format)))() world = GWorldPtr() quicktime.QTNewGWorldFromPtr(byref(world), qtformat, byref(rect), c_void_p(), c_void_p(), 0, buffer, len(format) * width) quicktime.SetGWorld(world, 0) quicktime.SetMovieGWorld(movie, world, 0) visual = quicktime.GetMovieIndTrackType(movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic) if not visual: raise ImageDecodeException('No video track') time = 0 interesting_time = c_int() quicktime.GetTrackNextInterestingTime(visual, nextTimeMediaSample, time, 1, byref(interesting_time), None) duration = interesting_time.value / time_scale frames = [] while time >= 0: result = quicktime.GetMoviesError() if result == noErr: # force redraw result = quicktime.UpdateMovie(movie) if result == noErr: # process movie quicktime.MoviesTask(movie, 0) result = quicktime.GetMoviesError() _oscheck(result) buffer_copy = (c_byte * len(buffer))() memmove(buffer_copy, buffer, len(buffer)) image = ImageData(width, height, format, buffer_copy, -pitch) frames.append(AnimationFrame(image, duration)) interesting_time = c_int() duration = c_int() quicktime.GetTrackNextInterestingTime(visual, nextTimeMediaSample, time, 1, byref(interesting_time), byref(duration)) quicktime.SetMovieTimeValue(movie, interesting_time) time = interesting_time.value duration = duration.value / time_scale if duration <= 0.01: duration = 0.1 quicktime.DisposeMovie(movie) carbon.DisposeHandle(data_ref) quicktime.ExitMovies() return Animation(frames)
import sys import time from pyglet.window.carbon import _create_cfstring, _oscheck from pyglet.window.carbon import carbon from pyglet.window.carbon import quicktime quicktime.EnterMovies() filename = sys.argv[1] filename = _create_cfstring(filename) data_ref = ctypes.c_void_p() data_ref_type = ctypes.c_ulong() result = quicktime.QTNewDataReferenceFromFullPathCFString( filename, -1, 0, ctypes.byref(data_ref), ctypes.byref(data_ref_type)) _oscheck(result) sound = ctypes.c_void_p() fileid = ctypes.c_short(0) quicktime.NewMovieFromDataRef.argtypes = (ctypes.POINTER(ctypes.c_void_p), ctypes.c_short, ctypes.POINTER(ctypes.c_short), ctypes.c_void_p, ctypes.c_ulong) newMovieActive = 1 result = quicktime.NewMovieFromDataRef(ctypes.byref(sound), newMovieActive, ctypes.byref(fileid), data_ref, data_ref_type) _oscheck(result)
import sys import time from pyglet.window.carbon import _create_cfstring, _oscheck from pyglet.window.carbon import carbon from pyglet.window.carbon import quicktime quicktime.EnterMovies() filename = sys.argv[1] filename = _create_cfstring(filename) data_ref = ctypes.c_void_p() data_ref_type = ctypes.c_ulong() result = quicktime.QTNewDataReferenceFromFullPathCFString(filename, -1, 0, ctypes.byref(data_ref), ctypes.byref(data_ref_type)) _oscheck(result) sound = ctypes.c_void_p() fileid = ctypes.c_short(0) quicktime.NewMovieFromDataRef.argtypes = ( ctypes.POINTER(ctypes.c_void_p), ctypes.c_short, ctypes.POINTER(ctypes.c_short), ctypes.c_void_p, ctypes.c_ulong) newMovieActive = 1 result = quicktime.NewMovieFromDataRef(ctypes.byref(sound), newMovieActive, ctypes.byref(fileid), data_ref, data_ref_type) _oscheck(result)
def __init__(self, medium): self.medium = medium self._duration = quicktime.GetMovieDuration(medium.movie) if corevideo is not None: _oscheck(quicktime.InitializeQTML(0)) _oscheck(quicktime.EnterMovies()) # determine dimensions of video r = Rect() quicktime.GetMovieBox(medium.movie, ctypes.byref(r)) # save off current GWorld origDevice = ctypes.c_void_p() origPort = ctypes.c_void_p() quicktime.GetGWorld(ctypes.byref(origPort), ctypes.byref(origDevice)) # fix the rect if necessary self.width = r.right - r.left self.height = r.bottom - r.top self.rect = Rect(0, 0, self.height, self.width) # TODO sanity check size? QT can scale for us self.texture = image.Texture.create_for_size(image.GL_TEXTURE_2D, self.width, self.height, GL_RGB) if (self.texture.width != self.width or self.texture.height != self.height): self.texture = self.texture.get_region( 0, 0, self.width, self.height) # Flip texture coords as a cheap way of flipping image. gst_openal # does the same, so if you fix this, fix Windows too. bl, br, tr, tl = self.texture.tex_coords self.texture.tex_coords = tl, tr, br, bl if sys.byteorder == 'big': format = 'ARGB' qtformat = k32ARGBPixelFormat else: format = 'BGRA' qtformat = k32BGRAPixelFormat # create "graphics world" for QT to render to buf = quicktime.NewPtrClear(4 * self.width * self.height) self.buffer_type = c_char * (4 * self.width * self.height) self.gworld = ctypes.c_void_p() #GWorldPtr() result = quicktime.QTNewGWorldFromPtr(ctypes.byref(self.gworld), qtformat, ctypes.byref(self.rect), 0, 0, 0, buf, 4*self.width) _oscheck(result) assert self.gworld != 0, 'Could not allocate GWorld' quicktime.SetGWorld(self.gworld, 0) quicktime.SetMovieGWorld(medium.movie, self.gworld, 0) # pull out the buffer address and row stride from the pixmap # (just in case...) pixmap = quicktime.GetGWorldPixMap(self.gworld) assert pixmap != 0, 'Could not GetGWorldPixMap' if not quicktime.LockPixels(pixmap): raise ValueError, 'Could not lock PixMap' self.gp_buffer = quicktime.GetPixBaseAddr(pixmap) self.gp_row_stride = quicktime.GetPixRowBytes(pixmap) self.gp_buffer = cast(self.gp_buffer, POINTER(c_char * (self.gp_row_stride * self.height))).contents # use ImageData to swizzle the ARGB data self._image = image.ImageData(self.width, self.height, format, self.gp_buffer) # restore old GWorld quicktime.SetGWorld(origPort, origDevice) # make sure we're at the start quicktime.GoToBeginningOfMovie(self.medium.movie)
def dispatch_events(self): ''' draw to the texture ''' if self._seek_to is not None: ts = int(self._seek_to * self._medium._time_scale) self._seek_to = None quicktime.SetMovieTimeValue(self._movie, ts) quicktime.MoviesTask(self._movie, 0) _oscheck(quicktime.GetMoviesError()) self.finished = quicktime.IsMovieDone(self._movie) ts = quicktime.GetMovieTime(self._movie, 0) if self.finished: # examples nudge one last time to make sure last frame is drawn quicktime.SetMovieTimeValue(self._movie, ts) quicktime.QTVisualContextTask(self.context) # TODO get corevideo timestamp from qt timestamp. "None" means "right # now", so potential problems with audio sync (though maybe not) cvts = None if quicktime.QTVisualContextIsNewImageAvailable(self.context, cvts): cv_image = ctypes.c_void_p() r = quicktime.QTVisualContextCopyImageForTime(self.context, None, cvts, ctypes.byref(cv_image)) _oscheck(r) # free up the last frame if self._last_cv_image is not None: corevideo.CVOpenGLTextureRelease(self._last_cv_image) # grab the new frame self._last_cv_image = cv_image self._texture.target = corevideo.CVOpenGLTextureGetTarget(cv_image) self._texture.id = corevideo.CVOpenGLTextureGetName(cv_image) # XXX probably optimisable into a single array with some trickery bottom_left = (GLfloat * 2)() bottom_right = (GLfloat * 2)() top_right = (GLfloat * 2)() top_left = (GLfloat * 2)() corevideo.CVOpenGLTextureGetCleanTexCoords(cv_image, ctypes.byref(bottom_left), ctypes.byref(bottom_right), ctypes.byref(top_right), ctypes.byref(top_left)) self._texture.tex_coords = ( (bottom_left[0], bottom_left[1], 0), (bottom_right[0], bottom_right[1], 0), (top_right[0], top_right[1], 0), (top_left[0], top_left[1], 0)) # If we want the texture width and height to be correct... pyglet # media API doesn't specify glBindTexture(self._texture.target, self._texture.id) width = GLint() glGetTexLevelParameteriv(self._texture.target, 0, GL_TEXTURE_WIDTH, ctypes.byref(width)) height = GLint() glGetTexLevelParameteriv(self._texture.target, 0, GL_TEXTURE_HEIGHT, ctypes.byref(height)) self._texture.width = width.value self._texture.height = height.value
def _create_movie(self): if self.file is not None: raise NotImplementedError('TODO: file object loading') filename = _create_cfstring(self.filename) movie = Movie() if corevideo is None or True: # corevideo: set visualcontext to nil, then to the texture # context -- avoids having to use FromProperties. fileid = ctypes.c_short(0) data_ref = ctypes.c_void_p() data_ref_type = ctypes.c_ulong() result = quicktime.QTNewDataReferenceFromFullPathCFString(filename, -1, 0, ctypes.byref(data_ref), ctypes.byref(data_ref_type)) _oscheck(result) result = quicktime.NewMovieFromDataRef( ctypes.byref(movie), newMovieActive, ctypes.byref(fileid), data_ref, data_ref_type) if result == -2048: return None _oscheck(result) else: # use newer QT7 API true = Boolean(1) filePathRef = CFStringRef() filePathRef.value = filename # XXX this really wants the context passed to it - and there's # really not reason not to AFAICT. We pass a NULL context so that # it's not set up using the default GWorld. no_context = c_void_p(0) properties = (QTNewMoviePropertyElement * 5)( (kQTPropertyClass_DataLocation, kQTDataLocationPropertyID_CFStringPosixPath, ctypes.sizeof(filePathRef), ctypes.cast(ctypes.pointer(filePathRef), ctypes.c_void_p), 0), (kQTPropertyClass_Context, kQTContextPropertyID_VisualContext, ctypes.sizeof(c_void_p), ctypes.cast(ctypes.pointer(no_context), ctypes.c_void_p), 0), (kQTPropertyClass_NewMovieProperty, kQTNewMoviePropertyID_Active, ctypes.sizeof(Boolean), ctypes.cast(ctypes.pointer(true), ctypes.c_void_p), 0), (kQTPropertyClass_NewMovieProperty, kQTNewMoviePropertyID_DontInteractWithUser, ctypes.sizeof(Boolean), ctypes.cast(ctypes.pointer(true), ctypes.c_void_p), 0), (kQTPropertyClass_MovieInstantiation, kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs, ctypes.sizeof(Boolean), ctypes.cast(ctypes.pointer(true), ctypes.c_void_p), 0), ) quicktime.NewMovieFromProperties(len(properties), properties, 0, None, ctypes.byref(movie)) carbon.CFRelease(filename) return movie