Archive for September, 2007

Refatorando para Fluent Interface

Friday, September 21st, 2007

Ultimamente tenho passado boa parte do meu tempo trabalhando na WebMediaAPI. Para quem não conhece, a WebMediaAPI é uma… API que tem como objetivo padronizar, centralizar e facilitar o acesso à mídias e seu consumo na Globo.com.

Por exemplo, se você quer colocar vídeos no seu site, ao invés de dar vários SELECTs em tabelas que você não conhece e não entende, a idéia é que você possa usar um JAR na sua aplicação que encapsula várias funcionalidades oferecidas pela infraestrutura de WebMedia, simplificando o seu trabalho (pois não terá que descobrir como inventar a roda) e o nosso (centralizando e organizando o consumo de mídias).

No início do projeto um dos maiores desafios foi estabelecer como seria a fachada da WebMediaAPI. Nós tentamos alguns formatos e como precisávamos lançar logo a primeira versão acabamos optando por uma interface tradicional e simplificada. Para dar uma idéia melhor, vamos analisar o código para selecionar os últimos vídeos publicados de um programa:

int quantidade = 5;
long programaId = 456;
Set midias = new HashSet();

WebMediaServices webMediaServices = WebMediaFactory.getServices();
List idsMidias = webMediaServices
	.getIdsUltimasMidiasPublicadasPorPrograma(quantidade, programaId);

for (Iterator iter = idsMidias.iterator(); iter.hasNext();) {
   Long midiaId = (Long) iter.next();
   Midia midia = webMediaServices.getMidia(midiaId.longValue());
   midias.add(midia);
}

Não é muito difícil entender o funcionamento deste código. Só que ele poderia ser muito melhor… Esta interface pode até funcionar mas não é nem um pouco intuitiva. A classe WebMediaServices como pode-se imaginar ficou com dezenas de métodos e virou basicamente um grande saco de funcionalidades. Qualquer método simplesmente ficava nesta classe, o que não é nem um pouco elegante.

Depois de algum tempo tive a idéia de refatorar a API para uma Fluent Interface. A idéia é tentar fazer alguma coisa que se aproxime de uma DSL interna, que não é nada mais do que uma API com nomes interessantes. Ao invés de um saco de métodos a WebMediaAPI agora é acessada através de uma interface semânticamente organizada e seu design é pensado para ser legível e fluente.

Veja como ficou o mesmo serviço para selecionar os últimos vídeos publicados do programa “Altas Horas”:

Long altasHoras = new Long(456);
Set videos = WebMediaAPI.videos().recentes().doPrograma(altasHoras);

Bem mais elegante!

O lado negativo é que quanto mais fácil a API torna-se para o cliente, mais difícil torna-se sua implementação. Construir uma fluent interface muitas vezes me fez perder algumas horas pensando como certas coisas seriam feitas, mas eu gostei do resultado final e acho que para esse tipo de aplicação (WebMediaAPI) valeu a pena.

Para mostrar a diversidade e simplicidade da nova API, veja mais alguns exemplos (repare que eu não tenho que dizer o que eles fazem para você entendê-los):

// 1
Set programas = WebMediaAPI.programas().comTitulo("Fantastico");

// 2
Long redeGlobo = new Long(123);
Set videos = WebMediaAPI.videos().favoritos().doCanal(redeGlobo);

// 3
Long destaquePrincipalGloboVideos = new Long(123);
Integer quantidadeMaxima = new Integer(10);
Set videos = WebMediaAPI.videos().relacionados().aoCanal()
	.doVideo(destaquePrincipalGloboVideos, quantidadeMaxima);

Ainda temos um longo caminho pela frente e muita coisa ainda será melhorada. Já tenho várias idéias novas que na medida do possível serão incorporadas às próximas versões e compartilhadas aqui no blog.

Snapshot e Osprey

Friday, September 14th, 2007

Hoje foi mais um dia batendo cabeça com a Osprey e a snapshot e o programa de flash ao vivo.

A Osprey precisa de um driver especial que só funciona no kernel 2.6.9, mas não houve esforços pra migrar esse driver para as versões mais novas.

Esse kernel gerou um problema que eu nunca pude esperar que fosse acontecer, ele requer que um unnamed fifo (aquele que a gente cria usando a função pipe()) requer um reader e um feeder síncronos, e eu usava esse esquema de forma assíncrona, por exemplo.

for (;;) { write(fifo); read(fifo); }

No kernel 2.6.9 eu tenho que ter threads distintas para realizar essa função, o que me obrigou a mudar o programa que já estava funcionando para embutir 1 thread só pra ficar gravando no pipe pra eu poder funcionar como eu já funcionava antes com o kernel 2.6.20. Assim, ficou algo do tipo:

thread1: for (;;) { write (fifo); }

thread2: for (;;) { read (fifo);}

A alteração funcionou como esperado, não tive mais problemas. A única coisa que aconteceu com a mudança da PixelView para a Osprey é que a imagem é bem mais nítida, gerando menos keyframes que antes e assim está demorando um pouco mais de tempo para sincronizar as conexões novas. Da primeira vez que fiz o teste imaginei que o programa tivesse travado, mas na verdade é que demorou um certo tempo para vir um keyframe.

Mas no final de tudo eu terminei com um RPM para o CentOS 4 do kernel 2.6.9 com os drivers da Osprey para quando alguém precisar deles no futuro não precisar compilar tudo na mão e com o flash ao vivo funcionando na Osprey.

Fica faltando ver se essas mudanças vão criar o famigerado problema de lipsync que tinha com a PixelView. A priore estou usando os mesmo parametros de antes, V4L 1.x mas usando drivers OSS e não ALSA como era na PixelView.

Felizmente o mencoder não teve problemas em sincronizar os frames de áudio e vídeo, é possível ter uma prévia do que estamos fazendo em flashlive.

O próximo passo é conseguir integrar a lógica no Apache, de forma a ter uma arquitetura de distribuição de vídeo mais robusta.

Mas que raios de JS é esse?

Thursday, September 13th, 2007

Uma das duvidas de nossa equipe quanto ao Gerenciador de Layout sempre foi a estranha importação de um js e um css que é inserido sem consentimento. Esses arquivos, com nomes como 0,,IDSESSAO,00.js e 0,,IDSESSAO-xhtmls.css, podem causar problemas bizarros no momento de transferência entre ambientes.

Um exemplo disso é o problema que tivemos hoje em QA1. A página de Catálogo do GloboVideos 4.2 que está em homologação começou a acusar um erro de javascript que no ambiente local e no ambiente de desenvolvimento não apareciam.

Analisando o problema descobrimos que a fonte do problema era um erro de sintaxe encontrado no 0,,9448,00.js. Esse erro era causado pelo comentário na declaração de uma função cujo corpo e fechamento não estavam comentados. Apartir daí foi só descobrir como esse arquivo é gerado. Acabamos por descobrir que ele é gerado mesclando todas as funções genéricas, cadastradas no Gerenciador de Layout.

Foi então que percebemos um bug nessa geração, o comentário da declaração de função na verdade é o comentário de finalização de uma outra função colocada logo acima. Ou seja, entre uma e outra função mesclada para gerar o estranho arquivo js, o gerenciador não coloca nenhuma quebra de linha.

Para resolver isso bastou então inserir essa quebra de linha e limpar o cache.

A ameaça dos singletons

Wednesday, September 12th, 2007

Há muito tempo que ouvia sobre os problemas que o padrão singleton representa. É claro que com tantos argumentos não tinha como eu não concordar. Mas eu concordava sem dar muita importância pois nunca havia sentido na pele seus malefícios. Até que finalmente passei por uma grande dificuldade causada por um singleton. Isso finalmente despertou meu ódio por este abominável padrão. Neste artigo explico qual o problema e como o resolvi.

Ontem no desenvolvimento do Menu do GloboVideos 4.2, resolvi exercitar a prática de TDD, ou seja, eu implementeria os testes unitários para guiar o desenvolvimento das classes. O problema é que a classe que representaria o Menu do GloboVideos precisaria utilizar a classe MenuBO (com.globo.portal.cda.menu.business.MenuBO) do Portal.

A idéia era simples, mocar o MenuBO, para isolar o acesso ao banco da minha classe de forma a só testar as regras de negócio do menu do GloboVideos. Mas isso não foi possível, pois esta classe, meus amigos, segue o padrão singleton. Ou seja, o construtor dela é privado, o que impossibilita a criação de Mocks e de SubClasses.

A solução que encontrei foi criar uma classe Proxy. A MenuBOProxy. Não sem antes testar de várias maneiras um jeito de criar mocks com classes de construtor privado. Não consegui. A classe MenuBOProxy apenas implementa todos os métodos de MenuBO, delegando cada uma delas a uma instância do objeto único de MenuBO. Veja como a classe ficou:


public class MenuBOProxy {

	private MenuBO menuBo;

	public MenuBOProxy() {
		this.menuBo = MenuBO.getInstance();
	}

	public MenuBOProxy(MenuBO menuBo) {
		this.menuBo = menuBo;
	}

	public Vector listaItem(MenuVO menu)
		throws BusinessException {
		return menuBo.listaItem(menu);
	}

	public MenuVO listaMenu(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenu(menu);
	}

	public Vector listaMenus()
		throws BusinessException {
		return menuBo.listaMenus();
	}

	public String retornaListaNomeMenu(Vector vetMenuId)
		throws BusinessException {
		return menuBo.retornaListaNomeMenu(vetMenuId);
	}

	public MenuVO listaMenuPorPortalNome(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenuPorPortalNome(menu);
	}

	public MenuVO listaMenuPorId(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenuPorPortalNome(menu);
	}
}

Com esse proxy foi possivel criar um mock e enfim testar separadamente a lógica do Menu do GloboVideos.

Por hora, a versão atual do GloboVideos também foi desenvolvido utilizando-se singletons seguindo o padrão do Portal. Mas aos poucos estamos migrando suas funcionalidades de forma a permitir uma maior testabilidade no código. Sempre seguindo a máxima de que o padrão singleton é mal, pega um pega geral.

Outros links com mais argumentos e exemplos disso estão disponíveis abaixo:

http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx
http://c2.com/cgi/wiki?SingletonsAreEvil
http://www.softwarereality.com/design/singleton.jsp
http://members.capmac.org/~orb/blog.cgi/tech/coding/no_singletons.writeback
http://www.testingreflections.com/node/view/552

Wirecast: transmissões ao vivo de baixo custo

Tuesday, September 11th, 2007

Nesse último techtalk gravei a minha palestra sobre o OLPC com uma solução de cortes ao vivo que me deixaria muito feliz de apresentar também, mas como a coisa toda ainda está em sendo lapidada achamos ainda inoportuno preparar um techtalk sobre o assunto. Então, para matar a vontade, escrevo um pouco aqui sobre as novas possibilidades dessa ferramenta, que surgiu da crença de que poderiamos, como uma empresa de internet, encontrar uma forma mais viável, que as tradicionais herdadas da TV, para fazer nossas transmissões ao vivo.

As metas eram as seguintes:

  • Encontrar um programa que fizesse uso da nova arquitetura das placas gráficas, capazes de processar bilhões de pixels por segundo, para nosso proveito — edição de multiplas fontes de vídeo com cortes suaves, aplicação de logo marcas, gerador de caracteres e até propaganda, como notado mais tarde — tudo isso ao vivo.
  • Esse programa também teria que fazer um uso eficiente do processador para codificar todo esse sinal processado em streams windows média, do mesmo formato que fazemos atualmente.
  • Que fosse possível gravar o mesmo sinal codificado para o ar, para possíveis edições posteriores e se possível, ainda, que não houvesse necessidade de transcodificar novamente para fazer esses cortes.

Existem muitas soluções em hardware, que fazem a força bruta com o trabalho em circuitos especializados para tratamento de vídeo digital de alta qualidade, mas todos muito acima do nosso orçamento de pequenas produções. Que diga-se de passagem, é como a internet deve ser usada — lembremos do long-tail da amazon.com — o objetivo não é transmitir para mais gente que a TV, isso é inviavel, porque logo a nossa infra-estrutura despencaria e nossos gastos iriam para o espaço, mas transmitir mais conteudo que a TV jamais poderá na sua forma de broadcast e manter consumidores fieis a essa tremenda variedade.

Então se passaram muitas madrugadas de pesquisa para provar que já era possível para computadores pessoais comuns produzirem vídeos digitais de alta qualidade, que já seriam melhores que os vídeos analógicos dos quais nos alimentamos da TV hoje. Depois de muito custo o primeiro programa que encontrei foi o Visual Communicator da finada Serious Magic, comprada pela Adobe o logo tirado do ar, confesso que fiquei desanimado, por achar que seria o primeiro e único a fazer isso, e começava a avaliar as complicações de implementar eu mesmo o que eu sabia que era possível… Quando encontrei o Wirecast, muito mais simples e dinâmico que o Visual Communicator, fiquei bastante empolgado e cri firmemente que essa era a solução para as inumeras requisições de pequenos estúdios que recememos mensalmente.

Na Palestra do OLPC fiz o seguinte, em apenas um laptop rodei o Wirecast, capturando de uma camera por DV, o Desktop Presenter (programa que captura a tela do desktop de um computador e envia pela rede para o Wirecast como se fosse mais uma camera) capturando desktop extendido que tinha um Acrobat Reader (para a própria apresentação) e mais tarde um VNC Viewer conectado com o XO (laptop do OLPC) e no final um VMWare Player (com a versão mais nova do Sugar, sistema operacional do XO) nesse ponto a memória do computador acabou e mais nada acontecia, o Wirecast se mostrou robusto por, apesar de não ter condições de continuar com o processamento do vídeo, parar a gravação fechando o arquivo corretamente. Como já estava nas perguntas não me importei mais com o laptop e continuei respondendo ao público. Apesar do final desastrado e so som mal ajustado não é preciso muita imaginação para ver as possibilidades dessa solução simples e barata nas nossas produções reais.

Palestra sobre o Laptop de 100 Dólares gravada em WMV com o Wirecast e posteriormente codificada em Flash Vídeo

Fico muito feliz de ver essa solução indo adiante, pois ela se encontra em Teste Beta no Estúdio do Chat no Downtown e com boas perspectivas de ser usada em vários outros lugares. Lembro o quanto a defendi frente a todos que não acreditavam que uma solução de 500 dólares poderia ser de maior qualidade que as de milhares de dólares disponíveis no mercado; fico feliz por não te-los decepcionado ainda e espero que possamos fazer todos os ajustes necessários para tornar essa a nova maneira de produzir vídeos na globo.com.

“Smart” Streaming

Tuesday, September 4th, 2007

Bom pessoal, resolvi inaugurar meus posts aqui no blog para contar um dos desafios mais recentes que me propus a investigar…. implementar um Intelligent Streaming para o Flash (Live Streaming via HTTP)! A primeira coisa que deve ter vindo na cabeça de vocês, pelo menos daqueles que já conhecem as tecnologias Windows Media e Flash Vídeo, é: não dá pra fazer multi-target em Flash. Sim, é verdade… e isto é uma grande desvantagem do Flash Vídeo. Para aqueles que não conhecem, então, vamos à uma rápida explicação:

“Intelligent Streaming é a capacidade que o Windows Media tem de aumentar ou reduzir o bitrate do vídeo de acordo com a disponibilidade de banda do usuário. Em outras palavras: menos banda, menor bitrate, menor qualidade; mais banda, maior bitrate, maior qualidade; tudo isso “on the fly” ”

Bom, teoricamente, para fazer isso em Flash, seria necessário ter dentro do encapsulamento FLV, N targets diferentes de vídeo, o que não é possível. Desta forma, resolvi batizar a solução que pensei de “Smart” Streaming… ela deve ser esperta o suficiente para tomar as decisões certas.

Antes de explicar minha idéia, vamos a motivação: “Não podemos comprometer os usuários com pouca banda em prol de um vídeo de altíssima qualidade, da mesma forma que não podemos entregar um vídeo de qualidade média para um usuário capaz de ver um vídeo com uma qualidade melhor”. Além disso, nosso amigo Luiz vem desenvolvendo em seu projeto pessoal uma alternativa para Live Streaming em Flash via HTTP, sem utilizar o Flash Media Server. Uma das features que poderia impulsionar ainda mais a utilização do que ele vem desenvolvendo é justamente garantir uma melhor experiência para o usuário.

Assim, minha idéia para o “smart” streaming em Flash consiste basicamente em controle de buffer no cliente (algo que eu já havia estudado no FMS para Fast Start e Fast Cache). A utilização de um streaming em flash via HTTP, torna o consumo do vídeo pelo cliente um processo idêntico ao download progressivo, ou seja, o flash player acha que está recebendo um vídeo On Demand via progressive download, mas na verdade está pegando um conteúdo Live via Streaming. Este fato de o player “achar” que o conteúdo é On Demand, nos permite, teoricamente, utilizar algumas classes do Flash que verificam a quantidade de bytesLoaded, etc, as mesmas que a maioria dos players do mercado usam para só dar start no vídeo quando já foi realizado um determinado buffer inicial. Assim, se realizarmos uma análise do buffer no cliente, podemos identificar se o mesmo tem ou não banda suficiente para receber determinado streaming. Caso seja identificado um “esvaziamento” do buffer, então devemos trocar a URL do vídeo para uma onde seja feito um streaming com menor bitrate. Da mesma forma, caso o buffer permaneça cheio, podemos trocar o usuário para um vídeo com maior bitrate. A desvantagem, neste caso, seria a necessidade de realizar um encoding/delivery separado para cada target. Além disso, a troca entre os targets não seria completamente transparente para o usuário, porém, é possível minimizar os impactos dela através do gerenciamento do buffer inicial.

Durante os testes do Flash Media Server, cheguei a implementar um mock-up com idéia semelhante, mas com um processo de checagem de banda muito mais eficiente, graças ao FMS.

Com esta técnica, evitamos que um usuário não consiga visualizar um conteúdo ao vivo porque não tem banda, da mesma forma que não reduzimos a qualidade do vídeo para uma boa parcela dos usuários que possuem MegaFlash e afins. Além disso, poderíamos utilizar a solução em desenvolvimento de streaming via HTTP, eliminando a necessidade de comprar licenças FMS.

Bom, como eu disse, este é apenas um conceito, uma atividade que ainda vai me entreter por alguns dias… Minha idéia é postar aqui a evolução deste protótipo, para que vocês comentem e sugiram alternativas que posso não ter pensado!

Blog Interno da Equipe WebMedia

Tuesday, September 4th, 2007

Olá Pessoal,

este é o primeiro post do Blog Interno da equipe WebMedia, a idéia é que todos da equipe possam compartilhar o que estamos desenvolvendo, o que estamos experimentando tanto em termos de processos quanto nos projetos de mídia com o resto da empresa.

Vários assuntos estão na nossa pauta diária, mas gostaria de compartilhar com vocês alguns dos que estamos tocando neste momento.

Uma das áreas de atuação da equipe Webmedia são os projetos de engenharia de TV, estes projetos envolvem o desenho e especificação dos sistemas de áudio e vídeo que incluem edição, captura, recepção de sinais e produção de vídeo entre outras coisas. São nestes sistemas que os editores de vários locais diferentes (CGP, CGJ, SP, SGR, Globosat e aqui mesmo no Cittá e Downtown) conseguem publicar vídeos, áudios e podcasts. Neste momento estamos trabalhando em alguns projetos de engenharia, sob responsabilidade da equipe do Azambuja.

  • Novos equipamentos de produção e edição de vídeos para o GloboEsporte.com
  • Upgrade no Estudio do Chat no Downtown, e renovação dos cases de produção remotos
  • Projeto de vídeos do G1 (ilhas, capturas, EFs, enfim tudo)

Falando agora da parte de Desenvolvimento de Software, estamos tocando o projeto no GloboVideos 4.2 sob o comando do Phillip, este é um grande passo para a plataforma do GloboVideos, pois há diversas novidades principalmente embaixo do capô, entre elas estão:

  • Engine de renderização de Widgets
  • Novo Layout compatível com o novo padrão da Globo.com
  • Uso de Scrum no processo de desenvolvimento
  • Uso de ferramentas de Integração Continua, como Cruise Control e FIT
  • Testes automatizados usando Selenium

Entre outras novidades que o pessoal irá divulgar daqui para a frente através deste Blog.