Source Code Cross Referenced for GIFPlayer.java in  » 6.0-JDK-Modules » j2me » com » sun » mmedia » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.mmedia 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0004:         * 
0005:         * This program is free software; you can redistribute it and/or
0006:         * modify it under the terms of the GNU General Public License version
0007:         * 2 only, as published by the Free Software Foundation.
0008:         * 
0009:         * This program is distributed in the hope that it will be useful, but
0010:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012:         * General Public License version 2 for more details (a copy is
0013:         * included at /legal/license.txt).
0014:         * 
0015:         * You should have received a copy of the GNU General Public License
0016:         * version 2 along with this work; if not, write to the Free Software
0017:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0018:         * 02110-1301 USA
0019:         * 
0020:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0021:         * Clara, CA 95054 or visit www.sun.com if you need additional
0022:         * information or have any questions.
0023:         */
0024:        package com.sun.mmedia;
0025:
0026:        import java.io.IOException;
0027:        import java.io.ByteArrayOutputStream;
0028:        import java.util.Vector;
0029:
0030:        import javax.microedition.media.Control;
0031:        import javax.microedition.media.MediaException;
0032:        import javax.microedition.media.PlayerListener;
0033:        import javax.microedition.media.control.VideoControl;
0034:        import javax.microedition.media.control.FramePositioningControl;
0035:        import javax.microedition.media.control.RateControl;
0036:        import javax.microedition.media.control.StopTimeControl;
0037:
0038:        import com.sun.mmedia.Configuration;
0039:        import com.sun.mmedia.VideoRenderer;
0040:
0041:        /**
0042:         * A player for the GIF89a.
0043:         *
0044:         * @created    January 30, 2004
0045:         */
0046:        final public class GIFPlayer extends BasicPlayer implements  Runnable {
0047:            /* Single image decoder */
0048:            private GIFImageDecoder imageDecoder;
0049:
0050:            /* the width of a video frame */
0051:            private int videoWidth;
0052:
0053:            /* the height of a video frame */
0054:            private int videoHeight;
0055:
0056:            /* a full GIF frame, also called the reference frame */
0057:            private int[] referenceFrame = null;
0058:
0059:            /* the play thread */
0060:            private Thread playThread; // default is null
0061:
0062:            /* flag indicating whether to end the play thread.
0063:             * done is set to true upon stopping or closing the player
0064:             * or when the frame count progresses to the total number
0065:             * of frames in this movie.
0066:             */
0067:            private boolean done;
0068:
0069:            /* the start time in milliseconds.
0070:             * startTime is initialized upon start of the play thread.
0071:             */
0072:            private long startTime;
0073:
0074:            /* early threshold value for the display time in milliseconds. */
0075:            private long EARLY_THRESHOLD = 100;
0076:
0077:            /* minimum wait time */
0078:            private final long MIN_WAIT = 50;
0079:
0080:            /* For zero duration GIFs (e.g. non-animated) wait time between STARTED and END_OF_MEDIA */
0081:            private final long ZERO_DURATION_WAIT = 50;
0082:
0083:            /* a table of frame durations */
0084:            private Vector frameTimes;
0085:
0086:            /* the frame count, shows number of rendered frames, and index of next frame to render  */
0087:            private int frameCount;
0088:
0089:            /* Last frame duration while scanning frames */
0090:            private int scanFrameTime;
0091:
0092:            /* elapsed media time since start of stream */
0093:            private long mediaTimeOffset;
0094:
0095:            /* the display time of the last read & created frame  */
0096:            private long displayTime; // default is 0
0097:
0098:            /* the video renderer object for the GIF Player */
0099:            private VideoRenderer videoRenderer;
0100:
0101:            /* the video control object for the GIF Player */
0102:            private VideoControl videoControl;
0103:
0104:            /* the frame positioning control object for the GIF Player */
0105:            private FramePosCtrl framePosControl;
0106:
0107:            /* the rate control object for the GIF Player */
0108:            private RateCtrl rateControl;
0109:
0110:            /* the duration of the movie in microseconds */
0111:            private long duration;
0112:
0113:            /* the seek type of the stream: either <code>NOT_SEEKABLE</code>, 
0114:             * <code>SEEKABLE_TO_START</code> or <code>RANDOM_ACCESSIBLE</code>
0115:             */
0116:            private int seekType;
0117:
0118:            /* the position in the source stream directly after the GIF header */
0119:            private long firstFramePos;
0120:
0121:            /* stopped flag */
0122:            private boolean stopped;
0123:
0124:            /* The lock object of play thread */
0125:            private Object playLock = new Object();
0126:
0127:            /* image data */
0128:            private byte[] imageData;
0129:            private int imageDataLength;
0130:            private int lzwCodeSize;
0131:
0132:            protected Control doGetControl(String type) {
0133:                if (type.startsWith(BasicPlayer.pkgName)) {
0134:
0135:                    type = type.substring(BasicPlayer.pkgName.length());
0136:
0137:                    if (type.equals(BasicPlayer.vicName)
0138:                            || type.equals(BasicPlayer.guiName)) {
0139:                        // video control
0140:                        return videoControl;
0141:                    } else if (type.equals(BasicPlayer.fpcName)) {
0142:                        // frame positioning control
0143:                        return framePosControl;
0144:                    } else if (type.equals(BasicPlayer.racName)) {
0145:                        // rate control
0146:                        return rateControl;
0147:                    } else if (type.equals(BasicPlayer.stcName)) {
0148:                        // stop time control
0149:
0150:                        // StopTimeControl is implemented BasicPlayer,
0151:                        // the parent class of GIF Player
0152:                        return this ;
0153:                    }
0154:                }
0155:                return null;
0156:            }
0157:
0158:            /**
0159:             * Retrieves the duration of the GIF movie.
0160:             *
0161:             * @return    the duration in microseconds.
0162:             */
0163:            protected long doGetDuration() {
0164:                return duration;
0165:            }
0166:
0167:            protected long doGetMediaTime() {
0168:                long mediaTime;
0169:
0170:                if (getState() < STARTED) {
0171:                    mediaTime = mediaTimeOffset;
0172:                } else {
0173:                    mediaTime = ((System.currentTimeMillis() - startTime) * 1000)
0174:                            + mediaTimeOffset;
0175:                    mediaTime *= (rateControl.getRate() / 100000.0);
0176:                }
0177:
0178:                if (mediaTime >= duration) {
0179:                    return duration;
0180:                }
0181:
0182:                return mediaTime;
0183:            }
0184:
0185:            protected long doSetMediaTime(long now) throws MediaException {
0186:                if (seekType == NOT_SEEKABLE)
0187:                    throw new MediaException("stream not seekable");
0188:
0189:                if (state == STARTED)
0190:                    doStop();
0191:
0192:                if (now > duration)
0193:                    now = duration;
0194:
0195:                mediaTimeOffset = now;
0196:
0197:                try {
0198:                    int count = framePosControl.mapTimeToFrame(now);
0199:                    //System.out.println("SetMediaTime to " + now + " (frame = " + count + "), frameCount=" + frameCount);
0200:
0201:                    if (count + 1 < frameCount) {
0202:                        // rewind to beginning
0203:                        frameCount = 0;
0204:                        seekFirstFrame();
0205:                    }
0206:
0207:                    // skip frames
0208:                    while (frameCount <= count && getFrame())
0209:                        // We need to decode all frames to have the correct pixels
0210:                        // for frames with transparent color
0211:                        decodeFrame();
0212:
0213:                    displayTime = getDuration(frameCount) / 1000;
0214:                    //System.out.println("SetMediaTime: displayTime = " + displayTime + "; frameCount=" + frameCount);
0215:
0216:                    renderFrame();
0217:
0218:                    if (state == STARTED)
0219:                        // restart the player
0220:                        doStart();
0221:                } catch (IOException e) {
0222:                    throw new MediaException(e.getMessage());
0223:                }
0224:
0225:                return now;
0226:            }
0227:
0228:            protected void doRealize() throws MediaException {
0229:                duration = TIME_UNKNOWN;
0230:                frameCount = 0;
0231:                mediaTimeOffset = 0;
0232:
0233:                seekType = stream.getSeekType();
0234:
0235:                // parse GIF header
0236:                if (parseHeader()) {
0237:                    scanFrames();
0238:
0239:                    // initialize video control
0240:                    videoRenderer = Configuration.getConfiguration()
0241:                            .getVideoRenderer(this , videoWidth, videoHeight);
0242:                    videoControl = (VideoControl) videoRenderer
0243:                            .getVideoControl();
0244:                    videoRenderer.initRendering(VideoRenderer.XBGR888
0245:                            | VideoRenderer.USE_ALPHA, videoWidth, videoHeight);
0246:
0247:                    // initialize frame positioning control
0248:                    framePosControl = new FramePosCtrl();
0249:
0250:                    // initialize rate control
0251:                    rateControl = new RateCtrl();
0252:
0253:                    referenceFrame = null;
0254:
0255:                } else
0256:                    throw new MediaException("invalid GIF header");
0257:
0258:            }
0259:
0260:            protected void doPrefetch() throws MediaException {
0261:                if (referenceFrame == null)
0262:                    referenceFrame = new int[videoWidth * videoHeight];
0263:
0264:                try {
0265:                    frameCount = 0;
0266:                    seekFirstFrame();
0267:
0268:                    // get first frame
0269:                    if (!getFrame())
0270:                        throw new MediaException("can't get first frame");
0271:
0272:                    decodeFrame();
0273:
0274:                    // If duration is 0 prepare the last frame once.
0275:                    if (duration == 0) {
0276:                        while (getFrame())
0277:                            decodeFrame();
0278:                        renderFrame();
0279:                    }
0280:
0281:                } catch (IOException e) {
0282:                    throw new MediaException("can't seek first frame");
0283:                }
0284:            }
0285:
0286:            protected boolean doStart() {
0287:                if (duration == 0) { // e.g. for non-animated GIFs
0288:                    new Thread(new Runnable() {
0289:                        synchronized public void run() {
0290:                            try {
0291:                                wait(ZERO_DURATION_WAIT);
0292:                            } catch (InterruptedException ie) {
0293:                            }
0294:                            sendEvent(PlayerListener.END_OF_MEDIA, new Long(0));
0295:                        }
0296:                    }).start();
0297:                } else {
0298:                    startTime = System.currentTimeMillis();
0299:
0300:                    if (stopped) {
0301:                        // wake up existing play thread
0302:                        stopped = false;
0303:
0304:                        synchronized (playLock) {
0305:                            playLock.notifyAll();
0306:                        }
0307:                    } else {
0308:                        displayTime = getFrameInterval(frameCount) / 1000;
0309:
0310:                        // Ensure that previous thread has finished
0311:                        playThreadFinished();
0312:
0313:                        synchronized (playLock) {
0314:                            if (playThread == null) {
0315:                                // Check for null is a protection against several
0316:                                // simultaneous doStart()'s trying to create a new thread.
0317:                                // But if playThreadFinished() failed to terminate
0318:                                // playThread, we can have a problem
0319:
0320:                                // create a new play thread
0321:                                playThread = new Thread(this );
0322:                                playThread.start();
0323:                            }
0324:                        }
0325:                    }
0326:                }
0327:                return true;
0328:            }
0329:
0330:            protected void doStop() throws MediaException {
0331:                if (stopped)
0332:                    return;
0333:
0334:                synchronized (playLock) {
0335:                    try {
0336:                        if (playThread != null) {
0337:                            stopped = true;
0338:                            playLock.notifyAll();
0339:                            mediaTimeOffset = doGetMediaTime();
0340:                            startTime = 0;
0341:                            playLock.wait();
0342:                        }
0343:                    } catch (InterruptedException ie) {
0344:                        //do nothing
0345:                    }
0346:                }
0347:            }
0348:
0349:            protected void doDeallocate() {
0350:                playThreadFinished();
0351:
0352:                stopped = false;
0353:                referenceFrame = null;
0354:            }
0355:
0356:            protected void doClose() {
0357:                done = true;
0358:
0359:                if (videoRenderer != null) {
0360:                    videoRenderer.close();
0361:                    videoRenderer = null;
0362:                }
0363:
0364:                frameTimes = null;
0365:                imageDecoder = null;
0366:                imageData = null;
0367:            }
0368:
0369:            public void run() {
0370:                done = false;
0371:
0372:                while (!done) {
0373:                    if (!stopped)
0374:                        processFrame();
0375:
0376:                    if (stopped) {
0377:                        synchronized (playLock) {
0378:                            playLock.notifyAll();
0379:
0380:                            try {
0381:                                playLock.wait();
0382:                            } catch (InterruptedException e) {
0383:                                // nothing to do
0384:                            }
0385:                        }
0386:                    }
0387:                }
0388:
0389:                if (!stopped && !framePosControl.isActive()) {
0390:                    // the run loop may have terminated prematurely, possibly
0391:                    // due to an I/O error...
0392:                    // In this case, the duration needs to be updated.
0393:                    if (frameCount < frameTimes.size()) {
0394:                        duration = getDuration(frameCount);
0395:
0396:                        sendEvent(PlayerListener.DURATION_UPDATED, new Long(
0397:                                duration));
0398:                    }
0399:
0400:                    // send an end-of-media if the player was not stopped
0401:                    // and the run loop terminates because the end of media
0402:                    // was reached.
0403:                    mediaTimeOffset = doGetMediaTime();
0404:                    startTime = 0;
0405:
0406:                    sendEvent(PlayerListener.END_OF_MEDIA, new Long(
0407:                            mediaTimeOffset));
0408:                }
0409:
0410:                synchronized (playLock) {
0411:                    playThread = null;
0412:                    playLock.notifyAll();
0413:                }
0414:            }
0415:
0416:            private void stopTimeReached() {
0417:                // stop the player
0418:                mediaTimeOffset = doGetMediaTime();
0419:                stopped = true;
0420:                startTime = 0;
0421:                // send STOPPED_AT_TIME event
0422:                satev();
0423:            }
0424:
0425:            /**
0426:             * Ensures that playThread dies
0427:             */
0428:            private void playThreadFinished() {
0429:                synchronized (playLock) {
0430:                    // stop the playThread if it was created and started
0431:                    if (playThread != null) {
0432:                        done = true;
0433:
0434:                        // wake up the play thread if it was stopped
0435:                        playLock.notifyAll();
0436:
0437:                        // wait for the play thread to terminate gracefully
0438:                        try {
0439:                            // set maximum wait limit in case anything goes wrong.
0440:                            playLock.wait(5000);
0441:                        } catch (InterruptedException e) {
0442:                            // nothing to do.
0443:                        }
0444:                    }
0445:                }
0446:            }
0447:
0448:            private long getDuration(int frameCount) {
0449:                long duration = 0;
0450:
0451:                for (int i = 0; i < frameCount; i++) {
0452:                    duration += ((Long) frameTimes.elementAt(i)).longValue();
0453:                }
0454:
0455:                return duration;
0456:            }
0457:
0458:            private long getFrameInterval(int frameCount) {
0459:                long interval = 0;
0460:
0461:                if (frameCount > 0 && frameCount <= frameTimes.size()) {
0462:                    interval = ((Long) frameTimes.elementAt(frameCount - 1))
0463:                            .longValue();
0464:                }
0465:
0466:                return interval;
0467:            }
0468:
0469:            private int timeToFrame(long mediaTime) {
0470:                int frame = 0;
0471:
0472:                long elapsedTime = 0;
0473:
0474:                for (int i = 0; i < frameTimes.size(); i++) {
0475:                    long interval = ((Long) frameTimes.elementAt(i))
0476:                            .longValue();
0477:
0478:                    elapsedTime += interval;
0479:
0480:                    if (elapsedTime <= mediaTime)
0481:                        frame++;
0482:                    else
0483:                        break;
0484:                }
0485:
0486:                return frame;
0487:            }
0488:
0489:            private long frameToTime(int frameNumber) {
0490:                long elapsedTime = 0;
0491:
0492:                for (int i = 0; i < frameTimes.size(); i++) {
0493:                    long interval = ((Long) frameTimes.elementAt(i))
0494:                            .longValue();
0495:
0496:                    if (i < frameNumber)
0497:                        elapsedTime += interval;
0498:                    else
0499:                        break;
0500:                }
0501:
0502:                return elapsedTime;
0503:            }
0504:
0505:            private void processFrame() {
0506:                // the media time in milliseconds
0507:                long mediaTime = doGetMediaTime() / 1000;
0508:
0509:                // frame interval in milliseconds
0510:                long frameInterval = getFrameInterval(frameCount) / 1000;
0511:                //System.out.println("Frame: " + frameCount + ", length: " + frameInterval + ", at: " + mediaTime + ", displayTime: " + displayTime);
0512:
0513:                if (mediaTime + EARLY_THRESHOLD > displayTime) {
0514:                    // get the next frame
0515:                    if (!getFrame()) {
0516:                        // wait until end of last frame
0517:                        synchronized (playLock) {
0518:                            try {
0519:                                long waitTime = displayTime - mediaTime;
0520:
0521:                                if (waitTime > 0)
0522:                                    playLock.wait(waitTime);
0523:
0524:                            } catch (InterruptedException e) {
0525:                                // nothing to do
0526:                            }
0527:                        }
0528:                        done = true;
0529:                        return;
0530:                    }
0531:                    decodeFrame();
0532:
0533:                    // frame interval in milliseconds
0534:                    frameInterval = getFrameInterval(frameCount) / 1000;
0535:
0536:                    // move display time to end of frame
0537:                    displayTime += frameInterval;
0538:                }
0539:
0540:                // render last read frame
0541:                renderFrame();
0542:
0543:                // report that stop time has been reached if
0544:                // the mediaTime is greater or equal to stop time.      
0545:                if (stopTime != StopTimeControl.RESET
0546:                        && doGetMediaTime() >= stopTime) {
0547:                    stopTimeReached();
0548:                }
0549:
0550:                if (!stopped) {
0551:                    // threshold levels in milliseconds
0552:                    // It makes playback falter if frame intervals differ
0553:                    //EARLY_THRESHOLD = 250;
0554:                    //if (frameInterval > 0 && frameInterval < EARLY_THRESHOLD)
0555:                    //    EARLY_THRESHOLD = frameInterval / 2;
0556:
0557:                    mediaTime = doGetMediaTime() / 1000;
0558:
0559:                    if (mediaTime + EARLY_THRESHOLD <= displayTime) {
0560:                        // wait for a bit
0561:                        synchronized (playLock) {
0562:                            try {
0563:                                if (!done) {
0564:                                    mediaTime = doGetMediaTime() / 1000;
0565:
0566:                                    long waitTime = displayTime
0567:                                            - EARLY_THRESHOLD - mediaTime;
0568:
0569:                                    while (!stopped && waitTime > 0) {
0570:                                        if (waitTime > MIN_WAIT) {
0571:                                            playLock.wait(MIN_WAIT);
0572:                                            waitTime -= MIN_WAIT;
0573:                                        } else {
0574:                                            playLock.wait(waitTime);
0575:                                            waitTime = 0;
0576:                                        }
0577:
0578:                                        if (stopTime != StopTimeControl.RESET
0579:                                                && doGetMediaTime() >= stopTime) {
0580:                                            stopTimeReached();
0581:                                        }
0582:                                    }
0583:                                }
0584:                            } catch (InterruptedException e) {
0585:                                // nothing to do
0586:                            }
0587:                        }
0588:                    }
0589:                }
0590:            }
0591:
0592:            private void seekFirstFrame() throws IOException {
0593:                if (seekType == RANDOM_ACCESSIBLE) {
0594:                    // seek to the beginning of the first frame
0595:                    stream.seek(firstFramePos);
0596:                } else { // SEEKABLE_TO_START           
0597:                    // seek to the start of stream and parse the header
0598:                    stream.seek(0);
0599:                    parseHeader();
0600:                }
0601:                imageDecoder.clearImage();
0602:            }
0603:
0604:            private void decodeFrame() {
0605:                if (imageData != null && imageDecoder != null
0606:                        && referenceFrame != null)
0607:                    imageDecoder.decodeImage(lzwCodeSize, imageDataLength,
0608:                            imageData, referenceFrame);
0609:            }
0610:
0611:            private void renderFrame() {
0612:                if (referenceFrame != null)
0613:                    videoRenderer.render(referenceFrame);
0614:            }
0615:
0616:            private void scanFrames() throws MediaException {
0617:                //System.out.println("scanFrames at pos " + stream.tell());
0618:                frameCount = 0;
0619:                scanFrameTime = 0;
0620:                duration = 0;
0621:
0622:                frameTimes = new Vector();
0623:
0624:                boolean eos = false;
0625:
0626:                do {
0627:                    int id;
0628:
0629:                    try {
0630:                        id = readUnsignedByte();
0631:                        //System.out.println("scanFrames: id=" + id);
0632:                    } catch (IOException e) {
0633:                        id = 0x3b;
0634:                    }
0635:
0636:                    if (id == 0x21) {
0637:                        parseControlExtension(true);
0638:                    } else if (id == 0x2c) {
0639:                        parseImageDescriptor(true);
0640:                        frameCount++;
0641:                        frameTimes.addElement(new Long(scanFrameTime));
0642:                        duration += scanFrameTime;
0643:                        scanFrameTime = 0; // ?? reset to zero
0644:                    } else if (id == 0x3b) {
0645:                        eos = true;
0646:                    } else {
0647:                        eos = true;
0648:                    }
0649:                } while (!eos);
0650:
0651:                // reset the frame counter
0652:                frameCount = 0;
0653:
0654:                try {
0655:                    seekFirstFrame();
0656:                } catch (IOException e) {
0657:                    throw new MediaException(e.getMessage());
0658:                }
0659:            }
0660:
0661:            private boolean getFrame() {
0662:                //System.out.println("getFrame at pos " + stream.tell());
0663:
0664:                if (stream.tell() == 0)
0665:                    parseHeader();
0666:
0667:                boolean eos = false;
0668:
0669:                imageData = null;
0670:
0671:                do {
0672:                    int id;
0673:
0674:                    try {
0675:                        id = readUnsignedByte();
0676:                        //System.out.println("getFrame: id=" + id);
0677:                    } catch (IOException e) {
0678:                        id = 0x3b;
0679:                    }
0680:
0681:                    if (id == 0x21) {
0682:                        parseControlExtension(false);
0683:                    } else if (id == 0x2c) {
0684:                        parseImageDescriptor(false);
0685:                    } else if (id == 0x3b) {
0686:                        eos = true;
0687:                    } else {
0688:                        eos = true;
0689:                    }
0690:                } while (!eos && imageData == null);
0691:
0692:                if (imageData != null) {
0693:                    frameCount++;
0694:                    return true;
0695:                }
0696:
0697:                return false;
0698:            }
0699:
0700:            private boolean parseHeader() {
0701:                //System.out.println("parseHeader at pos " + stream.tell());
0702:
0703:                byte[] header = new byte[6];
0704:
0705:                try {
0706:                    stream.read(header, 0, 6);
0707:                } catch (IOException e) {
0708:                    return false;
0709:                }
0710:
0711:                // check that signature spells GIF
0712:                if (header[0] != 'G' || header[1] != 'I' || header[2] != 'F')
0713:                    return false;
0714:
0715:                // check that version spells either 87a or 89a
0716:                if (header[3] != '8' || header[4] != '7' && header[4] != '9'
0717:                        || header[5] != 'a')
0718:                    return false;
0719:
0720:                return parseLogicalScreenDescriptor();
0721:            }
0722:
0723:            private boolean parseLogicalScreenDescriptor() {
0724:                //System.out.println("parseLogicalScreenDescriptor at pos " + stream.tell());
0725:
0726:                byte[] logicalScreenDescriptor = new byte[7];
0727:                byte[] globalColorTable = null;
0728:
0729:                try {
0730:                    stream.read(logicalScreenDescriptor, 0, 7);
0731:                } catch (IOException e) {
0732:                    return false;
0733:                }
0734:
0735:                // logical screen width
0736:                videoWidth = readShort(logicalScreenDescriptor, 0);
0737:
0738:                // logical screen height
0739:                videoHeight = readShort(logicalScreenDescriptor, 2);
0740:
0741:                // flags
0742:                int flags = logicalScreenDescriptor[4];
0743:
0744:                // global color table flag
0745:                boolean globalTable = ((flags >> 7) & 0x01) == 1;
0746:
0747:                // color resolution
0748:                int resolution = ((flags >> 4) & 0x07) + 1;
0749:
0750:                // sort flag: not used in player
0751:                //int sortFlag = (flags >> 3) & 0x01;
0752:
0753:                // global color table depth
0754:                int tableDepth = (flags & 0x07) + 1;
0755:
0756:                // background color index
0757:                int index = logicalScreenDescriptor[5] & 0xff;
0758:
0759:                // pixel aspect ratio: not used inplayer
0760:                //int pixelAspectRatio = logicalScreenDescriptor[6];
0761:
0762:                imageDecoder = new GIFImageDecoder(videoWidth, videoHeight,
0763:                        resolution);
0764:
0765:                if (globalTable) {
0766:                    int size = 3 * (1 << tableDepth);
0767:                    globalColorTable = new byte[size];
0768:
0769:                    try {
0770:                        stream.read(globalColorTable, 0, size);
0771:                    } catch (IOException e) {
0772:                    }
0773:
0774:                    imageDecoder.setGlobalPalette(tableDepth, globalColorTable,
0775:                            index);
0776:                }
0777:
0778:                firstFramePos = stream.tell();
0779:
0780:                return true;
0781:            }
0782:
0783:            private int readShort(byte data[], int offset) {
0784:                int lo = data[offset] & 0xff;
0785:                int hi = data[offset + 1] & 0xff;
0786:
0787:                return lo + (hi << 8);
0788:            }
0789:
0790:            private int readShort() {
0791:                int val = 0;
0792:
0793:                try {
0794:                    int lo = readUnsignedByte();
0795:                    int hi = readUnsignedByte();
0796:
0797:                    val = lo + (hi << 8);
0798:                } catch (IOException e) {
0799:                }
0800:
0801:                return val;
0802:            }
0803:
0804:            private void parseImageDescriptor(boolean scan) {
0805:                //System.out.println("parseImageDescriptor at pos " + stream.tell());
0806:                byte[] imageDescriptor = new byte[9];
0807:                byte[] localColorTable = null;
0808:
0809:                try {
0810:                    stream.read(imageDescriptor, 0, 9);
0811:                } catch (IOException e) {
0812:                }
0813:
0814:                // packed fields
0815:                int flags = imageDescriptor[8];
0816:
0817:                // local color table flag
0818:                boolean localTable = ((flags >> 7) & 1) == 1;
0819:
0820:                int tableDepth = (flags & 0x07) + 1;
0821:
0822:                if (localTable) {
0823:                    int size = 3 * (1 << tableDepth);
0824:
0825:                    localColorTable = new byte[size];
0826:
0827:                    try {
0828:                        stream.read(localColorTable, 0, size);
0829:                    } catch (IOException e) {
0830:                    }
0831:                }
0832:
0833:                if (!scan) {
0834:                    // image left position
0835:                    int leftPos = readShort(imageDescriptor, 0);
0836:
0837:                    // image top position
0838:                    int topPos = readShort(imageDescriptor, 2);
0839:
0840:                    // image width
0841:                    int width = readShort(imageDescriptor, 4);
0842:
0843:                    // image height
0844:                    int height = readShort(imageDescriptor, 6);
0845:
0846:                    // interlace flag
0847:                    boolean interlaceFlag = ((flags >> 6) & 0x01) == 1;
0848:
0849:                    // sort flag: not used in player
0850:                    //int sortFlag = (flags >> 5) & 0x01;
0851:
0852:                    imageDecoder.newFrame(leftPos, topPos, width, height,
0853:                            interlaceFlag);
0854:
0855:                    // local color table size
0856:                    if (localTable)
0857:                        imageDecoder.setLocalPalette(tableDepth,
0858:                                localColorTable);
0859:                }
0860:
0861:                parseImageData();
0862:            }
0863:
0864:            private void parseImageData() {
0865:                //System.out.println("parseImageData at pos " + stream.tell());
0866:                int idx = 0;
0867:
0868:                try {
0869:                    lzwCodeSize = readUnsignedByte();
0870:
0871:                    if (imageData == null)
0872:                        imageData = new byte[1024];
0873:
0874:                    int size;
0875:
0876:                    do {
0877:                        size = readUnsignedByte();
0878:
0879:                        if (imageData.length < idx + size) {
0880:                            // increase image data buffer
0881:                            byte data[] = new byte[idx + size];
0882:                            System.arraycopy(imageData, 0, data, 0, idx);
0883:                            imageData = data;
0884:                        }
0885:
0886:                        if (size > 0)
0887:                            idx += stream.read(imageData, idx, size);
0888:
0889:                    } while (size != 0);
0890:
0891:                    //imageDataLength = idx;
0892:                } catch (IOException e) {
0893:                    //imageDataLength = 0;
0894:                }
0895:                // Supporting unfinished GIFs
0896:                imageDataLength = idx;
0897:                //System.out.println("parsed image data bytes: " + idx);
0898:            }
0899:
0900:            private void parsePlainTextExtension() {
0901:                try {
0902:                    // block size
0903:                    int size = readUnsignedByte();
0904:                    if (size != 12) {
0905:                        // ERROR
0906:                    }
0907:
0908:                    // text grid left position
0909:                    int leftPos = readShort();
0910:
0911:                    // text grid top position
0912:                    int topPos = readShort();
0913:
0914:                    // text grid width
0915:                    int width = readShort();
0916:
0917:                    // text grid height
0918:                    int height = readShort();
0919:
0920:                    // character cell width
0921:                    int cellWidth = readUnsignedByte();
0922:
0923:                    // character cell height
0924:                    int cellHeight = readUnsignedByte();
0925:
0926:                    // text foreground color index
0927:                    int fgIndex = readUnsignedByte();
0928:
0929:                    // text background color index
0930:                    int bgIndex = readUnsignedByte();
0931:
0932:                    // plain text data
0933:                    do {
0934:                        size = readUnsignedByte();
0935:
0936:                        if (size > 0) {
0937:                            byte[] data = new byte[size];
0938:
0939:                            stream.read(data, 0, size);
0940:                        }
0941:                    } while (size != 0);
0942:                } catch (IOException e) {
0943:                }
0944:            }
0945:
0946:            private void parseControlExtension(boolean scan) {
0947:                //System.out.println("parseControlExtension at pos " + stream.tell());
0948:                try {
0949:                    int label = readUnsignedByte();
0950:
0951:                    if (label == 0xff) {
0952:                        parseApplicationExtension();
0953:                    } else if (label == 0xfe) {
0954:                        parseCommentExtension();
0955:                    } else if (label == 0xf9) {
0956:                        parseGraphicControlExtension(scan);
0957:                    } else if (label == 0x01) {
0958:                        parsePlainTextExtension();
0959:                    } else {
0960:                        // unkown control extension
0961:                    }
0962:                } catch (IOException e) {
0963:                }
0964:            }
0965:
0966:            private void parseApplicationExtension() {
0967:                //System.out.println("parseApplicationExtension at pos " + stream.tell());
0968:                try {
0969:                    // block size
0970:                    int size = readUnsignedByte();
0971:
0972:                    if (size != 11) {
0973:                        // System.out.println("ERROR");
0974:                    }
0975:
0976:                    // application identifier
0977:                    byte[] data = new byte[8];
0978:                    stream.read(data, 0, 8);
0979:
0980:                    // application authentication code
0981:                    data = new byte[3];
0982:                    stream.read(data, 0, 3);
0983:
0984:                    do {
0985:                        size = readUnsignedByte();
0986:
0987:                        if (size > 0) {
0988:                            data = new byte[size];
0989:
0990:                            stream.read(data, 0, size);
0991:                        }
0992:                    } while (size != 0);
0993:                } catch (IOException e) {
0994:                }
0995:            }
0996:
0997:            private void parseCommentExtension() {
0998:                //System.out.println("parseCommentExtension at pos " + stream.tell());
0999:                try {
1000:                    int size;
1001:
1002:                    do {
1003:                        size = readUnsignedByte();
1004:
1005:                        if (size > 0) {
1006:                            byte[] data = new byte[size];
1007:
1008:                            stream.read(data, 0, size);
1009:                        }
1010:                    } while (size != 0);
1011:                } catch (IOException e) {
1012:                }
1013:            }
1014:
1015:            private void parseGraphicControlExtension(boolean scan) {
1016:                //System.out.println("parseGraphicControlExtension at pos " + stream.tell());
1017:
1018:                byte[] graphicControl = new byte[6];
1019:
1020:                try {
1021:                    stream.read(graphicControl, 0, 6);
1022:                } catch (IOException e) {
1023:                }
1024:
1025:                // block size: not used in player - validation only
1026:                //int size = graphicControl[0] & 0xff;
1027:
1028:                //if (size != 4) {
1029:                // ERROR: invalid block size in graphic control
1030:                //}
1031:
1032:                if (scan) {
1033:                    // delay time
1034:                    scanFrameTime = readShort(graphicControl, 2) * 10000;
1035:                } else {
1036:                    // packed field
1037:                    int flags = graphicControl[1] & 0xff;
1038:
1039:                    // transparency flag
1040:                    boolean transparencyFlag = (flags & 0x01) == 1;
1041:
1042:                    // user input: not used in player
1043:                    //int userInput = (flags & 0x02) == 2;
1044:
1045:                    // undraw mode
1046:                    int undrawMode = (flags >> 2) & 0x07;
1047:
1048:                    int transparencyColorIndex = -1;
1049:
1050:                    if (transparencyFlag)
1051:                        // transparent color index
1052:                        transparencyColorIndex = graphicControl[4] & 0xff;
1053:
1054:                    imageDecoder.setGraphicsControl(undrawMode,
1055:                            transparencyColorIndex);
1056:                }
1057:                // block terminator: shoud be 0
1058:                //int terminator = graphicControl[5] & 0xff;
1059:            }
1060:
1061:            private byte[] oneByte = new byte[1];
1062:
1063:            private int readUnsignedByte() throws IOException {
1064:                if (stream.read(oneByte, 0, 1) == -1)
1065:                    throw new IOException();
1066:
1067:                return oneByte[0] & 0xff;
1068:            }
1069:
1070:            class FramePosCtrl implements  FramePositioningControl {
1071:                /**
1072:                 * indicates whether the frame positioning control
1073:                 * is actively engaged.
1074:                 */
1075:                private boolean active;
1076:
1077:                /**
1078:                 * The constructor of FramePosCtrl.
1079:                 */
1080:                FramePosCtrl() {
1081:                    active = false;
1082:                }
1083:
1084:                public int seek(int frameNumber) {
1085:                    active = true;
1086:
1087:                    // clear the End-of-media flag to ensure that
1088:                    // a consecutive start call will start the player
1089:                    // from the seek position and not from the first
1090:                    // frame.
1091:                    EOM = false;
1092:
1093:                    if (frameNumber < 0) {
1094:                        frameNumber = 0;
1095:                    } else if (frameNumber >= frameTimes.size()) {
1096:                        frameNumber = frameTimes.size() - 1;
1097:                    }
1098:
1099:                    long time = mapFrameToTime(frameNumber);
1100:
1101:                    try {
1102:                        doSetMediaTime(time);
1103:                    } catch (MediaException e) {
1104:                        // nothing to do
1105:                    }
1106:
1107:                    active = false;
1108:
1109:                    return frameNumber;
1110:                }
1111:
1112:                public int skip(int framesToSkip) {
1113:                    active = true;
1114:
1115:                    // clear the End-of-media flag to ensure that
1116:                    // a consecutive start call will start the player
1117:                    // from the seek position and not from the first
1118:                    // frame.
1119:                    EOM = false;
1120:
1121:                    int frames_skipped = 0;
1122:
1123:                    int oldFrame = frameCount - 1;
1124:
1125:                    if (oldFrame < 0) {
1126:                        oldFrame = 0;
1127:                    } else if (oldFrame >= frameTimes.size()) {
1128:                        oldFrame = frameTimes.size() - 1;
1129:                    }
1130:
1131:                    long newFrame = (long) oldFrame + framesToSkip;
1132:
1133:                    if (newFrame < 0) {
1134:                        newFrame = 0;
1135:                    } else if (newFrame >= frameTimes.size()) {
1136:                        newFrame = frameTimes.size() - 1;
1137:                    }
1138:
1139:                    long time = mapFrameToTime((int) newFrame);
1140:
1141:                    try {
1142:                        doSetMediaTime(time);
1143:
1144:                        frames_skipped = (int) (newFrame - oldFrame);
1145:                    } catch (MediaException e) {
1146:                        // nothing to do
1147:                    }
1148:
1149:                    active = false;
1150:
1151:                    return frames_skipped;
1152:                }
1153:
1154:                public long mapFrameToTime(int frameNumber) {
1155:                    if (frameNumber < 0 || frameNumber >= frameTimes.size()) {
1156:                        return -1;
1157:                    }
1158:
1159:                    return (long) (frameToTime(frameNumber)
1160:                            * rateControl.getRate() / 100000L);
1161:                }
1162:
1163:                public int mapTimeToFrame(long mediaTime) {
1164:                    if (mediaTime < 0 || mediaTime > duration) {
1165:                        return -1;
1166:                    }
1167:
1168:                    long time = mediaTime * rateControl.getRate() / 100000;
1169:
1170:                    return (int) timeToFrame(time);
1171:                }
1172:
1173:                public boolean isActive() {
1174:                    return active;
1175:                }
1176:            }
1177:
1178:            class RateCtrl implements  RateControl {
1179:                /* the playback rate in 1000 times the percentage of the
1180:                 * actual rate.
1181:                 */
1182:                private int rate;
1183:
1184:                /* the minimum playback rate */
1185:                private final int MIN_PLAYBACK_RATE = 10000; // 10%
1186:
1187:                /* the maximum playback rate */
1188:                private final int MAX_PLAYBACK_RATE = 200000; // 200%
1189:
1190:                RateCtrl() {
1191:                    rate = 100000; // normal speed, 100%
1192:                }
1193:
1194:                public int setRate(int millirate) {
1195:                    if (millirate < MIN_PLAYBACK_RATE) {
1196:                        rate = MIN_PLAYBACK_RATE;
1197:                    } else if (millirate > MAX_PLAYBACK_RATE) {
1198:                        rate = MAX_PLAYBACK_RATE;
1199:                    } else {
1200:                        rate = millirate;
1201:                    }
1202:
1203:                    return rate;
1204:                }
1205:
1206:                public int getRate() {
1207:                    return rate;
1208:                }
1209:
1210:                public int getMaxRate() {
1211:                    return MAX_PLAYBACK_RATE;
1212:                }
1213:
1214:                public int getMinRate() {
1215:                    return MIN_PLAYBACK_RATE;
1216:                }
1217:            }
1218:
1219:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.