martes, 15 de mayo de 2012

Primera demo funcionando

La aplicación está prácticamente terminada salvo pequeños detalles.

Cambios que hemos introducido respecto a la versión anterior:

1) La aplicación cargaba varios ficheros desde la sdcard. Ahora en lugar de eso mientras se muestra la pantalla inicial se copian esos ficheros desde la misma aplicación hasta un directorio privado que solo se puede acceder desde la aplicación. En el momento en que la aplicación sea desinstalada, estos archivos se borrarán de la memoria del teléfono. Con esto conseguimos que la aplicación funcione en cualquier móvil, tenga o no ranura para sdcard. Era algo fundamental.

2) El menú principal ahora tiene un checkBox. Si está marcado, al pulsar el botón de traducir, se leerá la entrada de texto mediante un TTS.

3) Eliminamos las actividades destinadas al text to speech y al traductor. La primera función ahora está integrada en el menú principal; y respecto al traductor, pasa a ser una clase sin extender a una actividad. En el menú principal se crea un objeto de esta clase que se usa para traducir la entrada.
Con estos cambios, la aplicación solo tiene tres actividades: la pantalla inicial, el menú, y la pantalla donde se muestran los vídeos.

4) Se ha diseñado un método de reproducción de vídeos frame a frame sin retardo entre ellos, sin problemas de memoria, y con una velocidad fácil de controlar. Además al tocar sobre el vídeo se hace visible un botón de replay. Si el botón se pulsa cuando se está reproduciendo un vídeo, entonces no hace nada, porque se superpondrían dos hilos de ejecución y el resultado es terrible. Se han probado distintas velocidades, y a 10 frames por segundo se ve bastante bien.

En la siguiente entrada al blog explicaremos la forma en la que hemos reproducido los vídeos. Es una clase bastante complicada, puesto que cuando entran threads de por medio todo se hace mucho más difícil.

domingo, 13 de mayo de 2012

Posibilidades: 2ª opción

Primeramente, hemos intentado hacer la primera opción de las que os pusimos en el último post. Hemos optado por reducir el tamaño de las imágenes (Recordad que hacía falta una reducción del orden 1:10)

¿Cómo lo hemos hecho?

Las imágenes originales son de 480 x 640 = 307200 píxeles
307200 píxeles x 32 bits/píxel = 9.8·10^6 bits

Haciendo la reducción, nos quedan 307200/10 = 30720 píxeles

Sabemos que 480 es 3/4 veces 640. Luego, x·3/4·x = 30720

x = 202.386 ~ 200
3/4·x = 151.79 ~ 150

Total: 150x200x32 bits = 0.96·10^6 bits(10 veces menos que antes)

¿Cuál es el problema entonces?

El problema reside en que hay que pasar todos los vídeos a frames y, a su vez, reducir esos frames, es decir:

330 vídeos · 15 frames / vídeos · 330 reducciones = 1 633 500  cambios


Motivo más que suficiente para probar la otra opción que de funcionar será la definitiva.

sábado, 12 de mayo de 2012

Reproducción de un gif/vídeo: nuevo contratiempo

Hace un par de entradas atrás pusimos las capturas de las tres opciones de reproducción de un gif que teníamos y recordad que al final llegamos a una conclusión que era que la opción tercera era la buena. Pues bien, al contrario de nuestra creencia, la reproducción en el móvil también mantiene la parte más oscura de debajo de la cabeza, es decir, que no se ven suficientemente claros los gestos.

Tras haber probado TODO con los vídeos o imágenes animadas, ya solo nos queda una opción: sacar los fotogramas de los vídeos (unos 15 aproximadamente) y buscar una manera de reproducirlos unos tras otros.

¿Qué pasa con esta opción?

Hemos estado probando y resulta que con frames (fotogramas) las animaciones se ven bien, pero solo hemos conseguido reproducir 10 frames seguidos, si metemos más da un error de memoria.

Llegados a este punto, se nos abren dos nuevas alternativas:

a) Reducir considerablemente el tamaño y la calidad: pasando a 1:10 los bytes, podríamos reproducir unos 100 frames, que pueden ser entre 7 y 12 vídeos. Como la pantalla del móvil es pequeña igual no se aprecia mucho la calidad y podría valernos.

b) Crear un objeto de tipo AnimationDrawable(), al que le añadamos los frames que queramos, y así será más fácil hacer operaciones del tipo: controlar velocidad, botón de start y stop.
  Con un thread ir cambiando el fondo, por ejemplo. Hay que tener cuidado porque la UI (Interfaz de usuario) solo la puede cambiar el thread principal, por lo que habría que mandarle mensajes a este cada vez que queramos cambiar de imagen. Esta es más complicada, pero en principio evitaríamos los problemas de memoria.

Vamos a probar ambas alternativas y ver qué resultado es más satisfactorio.

domingo, 6 de mayo de 2012

Concatenación de Videos ( I )

También hemos dado los primeros pasos para la concatenación de los vídeos en C++.
 La idea es que esta clase en c++ cree el gif salida.gif (varios gifs consecutivos) en la carpeta Assets y la clase Video que llama a GifDecoderView descrita en el anterior post lo reproduzca.

 La clase en C++ la hemos llamado merge_gif y hemos creado su correspondiente fichero .h (merge_gif.h). El archivo .h contiene la definición de la clase mientras que el .cpp contiene la definición de las funciones de la clase.

Hemos cambiado los char* por jstrnigs ya que recordad que daban problemas los char en java y en c++ al no funcionar de igual manera.
En traduce.cpp, que era la clase encargada de la traducción en c++, añadimos un método que llame a este método que hemos llamado Concatenar de la clase merge_gif.cpp. También lo añadimos en el makefile.

Con todo esto, está listo para la compilación, que hay que hacer siempre que trabajemos con los ficheros de c++ para su correcto funcionamiento en Java. Esta compilación la hacíamos ejecutando el archivo ndk-build con Cygwin. En traduciendo.java, llamamos al método de C++ : public native void ConcatenarGifs(String frase);

Clase para la reproducción de un Gif

Hoy hemos conseguido la reproducción de un solo gif.
Lo que hemos hecho ha sido que pase de menuprincipal.java a Video.java en lugar de traduciendo para evitar errores de otro tipo que no tienen que ver con la reproducción.

 En la clase Video es donde trabajamos para ello.

Teníamos tres posibilidades de reproducción de un gif animado. Estas posibilidades las hemos encontrado por Internet:

http://droid-blog.net/2011/10/15/tutorial-how-to-play-animated-gifs-in-android-%E2%80%93-part-2/

La primera posibilidad y la tercera no funcionaban como esperábamos. Basta con ver la ejecución en este caso de la opción tres(Usando WebView):
Como véis, la imagen sale cortada por la mitad y, además, solo se reproducía el primer fotograma por lo que era básicamente una imagen, un gif sin animar.

Con la primera parte tuvimos problemas en la vinculación del gif al programa:
Al final, la buena resultó ser la opción 2, que era la más compleja y que, en un principio, quisimos evitar. Para esta manera, el gif lo guardamos en la carpeta Assets y el método se llama GifDecoderView. Hemos localizado en esta opción la posibilidad de controlar la velocidad de los fotogramas, que se podrá hacer o bien poniendo varios botones con 2x, 0.5x, 0.25x... o bien con una slidebar.
En la captura obviamente no se aprecia pero esta vez sí se reproducía el gif. La parte más oscura del vídeo es cosa del emulador, ya que en el teléfono móvil sí funciona correctamente.

Paso de videos .mp4 a imagenes .gif

Aquí dejamos unas capturas del proceso de paso de archivos.mp4 a .gif, por medio del programa VirtualDub.
De la siguiente manera, especificamos que solo se reproduzcan una única vez, sin repeticiones:

miércoles, 25 de abril de 2012

Vídeos en formato gif

Vamos a intentar solucionar nuestros problemas con los vídeos pasándolos de formato mp4 a gif con el programa VirtualDub. Esto ya esta hecho y ahora nos ponemos con la clase que haga el play de un gif. En android ya viene predefinida una clase llamada android.graphics.Movie que nos permite reproducir distintos InputStreams( cualquier cosa de la que se leen bytes. Puede ser el teclado, un fichero, un socket, o cualquier otro dispositivo de entrada). Una vez que consigamos hacer compilar la clase y veamos que funcione, intentaremos controlar el número de repeticiones del Gif para que no se reproduzca indefinidamente. Por otro lado, ya hemos hecho el TTS(text to speech) y funciona correctamente. Más adelante subiremos muestras de todo esto.

domingo, 22 de abril de 2012

Primeras soluciones al traductor

Tras dos semanas de continuos problemas tanto de compatibilidades entre c++ y java o entre móvil y emulador como del código en sí, al final hemos solucionado todos los problemas que teníamos con el traductor.

Hemos creado un < TextView con el objetivo de que tradujera las palabras que le metíamos en la entrada y nos las sacara por pantalla en forma de texto. Recordemos que tenemos dos archivos .txt uno con las palabras o frases más frecuentes en nuestra lengua y otro con las palabras o frases en lengua de signos LSE. La idea es que nos relacionara ambos archivos cada vez que introducimos una palabra o frase.

Por ejemplo, si nosotros introducimos "el bonotransporte lo tiene que pedir en una oficina o estanco", el traductor interpretará "ABONO OFICINA O TIENDA ESTANCO TU PEDIR".

Uno de los problemas más importantes que hemos tenido es el de las tildes. Esto ha sido un quebradero de cabeza y al final hemos optado por quitarlas.

Con todo esto, el traductor parece, en principio, que ya funciona.


En cuanto a los vídeos, hemos vuelto a poner la clase VideoView en lugar de la clase MediaPlayer que es más complicada.

lunes, 16 de abril de 2012

Strings en jni

Aquí viene descrito nuestro problema:
http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jnistring.html#string

The String object in the Java language, which is represented as jstring in Java Native Interface (JNI), is a 16 bit unicode string. In C a string is by default constructed from 8 bit characters. So, to access a Java language String object passed to a C or C++ function or return a C or C++ string to a Java language method, you need to use JNI conversion functions in your native method implementation.

Después de ver el código del traductor que utilizamos, nos hemos dado cuenta de que no hace nada de esto.

Procedemos a efectuar los siguientes cambios en las clases traduce.h y traduce.cpp que son las que nos dan problemas:

En la clase traduce.h intercambiar la línea de arriba por la de abajo:

JNIEXPORT jint JNICALL Java_com_traductor_lse_Traduciendo_Traduccion(JNIEnv *env, jobject obj, char *origen, char *destino);

JNIEXPORT jint JNICALL Java_com_traductor_lse_Traduciendo_Traduccion(JNIEnv *env, jobject obj, jcharArray origen, jcharArray destino);


Además habría que cambiar el método traduccion (el que nos da el problema en Java) de la clase traduce.cpp:

jcharArray origen --> char *origen
jcharArray destino --> char *destino
***Lo que haya en traduccion***
char *destino --> jcharArray destino

Con estos cambios esperamos solucionarlo.

domingo, 15 de abril de 2012

Librerías de C++ . Nuevo problema

Este fin de semana nos ha surgido un nuevo problema con las librerías.

Ejecutamos bien los métodos inicialización, traducción y finalización de la clase Traduciendo.java, pero cuando pasa a ejecutar la siguiente instrucción se produce un error y en el LogCat empiezan a salir líneas etiquetadas con DEBUG y después pone que el proceso ha muerto, y vuelve a la actividad anterior, en este caso MenuPrincipal, y ahí se queda.

Aquí ilustramos lo dicho:

jueves, 12 de abril de 2012

Objetivos de la semana

Después de un tiempo de parón debido a Semana Santa, hemos vuelto esta semana con la idea de solucionar dos temas que llevamos arrastrando desde hace algunas semanas:

En primer lugar y más prioritario, conseguir concatenar los vídeos de manera que no hay interrupciones cuando se reproduzcan dos o más vídeos.

En segundo lugar, acabar con el traductor. En lo que estamos trabajando es en conseguir que el traductor traduzca varias palabras distintas, todas ellas en una misma frase, y que sepa diferenciarlas claramente.

sábado, 31 de marzo de 2012

viernes, 30 de marzo de 2012

Vídeos. La clase Videos

En primer lugar, cambiamos los vídeos de ubicación. Los pasamos de la carpeta raw a la sdcard del emulador, en una carpeta a la que llamamos LSEDapps. También metemos ahí los 5 archivos de texto.

Además, pasamos los vídeos a formato mp4 para que sean reconocidos por Android. De esta manera han pasado de ocupar 250 MB a 16 MB.

Continuamos con la clase Videos.
En ella, construimos un objeto de tipo VideoView y lo inicializamos. Ponemos listeners para saber cuándo los vídeos están preparados o terminados. Lo hacemos con los métodos OnPreparedListener y OnCompletionListener pasándole como parámetro mp(de MediaPlayer).

Creamos también un método playVideo que vinculamos al vídeo en cuestion de manera que el parámetro que le pasamos es un string con el path del vídeo:

sdcard/LSEDapps/volver.mp4 es un ejemplo del path de uno de los videos que tenemos llamado volver.

En cuanto al VideoView.xml del layout que es como el diseño que tendrá la pantalla(en este caso la de reproducción de vídeos), tenemos un < VideoView y un < EditText donde pondremos un texto.

Ahora el problema al que nos estamos enfrentando es al de concatenar vídeos para que se reproduzcan de manera consecutiva.

Librerías de C++ (IV). Problema resuelto

Ya hemos solucionado el problema que nos surgió el otro día y que os lo hicimos llegar a través de este blog.

La solución, simple pero difícil de darse cuenta, residía en la función
static {
System.loadlibrary("libtraductor");
}
donde libtraductor es el nombre del archivo .so.

Pues bien, aunque el código compilaba, lo cierto es que luego no se llegaba a ejecutar el emulador. Basta con cambiar libtraductor por traductor, manteniendo libtraductor como nombre del archivo .so.

De esta manera, tenemos:

static {
System.loadlibrary("traductor");
}

lunes, 26 de marzo de 2012

Un poco de diseño gráfico


Hacer una aplicación para Android no solo consiste en escribir líneas de código, el diseño gráfico es muy importante. Una aplicación puede estar muy bien programada y ser muy útil, pero si la interfaz de usuario no está lograda, simplemente no nos gusta.

Cuando alguien entra en una aplicación, lo primero que ve es el icono que tiene que pulsar para entrar en ella. Queremos iconos llamativos, diferentes, que tengan algo especial. Pero esto no es tan fácil como parece.

Para hacer nuestro icono hemos utilizado Photoshop. Nos hemos basado en los iconos que hay en iOS, ya que la forma que tiene es un cuadrado con borde redondeado. Tiene un efecto parecido al del icono de la App Store, que hemos conseguido aplicando varias capas y filtros. Sobre esta base hemos puesto una imagen del avatar que interpreta los signos en nuestra aplicación, un borde plateado, y listo.

Vídeos

Hoy hemos empezado con los vídeos ya que estamos bloqueados en la parte de las librerías de C++; problema que intentaremos solventar en la próxima reunión con Rubén.
Esta parte es independiente de las librerías, es decir, podemos hacerlas por separado y, al final, unirlas. Las librerías son necesarias para saber qué vídeos exactamente hay que reproducir.

Por eso, de momento, vamos a ver cómo reproducir un vídeo cualquiera en nuestra aplicación.
Primeramente vinculamos el botón reproducir a una clase llamada Videos, en la que programaremos todo lo relacionado.
En una carpeta llamada raw, ubicada en res, guardamos todos los vídeos que contienen el avatar representando las distintas letras y/o palabras.
Este es, de momento, el avatar que tenemos para la reproducción de los vídeos



Sin embargo, el primer intento de código no ha salido como esperábamos pues nos sale un problema que aún no tenemos detectado. Os dejamos el problema desde el punto de vista del código:



y desde el punto de vista del emulador:

domingo, 25 de marzo de 2012

Librerías de C++ ( III ) Problema.

Vamos a poner aquí unas cuantas líneas de código que nos parecen interesantes.

Hemos puesto lo siguiente para permitir que se pueda escribir en la tarjeta de memoria:

< uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/ >

Siguiendo con la sdcard, escribimos andoid:installlocation="preferExternal" para instalar la aplicación en la tarjeta, en caso de que la interna no tenga suficiente capacidad, como es precisamente nuestro caso.

También, con la línea de código pretendemos que no se vaya la luz de la pantalla mientras se reproduzca un vídeo:
< uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/ >

Sin embargo, cuando ejecutamos la aplicación con el emulador, algo falla pues nos aparece un mensaje de error que nos obliga a cerrar el programa.
Aquí podéis verlo:

Librerías de C++ ( II )

Primeramente, aunque no tenga que ver con esta parte en sí, hemos creado unas trazas para localizar errores en caso de que ocurriesen.

Prosiguiendo con lo anterior, ahora tenemos que cargar la librería, para lo que usamos lo siguiente:

static {
System.loadlibrary("libtraductor");
}

que, recordemos, libtraductor es el nombre del archivo .so.

Lo siguiente es meter unos archivos de texto en la sdcard del teléfono. Como no tenemos un teléfono android físicamente, hemos dado con una herramienta muy útil para usar la sdcard del emulador del teléfono.
Se trata de abrir eclipse con la Perspectiva DDMS. Esta perspectiva nos da varias nuevas posibilidades que os iremos comentando según las vayamos utilizando.
En esta primera imagen vemos que muestra estadísticas sobre la consumición de memoria por parte de la aplicación.



En esta perspectiva, en mnt/sdcard, metemos los 5 archivos de texto requeridos, que era nuestro objetivo, tal y como se muestra en la imagen:

viernes, 23 de marzo de 2012

Segunda parte: Librerías de C++

Esta segunda parte consta del traductor a LSE en C++ importado como una librería.

Para poder utilizar este traductor y trabajar con él se ha utilizado el NDK de Android.
Además, hemos instalado (24h de instalación) Cygwin, una colección de herramientas ideadas para proporcionar un comportamiento similar a los sistemas Unix en Microsoft Windows. Es decir, Cygwin es un entorno Linux para Windows.

¿Qué hemos hecho con ello?

En primer lugar creamos en nuestro proyecto una carpeta llamada jni.
Dentro de la carpeta jni deben estar las clases en código nativo (en este caso C++) y el makefile. Los makefiles son los ficheros de texto que utiliza la herramienta de generación o automatización de código make para llevar la gestión de la compilación de programas. Se podrían entender como los guiones de la película que quiere hacer make.

Desde el Cygwin ejecutamos en el directorio de nuestra aplicación la instrucción ndk-build.
Se crea un archivo con extensión .so (shared object). Archivo que metemos en la carpeta (que se crea por defecto al ejecutar) libs/armeabi. Lo llamamos libtraductor.so

Aquí os dejamos una imagen de la compilación con cygwin:

Primer Hito: Resumen de lo conseguido

Tras el primer hito del curso, este es el resumen de la primera parte de la práctica, ya finalizada:

Tenemos una pantalla de bienvenida con las siguientes características:
Activity con un Thread para controlar el tiempo
A los 3 segundos para y se cambia la pantalla de bienvenida por el menú principal de la aplicación
Utilizamos la clase Intent para lanzar una nueva Activity que será el menú principal
Menú principal:
Tiene un cuadro para insertar texto y el botón de traducir


En res/drawable_hdpi está el icono de la aplicación, y es el que aparecerá en el móvil
En res/drawable está menu_background.jpg que es la imagen que sale en la pantalla incial
En res/values/strings se definen los Strings que se usan en los ficheros .xml
Además están las carpeta res/layout y res/layout-finger

En estos ficheros XML en layout, se configura la interfaz gráfica de la aplicación
pantallaincial.xml
ImageView: para mostrar una imagen
main.xml
TextView: una etiqueta que muestra una frase
EditText: cuadro para introducir el texto a traducir
Button: botón de traducir
ImageView: logo del proyecto Consignos

El archivo AndroidManifest.xml describe los componentes de la aplicación:
Activities, services, broadcast receivers, and content providers.
Nombra a las clases que implementan cada uno de los componentes y publica sus capacidades (por ejemplo, que los mensajes puedan manejar Intent).
En nuestra aplicación hay dos actividades, cada una lanzada por un intent

lunes, 19 de marzo de 2012

Logo Consignos

Posteriormente usaremos una serie de videos que muestran la traducción a lengua de signos LSE.
Como son videos del proyecto Consignos, tendremos que poner el siguiente logo
en la parte de abajo de la aplicación.
Simplemente en la carpeta drawable ubicada en res colocamos la imagen deseada, mientras que en main.xml construimos un < ImageView relacionado con la imagen introducida. La ponemos en modo wrap_content para que se ajuste al tamaño de la pantalla en cuanto al ancho.
Este es la nueva imagen de la aplicación con la última modificación:

sábado, 10 de marzo de 2012

Aspecto de la aplicación

En res->values->strings.xml creamos un texto llamado 'instrucciones', que contiene un subtexto 'Inserte texto'.

En res->layout->main.xml, construiremos un < TextView que llamará al texto antes mencionado, que actúa a modo de etiqueta.
Siguiendo en esta clase, creamos un nuevo texto con < EditText.

Volviendo a strings.xml, creamos un nuevo string, esta vez llamándolo 'traducir'. El contenido de este texto será el que aparezca en el botón que creamos a continuación:
< Button, centrándolo horizontalmente de esta manera:
android:layout:gravity="center_horizontal".

Así se ve la aplicación:



Cuando pulsamos sobre el cuadro de texto, tenemos la posibilidad tanto de escribir con nuestro teclado como de escribir con el teclado habilitado por el móvil como se muestra a continuación:

Primeros pasos: Arranque de la aplicación

Hemos llamado al proyecto 'Lenguaje de signos'.
El primer objetivo es crear una pantalla de carga de duración unos 3 segundos que nos lleve posteriormente a la pantalla principal de la aplicación.
Al crear un proyecto en android, aparecen unas carpetas y archivos ya por defecto.
Una de ellas, drawable_hdpi, ubicada en la carpeta res, contiene el logo de la aplicación. Hemos creado un nuevo logo y guardado en formato jpg incluyéndolo en dicha carpeta. Este es el aspecto de la aplicación:



De nuevo en res creamos otra carpeta llamada 'drawable' en la que trabajaremos posteriormente.
Confeccionamos también un archivo PantallaInicial.xml en res->Layout.
Por defecto se crea un archivo LenguajeDeSignosActivity.java encargado de que salte la pantalla; con su método onCreate(es básicamente lo que se ejecuta, parecido al main de java).
Especificamos dentro del archivo .java el tiempo(en milisegundos) que dure la pantalla de espera. En nuestro caso 3000ms (=3 segundos): long m_dwSplashTime=3000;
Un hilo new Thread()será el encargado de ir contando esos segundos.
Este es el aspecto que tiene la pantalla de espera que aparece cuando pinchamos en el icono:



Construimos también un método protected void onPause para parar la aplicación cuando llegue una llamada, mensaje de texto o similares, con su correspondiente método onResume() para volver a la aplicación una vez que estamos en pausa.

Creamos otra clase en src->lenguaje.signos a la que llamamos 'MenuPrincipal', también con su método public void onCreate.
Modificamos el AndroidManifest.xml para que cambie de pantalla.

martes, 21 de febrero de 2012

Primera semana: Instalaciones varias

En esta primera sesión, se pretende llevar a cabo una toma de contacto con las herramientas que vamos a utilizar durante el desarrollo de la práctica.

Primeramente, instalamos el entorno apropiado. En nuestro caso, pensamos en Eclipse pues es el que más posibilidades nos ofrece para programar en Android.

Añadimos también el Java Development Kit(JDK), software que nos proporciona herramientas de desarrollo para la creación de programas en Java.

Posteriormente instalamos el kit de desarrollo de software en Android(SDK de Android), para poder crear programas en este sistema específico. Además, instalamos también el plugin ADT(Android Development Tools) para el Eclipse.

Por último, añadimos plataformas y herramientas adicionales.

Arranca la práctica especial de LSED

Inauguramos este blog con el objetivo de hacer un seguimiento específico de la práctica innovadora para la asignatura LSED de la ETSIT de la Universidad Poítécnica de Madrid.

Esta práctica consistirá en la traducción de un mensaje de voz a lenguaje de signos interpretado por un avatar, en Android.
En cuanto al software, usaremos el lenguaje de programación Java.

El programa constará de 4 partes principalmente: Una primera en la que se traducirá la voz a texto, para lo que usaremos el reconocedor de Google; una segunda que será el traductor en sí, con librerías en C y C++ que adaptaremos a Java; una parte dedicada a los vídeos en lenguaje de signos y, por último, un TTS que traduce texto a voz.

Cada semana iremos comentando los distintos pasos llevados a cabo.