package camera4.test;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import android.app.Activity;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
public class VideoActivity extends Activity implements OnClickListener,
SurfaceHolder.Callback {
boolean isStarth264 = false;
// public native static int putH264Data(int nativePtr, byte[] buffer); // 视频录制显示
LocalSocket receiver, sender;
LocalServerSocket lss;
private MediaRecorder mMediaRecorder = null;
private SurfaceHolder mSurfaceHolder = null;
private static final int mVideoEncoder = MediaRecorder.VideoEncoder.H264;
Camera camera = null;
Thread t;
boolean isThread = true;
Button stop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("", "videoActivity----oncreate");
setContentView(R.layout.video_chat);
stop=(Button)findViewById(R.id.stop);
stop.setOnClickListener(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
final SurfaceView previewSurface = (SurfaceView) findViewById(R.id.video_capture_surface);
final SurfaceHolder holder = previewSurface.getHolder();
previewSurface.setZOrderOnTop(true);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
initLocalSocket();
}
public void initLocalSocket() {
receiver = new LocalSocket();
try {
lss = new LocalServerSocket("qwwwwwwqq");
receiver.connect(new LocalSocketAddress("qwwwwwwqq"));
receiver.setReceiveBufferSize(500000);
receiver.setSendBufferSize(500000);
sender = lss.accept();
sender.setReceiveBufferSize(500000);
sender.setSendBufferSize(500000);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
@Override
protected void onDestroy() {
Log.i("", "onDestroy");
super.onDestroy();
}
private void stopVideoRecording() {
if (isThread) {
isThread = false;
Log.i("", "停止线程");
}
Log.i("", "mMediaRecorder stopVideoRecording");
if (mMediaRecorder != null) {
// 停止录制
Log.i("", "stop video---start");
mMediaRecorder.stop();
Log.i("", "stop video---end");
// 释放资源
mMediaRecorder.release();
mMediaRecorder = null;
}
if (camera != null) {
camera.lock();
camera.release();
camera = null;
}
try {
lss.close();
receiver.close();
sender.close();
lss = null;
receiver = null;
sender = null;
} catch (IOException e) {
e.printStackTrace();
}
}
private void releaseMediaRecorder() {
Log.i("", "mMediaRecorder Releasing media recorder.");
if (mMediaRecorder != null) {
try {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
} catch (Exception e) {
e.printStackTrace();
}
}
if (camera != null) {
try {
Log.e("", "camera release");
camera.lock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void initializeVideo() {
isThread = true;
if (mSurfaceHolder != null) {
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
if (camera != null) {
Log.e("", "camera!=null initRecord");
try {
camera.setDisplayOrientation(90);
camera.unlock();
mMediaRecorder.setCamera(camera);
} catch (Exception e) {
e.printStackTrace();
}
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOrientationHint(90);
mMediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setVideoEncoder(mVideoEncoder);
mMediaRecorder.setVideoSize(320, 240);
mMediaRecorder.setVideoFrameRate(30);
// mMediaRecorder.setVideoEncodingBitRate(200 * 1000);
mMediaRecorder.setMaxDuration(100000);
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mMediaRecorder.setOutputFile(sender.getFileDescriptor());
try {
Log.i("", "start video-----------");
mMediaRecorder.prepare();
mMediaRecorder.start();
Log.i("", "end video-----------");
} catch (IOException e) {
releaseMediaRecorder();
finish();
e.printStackTrace();
}
}
}
public static byte[] sps_pps;
public static byte[] sps;
public static byte[] pps;
public static byte[] frame_buf;
int sps_len;
int pps_len;
int frame_cnt;
public void startVideoRecording() {
sps_pps = new byte[256];
sps = new byte[32];
pps = new byte[32];
sps_len = 0;
pps_len = 0;
frame_cnt = 0;
frame_buf = new byte[256 * 1024];
(t = new Thread() {
public void run() {
int frame_size = 1024;
byte[] buffer = new byte[1024 * 256];
int num = 0, number = 0;
int start, n = 0, i, readlen, spspps_len = 0;
int pre_n = 0, j, nbr = 0, finddone = 0, find_mdat_done = 0, find_frist0x65_done = 0, want_read_framelen = 0;
byte mdat[] = new byte[4];
int tmp_num[] = new int[4];
byte fixhead[] = new byte[4];
int ret = 1;
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
initializeVideo();
fixhead[0] = fixhead[1] = fixhead[2] = 0;
fixhead[3] = 1;
InputStream fis = null;
try {
fis = receiver.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
number = 0;
releaseMediaRecorder();
// * 现在为了调试,第一次录制的码流不能大于64KByte。将来需要优化!!!!
try {
num = fis.read(buffer, number, 256 * 1024);
} catch (IOException e1) {
e1.printStackTrace();
}
Log.i("", "MediaRecorder read 2233: " + num);
// 测试用
writeH264();
// * 找出码流中的avcC字段,因为该字段后面是h264的sps和pps信息
for (start = 0; start < num - 4; start++) {
if (buffer[start] == 'a' && buffer[start + 1] == 'v'
&& buffer[start + 2] == 'c'
&& buffer[start + 3] == 'C') {
start += 4;
break;
}
}
if (start + 4 > num) {
// * 在码率中没有找到avcC字段,根据需要进行处理
} else {
// * 跳过头部信息,现在用不着. 头部信息长度为6
start += 6;
// * 现在开始读取sps和pps
for (i = 0; i < 2; i++) {
readlen = 0;
readlen = buffer[start++];
readlen = buffer[start++] + (readlen << 8);
for (n = 0; n < readlen; n++) {
sps_pps[spspps_len++] = buffer[start + n];
// Log.i("aaa", " " + buffer[start + n]);
}
// ret = putH264Data(spspps_len, sps_pps);
if (i == 0) {
for (n = 0; n < spspps_len; n++) {
sps[n] = sps_pps[n];
sps_len = spspps_len;
}
} else {
for (n = 0; n < spspps_len; n++) {
pps[n] = sps_pps[n];
pps_len = spspps_len;
}
}
spspps_len = 0;
start += readlen + 1; // *根据二进制码流,要多加一个byte.详见h264解码资料
}
}
try {
raf.write(fixhead,0,4);
raf.write(sps, 0, sps_len);
raf.write(fixhead,0,4);
raf.write(pps, 0, pps_len);
} catch (IOException e) {
e.printStackTrace();
}
initializeVideo();
number = 0;
// 重新启动捕获,以获取视频流
DataInputStream dis = new DataInputStream(fis);
mdat[0] = 'm';
mdat[1] = 'd';
mdat[2] = 'a';
mdat[3] = 't';
n = 0;
// 这里存在一个bug,在h264数据中第一个IDR大于64Byte会出错(该值可以更改)!!!!哈哈
while (finddone == 0) {
try {
num = fis.read(buffer, 0, 64);
} catch (IOException e) {
break;
}
for (i = 0; i < num; i++) {
// * find "mdat" string
if (find_mdat_done == 0) {
if (mdat[n++] == buffer[i]) {
// * 在码流中找到了mdat字段
if (n >= 4) {
find_mdat_done = 1;
}
continue;
}
// * 没有找到mdat字段
n = 0;
} else if (find_frist0x65_done == 0) {
if (buffer[i] == 0x65) {
want_read_framelen = 0;
nbr = 0;
for (j = 0; j < 4; j++) {
want_read_framelen += (tmp_num[(n++) % 4] & 0xFF) << ((3 - j) * 8);
}
frame_buf[nbr++] = 0x65; // *把0x65写入buffer
find_frist0x65_done = finddone = 1;
} else {
tmp_num[(n++) % 4] = buffer[i] & 0xFF;
}
} else {
frame_buf[nbr++] = buffer[i];
}
}
}
want_read_framelen -= nbr;
byte[] tmpframe_buf = new byte[1024 * 256];
// * 注:这里假设h264每一帧的数据小于128KByte,如果超出会造成crash,将来需要优化此代码啊。
// int is = 0;
while (isThread) {
// Log.i("","isThread=--"+isThread);
// is = is + 1;
try {
// 读取每场的长度
int h264length = want_read_framelen;
num = 0;
while (h264length > 0) {
num = fis.read(tmpframe_buf, 0, h264length);
for (i = 0; i < num; i++) {
frame_buf[nbr++] = tmpframe_buf[i];
}
h264length -= num;
}
if ((frame_cnt > 100)
&& ((frame_buf[0] & 0x1F) == 0x05)) {
// ret = putH264Data(sps_len, sps);
// ret = putH264Data(pps_len, pps);
frame_cnt = 0;
}
ret = 1;
// ret = putH264Data(nbr, frame_buf);
raf.write(fixhead,0,4);
raf.write(frame_buf, 0, nbr);
// * 读取h264帧的长度信息
want_read_framelen = dis.readInt();
nbr = 0;
frame_cnt++;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
}).start();
}
public void surfaceCreated(SurfaceHolder holder) {
Log.i("", "VideoActivity---surfaceCreated-------------");
mSurfaceHolder = holder;
if (camera == null) {
Log.i("", "camera front");
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
} catch (Exception e) {
Log.i("", "相机不可以用 !");
camera = null;
}
}
startVideoRecording();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mSurfaceHolder = holder;
}
public void surfaceDestroyed(SurfaceHolder holder) {
mSurfaceHolder = null;
}
RandomAccessFile raf = null;
public void writeH264() {
try {
Log.i("", "writeH264----");
File file = new File("/sdcard/stream.h264");
if (file.exists())
file.delete();
raf = new RandomAccessFile(file, "rw");
} catch (Exception ex) {
Log.v("System.out", ex.toString());
}
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.stop:
stopVideoRecording();
break;
default:
break;
}
}
}