
En este art铆culo hablar茅 sobre c贸mo escribir un complemento en C para el reproductor multimedia VLC. Escrib铆 mi plugin para simplificar ver programas de televisi贸n y pel铆culas en ingl茅s. La idea de crear este complemento se describe en las secciones
Idea y
B煤squeda de una soluci贸n . Los detalles t茅cnicos de la implementaci贸n del complemento se proporcionan en las secciones de
implementaci贸n y
complemento Hello World . Lo que sucedi贸 al final y c贸mo usarlo se puede encontrar en la 煤ltima secci贸n,
Resultado .
El c贸digo fuente del proyecto est谩 disponible en
GitHub .
Idea
La idea de aprender un idioma extranjero mientras veo mi serie favorita no es nueva, pero siempre he tenido problemas con ella personalmente. Es muy dif铆cil ver una serie o una pel铆cula cuando no entiendes la mitad de lo que dicen. Por supuesto, puede activar los subt铆tulos, pero si se encuentra una palabra o expresi贸n desconocida en un discurso, no quedar谩 m谩s claro que el texto lo duplicar谩. Y no me gust贸 ver la serie con subt铆tulos en ruso: el cerebro cambia a su idioma nativo y deja de percibir el habla extranjera. Le铆 en alguna parte que primero necesitas ver una serie en ruso y luego en el original. Pero este enfoque tampoco me conven铆a. En primer lugar, d贸nde tomar tanto tiempo para mirar la misma cosa varias veces, y en segundo lugar, mirar la segunda vez ya no es tan interesante: se pierde la motivaci贸n.
A pesar de todas las dificultades para ver programas de televisi贸n extranjeros, puedo leer bastante bien la documentaci贸n t茅cnica, art铆culos y libros en ingl茅s. Me gusta leer libros en el lector electr贸nico Kindle, ya que la funci贸n del diccionario es genial: puedes encontrar una traducci贸n de una palabra desconocida con solo tocar la pantalla. Es conveniente leer art铆culos y sitios en ingl茅s instalando una extensi贸n especial para la traducci贸n en el navegador. Uso la extensi贸n
Yandex.Translation . Este enfoque le permite leer y comprender textos en ingl茅s, sin mucha distracci贸n para la b煤squeda de palabras desconocidas.
Pens茅, por qu茅 no aplicar el mismo enfoque para ver programas de televisi贸n: activamos la serie en ingl茅s tan pronto como se encuentra una frase incomprensible, cambiamos a la pista de audio rusa y retrocedemos un poco. A continuaci贸n, seguimos viendo la serie en ingl茅s.
Busca una soluci贸n
De hecho, toda la funcionalidad que necesito ya est谩 disponible en muchos reproductores multimedia populares. Lo 煤nico que me gustar铆a cambiar la pista de audio y rebobinar el video hace unos segundos con el clic de un bot贸n. Tambi茅n ser铆a genial si, despu茅s de traducir un fragmento incomprensible, el reproductor multimedia cambiara la pista de audio al ingl茅s. Bueno, ser铆a bueno poder repetir el fragmento traducido previamente con la pista en ingl茅s.
Es decir, necesito un reproductor multimedia para el que pueda escribir complementos. Tambi茅n es deseable que sea multiplataforma, ya que uso una PC con Windows y una computadora port谩til con Linux. Mi elecci贸n recay贸 inmediatamente en el VLC. En habr incluso encontr茅
un art铆culo en el que
@Idunno dice c贸mo escribir una extensi贸n VLC en LUA. Por cierto, tambi茅n escribi贸 esta extensi贸n para aprender ingl茅s) Desafortunadamente, esta extensi贸n no funciona en las 煤ltimas versiones de VLC (anteriores a 2.0.5). Debido a la operaci贸n inestable, la capacidad de agregar funciones de devoluci贸n de llamada a trav茅s de las cuales era posible procesar eventos de teclado en la extensi贸n LUA se elimin贸 de la API LUA. En
README , un enlace a la lista de correo de desarrolladores de VLC que discuten este problema lleva a su extensi贸n en GitHub
@Idunno .
Por lo tanto, para implementar mi idea, una extensi贸n de LUA no funciona, necesita escribir un complemento en C. Y aunque escrib铆 algo en C la 煤ltima vez hace unos 7 a帽os, de vuelta en la universidad, decid铆 probarlo.
Hola plugin mundial
Vale la pena se帽alar que el reproductor multimedia VLC tiene bastante buena
documentaci贸n . Aprend铆 de 茅l que el desarrollo de un reproductor multimedia utiliza un enfoque modular. VLC consta de varios m贸dulos independientes que implementan cierta funcionalidad, y el n煤cleo (
libVLCCore ), que administra estos m贸dulos. Hay dos tipos de m贸dulos: internos (
en 谩rbol ) y externos (
fuera de 谩rbol ). El c贸digo fuente de los m贸dulos internos se almacena en un repositorio con el c贸digo del n煤cleo. Los m贸dulos externos se desarrollan y ensamblan independientemente del reproductor multimedia VLC. En realidad, estos 煤ltimos son lo que se llaman complementos.
La documentaci贸n tambi茅n tiene
un art铆culo sobre c贸mo escribir su complemento (m贸dulo) en C. Este art铆culo proporciona el c贸digo fuente de un complemento simple que, cuando se inicia VLC, muestra un mensaje de bienvenida "
Hola, <nombre> " en la consola (se toma el valor <nombre> desde la configuraci贸n del complemento). Corriendo un poco m谩s adelante, dir茅 que en el ejemplo anterior, agregue la siguiente l铆nea despu茅s de
set_category(CAT_INTERFACE)
:
set_subcategory( SUBCAT_INTERFACE_CONTROL )
Bueno, todo lo que queda es ensamblar el complemento y probar su funcionamiento. Tambi茅n hay una
instrucci贸n para construir un complemento externo. Aqu铆 vale la pena prestar atenci贸n a la secci贸n de
Internacionalizaci贸n , que describe c贸mo funciona la localizaci贸n en VLC. En resumen, para complementos externos necesita definir macros
N_()
,
_()
:
#define DOMAIN "vlc-myplugin" #define _(str) dgettext(DOMAIN, str) #define N_(str) (str)
Para el ensamblaje, se propone utilizar el viejo Makefile o Autotools. Decid铆 seguir el camino simple y eleg铆 el Makefile. En el Makefile, debe recordar definir la variable
MODULE_STRING
: este es el identificador de nuestro complemento. Tambi茅n modifiqu茅 un poco el trabajo con directorios, ahora se definen a trav茅s de
pkg-config . El resultado son los siguientes archivos:
hola.c #ifdef HAVE_CONFIG_H # include "config.h" #endif #define DOMAIN "vlc-myplugin" #define _(str) dgettext(DOMAIN, str) #define N_(str) (str) #include <stdlib.h> /* VLC core API headers */ #include <vlc_common.h> #include <vlc_plugin.h> #include <vlc_interface.h> /* Forward declarations */ static int Open(vlc_object_t *); static void Close(vlc_object_t *); /* Module descriptor */ vlc_module_begin() set_shortname(N_("Hello")) set_description(N_("Hello interface")) set_capability("interface", 0) set_callbacks(Open, Close) set_category(CAT_INTERFACE) set_subcategory( SUBCAT_INTERFACE_CONTROL ) add_string("hello-who", "world", "Target", "Whom to say hello to.", false) vlc_module_end () /* Internal state for an instance of the module */ struct intf_sys_t { char *who; }; /** * Starts our example interface. */ static int Open(vlc_object_t *obj) { intf_thread_t *intf = (intf_thread_t *)obj; /* Allocate internal state */ intf_sys_t *sys = malloc(sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; intf->p_sys = sys; /* Read settings */ char *who = var_InheritString(intf, "hello-who"); if (who == NULL) { msg_Err(intf, "Nobody to say hello to!"); goto error; } sys->who = who; msg_Info(intf, "Hello %s!", who); return VLC_SUCCESS; error: free(sys); return VLC_EGENERIC; } /** * Stops the interface. */ static void Close(vlc_object_t *obj) { intf_thread_t *intf = (intf_thread_t *)obj; intf_sys_t *sys = intf->p_sys; msg_Info(intf, "Good bye %s!", sys->who); /* Free internal state */ free(sys->who); free(sys); }
Makefile LD = ld CC = cc PKG_CONFIG = pkg-config INSTALL = install CFLAGS = -g -O2 -Wall -Wextra LDFLAGS = LIBS = VLC_PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags vlc-plugin) VLC_PLUGIN_LIBS := $(shell $(PKG_CONFIG) --libs vlc-plugin) VLC_PLUGIN_DIR := $(shell $(PKG_CONFIG) --variable=pluginsdir vlc-plugin) plugindir = $(VLC_PLUGIN_DIR)/misc override CC += -std=gnu99 override CPPFLAGS += -DPIC -I. -Isrc override CFLAGS += -fPIC override LDFLAGS += -Wl,-no-undefined,-z,defs override CPPFLAGS += -DMODULE_STRING=\ override CFLAGS += $(VLC_PLUGIN_CFLAGS) override LIBS += $(VLC_PLUGIN_LIBS) all: libhello_plugin.so install: all mkdir -p -- $(DESTDIR)$(plugindir) $(INSTALL) --mode 0755 libhello_plugin.so $(DESTDIR)$(plugindir) install-strip: $(MAKE) install INSTALL= uninstall: rm -f $(plugindir)/libhello_plugin.so clean: rm -f -- libhello_plugin.so src/*.o mostlyclean: clean SOURCES = hello.c $(SOURCES:%.c=src/%.o): $(SOURCES:%.c=src/%.c) libhello_plugin.so: $(SOURCES:%.c=src/%.o) $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) .PHONY: all install install-strip uninstall clean mostlyclean
La forma m谩s f谩cil de construir un complemento para Linux. Para hacer esto, debe instalar, de hecho, el reproductor multimedia VLC, as铆 como los archivos y herramientas necesarios para compilar el complemento. En Debian / Ubuntu, esto se puede hacer con el siguiente comando:
sudo apt-get install vlc libvlc-dev libvlccore-dev gcc make pkg-config
En realidad, todo est谩 listo, recopilamos e instalamos nuestro complemento usando el comando:
sudo make install
Para probar el complemento, ejecute VLC tambi茅n desde la consola:
vlc
Desafortunadamente, no vimos ning煤n "
Hola mundo ". La cuesti贸n es que el complemento primero debe estar habilitado. Para hacer esto, abra la configuraci贸n (
Herramientas >
Preferencias ), cambie a la vista avanzada (seleccione
Todo en el grupo
Mostrar configuraci贸n ) y busque en el 谩rbol en el panel izquierdo
Interfaz >
Interfaces de control - marque la casilla junto a nuestro complemento de
interfaz Hello .

Guardamos la configuraci贸n y reiniciamos el VLC.

Crea un complemento para Windows
Con Windows, las cosas son un poco m谩s complicadas. Para compilar el complemento, debe descargar sdk, que contiene bibliotecas, encabezados y archivos de configuraci贸n de VLC. Anteriormente, SDK era parte del ensamblaje VLC normal y se pod铆a encontrar en la carpeta de instalaci贸n del programa. Ahora viene como un ensamblaje de reproductor multimedia separado. Por ejemplo, para VLC versi贸n 3.0.8, este ensamblaje se puede descargar en
ftp://ftp.videolan.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.7z (es importante descargar 7z -archivo).
Copie el contenido del archivo en una carpeta, por ejemplo, en
C: \ Proyectos . Adem谩s de SDK, el archivo tambi茅n contiene el propio reproductor multimedia, que se puede utilizar para probar y depurar el complemento.
Para que nuestro Makefile se pueda usar para compilar e instalar el complemento, debe corregir el archivo
C: \ Projects \ vlc-3.0.8 \ sdk \ lib \ pkgconfig \ vlc-plugin.pc , que indica la ruta correcta a la carpeta
sdk en las variables
prefijo y
pluginsdir y
complementos respectivamente:
prefix=/c/Projects/vlc-3.0.8/sdk pluginsdir=/c/Projects/vlc-3.0.8/plugins
Para compilar en Windows, tambi茅n necesitamos instalar un compilador y otras utilidades. Todo el software necesario se puede obtener instalando el entorno
MSYS2 . El sitio web del proyecto tiene instrucciones detalladas de instalaci贸n. En resumen, inmediatamente despu茅s de la instalaci贸n, debe abrir la consola (
C: \ msys64 \ msys2.exe ) y actualizar los paquetes MSYS2 con el comando:
pacman -Syu
A continuaci贸n, cierre la ventana del terminal MSYS2, luego 谩brala nuevamente y ejecute el comando
pacman -Su
Despu茅s de actualizar todos los paquetes, debe instalar la cadena de herramientas:
pacman -S base-devel mingw-w64-x86_64-toolchain
Ahora que todos los paquetes necesarios est谩n instalados, puede comenzar a compilar el complemento. Modifiqu茅 un poco el Makefile para que pudiera compilar el complemento tanto en Linux como en Windows. Adem谩s, tuve que eliminar algunos par谩metros de compilaci贸n MinGW no compatibles, como resultado, el Makefile comenz贸 a verse as铆:
Makefile para Windows LD = ld CC = cc PKG_CONFIG = pkg-config INSTALL = install CFLAGS = -g -O2 -Wall -Wextra LDFLAGS = LIBS = VLC_PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags vlc-plugin) VLC_PLUGIN_LIBS := $(shell $(PKG_CONFIG) --libs vlc-plugin) VLC_PLUGIN_DIR := $(shell $(PKG_CONFIG) --variable=pluginsdir vlc-plugin) plugindir = $(VLC_PLUGIN_DIR)/misc override CC += -std=gnu99 override CPPFLAGS += -DPIC -I. -Isrc override CFLAGS += -fPIC override LDFLAGS += -Wl,-no-undefined override CPPFLAGS += -DMODULE_STRING=\ override CFLAGS += $(VLC_PLUGIN_CFLAGS) override LIBS += $(VLC_PLUGIN_LIBS) SUFFIX := so ifeq ($(OS),Windows_NT) SUFFIX := dll endif all: libhello_plugin.$(SUFFIX) install: all mkdir -p -- $(DESTDIR)$(plugindir) $(INSTALL) --mode 0755 libhello_plugin.$(SUFFIX) $(DESTDIR)$(plugindir) install-strip: $(MAKE) install INSTALL= uninstall: rm -f $(plugindir)/libhello_plugin.$(SUFFIX) clean: rm -f -- libhello_plugin.$(SUFFIX) src/*.o mostlyclean: clean SOURCES = hello.c $(SOURCES:%.c=src/%.o): $(SOURCES:%.c=src/%.c) libhello_plugin.$(SUFFIX): $(SOURCES:%.c=src/%.o) $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) .PHONY: all install install-strip uninstall clean mostlyclean
Dado que MSYS2 no sabe nada acerca de nuestro SDK para VLC, debe agregar la ruta a la carpeta
pkgconfig desde este SDK a la
variable de entorno
PKG_CONFIG_PATH . Abra la consola MinGW (
C: \ msys64 \ mingw64.exec ) y ejecute los comandos:
export PKG_CONFIG_PATH=/c/projects/vlc-3.0.8/sdk/lib/pkgconfig:$PKG_CONFIG_PATH make install
Para probar el complemento, ejecute VLC tambi茅n desde la consola:
/c/projects/vlc-3.0.8/vlc
Como en el caso de Linux, vaya a la configuraci贸n y active nuestro complemento. Guardamos la configuraci贸n y reiniciamos el VLC.
Implementaci贸n de complementos
Para implementar mi complemento, necesitaba entender c贸mo controlar el reproductor multimedia (cambiar la pista de audio, rebobinar) y c贸mo manejar los eventos de pulsaci贸n de teclas. Para entender todo esto, recurr铆 a la
documentaci贸n . Tambi茅n en Internet encontr茅 un par de art铆culos interesantes que arrojan luz sobre la arquitectura del reproductor multimedia:
la arquitectura del marco multimedia VLC y la
documentaci贸n API del reproductor multimedia VLC .
VLC consta de una gran cantidad de m贸dulos independientes (m谩s de 400). Cada m贸dulo debe proporcionar informaci贸n sobre el tipo de funcionalidad que implementa, as铆 como las funciones de inicializaci贸n / finalizaci贸n. Esta informaci贸n se describe en el
bloque vlc_module_begin () -
vlc_module_end () utilizando las
macros set_capability () y
set_callbacks () . Las funciones de inicializaci贸n / finalizaci贸n del m贸dulo (generalmente llamadas
Abrir y
Cerrar ) tienen la siguiente firma:
static int Open(vlc_object_t *) static void Close(vlc_object_t *)
vlc_object_t es el tipo base para representar datos en VLC, del cual se heredan todos los dem谩s (vea el art铆culo
Object_Management ). Un puntero a
vlc_object_t debe convertirse a un tipo de datos espec铆fico de acuerdo con la funcionalidad que implementa el m贸dulo. Para controlar el reproductor multimedia,
configuro el valor de
la interfaz en la macro
set_capability () . En consecuencia, en las funciones
Abrir y
Cerrar , necesito
enviar vlc_object_t a
intf_thread_t .
La interacci贸n entre los m贸dulos se basa en el patr贸n de dise帽o del
observador . VLC proporciona un mecanismo de
"variables de objeto" (consulte
Variables ), con el que puede agregar variables a instancias de tipo
vlc_object_t (y sus derivados). Los m贸dulos pueden intercambiar datos a trav茅s de estas variables. Tambi茅n puede adjuntar una funci贸n de devoluci贸n de llamada a la variable, que se llamar谩 cuando cambie el valor de esta variable.
Como ejemplo, considere el m贸dulo de teclas de
acceso r谩pido (
modules / control / hotkeys.c ), que es responsable de manejar los eventos de teclas de
acceso r谩pido. En la funci贸n Open, la funci贸n de devoluci贸n de llamada
ActionEvent se cuelga en la
variable clave-acci贸n :
var_AddCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf );
Un puntero a
vlc_object_t , un nombre de variable, una funci贸n de devoluci贸n de llamada y un puntero a anular se pasan a la funci贸n
var_AddCallback para pasar datos arbitrarios, que luego se reenv铆an a la funci贸n de devoluci贸n de llamada especificada. La firma de la funci贸n de devoluci贸n de llamada se muestra a continuaci贸n.
static int ActionEvent(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *)
Un puntero a
vlc_object_t , el nombre de la variable, los valores antiguos y nuevos de esta variable (en este caso, el identificador de la combinaci贸n de teclas de acceso r谩pido presionadas correspondiente de la acci贸n), as铆 como el puntero a cualquier dato adicional especificado al agregar la funci贸n de devoluci贸n de llamada, se pasan a la funci贸n de devoluci贸n de llamada .
El procesamiento directo de eventos de teclas de
acceso r谩pido se realiza en la funci贸n
PutAction , que se llama dentro de la funci贸n de devoluci贸n de llamada de
ActionEvent . La funci贸n
PutAction acepta un identificador de un evento de presionar una combinaci贸n de teclas de acceso r谩pido (
i_action ) y, con la ayuda del operador del interruptor, realiza las acciones correspondientes.
Por ejemplo, un evento de rebobinado corresponde a
ACTIONID_JUMP_BACKWARD_SHORT
. Para realizar la acci贸n correspondiente, el intervalo de rebobinado se toma de la configuraci贸n de VLC (de la variable
tama帽o de salto corto ):
mtime_t it = var_InheritInteger( p_input, varname );
Para rebobinar el archivo que se est谩 reproduciendo, simplemente configure la variable de
desplazamiento de tiempo en el valor correspondiente al tiempo (en microsegundos) por el que desea cambiar la reproducci贸n:
var_SetInteger( p_input, "time-offset", it * sign * CLOCK_FREQ );
Para el avance r谩pido, debe especificar un valor positivo, para el retroceso r谩pido: negativo. La
constante CLOCK_FREQ se usa para convertir segundos a microsegundos.
Del mismo modo, la pista de audio cambia (evento
ACTIONID_AUDIO_TRACK
). Solo la variable
audio-es responsable de la pista de audio puede aceptar un conjunto limitado de valores (de acuerdo con las pistas de audio disponibles en el archivo que se est谩 reproduciendo). Puede obtener una lista de posibles valores de una variable utilizando la funci贸n
var_Change () :
vlc_value_t list, list2; var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES, &list, &list2 );
Adem谩s de la lista de valores, esta funci贸n tambi茅n le permite obtener una lista de descripciones de estos valores (en este caso, el nombre de las pistas de audio). Ahora podemos cambiar la pista de audio usando la funci贸n
var_Set () :
var_Set( p_input, "audio-es", list.p_list->p_values[i] );
C贸mo administrar el reproductor multimedia descubierto, queda por aprender c贸mo manejar los eventos del teclado. Lamentablemente, no pude agregar una nueva tecla de acceso r谩pido. Todas las teclas de acceso r谩pido est谩n codificadas en el c贸digo del n煤cleo VLC (
src / misc / actions.c ). Por lo tanto, agregu茅 un controlador para los eventos de pulsaci贸n de teclas del teclado de nivel inferior, colgando mi funci贸n de devoluci贸n de llamada para cambiar la variable
presionada por la
tecla :
var_AddCallback( p_intf->obj.libvlc, "key-pressed", KeyboardEvent, p_intf );
La variable
presionada la tecla almacena el c贸digo de caracteres (en Unicode) correspondiente a la 煤ltima tecla presionada. Por ejemplo, cuando presiona la tecla con el n煤mero
"1" , a la variable
presionada se le asignar谩 el valor
49 (0x00000031 en el sistema de n煤mero 16). Puede ver otros c贸digos de caracteres en
unicode-table.com . Adem谩s, el valor de la variable
presionada por la
tecla tiene en cuenta la presi贸n de las teclas modificadoras, el cuarto byte significativo se les asigna. Entonces, por ejemplo, cuando presiona la
combinaci贸n de teclas "
Ctrl + 1 ", a la variable
presionada se le asignar谩 el valor 0x
04 000031 (00000
1 00 00000000 00000000 00110001
2 ). Para mayor claridad, la siguiente tabla muestra los significados de varias combinaciones de teclas:
Preste atenci贸n al valor al presionar la combinaci贸n "
Shift + 1 ". Ya que en este caso el "
! ", Entonces el valor del primer byte corresponder谩 al c贸digo de este car谩cter en Unicode (0x00000021).
Resultado
Llam茅 a mi complemento
TIP un acr贸nimo de la frase "traducirlo, por favor", tambi茅n la punta se puede traducir como "pista". El c贸digo fuente del complemento se publica en
GitHub , donde tambi茅n puede descargar ensamblajes de complementos listos para Windows y Linux.
Para instalar el complemento, debe copiar el archivo
libtip_plugin.dll (libtip_plugin.so para Linux) en la carpeta
<path-to-vlc> / plugins . En Windows, VLC generalmente se instala en la carpeta
C: \ Archivos de programa \ VideoLAN \ VLC . En Linux, puede encontrar la carpeta de instalaci贸n con el comando:
whereis vlc
En Ubuntu, por ejemplo, VLC est谩 instalado en
/ usr / lib / x86_64-linux-gnu / vlc .
A continuaci贸n, deber谩 reiniciar VLC, luego en el men煤 principal abra
Herramientas >
Preferencias , cambie a la vista avanzada (seleccione
Todo en el grupo
Mostrar configuraci贸n ), en el panel izquierdo vaya a la secci贸n
Interfaz >
Control y marque la casilla junto a
CONSEJO (traduzca, por favor) . Por otra parte, deber谩 reiniciar el VLC.

En la configuraci贸n del complemento, puede especificar los n煤meros de las pistas de audio principal y auxiliar (para traducci贸n), as铆 como el tiempo (en segundos) por el cual el complemento se rebobinar谩 para repetir con la pista de audio auxiliar.

Para controlar el complemento, agregu茅 los siguientes m茅todos abreviados de teclado:
- " / " Para traducci贸n
- " Shift + / " para repetir el fragmento de video traducido previamente con la pista de audio principal
Durante la ejecuci贸n de los comandos de traducci贸n y reintento, el complemento muestra los mensajes
"CONSEJO: traducir" y
"CONSEJO: repetir" en la esquina superior izquierda
, respectivamente.

Desde mi experiencia con el complemento, puedo decir que, en general, estoy satisfecho con el resultado. Lo principal es elegir el contenido correcto, si se entiende al menos la mitad del discurso extranjero utilizado all铆, el complemento ayudar谩 a traducir el resto. De lo contrario, el complemento probablemente ser谩 in煤til.