---
title: "Video: Estructuras básicas"
---

Utilizando la biblioteca (*library*) de Video, Processing nos permite manipular video pregrabado con `Movie` y/o obtenido en vivo desde cámara web con `Capture`.

La biblioteca maneja toda la lógica para abrir y reproducir videos en el caso de `Movie`, y para manejar a la cámara web en el caso de `Capture`.

Además, cada *frame* de video nos la entrega como una imagen (`PImage`) con la cual podemos hacer cualquier manipulación como cuando trabajamos con imágenes estáticas:

* [[Imágenes: Abrir, mostrar, leer]](/notas/imagenes-read.html)
* [[Imágenes: Colores, filtros]](/notas/imagenes-colores.html)
* [[Imágenes: Capas y máscaras]](/notas/imagenes-capas.html)

# Preparación

## Instalación de la biblioteca

Para instalar la biblioteca de Video, ve al menú *Sketch -> Importar biblioteca... -> Añadir biblioteca*. En la ventana que se abre, busca Video y selecciona la opción que dice *Video | GStreamer-based video library for Processing* y tiene como autora a *The Processing Foundation*.

Haz click en esa opción, y presiona el botón *Install* para que la biblioteca se descargue e instale.

Este proceso solo hay que realizarlo una vez.

## Importar biblioteca

Para utilizar la biblioteca en nuestro sketch, podemos ir al menú *Sketch -> Importar biblioteca... -> Video*; esto agregará la siguiente línea de código:

```java
import processing.video.*;
```

Si lo prefieres puedes escribir esa línea de código directamente, en lugar de usar los menús.

## Uso de videos

Para poder utilizar videos pregrabados con `Movie`, es necesario tener **nuestro sketch de código guardado**.

En la carpeta donde se encuentra el archivo *.pde* de nuestro sketch hay que crear una carpeta llamada *data*, y ahí es donde hemos de colocar los videos que queremos utilizar.

Por ejemplo, si guardamos nuestro sketch dentro de la carpeta *sketchbook* con el nombre *estudioVideos*, hay que colocar nuestros videos en la carpeta *sketchbook/estudioVideos/data*.

### Consideraciones

Toma en cuenta que para fines de *sketching*, y dependiendo de tu equipo computacional, puede convenir trabajar provisionalmente con archivos de video de baja resolución y/o calidad. Esto permitirá que tu sketch cargue más rápido al ejecutarlo.

También, podría suceder que si tu programa realiza operaciones muy intensivas computacionalmente en cada frame, el *frame rate* podría reducirse, en especial manipulando video en vivo.

Si la prioridad es la ejecución en vivo puedes bajar la resolución y/o calidad, y si la prioridad es el resultado del procesamiento entonces puedes guardar cada *frame* con `saveFrame("frames/frame-####.png");` y después ensamblarlas en un video.

## Uso de cámara web

El uso de cámara web con `Capture` funciona sin problema en GNU/Linux y Windows.

Para versiones recientes de Mac OS X, al parecer hay que realizar el siguiente procedimiento:

[Video Library 2.0 - MacOS Mojave / Catalina Issues](http://wiki.iad.zhdk.ch/CV/904626177/Video+Library+2.0#VideoLibrary2.0-MacOSMojave/CatalinaIssues)

(por confirmar)


# Movie: Videos pregrabados

La clase `Movie` maneja videos pregrabados. Con ella podemos cargar videos, iniciar o detener su avance, obtener datos temporales, etc. 

## Estructura básica

Este sketch muestra la estructura básica para utilizarla:

```java
// estructura básica para cargar y reproducir video

// agrega 'library' de Video
import processing.video.*;

// variable de clase Movie
Movie video;

void setup(){
  size(640, 360);
  // crea objeto de clase Movie, cargando video
  video = new Movie(this, "epilogue.mp4");
  
  // reproduce video una vez
  video.play();
  // reproduce video en loop:
  // video.loop();
}

void draw(){
 // revisa si hay una nueva frame de video:
 if( video.available() ){
  // lee la frame hacia video
  video.read(); 
  // realiza aquí dentro operaciones como redimensiones, recortes y máscaras
 }
 
 // dibuja la frame de video:
 image(video, 0, 0);
}
```

Nota las similitudes y diferencias con el uso de `PImage`.

La principal diferencia aquí es el condicional con el método `.available()`, que carga en nuestro programa cada *frame* de video únicamente cuando está listo. Esto se debe a que el *frameRate* de reproducción de video y el *frameRate* de ejecución del sketch puede variar o desfasarse un poco.

## Evento `movieEvent( )`

En lugar del condicional podemos usar la función `movieEvent( )` que se llama cada vez que hay alguna actualización en la lectura del video.

El sketch anterior quedaría de la siguiente forma:

```java
// estructura básica para cargar video con movieEvent()

// agrega 'library' de Video
import processing.video.*;

// variable de clase Movie
Movie video;

void setup(){
  size(640, 360);
  // crea objeto de clase Movie, cargando video
  video = new Movie(this, "epilogue.mp4");
  
  // reproduce video una vez
  video.play();
  // reproduce video en loop:
  // video.loop();
}

void draw(){
 // dibuja la frame de video:
 image(video, 0, 0);
}

void movieEvent(Movie v){
 // lee la frame de video
 v.read(); 
 // realiza aquí dentro operaciones como redimensiones, recortes y máscaras
}
```

## Métodos

La clase `Movie` tiene más métodos para controlar la reproducción del video:

* `.play()`
* `.pause()`
* `.stop()`
* `.loop()` y `.noLoop()`
* `.jump( t )`: para saltar a cierto momento `t` en el video (en segundos)
* `.speed( s )`: cambia la velocidad relativa de reproducción: 1.0 es normal, 2.0 es el doble de rápido, 0.5 es la mitad, etc.
* `.frameRate( f )`: cambia el *frameRate* de reproducción del video
* `.time()`: indica en qué ubicación temporal del video se encuentra la reproducción
* `.duration()`: regresa la duración del video en segundos

Encuentra más detalles sobre ellos en la referencia de la biblioteca:

[Video \ Libraries \ Processing.org](https://processing.org/reference/libraries/video/index.html)

## Ejemplos

### Recortes

Este ejemplo recorta e intercambia de lugar las mitades horizontales del video cargado.

Nota cómo los recortes se realizan justo después de que se lee cada *frame* del video (`.read()`), y en el ciclo `draw()` únicamente se dibujan.

```java
// este ejemplo recorta e intercambia las mitades horizontales del video

// agrega 'library' de Video
import processing.video.*;

// variable de clase Movie
Movie video;

// variables para los recortes
PImage mitad1, mitad2;

void setup(){
  size(640, 360);
  // crea objeto de clase Movie, cargando video
  video = new Movie(this, "epilogue.mp4");
  
  // crea los objetos de clase PImage para recortes
  mitad1 = createImage(width/2, height, RGB);
  mitad2 = createImage(width/2, height, RGB);
  
  // reproduce video en loop:
  video.loop();
}

void draw(){
 // dibuja las mitades en posiciones intercambiadas
 // mitad izquierda dibujada a la derecha:
 image(mitad1, width/2, 0);
 // mitad derecha dibujada a la izquierda
 image(mitad2, 0, 0);
}

void movieEvent(Movie v){
 // lee la frame de video
 v.read(); 
 // redimensiona frame al tamaño del canvas
 v.resize(width, height);
 // obtén la mitad izquierda 
 mitad1 = v.get(0, 0, v.width/2, v.height);
 // obtén la mitad derecha
 mitad2 = v.get(width/2, 0, v.width/2, v.height);
}
```

# Capture: Cámara(s) web

La clase `Capture` maneja cámaras web. Con ella podemos escoger entre cámaras, asignar alguna resolución, encenderla o apagarla. 

## Estructura básica

Este sketch muestra la estructura básica para utilizarla. Es muy parecida al uso de `Movie`, con la diferencia de que en lugar de cargar un video, hay que escoger una cámara y asignarle una resolución.

```java
// estructura básica para usar una cámara web

// importa 'library' de Video
import processing.video.*;

// variable de clase Capture
// para la cámara web
Capture cam;

void setup(){
 size(640, 480);
 
 // obtén lista de cámaras conectadas
 String[] camaras = Capture.list();
 // muestra la lista en la consola
 printArray( camaras );
 
 // crea objeto de clase Capture
 // utilizando la primera cámara
 // con resolución de 640x480
 cam = new Capture(this, 640, 480, camaras[0]);
 // enciende la cámara
 cam.start();
}

void draw(){
 // revisa si hay una nueva frame de video
 if ( cam.available() ){
   // lee la nueva frame de la cámara
   cam.read(); 
   // realiza aquí operaciones como redimensiones, recortes y máscaras
 }
 // dibuja la frame de la cámara
 image(cam, 0, 0); 
}
```

### Espejo

Nota que el video no está "espejado"; se muestra literalmente lo que ve la cámara.

Para dibujar en espejo podemos utilizar estas líneas de código con transformaciones:

```java
 scale(-1, 1); // invierte el eje X
 translate(-width, 0); // mueve esq. sup. izq. a la "derecha"
 image(cam, 0, 0);
```

Lo que sucede aquí es que primero el eje X se invierte. Luego se traslada el origen `width` pixeles a "la izquierda" (porque es negativo), pero como el eje X está invertido esto se traduce en trasladar el origen `width` pixeles a "la derecha" del canvas. 

De esta forma, lo que era la esquina superior izquierda de la imagen ahora queda en la esquina superior derecha del canvas, todo en espejo.

[[Transformaciones]](/notas/transformaciones.html)

## Evento `captureEvent( )`

Al igual que con `movieEvent( )` (ver arriba), aquí un equivalente que se llama con cada nueva frame de la cámara web. 

La estructura básica quedaría así:

```java
// estructura básica para usar una cámara web con captureEvent

// importa 'library' de Video
import processing.video.*;

// variable de clase Capture
// para la cámara web
Capture cam;

void setup(){
 size(640, 480);
 
 // obtén lista de cámaras conectadas
 String[] camaras = Capture.list();
 // muestra la lista en la consola
 printArray( camaras );
 
 // crea objeto de clase Capture
 // utilizando la primera cámara
 // con resolución de 640x480
 cam = new Capture(this, 640, 480, camaras[0]);
 // enciende la cámara
 cam.start();
}

void draw(){
 // dibuja la frame de la cámara
 image(cam, 0, 0); 
}

void captureEvent( Capture c ){
 // lee la nueva frame de la cámara
 c.read(); 
 // realiza aquí operaciones como redimensiones, recortes y máscaras
}
```

## Ejemplos

### Recortes

Similar al ejemplo de arriba con `Movie`, este programa recorta e intercambia de lugar las mitades horizontales del video proveniente de la cámara web.

```java
// este ejemplo recorta e intercambia las mitades horizontales del video de la cámara

// agrega 'library' de Video
import processing.video.*;

// variable de clase Capture
// para la cámara web
Capture cam;

// variables para los recortes
PImage mitad1, mitad2;

void setup(){
  size(640, 480);
  
  // crea los objetos de clase PImage para recortes
  mitad1 = createImage(width/2, height, RGB);
  mitad2 = createImage(width/2, height, RGB);

  // obtén lista de cámaras conectadas
  String[] camaras = Capture.list();
  // muestra la lista en la consola
  printArray( camaras );
 
  // crea objeto de clase Capture
  // utilizando la primera cámara
  // con resolución de 640x480
  cam = new Capture(this, 640, 480, camaras[0]);
  // enciende la cámara
  cam.start();
}

void draw(){
 // "espejea" video
 scale(-1, 1); // invierte el eje X
 translate(-width, 0); // mueve esq. sup. izq. a la "derecha"

 // dibuja las mitades en posiciones intercambiadas
 // mitad izquierda dibujada a la derecha:
 image(mitad1, width/2, 0);
 // mitad derecha dibujada a la izquierda
 image(mitad2, 0, 0);
}

void captureEvent(Capture c){
 // lee la frame de video de la cámara
 c.read(); 
 // redimensiona frame al tamaño del canvas
 //c.resize(width, height);
 // obtén la mitad izquierda 
 mitad1 = c.get(0, 0, c.width/2, c.height);
 // obtén la mitad derecha
 mitad2 = c.get(width/2, 0, c.width/2, c.height);
}
```
