⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 livestream.java

📁 java程序中关于多媒体编程 既有文件说明 更有例子 希望大家可以一起学习交流
💻 JAVA
字号:
package com.sun.media.protocol.screen;

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import java.io.IOException;
import java.util.StringTokenizer;

// 实时数据流类:实时采集屏幕数据
public class LiveStream implements PushBufferStream, Runnable {
  protected int maxDataLength;       // 图像最大长度
  protected int [] data;             // 存放图像数据的数组
  protected RGBFormat rgbFormat;     // 图像采集格式
  protected boolean started;         // 是否开始采集的标志
  protected Thread thread;           // 图像采集子线程
  protected float frameRate = 1f;         // 图像采集的帧率
  protected BufferTransferHandler transferHandler;      // 缓冲区传输句柄
  protected Control [] controls = new Control[0];       // 控制器数组
  protected int x, y, width, height;         // 采集区域的开始(左上点)坐标和尺寸

  protected Robot robot = null;              // 获取屏幕数据的类对象

  int seqNo = 0;                             // 图像序列号

  // 构造函数
  public LiveStream(MediaLocator locator) {
    try {
      parseLocator(locator);    // 解析媒体定位器
    }
    catch (Exception e) {
      System.err.println(e);
    }

    try {
      robot = new Robot();                 // 在主屏幕坐标系下构造一个Robot对象
    }
    catch (AWTException awe) {
      throw new RuntimeException("");
    }

    Dimension size = new Dimension(width, height);     // 得到采集图像的尺寸
    maxDataLength = size.width * size.height * 3;      // 图像数据最大长度
    rgbFormat = new RGBFormat(size, maxDataLength,Format.intArray,
                              frameRate,32,0xFF0000, 0xFF00, 0xFF,
                              1, size.width,VideoFormat.FALSE,Format.NOT_SPECIFIED);
                   // 构造一个RGB格式

    data = new int[maxDataLength];                // 初始化数据数组
    thread = new Thread(this, "Screen Grabber");  // 初始化采集线程
  }

  // 解析媒体定位器,得到采集屏幕图像的参数
  protected void parseLocator(MediaLocator locator) {
    String rem = locator.getRemainder();      // 得到媒体定位器的字符串描述,不包括前面的协议名
    while (rem.startsWith("/") && rem.length() > 1)      // 去掉字符串前面的"/"
      rem = rem.substring(1);
    StringTokenizer st = new StringTokenizer(rem, "/");  // 用“/”作为分割符分割rem字符串
    if (st.hasMoreTokens()) {       // 如果rem中“/”之后有字符串
      String position = st.nextToken();    // 得到该字符串
      StringTokenizer nums = new StringTokenizer(position, ",");   // 用“,”作为分割符分割position字符串
      String stX = nums.nextToken();      // 得到采集图像左上点的横坐标
      x = Integer.parseInt(stX);
      String stY = nums.nextToken();      // 得到采集图像左上点的纵坐标
      y = Integer.parseInt(stY);
      String stW = nums.nextToken();      // 得到采集图像的宽度
      width = Integer.parseInt(stW);
      String stH = nums.nextToken();      // 得到采集图像的高度
      height = Integer.parseInt(stH);
    }
    if (st.hasMoreTokens()) {       // 如果rem中“/”之后有字符串
      String stFPS = st.nextToken();       // 得到该字符串
      frameRate = (Double.valueOf(stFPS)).floatValue();     // 转换为图像采集的帧率
    }
  }

  // 通知开始或停止采集
  void start(boolean started) {
    synchronized ( this ) {
      this.started = started;
      if (started && !thread.isAlive()) {    // 如果是开始采集
        thread = new Thread(this);
        thread.start();      // 开始采集线程
      }
      notifyAll();           // 通知等待过程
    }
  }

  /***************************************************************************
   * 下面几个函数实现了 PushBufferStream 接口
   ***************************************************************************/

  // 得到图像采集格式
  public Format getFormat() {
    return rgbFormat;
  }

  // 从数据源读数据到缓冲区
  public void read(Buffer buffer) throws IOException {
    synchronized (this) {
      Object outdata = buffer.getData();
      if (outdata == null || !(outdata.getClass() == Format.intArray) ||
         ((int[])outdata).length < maxDataLength) {
        outdata = new int[maxDataLength];
        buffer.setData(outdata);             // 设置缓冲区中存放数据的单元
      }
      buffer.setFormat( rgbFormat );         // 设置采集格式
      buffer.setTimeStamp( (long) (seqNo * (1000 / frameRate) * 1000000) );   // 设置时间戳(以纳秒为单位),给出了该帧图像的表现时间
      BufferedImage bi = robot.createScreenCapture(new Rectangle(x, y, width, height));
                                              // 读给定的屏幕区域产生一幅图像
      bi.getRGB(0, 0, width, height,(int[])outdata, 0, width);     // 得到RGB图像数据,存在缓冲区的outdata单元中
      buffer.setSequenceNumber( seqNo );     // 设置图像序列号
      buffer.setLength(maxDataLength);       // 设置缓冲区中的数据长度
      buffer.setFlags(Buffer.FLAG_KEY_FRAME);   // 设置采集的图像为关键帧
      buffer.setHeader( null );
      seqNo++;                                  // 图像序列号加1
    }
  }

  // 设置缓冲区传输句柄,以便数据准备好时通知缓冲区
  public void setTransferHandler(BufferTransferHandler transferHandler) {
    synchronized (this) {
      this.transferHandler = transferHandler;
      notifyAll();      // 通知等待过程
    }
  }

   /***************************************************************************
   * 下面这几个函数实现了 SourceStream 接口,因为 public interface PushBufferStream extends SourceStream
   ***************************************************************************/

  // 得到数据源数据类型的描述
  public ContentDescriptor getContentDescriptor() {
    ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW);    // 内容描述
    return cd;
  }

  // 得到数据流的长度
  public long getContentLength() {
    return LENGTH_UNKNOWN;
  }

  // 判断数据流是否结束
  public boolean endOfStream() {
    return false;
  }

   /***************************************************************************
   * 下面几个函数实现了 Controls 接口,因为 public interface SourceStream extends Controls
   ***************************************************************************/

  // 得到所有控制器
  public Object [] getControls() {
    return controls;
  }

  // 得到特定类型的控制器
  public Object getControl(String controlType) {
    try {
      Class  cls = Class.forName(controlType);
      Object cs[] = getControls();
      for (int i = 0; i < cs.length; i++) {
        if (cls.isInstance(cs[i]))
          return cs[i];
      }
      return null;
    }
    catch (Exception e) {
      return null;
    }
  }

  /***************************************************************************
   * 下面这个函数实现了 Runnable 接口
   ***************************************************************************/

  // 采集线程的执行体
  public void run() {
    while (started) {                      // 不断采集数据直到通知停止
      synchronized (this) {
        while (transferHandler == null && started) {    // 等待传输句柄与数据流连接好并被告知开始采集
          try {
            wait(1000);
          }
          catch (InterruptedException ie) { }
        } // while
      }

      if (started && transferHandler != null) {
        transferHandler.transferData(this);     // 向缓冲区中写数据,形成“推”数据流
        try {
          Thread.currentThread().sleep( 10 );
        }
        catch (InterruptedException ise) { }
      }
    } // while (started)
  } // run

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -