Olá amigos!
Recentemente a equipe de opensource da Adobe lançou um framework mais do que excelente, trata-se do OSMF Open Source Media Framework, um conjunto de Classes voltados para trabalho e monetização de mídia em flash (filmes, vídeo, áudio, imagens), que facilita e acelera em muito a vida do desenvolvedor, ainda com o destaque de ser otimizado para o também quentíssimo Flash Player 10.1.
“Brinque” (mas não espere demais dele) com o player abaixo:
Este artigo não tem como base entregar um player 100% funcional e pronto pra ser utilizado ou distribuído mas sim oferecer um caminho para o desenvolvedor ou estudante da plataforma começar a desenvolver seus próprios aplicativos de mídia baseados no OSMF, criando cada vez mais experiências ricas para o internauta ou seu cliente.
Para iniciar, faça o download aqui http://www.opensourcemediaframework.com/ do framework e inclua ele no seu ClassPath.
Desativando configurações específicas do Flash Player 10.1
O OSMF contém, claro, métodos e funções otimizados para Flash Player 10.1 e isso irá disparar alguns erros no seu Flash (ide) quando você estiver testando o filme e não tiver atualizado o Flash Player para a versão atual, então devido a isso iremos desativar uma das configurações do framework, você pode deixar ativado se quiser, mas precisará instalar o Debug Flash Player ( adobe.com/download) 10.1.
Iremos desativar também a opção de LOGGING, mas essas configurações estaremos desativando apenas para acelerar o processo do artigo, você pode ler a documentação e aprender a utilizar caso deseje. Aliás, você que estiver acompanhando este artigo, precisa ler a documentação do OSMF, ele tem muita coisa importate.
No documento que você for utilizar para fazer o seu player, edite em “file > ActionScript Settings > Config Constants”, adicione duas linhas:
Name: CONFIG::FLASH_10_1 Value: false
Name: CONFIG::LOGGING Value: false

Com isso desativamos essas duas configurações específicas, uma pra flash player 10.1 e outra pra logging, que não iremos utilizar.
Como funciona o OSMF
O OSMF funciona encapsulando todos os processos responsáveis por exibir e controlar arquivos de mídia (imagens, vídeo, áudio, swfs), permitindo ao desenvolvedor criar aplicações ricas baseadas em mídia com alto nível de controle, com possibilidade de criação de plugins dos mais variados tipos (grande maioria dos já criados visando monetização de mídia através de google ad words).
O processo utilizado neste player do artigo segue o fluxo padrão e mais simples do OSMF, onde você:
- Cria um MediaContainer(org.osmf.containers.MediaContainer)
- Cria um VideoElement (org.osmf.elements.VideoElement)
- Cria uma URLResource (resource, endereço, url) – (org.osmf.media.URLResource)
- Configura o objeto resource no elemento vídeo
- Adiciona o elemento vídeo ao container
- Configura o MediaPlayer para controlar o elemento de mídia (org.osmf.media.MediaPlayer)
- Define o tipo de mídia do MediaPlayer como sendo o elemento vídeo
- Controla
Dessa forma, em síntese, temos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package { import flash.display.MovieClip; import org.osmf.containers.MediaContainer; import org.osmf.elements.VideoElement; import org.osmf.media.MediaPlayer; import org.osmf.media.URLResource; /** * OSMF Basic * @author Eder Lima */ public class BasicPlayer extends MovieClip { public function BasicPlayer() { var container:MediaContainer = new MediaContainer(); var video:VideoElement = new VideoElement(); var url:URLResource = new URLResource("video.flv"); video.resource = url; container.addMediaElement(video); var player:MediaPlayer = new MediaPlayer(); player.autoPlay = false; player.media = video; player.play() } } } |
O interessante do MediaContainer é que ele controla automaticamente a proporção do vídeo em caso de resize, matendo o vídeo sempre ajustado caso você altere o tamanho do stage e altere juntamente o container de vídeo, é muito bom.
Vamos criar um player de vídeo que reproduza o vídeo, pause, altere entre mudo e com volume total (1), com barra de progresso, barra de processo de carregamento do vídeo e um tracker, que pode ser arrastado, avançando ou retrocedendo o vídeo de acordo com a sua posição, que altere o tempo com o arraste e por fim que exiba o tempo atual da reprodução e o tempo total. Ufa! (Isso ainda é pouco comparado com o que se pode fazer com o OSMF);
Criando o Player
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | package { import flash.display.MovieClip; import flash.events.Event; import flash.events.MouseEvent; //importando as classes do framework necessárias para um player simples //MediaContainer > Um container que se autoajusta ao palco, permitindo o redimensionamento correto do video import org.osmf.containers.MediaContainer; //VideoElement > Objeto vídeo import org.osmf.elements.VideoElement; //MediaPlayer > Player de mídia, seleciona o tipo de mídia (vídeo) e controla import org.osmf.media.MediaPlayer; //URLResource > Objeto que controla a url do arquivo que será reproduzido import org.osmf.media.URLResource; //TimeEvent > Classe de eventos que determina quando o filme inicia ou termina import org.osmf.events.TimeEvent; //importando a tweenlite import com.greensock.TweenLite; import com.greensock.easing.Strong; //importando a Classe Rectangle, utilizada no drag import flash.geom.Rectangle; /** * FPOSMFPlayer * FlashPedia Opensource Media Framework Player * @author Eder Lima */ public class FPOSMFPlayer extends MovieClip { //criando objetos do player de vídeo private var player:MediaPlayer; private var video:VideoElement; private var url:URLResource; private var container:MediaContainer; //criando o rectangle para o arraste do tracker private var dragRect:Rectangle; //boolean para saber se a execução do filme já foi iniciada private var started:Boolean = false; public function FPOSMFPlayer() { //iniciando o filme addEventListener(Event.ADDED_TO_STAGE, initPlayer); } private function initPlayer(event:Event):void { removeEventListener(Event.ADDED_TO_STAGE, initPlayer); //executando função que configura o player configurePlayer(); //executando função que configura os controles configureControls(); } private function configurePlayer():void { /** * configurando a url do vídeo de acordo com o parâmetro passado através do html, * o parâmetro será "video" */ root.loaderInfo.parameters['video'] != undefined ? url = new URLResource(String(root.loaderInfo.parameters['video'])) : throwError("URL do vídeo não informada"); //criando o novo objeto VideoElement video = new VideoElement(); //adicionando a url do video como Resource (usando URLResource) ao vídeo video.resource = url; //video.resource = new URLResource("video.flv"); //criando um novo MediaPlayer (ele é quem controlará o vídeo exibido) player = new MediaPlayer(); //definindo para não iniciar automaticamente player.autoPlay = false; //selecionando a mídia a ser trabalhada, no caso o vídeo player.media = video; //adicionando um evento para quando a execução do filme terminar player.addEventListener(TimeEvent.COMPLETE, movieCompleteHandler); //criando um novo container container = new MediaContainer(); //configurando os tamanhos container.width = stage.stageWidth; container.height = stage.stageHeight; //adicionando o vídeo ao container container.addMediaElement(video); //adicionando o container de vídeo ao palco addChild(container); //colocando o container de vídeo atrás dos controles, que já estão no palco setChildIndex(container, 0); } //configurando os controles do player private function configureControls():void { //configurando as escalas das barras bar.seekbar.seekbar.scaleX = 0; bar.seekbar.loadedbar.scaleX = 0; //configurando o rectangle de arraste do tracker] dragRect = new Rectangle(0, 4, bar.seekbar.bgbar.width, 0); //criando um array com os botões utilizados no player para facilitar algumas funções var controls:Array = [bar.btplay, bar.seekbar.bgbar, bar.timeinfo, bar.seekbar.tracker, bar.btvolume]; //para cada botão for each(var item:MovieClip in controls) { //usa o HandCursor item.buttonMode = true; } //parando o botão play no estado para iniciar bar.btplay.gotoAndStop(1); bar.btplay.addEventListener(MouseEvent.CLICK, playVideo); //configurando o over sobre o tempo bar.timeinfo.mouseChildren = false; bar.timeinfo.addEventListener(MouseEvent.ROLL_OVER, overTime); bar.timeinfo.addEventListener(MouseEvent.ROLL_OUT, outTime); //configurando a barra de progresso para clique //desativando a barra de load e a barra de progresso bar.seekbar.seekbar.mouseEnabled = false; bar.seekbar.loadedbar.mouseEnabled = false; //configurando o volume simples / alterna entre mudo e normal bar.btvolume.gotoAndStop(1); bar.btvolume.addEventListener(MouseEvent.CLICK, toggleMute); } //função que inicia o vídeo caso ainda não tenha tocado e depois pausa private function playVideo(event:MouseEvent):void { if (!started) { started = true; //ativando o clique sobre a barra de fundo bar.seekbar.bgbar.addEventListener(MouseEvent.CLICK, seekOnClick); //configurando o arraste do tracker bar.seekbar.tracker.addEventListener(MouseEvent.MOUSE_DOWN, seekOnDrag); //adicionando um evento para informar o progresso do download do vídeo //processo separado dos outros justamente para manter o progresso informando mesmo em caso de o vídeo estar parado this.addEventListener(Event.ENTER_FRAME, traceLoad); } //se o player estiver parado toca, senão pausa player.playing ? toPause() : toPlay(); } //função que toca o vídeo private function toPlay():void { //toca o vídeo player.play(); //muda o estado do botão play bar.btplay.gotoAndStop(2); //adiciona os eventos addListeners(); } //função que pausa private function toPause():void { //pausa o vídeo player.pause(); //muda o estado do botão play bar.btplay.gotoAndStop(1); } //adicionando listeners para as barras e o tempo private function addListeners():void { this.addEventListener(Event.ENTER_FRAME, trackInfos); } //removendo listeners para as barra e o tempo private function removeListeners():void { this.removeEventListener(Event.ENTER_FRAME, trackInfos); } //informando progresso do filme através das barras e da posição do tracker private function trackInfos(event:Event):void { //informando a escala da reprodução bar.seekbar.seekbar.scaleX = player.currentTime / player.duration; //posicionando o tracker conforme a execução do filme bar.seekbar.tracker.x = player.currentTime / player.duration * bar.seekbar.bgbar.width; //informando o tempo total bar.timeinfo.timer.duration.text = String(addZero(int(player.duration / 60)) +":" + addZero(int(player.duration % 60))); //informando o tempo total bar.timeinfo.timer.current.text = String(addZero(int(player.currentTime/60)) +":"+addZero(int(player.currentTime%60))); } //função que informa o progresso do download do vídeo private function traceLoad(event:Event):void { //informando os bytes carregados bar.seekbar.loadedbar.scaleX = player.bytesLoaded / player.bytesTotal; } //função que permite avançar clicando sobre a barra de progresso private function seekOnClick(event:MouseEvent):void { //executando a função que faz o seek do player, somente se a posição do click for menor que a posição da barra //que informa o progresso de carregamento do vídeo if (event.target.mouseX <= bar.seekbar.loadedbar.scaleX * bar.seekbar.bgbar.width) { //informa o tempo para qual o filme deve avançar this.seekTo(event.target.mouseX / event.target.width * player.duration); //se o player estiver parado if (!player.playing) { //volta a reproduzir this.toPlay(); } } } //função que permite arrastar o tracker e saltar para o tempo específico do filme private function seekOnDrag(event:MouseEvent):void { //remove todos os listeners, dessa forma as barras passam a seguir o comando do usuário removeListeners(); //inicia o arraste do tracker, tendo como limites a barra de fundo event.target.startDrag(false, dragRect); //adiciona os eventos para quando o mouse estiver em movimento event.target.addEventListener(MouseEvent.MOUSE_MOVE, onTrackMove); //adiciona os eventos para quando soltarmos o clique do mouse ou quando arrastarmos o ponteiro pra fora da área do tracker event.target.addEventListener(MouseEvent.MOUSE_OUT, stopTheDrag); event.target.addEventListener(MouseEvent.MOUSE_UP, stopTheDrag); } //executando os eventos durante o arraste do mouse private function onTrackMove(event:MouseEvent):void { //se a posição do tracker for menor que a escala da barra de progresso de carregamento if (event.target.x <= bar.seekbar.loadedbar.scaleX * bar.seekbar.bgbar.width) { //a barra de progresso de execução segue a posição do tracker bar.seekbar.seekbar.scaleX = event.target.x / bar.seekbar.bgbar.width; //o tempo é alterado para o tempo representado pela posição do tracker bar.timeinfo.timer.current.text = String(addZero(int((event.target.x / bar.seekbar.bgbar.width * player.duration) / 60)) +":" + addZero(int((event.target.x / bar.seekbar.bgbar.width * player.duration) % 60))); } //senão else { //paramos o arraste toStopTheDrag(); } //atualizamos o filme depois de cada movimento do mouse (somente para tornar o arraste mais suave mesmo com framerates baixos) event.updateAfterEvent(); } //parando o arraste //chamamos uma segunda função para reaproveitamento private function stopTheDrag(event:MouseEvent):void { toStopTheDrag(); } //função que para o arraste private function toStopTheDrag():void { //removendo eventos adicionados ao iniciar o arraste bar.seekbar.tracker.removeEventListener(MouseEvent.MOUSE_MOVE, onTrackMove); bar.seekbar.tracker.removeEventListener(MouseEvent.MOUSE_OUT, stopTheDrag); bar.seekbar.tracker.removeEventListener(MouseEvent.MOUSE_UP, stopTheDrag); //parando o arraste do tracker bar.seekbar.tracker.stopDrag(); //saltando para o tempo resultante da posição do tracker this.seekTo(bar.seekbar.tracker.x / bar.seekbar.bgbar.width * player.duration); //alterando o estado do botão play !player.playing ? this.toPlay() : void; } //alterando entre estado mudo e normal private function toggleMute(event:MouseEvent):void { player.volume <= 0 ? unMute() : mute(); } //alterando para mudo private function mute():void { player.volume = 0; bar.btvolume.gotoAndStop(2); } //alterando para normal private function unMute():void { player.volume = 1; bar.btvolume.gotoAndStop(1); } //função executada ao fim da execução do filme (permite reinício a partir da cache, usa seek(0) no framework) private function movieCompleteHandler(event:TimeEvent):void { //alterando o estado do botão play bar.btplay.gotoAndStop(1); } //função que salta para o tempo especificado do filme private function seekTo(time:Number):void { player.seek(time); } //função com o mouse sobre o tempo private function overTime(event:MouseEvent):void { TweenLite.to(event.target.timer, .3, { y:-12} ); } private function outTime(event:MouseEvent):void { TweenLite.to(event.target.timer, .3, { y:0} ); } //informado erros (forma simples, jogando erros na tela de debug) private function throwError(error:String = ""):void { throw new Error(error); } //normalizando o tempo em 00:00 private function addZero(value:int):String { //se o valor for menor ou igual a 9 retorna 0x, senão retorna x return value <= 9 ? "0" + value : String(value); } } } |
Bom, como disse no começo o player não é nem de longe uma solução final, então fica pra vocês o exercício de mostrar e esconder os controles e manipular o tamanho dos objetos conforme o tamanho do stage. Quem quiser, claro, pode ir além e criar um controle de volume de arraste e etc.
Arquivos fonte para download:
FlashPedia OSMF Player
Baixado 78 vezes
Tamanho 
Dúvidas? Sugestões? Críticas? Fiquem a vontade nos comentários
Enjoy ;)

em 23 de junho de 2010
Parabens, Eder!!
Mais um post de excelente qualidade :)))
em 23 de junho de 2010
Ficou tudo muito fácil com esse framework e o Eder mostrou como! Hehe!
(y)
em 24 de junho de 2010
“Dúvidas? Sugestões? Críticas? Fiquem a vontade nos comentários”(SIC)
Já que você mesmo permite, então lá vai…
-MUITO BOM!!!!
;P
em 24 de junho de 2010
Exemplo bacana dos recursos do OSMF’
:)
\o gtz’ Eder
em 27 de junho de 2010
Excelente! Longe de ser um exemplo final, mas é uma mão na roda.
Vou agendar uma fuçada nisso essa semana.
Tô acompanhando Eder, continue nos Post’s Hot Hots.
Obrigado!
em 22 de julho de 2010
Mto bom o Post!!!
mas..
Estou tentando implementar o OSMF em um cd que estou fazendo, utilizando o Gaia Framework.
Quando entro pela primeira vez na página que contém o vídeo, o vídeo roda perfeitamente. Quando saio e depois volto a mesma página de vídeo, acontece o seguinte erro:
>TypeError: Error #1034: Falha de coerção de tipo: não é possível converter org.osmf.net.rtmpstreaming::RTMPDynamicStreamingNetLoader@24a726a1 em org.osmf.traits.LoaderBase.
Entender o erro, eu entendo, o problema é como resolvo. Ja tentei de tudo, até comentar a(s) linha(s) do erro, mas não adianta.
O que pode ser?
Vlw!!!
em 22 de julho de 2010
Ainda não enfrentei esse problema, precisaria ver a parte do código que inicia o player.
Já tentou fazer o load e unload sem utilizar o gaia? Pois ele armazena os filmes num dictionary pra não precisar carregar novamente, isso pode influir caso vc inicialize o player de vídeo diretamente na função principal de uma document class.
Outra coisa, está destruindo o objeto do player ou desativando ao remover ele do palco?
Realmente, não tenho certeza do que pode ser, pois não fiz ainda nada semelhante ao que você está fazendo.