def readPacket(self, header, input): channel = self.channels.get(header[0]) if channel is None: header_size = header[2] if header_size < self.read_chunk_size: return self.processBody(header, input.read(header_size)) buffer = BytesOutput(True) buffer.write(input.read(self.read_chunk_size)) self.channels[header[0]] = [ header, buffer, header_size - self.read_chunk_size ] else: channel_header = channel[0] if header[1] != channel_header[1]: raise Exception, "Timestamp Changed" if header[4] != channel_header[4]: raise Exception, "Stream Id Changed" if header[3] != channel_header[3]: raise Exception, "Type Changed" if header[2] != channel_header[2]: raise Exception, "Size Changed" if channel[2] > self.read_chunk_size: channel[1].write(input.read(self.read_chunk_size)) channel[2] -= self.read_chunk_size else: channel[1].write(input.read(channel[2])) del self.channels[header[0]] return self.processBody(channel[0], channel[1].getBytes()) return None
def readPacket(self, header, input): channel = self.channels.get(header[0]) if channel is None: header_size = header[2] if header_size < self.read_chunk_size: return self.processBody(header, input.read(header_size)) buffer = BytesOutput(True) buffer.write(input.read(self.read_chunk_size)) self.channels[header[0]] = [header, buffer, header_size - self.read_chunk_size] else: channel_header = channel[0] if header[1] != channel_header[1]: raise Exception, "Timestamp Changed" if header[4] != channel_header[4]: raise Exception, "Stream Id Changed" if header[3] != channel_header[3]: raise Exception, "Type Changed" if header[2] != channel_header[2]: raise Exception, "Size Changed" if channel[2] > self.read_chunk_size: channel[1].write(input.read(self.read_chunk_size)) channel[2] -= self.read_chunk_size else: channel[1].write(input.read(channel[2])) del self.channels[header[0]] return self.processBody(channel[0], channel[1].getBytes()) return None
def makeHandshakeResponse(handshake): flash_plugin_version = unpack(">I", handshake[4:8])[0] #scheme = SCHEMES.get(flash_plugin_version, 0) scheme = validateClient(handshake) print "scheme", scheme handshake = prepareHandshake(handshake, scheme) output = BytesOutput(True) output.writeByte(0x03) output.write(makeHandshakePart1(handshake, scheme)) output.write(makeHandshakePart2(handshake, scheme)) return output.getBytes()
def makeHandshakeResponse(handshake): flash_plugin_version = unpack(">I", handshake[4:8])[0] #scheme = SCHEMES.get(flash_plugin_version, 0) scheme = validateClient(handshake) print "scheme", scheme handshake = prepareHandshake(handshake, scheme); output = BytesOutput(True) output.writeByte(0x03) output.write(makeHandshakePart1(handshake, scheme)) output.write(makeHandshakePart2(handshake, scheme)) return output.getBytes()
def getVideoFrame(self, index, ref_time): try: time, type, offset, size, keyframe, composition_time = self.info.frames[index] except: return None if type != FRAME_TYPE_VIDEO: return None data = BytesOutput(True) data.write(self.getFrameHeader(type, keyframe, False, (time - ref_time) + composition_time)) self.file.seek(offset, 0) data.write(self.file.read(size)) self.video_count += 1 return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_VIDEO, data.getBytes()), 0, None)
def getVideoFrame(self, index, ref_time): try: time, type, offset, size, keyframe, composition_time = self.info.frames[ index] except: return None if type != FRAME_TYPE_VIDEO: return None data = BytesOutput(True) data.write( self.getFrameHeader(type, keyframe, False, (time - ref_time) + composition_time)) self.file.seek(offset, 0) data.write(self.file.read(size)) self.video_count += 1 return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_VIDEO, data.getBytes()), 0, None)
def getFrame(self): try: time, type, offset, size, keyframe, composition_time = self.info.frames[ self.index] except: return None output = BytesOutput(True) first = False if (type == FRAME_TYPE_VIDEO): if (self.video_count == 0): first = True rtmp_type = Rtmp.RTMP_TYPE_VIDEO self.video_count += 1 elif (type == FRAME_TYPE_AUDIO): if (self.audio_count < 2): first = True rtmp_type = Rtmp.RTMP_TYPE_AUDIO self.audio_count += 1 stream_id = None if first: output.write(self.getDescription(type, (time == 0))) stream_id = self.id data = BytesOutput(True) data.write(self.getFrameHeader(type, keyframe, False, composition_time)) self.file.seek(offset, 0) data.write(self.file.read(size)) timestamp = time - self.base_time output.write( self.rtmp.make(self.channel, (rtmp_type, data.getBytes()), timestamp, stream_id)) self.index += 1 self.base_time = time return (time, output.getBytes())
def getDescription(self, type, first_time = False): data = BytesOutput(True) data.write(self.getFrameHeader(type, True, True)) if type == FRAME_TYPE_VIDEO: data.write(self.info.descriptions[0]) return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_VIDEO, data.getBytes()), 0, (None, self.id)[first_time]) elif type == FRAME_TYPE_AUDIO: data.write(self.info.descriptions[1]) return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_AUDIO, data.getBytes()), 0, (None, self.id)[first_time]) else: return None
def getFrame(self): try: time, type, offset, size, keyframe, composition_time = self.info.frames[self.index] except: return None output = BytesOutput(True) first = False if (type == FRAME_TYPE_VIDEO): if (self.video_count == 0): first = True rtmp_type = Rtmp.RTMP_TYPE_VIDEO self.video_count += 1 elif (type == FRAME_TYPE_AUDIO): if (self.audio_count < 2): first = True rtmp_type = Rtmp.RTMP_TYPE_AUDIO self.audio_count += 1 stream_id = None if first: output.write(self.getDescription(type, (time == 0))) stream_id = self.id data = BytesOutput(True) data.write(self.getFrameHeader(type, keyframe, False, composition_time)) self.file.seek(offset, 0) data.write(self.file.read(size)) timestamp = time - self.base_time output.write(self.rtmp.make(self.channel, (rtmp_type, data.getBytes()), timestamp, stream_id)) self.index += 1 self.base_time = time return (time, output.getBytes())
def getDescription(self, type, first_time=False): data = BytesOutput(True) data.write(self.getFrameHeader(type, True, True)) if type == FRAME_TYPE_VIDEO: data.write(self.info.descriptions[0]) return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_VIDEO, data.getBytes()), 0, (None, self.id)[first_time]) elif type == FRAME_TYPE_AUDIO: data.write(self.info.descriptions[1]) return self.rtmp.make(self.channel, (Rtmp.RTMP_TYPE_AUDIO, data.getBytes()), 0, (None, self.id)[first_time]) else: return None
def make(self, channel_id, packet, timestamp=0, stream_id=0): type = packet[0] header = [channel_id, timestamp, None, type, stream_id] data = BytesOutput(True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: data.writeUInt(packet[1]) # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: data.writeUInt(packet[1]) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control_stream_id, control = packet[1] control_type = control[0] value1 = None value2 = None # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: pass # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: pass # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: value1 = control[1] # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: pass # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: value1 = control[1] # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: value1 = control[1] # Unknown elif control_type == RTMP_CONTROL_UNKNOWN: control_type = control[1] value1 = control[2] value2 = control[3] data.writeUInt16(control_type) data.writeUInt(control_stream_id) if value1 is not None: data.writeUInt(value1) if value2 is not None: data.writeUInt(value2) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: data.writeUInt(0x002625A0) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: data.writeUInt(0x002625A0) data.writeByte(0x02) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: data.write(packet[1]) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: data.write(packet[1]) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: data.writeString(packet[1]) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: name, id, args = packet[1] Amf.write(data, (3, name)) #Command name Amf.write(data, (1, id)) #Command id for arg in args: # Args (Amf Values) Amf.write(data, arg) # Unknown elif type == RTMP_TYPE_UNKNOWN: type, body = packet[1] header[4] = type data.write(body) # Other else: header[4] = None data = data.getBytes() length = len(data) header[2] = length output = BytesOutput(True) output.write(self.makeHeader(header)) if length > 0: pos = self.write_chunk_size if length <= pos: output.write(data) else: output.write(buffer(data, 0, pos)) length -= pos while length > 0: output.writeByte(header[0] | (headerSizeToByte(1) << 6)) n = (length, self.write_chunk_size)[length > self.write_chunk_size] output.write(buffer(data, pos, n)) pos += n length -= n return output.getBytes()
def make(self, channel_id, packet, timestamp = 0, stream_id = 0): type = packet[0] header = [channel_id, timestamp, None, type, stream_id] data = BytesOutput(True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: data.writeUInt(packet[1]) # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: data.writeUInt(packet[1]) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control_stream_id, control = packet[1] control_type = control[0] value1 = None value2 = None # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: pass # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: pass # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: value1 = control[1] # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: pass # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: value1 = control[1] # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: value1 = control[1] # Unknown elif control_type == RTMP_CONTROL_UNKNOWN: control_type = control[1] value1 = control[2] value2 = control[3] data.writeUInt16(control_type) data.writeUInt(control_stream_id) if value1 is not None: data.writeUInt(value1) if value2 is not None: data.writeUInt(value2) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: data.writeUInt(0x002625A0) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: data.writeUInt(0x002625A0) data.writeByte(0x02) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: data.write(packet[1]) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: data.write(packet[1]) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: data.writeString(packet[1]) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: name, id, args = packet[1] Amf.write(data, (3, name)) #Command name Amf.write(data, (1, id)) #Command id for arg in args: # Args (Amf Values) Amf.write(data, arg) # Unknown elif type == RTMP_TYPE_UNKNOWN: type, body = packet[1] header[4] = type data.write(body) # Other else: header[4] = None data = data.getBytes() length = len(data) header[2] = length output = BytesOutput(True) output.write(self.makeHeader(header)) if length > 0: pos = self.write_chunk_size if length <= pos: output.write(data) else: output.write(buffer(data, 0, pos)) length -= pos while length > 0: output.writeByte(header[0] | (headerSizeToByte(1) << 6)) n = (length, self.write_chunk_size)[length > self.write_chunk_size] output.write(buffer(data, pos, n)) pos += n length -= n return output.getBytes()