最近无聊,做一下android音视频方面的学习和研究。网上有很多案例值得我们去学习。我个人先去大概了解了一下音视频的一些基本概念,然后做了一个小demo,实现了一台手机录制,另一台手机实时播放。视屏录制采用的Camera,预览用的SurfaceView,把采集的视频压缩成bitmap,通过socket进行传输到另外一台手机上。这个demo只是用来学习android Camera,bitmap传输比较耗流量,所以该demo仅供学习。
视频采集客户端:
录制页面activity
package com.fm.camero;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import com.fangming.myframwork.R;
import com.fm.qxtapp.MyApp;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
/**
* @describe 视频录制成图片压缩socket传输
* @author fangming
* @CreateTime 2016年8月16日下午2:32:41
*/
public class TestcamoraActivety2 extends ServiceActivity implements Callback, PreviewCallback {
private TestcamoraActivety2 _this;
private String TAG = TestcamoraActivety2.class.getSimpleName();
private Button btn_start;
private SurfaceView sf_surfaceView;
private SurfaceHolder suHolder;
private int width;// 分辨率宽度
private int height;// 分辨率高度
private Camera mCamera;
private boolean isStreaming = false;
private MyApp myApp;
private Button btn_puse;
private ImageView iv_show;
private Boolean isShow = true;
int mwidth, mheight;
private Button btn_switch;
private Button btn_conn;
private Button btn_disconn;
private EditText et_ip;
private EditText et_port;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_testcamora);
_this = this;
initView();
myApp = MyApp.getInstance();
}
private void initSurfaceholder() {
suHolder = sf_surfaceView.getHolder();
suHolder.addCallback(this);
// width = 352;
// height = 288;
width = 320;
height = 480;
mwidth = width;
mheight = height;
System.out.println("*****相机初始化完成*****");
}
private void initView() {
btn_start = (Button) findViewById(R.id.btn_start);
btn_puse = (Button) findViewById(R.id.btn_puse);
iv_show = (ImageView) findViewById(R.id.iv_show);
sf_surfaceView = (SurfaceView) findViewById(R.id.sf_surfaceView);
initSurfaceholder();
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCamera.startPreview();
// new DumpFrameTask().execute();
}
});
btn_puse.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCamera.stopPreview();
}
});
btn_switch = (Button) findViewById(R.id.btn_switch);
btn_switch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
btn_conn = (Button) findViewById(R.id.btn_conn);
btn_disconn = (Button) findViewById(R.id.btn_disconn);
et_ip = (EditText) findViewById(R.id.et_ip);
et_port = (EditText) findViewById(R.id.et_port);
btn_conn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ip = et_ip.getText().toString();
port = et_port.getText().toString();
bindMyService();
}
});
btn_disconn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
unBindMyService();
}
});
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
isStreaming = true;
System.out.println("*****相机采集到的数组长度" + data.length + "*****");
if (isShow) {
mwidth = camera.getParameters().getPreviewSize().width;
mheight = camera.getParameters().getPreviewSize().height;
isShow = false;
}
YuvImage image = new YuvImage(data, ImageFormat.NV21, mwidth, height, null);
if (image != null) {
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, mwidth, height), 80, outstream);
byte[] arr=outstream.toByteArray();
// Bitmap bitmap =BitmapFactory.decodeByteArray(arr,0, arr.length);
// iv_show.setRotation(90);
// iv_show.setImageBitmap(bitmap);
mService.sendDate(arr);
try {
outstream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(suHolder);
} catch (IOException e1) {
e1.printStackTrace();
}
mCamera.setPreviewCallback(this);
List<Size> previewSizes = mCamera.getParameters().getSupportedPreviewSizes();
width = previewSizes.get(0).width;
height = previewSizes.get(0).height;
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(width, height);
// 横竖屏镜头自动调整
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait"); //
parameters.set("rotation", 90); // 镜头角度转90度(默认摄像头是横拍)
mCamera.setDisplayOrientation(90); // 在2.2以上可以使用
} else// 如果是横屏
{
parameters.set("orientation", "landscape"); //
mCamera.setDisplayOrientation(0); // 在2.2以上可以使用
}
System.out.println("*****surfaceCreated*****");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("*****系统执行surfaceChanged*****");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("*****surfaceDestroyed*****");
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unBindMyService();
};
@Override
public void finish() {
super.finish();
Intent mintent = new Intent();
mintent.setAction(ConnectionService.ACTION);
stopService(mintent);
}
}
该activity布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/sf_surfaceView"
android:layout_width="match_parent"
android:layout_height="300dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start" />
<Button
android:id="@+id/btn_puse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停" />
<Button
android:id="@+id/btn_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="转码" />
<Button
android:id="@+id/btn_conn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="connect" />
<Button
android:id="@+id/btn_disconn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="disconnect" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<EditText
android:id="@+id/et_ip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="192.168.1.108" />
<EditText
android:id="@+id/et_port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="6001" />
</LinearLayout>
<ImageView
android:id="@+id/iv_show"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@drawable/ic_launcher" />
</LinearLayout>
在这个录制中,遇到的几个比较坑的地方,第一个是视频的宽和高,没有设置好,播放时会导致黑屏或者花屏。还有就是对于camera采集的视频格式的一些问题。默认是ImageFormat.NV21,也就是YUV420sp。
// yuv420P(YV12)或者yuv420SP(NV21/NV12)
parameters.setPreviewFormat(ImageFormat.NV21);
我们采集的视频最后通过onPreviewFrame这个回调接口获得
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
isStreaming = true;
System.out.println("*****相机采集到的数组长度" + data.length + "*****");
if (isShow) {
mwidth = camera.getParameters().getPreviewSize().width;
mheight = camera.getParameters().getPreviewSize().height;
isShow = false;
}
YuvImage image = new YuvImage(data, ImageFormat.NV21, mwidth, height, null);
if (image != null) {
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, mwidth, height), 80, outstream);
byte[] arr=outstream.toByteArray();
// Bitmap bitmap =BitmapFactory.decodeByteArray(arr,0, arr.length);
// iv_show.setRotation(90);
// iv_show.setImageBitmap(bitmap);
//视频发送
mService.sendDate(arr);
try {
outstream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
采集到的视频通过mService.sendDate(arr);进行发送。mService是我自己定义的一个service用来后台处理数据。
ConnectionService类
package com.fm.camero;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import com.fm.constants.Constants;
import com.fm.utill.ByteConvertUtils;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class ConnectionService extends Service {
public final static String ACTION = "com.connectionService";
private final static int PACKATHEADER_SIGN_LENGTH = 2;// 我的包标识
private final static int PACKATHEADER_TYPE_LENGTH = 4;// 包类型 4byte
private final static int PACKATHEADER_DATALEN_LENGTH = 4;// 包长度 4byte
private final static int PACKATHEADER_LENGTH = PACKATHEADER_SIGN_LENGTH + PACKATHEADER_TYPE_LENGTH
+ PACKATHEADER_DATALEN_LENGTH;// 包头
private String ipAdd = "192.168.1.109";
private int port = 6001;
private String TAG = "ConnectionService";
private Socket mSocket;
private OutputStream outStream;
private InputStream inStream;
private InitSocketThread initSocketThread;
private Boolean isAccepte = true;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "---->" + "onCreateservice");
}
@Override
public void onDestroy() {
Log.e(TAG, "---->service停止");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "---->" + "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**
* 初始化socket线程
*/
class InitSocketThread extends Thread {
@Override
public void run() {
super.run();
initSocket();
}
}
/**
* 初始化socket
*/
private synchronized void initSocket() {
Log.e(TAG, "---->创建socket成功");
try {
mSocket = new Socket(ipAdd, port);
if (mSocket.isConnected()) {
Log.e(TAG, "---->连接成功");
outStream = mSocket.getOutputStream();
inStream = mSocket.getInputStream();
}
} catch (SocketException e) {
Log.d(TAG, "socket conn fail");
e.printStackTrace();
} catch (IOException e) {
Log.d(TAG, "socket conn fail");
e.printStackTrace();
}
}
public class MyBinder extends Binder {
public ConnectionService getService() {
return ConnectionService.this;
}
}
public MyBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void sendDate(byte[] data) {
int datalength = data.length;
byte[] buffer = new byte[PACKATHEADER_LENGTH + datalength];
// 设置包头3000
System.arraycopy(Constants.APPREQUEST_HEAD, 0, buffer, 0, 2);
// 设置type
byte[] type = { 0, 0, 0x26, (byte) 0x48 };
System.arraycopy(type, 0, buffer, 2, 4);
// 设置长度
byte[] len = ByteConvertUtils.intToBytes(datalength);
System.arraycopy(len, 0, buffer, 6, 4);
// 设置内容
System.arraycopy(data, 0, buffer, 10, datalength);
new sendDataThread(buffer).start();
}
public class sendDataThread extends Thread {
byte byteBuffer[] = null;
public sendDataThread(byte[] data) {
this.byteBuffer = data;
}
public void run() {
try {
outStream.write(byteBuffer, 0, byteBuffer.length);
System.out.println("发送的数据长度:" + byteBuffer.length);
outStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setIpAndPort(String ip, String port) {
if (ip != null && !ip.equals("")) {
ipAdd = ip;
}
if (port != null && !port.equals("")) {
this.port = Integer.valueOf(port);
}
if (initSocketThread == null) {
initSocketThread = new InitSocketThread();
initSocketThread.start();
}
}
}
以上就是客户端录制,下面是播放客户端
播放端activity
package com.fm.server;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
private MainActivity _this;
private ImageView iv_btmap;
private EditText et_port;
private Button btn_bind;
private Button btn_unbind;
public String mPort;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_this = this;
initView();
}
private void initView() {
iv_btmap = (ImageView) findViewById(R.id.iv_btmap);
et_port = (EditText) findViewById(R.id.et_port);
btn_bind = (Button) findViewById(R.id.btn_bind);
btn_unbind = (Button) findViewById(R.id.btn_unbind);
btn_bind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String port = et_port.getText().toString();
if (port == null || port.equals("")) {
Toast.makeText(_this, "端口为null", Toast.LENGTH_SHORT).show();
return;
}
mPort = port;
bindService();
}
});
btn_unbind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
unBindService();
}
});
}
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
byte[] data = (byte[]) msg.obj;
if (data == null) {
return;
}
System.out.println("handle收到的数据:" + data.length);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
// Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
// data.length, options);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (bitmap != null) {
iv_btmap.setRotation(90);
iv_btmap.setImageBitmap(bitmap);
}
break;
default:
break;
}
};
};
@Override
public void finish() {
super.finish();
if (mService != null) {
unBindService();
}
}
public void bindService() {
Intent mintent = new Intent();
mintent.setClass(_this, BindService.class);
bindService(mintent, conn, Context.BIND_AUTO_CREATE);
}
public void unBindService() {
if (mService != null) {
unbindService(conn);
}
}
public BindService mService = null;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((BindService.MyBinder) service).getService();
mService.startConn(mPort);
mService.setHandler(mHandler);
}
};
}
播放端service
package com.fm.server;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Arrays;
import com.fm.constants.Constants;
import com.fm.utill.ByteConvertUtils;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
public class BindService extends Service {
private String TAG = "BindService";
public int port = 6001;
public OutputStream outStream;
public InputStream inStream;
public Socket mSocket;
private InitSocketThread initSocketThread;
private ReadThread readThread;
private Boolean isAccepte = true;
ServerSocket server;
private final static int PACKATHEADER_SIGN_LENGTH = 2;// 我的包标识
private final static int PACKATHEADER_TYPE_LENGTH = 4;// 包类型 4byte
private final static int PACKATHEADER_DATALEN_LENGTH = 4;// 包长度 4byte
private final static int PACKATHEADER_LENGTH = PACKATHEADER_SIGN_LENGTH + PACKATHEADER_TYPE_LENGTH
+ PACKATHEADER_DATALEN_LENGTH;// 包头
public void setPort(int port) {
this.port = port;
}
private Handler hander;
public void setHandler(Handler hander) {
this.hander = hander;
}
public void startConn(String port) {
if (port != null && !port.equals("")) {
this.port = Integer.valueOf(port);
}
initSocketThread = new InitSocketThread();
initSocketThread.start();
}
/**
* 初始化socket线程
*/
class InitSocketThread extends Thread {
@Override
public void run() {
super.run();
initSocket();
}
}
/**
* 初始化socket
*/
private void initSocket() {
Log.e(TAG, "---->创建socket成功");
try {
server = new ServerSocket(port);
mSocket = server.accept();
if (mSocket.isConnected()) {
Log.e(TAG, "---->连接成功");
outStream = mSocket.getOutputStream();
inStream = mSocket.getInputStream();
readThread = new ReadThread();
readThread.start();
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (isAccepte) {
if (mSocket != null && mSocket.isConnected()) {
devide(new DataInputStream(new BufferedInputStream(inStream)));
}
}
}
}
public synchronized void devide(DataInputStream ds) {
try {
if (ds.available() > 0) {
recv(ds);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void recv(DataInputStream dis) throws IOException {
byte[] head = new byte[PACKATHEADER_LENGTH];
Log.e(TAG, "---->>接收数据的长度" + dis.available());
try {
dis.readFully(head, 0, PACKATHEADER_LENGTH);
} catch (IOException e) {
return;
}
// 读取前两个字节我的数据包标识head[]
byte[] sign = new byte[2];
sign = Arrays.copyOfRange(head, 0, 2);
if (ByteConvertUtils.bytesToInt2(sign) != Constants.APP_CTL_HEAD) {
return;
}
// 读取4byte包类型
byte[] type = new byte[4];
type = Arrays.copyOfRange(head, 2, 6);
int nType = ByteConvertUtils.bytesToInt(type);
// 读取4byte内容长度
byte[] datalen = new byte[4];
datalen = Arrays.copyOfRange(head, 6, 10);
int nDatalen = ByteConvertUtils.bytesToInt(datalen);
Log.e(TAG, "type:" + nType);
switch (nType) {// App登陆/查询网关
case Constants.VEDIO_STREAM:
byte[] data = null;
if (nDatalen > 0) {
// 接收指定长度的内容
data = new byte[nDatalen];
dis.readFully(data, 0, nDatalen);
Log.e(TAG, "len:" + nDatalen);
sendMessage(data);
}
break;
default:
Log.e(TAG, "---->不识别的命令");
break;
}
};
public void sendMessage(byte[] data) {
Message msg = hander.obtainMessage();
msg.what = 0;
msg.obj = data;
hander.sendMessage(msg);
}
@Override
public void onCreate() {
Log.e(TAG, "---->" + "onCreateservice");
super.onCreate();
}
@Override
public void onDestroy() {
Log.e(TAG, "---->service停止");
super.onDestroy();
isAccepte = false;
if (readThread != null && readThread.isAlive()) {
readThread.interrupt();
readThread = null;
}
initSocketThread.interrupt();
initSocketThread = null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "---->" + "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
public class MyBinder extends Binder {
public BindService getService() {
return BindService.this;
}
}
public MyBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
主要用来和视频采集端进行socket通信。
另外附上一个简单的静态类
package com.fm.constants;
public class Constants {
public static final int APP_CTL_HEAD = 3000;// 包头标识
public static final byte[] APPREQUEST_HEAD={0x0b,(byte) 0xB8};//包头标识
public static final int VEDIO_STREAM = 9800;//服务端将要发送播放视频命令
}
工具类:
package com.fangming.utill;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import android.util.Log;
public class ByteConvertUtils {
/**
* 长整形转byte数组
*
* @param n
* 长整形数字
* @return 转换后的数组
*/
public static byte[] longToBytes(long n) {
byte[] b = new byte[8];
b[7] = (byte) (n & 0xff);
b[6] = (byte) (n >> 8 & 0xff);
b[5] = (byte) (n >> 16 & 0xff);
b[4] = (byte) (n >> 24 & 0xff);
b[3] = (byte) (n >> 32 & 0xff);
b[2] = (byte) (n >> 40 & 0xff);
b[1] = (byte) (n >> 48 & 0xff);
b[0] = (byte) (n >> 56 & 0xff);
return b;
}
public static short[] ByteToShortArray(byte[] byteArray)
{
short[] shortArray = new short[byteArray.length/2];
ByteBuffer.wrap(byteArray).order(ByteOrder.BIG_ENDIAN).asShortBuffer().get(shortArray);
return shortArray;
}
public static byte[] StringToByteArray(String houseNo)
{
Log.i("houseNo.length","houseNo.length"+houseNo.length());
byte[] byteArray=new byte[houseNo.length()];
for(int i=0;i<houseNo.length();i++)
{
byteArray[i]=Byte.parseByte(""+houseNo.charAt(i));
}
return byteArray;
}
/**
* 长整形转byte数组
*
* @param n
* 长整形数字
* @param array
* 转换后的结果
* @param offset
* 从第offset位开始转换
*/
public static void longToBytes(long n, byte[] array, int offset) {
array[7 + offset] = (byte) (n & 0xff);
array[6 + offset] = (byte) (n >> 8 & 0xff);
array[5 + offset] = (byte) (n >> 16 & 0xff);
array[4 + offset] = (byte) (n >> 24 & 0xff);
array[3 + offset] = (byte) (n >> 32 & 0xff);
array[2 + offset] = (byte) (n >> 40 & 0xff);
array[1 + offset] = (byte) (n >> 48 & 0xff);
array[0 + offset] = (byte) (n >> 56 & 0xff);
}
/**
* 将指定byte数组以16进制的形式打印到控制台
* @param hint String
* @param b byte[]
* @return void
*/
public static String printHexString( byte[] b) {
StringBuffer returnValue = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
System.out.print(hex.toUpperCase() + " ");
returnValue.append(hex.toUpperCase() + " ");
}
return "[" + returnValue.toString() + "]";
}
/**
*
* @param b byte[]
* @return String
*/
public static String Bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
/*
* 字节数组转换成Int数 读取后四个字节的内容长度
*/
public static int byte2Int(byte[] b) {
int intValue = 0;
for (int i = 0; i < b.length; i++) {
intValue += (b[i] & 0xFF) << (8 * (i));
}
return intValue;
}
/**
* bytes 转 Long
*
* @param array
* 要转换的byte
* @return long长整形数字
*/
public static long bytesToLong(byte[] array) {
return ((((long) array[0] & 0xff) << 56) | (((long) array[1] & 0xff) << 48) | (((long) array[2] & 0xff) << 40)
| (((long) array[3] & 0xff) << 32) | (((long) array[4] & 0xff) << 24)
| (((long) array[5] & 0xff) << 16) | (((long) array[6] & 0xff) << 8) | (((long) array[7] & 0xff) << 0));
}
public static short[] bytesToShorts(byte byteBuffer[]) {
int len = byteBuffer.length/2;
short[] output = new short[len];
int j = 0;
for (int i = 0; i < len; i++) {
output[i] = (short) (byteBuffer[j++] << 8);
output[i] |= (byteBuffer[j++] & 0xff);
// output[i] = (short) (byteBuffer[j++] << 8);
// output[i] += ((0x7f &byteBuffer[j]) + (byteBuffer[j] < 0 ? 128 : 0));
// j++;
}
return output;
}
public static byte[] shortsToBytes(short shortBuffer[]) {
int len = shortBuffer.length;
byte[] output = new byte[len*2];
int j = 0;
for (int i = 0; i < len; i++) {
output[j++] = (byte) (shortBuffer[i] >>> 8);
output[j++] = (byte) (0xff & shortBuffer[i]);
}
return output;
}
/**
* 将指定字符串src,以每两个字符分割转换为16进制形式 如:"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF,
* 0xD9}
*
* @param src
* String
* @return byte[]
*/
public static byte[] hexString2Bytes(String src) {
if (src == null || "".equals(src)) {
return null;
}
byte[] tmp = src.getBytes();
int len = tmp.length / 2;
if (len <= 0) {
return null;
}
byte[] ret = new byte[len];
for (int i = 0; i < len; i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
/**
* 将两个ASCII字符合成一个字节; 如:"EF"--> 0xEF
*
* @param src0
* byte
* @param src1
* byte
* @return byte
*/
public static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
.byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
.byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
/**
* byte数组转长整形数字
*
* @param array
* 要转换的byte数组
* @param offset
* 从第offset开始转换
* @return 转换后的长整形数字
*/
public static long bytesToLong(byte[] array, int offset) {
return ((((long) array[offset + 0] & 0xff) << 56) | (((long) array[offset + 1] & 0xff) << 48)
| (((long) array[offset + 2] & 0xff) << 40) | (((long) array[offset + 3] & 0xff) << 32)
| (((long) array[offset + 4] & 0xff) << 24) | (((long) array[offset + 5] & 0xff) << 16)
| (((long) array[offset + 6] & 0xff) << 8) | (((long) array[offset + 7] & 0xff) << 0));
}
public static byte[] intToBytes(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
public static void intToBytes(int n, byte[] array, int offset) {
array[3 + offset] = (byte) (n & 0xff);
array[2 + offset] = (byte) (n >> 8 & 0xff);
array[1 + offset] = (byte) (n >> 16 & 0xff);
array[offset] = (byte) (n >> 24 & 0xff);
}
/**
* @param b
* @return
*/
public static int bytesToInt(byte b[]) {
return b[3] & 0xff | (b[2] & 0xff) << 8 | (b[1] & 0xff) << 16 | (b[0] & 0xff) << 24;
}
/**
* @param b
* @return
*/
public static int bytesToInt2(byte b[]) {
return b[1] & 0xff | (b[0] & 0xff) << 8;
}
/**
* byte 数组转 int
*
* @param b
* byte数组
* @param offset
* 从数组的第几位开始转
* @return 整形
*/
public static int bytesToInt(byte b[], int offset) {
return b[offset + 3] & 0xff | (b[offset + 2] & 0xff) << 8 | (b[offset + 1] & 0xff) << 16
| (b[offset] & 0xff) << 24;
}
/**
* 无符号整形转数组
*
* @param n
* 要转换的整形
* @return byte数组
*/
public static byte[] uintToBytes(long n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
public static void uintToBytes(long n, byte[] array, int offset) {
array[3 + offset] = (byte) (n);
array[2 + offset] = (byte) (n >> 8 & 0xff);
array[1 + offset] = (byte) (n >> 16 & 0xff);
array[offset] = (byte) (n >> 24 & 0xff);
}
public static long bytesToUint(byte[] array) {
return ((long) (array[3] & 0xff)) | ((long) (array[2] & 0xff)) << 8 | ((long) (array[1] & 0xff)) << 16
| ((long) (array[0] & 0xff)) << 24;
}
public static long bytesToUint(byte[] array, int offset) {
return ((long) (array[offset + 3] & 0xff)) | ((long) (array[offset + 2] & 0xff)) << 8
| ((long) (array[offset + 1] & 0xff)) << 16 | ((long) (array[offset] & 0xff)) << 24;
}
public static byte[] shortToBytes(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) ((n >> 8) & 0xff);
return b;
}
public static void shortToBytes(short n, byte[] array, int offset) {
array[offset + 1] = (byte) (n & 0xff);
array[offset] = (byte) ((n >> 8) & 0xff);
}
public static short bytesToShort(byte[] b) {
return (short) (b[1] & 0xff | (b[0] & 0xff) << 8);
}
public static short bytesToShort(byte[] b, int offset) {
return (short) (b[offset + 1] & 0xff | (b[offset] & 0xff) << 8);
}
public static byte[] ushortToBytes(int n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) ((n >> 8) & 0xff);
return b;
}
public static void ushortToBytes(int n, byte[] array, int offset) {
array[offset + 1] = (byte) (n & 0xff);
array[offset] = (byte) ((n >> 8) & 0xff);
}
public static int bytesToUshort(byte b[]) {
return b[1] & 0xff | (b[0] & 0xff) << 8;
}
public static int bytesToUshort(byte b[], int offset) {
return b[offset + 1] & 0xff | (b[offset] & 0xff) << 8;
}
public static byte[] ubyteToBytes(int n) {
byte[] b = new byte[1];
b[0] = (byte) (n & 0xff);
return b;
}
public static void ubyteToBytes(int n, byte[] array, int offset) {
array[0] = (byte) (n & 0xff);
}
public static int bytesToUbyte(byte[] array) {
return array[0] & 0xff;
}
public static int bytesToUbyte(byte[] array, int offset) {
return array[offset] & 0xff;
}
// char 类型、 float、double 类型和 byte[] 数组之间的转换关系还需继续研究实现。
}
就写到这里,欢迎加我的qq和我交流,也可以加入我们的开发交流群。
个人qq:2385313404
开发交流qq群:574424529