def writeDuration(self, duration): if self._debug: print('writing duration', duration) output = amf.AMFBytesIO() amfWriter = amf.AMF0(output) # TODO: use AMF3 if needed amfWriter.write('onMetaData') amfWriter.write( {"duration": duration, "videocodecid": 7, "audiocodecid": 10}) output.seek(0) data = output.read() length, ts = len(data), 0 data = struct.pack( '>BBHBHB', Message.DATA, (length >> 16) & 0xff, length & 0x0ffff, (ts >> 16) & 0xff, ts & 0x0ffff, (ts >> 24) & 0xff) + b'\x00\x00\x00' + data data += struct.pack('>I', len(data)) lastpos = self.fp.tell() if lastpos != 13: self.fp.seek(13, os.SEEK_SET) self.fp.write(data) if lastpos != 13: self.fp.seek(lastpos, os.SEEK_SET)
def fromMessage(cls, message): ''' initialize from a parsed RTMP message''' assert (message.type in [Message.RPC, Message.RPC3, Message.DATA, Message.DATA3]) length = len(message.data) if length == 0: raise ValueError('zero length message data') if message.type == Message.RPC3 or message.type == Message.DATA3: assert message.data[0] == b'\x00' # must be 0 in AMF3 data = message.data[1:] else: data = message.data #from pyamf import remoting amfReader = amf.AMF0(data) inst = cls() inst.type = message.type inst.time = message.time inst.name = amfReader.read() # first field is command name try: if message.type == Message.RPC or message.type == Message.RPC3: inst.id = amfReader.read() # second field *may* be message id inst.cmdData = amfReader.read() # third is command data else: inst.id = 0 inst.args = [] # others are optional while True: inst.args.append(amfReader.read()) # amfReader.read()) except EOFError: pass return inst
def writeDuration(self, duration): if self._debug: print("writing duration", duration) output = amf.AMFBytesIO() amfWriter = amf.AMF0(output) # TODO: use AMF3 if needed amfWriter.write("onMetaData") amfWriter.write({ "duration": duration, "videocodecid": 7, "audiocodecid": 10 }) output.seek(0) data = output.read() length, ts = len(data), 0 data = (struct.pack( ">BBHBHB", Message.DATA, (length >> 16) & 0xFF, length & 0x0FFFF, (ts >> 16) & 0xFF, ts & 0x0FFFF, (ts >> 24) & 0xFF, ) + b"\x00\x00\x00" + data) data += struct.pack(">I", len(data)) lastpos = self.fp.tell() if lastpos != 13: self.fp.seek(13, os.SEEK_SET) self.fp.write(data) if lastpos != 13: self.fp.seek(lastpos, os.SEEK_SET)
def toMessage(self): msg = Message() assert self.type msg.type = self.type msg.time = self.time output = amf.AMFBytesIO() amfWriter = amf.AMF0(output) amfWriter.write(self.name) if msg.type == Message.RPC or msg.type == Message.RPC3: amfWriter.write(self.id) amfWriter.write(self.cmdData) for arg in self.args: amfWriter.write(arg) output.seek(0) # hexdump.hexdump(output) # output.seek(0) if msg.type == Message.RPC3 or msg.type == Message.DATA3: data = b'\x00' + output.read() else: data = output.read() msg.data = data output.close() return msg
def reader(self, stream): '''A generator to periodically read the file and dispatch them to the stream. The supplied stream object must have a send(Message) method and id and client properties.''' if self._debug: print('reader started') yield try: while self.fp is not None: bytes = self.fp.read(11) if len(bytes) == 0: try: tm = stream.client.relativeTime except BaseException: tm = 0 response = Command( name='onStatus', id=stream.id, tm=tm, args=[ amf.Object( level='status', code='NetStream.Play.Stop', description='File ended', details=None)]) yield stream.send(response.toMessage()) break type, len0, len1, ts0, ts1, ts2, sid0, sid1 = struct.unpack( '>BBHBHBBH', bytes) length = (len0 << 16) | len1 ts = (ts0 << 16) | (ts1 & 0x0ffff) | (ts2 << 24) body = self.fp.read(length) ptagsize, = struct.unpack('>I', self.fp.read(4)) if ptagsize != (length + 11): if self._debug: print( 'invalid previous tag-size found:', ptagsize, '!=', (length + 11), 'ignored.') if stream is None or stream.client is None: break # if it is closed #hdr = Header(3 if type == Message.AUDIO else 4, ts if ts < 0xffffff else 0xffffff, length, type, stream.id) hdr = Header(0, ts, length, type, stream.id) msg = Message(hdr, body) # if self._debug: print 'FLV.read() length=', length, 'hdr=', hdr # if hdr.type == Message.AUDIO: print 'r', hdr.type, hdr.time if type == Message.DATA: # metadata amfReader = amf.AMF0(body) # TODO: use AMF3 if needed name = amfReader.read() obj = amfReader.read() if self._debug: print('FLV.read()', name, repr(obj)) yield stream.send(msg) if ts > self.tsp: diff, self.tsp = ts - self.tsp, ts if self._debug: print('FLV.read() sleep', diff) yield multitask.sleep(diff / 1000.0) except StopIteration: pass except BaseException: if self._debug: print('closing the reader', (sys and sys.exc_info() or None)) if self.fp is not None: try: self.fp.close() except BaseException: pass self.fp = None