the litl developer blog
15Nov/100

What’s overscan and why do I have to deal with it?

by @ryancanulla

Overscan is extra image area around the four edges of a video image that may not be seen reliably by the viewer. It exists because television sets in the 1930s through 1970s were highly variable in how the video image was framed within the cathode ray tube (CRT).
source: Wikipedia

Simply put, overscan is about 5% (this will vary depending on TV size/manufacturer) of your content that will be cropped when put on a tv screen. If you crop an image and blow it up to the original size, you would be overscanning. If you are familiar with print, this process is similar to “bleeding”. Consider the example below.

The reason overscan exists is because of older CRT TV’s where the tube couldn’t produce quality images on the edge of the tube. In order to effectively deal with poor quality on the edges of tubes, TV manufacturers made tubes larger and hid the part that was blurry behind the TV casing, essentially cropping a portion of the image.


Look at the black bar of meta-data at the top of the screen


Check out the green line on the left of the screen.

Okay, I know what you’re saying, “So what; who still uses CRT anyway? Why am I still being affected by this?”, but the short of it is that over the years broadcast companies have been using this “cropped” area to send meta information over analog signals. Also, since they expect it to be cropped, there is less time polishing the content available on the edges of the screen. This is the reason that even modern TV’s overscan.

Tell me litl makes it easier?

We sure do! Now that you know all about overscan, know that we handle everything for you so you don’t need to actually do anything different! Continue to use liquid layouts (based off percentages) and set view & view sizes by listening for the ViewChangeEvent on your litl service. In that event you will find the full viewing area for your TV screen.

Check out this sample code.

ViewManager.as

package com.litl.overscan
{
    import com.litl.sdk.enum.View;
    import com.litl.sdk.message.InitializeMessage;
    import com.litl.sdk.message.ViewChangeMessage;
    import com.litl.sdk.service.LitlService;

    import flash.display.Sprite;
    import flash.utils.Dictionary;

    public class LitlViewManager extends Sprite
    {
        private var _service:LitlService;
        private var _currentViewState:String;

        protected var _view:Sprite;
        protected var controller:GameController = GameController.getInstance();
        protected var currentView:ViewBase;
        protected var views:Dictionary;

        public function LitlViewManager(view:Sprite) {
            _view = view;
            views = new Dictionary();
        }

        protected function setView(e:ViewChangeMessage):void {
            // Remove the current view from the display list.
            if (currentView && contains(currentView)) {
                removeChild(currentView);
            }

            if (views == null)
                views = new Dictionary(false);

            currentView = views[e.view] as ViewBase;

            switch (e.view) {
                default:
                    throw new Error("Unknown view state");
                    break;

                case View.CHANNEL:

                    if (currentView == null)
                        currentView = new ChannelView(_service);
                    _currentViewState = View.CHANNEL;
                    break;
                case View.FOCUS:

                    if (currentView == null)
                        currentView = new ChannelView(_service);
                    _currentViewState = View.CHANNEL;
                    break;
                case View.CARD:

                    if (currentView == null)
                        currentView = new CardView();
                    _currentViewState = View.CARD;
                    break;
            }

            views[e.view] = currentView;
            controller.currentView = currentView;

// IMPORTANT -- This is where we update the size of the display object
//                           based on the dimensions returned by our ViewChangeEvent

// NOTE  -- If you extend ViewBase from our SDK rather than sprite, you will have
//                 access to the setSize() method
            currentView.setSize(e.width, e.height);

            if (!contains(currentView))
                addChild(currentView);
        }

        public function set service(value:LitlService):void {
            _service = value;
            _service.addEventListener(ViewChangeMessage.VIEW_CHANGE, setView);
        }

        public function get currentViewState():String {
            return _currentViewState;
        }

    }
}

ChannelView.as

package com.litl.marbelmayhem.views
{
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.events.Event;
    import flash.net.URLRequest;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;

    public class Scoreboard extends ViewBase
    {
        private var background:Sprite;
        private var timeBG:Bitmap;
        private var logo:Bitmap;
        private var timeDisplay:TextField;

        public function Scoreboard(e:ViewBase) {
            super();
            _view = e;
            init();
        }

        private function init():void {
            createChildren();
        }

// NOTE -- This is where we instantiate our objects and add them to memory
        private function createChildren():void {
            background = new Sprite();
            background.graphics.beginFill(0x333333);
            background.graphics.drawRect(0, 0, 1280, 800 * .15);
            addChild(background);

            logo = gameAssets.logoBitmap;
            logo.cacheAsBitmap = true;
            addChild(logo);

            timeBG = gameAssets.timeBGBitmap;
            timeBG.cacheAsBitmap = true;
            addChild(timeBG);

            var timeFormat:TextFormat = new TextFormat();
            timeFormat.font = "Calibri";
            timeFormat.size = 34;
            timeFormat.color = 0x000000;

            timeDisplay = new TextField();
            timeDisplay.autoSize = TextFieldAutoSize.LEFT;
            timeDisplay.defaultTextFormat = timeFormat;
            timeDisplay.setTextFormat(timeFormat);
            addChild(timeDisplay);
        }

// Note -- The sizeUpdated() is part of ViewBase and called when the setSize() is called.
//               This means that whenever our size changes the objects on our stage will
//               reset.  Notice how they are set using percentages (get liquid baby!)
        override protected function sizeUpdated():void {
            logo.x = this.width * .10;
            logo.y = (background.height / 2) - (logo.height / 2);

            timeBG.x = (this.width / 2) - (timeBG.width / 2);
            timeBG.y = (background.height / 2) - (timeBG.height / 2);

            timeDisplay.x = (timeBG.x + (timeBG.width / 2)) - (timeDisplay.width / 2);
            timeDisplay.y = (timeBG.y + (timeBG.height / 2)) - (timeBG.height / 2) + 5;
        }
    }
}
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


No trackbacks yet.