Archive for the ‘computação’ Category

Como escrever números por extenso

julho 30, 2009

Precisei escrever uma rotina para escrever números por extenso de até R$ 999.999,99 por extenso. Fiz um programinha em Java e depois converti para VBA, para ser usado no Excel. A rotina não está otimizada e nem muito genérica. Mas se alguém precisar de algo mais genérico (para números maiores), é só pegar o código e estender, está bem simples.

Código em Java:

extenso java

Saída:

extenso saida
Código em VBA:

extenso vba

Como usar no Excel:

extenso vba uso 1

extenso vba uso 2

TV Digital Interativa

janeiro 1, 2009

Introdução

O objetivo deste documento é discorrer um pouco sobre a TV Digital Interativa (TVDI), falando sobre o estado da arte, estado atual, aplicações típicas da TVDI, middlewares, API para construção do software para TVDI entre outros.

O estado da arte em mídias interativas

O mais alto nível de interatividade é aquele em que o usuário (telespectador) se sente dentro da aplicação ao qual ele está submetido, por exemplo, vendo um filme sobre o reino animal marinho, o telespectador se sente dentro do mar, vendo a paisagem marinha e peixes a sua volta. É nesse nível de interatividade que estamos interessados neste documento, na interatividade em que o telespectador se sente dentro do mundo virtual.

A primeira características desses mundos virtuais é a noção de 3 dimensões. A noção de profundidade é originada a partir de algumas características da imagem, como a tonalização e o sombreamento.

Uma das formas de se obter imagens 3D é combinar duas imagens 2D (estereopsia). Atualmente já existem alguns dispositivos óptico-eletrônicos capazes de introduzir essa noção de 3D. Esses sistemas podem ser classificados em 3 grupos:

  1. Sistemas auto estereoscópicos: São sistemas em que o usuário não precisa de dispositivos especiais para obter o efeito de estereopsia.
  2. Sistemas estereoscópicos multiplexados em tempo: Sistemas em que um dispositivo realiza a separação do par de imagens estereoscópicas para cada olho do usuário.
  3. Sistemas estereoscópicos paralelos no tempo: São aqueles em que o par de imagens estereoscópicas são apresentados simultaneamente ao usuário que faz uso de óculos polarizadores para realizar a separação de imagens.

Uma outra forma de se obter imagens 3D é através da utilização de tecnologias de projeção de imagens.

Outra característica para se sentir imerso no mundo virtual é a interação táctil, ou seja, sentir o mundo virtual através do tato. Para fornecer o sentido do tato, os dispositivos atuais usam motores elétricos, pistões hidráulicos e bolsas pneumáticas, conseguindo sensação de toque e de força. Um avanço da pesquisa atual nessa área permite simular também a força de retorno entre a interação entre o objeto virtual e o usuário. Hoje já existem dispositivos que fazem isso, como o Phanton Desktop, um sistema utilizado para treinamento de transplante de medula óssea.

O estado da arte na TVDI

A TVDI foi concebida para ser interativa, mas o que significa essa interatividade?

A TV Digital não é uma simples televisão e muito menos um computador, ela é “algo” entre esses 2 termos. Ela é como se fosse uma televisão onde pequenos programas de computador possam rodar sobre ela. Esses programas rodam num sistema com poucos recursos, diferentemente do PC. A interatividade na TVDI significa simplesmente o retorno de pequenas informações por parte do usuário.

O que existe de mais avançado hoje em termos de interatividade na TV Digital é o uso de um canal de retorno permanente de alta velocidade, um teclado, um mouse e um controle remoto.

O canal de retorno é utilizado no envio de informações pelo usuário para o seu provedor de serviço, emissora, enfim, entre o usuário e o resto do mundo. Esse canal de retorno pode ser de qualquer tipo, um modem PSTN, cable modem, ADSL, Ethernet, qualquer coisa. O que importa é que a conexão deva suportar o protocolo TCP/IP.

Atualmente a entrada de informações pelo o usuário pode ser feita através de um controle remoto, teclado e mouse, porém nada impede que no futuro também sejam utilizados dispositivos táctis e óculos de visualização 3D (veja seção anterior).

O formato de vídeo utilizado é o MPEG-4.

O estado atual da TVDI

O canal de retorno nem sempre possui conexão 24 horas por dia e por isso a interatividade da TVDI pode ser classificada em 3 níveis:

  • Nível 1: Interatividade Local: A emissora transmite vários programas ou opções adicionais e o usuário pode escolher entre uma programação e outra ou habilitar/desabilitar as opções;
  • Nível 2: Retorno solicitado pelo provedor: Neste nível de interatividade o usuário pode apenas responder aos aplicativos enviados pelo provedor;
  • Nível 3: Acesso livro a Internet: O usuário pode navegar pela Internet e ter acesso a seus recursos.

Aplicações diferentes podem ser construídas baseadas nesses 3 níveis de interatividade.

Na seção anterior foi dito que a entrada de informações pelo usuário é feita através de controle remoto, teclado e mouse. Na prática quase não existe teclado e mouse e podemos contar somente com a existência do controle remoto. Aplicações diferentes também são construídas com base na presença ou ausência de cada um desses dispositivos.

O formato de vídeo utilizado é o MPEG-4 e a API JavaTV é utilizada na construção de softwares para a TVDI.

Aplicações

As aplicações para TVDI podem ser classificadas em três grupos básicos sendo estes o grupo de Entretenimento, TV-Comércio e Comunicação sendo os limites de definição destes três grupos bastante flexíveis pois uma mesma aplicação pode ser classificada em um ou mais destes grupos.

Dentre as aplicações para a área de entretenimento podem ser citadas o EPG (Electronic Program Guide), vídeo sob demanda (VOD), jogos em ambiente multiusuário, programas de auditório com jogos interativos, programas de esportes com participações do usuário, e outros.

Dentre as aplicações para a área de TV-comércio podem ser citados o sistema de compras, controle bancário, comerciais interativos e distribuição de música.

Dentre as aplicações para a área de comunicação podem ser citados o sistema de email, Internet e chat.

TV-Comércio

A TV interativa oferece grandes possibilidades no que se refere a área de marketing de forma a personalizar o conteúdo a ser oferecido combinando o mesmo com o perfil do usuário. Desta forma, os anúncios podem ser melhor direcionados a seu público alvo trazendo como feedback a  resposta dos usuários a estes anúncios.

De uma forma geral, anúncios para TV interativa encorajam os expectadores a acessarem conteúdos personalizados dispostos em pontos estratégicos na tela, de forma que quando acionados direcionam o usuário a um site, exibido em parte da tela da TV enquanto o comercial continua a ser executado em segundo plano. O site acionado traz informações adicionais sobre o produto que não estão disponíveis no comercial e podem oferecer aos consumidores a possibilidade de efetuar uma compra acionando o controle remoto.

EPG

EPG é um serviço básico da TVDI que inclui informações de conteúdo e horários para a programação disponível para TV, ou seja, é um Guia de Programação Eletrônico.

Tipicamente os EPGs são controlados e preparados por um provedor de serviços que faz a listagem e controla um canal dedicado de EPG que normalmente exibe a listagem de programação dos canais afiliados ao proprietário do canal EPG.

EPGs normalmente oferecem um mínimo de funcionalidade como sistema de busca e navegação dentre as opções disponíveis, exibição de informações detalhadas do programa selecionado,  filtragem de conteúdo com base  no gênero, etc.

Uma modalidade mais simplificada do EPG é a representada por mini-guias que correspondem a outra poderosa ferramenta de busca. Os mini-guias minimizam a interrupção da programação corrente enquanto oferece a funcionalidade de busca. Tipicamente um mini-guia é exibido na parte inferior da tela.

Video-sob-Demanda (VOD)

Com os serviços de vídeo sob demanda, os usuários podem escolher os programas que desejam assistir em qualquer momento. O sistema de VOD converte o receptor de TV interativa em um sistema de aluguel de vídeos. Com a disponibilidade de centenas de vídeos para seleção, a aplicação VOD está relacionada ao processo de busca, navegação e seleção dos vídeos as quais são realizadas através dos guias de VOD que se assemelham em linhas gerais ao EPG. O processo de seleção de um vídeo normalmente passa por quatro estágios:

  1. Procura: o usuário aciona uma página de pesquisa contendo um formulário que permite a especificação dos atributos do filme desejado. Uma forma comum é a utilização de palavras chaves onde as mais utilizadas podem inclusive estar pré-programadas através da combinação de teclas do controle remoto ou teclado.
  2. Pré-visualização: O usuário seleciona um filme e solicita a exibição da descrição e trailer do mesmo.
  3. Seleção: O usuário tem a opção de selecionar o vídeo pré-visualizado ou voltar para a tela anterior de busca. Se o vídeo é selecionado para exibição, uma sessão VOD é inicializada possivelmente seguida por uma tela de confirmação de transação, e o processo continua para o passo quatro.
  4. Exibição do vídeo: Finalmente o vídeo é exibido através de uma sessão VOD.

Guias VOD podem ser implementados via broadcast como através da Internet via provedor de serviços Internet sendo que esta última alternativa normalmente trará respostas mais lentas, mas por outro lado terá um custo reduzido em comparação com a primeira alternativa.

Jogos

O usuário acessa um canal dedicado de jogos onde é requisitado a entrar com um nome que identifica o perfil do usuário para jogos. Em seguida uma lista de jogos é apresentada onde os jogos são classificados como multiusuário ou um jogador somente. No índice de jogos, cada jogo pode possuir uma breve apresentação em forma de animação e texto. Quando for o caso, ao selecionar o jogo, pode ser dada ao usuário a possibilidade de retomar a um último estágio gravado do jogo. Da mesma forma, durante o jogo pode ser oferecida a opção de salvar o estágio atual.

Na finalização do jogo, o placar pode ser comparado com as maiores pontuações publicadas semanalmente. Em determinados casos, o usuário pode se juntar a um grupo de jogadores que competem com outro grupo. Caso a pontuação seja suficientemente alta, podem ser oferecidas ao usuário algumas bonificações, como por exemplo milhagens em programas de empresas aéreas, ou ainda a opção de salvar o estágio atual por uma pequena taxa.

Programas de auditório com jogos interativos

Shows com jogos interativos possuem inúmeras variações. Os mais desafiadores são aqueles que apresentam cenário de competições em tempo real entre os expectadores de um show. Por exemplo, no início de um show, o usuário seleciona a opção de participar do jogo sendo que se esta opção não for acionada, o show é exibido sem interatividade. Caso a opção de participação tenha sido acionada, em determinados momentos do show as perguntas serão apresentadas ao usuário participante o qual terá a opção de respondê-las o que, por sua vez, fará com que sua pontuação  aumente caso as respostas tenham sido escolhidas corretamente. Caso a pontuação do usuário seja suficiente, ele poderá ser recompensado com algum tipo de premiação. Dependendo das regras do jogo, quando aplicável, uma resposta incorreta pode suprimir questões subseqüentes até que uma nova sessão seja inicializada.

Programas musicais interativos

De forma geral, as aplicações interativas deste grupo serão realizadas offline através do uso de material armazenado onde o usuário pode, dentre outros, selecionar para exibição vídeos a partir de uma coleção de componentes de vídeos sincronizados, selecionar, a partir de determinados pontos estrategicamente posicionados na tela, outras câmeras que resultarão em novos ângulos de visão do show, apresentação de informações adicionais sobre o show e seus participantes, download de músicas ou amostras de músicas, etc. Em caso de shows musicais realizados ao vivo, a interação com o usuário não pode ser implementada de forma satisfatória.

Programas educacionais interativos

A área educacional abre inúmeras possibilidades em termos de interatividade com o usuário. As aplicações deste grupo oferecem várias possibilidades de intervenção do usuário que vai desde a escolha da linguagem de áudio dentre as disponíveis até o acionamento de opções dispostas como ícones ou texto em posições estratégicas na tela que quando selecionadas complementam o conteúdo exibido a partir de outros vídeos, textos, páginas web, etc.

Como exemplos de aplicações nesta área podemos citar documentários interativos, cursos on-line, testes de conhecimento on-line e tira-dúvidas on-line em forma de chat.

Canais de notícias interativos

Abaixo da tela de exibição do vídeo de notícia há a apresentação de texto adicional em forma de barra de texto rolante na qual, após ser clicada, abre uma ou mais telas sobrepostas ao vídeo, então em segundo plano, apresentando informações adicionais, vídeos, imagens, etc, a fim de complementar a notícia principal e/ou explicar o texto inicialmente apresentado abaixo do vídeo principal de notícias.

Canais de esportes interativos

Assim como nos programas de música interativos, o usuário tem acesso as opções dispostas na tela que depois de selecionadas permitem a escolha de exibição através de outras câmeras, informações adicionais sobre os jogadores, times e outros assuntos relacionados.

É possível ainda o processo de comercialização de produtos dos times relacionados através do acionamento das opções correspondentes.

Canais com informações de transportes

As aplicações deste grupo basicamente se encaixam em monitoração de horário de chegada e partida de vôos no aeroporto local ou outros aeroportos e serviços de apresentação de mapas e direções a partir de um endereço digitado ou de critérios especificados em uma página de busca.

Canais de comércio

As aplicações deste grupo podem ser usadas em conjunto com outros tipos de aplicação, como, por exemplo, a possibilidade de adquirir determinado produto a partir de um anúncio ou da exibição de um jogo em um canal de esporte interativo, bem como pode haver canais dedicados à comercialização de produtos de determinada empresa ou conjunto de empresas.

As aplicações para TV-comércio devem oferecer opções através do acionamento das quais o usuário possa obter informações adicionais sobre o produto em questão, informações sobre produtos similares de outras marcas e produtos correlacionados ao produto exibido.

Middlewares

Atualmente existem basicamente 3 padrões de TV Digital no mundo, o europeu (DVB), americano (ATSC) e japonês (ISDB). Cada um desses modeles especifica um middleware, que pode ser imaginado como sendo o contexto onde a aplicação é executada. Assim como existem 3 padrões, existem também basicamente 3 tipos de middleware: MHP (europeu), DASE (americano) e ARIB (japonês).

Para a criação de software para a TV Digital é utilizada a API JavaTV, que nada mais é que um conjunto de API da linguagem Java. Dessa forma, utilizar somente a API JavaTV para o desenvolvimento da aplicação garante que ela será portável entre todos os tipos de middleware. Entretanto, existem bibliotecas de terceiros que também são utilizadas, como por exemplo a biblioteca do pacote org.dvb.*, que são utilizadas para construção de aplicações exclusivas para o middleware MHP.

Na próxima seção falaremos um pouco de algumas APIs utilizadas para a construção de aplicações para a TV Digital, utilizando a API JavaTV e a API do pacote org.dvb.* e seus subpacotes. Lembre-se de que a aplicação que só utiliza a primeira dessas é portável entre todos os middlewares e as aplicações que utilizam a segunda só é executada no middleware MHP.

Programando para a TVDI – A API JAVATV

Na seção “Aplicações” descrevemos um conjunto de aplicações de exemplo para a TVDI. Nesta seção mostraremos pequenos trechos de códigos que podem ser utilizados para a construção de uma dessas aplicações.

Gerenciar o ciclo de vida da aplicação

Existem 2 tipos de aplicações MHP: DVB-HTML e DVB-J. A primeira é baseada em HTML e a segunda em Java. Aplicações DVD-HTML são ramentes utilizadas e por isso o foco nesse trabalho será nas aplicações DVB-J, que também são chamadas de Xlets.

O conceito dos Xlets é semelhante aos dos Applets, Servlets ou Midlets, ou seja, possui um ciclo de vida, gerenciado pelo container. Assim como o browser gerencia o ciclo de vida de um applet e um container web gerencia o ciclo de vida de um servlet, o middelware gerencia o ciclo de vida do Xlet. A partir desse momento, serão discutidos algumas tópicos relacionados a Java, caso o leitor não esteja familiarizado com essa linguagem, uma ótima referência é o livro Thinking in Java, disponível para download no site http://www.bruceeckel.com.

Em Java, um Xlet é todo objeto que implementa a interface javax.tv.xlet.Xlet. Essa interface define quatro métodos, exibidos na listagem 1. Cada método nessa interface tem um papel importante no gerenciamente do ciclo de vida do Xlet.

listagem1

Listagem 1 – javax.tv.xlet.Xlet

O clico de vida dos Xlets passa pelo seguinte fluxo:

  1. O Xlet é carregado (através do comando Class.forName()) e uma instância sua é criada usando o construtor default. Nesse ponto ele está no estado Loaded;
  2. Quando o usuário resolve iniciar a aplicação, o método initXlet() é chamado naquela instância carregada. O Xlet vai para o estado Paused. É passado para o método initXlet uma instância representa o contexto do Xlet, do tipo javax.tv.xlet.XletContext;
  3. Quando initXlet() retorna, o gerenciador de aplicações chama o método startXlet(). O Xlet move para o estado Started. É nesse estado que a interação com o usuário é realizada;
  4. Durante a execução da aplicação, o gerenciador de aplicativos pode chamar o método pauseXlet(), movendo a aplicação novamente para o estado Paused;
  5. Os passos 3 e 4 podem ser executados inúmeras vezes;
  6. O gerenciador de aplicativos pode chamar o método destroyXlet() movendo o Xlet para o estado Destroyed e liberando todos os seus recursos;

Esse é o ciclo de vida do Xlet, e todas as aplicações baseadas DVB-J seguem esse ciclo. Uma figura importante é o contexto do Xlet passado como parâmetro para o método XletContext. XletContext representa o contexto do Xlet (alguma semelhança com ServletContext?), e sua interface aparece na listagem 2.

listagem2Listagem 2 – javax.tv.xlet.XletContext

XletContext é utilizado pelo Xlet para obter informações sobre o seu ambiente e informar algumas coisas a respeito do seu ciclo de vida. Os métodos notifyDestroyed(), notifyPaused() permite ao Xlet notificar que ele está mudando para o estado Destroyed/Paused. O método resumeRequest() envia uma requisição pedindo que o Xlet volte para o estado Started. O método getXletProperty() é utilizado para obter algumas informações do ambiente, como por exemplo os parâmetros passados para a aplicação, ou o ID da organização da aplicação.

Embora seja uma forma de acessar propriedades do contexto do Xlet, XletContext não é a única forma de objter informações. O comando System.getProperties() ou System.getProperty() também pode ser utilizado, porém somente algumas propriedades são suportadas de acordo com a especificação:

  • file.separator;
  • path.separator;
  • line.separator;
  • dvb.persistent.root;

Nesse ponto deve ter ficado claro para o leitor os estados do ciclo de vida de um Xlet, quando o Xlet muda de estado e os métodos chamados no Xlet a cada mudança de estado.

Gerenciar recursos

Por mais simples que seja a aplicação, vários recursos podem ser utilizados, a quantidade de recursos de um middelware é baixa e por isso é necessário um esquema de gerenciamento de recursos. Algumas API’s da MHP são baseadas na API de notificação de recurso DAVIC contidas no pacote org.davic.resources. Essa API foi criada para ser utilizada com outras API’s.

A interface ResourceServer é implementada por uma classe na API. Ela é reponsável por gerenciar acessos a recursos escassos e gerenciar como esses recursos são alocados. Essa interface permite que uma aplicação se registre como um listener para eventos indicando mudança no status do recurso. Sua assinatura está na listagem 3.

listagem3Listagem 3 – org.davic.resources.ResourceServer

Assim como existe a interface ResourceServer, existe também a versão cliente, ResourceClient. Essa interface é implementada por uma classe da aplicação MHP, ela gerencia o uso do recurso pela aplicação. Por exemplo, quando o middelware precisa do recurso, ele notifica a aplicação através dessa classe. Sua listagem pode ser visualizada na listagem 4.

listagem4Listagem 4 – org.davic.resources.ResourceClient

Os três métodos dessa interface possuem a mesma utilidade, indicam uma requisição ao recurso, um pedido para que ele seja liberado pela aplicação:

  • requestRelease: O middelware pede o recurso a aplicação. Caso a aplicação libere o recurso, true é retornado, caso a aplicação não libere, é retornado false; A aplicação não é obrigada a liberar o recurso;
  • release: Se a aplicação resolve não liberar o recurso, o middleware pode exigir que o recurso seja liberado, chamando o método release;
  • notifyRelease: Caso o método release não retorne, como por exemplo, num loop infinito (código malicioso), o recurso é tomado da aplicação e notifyRelease é chamado, informando à aplicação que aquele recurso está sendo tomado.

Como podemos observar na listagem 4, ResourceProxy é passado como parâmetro para os métodos da interface. Um objeto do tipo ResourceProxy representa o acesso ao recurso. Por questões de segurança, um recurso não é acessado diretamente pela aplicação, e sim através de um proxy. O proxy é que tem acesso ao recurso.

Deve estar claro ao leitor a necessidade do middelware implementar um esquema de gerenciamento de recursos, afinal o middelware não é um PC e seus recursos são escassos.

Interface gráfica

Independente da aplicação, uma aplicação pra TV Digital deve no mínimo exibir alguma coisa na tela e por isso vamos descrever algumas partes sobre como a especificação MHP trata interfaces gráficas. A especificação MHP usa parte da AWT (API para desenhar interface gráfica de Java) e da API GUI da especificação HAVi.

Algumas considerações fazem da parte gráfica uma das partes mais complicadas da especificação MHP. Para desenhar na tela, várias coisas devem ser levadas em consideração, entre elas:

  1. Aspect Ratio: A TV pode ter relação de aspecto de 4:3, ou 16:9, e isso muda a forma como as coisas são desenhadas na tela;
  2. Transparência;
  3. Espaço de cores. Java usa RGB e o sinal de TV é baseado em crominância e luminância.
  4. Como converter entre um e outro?
  5. Não existe gerenciador de janelas;

A API para interface gráfica com usuário (GUI) da HAVi foi adotada pela DVB para o uso no MHP.

O display da TV digital pode ser dividido em 3 camadas:

  1. Camada de fundo (Background Layer): Exibe um fundo fixo, com uma cor ou uma imagem estática;
  2. Camada de vídeo (Video Layer): Camada onde o vídeo é exibido. É exibido em cima da camada de fundo;
  3. Camada de gráficos (Graphics Layer): É a última camada, onde as aplicações gráficas em MHP trabalham.

A API para manipulação gráfica da HAVi define uma classe HScreen para representar o dispositivo gráfico. Existe somente uma instância dessa classe pra cada dispositivo gráfico.Cada HScreen tem um conjunto de HScreenDevice, que representa as camadas do display. Como existem 3 camadas, existem também 3 subclasses de HScreenDevice:

  1. HBackgroundDevice: Representa a camada de fundo;
  2. HVideoDevice: Representa a camada de video;
  3. HGraphicsDevice: Representa a camada de gráficos.

Para obter informações a respeito dessas camadas, é necessário o uso de uma outra classe, HScreen, definida na listagem 5. HScreen representa o dispositivo físico, a tela, e só existe uma instância de HScreen por dispositivo.

Como podemos observar, a classe HScreen fornece métodos getter para a camada padrão de fundo, vídeo e de gráficos. Além disso, HScreen fornece métodos getter também para as outras possíveis classes do tipo HScreen que possam existir (caso tenha mais de um dispositivo de tela).

Ainda na listagem 5, podemos observar a existência de métodos getter para HVideoDevice e HGraphicsDevice onde o retorno é um array desses objetos. Isso é porque, diferentemente de HBackgroundDevice, podem existir vários devices desses outros tipos. Por exemplo, durante um jogo de futebol podemos ter um HVideoDevice principal mostrando o jogo e um HVideoDevice secundário mostrando o jogo sob um outro ângulo, no canto da tela. Nesse caso, teríamos 2 HVideoDevice. Em relação a HGraphicsDevice, pode existir um HGraphicsDevice para cada camada (se isso for suportado), e nesse caso também podem existem inúmeras instâncias de HGraphicsDevice.

listagem5Listagem 5 – org.havi.ui.Hscreen

Cada camada pode ser configurada separadamente, usando a própria classe HBackgroundDevice, HGraphicsDevice e HVideoDevice. Para isso, é definido uma outra classe HScreenConfiguration. É claro que HScreenConfiguration possui subclasses personalizadas para cada tipo de device (background: HBackgroundConfiguration, video: HVideoConfiguration, graphics: HGraphicsConfiguration).

Quando se faz um programa desktop para PC e usamos AWT, a classe de janela extende a classe Frame. Em aplicações MHP isso não é mais possível, pois no set-top-box não podemos contar com o mesmo gerenciador de janelas implementado é igual ao do PC, principalmente pela quantidade de recursos disponíveis. Sendo assim, é necessário definir outra forma de criar janelas, e por isso foi definida a classe HScense.

Como não podemos contar com um gerenciador de janelas, não podemos criar uma aplicação com mais de um HScense (janela) por dispositivo (HScreen). Outra diferença para o Frame é o mode de criar o HScense. Para criar um HScense, é usada uma factory, HScenseFactory. Para isso, é passado como parâmetro para a factory um objeto do tipo HScenseTemplate, que representa a configuração da tela que o usuário deseja. A listagem 6 e 7 exibe a assinatura das classes HScenseFactory e HScenseTemplate.

Como podemos observar na listagem 6, HsceneFactory também é um Singleton, e por isso não pode ser instanciado diretamente. Para ter acesso ao objeto é necessário chamar o método  HSceneFactory.getInstance().

listagem6Listagem 6 – org.havi.ui.HSceneFactory

listagem7Listagem 7 – org.havi.ui.HSceneTemplate

Player MPEG (Áudio e Vídeo)

A parte mais importante para um TV Digital é o player MPEG, pois sem ele não é possível exibir áudio e vídeo. O Framework escolhido para tocar mídia foi o Java Media Framework (JMF) versão 1.1. Logo, para entender como o MHP trabalha com mídias, é necessário entender o Java Media Framework. JMP possui os conceitos de Player, Control e DataSources:

  • Player: Faz a decodificação da mídia e toca;
  • Control: Adiciona funcionalidades a Player (design pattern Decorator),como por exemplo congelar a imagem.
  • DataSources: Representa a mídia. Um Player não pode ser criado sem um DataSource;

O ponto de partida para a criação de uma aplicação que usa JMF é o uso da classe Manager, definida na listagem 8.

listagem8Listagem 8 –  javax.media.Manager

Como podemos observar na listagem 8, existem  métodos estáticos na classe Manager que possibilita a criação de DataSource (createDataSource()) e Player (createPlayer()). A idéia é criar um DataSource, que aponta para os dados, e aí sim criar o Player, que está vinculado àquele DataSource. Por serem classes importantes, DataSource aparece na listagem 9 e Player aparece na listagem 10.

listagem9Listagem 9 – javax.media.DataSource

A classe DataSource é bem simples, basicamente ela fornece métodos para conectar o DataSource a sua fonte de dados (connect()), saber que tipo de dados é aquela fonte (getContentType()), iniciar (start()) e parar (stop()) a transferência daqueles dados, e, quando não for mais necessário o uso do DataSource, se desconectar da fonte (disconnect()).

A interface Player já é mais complicada, a listagem 10 mostra parte da interface. Como podemos observar nessa listagem, a implementação de Player perrmite alterar a fonte de dados (setSource() – Obs.: Na implementação MHP, não se usa esse método para trocar a fonte de dados).

Um objeto do tipo Player possui estados. Quando o Player é criado, ele está no estado Unrealized. Se o método realized() é chamados, o Player vai para o estado Realized. Isso dá ao Player a possibilidade de carregar todos os recursos que ele necessita para efetivamente tocar a mídia. O método prefetch() move o Player para o estado Prefetch. Nesse estado, é garantido que todos os recursos foram carregados e que o Player já pode tocar a mídia. O último estado de Player é Started, que é quando o método start() é chamado. Nesse estado, a mídia é tocada. No estado Started, Player pode voltar para o estado Prefetch ou Realized se for chamado o método stop(). Qual o estado será chamado dependerá do tipo de mídia que está sendo tocada. O método deallocate() desaloca recursos escassos e volta o estado para Realized, caso o estado seja Realized, Prefetch ou Started, ou volta para o estado Unrealized, caso ele ainda esteja na transição de Unrealized para Realized.

O método  addControllerListener() permite que eventos sejam registrados na classe Player. Dessa forma, quando houver alguma mudança no estado de Player, a aplicação será notificada através desses eventos. Existem eventos para notificar mudanças no estado de Player, notificar problemas com a conexão com o DataSource, saber da situação dos recursos escassos, entre outros.

listagem10Listagem 10 –  javax.media.Player

É importante observar que fazer uma aplicação que utiliza JMF no desktop é diferente do que fazer uma aplicação que utiliza JMF na TV Digital. Apesar da similaridade no modo de programar, existem várias diferenças, pois o que funciona de um jeito no aplicativo desktop, pode não funcionar num ambiente de broadcast. Algumas vezes o problema pode ser resolvido com a classe Control, que adiciona funcionalidades ao Player.

No MHP, o vídeo é recebido no formato MPEG, que nada mais é do que uma sequência de quadros comprimidos. MHP decodifica essa sequência de quadros e exibe o filme na camada de vídeo ou na camada de gráficos (veja seção 2.3). Para isso, existem 2 tipo de Players na JMF, uma para exibição do vídeo na camada de vídeo e outro que exibe um vídeo num compoente AWT na camada de gráficos. A primeira opção deve sempre ser suportado, a última não. A figura 1 mostra como fica o esquema das camadas nesse caso. As 3 camadas (Background, Video e Graphics) continuam normalmente, e um componente AWT é criado em cima da camada Graphics, com um vídeo rodando dentro desse componente. Quando o componente é movido, ao tem seu tamanho alterado, o vídeo também é movido ou tem o seu tamanho alterado.

figura11Figura 1 – Componente AWT rodando vídeo MPEG

Canal de retorno

Como já foi dito na seção “O estado da arte na TVDI”, o canal de retorno é a forma utilizada para a aplicação se comunicar com o mundo externo. Essa comunicação pode ser feita através de um modem, ADSL, ou qualquer outra forma, a única exigência é que ela suporte TCP/IP.

Para o programador, conectar com o mundo significa usar a API java.net, que assim como a AWT e JMF, tem algumas restrições no seu uso quando utilizada junto com MHP. A principal diferença é que java.net supõe que exista uma conexão permanente com a Internet, o que não é verdade no caso da TV Digital. Para suprir essa diferença, é necessário o uso de uma outra API, definida no pacote org.dvb.net.rc.

O canal de retorno é representado pela classe RCInterface (note que apesar da existência da palavra interface no nome, RCInterface é uma classe!), que possui uma subclasse, ConnectionRCInterface, que representa um canal de retorno que não está permanentemente conectado. A classe ConnectionRCInterface aparece na listagem 11.

Como podemos observar na listagem 11, ConnectionRCInterface possui métodos para controlar a conexão do canal de retorno (isConnected(), connect(), disconnect(), getConnectedTime()), setar os parâmetros de inicialização da conexão (setTarget()), controlar os eventos que ocorrem na conexão através de notificações (addConnectionListener(), removeConnectionListener()) entre outros métodos.

Ainda pela listagem 11, podemos observar que ele implementa a interface ResourceProxy, ou seja, ConnectionRCInterface representa também um recurso escasso, e toda a discussão da seção 2.2 se aplica também a ConnectionRCInterface. Por ser um recurso escasso, o acesso a ele é gerenciado através de uma outra classe, RCInterfaceManager. A listagem 12 mostra um exemplo de como obter o canal de retorno.

listagem11Listagem 11 –  org.dvb.net.rc.ConnectionRCInterface

listagem12Listagem 12 – Obtendo o canal de retorno

A listagem 12 mostrou como obter o canal de retorno. Além disso, é necessário fazer a conexão com o canal de retorno (lembre que a conexão não é permante!). Para isso é necessário informar onde o canal de retorno deve conectar (método setTarget()) e depois chamar o método connect(). A listagem 13 exemplifica o processo.

listagem13Listagem 13 – Estabelecendo uma conexão com o canal de retorno

É importante resaltar que a listagem 13 deve estar envolvida num bloco try-catch, pois a exceção PermissionDeniedException pode ser lançada na tentativa de conexão.

Múltiplos serviços

A primeira questão a ser tratada aqui é que agora o middleware possui duas aplicações. Como passar de uma para a outra? Aqui entra em cena a API de seleção de serviços da JavaTV. Nesse caso, selecionar um serviço pra ser executado pode matar a execução do outro serviço que estava rodando. Na terminologia da API JavaTV, um serviço é um conjunto de áudio e/ou vídeo e/ou aplicações que agrupadas formam uma entidade (que juntas fazem algum sentido).

A idéia de uma aplicação matar a outra é a seguinte. Podem existir vários contextos de serviços rodando, mas em cada um deles só pode ser rodado um serviço de cada vez. Quando a aplicação vai ser executada, ela deve rodar em cima de algum contexto. Se já existir uma aplicação rodando nesse contexto, ela será destruída para que a outra possa ser executada.

Deve ser ressaltado aqui que a API de seleção de serviços deve ser utilizada quando estamos em um serviço e queremos carregar um outro. No nosso exemplo de aplicações, estávamos no serviço Fale Conosco. Nesse serviço, poderia existir um botão que abriria um novo serviço (uma espécie de hyperlink), a declaração de isento do imposto de renda. Nesse caso, estamos abrindo uma nova aplicação, e a API de seleção de serviços deve ser utilizada. Se o que tivesse que ser feito fosse na verdade trocar o vídeo que estava sendo exibido na aplicação, isso poderia ser feito com a JMF, e não seria necessário usar a API de seleção de serviços.

listagem14Listagem 14 – Selecionando um novo serviço

A API possui duas interfaces principais, Service e ServiceContext. Com uma instância de ServiceContext, podemos rodar uma aplicação (Service). Para obter um ServiceContext ou criar um novo, é utilizada a classe ServletContextFactory, que como o próprio nome diz, é um fábrica de objetos do tipo ServletContext. Além de implementar o design pattern Factory, ServletContextFactory também implementa o design pattern Singleton.

A listagem 14 mostra passo a passo como obter um ServletContext e adicionar um serviço a ele.

Observação

Esse trabalho foi feito já tem um tempo (entre 3 e 4 anos). Muita coisa aqui pode estar defasada (e provavelmente está), mas é um ponto de partida para um estudo sobre o assunto. Todas as informações disponíveis aqui foram coletadas na Internet.

Como calcular a área de um polígono irregular

dezembro 5, 2008

Recentemente precisei calcular a área de um polígono irregular. Mas como? Fiz uma pesquisa sobre geometria computacional, e uma das formas que encontrei foi em dividir o polígono em vários triângulos e, após isso, calcular a área de cada triângulo. Tudo bem, mas como dividir o polígono em vários triângulos menores? Por exemplo, como dividir automaticamente o polígono da figura 1 em triângulos? Existem algoritmos para isso, para fazer a triangulação de polígonos.

triangulacao

Figura 1 – Um polígono dividido em vários triângulos

Basicamente o algoritmo funciona da seguinte forma. Divide o polígono em vários polígonos monotone* e depois faz a triangulação de cada um desses algoritmos usando um algoritmo para fazer a triangulação.

Essa é uma das formas de se fazer isso. Uma outra forma é baseada na técnica descrita no post “Como calcular computacionalmente o valor de PI“. Nesse caso podemos fazer o seguinte. Desenhamos o polígono em cima de um outro polígono já conhecido, no caso um retângulo. Sabemos como calcular a área do retângulo. Depois disso, começamos a gerar pontos aleatórios dentro do retângulo (o polígono que queremos calcular a área está em cima do retângulo). Para cada ponto, vemos se o ponto caiu dentro do polígono irregular. Se dividirmos a quantidade de pontos que caiu dentro do polígono pela quantidade de pontos gerada, temos a relação entre a área do polígono e a área do retângulo. Como a área do retângulo é conhecida, fica simples calcular a área do polígono, basta fazer uma multiplicação.

No entanto, fica a questão: Como saber se um ponto está dentro do polígono?  Para efeitos práticos para o cálculo da área dessa forma, podemos traçar uma semi-reta paralela ao eixo x em direção a +x. Se essa semi-reta interceptar um número ímpar de arestas, podemos dizer que ele está dentro do polígono – Figura 2.

dentroforaFigura 2 – Ponto dentro e fora do polígono

Agora que sabemos quando um ponto está dentro de um polígono, precisamos saber que essa semi-reta interceptou uma das arestas. Isso pode ser feito da seguinte forma:

Primeiro, calculamos a equação da aresta. Considerando que os vértices da aresta são (x1, y1) e (x2,y2), temos que a equação é:

x = x1 + (y-y1)\frac{(x2-x1)}{(y2-y1)}

Aplicando a coordenada y do ponto nessa equação, temos um valor de x. Se esse valor for maior que o valor da coordenada x do ponto, sabemos então que o ponto está a esquerda da aresta.

Além disso, se verificarmos que a coordenada y está entre min(y1,y2) e max(y1,y2), então sabemos que a semi-reta intercepta a aresta.

Com isso já podemos calcular a área de um polígono irregular.

Para ilustrar, segue um código Java para isso.

Classe Ponto

classe-ponto

Classe Aresta

classe-aresta

Classe Poligono

classe-poligono

Como primeiro teste, desenhei um polígono e gerei vários pontos aleatórios para testar se o método para verificar se está dentro do polígono está funcionando. Os pontos verdes estão fora do polígono e os amarelo dentro. Desenhei pequenos círculos em volta do ponto gerado, para aproveitar uma rotina que já tenho aqui. Podemos ver que a rotina se mostra adequada para o problema.

teste-ponto-esta-dentro-do-poligono

Figura 3 – Teste do método para verificar se pontoe stá dentro do polígono

Resta agora testar se isso funciona para calcular a área. Para isso, vamos criar um quadrado de lado 1 e gerar pontos aleatórios dentro de um quadrado de lado 2 e calcular a relação entre a quantidade de pontos dentro do quadrado e a quantidade de pontos gerada. Esse valor multiplicado pela área do quadrado maior (4), deve dar a área do quadrado, que sabemos que é 1. Na verdade, como esse método não é exato, a área deve ser próxima de 1, e não exatamente 1. Segue trecho de código usado para teste:

teste-calculo-da-area

Uma das saídas desse programa é mostrada na figura abaixo. Note que o valor da área calculado por esse método é muito próximo ao valor real. Na verdade, podemos aumentar a precisão do algoritmo aumentando o número de pontos gerados.

saida-do-programaFigura 4 – Resultado do programa

A Figura 5 mostra uma figura de exemplo para esse teste, com os pontos gerados:

exemplo-de-pontos-gerados

Figura 5 – Exemplo do teste efetuado

* – optei por não fazer a tradução dessa palavra pois não sei como ela é traduzida em geometria computacional.

Problema das 3 portas

novembro 9, 2008

Probabilidade é um assunto interessante. Em um post antigo falamos sobre o problema dos aniversários e vimos que para um grupo de apenas 30 pessoas a probabilidade de termos 2 aniversariantes no mesmo dia é de mais de 70%, o que não é muito o senso comum.

Outro problema interessante de probabilidade é o problema das 3 portas. Um apresentador de um programa de televisão chama para o palco uma pessoa que deve escolher entre 3 portas. Uma dessas portas tem prêmios e as outras 2 não tem nada. Inicialmente a pessoa escolhe uma porta e, em seguida, o apresentador abre uma porta vazia. Como sempre tem 2 portas que não tem nada atrás delas, sempre haverá uma porta para o apresentador abrir. Feito isso ele pergunta se você quer trocar de porta. E agora?

A grande maioria das pessoas nao troca de porta. Talvez por supertição, pois escolheu seu número da sorte. Mas o que é melhor, trocar de porta ou não? Ou tanto faz? Vamos resolver o problema sem fazer contas…..

Obviamente a chance de você acertar a porta na primeira escolha é de 1/3, 33,33%. Vamos verificar então o que acontece se você trocar de porta.

Inicialmente temos 3 portas, P1, P2 e P3. E você escolheu a porta P1. Temos 3 possibilidades:

  • O prêmio está atrás da porta P: Nesse caso o apresentador abre uma das portas P2 ou P3. Se você trocar você estará trocando o prêmio por nada.
  • O prêmio está atrás da porta P2: Nesse caso o apresentador abrirá a porta P3. Se você trocar de porta você estará trocando pela porta P1, ou seja, estará trocando nada pelo prêmio.
  • O prêmio está atrás da porta P3: Nesse caso o apresentador abrirá a porta P2. Se você trocar de porta você estará trocando pela porta P1, ou seja, estará trocando nada pelo prêmio.

Observe que das 3 possibilidades, 2 são vencedoras. Sendo assim, a probabilidade de ganhar o prêmio caso você troque de porta é de 2/3, ou 66,67%, ou seja, o dobro de chance de levar para casa o prêmio.

Bom, para facilitar, vamos ver um pequeno programa em Java que faz uma simulação sobre esse problema e nos mostra o resultado. É mais fácil de acreditar…

problema-3-portas1

Obs.: O código acima foi construído de forma a diminuir seu tamanho para publicação nesse blog, por isso o uso de operadores não muito indicado por alguns livros, como o operador ternário (?:).

Como converter um número em base b para um número no sistema de numeração decimal

setembro 18, 2008

No mundo da computação é muito comum vermos números escritos em sistemas de numeração diferentes do sistema decimal. Atenção especial são dadas para os sistemas de base 2 (binário) e de base 16 (hexadecimal). Mas para muitos de nós o sistema decimal é mais palpável do que qualqer outro. Você sabe como converter qualquer sistema escrito numa base b qualquer para o sistema decimal?

Um número N em uma base b qualquer pode ser escrito da seguinte forma:

N = b_n...b_3b_2b_1b_0

onde b_i é uma letra do alfabeto (dígito) que compõe o sistema de numeração. Para um sistema de numeração binário (base 2), b_i pode ser 0 ou 1. Para um sistema de numeração de base 8 b_i pode ser 0, 1, 2, 3, 4, 5, 6, 7. Para um sistema de numeração de base 16 b_i pode ser 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F e assim por diante.

Para converter o número b_n...b_3b_2b_1b_0 para a base 10 é simples. Basta aplicar a seguinte forma:

D = {b_0}B^{0} + {b_1}B^{1} + {b_2}B^{2} + ....{b_n}B^{n}

onde B é a base do sistema. Para o sistema binário B = 2 e a fórmula se reduz em:

D = {b_0}2^{0} + {b_1}2^{1} + {b_2}2^{2} + ....{b_n}2^{n}

Para ilustrar, o seguinte trecho de código na linguagem Java converte uma string que possui os números em binário para um número em decimal:

IP Móvel

setembro 10, 2008

O IP Móvel permite que um computador se mova de uma rede para outra sem mudar seu endereço IP e sem exigir que todos os roteadores propaguem uma rota específica do host. Ao mover-se de sua rede doméstica para uma rede estrangeira, um computador móvel precisa obter um endereço temporário adicional, chamado endereço care-of. As aplicações usam o endereço doméstico original do móvel; o endereço care-of só é usado pelo software da rede subjacente a fim de permitir encaminhamento e distribuição através da rede estrangeira.

Quando detecta que se moveu, um móvel obtém um endereço care-of co-localizado ou descobre um agente móvel estrangeiro e requisita que o agente atribua um endereço care-of. Após obter um endereço care-of, o móvel se registra com seu agente doméstico (direta ou indiretamente através do agente estrangeiro) e requisita que o agente encaminhe datagramas.

Uma vez completado o registro, um móvel pode se comunicar com qualquer computador na Internet. Os datagramas enviados pelo móvel são encaminhados diretamente para o destino especificado. Entretanto, cada datagrama enviado de volta para o móvel segue uma rota até a rede doméstica do móvel, onde é interceptado pelo agente doméstico, encapsulado em IP e, depois tunelado para o móvel.

Fonte: Interligação de redes com TCP/IP, Volume 1: Princípios, protocolos e arquitetura, Douglas E. Comer

Dúvidas de usuários – Verificar se um número é ímpar no Matlab

maio 23, 2008

Para saber mais sobre essa seção clique aqui.

Pergunta

Um usuário chegou a esse blog através da seguinte consulta a um motor de busca: “matlab verificar numero impar”. Então acho que a pergunta é: Como verificar se um número é ímpar no Matlab?

Resposta

Como verificar se um número é par ou ímpar? Ora, um número par é aquele que é divisível por 2 e um número ímpar é aquele que não é divisível por 2. Tudo bem, mas como verificar isso no Matlab?

No Matlab temos a função mod(), que fornece o resto da divisão. Essa função recebe 2 argumentos, o primeiro é o número que você quer dividir e o segundo é o número pelo qual você quer dividir. A função mod te fornece o resto dessa divisão. Se o resultado da divisão de um número x por 2 é 1, então esse número é ímpar. Se o resultado for 0, então o número é par. O seguinte trecho de código Matlab mostra isso:

x = 3;

if mod(x,2) == 1
sprintf('é ímpar')
else
sprintf('é par')
end

Geração de números aleatórios

novembro 23, 2007

A forma mais comum de se obter números pseudorandômicos em um computador digital é usando o seguinte gerador:

{R}_{i} = (A{R}_{i-1}+C) mod M, i = 1, 2, 3, ...

onde {R}_{0} é a semente, ou valor inicial, M o divisor, C uma constante aditiva e A um multiplicador. A notação mod M significa que a aritimética é feita módulo M, ou seja, {R}_{i} é o resto da divisão de A{R}_{i-1}+C por M. A seqüência resultante terá boa propriedades estatísticas e produzirá longas seqüências sem repetição dependendo dos números escolhidos.

Bons valores para M, Asão:

M = {2}^{31}

A = 764261123

{R}_{0} é escolhido como um número ímpar.

A implementação dessa rotina em matlab é

R0=1;
A=764261123;
C=0;
M=2^31;

R=zeros(1000,1);
R(1)=mod(A*R0+C,M);
for i=2:1000
R(i)=mod(A*R(i-1)+C,M);
end

plot(R);

Esse mesmo código, em linguagem Java, é

double[] R = new double[1000];
double A=764261123;
double C=0;
double M=Math.pow(2, 31);

R[0] = 1;
for (int i=1; i<1000; i++)
R[i]=(A*R[i-1]+C) % M;

Cabe ressaltar que esse gerador é um gerador de números pseudorandômicos. Isso significa que, dada as mesmas condições (semente, A, C e M), a mesma seqüência será gerada. Verdadeiros geradores randômicos devem usar eventos realmente randômicos, como por exemplo o ruído de dispositivos eletrônicos ou o sinal captado por um microfone em um ambiente natural.

Fonte: Random Signal Analysis in Engineering Systems, John J. Komo

Como calcular computacionalmente o valor de PI

novembro 15, 2007

Apesar de existirem vários meios de se obter o valor de \pi, talvez a mais simples é a que usa alguns conceitos básicos de estatística. Considere a figura abaixo que mostra um círculo de raio 1 inscrito em um quadrado de lado 2. A área do círculo e a área do quadrado são dadas pelas equações

{A}_{circulo} = \pi{r}^{2} = \pi , r = 1

{A}_{quadrado} = {l}^{2} = 4 , l = 2

 

Circulo inscrito em um quadrado

 

Obviamente, a relação entre {A}_{circulo} e {A}_{quadrado} é

\frac{{A}_{circulo}}{{A}_{quadrado}} = \frac{\pi}{4}

Ou seja, \pi vale

\pi = 4\frac{{A}_{circulo}}{{A}_{quadrado}}

Feito isso, para calcular \pi basta gerar vários pontos aleatórios dentro do quadrado. O valor de \pi será dado pela quantidade de pontos que estão dentro do círculo dividido pela quantidade de pontos que estão dentro do quadrado (quantidade de pontos gerados). Em Matlab, isso pode ser feito com o seguinte código

amostras = 5000000; px = 2 * rand(amostras,1) - 1; py = 2 * rand(amostras,1) - 1; ptosDentroDoCirculo = sum(px.^2 + py.^2 <= 1); estimadorPi = 4 * ptosDentroDoCirculo/amostras

Em Java, este mesmo código pode ser escrito como

int amostras = 5000000;
int pontosDentroDoCirculo = 0;
for (int i = 0; i < amostras; i++) {

double px = 2*Math.random()-1;
double py = 2*Math.random()-1;
if (Math.pow(px,2) + Math.pow(py,2) <= 1) {

pontosDentroDoCirculo++;

}

}
System.out.println("PI: " + 4*(double)pontosDentroDoCirculo/(double)amostras);

Apesar de não ser a forma mais efeciente de se calcular \pi, mas é uma das mais simples de entender.