Using video

We will now load a video as a texture in Three.js. Again, no `video` tag to help us, so we will use the same workaround as previously for images, and use EVG textures.

We will try to load the given resource as an EVG texture, and if this fails we try to load the resource as a filter. This implies:

- your filter will now accept video inputs
- you will have to relink input PIDs to sources

The first thing to do is accept incoming raw video for your filter, typically in initialize():
```
filter.initialize = function()
{
  //we accept and produce raw video streams
  this.set_cap({id: "StreamType", value: "Video", inout: true} );
  this.set_cap({id: "CodecID", value: "raw", inout: true} );

  //declare output PID
}
```

The check if loading an image fails:

```
    try {
      img.load(img.src, true);
      if (img.on_load != null)
        img.on_load({});
    } catch (e) {
      print('Loading as filter ' + img.src);
      load_src_as_filter(img);
    }
```

We now need to load a source filter for this URL:

```

function load_src_as_filter(img)
{
  //no associated PID
  img.pid = null;

  //make the EVG texture a named texture
  img.set_named("map");
  //no need to recompute shaders yet
  img.recompute_shaders = false;

  //load a source filter
  img._src_filter = filter.add_source(img.src);
  if (!img._src_filter) return;

  //indicate we want our filter to connect to PIDs coming from the source
  filter.set_source(img._src_filter);

  //remember our EVG texture and notify the load callback
  sources.push(img);
  if (img.on_load)
    img.on_load({});
}
```

The first important thing here is that we make our EVG texture a named texture, so that pixel conversion to RGBA is done in the shader. As with WebGL, this means that the shader will have to be recompiled once the pixel format and frame size of the source is known.  
The name `map` chosen is the name used by the sampler2D in most material shaders of Three.js. 

_Note_
You don't have to use named textures if you know that the input is in RGB/RGBA format (or a format requiring a single texture in openGL), but named texture will always work whether the source is in YUV or RGB format.

The second important thing is that we call right away the load callback to trick Three.js into believing the texture is OK. This means that we need a valid texture at this point, so in the texture construction we will create the texture a a dummy 2x2 RGB one:

```
  let img = new evg.Texture(2, 2, 'rgb', new ArrayBuffer(2*2*3));
```

If we call the Three.js callback after updating the texture, we will likely have complaints about "texture too big" for Three.js.


We now need to grab frames from the source. We first need to catch PID connections:

```
function get_source_by_pid(pid)
{
  let res = null;
  sources.forEach( img => { 
    if (pid.is_filter_in_parents(img._src_filter)) {
      res = img;
      return;
    }
  } );
  return res;
}


filter.configure_pid = function(pid)
{
  if (!sources.length) return GF_FILTER_NOT_SUPPORTED;
  let img = get_source_by_pid(pid);
  if (!img) return GF_BAD_PARAM;

  //first connection
  if (!img.pid) {
      img.pid = pid;
      print('PID connected');
      //start playback at 60 sec into content
      let evt = new FilterEvent(GF_FEVT_PLAY);
      evt.start_range = 60.0;
      pid.send_event(evt);
  }
  //we need to recompute shaders after the first upload - a clean code should check if width/height/pixformat have changed, if not no need to reconfigure
  img.recompute_shaders = true;
}
```

Now the input PID is associated to the EVG texture, we just need to update the texture in the filter `process` function:

```
  //browse all sources, and update packets 
  let pids=[];
  if (sources.length) {
    let img = sources[0];
    if (img.pid) {
      let pck = img.pid.get_packet();
      if (pck) {
        //update texture
        img.update(pck);
        //remember to release packet once drawn
        //we cannot release right now as the packet may be using openGL textures, which could then be discarded before render()
        pids.push(img.pid);
        //first packet seen, recompute our shaders - here we just create a new material on our only textured object, the cube
        if (img.recompute_shaders) {
          img.recompute_shaders = false;
          cube.material = new THREE.MeshBasicMaterial({ map: texture });
        }
      }
    }
  }
```

And that's it. You will also need to cleanup your packets once no longer used, e.g. after `render()`:

```
  pids.forEach( pid => { pid.drop_packet(); });
```

In this example,  we assume the source is 25fps just like our filter, but you may decide otherwise and not trash a packet at each generated frame.


The complete code for this example is [here](examples/three/ex4.js).