Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

jueves, 23 de abril de 2020

Los Filósofos Comiendo en Java con Netbeans

Una explicación de este problema está en este enlace. Se trata de un problema de concurrencia: en una mesa circular hay cinco filósofos con cinco platos y cinco cucharas al lado derecho de cada uno. Todos deben poder comer sin fastidiar al filósofo de al lado. A su vez, cada filósofo emplea un tiempo en dejar de comer y ponerse a pensar.
Aquí los filósofos son hijos y las cucharas son recursos compartidos. En mi caso, las cucharas son accesos exclusivos a archivos compartidos.
Para evitar problemas de deadlock (un hilo no libera un recurso que otro necesita, mientras que el segundo hilo mantiene un recurso que el primero necesita...) o starvation (todos los recursos compartidos están ocupados), incluí varias reglas y sincronismos, por ejemplo que los filósofos sólo podían coger las cucharas a su izquierda (identificadas por sus índices). La mesa circular se simula jugando con los índices, el filósofo al que se le asigna el índice cero recibe la última y la primera cuchara:

La clase Spoon recibe como parámetros el índice del filósofo al que ha sido asignada, el número total de filósofos y los nombres de los archivos. La clase Philosopher recibe como parámetros dos objetos Spoon, el lugar que ocupa en la mesa (es decir su índice en el array), y su nombre. Es en esta clase donde se realizan las funciones multihilo.

Los archivos aparecerán en la carpeta del proyecto:


Nunca aparecerán más de cuatro archivos file1x.tmp por la regla que añadí: si se ocupan todas las cucharas, el filósofo debe soltarlas:


El proyecto completo se puede descargar de aquí, corre en java 8.

jueves, 12 de marzo de 2020

Evitar la edición automática de texto en Libre Office 6

Una cosa que odio es cuando un editor de texto edita automáticamente lo que escribo. Estaba listando unas rutas de linux en un archivo en Libre Office Write, y succedía que un texto como /home/user01/ me lo formateaba como homeuser01. Tenía que poner Crtl+z para deshacer lo que el editor insistía en hacer.
Rebuscando en los foros y la documentación de Libre Office, encontré que es muy fácil evitarlo, hay que ir a "Herramientas->Corrección Automática" y deseleccionar "Al escribir":


Si se quiere un control más preciso, se puede ir a "Opciones de corrección automática" y deseleccionar en la pestaña "Opciones" donde dice "Negrita, Itálica, tachado y subrayado automáticos":


Concuerdo con lo que dice alguien en este foro:
"Esto NUNCA debería ser un valor por defecto: este es el tipo de estupidez que hace que LO sea imposible de usar por nuevos usuarios.
Cuando alguien escribe algo, espera obtener lo que escribió a menos que diga lo contrario. ¡A quien se le ocurrió esta idea debería ser arrojado al río con una ruta de directorio de Unix atada al cuello! ;-)"

Yo propongo /dev/null como esa ruta de directorio Unix >:)

jueves, 20 de febrero de 2020

Ecualización del Histograma de una Imagen a Color

Otra entrada migrada de la vieja web:

Revisando mi programa para ecualizar el histograma de una imagen en blanco y negro, pensé que ya era hora de aplicar el mismo algoritmo pero para imágenes a color. El procedimiento es el mismo que el que explico aquí, pero la ecualización se aplica sobre las tres componentes de cada píxel (R,G,B). Aparte, le hice una mejora al código fuente: todo lo que es el procesamiento de la imagen está en una clase separada del código del formulario (la ventana del programa). La clase de llama "Imagen" y tiene un solo método: "EcuHistograma" que devuelve un mapa de bits con la imagen ya procesada. A continuación está el código que ecualiza el histograma para los tres planos R, G y B:


La imagen con el histograma ecualizado es:




Añadiendo Ruido Tipo Perlin


En Internet, ya no recuerdo cómo, me topé con esto:  https://flafla2.github.io/2014/08/09/perlinnoise.html. Debo admitir que en un principio fue difícil de entender la lógica detrás del Ruido de Perlin, mas después de mucho leer y revisar los seudocódigos, entendí de qué trataba todo:
1. Se tiene un píxel de una imagen con sus dos coordenadas: X e Y.

2. Se ingresan las coordenadas X e Y. A partir de esos dos valores, la función que genera el ruido de Perlin devolverá un solo valor, el cual se sumará o restará al píxel correspondientes a dichas coordenadas.

3. Es importante que para unos valores dados de X e Y, la función generadora del ruido de Perlin siempre dé como resultado el mismo valor, por ello se dice que es seudoaleatoria: inicia con ciertos valores aleatorios al inicio del algoritmo y que no vuelven a variar a menos que se vuelva a correr el algoritmo desde cero. Los números aleatorios se crean al inicio solamente. La función generadora sería totalmente aleatoria si generada un número aleatorio para cada píxel, mas siempre utiliza los mismos números.

Esto es más fácil de comprender en esta web, donde está el algoritmo del que basé mi código: http://www.sepcot.com/blog/2006/08/PDN-PerlinNoise2d. Este código está hecho para el programa Freeware escrito en C#: Paint.Net. Yo lo adapté para que funcionara de forma independiente, además le añadí una segunda función para generar ruido, basada en funciones trigonométricas. Al combinar mi función con la original, y jugar con algunas constantes, obtuve un interesante efecto de cuadraditos:



El código completo para ecualizar histogramas de imágenes a color y añadir ruido Perlin puede bajarse de aquí (para Visual Studio Express 2008).

miércoles, 22 de enero de 2020

Ecualización del Histograma de una Imagen en C#

Otra entrada migrada de la vieja web :)


Jugando con el Visual Studio Express, cogí mi anterior algoritmo en Matlab para ecualizar el histograma de una imagen y lo quise adaptar para C# (y de paso lo optimicé un poco). La función para cargar la imagen de prueba (en el evento Load del formulario) es espantosamente complicada, esto se puede mejorar usando la clase Path de System.IO (lo que se hace es cargar una imagen que esté en la misma ruta de la aplicación).


El programa (para Visual Studio 2008) se puede descargar de aquí. El algoritmo para ecualizar el histograma está dentro del evento click del ratón. Está pensado para valores negativos también, para el caso en que la imagen a ecualizar haya tenido algún tratamiento intermedio que genere valores negativos (los objetos Bitmap sólo aceptan valores entre 0 y 255). 


lunes, 20 de enero de 2020

Filtrado E Histograma De Una Imagen Para Matlab 6.5 ó 7

Otra entrada migrada de la vieja web :)


Una imagen digitalizada no es más que una matriz de números, donde cada número representa el valor de un píxel. Se diferencia de una señal digitalizada en que una señal es un vector, o varios vectores separados (como el caso de la música estéreo, compuesta por dos vectores de números que representan los canales derecho e izquierdo).

Para el procesamiento de una imagen existen varias técnicas, las cuales se usan para obtener información no visible, resaltar bordes, suavizarlos, quitar detalles irrelevantes, agrupar objetos, eliminar el fondo, etc.

Una técnica muy usada es el filtrado, el cual puede ser lineal o no lineal. El filtrado lineal es simplemente convolucionar la imagen con una matriz predefinida. (la convolución es una operación de sumas y multiplicaciones que se usa tanto en señales como en imágenes). Un filtro lineal es el "Filtro de Promedio" o "Mean Filter". Se usan para suavizar, detectar o resaltar bordes, eliminación de ruido, etc.

El filtrado no lineal se compone de técnicas más complicadas. El más básico es el Filtrado de Mediana o "Median Filter", que consiste en coger una pequeña porción de la imagen (generalmente 3x3 píxeles), evaluar el valor de los píxeles y cambiar sus valores al de aquél que tenga un valor central. Es útil para eliminar ruido impulsivo.

Otra técnica muy usada es la "Ecualización del Histograma". El Histograma de una imagen es el ploteo de los valores de sus píxeles. Una imagen en blanco tendrá todos sus valores iguales a 255, si la mitad es negra, en la gráfica del histograma aparecerán dos líneas iguales a ambos extremos: en los valores correpondientes al 0 y al 255. Una imagen de escala de grises tendrá en su histograma "x" píxeles con el valor 0, "y" píxeles con el valor 1, etc.

Así, el histograma es la representación de la densidad de probabilidad de cada valor de gris para esa imagen.

Tanto el histograma, como el histograma ecualizado, son vectores.

Ecualizar el Histograma es hacerlo lo más llano y separado posible. Esto hace que los píxeles se distribuyan más ampliamente por todo el rango de valores (del 0 al 255) y que en la imagen ecualizada se resaltarán detalles que antes no eran evidentes.

Para generar una imagen con el histograma ecualizado se requieren varios pasos:

1. Calcular el histograma de la imagen

2. Normalizar el histograma (dividirlo entre el número total de píxeles)

3. Calcular el histograma acumulado (ir sumando los píxeles desde el valor 0 al 255, esto originará una gráfica creciente)

4. Se aplica el algoritmo (como se trata de matrices, debe estar dentro de dos bucles anidados):

Para valores de la imagen original distintos de cero:
imagen_ecualizada(i,j) = histograma_acumulado(imagen_original(i,j))

Para valores de la imagen original iguales a cero:
imagen_ecualizada(i,j) = histograma_acumulado(imagen_original(i,j)+1)

Donde lo que va entre paréntesis es el índice, o índices, de cada píxel de la imagen o de cada valor del histograma. Así  "imagen_original(i,j)" viene a indicar el índice del vector del histograma acumulado correspondiente. De esta manera se le asigna a cada píxel de la imagen ecualizada (o imagen con el histograma ecualizado) la densidad de probabilidad acumulada correspondiente al valor del píxel de la imagen original.
Como este algoritmo está hecho para Matlab, y como Matlab no maneja índices iguales a cero, se considera que el histograma va de 1 a 256, en lugar de 0 a 255. Así la densidad de probabilidad del valor cero será la que está en el índice 1 en el vector del histograma.

El algoritmo que presento akí está considerado para matrices con valores tanto positivos como negativos. Es un archivo zip que incluye ejemplos de filtraje, ecualización y eliminación de ruido.

Link de donde aprendí la teoría para poder hacer esto:

http://homepages.inf.ed.ac.uk/rbf/HIPR2/filtops.htm

miércoles, 11 de diciembre de 2019

Comprimiendo y descomprimiendo archivos en formato rar en Ubuntu

Estoy usando Xubuntu 16 y necesité descomprimir un archivo rar. Luego de una intensa búsqueda de veinte segundos en google llegué a esta web donde explican cómo instalar rar y unrar y poder lidiar con este tipo de archivos. A continuación un resumen:

Ejecutar los siguientes comandos:

sudo apt-get install rar
sudo apt-get install unrar

Para descomprimir un archivo rar en la misma carpeta donde está se ejecuta el comando:

unrar x EjerciciosEjemplo.rar

Pero lo que no dice la web es que, una vez que se instala rar y unrar, el sistema ya reconoce este formato de archivos y no es necesario usar la consola ni instalar nada más. Para comprimir un archivo en formato rar basta hacerle clic derecho e ir a la opción "Crear un archivador":



 Y luego se escoge el formato deseado, en este caso rar, y se presiona el botón "crear":



Para descomprimir, basta hacerle doble clic al archivo rar y el Gestor de Archivadores lo abrirá como si fuera el mismísimo winrar:


viernes, 8 de noviembre de 2019

Matlab: Resolviendo la ecuación de onda bidimensional en el caso de una membrana de forma piramidal

El código fuente para resolver una ecuación de onda bidimensional está dado en el archivo twodimwavedirbc.m disponible en esta web: MATH 5343 Numerical Solution for Partial Differential Equations, Spring 2011.

La idea es resolver el ejercicio 12a del capítulo 12.2 del libro "Introduction to Numerical Ordinary and Partial Differential Equations Using MATLAB" de Alexander Stanoyevitch (de este libro proviene el scrip twodimwavedirbc.m):


Es decir, es una ecuación de onda cuya forma inicial es una pirámide. La dificultad aquí es dibujar la pirámide, yo la deduje como explico a continuacion:

La pirámide mostrada:
está formada por cuatro planos limitados por las rectas Y=X y Y = -X/2+4:

Las regiones donde Z es una función de X o de Y (dependiendo del plano donde se proyecta el eje Z) se muestran a continuación:


Para X<2, Y<2 y la región donde X<Y, la variable Z está definida por la función Z= Y/2.
Esto se hace para cada región de cada uno de los cuatro planos que definen la pirámide.

El script resultante es:

function z = pyramid(x, y)
z=0;

if y<=2 && x <= 2
   if y < x
       z=y/2;
   else
       z=x/2;
   end
end


if y<=2 && x > 2 && x <= 4
   if y < 4-x
       z=y/2;
   else
       z=-x/2+2;
   end
end


if y > 2 && x <= 2 && y <= 4
   if y < 4-x
       z=x/2;
   else
       z=-y/2+2;
   end
end


if y > 2 && y <= 4 && x > 2 && x <= 4
   if y < x
       z=-x/2+2;
   else
       z=-y/2+2;
   end
end

end
 


Modifiqué un poco el archivo twodimwavedirbc.m para hacerlo más flexible:

function [x, y, t, U] = twodimwavedirbc2(phi, nu, a1, a, b1, b, T, h, c)
% a1: punto inicial del eje x
% b1: punto inicial del eje y

% solves the two-dimensional wave problem u_tt = c^2(u_xx+u_yy)
% on the rectangle {a1<= x <= a,  b1<= y <= b}, with u(x,y)=0
% on the boundary of the rectangle.

% variables de entrada: 
% phi=phi(x,y) = función de la forma inicial de la onda
% nu=nu(x,y) = función inicial de la velocidad onda

% a= right endpoint of x, b = right endpoint of y, 
% T = final time solution will be computed.  h=common gap on
% x, y-grids,   k= t-grid gap, c = speed of wave.
% wave.
% Output variables: x = row vector for first space variable, y =
% row vector for second space variable,  t = time grid row vector
%(starts at t=0, ends at t=T, has Nt equally spaced values), 
% U = (Nx)by(Ny)by(Nt) matrix of solution approximations at
% corresponding grid points (where Ny = number of y-grid points)
% x grid will correspond to first entries of U, y
% grid values to second entries of U, and t grid to third entries of U.
% CAUTION:  This method will only work if h is chosen so that the x
% and y grids can have a common gap size, i.e., if h = a/h and
% b/h must be integers.
% The time grid gap is chosen so that mu = 1/2, this guarantees the
% Courant-Friedrichs-Levy condition holds and simplifies the
% main finite difference formula.


k=h/sqrt(2)/c; %k is determined from mu = 1/2

if (b/h-floor(round(b/h))>10*eps)||(a/h-floor(round(a/h))>10*eps)
    fprintf('Space grid gap h must divide evenly into both a and b \r')
    fprintf(' Either try another input or modify the algorithm')
    error('M-file will exit')
end

Nx = round((a-a1)/h)+1; %number of points on x-grid
Ny = round((b-b1)/h)+1; %number of points on y-grid
Nt = floor(T/k)+1; %number of points on t-grid
U=zeros(Nx, Ny, Nt);
x=a1:h:a;
y=b1:h:b;
t=0:k:T;
% Recall matrix indices must start at 1.  Thus the indices of the
% matrix will always be one more than the corresponding indices that
% were used in theoretical development.


% Note that by default, zero boundary values have been assigned to all
% grid points on the edges of the rectangle (and, for the time being,
% at all grid points).
%Assign initial time t=0 values and next step t=k values.

for i=2:(Nx-1)
     for j=2:(Ny-1)
    U(i,j,1)=feval(phi,x(i),y(j));
    U(i,j,2)=.25*(feval(phi,x(i-1),y(j))+...
      feval(phi,x(i+1),y(j))+feval(phi,x(i),y(j-1))+...
      feval(phi,x(i),y(j+1)))+ k*feval(nu,x(i),y(j));     
     end
end

%Assign values at interior grid points
for ell=3:Nt %letter ell looks too much like number one
    U(2:(Nx-1),2:(Ny-1), ell) = ...
     +.5*(U(3:Nx,2:(Ny-1), ell-1)+ U(1:(Nx-2),2:(Ny-1), ell-1)...
     + U(2:(Nx-1),3:Ny, ell-1) + U(2:(Nx-1),1:(Ny-2), ell-1))...
     - U(2:(Nx-1),2:(Ny-1), ell-2);
end


Y el script principal es:

clc; clear all; close all;
phi = @(x, y)sin(2*x) *sin(2*y);
nu=@(x, y)0;
[x, y, t, U] = twodimwavedirbc2('pyramid', nu, 0, 4, 0, 4, 4, 0.1, 1);
[a b c] = size(U);
%ans = 26 26 46
for ell=1:c
     surf(x,y,U(:, :,ell));
     axis([0, 4, 0, 4 -1, 1]);
     M(:,:,ell) = getframe;
end
movie(M, 2, 4)



Lo he probado en Matlab, y acá está corriendo lo mejor que puede en Octave 4.4.1 a pesar de que me dice que la función Movie no está implementada:

viernes, 25 de octubre de 2019

Resolviendo una ecuación parabólica unidimensional en Matlab/Octave

El siguiente ejercicio se encuentra en el libro "Computational Partial Differential Equations Using MATLAB" by Yi-Tung Chen, Jichun Li, capítulo 2, ejercicio 3:


Una pista de cómo resolver este ejercicio está en la sección 2.21:


Los autores dan un código base sobre el qué trabajar. Luego de recibir un poco de ayuda de la gentita de Stackoverflow, este es el código para resolver el problema:


 %---------------------------------------------------------------
% para1d.m:
%    use the explicit scheme to solve the parabolic equation
%    u_t(x,t) = u_{xx}(x,t),          xl < x < xr, 0 < t < tf
%    u(x,0) = f(x),                   xl < x < xr
%    u_x(0,t) = gl(t), u_x(1,t) = gr(t),  0  < t < tf
%---------------------------------------------------------------

clc;
close all;
clear all;  
                % clear all variables in memory

xl=0; xr=1;                 % x domain [xl,xr]
J = 31;                     % J: number of division for x
dx = (xr-xl) / J;           % dx: mesh size
tf = 0.1;                   % final simulation time
Nt = 51;                    % Nt: number of time steps
dt = tf/Nt/4;

mu = dt/(dx)^2;

if mu > 0.5         % make sure dt satisy stability condition
    error('mu should < 0.5!')
end

% Evaluate the initial conditions
x = xl : dx : xr;              % generate the grid point
f = x;

% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);

% boundary condition at left side

gl = 0;
% boundary condition at right side
gr = 0;

% Find the approximate solution at each time step
for n = 1:Nt
    t = n*dt;         % current time
     
    if n==1
      for j=2:J
       % first time step
        u(j,1) = f(j) + mu*(f(j+1)-2*f(j)+f(j-1));
      end
    end

  
    if n > 1
        for j=2:J
         % interior nodes
           u(j,n) = u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
        end
    end

  
    % hint 2.21 Los valores en la frontera es mejor calcularlos al final
    % pues estoy cogiendo índices que dependen de los nodos interiores

    u(1, n) = u(2, n) - dx * gl;
    u(J+1,n) = u(J, n) + dx * gr;
  
    % calculate the analytic solution
    for j=1:J+1
      xj = xl + (j-1)*dx;    
      suma = zeros(1000 , 1);

      for k= 1:1000
        suma(k) = 4/(((2*k-1)*pi)^2);
        suma(k) = suma(k) * exp(-((2*k-1)^2)*t*pi^2) * cos((2*k-1)*pi*xj);
      end

      u_ex(j, n)= double(0.5 - sum(suma));
    end
end


% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(cool);     % draw gray figure
surf(x, tt, u');     % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')

figure(2)
surf(x, tt, u_ex');     % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')

maxerr=max(max(abs(u-u_ex))),



El resultado es:


Probado en Octave 4.4.1 y Matlab 2008 R2.

miércoles, 11 de septiembre de 2019

Error de Visual C++ 2017: C3078 se debe especificar el tamaño de la matriz en nuevas expresiones

Este error no me pasaba en Visual Studio 2013. El error C3078 surgió de repente luego de actualizar mi proyecto en Visual C++ a Visual Studio 2017 y al SDK de Windows versión 10.0.17763.0 (para actualizar el SDK al que apunta nuestra solución se hace clic derecho en Solución->Redestinar Solución):



La línea que generaba el error en mi código fuente es la segunda en el siguiente ejemplo:

unsigned char* tempPointer;
tempPointer = new unsigned char[]{'H', 'i', '\0'};

El error no podría ser más fácil de resolver, sólo hay que indicar el tamaño del array:

unsigned char* tempPointer;
tempPointer = new unsigned char[3]{'H', 'i', '\0'};

Algo debe haber cambiado en el estándar de C++.

martes, 16 de julio de 2019

(Tutotial viejito): Creando Un Ocx Para Reproducir Video Con La Api Mcisendstring

Este es otro tutorial migrado de la vieja web:

Sucedió que necesité mucho mucho un ocx para reproducir video, pero no cualquier ocx: no debía depender de componentes instalados con anterioridad, lo que yo quería era un ocx que trabajara directamente con las Apis del windows.
Las Apis son funciones del propio Windows, guardadas dentro de los millones de Dlls en la carpeta de instalación (especialmente en la System32). Las Apis son casi un millar y lo hacen todo: obtienen información de los discos y las particiones, las características del escritorio, la pantalla, los colores, el hardware, los archivos, manejan multimedia, los periféricos, etc etc.

Rebuscando en internet, hallé muchos códigos fuentes que llamaban a las Apis que manejan multimedia: MciExecute, MciSendCommand y MciSendString.

De todas, la mejor es la MciSendString. La primera tiene opciones un tanto limitadas, la segunda requiere que se le pasen parámetros en hexadecimal, mientras que la última permite cadenas fácilmente entendibles.


Cómo funciona MciSendString:

Esta Api devuelve un valor tipo Long que es un código por si ocurre un error. Para saber qué error ha sido se llama a otra Api: mciGetErrorString, la cual no usé para este ocx.


Y fue gracias a estos ejemplos que aprendí a usar la MciSendString:



Lo primero que se debe hacer con esta Api es enviarle la ruta del archivo multimedia que se quiere reproducir:

"vid" es una variable tipo Long, "rutavideo" es una variable tipo String y contiene la ruta del archivo, algo así como:

C:\carpeta\ese_archivo.mpg 


 Lo que primero se hace es ponerle las comillas al principio y al final.


rutavideo = Chr$(34) & rutavideo & Chr$(34) 'para agregarle las comillas
vid = mciSendString("open " & rutavideo & " type mpegvideo alias movie parent " & Picture1.hWnd & " style " & "child ", 0, 0, 0)
vid = mciSendString("put movie window at 0 0 336 240", 0&, 0, 0)

La segunda y tercera líneas le dice que abra el archivo de esa ruta como un video del tipo mpeg (todos los videos que quería reproducir son mpegs) y que lo reconozca como "movie" porque así es más fácil de escribir (¡observad el espacio después de "open"! aquí hay que respetar los espacios!!). 
En esta segunda línea también se puede poner simplemente:



vid = mciSendString("open "& rutavideo & type mpegvideo alias movie", 0&, 0, 0)
 


Pero esto hará que cuando se reproduzca el video
lo haga en una ventana Popup, y yo quería reproducirlo dentro de mi control ocx,
así que por ello le incluí un Picturebox. La propiedad "Picture1.hWnd"
devuelve un número tipo Long que es el identificador del control donde se desea
reproducir el video (puede ser un form también), así se evita que aparezca esa
ventana Popup. 
El resto de las instrucciones es más simple (basta recordar que ya la Api reconoce a nuestro archivo y su ruta como "movie"):

vid = mciSendString("play movie", 0, 0, 0)
vid = mciSendString("pause movie", 0, 0, 0)
vid = mciSendString("resume movie", 0, 0, 0)
vid = mciSendString("stop movie", 0, 0, 0)


Para reproducir desde un tiempo determinado ("tiempo" es una variable tipo Long):
vid = mciSendString("play movie from " & tiempo, 0, 0, 0)

Una muy importante es:
vid = mciSendString("close movie", 0, 0, 0)


Si no se "cierra" nuestro archivo, a la siguiente que se quiera reproducir no aparecerá. Esta instrucción debe estar en el evento Unload del form y cada vez que se quiere reproducir otro video.

Hasta aquí lo básico para hacer un reproductor con MciSendString. Ahora falta meterlo todo en un ocx, al cual llamé "video_rep".
Cómo crear un ocx está en esta web:
http://www.elguruprogramador.com.ar/articulos/creando-un-control-activex-ocx.htm
Lo que hice fué combinar ambas cosas: los comandos del MciSendString dentro de sus respectivas funciones en el ocx para luego "jalarlas" desde una aplicación.
El código fuente de video_rep y unejemplo de cómo usarlo está akí.
Este ocx aún puede mejorarse y adaptarse. Quise hacerlo de modo que pudiera usarse con o sin Slider, bueno, yo sólo lo he probado con Slider.

Y ahora, una excelente web con recopilación de trillones de Apis:


http://allapi.mentalis.org/index2.shtml

Recomiendo mucho bajar el ApiViewer y el Api-Guide