class Frame(object): """Basic frame object, all other frametypes extend from this.""" _buffer = None length = None @property def view(self): """view() -> memoryview Returns a memoryview of the frame's data. """ return self._buffer.view() def bytes(self): """bytes() -> bytearray() Returns a copy of the frame's data. """ return self._buffer.bytes() def __eq__(self, other): if isinstance(other, Frame): return self._buffer == other._buffer else: return self._buffer == other def _frame_assembled(self): """Implement this method if you need to do sth. as soon as the frames buffer is available.""" pass def append(self, buf): """append(buf) -> nothing Append data from buf to this frame, up to the frame's length. Expects a ZeroCopyBuffer as input. """ self._buffer = ZeroCopyBuffer(self.length) buf.delete(self._buffer.extend(buf)) if (len(self._buffer) < self.length): assert(len(buf) == 0) self._buffer.fill(buf._fileobj, completely=True) assert(len(self._buffer) == self.length) self._frame_assembled()
def append(self, buf): """append(buf) -> nothing Append data from buf to this frame, up to the frame's length. Expects a ZeroCopyBuffer as input. """ self._buffer = ZeroCopyBuffer(self.length) buf.delete(self._buffer.extend(buf)) if (len(self._buffer) < self.length): assert(len(buf) == 0) self._buffer.fill(buf._fileobj, completely=True) assert(len(self._buffer) == self.length) self._frame_assembled()
def frames(self, skip_invalid_data = True, emit_meta_frames = True, \ emit_riff_frames = True, emit_id3_frames = True, emit_ape_frames = True): """frames(skip_invalid_data = True, emit_meta_frames = True, \ emit_riff_frames = True, emit_id3_frames = True, emit_ape_frames = True) -> frame data Reads frames one-by-one, according to the method's arguments. Raises an MP3Error if invalid data is encountered and ingore_invalid_data is False. """ in_sync = True try: buf = ZeroCopyBuffer(self._buffer_size, self._inobj) buf.fill() while len(buf) > 4: # We need at least 4 bytes for our shortest header # Try to parse a frame frame = None for frame_class in self._FRAME_TYPES: try: frame = frame_class(buf, self, strict=not in_sync) break except _InvalidFrame: pass if frame and not in_sync: # Recover from lost sync try: buf.fill(at_least = frame.length + 12) # See if there is a consequent valid frame for frame_class in self._FRAME_TYPES: try: frame_class(buf, self, offset=frame.length, strict=True) in_sync = True break except _InvalidFrame: pass frame = in_sync and frame or None except EOFError: # Not enough data left to check the next frame, accept it anyways pass if frame: # Consumed data is removed from the buffer in Frame.append() frame.append(buf) if (isinstance(frame, ID3Frame) and (emit_meta_frames or emit_id3_frames)) or \ (isinstance(frame, APEFrame) and (emit_meta_frames or emit_ape_frames)) or \ (isinstance(frame, RIFFFrame) and emit_riff_frames) or \ isinstance(frame, MPEGFrame): yield frame else: in_sync = False if not skip_invalid_data: raise MP3Error('encountered invalid data') buf.delete(1) if len(buf) < 12: buf.fill(self._inobj) except EOFError: if not skip_invalid_data: raise MP3Error('encountered invalid data') finally: del buf