İnteraktif Video
Daha önce müşterim olan bir ajansın ricası üzerine Pazarlama Dehası isminde bir interaktif video oyunu hazırlamıştım. Benzer çerçevede yeniden bir interaktif video hazırlama durumu söz konusu olunca bunun yapımını sizinle paylaşmaya karar verdim.
İnteraktif video izleyenin kararlarına göre değişik cevapları verebilen senkronize bir medya akışıdır. Yani video içinde sorulan bir soruya, izleyenin cevap vermesi ve bu cevaba göre farklı videoların gösterilmesi. Elbette birden fazla soru olacağı için bunu bir döngüde tasarlayıp soru ve cevap alternatiflerini oluşturmak ve parametrik olarak bunları değiştirebilmek en sağlıklı yöntem olacak. Herşeyi timeline üzerine yığıp ActionScript kullanmadan işi yapmanın çok da pratik bir yöntem olduğunu söyleyemem; özellikle de soru-cevap sayısı fazlaysa…
Tabii ki Flash ile düz akışlı video yapmaktan fazlasını yapabiliriz. Videonun önüne ve arkasına görseller ekleyebilir, bu görselleri videonun çeşitli anlarıyla senkronize edebilir, videoya paralel görsel ya da ses efektleri ekleyebiliriz. Zaten Adobe, Flash 9 ‘u duyururken alfa kanalı (transparan video) ve hızlanma konularını vurgulamıştı. Bu sayede daha canlı, daha renkli sunumlar hazırlanabilecek. Flash 10 ‘un neler sağlayabileceğine hiç girmiyorum; C++ ve bunun üzerinden oluşturulabilmesi mümkün bir 3D arabirimi, yine C++ üzerinden efektlerin işlenmesi için grafik kartına erişim, IK (inverse kinematics) gibi araçlar sayesinde Flash, çok farklı yerlere doğru ilerleyeceğe benziyor. Adobe Labs üzerinde bunlarla ilgili detaylı ön-bilgiler mevcut (AIF).
Konumuza dönersek, demin de belirttiğim gibi, düzgün tasarlanmış bir döngü ile esnek bir tercihli video akışını kolaylıkla sağlayabiliriz. Buna dilerseniz cevaplara göre skor hesaplanması, veri girişi gibi ek özellikler de ekleyebilirsiniz. Çalışmayı yaygınlığından AS2 ile hazırlayacağız, ama ufak değişiklikler ile AS3 ‘de de çalışabilir. Videoların gösterilmesinde elbette FLVPlayer component’ini kullanacağız. Ama timeline’dan ziyade ActionScript odaklı çalıştığımız için bu component’e erişebilmek için ilk satırımız
import mx.video.*;
olmalı.

Düzen olarak da timeline’ı akışın farklı durumlarını oluşturmak için kullanacağım. Timeline üzerinde birkaç keyframe yetecektir. Bunları görevlerine göre isim vererek init, boot, boot_end, loop ve answers olarak adlandırıyorum. init, movie ilk başladığında gereken tanımlamaları ve oluşturulacak değişkenleri içeriyor. boot, döngü dışında videonun başına ek bir giriş videosu / animasyonu koymak için eklediğim keyframe bir keyframe; doğrudan soru-cevaplara geçmek için bunu atlayabilirsiniz. loop sorunun sorulduğu kısım ve burada verilen cevaba göre answers keyframe’ine gidiliyor. Answers bitince gösterim, loop’dan devam edecek şekilde ayarlanacak. Bu şekilde sorular bitene kadar loop ve answers arasında gidip geleceğiz. Layer’lar da isimlerinden anlaşılacaktır. Anim1-5 layer’larına her soru için bir animasyon yerleştirdim; soruyu soran, videonun bir noktasında sorunun yazılı olduğu bir panoyu çekerek ekrana getiriyor. Bu animasyonları senkronizasyon problemleri yaşamamak için dışardan dinamik yüklemek yerine doğrudan stage’e yerleştirmeyi uygun gördüm. Vcr layer’ı, stage boyunda video player’ımızı içeriyor. intro, soruların öncesinde oynatılacak animasyonu içeriyor. Buttons layer’ında 4 adet buton bulunuyor. Bunlar, soru seçeneklerinin konumlarıyla aynı. Böylece butonların seçimini animasyon movieclip’inin içinde bir yerlerde tanımlamak yerine genel yapıda daha dinamik biçimde tanımlayabiliyorum. Bu sayede animasyon movieclip’ine mümkün olduğunca az bağımlı oluyoruz. Bun animasyonlar, ilk ve son frame’lerinde birer stop(); komutu olan, 2. frame’den itibaren istediğimiz kadar detaylı hazırlayabileceğimiz movieclip’ler. Birkaç mask ve görsel malzeme ile çok güzel ekrana geliş efektleri tasarlanabilir ve videonun üzerine gelecek soru kartlarını süsleyebilirsiniz.

Videoplayer component’ini ve intro’yu aralarda kesiklikler olmaması için bunları birer kabuk movieclip içine yerleştiriyorum. İlk frame, her zamanki gibi, stop(); komutu içeriyor, _in ve _out, esas movieclip’imizin fadein ve fadeout yaparak gösterildiği tween’leri içeriyor ve sonlarında yine birer stop(); komutu bulunuyor. Bu kabuk movieclip’e isim verdiğimizde istediğimiz yerden _root.isim.gotoAndPlay(’in’); gibi bir komutla bu geçişlerden uygun olanı başlatabiliriz. Sonlarında stop(); komutu olduğundan geçiş bittiğinde bu kabuk movieclip’ine başka bir komut verene kadar beklemede kalacaklardır. _root.vhs.tape.vcr, component olarak stage’e eklediğim videoplayer’ın erişim yolu.
Geliştirme esnasında gereksiz vaktimi çalan bir problem, butonların zamansız yerlerde aktif halde kalması idi. Bu yüzden onları basitçe gerekmedikleri durumlarda _y = -1000 gibi bir koordinata taşıyorum. _visible ya da _alpha komutlarını kullanmak, onların stage üzerindeki varlıklarını etkilemediğinden çalışmaya devam edeceklerdi. Ayrıca stage’de herhangi bir movieclip’i _alpha ile kısmanın yavaşlamaya sebep olduğunu belirtmeliyim. Bu yüzden fonda dekor işlevli grafiksel ögeler kullanacaksanız bunları vektör ya da movieclip’ler yerine bmp olarak yerleştirmenizin gösterim hızından önemli ölçüde tasarruf sağlayacağını belirtmemde fayda var.
boot_end kısmına biraz değinmemde fayda var; kodda karışıklığı önlemek ve tekrar kullanılacak bazı kodları fonskiyon olarak önden tanımlamak bana daha pratik geldi. Elbette bunları döngünün içine de koyabilirdim, ama ince ayar veya bug tespiti gibi durumlarda bunların kafa karıştırdığını deneyimlediğimden bu şekilde çalışmayı yeğliyorum. killEvents, selectMovie, turnOff ve turnOn bu türden fonksiyonlar. killEvents ile soru ve cevapların oluşturduğu event’lar temizleniyor. Bunu yapmadan addEvent ile her soru ve cevapta event eklerseniz, bunlar kısa zamanda player objesini şişirmeye ve aynı işi yapan kodlar arttığındna yavaşlatmaya başlayacaklardır.
FLVPlayer’ın yapısal bir avantajını projemde akışı rahatlatmak için kullandım. Bir player’a birden fazla video ekleyerek bunlara Array gibi index değeriyle erişmeniz ve göstermeniz mümkün. activeVideoPlayerIndex ve visibleVideoPlayerIndex parametreleri ile bringVideoPlayerToFront() metodu ile hangi index’deki videoyu göstermek istediğimizi belirtebiliyoruz. Aynı anda hafızada 3 video bulunduruyorum, 0 index’inde sorunun kendisi, 1,2 indexlerinde de doğru ve yanlış cevap için videolar bulunuyor. Video yükleme sırasında senkron kaymasını engellemek için de cevapları, sorudan önce, başta yüklüyorum. İndex belirterek video yüklemeyi de
_root.vhs.tape.vcr.activeVideoPlayerIndex = 1;
_root.vhs.tape.vcr.load('videos/s01-true.flv');
komutlarıyla sağlayabiliriz. Cevapları yükler yüklemez, soruya ait event’ları tanımlamak doğru bir yol olacaktır. Her zamanki gibi, bir listener objesi yaratarak belirli bir durumda tetiklenmesini sağlamak için şöyle bir kod kullanıyoruz:
var earCueQc:Object = new Object();
earCueQc.complete = function(eO:Object):Void {
if(_root.vhs.tape.vcr.visibleVideoPlayerIndex == 0){
turnOff();
}
}
_root.vhs.tape.vcr.addEventListener("complete", earCueQc);
Burada, complete tetikleyicisini kullanarak movie akışı bittiğinde turnOff(); fonksiyonunu çağırmasını belirtiyoruz. Benzer şekilde cuePoint tetikleyicisini kullanarak videonun belli yerlerine gelindiğinde stage’e eklediğimiz animasyonların çalışmasını sağlıyoruz. Ama bunun için videoya cuePoint (tetikleme işaretleri) koymalıyız, bunun için Flash Video Encoder ile videoları hazırlarken video seçili haldeyken Settings’e basarak video sıkıştırma ayarlarından Cue Points menüsünü kullanıyoruz. Video ve ses kalitesini ihtiyacınıza göre ayarlarsınız; ama videonun flash stage’ine transparan şekilde aktarılamsını istiyorsanız Video menüsünde Encode alpha channel’ı seçmelisiniz. Dijital videolarda interlacing denen görüntünün çizgi çizgi olma durumunu da Deinterlace seçeneğiyle düzeltebilirsiniz.

Video gösterim sırasında belirli noktalara gelindiğinde birer event tetiklenebilir. Bu yüzden videoyu encode ederken cuepoint’ları event olarak tanımlıyorum. Diğer alternatifimiz olan navigation’ı seekToNavCuePoint(), seekToNextNavCuePoint() ve seekToPrevNavCuePoint() gibi metodlarla videoyu istediğimiz noktaya getirmekte kullanabiliriz. Event şeklinde cuePoint kullanırken dikkatimi çeken bir nokta var; CuePoint’lar video dosyası yüklendikten çok kısa bir süre sonra (1 saniye kadar) yüklenmiş oluyor. Eğer videonuzun başında atlamak istediğiniz bir bölüm varsa bu yüzden video başlangıcını CuePoint beklemek yerine saniye olarak değerini vererek seek() ettirmemiz daha sağlıklı olur. Daha da sağlıklısı FLVPlayer’ın metadataReceived event’ını ve metadataLoaded değerini kullanarak CuePoint ve video hakkında diğer bilgileri içeren metadata blokunu beklemek ve bu gelince işlemlere başlamak.
var listenerObject:Object = new Object();
listenerObject.metadataReceived = function(eventObject:Object):Void {
};
my_FLVplybk.addEventListener("metadataReceived", listenerObject);
şeklinde bir kod ile metadata bilgisinin gelmesini bekleyebilirsiniz. Bu bilgiler gelince .metadata objesi, aşağıdaki parametreleri içerir:
canSeekToEnd
cuePoints
audiocodeic
audiodelay
audiodatarate
videocodecid
framerate
videodatarate
height
width
duration
Buradaki cuePoints, bizim ihtiyacımız olan CuePoint objelerini içeren bir array’dir. Her bir CuePoint objesi, type, name, time ve opsiyonel olarak parameters bilgisin ihtiva eder. Yani
player.metadata.cuePoints[n].time
gibi bir ifade ile videoda kayıtlı CuePoint’ların zaman bilgilerine erişebilirsiniz.
Hazırladığım örnekte başlangıcı saniyesini doğrudan girip seek() ettirmek pratik geldi. Aşağıdaki kod bloğu da CuePoint’lara göre ne yapmak istediğimizi belirtiyoruz. Event objesi içerisinden CuePoint’ları algılatmak için eO.info üzerinden tetiklemeyi sağlayan CuePoint objesine erişebiliriz. event objesi, temelde tetiklemeyi yaratan objenin kopyasını içerir.
var earCueQ:Object = new Object();
earCueQ.cuePoint = function(eO:Object):Void {
switch(eO.info.name){
case 'wipe':
_root.tuslar._y = bxYs;
_root['s'+_root.SI+'anim']._visible = true;
_root['s'+_root.SI+'anim'].gotoAndPlay(2);
break;
case ‘end’:
case ‘wipe_end’:
_root.vhs.gotoAndPlay(’_out’);
_root.vhs.tape.vcr.pause(true);
stop();
break;
}
}
_root.vhs.tape.vcr.addEventListener(’cuePoint’, earCueQ);
Gördüğünüz gibi, videoalarda wipe ve end isimli iki cuePoint bulunmakta; bazen wipe_end de olduğu için bunu end ile aynı değerlendirdim. Soru kartının ekrana getirileceği noktada wipe isimli cuePoint devreye giriyor. Ekrandaki görünmez butonları, gerçek koordinatlarına getiriyor, uygun animasyonu görünür hale getirdikten sonra onu başlatıyorum. video biriminde devreye giren end / wipe_end cuePoint’ı da videonun fadeout edilmesini ve sonra da pause edilmesini sağlıyor. Videoyu göstermek için de loop frame’inin son satırları şu şekilde:
selectMovie(0);
_root.vhs.tape.vcr.load('videos/s0'+SI+'.flv');
_root.vhs.tape.vcr.setFLVCuePointEnabled(true, 'begin');
_root.vhs.tape.vcr.seek(_root.CueQ[_root.SI-1][0]);
turnOn();
_root.vhs.tape.vcr.volume = 100;
_root.vhs.gotoAndPlay(’_in’);
_root.vhs.tape.vcr.play();
stop();
selectMovie ile doğru video index’ini ayarladıktan sonra .load() ile uygun videoyu yüklüyor, seek() ile de buna ait başlangıç noktasına gelmesini sağlıyoruz. turnOn() player’ı görünür kılıyor, sonra önceden video başındaki seslerin duyulmaması için kısmış olduğumuz sesi açıyor, video’yu fadein ederek play() ile çalıştırıyoruz.
Benzer bir gösterim mantığı, answers frame’inde de var. Tek önemli fark, zaten yüklenmiş videoyu göstereceğimiz için sadece
selectMovie(_root.whichVideo);
...
_root.vhs.tape.vcr.seek(_root.CueA[_root.whichVideo-1][_root.SI-1][0]);
_root.vhs.tape.vcr.play();
ile cevaba uygun videoyu seçmek ve başlangıcına yine daha önceden hazırladığım başlangıç zamanlarını içeren array’den gelen değerle erişmek. Tabii bu sefer cuePoint event’larından end işimize yarayacak; cevaplarda herhangi bir animasyon efekti eklemediğimden. end cuePoint’ına ulaşıldığında veya complete event’ı tetiklendiğinde (video akışı bittiğinde), gösterilen video indeksini (_root.SI) artırıyoruz ve başa dönüyoruz.
Önümüzdeki günlerde vakit bulduğumda elimdeki çalışma dosyasını temizleyerete buraya ekleyebilirim; çalışan bir örneği incelemek her zaman daha kolay anlamayı sağlar. Ama yukarıdaki bilgilerle artık siz de kendinize ait bir interaktif video yapısı kurabilirsiniz.