I don't know if that's something I would handle at the VM level, probably rather an API on top of a native call mechanism in the core library.
I suppose if there is enough similarity across I/O then perhaps something could be added. I'm not familiar enough with the state of low level programming to know, and I'd lean towards minimalism unless there was a compelling reason not to.
One option would be to provide all IO operations as high level plugins or 'virtual drivers' provided by the platform runtime, similar to how one might install and configure plugins for all of the input and output plugins for video game system emulators.
What the VM would provide in a centralized manner would be a repository mapping API names to public header files.
This way, if a developer distributed a program over the internet imported a reference to 'simple-video.01' API, the end user and VM could lookup the name and pull a copy of the header API defining the calling convention directly from the VM website.
In order to run the program, they could then either find or write a 'native plugin' for their platform which implemented 'simple-video.01' API using machine code similar to a C shared object. Or, they could find or write a 'soft plugin' which translates the calls in the 'simple-video.01' API into calls to another API which their was machine code for (say, 'direct-video.51') using VM bytecode. This way the VM could automatically infer the native code necessary to generate effects, even if it was less efficient or qualitatively different depending on the needs of the end user.
For output, the headers would basically need to specify a list of tuples of primitive data types for effects. For input, the headers could perhaps specify a set of named primitive tuples, arrays, and tables which vary over time and can be directly accessed, similar to how one might access pipelined input variables in an OpenGL or Direct3D GPU shader.