/* * Copyright © 2011 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.overlay; // //Source File Name: VideoCanvas.java /** * VideoCanvas displays video or camera viewfinder on Canvas * Drawing ControlBar on VideoControl * Operating VideoControl with ControlBar */ import java.io.IOException; import java.io.InputStream; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.media.Manager; import javax.microedition.media.MediaException; import javax.microedition.media.Player; import javax.microedition.media.control.VideoControl; class VideoCanvas extends Canvas implements CommandListener, Runnable { private final VideoOverlayMIDlet midlet; private final Command backCommand = new Command("Back", Command.BACK, 0); private final Command captureCommand = new Command("Capture", Command.SCREEN, 0); private Player player; private VideoControl videoControl; private boolean active; /** If empty paint() is wanted */ boolean emptyPaint = false; /** VideoCanvas type */ private int type; /** ControlBar with buttons */ private ControlBar controlBar; // Coordinates for moving ControlBar private int prev_x; private int prev_y; /** Back button location x */ private int exitX = 0; /** Back button location y */ private int exitY = 0; private int canvasW; // Canvas width private int canvasH; // Canvas height private int videoW; // Video display area width private int videoH; // Video display area height private int video_x; // VideoControl x coordinate private int video_y; // VideoControl y coordinate /** Moving is true when tap down occurs inside ControlBar area */ private boolean moving = false; /** * Dragged is true when ControlBar is moving with pointer dragging event * Prevents pressing button during moving ControlBar */ private boolean dragged = false; /** Background color of VideoCanvas */ private final int BACKGROUND_COLOR = 0x000000;//0x33CC66; /** Text color of VideoCanvas */ private final int TEXT_COLOR = 0xFFFFFF; /** Video path in resources */ private final String VIDEO_LOCATOR = "/test.mp4"; /** If ControlBar is visible */ private boolean hideControlBar; /** Canvas full screen mode flag */ private boolean fsMode; /** * Initializing VideoControl indicator * True until VideoControl is ready */ private boolean initializingVideo = false; /** Initializing drawing indicator */ private long prevRepaint = 0; private boolean running; private boolean paused = false; private Image back_icon; public void commandAction(Command c, Displayable d) { if (c == backCommand) { closingVideoCanvas(); } else if (c == captureCommand) { takeSnapshot(); } } private static final String[] INIT_STRINGS = new String[]{ "Initializing.", "Initializing..", "Initializing...", "Initializing...." }; private int stringIndex = 0; /** * VideoCanvas displays video or camera viewfinder on Canvas * Drawing ControlBar on VideoControl * Operating VideoControl with ControlBar * @param midlet - parent MIDlet * @param type - camera or video */ public VideoCanvas(VideoOverlayMIDlet midlet, int type) { this.type = type; this.player = null; this.videoControl = null; this.active = false; this.running = false; this.paused = false; this.hideControlBar = false; this.fsMode = false; this.midlet = midlet; this.canvasW = getWidth(); this.canvasH = getHeight(); this.videoW = canvasW; this.videoH = canvasH; addCommand(backCommand); setCommandListener(this); this.createImages(); this.controlBar = new ControlBar(this, 0, 0, this.videoW / 2); } /** * Creating images from resources for Back button */ public void createImages() { try { back_icon = Image.createImage("/buttons/back.png"); } catch (IOException ex) { back_icon = null; } } /** * Initializing player and setting it to videoControl */ public void initPlayer() { initializingVideo = true; // Always start player in normal mode fsMode = false; this.setFullScreenMode(fsMode); try { if (this.type == VideoOverlayMIDlet.CAMERA) { player = Manager.createPlayer("capture://video"); } else { InputStream is = this.getClass().getResourceAsStream( this.VIDEO_LOCATOR); player = Manager.createPlayer(is, this.VIDEO_LOCATOR.substring( this.VIDEO_LOCATOR.lastIndexOf('.') + 1)); } player.realize(); player.prefetch(); videoControl = (VideoControl) player.getControl("VideoControl"); if (videoControl != null) { videoControl.initDisplayMode( VideoControl.USE_DIRECT_VIDEO, this); videoControl.setDisplayFullScreen(true); if (this.type == VideoOverlayMIDlet.CAMERA) { addCommand(captureCommand); } else { player.setLoopCount(-1); } this.controlBar.setX(videoControl.getDisplayX()); this.controlBar.setY(videoControl.getDisplayY()); videoControl.setVisible(true); player.start(); // Empty paint is called to ensure // that videoControl area is clear emptyPaint = true; repaint(); serviceRepaints(); emptyPaint = false; } } catch (IOException ioe) { discardPlayer(); System.out.println(ioe.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("IOException:", ioe.getMessage(), null, AlertType.ERROR)); } catch (MediaException me) { discardPlayer(); System.out.println(me.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("MediaException:", me.getMessage(), null, AlertType.ERROR)); } catch (SecurityException se) { discardPlayer(); System.out.println(se.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("SecurityException", se.getMessage(), null, AlertType.ERROR)); } catch (Exception e) { discardPlayer(); System.out.println(e.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("Exception", e.getMessage(), null, AlertType.ERROR)); } finally { initializingVideo = false; } } /** * discardPlayer() * Closing player and setting player and videoControl to null */ private void discardPlayer() { if (player != null) { player.close(); player = null; } videoControl = null; } public void paint(Graphics g) { if (emptyPaint == true) { // Do not draw anything // Ensure that videoControl area is clear return; } int state = Player.UNREALIZED; if (player != null) { state = player.getState(); } if (initializingVideo) { paintInitString(g); } else { switch (state) { case Player.PREFETCHED: paintOverlay(g); break; case Player.STARTED: paintOverlay(g); break; case Player.CLOSED: paintString("Closing...", g); break; case Player.UNREALIZED: break; case Player.REALIZED: break; default: g.setColor(BACKGROUND_COLOR); g.fillRect(0, 0, getWidth(), getHeight()); paintString("Closing...", g); break; } } prevRepaint = System.currentTimeMillis(); } private void paintInitString(Graphics g) { long currentTime = System.currentTimeMillis(); if (currentTime - prevRepaint > 100) { ++stringIndex; if (stringIndex >= INIT_STRINGS.length) { stringIndex = 0; } } paintString(INIT_STRINGS[stringIndex], g); } private void paintString(String str, Graphics g) { Font f = Font.getDefaultFont(); g.setColor(BACKGROUND_COLOR); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(TEXT_COLOR); g.setFont(f); g.drawString(str, getWidth() / 2, getHeight() / 2, Graphics.BASELINE | Graphics.HCENTER); } /** * Drawing content on top of MMAPI content * @param g - Graphics object from the paint event */ private void paintOverlay(Graphics g) { // Check if canvas changes (e.g., in screen rotation) if (canvasW != getWidth() || canvasH != getHeight()) { canvasW = getWidth(); canvasH = getHeight(); // Setting new location this.controlBar.setX(videoControl.getDisplayX()); this.controlBar.setY(videoControl.getDisplayY()); } video_x = videoControl.getDisplayX(); video_y = videoControl.getDisplayY(); videoW = videoControl.getDisplayWidth(); videoH = videoControl.getDisplayHeight(); // Clear areas outside the videoControl g.setColor(BACKGROUND_COLOR); g.fillRect(0, 0, canvasW, video_y); g.fillRect(0, video_y + videoH, canvasW, canvasH); g.fillRect(0, 0, video_x, videoH); g.fillRect(video_x + videoW, 0, canvasW, canvasH); // Stop painting if clearing flag is up if (hideControlBar) { return; } // Setting ControlBar boundaries // Height is fixed size controlBar.setWidth(videoW / 2); // Control Bar this.drawButtons(g); // In fullscreen mode, drawing exit button if (fsMode) { // Portrait if (canvasH > canvasW) { exitX = videoW - (videoW / 3); exitY = canvasH - (back_icon.getHeight() + 20); } // Landscape else { exitX = videoW; exitY = videoH - (back_icon.getHeight() + 20); } g.drawImage(back_icon, (exitX + canvasW) / 2, exitY, Graphics.TOP | Graphics.HCENTER); } } /** drawButtons(Graphics g) * Drawing ControlBar with buttons * @param g - Graphics object from the paint event */ private void drawButtons(Graphics g) { controlBar.drawControlBar(g); } public boolean isFullScreen() { return fsMode; } public int getType() { return this.type; } public int getPlayerState() { return this.player.getState(); } /** * Initializing Player for VideoControl in own thread * Calling initPlayer to create Player */ synchronized void startCanvas(int type) { this.controlBar.setButton_type(type); new Thread(new Runnable() { public void run() { initPlayer(); } }).start(); } /** * Starting thread again if it is stopped * Happens also the first time Canvas is displayed */ synchronized void start() { if (!running) { Thread thread = new Thread(this); thread.start(); } } /** * Stopping player and hiding VideoControl * This happens when Canvas is not current or it is destroyed */ synchronized void stop() { if (player != null && active) { try { videoControl.setVisible(false); player.stop(); } catch (MediaException me) { System.out.println(me.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("MediaException:", me.getMessage(), null, AlertType.ERROR)); } active = false; } } /** * closingVideoCanvas() * Player is stopped and discarded * Full screen mode is set to false * Commands are removed */ private void closingVideoCanvas() { if (this.running == true) { this.running = false; } fsMode = false; this.stop(); this.discardPlayer(); if (this.type == VideoOverlayMIDlet.CAMERA) { removeCommand(captureCommand); } midlet.videoCanvasExit(); } /** * takeSnapshot() * Taking the snapshot: * - Encoding is PNG with videoControl width and height * - Setting image to DisplayCanvas */ private void takeSnapshot() { if (player != null) { try { byte pngImage[] = videoControl.getSnapshot( "encoding=png&width=" + videoControl.getDisplayWidth() + "&height=" + videoControl.getDisplayHeight()); player.stop(); midlet.cameraCanvasCaptured(pngImage); } catch (MediaException me) { System.out.println(me.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("MediaException:", me.getMessage(), null, AlertType.ERROR)); } catch (Exception e) { System.out.println(e.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("Exception:", e.getMessage(), null, AlertType.ERROR)); } } } /** * togglePlayer() * Toggling the player: paused -> play -> paused */ public void togglePlayer() { if (player != null) { if (player.getState() == Player.STARTED) { pausePlayer(); } else { startPlayer(); } repaint(); } else { startPlayer(); } } /** * startPlayer() * Starting the player -> active = true */ public void startPlayer() { if (player != null && !active) { try { videoControl.setVisible(true); player.start(); repaint(); } catch (MediaException me) { System.out.println(me.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("Media exception:", me.getMessage(), null, AlertType.ERROR)); } catch (SecurityException se) { System.out.println(se.getMessage()); Display.getDisplay(this.midlet).setCurrent( new Alert("SecurityException", se.getMessage(), null, AlertType.ERROR)); } active = true; } } /** * pausePlayer() * Pausing the player -> active = false */ public void pausePlayer() { if (player != null) { try { player.stop(); } catch (MediaException me) { } active = false; } } /** * pointerReleased(int x, int y) * Pointer events in ControlBar */ protected void pointerReleased(int x, int y) { if (player == null) { return; } moving = false; if (dragged) { dragged = false; return; } if (hideControlBar) { hideControlBar = false; repaint(); return; } int CB_H = this.controlBar.getHeight(); int CB_W = this.controlBar.getWidth(); int CB_Y = this.controlBar.getY(); int CB_X = this.controlBar.getX(); // Snap or Play/Stop, Show and Hide if (y > CB_Y && y < CB_Y + CB_H && x > CB_X && x < CB_X + CB_W) { if (x > CB_X && x < CB_X + (CB_W / 3)) { // First button takes snapshot or starts/stops the player if (this.type == VideoOverlayMIDlet.CAMERA) { this.takeSnapshot(); } else { this.togglePlayer(); } } else if (x > CB_X + (CB_W / 3) && x < CB_X + 2 * (CB_W / 3)) { // Second button toggles the full screen mode fsMode = !fsMode; this.setFullScreenMode(fsMode); } else if (x > CB_X + 2 * (CB_W / 3) && x < CB_X + CB_W) { // Third button hides the ControlBar this.hideControlBar = true; repaint(); } return; } // In full screen mode, exit is allowed if (fsMode) { if (y >= exitY && x > exitX) { // Closing video closingVideoCanvas(); return; } } } protected void pointerPressed(int x, int y) { // If inside ControlBar, move it if (y > this.controlBar.getY() && y < this.controlBar.getY() + this.controlBar.getHeight() && x > this.controlBar.getX() && x < this.controlBar.getX() + this.controlBar.getWidth()) { moving = true; prev_x = x; prev_y = y; } } protected void pointerDragged(int x, int y) { // Move ControlBar if (moving) { int CB_Y = this.controlBar.getY(); int CB_X = this.controlBar.getX(); CB_X = CB_X + (x - prev_x); CB_Y = CB_Y + (y - prev_y); this.controlBar.setX(CB_X); this.controlBar.setY(CB_Y); prev_x = x; prev_y = y; repaint(); dragged = true; } } public void resume() { synchronized (this) { if (paused) { this.paused = false; } this.notifyAll(); } } public void pause() { synchronized (this) { if (!paused) { this.paused = true; } } } /** * showNotify() * Start thread when Canvas is displayed */ protected void showNotify() { resume(); start(); } /** * hideNotify() * Stop thread when Canvas is hidden */ protected void hideNotify() { pause(); pausePlayer(); } public void run() { this.running = true; while (running) { try { synchronized (this) { if (paused) { this.wait(); } } repaint(); serviceRepaints(); Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } this.running = false; } }