Copy link to clipboard
Copied
I have a code setup to play fullscreen video with play/pause, close, and a scrubber/seek bar. Howver, there are some irregularities when publishing for either AIR for Android or AIR for iOS.
Publish for Android gives me an inconsistent scrubber ( in portrait, sometimes it scrubs/seeks, most of the time it does not detect a drag and thus does not scrub). Landscape seems to do a better job of adjusting the scrubber.
Using the same file and codes, when publishing for iOS, the scrubber does not move forward. When I tap and drag the scrubber, the video either restarts or goes back a few frames, but never goes forward.
Is this a bug on Adobe/AIR or do I need to make adjustments to the code to implement for iOS? What is causing these inconsistencies?
Please see the code below and feel free to make suggestions. Any help is greatly appreciated.
From file AIRMobileVideo.as :
package
{
import flash.display.MovieClip;
import flash.desktop.NativeApplication;
import flash.desktop.SystemIdleMode;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.StageVideoAvailabilityEvent;
import flash.geom.Rectangle;
import flash.media.StageVideo;
import flash.media.Video;
import flash.media.StageVideoAvailability;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.events.MouseEvent;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class AIRMobileVideo
{
protected var stream:NetStream;
protected var stageVideo:StageVideo;
protected var softwareVideo:Video;
public var stageref:Stage;
public var timelinetarget:MovieClip;
public var playingBlank:Boolean;
public var tmrDisplay:Timer;
// object holds all meta data
public var objInfo:Object;
public var customClient:Object;
public var bolProgressScrub:Boolean = false;
public var postime:Number;
public function AIRMobileVideo(stage:Stage, X:int, Y:int, width:int, height:int, target:MovieClip)
{
stageref = stage;
timelinetarget = target;
playingBlank = false;
var nc:NetConnection = new NetConnection();
nc.connect(null);
customClient = new Object();
customClient.onMetaData = metaDataHandler;
//stream.client = customClient;
stream = new NetStream(nc);
//stream.client = this ;
stream.client = customClient;
var vidWidth:int;// = stage.fullScreenWidth;//1028;
var vidHeight:int;// = int((480*vidWidth)/640);//764;
var Ycal;// = (stage.fullScreenHeight/2) - (vidHeight/2)
var X;
if(stageref.fullScreenWidth>stageref.fullScreenHeight){
//landscape
vidHeight = stageref.fullScreenHeight;//
vidWidth = int((640*vidHeight)/480);
Ycal = 0;//
X = (stageref.fullScreenWidth/2) - (vidWidth/2);
} else {
//portrait
vidWidth = stageref.fullScreenWidth;//1028;
vidHeight = int((480*vidWidth)/640);//764;
Ycal = (stageref.fullScreenHeight/2) - (vidHeight/2);
X=0;
}
trace("width:"+vidWidth);
trace("height:"+vidHeight);
stream.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
// software fallback
softwareVideo = new Video(vidWidth, vidHeight);
softwareVideo.x = X;
softwareVideo.y = Ycal;
timelinetarget.addChild(softwareVideo);
var pt:Point = new Point(timelinetarget.mcVideoControls.mcProgressScrubber.x, timelinetarget.mcVideoControls.mcProgressScrubber.y);
pt = timelinetarget.mcVideoControls.mcProgressScrubber.parent.localToGlobal(pt);
timelinetarget.mcProgressShow.x = pt.x;
timelinetarget.mcProgressShow.y = pt.y;
timelinetarget.addcontrols();
timelinetarget.mcVideoControls.mcProgressScrubber.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
tmrDisplay = new Timer(10);
tmrDisplay.addEventListener(TimerEvent.TIMER, updateDisplay);
trace("AIRMobileVideo: using software fallback");
}
function onTouchBegin(event:TouchEvent) {
// set progress scrub flag to true
bolProgressScrub = true;
//
timelinetarget.killControlFadeout();
//stream.pause();
tmrDisplay.removeEventListener(TimerEvent.TIMER, updateDisplay);
stageref.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
stageref.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
// start drag
timelinetarget.mcVideoControls.mcProgressScrubber.startDrag(false, new Rectangle(0, 4, 400, 0));
}
function onTouchMove(event:TouchEvent) {
stream.seek(Math.round(timelinetarget.mcVideoControls.mcProgressScrubber.x * objInfo.duration / 400));
timelinetarget.mcVideoControls.mcProgressFill.mcFillRed.width = timelinetarget.mcVideoControls.mcProgressScrubber.x + 5;
timelinetarget.mcVideoControls.mcProgressFill.mcFillGrey.width = stream.bytesLoaded * 406 / stream.bytesTotal;
var pt:Point = new Point(timelinetarget.mcVideoControls.mcProgressScrubber.x, timelinetarget.mcVideoControls.mcProgressScrubber.y);
pt = timelinetarget.mcVideoControls.mcProgressScrubber.parent.localToGlobal(pt);
timelinetarget.mcProgressShow.x = pt.x;
timelinetarget.mcProgressShow.y = pt.y;
}
function onTouchEnd(event:TouchEvent) {
bolProgressScrub = false;
//
timelinetarget.mcVideoControls.mcProgressScrubber.stopDrag();
// update progress/volume fill
timelinetarget.mcVideoControls.mcProgressFill.mcFillRed.width = timelinetarget.mcVideoControls.mcProgressScrubber.x + 5;
//timelinetarget.mcVideoControls.mcProgressScrubber.x = postime * 364 / objInfo.duration;
//stream.seek(postime);
//stream.resume();
stageref.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
stageref.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
//tmrDisplay.addEventListener(TimerEvent.TIMER, updateDisplay);
timelinetarget.addControlFadeout();
// stop all dragging actions
event.updateAfterEvent();
}
public function updateDisplay(e:TimerEvent):void {
// checks, if user is scrubbing. if so, seek in the video
// if not, just update the position of the scrubber according
// to the current time
if(bolProgressScrub){
//postime = Math.round(timelinetarget.mcVideoControls.mcProgressScrubber.x * objInfo.duration / 364);
stream.seek(Math.round(timelinetarget.mcVideoControls.mcProgressScrubber.x * objInfo.duration / 400));
} else {
timelinetarget.mcVideoControls.mcProgressScrubber.x = stream.time * 400 / objInfo.duration;
}
//timelinetarget.mcVideoControls.mcProgressScrubber.scaleX = timelinetarget.mcVideoControls.scaleX;
// update the width from the progress bar. the grey one displays
// the loading progress
timelinetarget.mcVideoControls.mcProgressFill.mcFillRed.width = timelinetarget.mcVideoControls.mcProgressScrubber.x + 5;
timelinetarget.mcVideoControls.mcProgressFill.mcFillGrey.width = stream.bytesLoaded * 406 / stream.bytesTotal;
var pt:Point = new Point(timelinetarget.mcVideoControls.mcProgressScrubber.x, timelinetarget.mcVideoControls.mcProgressScrubber.y);
pt = timelinetarget.mcVideoControls.mcProgressScrubber.parent.localToGlobal(pt);
timelinetarget.mcProgressShow.x = pt.x;
timelinetarget.mcProgressShow.y = pt.y;
//trace("loaded:"+stream.bytesLoaded + " total:"+stream.bytesTotal);
}
public function resizeVid ():void {
var vidWidth:int;
var vidHeight:int;
var Ycal;
var X;
if(stageref.fullScreenWidth>stageref.fullScreenHeight){
//landscape
vidHeight = stageref.fullScreenHeight;//
vidWidth = int((640*vidHeight)/480);
Ycal = 0;
X = (stageref.fullScreenWidth/2) - (vidWidth/2);
} else {
//portrait
vidWidth = stageref.fullScreenWidth;//1028;
vidHeight = int((480*vidWidth)/640);//764;
Ycal = (stageref.fullScreenHeight/2) - (vidHeight/2);
X=0;
}
// software fallback
//softwareVideo = new Video(vidWidth, vidHeight);
softwareVideo.x = X;
softwareVideo.y = Ycal;
softwareVideo.width = vidWidth;
softwareVideo.height = vidHeight;
timelinetarget.addcontrols();
trace("AIRMobileVideo: using software fallback");
}
public function playVideo(url:String):void
{
stream.close();
softwareVideo.clear();
softwareVideo.attachNetStream(stream);
playingBlank = false;
stream.play(url);
}
public function pauseVideo():void
{
stream.pause();
}
public function resumeVideo():void
{
stream.resume();
}
public function stopVideo():void
{
trace("stopVideo()");
playingBlank = false;
zeroVideo();
stream.close();
softwareVideo.clear();
timelinetarget.removeChild(softwareVideo);
timelinetarget.removeBlackBack();
}
public function playBlankVideo():void
{
trace("playBlankVideo()");
playingBlank = true;
timelinetarget.removeControls();
stream.play("blank.mp4");
}
public function zeroVideo():void
{
stream.pause();
stream.seek(0);
}
public function metaDataHandler(infoObject:Object):void
{
objInfo = infoObject;
tmrDisplay.start();
}
private function handleActivate(event:Event):void
{
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
}
private function handleDeactivate(event:Event):void
{
NativeApplication.nativeApplication.exit();
}
private function statusHandler(event:NetStatusEvent):void
{
trace(event.info.code)
if(event.info.code=="NetStream.Play.Stop"){
trace("Video stopped");
if(playingBlank == true){
trace("stopVideo()");
stopVideo();
} else {
trace("playBlankVideo()");
playBlankVideo();
}
}
if(event.info.code=="NetStream.Play.Start"){
trace("Remove loading");
}
}
}
}
Copy link to clipboard
Copied
Have you checked if its a file specific problem?
With a 764 height resolution your video is non IOS-Standard (height+width should be divisible by 16)
Here are some limitations you should consider when encoding for IOS:
http://blog.zencoder.com/2012/01/24/encoding-settings-for-perfect-ipadiphone-video/
Try a standard video and report back.