reading video from USB memory (unplug/reinster causes issues

Currently running on Windows 7, but intended to be used in Ubuntu.

I’m not sure how to clear video files stored in USB stick when USB memory is removed and play again when reinserted.

from panda3d.core import *
import direct.directbase.DirectStart
from direct.task import Task
import os

# scan the F drive each 1 second and update media files if removed, modified and reinserted
fileIndex = 0
isPlaying = False

files = []
supportedFormats = ('avi', 'mp4', 'mpg', 'wmv', 'mov', 'mpeg')

# model to play videos on
model = loader.loadModel("box")
model.reparentTo(aspect2d)
model.setP(90)

def filesUpdateTask(task):
	global files
	global isPlaying
	
	files = [] # rescan
	try: # try to get list of supported video files in the root folder of the USB memory and play first one (for testing)
		filenames = os.listdir('f:/')
		
		for filename in filenames:
			for i in supportedFormats:
				if filename.lower().endswith(i):
					files.append(filename)
		print files
		
		if isPlaying == False:
			# play video
			texture = loader.loadTexture("/f/"+files[0]) # for now
			model.setTexture(texture, 1)
			texture.play()
			
			isPlaying = True
			
	except: # USB not connected or disconnected by user
		files = []
		isPlaying = False
		model.clearTexture()
		
	
	return task.again
	
taskMgr.doMethodLater(1, filesUpdateTask, 'filesUpdateTask')
filesUpdateTask(Task)


run()

When I reinsert, only the first frame is displayed this time, not the whole video. Maybe some cache has to be cleared?

This is for my spherical display project, I want the user to be able to see the video file in the USB memory as soon as it is plugged in and not crash if he unplugs halfway through. It doesnt crash now but when reinsterting only first frame is shown.

Are the textures perhaps named the same, and Panda is refusing to reload them because of the texture cache? If so, you should unloadTexture() the texture when you are done with it.

You can also use TexturePool.releaseAllTextures() whenever you plug-in/unplug the USB drive to make sure all textures have to be reloaded.

If I do TexturePool.releaseAllTextures() and then reinsert the USB stick, “python.exe” has stopped working" error shows up when the code tries loading the movie file. Nothing in the console, just a bold python.exe crash.
Same with loader.unloadTexture(). Try this code:

from panda3d.core import *
import direct.directbase.DirectStart
from direct.task import Task
import os

# scan the F drive each 1 second and update media files if removed, modified and reinserted
fileIndex = 0 # index/current video changed by Arduino button
isPlaying = False

files = []
supportedFormats = ('avi', 'mp4', 'mpg', 'wmv', 'mov', 'mpeg')

# model to play videos on
model = loader.loadModel("box")
model.reparentTo(aspect2d)
model.setP(90)
texture = None

def filesUpdateTask(task):
	global files
	global isPlaying
	global texture
	
	files = [] # rescan
	try: # try to get list of supported video files in the root folder of the USB memory and play first one (for testing)
		filenames = os.listdir('f:/')
		
		for filename in filenames:
			for i in supportedFormats:
				if filename.lower().endswith(i):
					files.append(filename)
		print files
		
		if isPlaying == False:
			# play video
			texture = loader.loadTexture("/f/"+files[0]) # for now
			model.setTexture(texture, 1)
			texture.play()
			
			isPlaying = True
			
	except: # USB not connected or disconnected by user
		files = []
		isPlaying = False
		if texture != None:
			loader.unloadTexture(texture)
			texture = None
		
	
	return task.again
	
taskMgr.doMethodLater(1, filesUpdateTask, 'filesUpdateTask')
filesUpdateTask(Task)


run()

Cant even open files stored in USB in Ubuntu. Is the path in the file managers wrong or incomplete one?

/media/pc/009A-28CC

This path seems to work, but if the user uses a different usb stick, will the “009A-28CC” change? I tried asking this somewhere else but Linux users weren’t too helpful with their answers. I explained that my usb stick get automounted already and that I’m not asking help with getting them mounted, but figuring out what will be a path string to use which won’t change for the same port.

Yes, this will probably change between sticks. (It’s probably also specific to whatever automount tool / settings that’s part of Ubuntu).

It might be possible to set a custom mount point by adding an entry to /etc/fstab by UUID but you’d have to know the UUIDs of all the sticks ahead of time.

However, you could read the /etc/mtab file (it’s text-based, should be easy to parse) to get a list of all the filesystems that are currently mounted. It will include the directory that they are mounted to. You could watch for changes on that file, and parse the file, checking which volume was added and where it is mounted on disk.

Thanks.
What about just trying to do listdir() on subfolders of /media/? I don’t know what else might be stored there but right not it seems only removable drives show up there and since there’s only one port for USB available for the user I don’t think it will be a problem.

BTW, the python.exe crash caused by ffmpeg doesn’t happen on Ubuntu like it did on Windows.
But loader.unloadTexture(texture) doesn’t work, only TexturePool.releaseAllTextures().

Sure, that sounds like it could work.

It’s also possible to disable automount entirely and let mounting be managed by your application, although that seems like more work.

If it’s always on the same USB port, you can remember the PCI path and check which device path it gets like this:

devPath = os.path.realpath("/dev/disk/by-path/pci-0000:00:12.2-usb-0:4:1.0-scsi-0:0:0:0")

Then you get something like /dev/sdf, which you can either consider mounting yourself to a directory of choice (here, /mnt/), if you disable automount:

mountPath = "/mnt/"
os.system("mount %s %s" % (devPath, mountPath))

(requires permissions to have been set up properly)

Or, you can look it up in the kernel mount table to find out where automount has put it:

table = open('/proc/mounts').readlines()
for line in table:
    parts = line.split()
    if parts[0] == devPath:
        mountPath = parts[1]

Having said all that, it may just be easier to do a listdir on /media/, if that’s more convenient, even if it’s a little bit more hacky. :slight_smile:

listdir() on /media would work fine I guess in the condition that only memory drives appear there, and plugging some other USB device won’t have a folder with an executable or something along this line show up there. As you can see I’m not really experienced with Linux…
Panda is running fine on Ubuntu on the Gizmo 2 board though and not giving me any trouble.