import urllib2 import socket import pygame from pygame.locals import * import cStringIO import sys import wave import struct ServerAddr = '192.168.1.13' UserName = 'admin' Password = 'admin' AudioUrl = 'http://' + ServerAddr + '/cgi/audio/audio.cgi' VideoUrl = 'http://' + ServerAddr + '/cgi/mjpg/mjpeg.cgi' # Passing the username and password with the URL doesn't seem to work, so setup a password manager passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, ServerAddr, UserName, Password) authhandler = urllib2.HTTPBasicAuthHandler(passman) opener = urllib2.build_opener(authhandler) urllib2.install_opener(opener) class ScreenHelper: screen = None fullScreen = True windowedRes = (640, 480) fullScreenRes = windowedRes curScreenRes = windowedRes def __init__(self): pygame.display.set_caption('CamViewer') # If the current screen res is a fullscreen mode, set our fullscreen res to that info = pygame.display.Info() if (info.current_w, info.current_h) in pygame.display.list_modes(): self.fullScreenRes = (info.current_w, info.current_h) self.toggleFullscreen() def toggleFullscreen(self): if self.fullScreen: self.screen = pygame.display.set_mode(self.windowedRes) self.curScreenRes = self.windowedRes self.fullScreen = False else: self.screen = pygame.display.set_mode(self.fullScreenRes, pygame.FULLSCREEN) self.curScreenRes = self.fullScreenRes self.fullScreen = True def blit(self, surface): offset = (0, 0) # If the surface doesn't match our res, scale it, maintaining aspect ratio if surface.get_size() != self.curScreenRes: widthRatio = float(self.curScreenRes[0]) / float(surface.get_width()) heightRatio = float(self.curScreenRes[1]) / float(surface.get_height()) scaledSize = None if widthRatio > heightRatio: scaledSize = (int(surface.get_width() * heightRatio), int(surface.get_height() * heightRatio)) offset = ((self.curScreenRes[0] - scaledSize[0]) / 2, 0) else: scaledSize = (int(surface.get_width() * widthRatio), int(surface.get_height() * widthRatio)) offset = (0, (self.curScreenRes[1] - scaledSize[1]) / 2) surface = pygame.transform.smoothscale(surface, scaledSize) # Blit the surface and update the display self.screen.blit(surface, offset) pygame.display.update() # Reads a chunk of data from an Airlink camera http stream class CamDataChunk: frame = 0 size = 0 tag1 = 0 time = 0 unknown1 = 0 tag2 = 0 unknown2 = 0 data = '' def read(self, stream): try: boundaryStr = stream.readline().decode() if boundaryStr != '--myboundary\r\n': print('Bad boundary: ' + boundaryStr) return False lengthStr = stream.readline().decode() if not lengthStr.startswith('Content-Length: '): print('Bad length: ' + lengthStr) return False length = int(lengthStr.strip().split()[1]) emptyStr = stream.readline() #print('Good frame, length %d' % length) dataLeft = length chunkData = '' while dataLeft > 0: data = stream.read(dataLeft) amtRead = len(data) dataLeft -= amtRead if amtRead == 0: print('Ran out of data') return False chunkData += data headerSize = 28 # Header format: # int ~synched, +1 per frame # int data size? varies jpg, constant audio # int J000 for JPG, A000 for wav # int ~synched, +1 per sec? # int ??? # int constant (0x00990201 video, 0x12d20700 audio) # int constant (0 both) chunkHeader = struct.unpack('iiiiiii', chunkData[:headerSize]) self.frame = chunkHeader[0] self.size = chunkHeader[1] self.tag1 = chunkHeader[2] self.time = chunkHeader[3] self.unknown1 = chunkHeader[4] self.tag2 = chunkHeader[5] self.unknown2 = chunkHeader[6] self.data = chunkData[headerSize:] return True except socket.error, (errno, strerror): print "Socket error(%s): %s" % (errno, strerror) return False def play(screen): videoStream = urllib2.urlopen(VideoUrl) #audioStream = urllib2.urlopen(AudioUrl) videoChunk = CamDataChunk() #audioChunk = CamDataChunk() while True: for event in pygame.event.get(): if event.type == QUIT: return if event.type == pygame.KEYDOWN: if event.key == K_f: screen.toggleFullscreen() elif event.key == K_ESCAPE: return if videoChunk.read(videoStream) == False: print 'Bad video chunk' return #if audioChunk.read(audioStream) == False: # print 'Bad audio chunk' # return # Display the current frame frameSurface = pygame.image.load(cStringIO.StringIO(videoChunk.data)).convert() screen.blit(frameSurface) # Play the current audio sample #soundObj = pygame.mixer.Sound(waveFile.getvalue()) #soundObj.play() pygame.init() screen = ScreenHelper() play(screen) pygame.display.quit()