Java 101之线程基础

作者: Al Saganich

<让我们深入了解一下Java线程,以及了解一下为什么需要需要开发基于线程的应用程序>

线程是Java语言的一个部分,而且是Java的最强大的功能之一。究竟什么是线程,为什么要开发基于线程的应用程序?在本文中,我们将深入了解一下线程的用法,以及使用线程的一些技术。在我们开始讲述线程之前,最好先了解一下有关背景知识和分析一下线程的工作原理。

当程序员一开始开发应用程序时,这些应用程序只能在一个时间内完成一件事情。应用程序从主程序开始执行,直到运行结束,像 Fortran/Cobol/Basic这些语言均是如此。

随着时间的推移,计算机发展到可以在同一时间段内运行不止一个应用程序的时代了,但是应用程序运行时仍然是串行的,即从开始运行到结束,下一条指令接着上一条指令执行。到最近,程序发展到可以在执行时,以若干个线程的形式运行。Java就具有运行多线程的能力,可以在同一时间段内进行几个操作,这就意味着给定的操作不必等到另外一个操作结束之后,才能开始。而且对某个操作可以指定更高一级的优先级。

不少程序语言,包括ADA, Modula-2和C/C++,已经可以提供对线程的支持。同这些语言相比,Java的特点是从最底层开始就对线程提供支持。除此以外,标准的Java类是可重入的,允许在一个给定的应用程序中由多个线程调用同一方法,而线程彼此之间又互不干扰。Java的这些特点为多线程应用程序的设计奠定了基础。

什么是线程?

究竟什么是线程呢?正如在图A中所示,一个线程是给定的指令的序列 (你所编写的代码),一个栈(在给定的方法中定义的变量),以及一些共享数据(类一级的变量)。线程也可以从全局类中访问静态数据。


栈以及可能的一些共享数据


每个线程有其自己的堆栈和程序计数器(PC)。你可以把程序计数器(PC)设想为用于跟踪线程正在执行的指令,而堆栈用于跟踪线程的上下文,上下文是当线程执行到某处时,当前的局部变量的值。虽然你可以编写出在线程之间传送数据的子程序,在正常情况下,一个线程不能访问另外一个线程的栈变量。

一个线程必须处于如下四种可能的状态之一,这四种状态为:

  • 初始态:一个线程调用了new方法之后,并在调用start方法之前的所处状态。在初始态中,可以调用start和stop方法。
  • Runnable一旦线程调用了start 方法,线程就转到Runnable 状态,注意,如果线程处于Runnable状态,它也有可能不在运行,这是因为还有优先级和调度问题。 阻塞/ NonRunnable:线程处于阻塞/NonRunnable状态,这是由两种可能性造成的:要么是因挂起而暂停的,要么是由于某些原因而阻塞的,例如包括等待IO请求的完成。 退出:线程转到退出状态,这有两种可能性,要么是run方法执行结束,要么是调用了stop方法。
  • 最后一个概念就是线程的优先级,线程可以设定优先级,高优先级的线程可以安排在低优先级线程之前完成。一个应用程序可以通过使用线程中的方法setPriority(int),来设置线程的优先级大小。

前面我们已经讲述了线程的基本知识,现在我们可以来看看Java为我们提供的用来开发基于线程的应用程序的两种机制:线程类和Runnable 接口。

派生线程类

最简单的编写基于线程的代码的方法之一,就是派生java.lang.Thread 类。该线程类是java.lang 包的一个成员,在缺省情况下,线程类可以被所有的Java应用程序调用。为了使用线程类,我们需要了解The java.lang.Thread 类中定义的五个方法:

  • run():该方法用于线程的执行。你需要重载该方法,以便让线程做特定的工作。
  • start():该方法使得线程启动run()
  • stop():该方法同start方法的作用相反,停止线程的运行。
  • suspend():该方法同stop方法不同的是,它并不终止未完成的线程,它仅仅挂起线程,以后还可恢复。
  • resume():该方法重新启动已经挂起的线程。

 

运行List A中的程序,运行结果见List B

List A :扩展线程类

class TestThreads {
  public static void main (String args []) {
     class MyThread extends Thread {
        String which;
        MyThread (String which)            {
        this.which = which;          
     }
     public void run() {
        int iterations = (int)(Math.random()*100) %15;
        int sleepinterval = (int)(Math.random()*1000);
        System.out.println(which + " running for " + iterations +" iterations");
        System.out.println(which + " sleeping for " + sleepinterval + "ms between loops");
        for (int i = 0; < iterations; i++) {
                      System.out.println(which +" " + i);
                              try {
                                  Thread.sleep(sleepinterval);
                              } catch (InterruptedException e) {}
                          }
                      }
       }

       MyThread a = new MyThread("Thread A");
       MyThread b = new MyThread("Thread B");
       MyThread c = new MyThread("Thread C");
       a.start();
       b.start();
       c.start();
   }
}

ListB: 清单A的输出

Thread A running for 16 iterations

Thread C running for 15 iterations

Thread B running for 14 iterations

Thread A sleeping for 305ms between

   loops

Thread C sleeping for 836ms between

   loops

Thread B sleeping for 195ms between

   loops

Thread A 0

Thread C 0

Thread B 0

. . .

Thread C 13

Thread B 13

Thread A 14

Thread C 14

Thread A 15

List A演示了如何从现有的Thread类中派生出一个新类。新创建的类重载了run 方法。有趣的是,实现run 方法不必很严格,因为Thread类提供一个缺省的run方法,尽管它不是特别有用。

在有些场合,我们不能简单地改变指定对象的父类。我们仍然需要采用线程。这时,我们就需要用到Runnable接口。

使用Runnable接口

开发线程应用程序的第二个方法是通过Runnable接口来实现。在不少场合,你不能重新定义类的父母,或者不能定义派生的线程类,也许你的类的层次要求你的父类为特定的类。在这些情况下,可以通过Runnable接口来实现多线程的功能。

提示:接口是个复杂的技术,要彻底理解它的用法需要花费力气。感兴趣的读者可以阅读我的前一篇文章《接口的阐述》,发表在1998年5月的 Visual J++ Developer's Journal杂志上。

List C是一个简单的动画小程序,它是一个使用Runnable接口的例子。该例子可以放在网页上,它需要从Applet类中派生出来。该小程序的目的是通过对一个接一个的图象进行着色,从而显示出动画的效果。因为动画占用了不少处理器时间,我们不打算在图象着色的时候阻塞其他进程的运行。例如,如果打算停止动画,我们不想等到它运行结束时,再调用stop方法。换句话说,我们可以让小程序线程化。

List C: 动画小程序

import java.applet.*;
import java.awt.*;


public class TstRunnable extends Applet
    implements Runnable {
  private Thread m_Thread = null;
  private Image m_Images[];
  private Image m_CurrentImage =null;
  private int m_nImgWidth = 0;
  private int m_nImgHeight = 0;
  private boolean m_fAllLoaded =  alse;
  private final int NUM_IMAGES = 18;

  public TstRunnable() { }
  private void displayImage(Graphics g) {
     if ( null != m_CurrentImage )
        g.drawImage(m_CurrentImage,(getSize().width - m_nImgWidth) / 2, 
                      (getSize().height - m_nImgHeight) / 2, null);
  }
  public void paint(Graphics g) {
     if (null != m_CurrentImage) {
        Rectangle r = g.getClipBounds();
        g.clearRect(r.x, r.y, r.width, r.height);
        displayImage(g);
    }
     else
        g.drawString("Loading images...", 10, 20);
  }
// The Applets start method is called when the page is first shown.
  public void start() {
     if (m_Thread == null) {
        m_Thread = new Thread(this);
        m_Thread.start();
     }
 }
// The Applets stop method is called when the page is hidden.
  public void stop() {
     if (m_Thread != null) {
        m_Thread.stop();
        m_Thread = null;
     }
  }
// The run method is used by the thread
//   object we created in this start method.
  public void run() {
     int iWhichImage = 0;
     Graphics m_Graphics = getGraphics();
     repaint();
     m_Graphics = getGraphics();
     m_Images   = newImage[NUM_IMAGES];
     MediaTracker tracker = new MediaTracker(this);
     String strImage;
     for (int i = 1; i <= NUM_IMAGES; i++) {
        m_Images[i-1] = getImage(getCodeBase(),          
                      "img" + new Integer(i).toString() + ".gif");
        tracker.addImage(m_Images[i-1],0);
     }
     try {
        tracker.waitForAll();
        m_fAllLoaded = !tracker.isErrorAny();
     } catch (InterruptedException e) {}
     if (!m_fAllLoaded) {
        stop();
        m_Graphics.drawString("Error loading images!", 10, 40);
        return;
     }
 // Assuming all images are the same          
 // width and height.
 //------------------------------------
     m_nImgWidth  = m_Images[0].getWidth(this);
     m_nImgHeight = m_Images[0].getHeight(this);
     repaint();
     while (true) {
        try {
// Draw next image in animation.
                      m_CurrentImage = m_Images[iWhichImage];
                      displayImage(m_Graphics);
                      iWhichImage = (iWhichImage+1) % NUM_IMAGES;
                      Thread.sleep(50);
        } catch (InterruptedException            e) {
                      stop();
        }
     }
 }
}

我们使用Runnable接口实现了线程,而没有通过创建线程类的派生类的方式。使用Runnable接口,需要我们实现run方法。我们也需要创建Thread对象的一个实例,它最终是用来调用run方法的。在小程序中的start方法中,我们通过使用thread建构方法产生一个Thread对象的实例,其参数就是实现Runnable接口的任何类。 Thread 对象启动已经定义好的run 方法,而run方法是用来进行动画显示的。当然,从线程类中派生出一个类,并在Applet派生类中创建实例,我们可完成同样的事情。该例子是用来演示Runnable接口的用法。

在我们接着读下去之前,有几个问题需要回答。你也许会问,浏览器调用Java小程序的start和stop方法吗? run 方法是如何被调用的? 情况是这样的,当浏览器启动了一个内部线程时,就相应地启动了applet 的运行。当网页显示时,就启动了applet的start 方法。Start方法创建一个线程对象,并把applet自身传送给线程,以实现run方法。

此时,两个线程在运行:由浏览器启动的初始线程,以及处理动画的线程。快速查看applet的start方法,可以知道它创建了线程,并启动了它。类似地,当网页被隐藏后,applet的stop方法就调用了线程的stop方法。

注意:AppletsThreads中的 start/stop子程序

在Applet 和Thread 两个类中都有start和stop方法,但它们的功能不同。一旦Applet 显示时,就调用applet的start方法,一旦applet 隐藏时,就调用applet的stop 方法。相反,线程的start方法将调用run方法,线程的stop方法将停止正在执行的线程。

动画程序的设计原理

既然我们已经看过动画是如何开始的。现在看看它的机理。首先,我们通过定义Runnable 接口的方式来编写小程序,一旦定义了该接口,就表明我们将在其后实现run方法。

public class TstRunnable
  extends Applet implements Runnable . . 

然后我们编写run方法,该方法将被动画线程所调用。

public void run() {
  . . . 
  }

我们也需要一个线程对象,该对象将管理我们的动画线程,如:

private Thread m_Thread = null;

一旦做好这些准备工作以后,当applet第一次被显示时,就会创建线程对象的一个实例,并把this对象作为建构方法的参数,之后就可以启动动画了:

public void start() {
  if (m_Thread == null)      {
     m_Thread      = new Thread(this);
     m_Thread.start();
  }
}

最后一步编写如下代码:一旦applet 被隐藏时,就停止动画,Applet的stop方法如下:

public void stop(){
  if (m_Thread != null) {
     m_Thread.stop();
     m_Thread = null;
  }
}
结论

基于线程的程序功能强大。本文中,我们讨论了线程的一些基本知识:什么是线程,如何使用它们。下个月,我们将学习一些使用线程时的注意点,并讨论线程的一些高级用法。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用。 Java转C++代码工具 J2C J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用也较为便捷。 Java邮箱地址验证 jaev jaev 是一个用来验证电子邮箱地址是否有效的 Java 项目。 Java的FastCGI网关 jFastCGI jFastCGI 是一个可以让Tomcat 类的Servlet容器支持运行PHP和其它fastcgi应用程序,将Servlet容器充当成一个FastCGI 的网关。 Java 绘图框架 JGraphEd JGraphEd 是一个 Java 的图形编辑应用和绘图框架。 Java 穿越NAT方案 JSTUN.tar JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一个完整的虚拟机以及一个 javap 字节码反汇编器。 brap(Java远程调用框架 BRAP) 一个Java远程调用框架,它将原生Java对象序列化压缩装入HTTP中。它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密 码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAUTH是简易的。目前互联网很多服务如Open API,很多大头公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权 的标准。 Java的命令行处理类库 JArgs JArgs 是一个 Java 语言用来处理应用程序的命令行参数的类库。 高性能内存消息和事件驱动库 Chronicle Chronicle 是一个超低延迟、高吞吐、持久化的消息和事件驱动的内存数据库,延迟只有16纳秒以及支持每秒钟 500-2000 万消息/记录。 google-api-translate-java(Java 语言对Google翻译引擎的封装类库) 语音识别程序 SpeechLion.tar SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来控制 Linux 桌面,例如打开google搜索、鼠标点击、下一窗口、打开帮助、静音等操作。 Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、数据压缩、颜色转换、键盘鼠标事件转换等等。 最短路径算法实现 k-shortest-paths 这是一个实现了 Yen 的排名算法的无环路径的项目 Java日历空间 JCalendarButton JCalendarButton是一个简单的java swing日历选择控件。它能够在日期输入框后面弹出一个日历。 网页搜索爬虫 BlueLeech BlueLeech是一个开源程序,它从指定的URL开始,搜索所有可用的链接,以及链接上的链接。它在搜索的同时可以下载遇到的链接所指向的所有的或预定义的范围的内容。 WebSocket协议的Java实现 WebSocket4J WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码图片。 Java 命令行解析器 JOpt Simple JOpt Simple 是一个简单的、测试驱动的命令行解析器,支持 POSIX getopt() 和 GNU getopt_long() Java的HTTP代理服务器 Smart Cache Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC框架 nfs-rpc nfs-rpc是一个集成了各种知名通信框架的高性能RPC框架,目前其最好的性能为在采用grizzly作为通信框架,采用pb作为序列化/反序列化时,tps为168k次/秒。 其支持的功能主要为: 1、透明的调用远端服务器提供的功能,例如UserService.getUserNameById; 2、单连接或多连接; 3、连接复用,因此在多线程获取连接时无需阻塞; 4、同步调用; 5、超时机制; 6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展支持(REST, RPC, SOAP, etc) Rails3消息队列系统 Sidekiq Sidekiq 为 Rails 3 应用程序提供一个高效的消息队列系统。 Java文件上传组件 COS FAT文件系统读写类库 fat32-lib fat32-lib 是一个用来读写 FAT 16/32 格式文件系统的纯 Java 类库(纯的)。 Eclipse的HTML格式化插件 Eclipse Tidy Eclipse HTML Tidy 是一款 Eclipse 的插件,用来对 HTML 文件内容进行清洗和格式化处理。它采用的是 JTidy 库对HTML进行处理。 INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试工具,它不是僵尸网络类的ddos,而是使用大量的代理作为bots发起DDOS。Port Groper可以与用测试防火墙,干扰web 统计脚本的跟踪,为网站增加流量..往好了用什么都能干,就是不能让一个网站下线。 FTP客户端Java类库 ftp4j ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java 类库,用来提供在命令行中显示进度条的功能。 Tomcat 安装apr 支持 Tomcat Native Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和精确跟踪。 条形码扫描和识别程序 LVBarcode LVBarcode 支持下列的条形码格式:Codabar,I2of5,Code39,ExCode39?,EAN-8,EAN-13,Code128 A,Code128 B,Code128 C,MSI,UPC-A,UPC-E. 中文转拼音库 pinyin4j Pinyin4j是一个流行的Java库,支持中文字符和拼音间的转换。拼音输出格式可以定制。 异步HTTP客户端开发包 HttpAsyncClient HttpAsyncClient 是一个异步的 HTTP 客户端开发包,基于 HttpCore NIO 和 HttpClient 组件。HttpAsyncClient 的出现并不是为了替换 HttpClient,而是作为一个补充用于需要大量并发连接,对性能要求非常高的基于HTTP的原生数据通信,而且提供了事件驱动的 API。 NIO网络框架 xSocket xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用javaJava批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG(解析表达式语法)分析设施。你定义的Java源代码的语法规则,直接,没有必要专门编写和维护,外部语法文件。同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信(MMS)的开发包,支持附件发送。 Oracle数据库工具 WARTS WARTS是一个纯Java数据库工具,可以执行字符编码识别的数据同步。开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,它功能强大,性能良好,秒杀当前流行的模板引擎。而且还易学易用。 Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq(JMS消息服务器 ActiveMQ) ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。 Ajax框架 ZK.rar ZK是一个Ajax Java Web框架,利用少量代码就能够开发出拥有Rich UI的Web应用。ZK提供基于XUL的标记语言和事件驱动的组件,可以让你像开发桌面应用程序一样简单。支持EL表达式和脚本语言包括:JavaScript、Ruby和Groovy等。支持Annotation及数据绑定。集成Google Maps、FCKeditor、DOJO以及Timeline。 Atom协议实现 Abdera.rar Apache Abdera是Atom联合协议(Atom Syndication)和Atom发布(Atom Publication)协议的开源实现,目前尚处于“孵化”阶段。最近,Abdera到达了0.40里程碑版,朝着成功孵化迈出了重要一步。 CKEditor for Java.rar 在线网页编辑插件(用浏览器编辑后所见即所得),支持多种平台下的脚本(asp aspx php cfm Dhtml htc),还集成了上传图片组件,含简、繁中文 cloudxy(弹性云计算平台 Cloudxy).rar Cloudxy 立足于实现虚拟子网(以太网)的弹性云计算平台 该项目主要包含有两个子项目: HLFS - 虚拟机分布式镜像存储 (类似于亚马逊EBS,首先发布出来) ECM - 虚拟环境管理系统 (后续发布) Compass UI 工具 Compass.app.rar Compass.app 是一个针对 Sass 和 Compass 的菜单工具,帮助设计师通过 UI 的方式编译样式,而不用去记住命令行。它是用 JRuby 开发的,可以在多个平台上使用,而不用安装 Ruby 环境。 dnsjava(Java的DNS开发包 dnsjava).rar dnsjava是DNS协议的一个Java开源实现。 DNS服务器 Eagle DNS.zip Eagle DNS 是一个用 Java 语言开发的功能强大的多线程的平台无关的DNS服务器,基于 dnsjava 类库,支持 Primary Zones 和 Secondary Zones。 EclipseHTMLEditor.rar Eclipse HTML编辑器插件 Eclipse的语法着色插件 Colorer Take.rar Colorer Take 能为在Eclipse中打开的各种类型源代码文件按语法着色。支持150多种语言。 ehcache(Java缓存框架 EhCache).rar EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。 Facebook API 的 Java 封装请求处理组件 RestFB.zip facebook的restAPI和graphAPI封装,供java调用。 Facebook个人资料导出工具 fbpwn.zip fbpwn(Facebook个人资料导出工具).rar Google API for Java.zip grimwepa(无线密码破解工具).rar 一个密码破解WEP和WPA加密的接入点(路由器) gtd-free(个人待办事项管理软件 GTD-Free).rar GUI界面引擎 SwiXml.zip Hibernate搜索框架 Hibernate Search.zip HTML5模板引擎 Thymeleaf.zip HTML文档解析器 HTMLParser.rar HTML解析器 jsoup.rar iqq(开源 QQ 工具 iQQ).rar jacob-liang-platform-uus(系统平台统一用户 ).rar jalarm(个人提醒工具 jAlarm).rar Java 3D图形引擎 Catcake.zip Java HTTP服务器 TJWS.zip Java 插件框架 jspf.zip Java 缓存系统 JBossCache.zip Java 计算机视觉库 BoofCV.zip Java-COM中间件 JACOB.zip Javascript 扩展工具包 j-et.rar Java串口开发包 RXTX.zip Java五线谱处理类库 abc4j.zip Java任务调度 jconch.rar Java加密包 Jasypt.zip Jasypt这个Java类包为开发人员提供一种简单的方式来为项目增加加密功能,包括:密码Digest认证,文本和对象加密,集成hibernate,Spring Security(Acegi)来增强密码管理。 Java加密库 JSDSI.rar Java单点登录系统 JA-SIG CAS.rar Java即时战略游戏 StarCraft Ⅰ.rar Java和DLL(COM)互操作 Jawin.zip Java图像处理类库 Java Image Filters.zip Java图形组件 JGraph.rar Java图形验证码 SimpleCaptcha.rar 一套用于生成各种图形验证码的库(Java) Java图表 JFreeChart.zip Java多播通讯框架 JGroups.zip JGroups是一个可靠的群组通讯Java工具包。它基于IP组播(IP multicast),但在可靠性,组成员管理上对它作了扩展。 JAVA字节码操作库 BCEL.zip Java实现的EverBox库 Everbox4j.zip Java实现的Web服务安全规范 WSS4J.zip Java对象验证框架 OVal.zip Java常用工具包 Jodd.zip Java应用服务器 Tomcat.zip Java应用框架 Nutz.rar Java开发的SHELL CRaSH.gz Java推箱子游戏 JSoko.rar Java搜索引擎 Lucene.zip Java时间工具包 JTimepiece.zip Java本地代码绑定工具 jSegue.zip Java本地调用接口 JNative.zip Java条形码生成库 Barcode4J.zip Barcode4J由Java语言编写而成,可以灵活的生成条形码。它采用Apache License V2.0许可,这使得它很容易在商业中被使用。它可以让您生成各种流行的一维和二维条码,包括DataMatrix 和 PDF417。以各种格式输出,包括SVG, EPS, bitmaps和Java2D,同样也可根据您的需要添加自己的输出格式。它为各种应用提供了插件,包括最重要的Apache FOP(格式对象处理器)。有一些用户将Barcode4J部署为一个servlet。 Java桌面搜索 JDesktopSearch.zip JDesktopSearch是一个基于Apache Lucene实现的桌面搜索引擎。它能够索引HTML、XML、OpenOffice、MS Word和PDF文档。其它类型的文件只索引文件名。 Java桌面程序开发框架 Viewa.zip Java模板引擎 FreeMarker.tar.gz Java源代码检索系统 JCite.zip Java的EPUB类库 Epublib.zip Java的HL7解析器 HAPI.zip Java的OpenID服务器 JOIDS.rar Java的UIMA注解类 uimaFIT.zip Java的UI皮肤 Quaqua.zip Java神经网络框架 Encog for Java.zip Java程序监控API Java Simon.zip Java算术表达式计算类库 ExpressionJ.zip Java线程错误捕获工具 CheckThread.zip Java网页浏览器 Lobo.zip Java网页爬虫 JSpider.zip Java视觉处理库 JavaCV.rar Java论坛系统 JForum.zip Java调用本地库 JNAerator.zip Java远程终端工具 JTA.rar Java邮件服务器 James.rar Java邮件检验库 JEmval.zip Java验证码生成库 JCaptcha.rar JAXP数据验证引擎 Serene.zip JBoss事务处理 JBossTS.zip JDBC连接池、监控组件 Druid.zip JFCSwing用户图形界面 SwingML.rar JNI代码生成器 JNIGen.zip JSCSS压缩工具 YUI Compressor.zip JSON查询语言 Jaql.rar JSON类库 Flexjson.zip JSP标签 Noka Tag.rar JS和CSS压缩混淆 JsCompressor.rar js文件压缩工具 Closure Compiler.rar jviolajones(人脸检测算法).rar lobby(经典board游戏 Domination).rar makagiga(开源个人桌面软件 Makagiga).rar MathML渲染器 JEuclid.rar OData的Java实现 odata4j.rar P2P应用程序协议框架 Java BEEP Core.zip paoding(中文分词库 Paoding).rar PDF 文档字体处理 FontBox.zip QQ农场外挂JAVA版本 qqhack.rar QQ登录的Java接口 open-qq.zip ralasafe(访问控制(权限管理)中间件 ).rar RPG游戏引擎 Arianne.zip SAT算法库 OpenSAT.zip sigar_mirror(系统信息收集API_Sigar).rar SNMP的MIB浏览器 JMIBBrowser.zip SQL解析类库 SQLJEP.zip SSH服务端 Apache SSHD.rar swiftp(Android上的FTP服务器 SwiFTP).rar swing-explorer(Swing开发辅助工具).rar Swing开发框架 Griffon.zip tbschedule(淘宝任务调度分配器).rar Tomcat的管理和监控 PSI Probe.zip WebDAV网关 Davenport.rar WebSocket通讯框架 jWebSocket.rar Web代理服务器 RabbIT.tar.gz Web服务框架 Apache Axis.rar Web相册平台 Apache PhotArk.rar Web集成开发环境 Cloud9 IDE.zip WordNet的Java包 JWordNet.zip XML解析器 Xerces.rar Yahoo的分布式流计算平台 S4.rar YAML解析器 SnakeYAML.zip zaproxy(Web渗透测试 Zed Attack Proxy).rar zxing(条形码处理类库).rar 业务流程管理(BPM)和工作流系统 Activiti.zip 个人博客软件 PersonalBlog.zip 个人知识库 Piggydb.zip 中国移动短信协议CMPP封装 hicmpp.zip 中文分词工具包 smallseg.jar 中文分词库 IKAnalyzer.zip 中文自然语言处理工具包 FudanNLP.zip 人工智能工具包 OpenAI.zip 企业信息系统开发平台 JBob.zip 使用Redis存放Session RedisManager.zip 入门级j2ee开源项目 simplejee.zip 全文搜索服务器 Solr.tgz 分布式缓存框架 SwarmCache.zip 加密库 BeeCrypt.zip 即时消息传输平台 Openfire.rar 国产Ajax框架 Buffalo.rar 国产纯Java多核体系结构模拟器 Archimulator.zip 在Java中运行Perl脚本 JERL.zip 坦克机器人战斗仿真引擎 Robocode.zip 多播事件总线 Avis.zip 多环境应用程序框架 WebOnSwing.rar 多用户在线游戏服务器端框架 Marauroa.tar.gz 大文件上传的Java Applet mupload.rar 天乙社区.rar 密钥管理工具 Keytool-IUI.zip 富客户端开发框架 Spring Richclient.tar.gz 开放实时数据处理平台 Twitter Storm.zip 开源JSF组件库 JQuery4JSF.rar 开源LDAP浏览器 JXplorer.zip 开源事务管理器 JOTM.zip 开源工作流系统 JWFD.rar 开源搜索系统 Red-Piranha.zip 开源日志管理 Logstash.jar 开源机器人技术中间件 OpenRTM-aist.zip 开源的Swing组件 JIDE.zip 开源足球游戏 Slam Soccer.rar 异步IO框架 Cindy.rar 懒惰者代码生成器 IdlerCodeGenerator.zip 拼写检查器 Hunspell.gz 指纹识别开发包 SourceAFIS.zip 数字图书制作工具 EpubCheck.rar 数据库连接池 C3P0.src.zip 数据持久层框架 Hibernate.zip 文件上传控件 GWTUpload.rar 文件压缩解压缩包 Commons Compress.rar 文件系统API EntityFS.zip 文字识别工具 Eye.zip 文本加密解密工具 ImmediateCrypt.zip 无线消息交换服务 HomerMX.zip 日历同步统计 GCALDaemon.zip 日历控件 Click Calendar.rar 最快速的java代码生成器 rapid-generator.zip 服务框架 Dubbo.rar 服务端JavaScript框架 RingoJS.rar 桌面博客工具 Thingamablog.zip 桌面图形计算器 GraphingCalculator.jar 桌面软件开发框架 joyWindow.zip 游戏引擎 JBox2D.zip 源问答系统 OpenEphyra.zip 漏洞检测程序 Yasca.zip 用户界面框架 XUI.rar 短信收发包 SMSLib.zip 磁盘的KV存储 JDBM2.rar 程序代码编辑器 jEdit.tar.bz2 第三代的P2P网络 ANts 简约的微博同步程序.zip 编程脚本引擎 Fantom.zip 网络应用框架 Netty.tar.bz2 网络抓包工具 jpcap.zip 网络数据包捕获函数库 jNetPcap.zip 网页抽取工具 Krabber.rar 联系人导出 ContactList.zip 表达式解释引擎 JSEL.rar 语音合成系统 FreeTTS.rar 调用远程API规范 XINS.zip 豆瓣OAuth认证示例项目.rar 跨平台的文件同步工具 Capivara.rar 远程文件传输工具 MammothCopy.tar.gz 通用数据底层 Jsa4j.zip 遗传算法包 JGAP.zip 重复数据删除 Duke.zip 面向对象的JavaScript框架 Dojo.rar 面向对象的脚本语言 ObjectScript.tar.gz 高性能Java网络框架 MINA.zip 高性能web代理程序 hyk-proxy.rar 高性能的Java 3D引擎 Xith3D.zip
java版MPEG播放器 import java.io.*; import java.net.*; import java.awt.*; import java.awt.image.*; import java.applet.*; /** * This class represents a buffered input stream which can read * variable length codes from MPEG-1 video streams. */ class BitInputStream { /** * MPEG video layers start codes */ public final static int SYNC_START_CODE = 0x000001; public final static int PIC_START_CODE = 0x00000100; public final static int SLICE_MIN_CODE = 0x00000101; public final static int SLICE_MAX_CODE = 0x000001af; public final static int USER_START_CODE = 0x000001b2; public final static int SEQ_START_CODE = 0x000001b3; public final static int EXT_START_CODE = 0x000001b5; public final static int SEQ_END_CODE = 0x000001b7; public final static int GOP_START_CODE = 0x000001b8; /** * The underlying input stream */ private InputStream stream; /** * The bit buffer variables */ private int bitbuffer, bitcount; /** * The 32 bit buffer variables */ private int buffer[], count, position; /** * Initializes the bit input stream object */ public BitInputStream(InputStream inputStream) { stream = inputStream; buffer = new int[1024]; bitbuffer = bitcount = 0; count = position = 0; } /** * Reads the next MPEG-1 layer start code */ public int getCode() throws IOException { alignBits(8); while (showBits(24) != SYNC_START_CODE) flushBits(8); return getBits(32); } /** * Shows the next MPEG-1 layer start code */ public int showCode() throws IOException { alignBits(8); while (showBits(24) != SYNC_START_CODE) flushBits(8); return showBits(32); } /** * Reads the next variable length code */ public int getBits(int nbits) throws IOException { int bits; if (nbits <= bitcount) { bits = bitbuffer >>> (32 - nbits); bitbuffer <<= nbits; bitcount -= nbits; } else { bits = bitbuffer >>> (32 - nbits); nbits -= bitcount; bitbuffer = get32Bits(); bits |= bitbuffer >>> (32 - nbits); bitbuffer <<= nbits; bitcount = 32 - nbits; } if (nbits >= 32) bitbuffer = 0; return bits; } /** * Shows the next variable length code */ public int showBits(int nbits) throws IOException { int bits = bitbuffer >>> (32 - nbits); if (nbits > bitcount) { bits |= show32Bits() >>> (32 + bitcount - nbits); } return bits; } /** * Flushes the current variable length code */ public void flushBits(int nbits) throws IOException { if (nbits <= bitcount) { bitbuffer <<= nbits; bitcount -= nbits; } else { nbits -= bitcount; bitbuffer = get32Bits() << nbits; bitcount = 32 - nbits; } } /** * Aligns the input stream pointer to a given boundary */ public void alignBits(int nbits) throws IOException { flushBits(bitcount % nbits); } /** * Reads the next 32-bit code from the buffered stream */ private int get32Bits() throws IOException { if (position >= count) { position = 0; for (count = 0; count < buffer.length; count++) buffer[count] = read32Bits(); } return buffer[position++]; } /** * Shows the next 32-bit code from the buffered stream */ private int show32Bits() throws IOException { if (position >= count) { position = 0; for (count = 0; count < buffer.length; count++) buffer[count] = read32Bits(); } return buffer[position]; } /** * Reads 32-bit big endian codes from the stream */ private int read32Bits() throws IOException { if (stream.available() <= 0) return SEQ_END_CODE; int a0 = stream.read() & 0xff; int a1 = stream.read() & 0xff; int a2 = stream.read() & 0xff; int a3 = stream.read() & 0xff; return (a0 << 24) + (a1 << 16) + (a2 << 8) + (a3 << 0); } } /** * Huffman VLC entropy decoder for MPEG-1 video streams. The tables * are from ISO/IEC 13818-2 DIS, Annex B, variable length code tables. */ class VLCInputStream extends BitInputStream { /** * Table B-1, variable length codes for macroblock address increments */ private final static byte MBAtable[][] = { // 00000011xxx { 33,11 }, { 32,11 }, { 31,11 }, { 30,11 }, { 29,11 }, { 28,11 }, { 27,11 }, { 26,11 }, // 0000010xxxx { 25,11 }, { 24,11 }, { 23,11 }, { 22,11 }, { 21,10 }, { 21,10 }, { 20,10 }, { 20,10 }, { 19,10 }, { 19,10 }, { 18,10 }, { 18,10 }, { 17,10 }, { 17,10 }, { 16,10 }, { 16,10 }, // 0000xxxx... { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33,11 }, { 25,11 }, { 19,10 }, { 15, 8 }, { 14, 8 }, { 13, 8 }, { 12, 8 }, { 11, 8 }, { 10, 8 }, { 9, 7 }, { 9, 7 }, { 8, 7 }, { 8, 7 }, // 00xxx...... { 0, 0 }, { 13, 8 }, { 7, 5 }, { 6, 5 }, { 5, 4 }, { 5, 4 }, { 4, 4 }, { 4, 4 }, // xxx........ { 0, 0 }, { 5, 4 }, { 3, 3 }, { 2, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 } }; /** * Table B-2, variable length codes for I-picture macroblock types */ private final static byte IMBtable[][] = { // xx { 0, 0 }, { 17,2 }, { 1,1 }, { 1,1 } }; /** * Table B-3, variable length codes for P-picture macroblock types */ private final static byte PMBtable[][] = { // 000xxx { 0,0 }, { 17,6 }, { 18,5 }, { 18,5 }, { 26,5 }, { 26,5 }, { 1,5 }, { 1,5 }, // xxx... { 0,0 }, { 8,3 }, { 2,2 }, { 2,2 }, { 10,1 }, { 10,1 }, { 10,1 }, { 10,1 } }; /** * Table B-4, variable length codes for B-picture macroblock types */ private final static byte BMBtable[][] = { // 00xxxx { 0,0 }, { 17,6 }, { 22,6 }, { 26,6 }, { 30,5 }, { 30,5 }, { 1,5 }, { 1,5 }, { 8,4 }, { 8,4 }, { 8,4 }, { 8,4 }, { 10,4 }, { 10,4 }, { 10,4 }, { 10,4 }, // xxx... { 0,0 }, { 8,4 }, { 4,3 }, { 6,3 }, { 12,2 }, { 12,2 }, { 14,2 }, { 14,2 }, }; /** * Table B-9, variable length codes for coded block patterns */ private final static byte CBPtable[][] = { // 000000xxx { 0,0 }, { 0,9 }, { 39,9 }, { 27,9 }, { 59,9 }, { 55,9 }, { 47,9 }, { 31,9 }, // 000xxxxx. { 0,0 }, { 39,9 }, { 59,9 }, { 47,9 }, { 58,8 }, { 54,8 }, { 46,8 }, { 30,8 }, { 57,8 }, { 53,8 }, { 45,8 }, { 29,8 }, { 38,8 }, { 26,8 }, { 37,8 }, { 25,8 }, { 43,8 }, { 23,8 }, { 51,8 }, { 15,8 }, { 42,8 }, { 22,8 }, { 50,8 }, { 14,8 }, { 41,8 }, { 21,8 }, { 49,8 }, { 13,8 }, { 35,8 }, { 19,8 }, { 11,8 }, { 7,8 }, // 001xxxx.. { 34,7 }, { 18,7 }, { 10,7 }, { 6,7 }, { 33,7 }, { 17,7 }, { 9,7 }, { 5,7 }, { 63,6 }, { 63,6 }, { 3,6 }, { 3,6 }, { 36,6 }, { 36,6 }, { 24,6 }, { 24,6 }, // xxxxx.... { 0,0 }, { 57,8 }, { 43,8 }, { 41,8 }, { 34,7 }, { 33,7 }, { 63,6 }, { 36,6 }, { 62,5 }, { 2,5 }, { 61,5 }, { 1,5 }, { 56,5 }, { 52,5 }, { 44,5 }, { 28,5 }, { 40,5 }, { 20,5 }, { 48,5 }, { 12,5 }, { 32,4 }, { 32,4 }, { 16,4 }, { 16,4 }, { 8,4 }, { 8,4 }, { 4,4 }, { 4,4 }, { 60,3 }, { 60,3 }, { 60,3 }, { 60,3 } }; /** * Table B-10, variable length codes for motion vector codes */ private final static byte MVtable[][] = { // 00000011xx { 16,10 }, { 15,10 }, { 14,10 }, { 13,10 }, // 0000010xxx { 12,10 }, { 11,10 }, { 10, 9 }, { 10, 9 }, { 9, 9 }, { 9, 9 }, { 8, 9 }, { 8, 9 }, // 000xxxx... { 0, 0 }, { 0, 0 }, { 12,10 }, { 7, 7 }, { 6, 7 }, { 5, 7 }, { 4, 6 }, { 4, 6 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, // xxx....... { 0, 0 }, { 2, 3 }, { 1, 2 }, { 1, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; /** * Table B-12, variable length codes for DC luminance sizes */ private final static byte DClumtable[][] = { // xxx...... { 1,2 }, { 1,2 }, { 2,2 }, { 2,2 }, { 0,3 }, { 3,3 }, { 4,3 }, { 5,4 }, // 111xxx... { 5,4 }, { 5,4 }, { 5,4 }, { 5,4 }, { 6,5 }, { 6,5 }, { 7,6 }, { 8,7 }, // 111111xxx { 8,7 }, { 8,7 }, { 8,7 }, { 8,7 }, { 9,8 }, { 9,8 }, { 10,9 }, { 11,9 } }; /** * Table B-13, variable length codes for DC chrominance sizes */ private final static byte DCchrtable[][] = { // xxxx...... { 0,2 }, { 0,2 }, { 0,2 }, { 0,2 }, { 1,2 }, { 1,2 }, { 1,2 }, { 1,2 }, { 2,2 }, { 2,2 }, { 2,2 }, { 2,2 }, { 3,3 }, { 3,3 }, { 4,4 }, { 5,5 }, // 1111xxx... { 5,5 }, { 5,5 }, { 5,5 }, { 5,5 }, { 6,6 }, { 6,6 }, { 7,7 }, { 8,8 }, // 1111111xxx { 8,8 }, { 8,8 }, { 8,8 }, { 8,8 }, { 9,9 }, { 9,9 }, { 10,10 }, { 11,10 } }; public final static short EOB = 64; public final static short ESC = 65; /** * Table B-14, variable length codes for DCT coefficients */ private final static short DCTtable[][] = { // 000000000001xxxx { 4609,16 }, { 4353,16 }, { 4097,16 }, { 3841,16 }, { 774,16 }, { 528,16 }, { 527,16 }, { 526,16 }, { 525,16 }, { 524,16 }, { 523,16 }, { 287,16 }, { 286,16 }, { 285,16 }, { 284,16 }, { 283,16 }, // 00000000001xxxx. {10240,15 }, { 9984,15 }, { 9728,15 }, { 9472,15 }, { 9216,15 }, { 8960,15 }, { 8704,15 }, { 8448,15 }, { 8192,15 }, { 3585,15 }, { 3329,15 }, { 3073,15 }, { 2817,15 }, { 2561,15 }, { 2305,15 }, { 2049,15 }, // 0000000001xxxx.. { 7936,14 }, { 7680,14 }, { 7424,14 }, { 7168,14 }, { 6912,14 }, { 6656,14 }, { 6400,14 }, { 6144,14 }, { 5888,14 }, { 5632,14 }, { 5376,14 }, { 5120,14 }, { 4864,14 }, { 4608,14 }, { 4352,14 }, { 4096,14 }, // 000000001xxxx... { 522,13 }, { 521,13 }, { 773,13 }, { 1027,13 }, { 1282,13 }, { 1793,13 }, { 1537,13 }, { 3840,13 }, { 3584,13 }, { 3328,13 }, { 3072,13 }, { 282,13 }, { 281,13 }, { 280,13 }, { 279,13 }, { 278,13 }, // 00000001xxxx.... { 2816,12 }, { 520,12 }, { 772,12 }, { 2560,12 }, { 1026,12 }, { 519,12 }, { 277,12 }, { 276,12 }, { 2304,12 }, { 275,12 }, { 274,12 }, { 1281,12 }, { 771,12 }, { 2048,12 }, { 518,12 }, { 273,12 }, // 0000001xxx...... { 272,10 }, { 517,10 }, { 1792,10 }, { 770,10 }, { 1025,10 }, { 271,10 }, { 270,10 }, { 516,10 }, // 000xxxx......... { 0, 0 }, { 272,10 }, { ESC, 6 }, { ESC, 6 }, { 514, 7 }, { 265, 7 }, { 1024, 7 }, { 264, 7 }, { 263, 6 }, { 263, 6 }, { 262, 6 }, { 262, 6 }, { 513, 6 }, { 513, 6 }, { 261, 6 }, { 261, 6 }, // 00100xxx........ { 269, 8 }, { 1536, 8 }, { 268, 8 }, { 267, 8 }, { 515, 8 }, { 769, 8 }, { 1280, 8 }, { 266, 8 }, // xxxxx........... { 0, 0 }, { 514, 7 }, { 263, 6 }, { 513, 6 }, { 269, 8 }, { 768, 5 }, { 260, 5 }, { 259, 5 }, { 512, 4 }, { 512, 4 }, { 258, 4 }, { 258, 4 }, { 257, 3 }, { 257, 3 }, { 257, 3 }, { 257, 3 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { EOB, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 }, { 256, 2 } }; /** * Storage for RLE run and level of DCT block coefficients */ private int data[]; /** * Initializes the Huffman entropy decoder for MPEG-1 streams */ public VLCInputStream(InputStream inputStream) { super(inputStream); data = new int[2]; } /** * Returns macroblock address increment codes */ public int getMBACode() throws IOException { int code, value = 0; /* skip macroblock escape */ while ((code = showBits(11)) == 15) { flushBits(11); } /* decode macroblock skip codes */ while ((code = showBits(11)) == 8) { flushBits(11); value += 33; } /* decode macroblock increment */ if (code >= 512) code = (code >> 8) + 48; else if (code >= 128) code = (code >> 6) + 40; else if (code >= 48) code = (code >> 3) + 24; else if (code >= 24) code -= 24; else throw new IOException("Invalid macro block address increment"); flushBits(MBAtable[code][1]); return value + MBAtable[code][0]; } /** * Returns I-picture macroblock type flags */ public int getIMBCode() throws IOException { int code = showBits(2); if (code <= 0) throw new IOException("Invalid I-picture macro block code"); flushBits(IMBtable[code][1]); return IMBtable[code][0]; } /** * Returns P-picture macroblock type flags */ public int getPMBCode() throws IOException { int code = showBits(6); if (code >= 8) code = (code >> 3) + 8; else if (code <= 0) throw new IOException("Invalid P-picture macro block code"); flushBits(PMBtable[code][1]); return PMBtable[code][0]; } /** * Returns B-picture macroblock type flags */ public int getBMBCode() throws IOException { int code = showBits(6); if (code >= 16) code = (code >> 3) + 16; else if (code <= 0) throw new IOException("Invalid B-picture macro block code"); flushBits(BMBtable[code][1]); return BMBtable[code][0]; } /** * Returns coded block pattern flags */ public int getCBPCode() throws IOException { int code = showBits(9); if (code >= 128) code = (code >> 4) + 56; else if (code >= 64) code = (code >> 2) + 24; else if (code >= 8) code = (code >> 1) + 8; else if (code <= 0) throw new IOException("Invalid block pattern code"); flushBits(CBPtable[code][1]); return CBPtable[code][0]; } /** * Returns motion vector codes */ public int getMVCode() throws IOException { int code = showBits(10); if (code >= 128) code = (code >> 7) + 28; else if (code >= 24) code = (code >> 3) + 12; else if (code >= 12) code -= 12; else throw new IOException("Invalid motion vector code"); flushBits(MVtable[code][1]); code = MVtable[code][0]; return (getBits(1) == 0 ? code : -code); } /** * Returns intra coded DC luminance coefficients */ public int getIntraDCLumValue() throws IOException { int code = showBits(9); if (code >= 504) code -= 488; else if (code >= 448) code = (code >> 3) - 48; else code >>= 6; flushBits(DClumtable[code][1]); int nbits = DClumtable[code][0]; if (nbits != 0) { code = getBits(nbits); if ((code & (1 << (nbits - 1))) == 0) code -= (1 << nbits) - 1; return code; } return 0; } /** * Returns intra coded DC chrominance coefficients */ public int getIntraDCChromValue() throws IOException { int code = showBits(10); if (code >= 1016) code -= 992; else if (code >= 960) code = (code >> 3) - 104; else code >>= 6; flushBits(DCchrtable[code][1]); int nbits = DCchrtable[code][0]; if (nbits != 0) { code = getBits(nbits); if ((code & (1 << (nbits - 1))) == 0) code -= (1 << nbits) - 1; return code; } return 0; } /** * Returns inter coded DC luminance or chrominance coefficients */ public int[] getInterDCValue() throws IOException { /* handle special variable length code */ if (showBits(1) != 0) { data[0] = 0; data[1] = getBits(2) == 2 ? 1 : -1; return data; } return getACValue(); } /** * Returns AC luminance or chrominance coefficients */ public int[] getACValue() throws IOException { int code = showBits(16); if (code >= 10240) code = (code >> 11) + 112; else if (code >= 8192) code = (code >> 8) + 72; else if (code >= 1024) code = (code >> 9) + 88; else if (code >= 512) code = (code >> 6) + 72; else if (code >= 256) code = (code >> 4) + 48; else if (code >= 128) code = (code >> 3) + 32; else if (code >= 64) code = (code >> 2) + 16; else if (code >= 32) code >>= 1; else if (code >= 16) code -= 16; else throw new IOException("Invalid DCT coefficient code"); flushBits(DCTtable[code][1]); data[0] = DCTtable[code][0] & 0xFF; data[1] = DCTtable[code][0] >>> 8; if (data[0] == ESC) { data[0] = getBits(6); data[1] = getBits(8); if (data[1] == 0x00) data[1] = getBits(8); else if (data[1] == 0x80) data[1] = getBits(8) - 256; else if (data[1] >= 0x80) data[1] -= 256; } else if (data[0] != EOB) { if (getBits(1) != 0) data[1] = -data[1]; } return data; } } /** * Fast inverse two-dimensional discrete cosine transform algorithm * by Chen-Wang using 32 bit integer arithmetic (8 bit coefficients). */ class IDCT { /** * The basic DCT block is 8x8 samples */ private final static int DCTSIZE = 8; /** * Integer arithmetic precision constants */ private final static int PASS_BITS = 3; private final static int CONST_BITS = 11; /** * Precomputed DCT cosine kernel functions: * Ci = (2^CONST_BITS)*sqrt(2.0)*cos(i * PI / 16.0) */ private final static int C1 = 2841; private final static int C2 = 2676; private final static int C3 = 2408; private final static int C5 = 1609; private final static int C6 = 1108; private final static int C7 = 565; public static void transform(int block[]) { /* pass 1: process rows */ for (int i = 0, offset = 0; i < DCTSIZE; i++, offset += DCTSIZE) { /* get coefficients */ int d0 = block[offset + 0]; int d4 = block[offset + 1]; int d3 = block[offset + 2]; int d7 = block[offset + 3]; int d1 = block[offset + 4]; int d6 = block[offset + 5]; int d2 = block[offset + 6]; int d5 = block[offset + 7]; int d8; /* AC terms all zero? */ if ((d1 | d2 | d3 | d4 | d5 | d6 | d7) == 0) { d0 <<= PASS_BITS; block[offset + 0] = d0; block[offset + 1] = d0; block[offset + 2] = d0; block[offset + 3] = d0; block[offset + 4] = d0; block[offset + 5] = d0; block[offset + 6] = d0; block[offset + 7] = d0; continue; } /* first stage */ d8 = (d4 + d5) * C7; d4 = d8 + d4 * (C1 - C7); d5 = d8 - d5 * (C1 + C7); d8 = (d6 + d7) * C3; d6 = d8 - d6 * (C3 - C5); d7 = d8 - d7 * (C3 + C5); /* second stage */ d8 = ((d0 + d1) << CONST_BITS) + (1 << (CONST_BITS - PASS_BITS - 1)); d0 = ((d0 - d1) << CONST_BITS) + (1 << (CONST_BITS - PASS_BITS - 1)); d1 = (d2 + d3) * C6; d2 = d1 - d2 * (C2 + C6); d3 = d1 + d3 * (C2 - C6); d1 = d4 + d6; d4 = d4 - d6; d6 = d5 + d7; d5 = d5 - d7; /* third stage */ d7 = d8 + d3; d8 = d8 - d3; d3 = d0 + d2; d0 = d0 - d2; d2 = ((d4 + d5) * 181) >> 8; d4 = ((d4 - d5) * 181) >> 8; /* output stage */ block[offset + 0] = (d7 + d1) >> (CONST_BITS - PASS_BITS); block[offset + 7] = (d7 - d1) >> (CONST_BITS - PASS_BITS); block[offset + 1] = (d3 + d2) >> (CONST_BITS - PASS_BITS); block[offset + 6] = (d3 - d2) >> (CONST_BITS - PASS_BITS); block[offset + 2] = (d0 + d4) >> (CONST_BITS - PASS_BITS); block[offset + 5] = (d0 - d4) >> (CONST_BITS - PASS_BITS); block[offset + 3] = (d8 + d6) >> (CONST_BITS - PASS_BITS); block[offset + 4] = (d8 - d6) >> (CONST_BITS - PASS_BITS); } /* pass 2: process columns */ for (int i = 0, offset = 0; i < DCTSIZE; i++, offset++) { /* get coefficients */ int d0 = block[offset + DCTSIZE*0]; int d4 = block[offset + DCTSIZE*1]; int d3 = block[offset + DCTSIZE*2]; int d7 = block[offset + DCTSIZE*3]; int d1 = block[offset + DCTSIZE*4]; int d6 = block[offset + DCTSIZE*5]; int d2 = block[offset + DCTSIZE*6]; int d5 = block[offset + DCTSIZE*7]; int d8; /* AC terms all zero? */ if ((d1 | d2 | d3 | d4 | d5 | d6 | d7) == 0) { d0 >>= PASS_BITS + 3; block[offset + DCTSIZE*0] = d0; block[offset + DCTSIZE*1] = d0; block[offset + DCTSIZE*2] = d0; block[offset + DCTSIZE*3] = d0; block[offset + DCTSIZE*4] = d0; block[offset + DCTSIZE*5] = d0; block[offset + DCTSIZE*6] = d0; block[offset + DCTSIZE*7] = d0; continue; } /* first stage */ d8 = (d4 + d5) * C7; d4 = (d8 + d4 * (C1 - C7)) >> 3; d5 = (d8 - d5 * (C1 + C7)) >> 3; d8 = (d6 + d7) * C3; d6 = (d8 - d6 * (C3 - C5)) >> 3; d7 = (d8 - d7 * (C3 + C5)) >> 3; /* second stage */ d8 = ((d0 + d1) << (CONST_BITS - 3)) + (1 << (CONST_BITS + PASS_BITS-1)); d0 = ((d0 - d1) << (CONST_BITS - 3)) + (1 << (CONST_BITS + PASS_BITS-1)); d1 = (d2 + d3) * C6; d2 = (d1 - d2 * (C2 + C6)) >> 3; d3 = (d1 + d3 * (C2 - C6)) >> 3; d1 = d4 + d6; d4 = d4 - d6; d6 = d5 + d7; d5 = d5 - d7; /* third stage */ d7 = d8 + d3; d8 = d8 - d3; d3 = d0 + d2; d0 = d0 - d2; d2 = ((d4 + d5) * 181) >> 8; d4 = ((d4 - d5) * 181) >> 8; /* output stage */ block[offset + DCTSIZE*0] = (d7 + d1) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*7] = (d7 - d1) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*1] = (d3 + d2) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*6] = (d3 - d2) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*2] = (d0 + d4) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*5] = (d0 - d4) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*3] = (d8 + d6) >> (CONST_BITS + PASS_BITS); block[offset + DCTSIZE*4] = (d8 - d6) >> (CONST_BITS + PASS_BITS); } } } /** * Motion vector information used for MPEG-1 motion prediction. */ class MotionVector { /** * Motion vector displacements (6 bits) */ public int horizontal; public int vertical; /** * Motion vector displacement residual size */ private int residualSize; /** * Motion displacement in half or full pixels? */ private boolean pixelSteps; /** * Initializes the motion vector object */ public MotionVector() { horizontal = vertical = 0; residualSize = 0; pixelSteps = false; } /** * Changes the current motion vector predictors */ public void setVector(int horizontal, int vertical) { this.horizontal = horizontal; this.vertical = vertical; } /** * Reads the picture motion vector information */ public void getMotionInfo(BitInputStream stream) throws IOException { pixelSteps = (stream.getBits(1) != 0); residualSize = (stream.getBits(3) - 1); } /** * Reads the macro block motion vectors */ public void getMotionVector(VLCInputStream stream) throws IOException { horizontal = getMotionDisplacement(stream, horizontal); vertical = getMotionDisplacement(stream, vertical); } /** * Reads and reconstructs the motion vector displacements */ private int getMotionDisplacement(VLCInputStream stream, int vector) throws IOException { int code = stream.getMVCode(); int residual = (code != 0 && residualSize != 0 ? stream.getBits(residualSize) : 0); int limit = 16 << residualSize; if (pixelSteps) vector >>= 1; if (code > 0) { if ((vector += ((code - 1) << residualSize) + residual + 1) >= limit) vector -= limit << 1; } else if (code < 0) { if ((vector -= ((-code - 1) << residualSize) + residual + 1) < -limit) vector += limit << 1; } if (pixelSteps) vector <<= 1; return vector; } } /** * Macroblock decoder and dequantizer for MPEG-1 video streams. */ class Macroblock { /** * Macroblock type encoding */ public final static int I_TYPE = 1; public final static int P_TYPE = 2; public final static int B_TYPE = 3; public final static int D_TYPE = 4; /** * Macroblock type bit fields */ public final static int INTRA = 0x01; public final static int PATTERN = 0x02; public final static int BACKWARD = 0x04; public final static int FORWARD = 0x08; public final static int QUANT = 0x10; public final static int EMPTY = 0x80; /** * Default quantization matrix for intra coded macro blocks */ private final static int defaultIntraMatrix[] = { 8, 16, 16, 19, 16, 19, 22, 22, 22, 22, 22, 22, 26, 24, 26, 27, 27, 27, 26, 26, 26, 26, 27, 27, 27, 29, 29, 29, 34, 34, 34, 29, 29, 29, 27, 27, 29, 29, 32, 32, 34, 34, 37, 38, 37, 35, 35, 34, 35, 38, 38, 40, 40, 40, 48, 48, 46, 46, 56, 56, 58, 69, 69, 83 }; /** * Mapping for zig-zag scan ordering */ private final static int zigzag[] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; /** * Quantization scale for macro blocks */ private int scale; /** * Quantization matrix for intra coded blocks */ private int intraMatrix[]; /** * Quantization matrix for inter coded blocks */ private int interMatrix[]; /** * Color components sample blocks (8 bits) */ private int block[][]; /** * Predictors for DC coefficients (10 bits) */ private int predictor[]; /** * Macroblock type encoding */ private int type; /** * Macroblock type flags */ private int flags; /** * Motion prediction vectors */ private MotionVector forward; private MotionVector backward; /** * Initializes the MPEG-1 macroblock decoder object */ public Macroblock() { /* create quantization matrices */ intraMatrix = new int[64]; interMatrix = new int[64]; /* create motion prediction vectors */ forward = new MotionVector(); backward = new MotionVector(); /* create DCT blocks and predictors */ block = new int[6][64]; predictor = new int[3]; /* set up default macro block types */ type = I_TYPE; flags = EMPTY; /* set up default quantization scale */ scale = 0; /* set up default quantization matrices */ for (int i = 0; i < 64; i++) { intraMatrix[i] = defaultIntraMatrix[i]; interMatrix[i] = 16; } /* set up default DC coefficient predictors */ for (int i = 0; i < 3; i++) predictor[i] = 1024; } /** * Returns the quantization scale */ public int getScale() { return scale; } /** * Changes the quantization scale */ public void setScale(int scale) { this.scale = scale; } /** * Returns the quantization matrix for intra coded blocks */ public int[] getIntraMatrix() { return intraMatrix; } /** * Changes the quantization matrix for intra coded blocks */ public void setIntraMatrix(int matrix[]) { for (int i = 0; i < 64; i++) intraMatrix[i] = matrix[i]; } /** * Returns the quantization matrix for inter coded blocks */ public int[] getInterMatrix() { return interMatrix; } /** * Changes the quantization matrix for inter coded blocks */ public void setInterMatrix(int matrix[]) { for (int i = 0; i < 64; i++) interMatrix[i] = matrix[i]; } /** * Returns the macroblock type encoding */ public int getType() { return type; } /** * Changes the macroblock type encoding */ public void setType(int type) { this.type = type; } /** * Returns the component block of samples */ public int[][] getData() { return block; } /** * Changes the component block of samples */ public void setData(int component, int data[]) { for (int i = 0; i < 64; i++) block[component][i] = data[i]; } /** * Returns the macro block type flags */ public int getFlags() { return flags; } /** * Changes the macro block type flags */ public void setFlags(int flags) { this.flags = flags; } /** * Returns true if the block is empty */ public boolean isEmpty() { return (flags & EMPTY) != 0; } /** * Returns true if the block is intra coded */ public boolean isIntraCoded() { return (flags & INTRA) != 0; } /** * Returns true if the block is pattern coded */ public boolean isPatternCoded() { return ((flags & PATTERN) != 0); } /** * Returns true if the block is forward predicted */ public boolean isBackwardPredicted() { return (flags & BACKWARD) != 0; } /** * Returns true if the block is backward predicted */ public boolean isForwardPredicted() { return (flags & FORWARD) != 0; } /** * Returns true if the block is forward and backward predicted */ public boolean isBidirPredicted() { return ((flags & FORWARD) != 0) && ((flags & BACKWARD) != 0); } /** * Returns true if the block has a quantization scale */ public boolean isQuantScaled() { return ((flags & QUANT) != 0); } /** * Returns the forward motion vector */ public MotionVector getForwardVector() { return forward; } /** * Returns the backward motion vector */ public MotionVector getBackwardVector() { return backward; } /** * Resets the DCT coefficient predictors */ public void resetDataPredictors() { for (int i = 0; i < 3; i++) predictor[i] = 1024; } /** * Resets the motion vector predictors */ public void resetMotionVectors() { forward.setVector(0, 0); backward.setVector(0, 0); } /** * Parses the next encoded MPEG-1 macroblock (according to ISO 11172-2) * decoding and dequantizing the DCT coefficient component blocks. */ public void getMacroblock(VLCInputStream stream) throws IOException { /* read macro block bit flags */ switch (getType()) { case I_TYPE: setFlags(stream.getIMBCode()); break; case P_TYPE: setFlags(stream.getPMBCode()); if (!isForwardPredicted()) resetMotionVectors(); if (!isIntraCoded()) resetDataPredictors(); break; case B_TYPE: setFlags(stream.getBMBCode()); if (isIntraCoded()) resetMotionVectors(); else resetDataPredictors(); break; } /* read quantization scale */ if (isQuantScaled()) { setScale(stream.getBits(5)); } /* read forward motion vector */ if (isForwardPredicted()) { getForwardVector().getMotionVector(stream); } /* read backward motion vector */ if (isBackwardPredicted()) { getBackwardVector().getMotionVector(stream); } /* read block pattern code */ int pattern = 0; if (isPatternCoded()) { pattern = stream.getCBPCode(); } /* clear DCT coefficients blocks */ for (int i = 0; i < 6; i++) { for (int j = 0; j < 64; j++) { block[i][j] = 0; } } /* read DCT coefficient blocks */ if (isIntraCoded()) { /* read intra coded DCT coefficients */ for (int i = 0; i < 6; i++) { block[i][0] = predictor[i < 4 ? 0 : i - 3]; getIntraBlock(stream, block[i], i); predictor[i < 4 ? 0 : i - 3] = block[i][0]; IDCT.transform(block[i]); } } else { /* read inter coded DCT coefficients */ for (int i = 0; i < 6; i++) { if ((pattern & (1 << (5 - i))) != 0) { getInterBlock(stream, block[i]); IDCT.transform(block[i]); } } } } /** * Parses an intra coded MPEG-1 block (according to ISO 11172-2) decoding * and dequantizing the DC and AC coefficients stored in zig zag order. */ private void getIntraBlock(VLCInputStream stream, int block[], int component) throws IOException { /* decode DC coefficients */ if (component < 4) block[0] += stream.getIntraDCLumValue() << 3; else block[0] += stream.getIntraDCChromValue() << 3; /* decode AC coefficients */ for (int i = 1; i <= block.length; i++) { int data[] = stream.getACValue(); if (data[0] == stream.EOB) break; int position = zigzag[i = (i + data[0]) & 63]; block[position] = (data[1] * scale * intraMatrix[i]) >> 3; } } /** * Parses a inter coded MPEG-1 block (according to ISO 11172-2) decoding * and dequantizing the DC and AC coefficients stored in zig zag order. */ private void getInterBlock(VLCInputStream stream, int block[]) throws IOException { /* decode DC and AC coefficients */ for (int i = 0; i <= block.length; i++) { int data[] = (i == 0 ? stream.getInterDCValue() : stream.getACValue()); if (data[0] == stream.EOB) break; data[1] += ((data[1] >> 31) << 1) + 1; int position = zigzag[i = (i + data[0]) & 63]; block[position] = (data[1] * scale * interMatrix[i]) >> 3; } } } /** * Picture decoder for MPEG-1 video streams according to ISO 11172-2. */ class Picture { /** * Picture current and predictors frame buffers */ private int frameBuffer[]; private int forwardBuffer[]; private int backwardBuffer[]; /** * Macroblock decoder and dequantizer */ private Macroblock macroblock; /** * Dimension of the picture in pixels */ private int width, height; /** * Dimension of the picture in macro blocks */ private int mbColumns, mbRows; /** * Picture temporal reference number */ private int number; /** * Picture synchronization delay (1/90000s ticks) */ private int delay; /** * Constructs a MPEG-1 video stream picture */ public Picture() { /* constructs the macroblock */ macroblock = new Macroblock(); /* initialize temporal fields */ number = 0; delay = 0; /* initialize dimension and frame buffers */ width = height = 0; mbColumns = mbRows = 0; frameBuffer = null; forwardBuffer = null; backwardBuffer = null; } /** * Changes the picture dimensions */ public void setSize(int width, int height) { /* set up picture dimension */ this.width = width; this.height = height; /* compute dimension in macro blocks */ mbColumns = (width + 15) >> 4; mbRows = (height + 15) >> 4; /* allocate frame buffers */ frameBuffer = new int[256 * mbRows * mbColumns]; forwardBuffer = new int[256 * mbRows * mbColumns]; backwardBuffer = new int[256 * mbRows * mbColumns]; } /** * Returns the picture temporal reference */ public int getNumber() { return number; } /** * Changes the picture temporal reference */ public void setNumber(int number) { this.number = number; } /** * Returns the picture temporal delay */ public int getDelay() { return delay; } /** * Changes the picture temporal delay */ public void setDelay(int delay) { this.delay = delay; } /** * Returns the macro block object */ public Macroblock getMacroblock() { return macroblock; } /** * Returns the dimension of the picture in pixels */ public int getWidth() { return width; } public int getHeight() { return height; } public int getStride() { return mbColumns << 4; } /** * Returns the last picture of the MPEG-1 video stream */ public int[] getLastFrame() { return backwardBuffer; } /** * Parses the next picture from the MPEG-1 video stream */ public int[] getFrame(VLCInputStream stream) throws IOException { /* read picture temporal reference */ setNumber(stream.getBits(10)); /* read picture encoding type */ macroblock.setType(stream.getBits(3)); /* read VBV delay of this picture */ setDelay(stream.getBits(16)); /* read forward motion information */ if (macroblock.getType() != Macroblock.I_TYPE) { macroblock.getForwardVector().getMotionInfo(stream); } /* read backward motion information */ if (macroblock.getType() == Macroblock.B_TYPE) { macroblock.getBackwardVector().getMotionInfo(stream); } /* skip extra bit information */ while (stream.getBits(1) != 0) stream.flushBits(8); /* skip extensions and user data chunks */ while (stream.showCode() == BitInputStream.EXT_START_CODE || stream.showCode() == BitInputStream.USER_START_CODE) { stream.getCode(); } /* update forward frame buffer */ if (macroblock.getType() != Macroblock.B_TYPE) { int buffer[] = forwardBuffer; forwardBuffer = backwardBuffer; backwardBuffer = buffer; } /* parse picture slices */ while (stream.showCode() >= BitInputStream.SLICE_MIN_CODE && stream.showCode() <= BitInputStream.SLICE_MAX_CODE) { getSlice(stream, stream.getCode()); } /* update backward frame buffer */ if (macroblock.getType() != Macroblock.B_TYPE) { int buffer[] = backwardBuffer; backwardBuffer = frameBuffer; frameBuffer = buffer; return forwardBuffer; } return frameBuffer; } /** * Parses the next picture slice from the MPEG-1 video stream */ private void getSlice(VLCInputStream stream, int code) throws IOException { /* compute macro block address */ int address = (code - BitInputStream.SLICE_MIN_CODE) * mbColumns - 1; /* read slice quantization scale */ macroblock.setScale(stream.getBits(5)); /* skip extra bit information */ while (stream.getBits(1) != 0) { stream.flushBits(8); } /* reset DCT predictors and motion vectors */ macroblock.setFlags(Macroblock.EMPTY); macroblock.resetDataPredictors(); macroblock.resetMotionVectors(); /* parse slice macro blocks */ while (stream.showBits(23) != 0) { /* get macro block address increment */ int lastAddress = address + stream.getMBACode(); /* handle skipped macro blocks */ if (macroblock.isEmpty()) { /* handle the first macro block address in the slice */ address = lastAddress; } else { while (++address < lastAddress) { /* assume inter coded macro block with zero coefficients */ macroblock.resetDataPredictors(); /* use previous motion vectors or zero in P-picture macro blocks */ if (macroblock.getType() == Macroblock.P_TYPE) macroblock.resetMotionVectors(); /* process skipped macro block */ if (macroblock.isBidirPredicted()) { motionPrediction(address, forwardBuffer, backwardBuffer, macroblock.getForwardVector(), macroblock.getBackwardVector()); } else if (macroblock.isBackwardPredicted()) { motionPrediction(address, backwardBuffer, macroblock.getBackwardVector()); } else { motionPrediction(address, forwardBuffer, macroblock.getForwardVector()); } } } /* decode macro block */ macroblock.getMacroblock(stream); /* process macro block */ if (macroblock.isIntraCoded()) { motionPrediction(address, macroblock.getData()); } else { if (macroblock.isBidirPredicted()) { motionPrediction(address, forwardBuffer, backwardBuffer, macroblock.getForwardVector(), macroblock.getBackwardVector()); } else if (macroblock.isBackwardPredicted()) { motionPrediction(address, backwardBuffer, macroblock.getBackwardVector()); } else { motionPrediction(address, forwardBuffer, macroblock.getForwardVector()); } motionCompensation(address, macroblock.getData()); } } } private void motionPrediction(int address, int sourceBuffer[], MotionVector vector) { int width = mbColumns << 4; int offset = ((address % mbColumns) + width * (address / mbColumns)) << 4; int deltaA = (vector.horizontal >> 1) + width * (vector.vertical >> 1); int deltaB = (vector.horizontal & 1) + width * (vector.vertical & 1); if (deltaB == 0) { for (int i = 0; i < 16; i++) { System.arraycopy(sourceBuffer, offset + deltaA, frameBuffer, offset, 16); offset += width; } } else { deltaB += deltaA; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { int d0 = sourceBuffer[offset + deltaA]; int d1 = sourceBuffer[offset + deltaB]; int d2 = (d0 & 0xfefefe) + (d1 & 0xfefefe); int d3 = (d0 & d1) & 0x010101; frameBuffer[offset++] = (d2 >> 1) + d3; } offset += width - 16; } } } private void motionPrediction(int address, int sourceBufferA[], int sourceBufferB[], MotionVector vectorA, MotionVector vectorB) { int width = mbColumns << 4; int offset = ((address % mbColumns) + width * (address / mbColumns)) << 4; int deltaA = (vectorA.horizontal >> 1) + width * (vectorA.vertical >> 1); int deltaB = (vectorB.horizontal >> 1) + width * (vectorB.vertical >> 1); int deltaC = (vectorA.horizontal & 1) + width * (vectorA.vertical & 1); int deltaD = (vectorB.horizontal & 1) + width * (vectorB.vertical & 1); if (deltaC == 0 && deltaD == 0) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { int d0 = sourceBufferA[offset + deltaA]; int d1 = sourceBufferB[offset + deltaB]; int d2 = (d0 & 0xfefefe) + (d1 & 0xfefefe); int d3 = (d0 & d1) & 0x010101; frameBuffer[offset++] = (d2 >> 1) + d3; } offset += width - 16; } } else { deltaC += deltaA; deltaD += deltaB; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { int d0 = sourceBufferA[offset + deltaA]; int d1 = sourceBufferB[offset + deltaB]; int d2 = sourceBufferA[offset + deltaC]; int d3 = sourceBufferB[offset + deltaD]; int d4 = ((d0 & 0xfcfcfc) + (d1 & 0xfcfcfc) + (d2 & 0xfcfcfc) + (d3 & 0xfcfcfc)); int d5 = (d0 + d1 + d2 + d3 - d4) & 0x040404; frameBuffer[offset++] = (d4 + d5) >> 2; } offset += width - 16; } } } private void motionPrediction(int address, int block[][]) { int width, offset, index; /* compute macroblock address */ width = mbColumns << 4; address = ((address % mbColumns) + width * (address / mbColumns)) << 4; /* reconstruct luminance blocks */ offset = address; index = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { frameBuffer[offset] = clip[512 + block[0][index]]; frameBuffer[offset+8] = clip[512 + block[1][index]]; offset++; index++; } offset += width - 8; } offset = address + (width << 3); index = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { frameBuffer[offset] = clip[512 + block[2][index]]; frameBuffer[offset+8] = clip[512 + block[3][index]]; offset++; index++; } offset += width - 8; } /* reconstruct chrominance blocks */ offset = address; index = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { int Cb = clip[512 + block[4][index]]; int Cr = clip[512 + block[5][index]]; int CbCr = (Cb << 8) + (Cr << 16); frameBuffer[offset++] += CbCr; frameBuffer[offset++] += CbCr; offset += width - 2; frameBuffer[offset++] += CbCr; frameBuffer[offset++] += CbCr; offset -= width; index++; } offset += width + width - 16; } } private void motionCompensation(int address, int block[][]) { int width, offset, index; /* compute macroblock address */ width = mbColumns << 4; address = ((address % mbColumns) + width * (address / mbColumns)) << 4; /* reconstruct luminance blocks */ offset = index = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { data[offset] = block[0][index]; data[offset+8] = block[1][index]; data[offset+128] = block[2][index]; data[offset+8+128] = block[3][index]; offset++; index++; } offset += 8; } /* reconstruct chrominance blocks */ offset = index = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { int Y, YCbCr; int Cb = 512 + block[4][index]; int Cr = 512 + block[5][index]; Y = 512 + data[offset++]; YCbCr = frameBuffer[address]; frameBuffer[address++] = (clip[((YCbCr >> 0) & 0xFF) + Y ] << 0) + (clip[((YCbCr >> 8) & 0xFF) + Cb] << 8) + (clip[((YCbCr >> 16) & 0xFF) + Cr] << 16); Y = 512 + data[offset++]; YCbCr = frameBuffer[address]; frameBuffer[address++] = (clip[((YCbCr >> 0) & 0xFF) + Y ] << 0) + (clip[((YCbCr >> 8) & 0xFF) + Cb] << 8) + (clip[((YCbCr >> 16) & 0xFF) + Cr] << 16); offset += 16-2; address += width-2; Y = 512 + data[offset++]; YCbCr = frameBuffer[address]; frameBuffer[address++] = (clip[((YCbCr >> 0) & 0xFF) + Y ] << 0) + (clip[((YCbCr >> 8) & 0xFF) + Cb] << 8) + (clip[((YCbCr >> 16) & 0xFF) + Cr] << 16); Y = 512 + data[offset++]; YCbCr = frameBuffer[address]; frameBuffer[address++] = (clip[((YCbCr >> 0) & 0xFF) + Y ] << 0) + (clip[((YCbCr >> 8) & 0xFF) + Cb] << 8) + (clip[((YCbCr >> 16) & 0xFF) + Cr] << 16); offset -= 16; address -= width; index++; } offset += 16; address += width+width-16; } } private static int data[] = new int[256]; private static int clip[] = new int[1024]; static { for (int i = 0; i < 1024; i++) { clip[i] = Math.min(Math.max(i - 512, 0), 255); } } } /** * The MPEG-1 video stream decoder according to ISO 11172-2. */ class MPEGVideoStream { /** * MPEG-1 video frame rate table */ private static final int frameRateTable[] = { 30, 24, 24, 25, 30, 30, 50, 60, 60, 12, 30, 30, 30, 30, 30, 30 }; /** * MPEG-1 video stream frame rate (frames per second) */ private int frameRate; /** * MPEG-1 video stream bit rate (bits per second) */ private int bitRate; /** * MPEG-1 video stream VBV buffer size (16 kbit steps) */ private int bufferSize; /** * MPEG-1 video stream time record (in frames) */ private int hour, minute, second, frame; /** * MPEG-1 video stream current picture */ private Picture picture; /** * MPEG-1 video stream boolean fields */ private boolean constrained, dropped, closed, broken; /** * The last MPEG-1 picture frame parsed */ private int frameBuffer[]; /** * The underlaying VLC input stream */ private VLCInputStream stream; /** * Initializes the MPEG-1 video input stream object */ public MPEGVideoStream(InputStream inputStream) throws IOException { /* set ups the VLC input stream */ stream = new VLCInputStream(inputStream); /* set ups the picture decoder */ picture = new Picture(); /* reset rates and buffer size */ frameRate = 0; bitRate = 0; bufferSize = 0; /* reset time record */ hour = 0; minute = 0; second = 0; frame = 0; /* reset boolean fields */ constrained = false; dropped = false; closed = false; broken = false; /* reset last frame buffer */ frameBuffer = getFrame(); } /** * Returns the MPEG-1 video stream frame rate */ public int getFrameRate() { return frameRate; } /** * Changes the MPEG-1 video stream frame rate */ public void setFrameRate(int rate) { frameRate = rate; } /** * Returns the MPEG-1 video stream bit rate */ public int getBitRate() { return bitRate; } /** * Changes the MPEG-1 video stream bit rate */ public void setBitRate(int rate) { bitRate = rate; } /** * Returns the MPEG-1 video stream VBV buffer size */ public int getBufferSize() { return bufferSize; } /** * Changes the MPEG-1 video stream VBV buffer size */ public void setBufferSize(int size) { bufferSize = size; } /** * Returns the MPEG-1 video stream time record */ public long getTime() { return frame + getFrameRate() * (second + 60L * minute + 3600L * hour); } /** * Changes the MPEG-1 video stream time record */ public void setTime(int hour, int minute, int second, int frame) { this.hour = hour; this.minute = minute; this.second = second; this.frame = frame; } /** * Returns true if the video parameters are constrained */ public boolean isConstrained() { return constrained; } /** * Enables or disables the video parameters constrains */ public void setConstrained(boolean constrained) { this.constrained = constrained; } /** * Returns true if the group of pictures drops frames */ public boolean isDropped() { return dropped; } /** * Changes the dropped flag of the group of pictures */ public void setDropped(boolean dropped) { this.dropped = dropped; } /** * Returns true if the group of pictures is closed */ public boolean isClosed() { return closed; } /** * Changes the closed flag of the group of pictures */ public void setClosed(boolean closed) { this.closed = closed; } /** * Returns true if there is a broken link */ public boolean isBroken() { return broken; } /** * Changes the broken flag of the group of pictures */ public void setBroken(boolean broken) { this.broken = broken; } /** * Returns the MPEG-1 video picture dimensions */ public int getWidth() { return picture.getWidth(); } public int getHeight() { return picture.getHeight(); } public int getStride() { return picture.getStride(); } /** * Parses the next frame of the MPEG-1 video stream */ public int[] getFrame() throws IOException { while (stream.showCode() != BitInputStream.SEQ_END_CODE) { switch (stream.getCode()) { case BitInputStream.SEQ_START_CODE: getSequenceHeader(stream); break; case BitInputStream.GOP_START_CODE: getGroupPictures(stream); break; case BitInputStream.PIC_START_CODE: return getPictureFrame(stream); case BitInputStream.USER_START_CODE: case BitInputStream.EXT_START_CODE: break; default: // throw new IOException("Unknown MPEG-1 video layer start code"); break; } } if (frameBuffer != picture.getLastFrame()) { frameBuffer = picture.getLastFrame(); return frameBuffer; } return null; } /** * Parses the sequence header from the MPEG-1 video stream */ private void getSequenceHeader(VLCInputStream stream) throws IOException { /* read picture dimensions in pixels */ int width = stream.getBits(12); int height = stream.getBits(12); int aspectRatio = stream.getBits(4); /* changes the MPEG-1 picture dimension */ if (picture.getWidth() == 0 && picture.getHeight() == 0) picture.setSize(width, height); /* read picture and bit rates */ setFrameRate(frameRateTable[stream.getBits(4)]); setBitRate(400 * stream.getBits(18)); stream.getBits(1); /* read VBV buffer size */ setBufferSize(stream.getBits(10)); /* read constrained parameters flag */ setConstrained(stream.getBits(1) != 0); /* read quantization matrix for intra coded blocks */ int intraMatrix[] = picture.getMacroblock().getIntraMatrix(); if (stream.getBits(1) != 0) { for (int i = 0; i < 64; i++) intraMatrix[i] = stream.getBits(8); } /* read quantization matrix for inter coded blocks */ int interMatrix[] = picture.getMacroblock().getInterMatrix(); if (stream.getBits(1) != 0) { for (int i = 0; i < 64; i++) interMatrix[i] = stream.getBits(8); } } /** * Parses group of pictures header from the MPEG-1 video stream */ private void getGroupPictures(VLCInputStream stream) throws IOException { /* read the drop frame flag */ setDropped(stream.getBits(1) != 0); /* read the time record */ int hour = stream.getBits(5); int minute = stream.getBits(6); int marker = stream.getBits(1); int second = stream.getBits(6); int frame = stream.getBits(6); setTime(hour, minute, second, frame); /* read closed and broken link flags */ setClosed(stream.getBits(1) != 0); setBroken(stream.getBits(1) != 0); } /** * Parses the next picture from the MPEG-1 video stream */ private int[] getPictureFrame(VLCInputStream stream) throws IOException { return picture.getFrame(stream); } } /** * The MPEG-1 video stream decoder applet that is intended to run * embedded inside of a Web page or another application. */ public class MPEGPlayer extends Applet implements Runnable { /** * The MPEG-1 video input stream */ private MPEGVideoStream stream; /** * The picture frame buffer */ private int pixels[], width, height, stride; /** * The memory image color model */ private DirectColorModel model = null; /** * The memory image source */ private MemoryImageSource source = null; /** * The memory image object */ private Image image = null; /** * The applet's execution thread */ private Thread kicker = null; /** * The video stream location */ private URL url = null; /** * The repeat boolean parameter */ private boolean repeat = true; /** * Applet information */ public String getAppletInfo() { return "MPEGPlayer 0.9 (15 Apr 1998), Carlos Hasan (chasan@dcc.uchile.cl)"; } /** * Parameters information */ public String[][] getParameterInfo() { String info[][] = { { "source", "URL", "MPEG-1 video stream location" }, { "repeat", "boolean", "repeat the video sequence" } }; return info; } /** * Applet initialization */ public void init() { try { if (getParameter("source") != null) url = new URL(getDocumentBase(), getParameter("source")); if (getParameter("repeat") != null) repeat = getParameter("repeat").equalsIgnoreCase("true"); } catch (MalformedURLException exception) { showStatus("MPEG Exception: " + exception); } } /** * Start the execution of the applet */ public void start() { if (kicker == null && url != null) { kicker = new Thread(this); kicker.start(); } showStatus(getAppletInfo()); } /** * Stop the execution of the applet */ public void stop() { if (kicker != null && kicker.isAlive()) { kicker.stop(); } kicker = null; } /** * The applet main execution code */ public void run() { int frame[]; long time; try { do { stream = new MPEGVideoStream(url.openStream()); width = stream.getWidth(); height = stream.getHeight(); stride = stream.getStride(); resize(width, height); pixels = new int[stride * height]; model = new DirectColorModel(24, 0x0000ff, 0x00ff00, 0xff0000); time = System.currentTimeMillis(); while ((frame = readFrame()) != null) { drawFrame(frame, width, height, stride); source = new MemoryImageSource(width, height, model,pixels,0,stride); image = createImage(source); paint(getGraphics()); time += 1000L / stream.getFrameRate(); try { Thread.sleep(Math.max(time - System.currentTimeMillis(), 0)); } catch (InterruptedException exception) { } image.flush(); } } while (repeat); } catch (IOException exception) { showStatus("MPEG I/O Exception: " + exception); } } /** * Paint the current frame */ public void paint(Graphics graphics) { if (image != null) graphics.drawImage(image, 0, 0, null); } /** * Reads the next MPEG-1 video frame */ private int[] readFrame() { while (true) { try { return stream.getFrame(); } catch (Exception exception) { showStatus("MPEG Exception: " + exception); } } } /** * Draws the current MPEG-1 video frame */ private void drawFrame(int frame[], int width, int height, int stride) { int offset = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int YCbCr = frame[offset]; int Y = 512 + ((YCbCr >> 0) & 0xff); int Cb = cbtable[(YCbCr >> 8) & 0xff]; int Cr = crtable[(YCbCr >> 16) & 0xff]; pixels[offset++] = (clip[Y + (Cr >> 16)] << 0) + (clip[Y + (((Cb + Cr) << 16) >> 16)] << 8) + (clip[Y + (Cb >> 16)] << 16); } offset += stride - width; } } /** * Color conversion lookup tables */ private static int clip[], cbtable[], crtable[]; static { clip = new int[1024]; cbtable = new int[256]; crtable = new int[256]; for (int i = 0; i < 1024; i++) { clip[i] = Math.min(Math.max(i - 512, 0), 255); } for (int i = 0; i < 256; i++) { int level = i - 128; cbtable[i] = (((int)(1.77200 * level)) << 16) - ((int)(0.34414 * level)); crtable[i] = (((int)(1.40200 * level)) << 16) - ((int)(0.71414 * level)); } } }
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值