Monday, March 5, 2012

sshot2frame - send screenshots to photoframe at video speed

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# Program: sshot2frame
#
# This screenshot-to-frame program takes a screenshot from your desktop
# and sends it to the  'Samsung SPF-87H Digital Photo Frame'
#
# This can be done at frame rates of 20+ fps so that it is even possible
# to watch video on the frame, when video is playing on the desktop!
# (tested with mythtv)
#
# It is an extension of the pyframe_basic program found here:
#    http://pyframe.blogspot.com/2011/12/pyframebasic-program_15.html
# Read that post to understand details not commented here
# Copyright (C) ullix

import sys
import struct
import usb.core

# additional imports are required
from PyQt4 import QtGui, QtCore
import Image
import StringIO
import time

device = "SPF87H Mini Monitor"
dev = usb.core.find(idVendor=0x04e8, idProduct=0x2034)

if dev is None:
    print "Could not find", device, " - using screen\n"
    frame = False
else:
    frame = True
    print "Found", device
    dev.ctrl_transfer(0xc0, 4 )  


# Must have a QApplication running to use the other pyqt4 functions
app  = QtGui.QApplication(sys.argv)

# Enter into a loop to repeatedly take screenshots and send them to the frame
start  = time.time()
frames = 0
while True:
    # take a screenshot and store into a pixmap
    pmap = QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop().winId())
   
    # if you want a screenshot from only a subset of your desktop, you can define it like this
    #pmap = QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop().winId(), x=0, y= 600, width=800, height=480)

    # next line is needed only when screenshot does not yet have the proper dimensions for the frame
    # note that distortion will result when aspect ratios of desktop and frame are different!
    # if not needed then inactivate to save cpu cycles
    pmap = pmap.scaled(800,480)
   
    # if desired, save the pixmap into a jpg file on disk. Not required here
    #pmap.save(filename , 'jpeg')

    # create a buffer object and store the pixmap in it as if it were a jpeg file   
    buffer = QtCore.QBuffer()
    buffer.open(QtCore.QIODevice.WriteOnly)
    pmap.save(buffer, 'jpeg')
   
    # now get the just saved "file" data into a string, which we will send to the frame
    pic = buffer.data().__str__()
   
    ######################   
    # this code within ########## is needed only to create an PIL Image object to be shown below
    # by image.show(), e.g. for debugging purposes when no frame is present
   
    #picfile = StringIO.StringIO(pic)            # stringIO creates a file in memory
    #im1=Image.open(picfile)   
    #im = im1.resize((800,480), Image.ANTIALIAS) # resizing not needed when screenshot already has the right size
                                                 # note that distortion will result when aspect ratios of desktop
                                                 # and frame are different!
    #picfile.close()
    ######################
   
    if not frame:
        # remember to activate above ########### lines if you use im.show() command
        im.show()       
    else:
        rawdata = b"\xa5\x5a\x18\x04" + struct.pack('<I', len(pic)) + b"\x48\x00\x00\x00" + pic
        pad = 16384 - (len(rawdata) % 16384)
        tdata = rawdata + pad * b'\x00'
        tdata = tdata + b'\x00'
        endpoint = 0x02
        bytes_written = dev.write(endpoint, tdata )

    frames += 1  

    # exit the while loop after some cycles, or remove code to get indefinite loop
    if frames > 100:
        break;

    # set time delay between screenshots in seconds. The frame can handle some 20+fps,
    # so 0.1sec (i.e. max of 10fps) is ok for the frame but possibly too fast for a slow cpu
    #time.sleep(0.1)
   
runtime = time.time() -start
print "Frames per second: {0:0.2f}".format( frames / runtime)      

No comments:

Post a Comment