Android流媒体研究<一>,一台手机录制,另一台手机播放
来源:互联网 发布:被淘宝投诉知识产权 编辑:程序博客网 时间:2024/04/30 01:23
最近无聊,做一下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
0 0
- Android流媒体研究<一>,一台手机录制,另一台手机播放
- ios android 一台手机两个系统。
- 手机上执行adb连接另一台android手机
- 一台电脑控制27台手机技术原理分析
- 一台电脑控制百台手机批量操作
- WeChat 聊天记录从一台手机转移到另外一台手机的注意事项
- 已知android手机一台,且不知是否含有sdcard,要求显示手机磁盘目录结构
- 一台电脑连上多台手机,如何选择其中一台进行处理
- android SDK从一台电脑转移到另一台电脑的问题
- VSS数据从一台服务器移动到另一台
- 虚拟机从一台电脑 拷贝到另一台电脑
- 从一台linux操作另一台的数据库
- 文件从一台服务器拷贝到另一台服务器
- 一台电脑控制多部手机怎么实现
- 一台手机+数据线,随时随地控制你的树莓派[八]
- 一台手机玩转你所有的社交生活(Android版)
- android自动化中的接电话case的扩展-告诉一台手机打个电话给我
- 如何把你的安卓手机变为一台无线Android测试机
- windbg使用
- DataTable.ImportRow()与DataTable.Add()的区别
- 【前端页面优化】改善你的jQuery的25个步骤 千倍级效率提升
- 关于膜系统的关键问题及解决方案(五)
- dubbo日志(二):部署dubbo-admain
- Android流媒体研究<一>,一台手机录制,另一台手机播放
- @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
- 手机APP项目测试点总结
- 控件visibility属性 控制是否可见
- Android Studio常用插件(2)
- 研发体系这点破事
- disconf
- 表单验证
- 第一篇__学习的开始