您的位置:首页 > 移动开发 > Android开发

基于Android的远程视频监控系统(含源码)

2014-05-07 10:26 309 查看
基本过程是android作为socket客户端将采集到的每一帧图像数据发送出去,PC作为服务器接收并显示每一帧图像实现远程监控。图片如下(后来PC端加了个拍照功能)。。。



(PS。刚学android和java不久很多东西还不懂,高手若是知道哪些地方可以继续优化的话还请多多指点下啊)

系统代码如下:

一、android手机客户端

(1)AndroidManifest.xml文件。添加camera和socket权限,并设置了程序开始执行的activity、

查看源码

打印?

01
<?
xml

version
=
"1.0"

encoding
=
"utf-8"
?>
02
<
manifest

xmlns:android
=
"http://schemas.android.com/apk/res/android"
03
package
=
"org.wanghai.CameraTest"
04
android:versionCode
=
"1"
05
android:versionName
=
"1.0"

>
06
07
<
uses-sdk

android:minSdkVersion
=
"15"

/>
08
09
<!--授予程序使用摄像头的权限-->
10
<
uses-permission

android:name
=
"android.permission.CAMERA"

/>
11
<
uses-feature

android:name
=
"android.hardware.camera"

/>
12
<
uses-feature

android:name
=
"android.hardware.camera.autofocus"

/>
13
<
uses-permission

android:name
=
"android.permission.INTERNET"
/>
14
<
uses-permission

android:name
=
"android.permission.KILL_BACKGROUND_PROCESSES"
/>
15
<
uses-permission

android:name
=
"android.permission.RESTART_PACKAGES"
/>
16
17
<
application
18
android:icon
=
"@drawable/ic_launcher"
19
android:label
=
"@string/app_name"

>
20
21
<
activity
22
android:name
=
".GetIP"
23
android:screenOrientation
=
"landscape"
24
android:label
=
"@string/app_name"

>
25
<
intent-filter
>
26
<
action

android:name
=
"android.intent.action.MAIN"

/>
27
<
category

android:name
=
"android.intent.category.LAUNCHER"

/>
28
</
intent-filter
>
29
</
activity
>
30
<
activity
31
android:name
=
".CameraTest"
32
android:screenOrientation
=
"landscape"
33
android:label
=
"@string/app_name"

>
34
35
</
activity
>
36
37
</
application
>
38
39
</
manifest
>
40
41
(2)main.xml设置surfaceview用于摄像头采集图像的预览
42
?
43
<?
xml

version
=
"1.0"

encoding
=
"utf-8"
?>
44
<
LinearLayout

xmlns:android
=
"http://schemas.android.com/apk/res/android"
45
android:layout_width
=
"fill_parent"
46
android:layout_height
=
"fill_parent"
47
android:orientation
=
"vertical"

>
48
49
<
SurfaceView
50
android:id
=
"@+id/sView"
51
android:layout_width
=
"fill_parent"
52
android:layout_height
=
"fill_parent"
53
android:scaleType
=
"fitCenter"
/>
54
55
</
LinearLayout
>
56
57
(3)login.xml登录界面,用于输入服务器IP
58
?
59
<?
xml

version
=
"1.0"

encoding
=
"utf-8"
?>
60
<
TableLayout

xmlns:android
=
"http://schemas.android.com/apk/res/android"
61
android:id
=
"@+id/loginForm"
62
android:orientation
=
"vertical"
63
android:layout_width
=
"fill_parent"
64
android:layout_height
=
"fill_parent"
65
>
66
67
<
TableRow
>
68
<
TextView
69
android:layout_width
=
"fill_parent"
70
android:layout_height
=
"wrap_content"
71
android:text
=
"IP:"
72
android:textSize
=
"10pt"
73
/>
74
<!--输入用户名的文本框-->
75
<
EditText
76
android:id
=
"@+id/ipedittext"
77
android:layout_width
=
"fill_parent"
78
android:layout_height
=
"wrap_content"
79
android:digits
=
"0123456789."
80
android:hint
=
"请填写服务器IP"
81
android:selectAllOnFocus
=
"true"
82
/>
83
</
TableRow
>
84
85
</
TableLayout
>
查看源码

打印?

001
4
)GetIP.java获得服务器IP后,通过Intent启动CameraTest的activity,ip信息通过Bundle传递
002
?
003
public
class
GetIP
extends

Activity{
004
Stringipname=
null
;
005
@Override
006
public

void
onCreate(BundlesavedInstanceState){
007
super
.onCreate(savedInstanceState);
008
//设置全屏
009
requestWindowFeature(Window.FEATURE_NO_TITLE);
010
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
011
setContentView(R.layout.main);
012
013
final

Builderbuilder=
new

AlertDialog.Builder(
this
);
//定义一个AlertDialog.Builder对象
014
builder.setTitle(
"登录服务器对话框"
);
//设置对话框的标题
015
016
//装载/res/layout/login.xml界面布局
017
TableLayoutloginForm=(TableLayout)getLayoutInflater().inflate(R.layout.login,
null
);
018
final

EditTextiptext=(EditText)loginForm.findViewById(R.id.ipedittext);
019
builder.setView(loginForm);
//设置对话框显示的View对象
020
//为对话框设置一个“登录”按钮
021
builder.setPositiveButton(
"登录"
022
//为按钮设置监听器
023
,
new
OnClickListener(){
024
@Override
025
public

void
onClick(DialogInterfacedialog,
int
which){

026
//此处可执行登录处理
027
ipname=iptext.getText().toString().trim();
028
Bundledata=
new
Bundle();

029
data.putString(
"ipname"
,ipname);
030
Intentintent=
new
Intent(GetIP.
this
,CameraTest.
class
);
031
intent.putExtras(data);
032
startActivity(intent);
033
}
034
});
035
//为对话框设置一个“取消”按钮
036
builder.setNegativeButton(
"取消"
037
,
new
OnClickListener()
038
{
039
@Override
040
public

void
onClick(DialogInterfacedialog,
int
which)

041
{
042
//取消登录,不做任何事情。
043
System.exit(
1
);
044
}
045
});
046
//创建、并显示对话框
047
builder.create().show();
048
}
049
}
050
051
5
)CameraTest.java程序主体。设置PreviewCallback后,每当一帧图像数据采集完成后将调用PreviewCallback的onPreviewFrame函数。在这里我们将YUV格式数据转为jpg,再启用线程将数据通过socket发送出去。
052
?
053
public
class
CameraTest
extends

Activity{
054
SurfaceViewsView;
055
SurfaceHoldersurfaceHolder;
056
int

screenWidth,screenHeight;
057
Cameracamera;
//定义系统所用的照相机
058
boolean

isPreview=
false
;
//是否在浏览中
059
private

Stringipname;
060
061
@SuppressWarnings
(
"deprecation"
)
062
@Override
063
public

void
onCreate(BundlesavedInstanceState){
064
super
.onCreate(savedInstanceState);
065
//设置全屏
066
requestWindowFeature(Window.FEATURE_NO_TITLE);
067
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
068
setContentView(R.layout.main);
069
070
//获取IP地址
071
Intentintent=getIntent();
072
Bundledata=intent.getExtras();
073
ipname=data.getString(
"ipname"
);
074
075
screenWidth=
640
;
076
screenHeight=
480
;
077
sView=(SurfaceView)findViewById(R.id.sView);
//获取界面中SurfaceView组件
078
surfaceHolder=sView.getHolder();
//获得SurfaceView的SurfaceHolder
079
080
//为surfaceHolder添加一个回调监听器
081
surfaceHolder.addCallback(
new

Callback(){
082
@Override
083
public

void
surfaceChanged(SurfaceHolderholder,
int
format,

int
width,
int

height){
084
}
085
@Override
086
public

void
surfaceCreated(SurfaceHolderholder){
087
initCamera();
//打开摄像头
088
}
089
@Override
090
public

void
surfaceDestroyed(SurfaceHolderholder){
091
//如果camera不为null,释放摄像头
092
if

(camera!=
null
){
093
if

(isPreview)
094
camera.stopPreview();
095
camera.release();
096
camera=
null
;
097
}
098
System.exit(
0
);
099
}
100
});
101
//设置该SurfaceView自己不维护缓冲
102
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
103
104
}

105
106
private

void
initCamera(){

107
if

(!isPreview){
108
camera=Camera.open();
109
}
110
if

(camera!=
null

&&!isPreview){
111
try
{
112
Camera.Parametersparameters=camera.getParameters();
113
parameters.setPreviewSize(screenWidth,screenHeight);
//设置预览照片的大小

114
parameters.setPreviewFpsRange(
20
,
30
);
//每秒显示20~30帧

115
parameters.setPictureFormat(ImageFormat.NV21);
//设置图片格式

116
parameters.setPictureSize(screenWidth,screenHeight);
//设置照片的大小
117
//camera.setParameters(parameters);//android2.3.3以后不需要此行代码
118
camera.setPreviewDisplay(surfaceHolder);
//通过SurfaceView显示取景画面
119
camera.setPreviewCallback(
new

StreamIt(ipname));
//设置回调的类
120
camera.startPreview();
//开始预览

121
camera.autoFocus(
null
);
//自动对焦
122
}
catch
(Exceptione){
123
e.printStackTrace();
124
}
125
isPreview=
true
;
126
}
127
}

128
129
}
130
131
class

StreamIt
implements

Camera.PreviewCallback{
132
private

Stringipname;
133
public

StreamIt(Stringipname){
134
this
.ipname=ipname;
135
}
136
137
@Override
138
public

void
onPreviewFrame(
byte
[]data,Cameracamera){
139
Sizesize=camera.getParameters().getPreviewSize();
140
try
{
141
//调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
142
YuvImageimage=
new
YuvImage(data,ImageFormat.NV21,size.width,size.height,
null
);

143
if
(image!=
null
){
144
ByteArrayOutputStreamoutstream=
new
ByteArrayOutputStream();
145
image.compressToJpeg(
new

Rect(
0
,
0
,size.width,size.height),
80
,outstream);

146
outstream.flush();
147
//启用线程将图像数据发送出去
148
Threadth=
new
MyThread(outstream,ipname);
149
th.start();
150
}
151
}
catch
(Exceptionex){
152
Log.e(
"Sys"
,
"Error:"
+ex.getMessage());
153
}
154
}

155
}
156
157
class

MyThread
extends

Thread{
158
private

byte
byteBuffer[]=

new
byte
[
1024
];
159
private

OutputStreamoutsocket;
160
private

ByteArrayOutputStreammyoutputstream;
161
private

Stringipname;
162
163
public

MyThread(ByteArrayOutputStreammyoutputstream,Stringipname){
164
this
.myoutputstream=myoutputstream;
165
this
.ipname=ipname;
166
try

{
167
myoutputstream.close();
168
}
catch
(IOExceptione){
169
e.printStackTrace();
170
}
171
}
172
173
public

void
run(){
174
try
{
175
//将图像数据通过Socket发送出去
176
SockettempSocket=
new
Socket(ipname,
6000
);
177
outsocket=tempSocket.getOutputStream();
178
ByteArrayInputStreaminputstream=
new
ByteArrayInputStream(myoutputstream.toByteArray());
179
int

amount;
180
while

((amount=inputstream.read(byteBuffer))!=-
1
){
181
outsocket.write(byteBuffer,
0
,amount);

182
}
183
myoutputstream.flush();
184
myoutputstream.close();
185
tempSocket.close();
186
}
catch
(IOExceptione){
187
e.printStackTrace();
188
}
189
}

190
191
}
192
193
二、PC服务器端
194
ImageServer.java用于显示图像,并且可以拍照

195
?
196
public
class
ImageServer{
197
public

static
ServerSocketss=
null
;
198
199
public

static
void

main(Stringargs[])
throws

IOException{
200
ss=
new
ServerSocket(
6000
);
201
202
final

ImageFrameframe=
new

ImageFrame(ss);
203
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
204
frame.setVisible(
true
);
205
206
while
(
true
){
207
frame.panel.getimage();
208
frame.repaint();
209
}
210
}

211
212
}
213
214
/**
215
Aframewithanimagepanel
216
*/
217
@SuppressWarnings
(
"serial"
)
218
class

ImageFrame
extends

JFrame{
219
public

ImagePanelpanel;
220
public

JButtonjb;
221
222
public

ImageFrame(ServerSocketss){
223
//getscreendimensions
224
Toolkitkit=Toolkit.getDefaultToolkit();
225
DimensionscreenSize=kit.getScreenSize();
226
int

screenHeight=screenSize.height;
227
int

screenWidth=screenSize.width;
228
229
//centerframeinscreen
230
setTitle(
"ImageTest"
);
231
setLocation((screenWidth-DEFAULT_WIDTH)/
2
,(screenHeight-DEFAULT_HEIGHT)/
2
);
232
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
233
234
//addpaneltoframe
235
this
.getContentPane().setLayout(
null
);
236
panel=
new
ImagePanel(ss);
237
panel.setSize(
640
,
480
);
238
panel.setLocation(
0
,
0
);
239
add(panel);
240
jb=
new
JButton(
"拍照"
);
241
jb.setBounds(
0
,
480
,
640
,
50
);
242
add(jb);
243
saveimagesaveaction=
new
saveimage(ss);
244
jb.addActionListener(saveaction);
245
}

246
247
public

static
final
int
DEFAULT_WIDTH=
640
;
248
public

static
final
int
DEFAULT_HEIGHT=
560
;
249
}
250
251
/**
252
Apanelthatdisplaysatiledimage
253
*/
254
@SuppressWarnings
(
"serial"
)
255
class

ImagePanel
extends

JPanel{
256
private

ServerSocketss;
257
private

Imageimage;
258
private

InputStreamins;
259
260
public

ImagePanel(ServerSocketss){
261
this
.ss=ss;
262
}

263
264
public

void
getimage()

throws
IOException{

265
Sockets=
this
.ss.accept();
266
System.out.println(
"连接成功!"
);
267
this
.ins=s.getInputStream();
268
this
.image=ImageIO.read(ins);
269
this
.ins.close();
270
}

271
272
public

void
paintComponent(Graphicsg){
273
super
.paintComponent(g);
274
if

(image==
null
)
return
;

275
g.drawImage(image,
0
,
0
,
null
);
276
}

277
278
}
279
280
class

saveimage
implements

ActionListener{
281
RandomAccessFileinFile=
null
;
282
byte

byteBuffer[]=
new

byte
[
1024
];
283
InputStreamins;
284
private

ServerSocketss;
285
286
public

saveimage(ServerSocketss){
287
this
.ss=ss;
288
}
289
290
public

void
actionPerformed(ActionEventevent){
291
try

{
292
Sockets=ss.accept();
293
ins=s.getInputStream();
294
295
//文件选择器以当前的目录打开
296
JFileChooserjfc=
new
JFileChooser(
"."
);
297
jfc.showSaveDialog(
new

javax.swing.JFrame());
298
//获取当前的选择文件引用
299
FilesavedFile=jfc.getSelectedFile();
300
301
//已经选择了文件
302
if

(savedFile!=
null
){
303
//读取文件的数据,可以每次以快的方式读取数据
304
try

{
305
inFile=
new
RandomAccessFile(savedFile,
"rw"
);
306
}
catch
(FileNotFoundExceptione){
307
e.printStackTrace();
308
}
309
}
310
311
int

amount;
312
while

((amount=ins.read(byteBuffer))!=-
1
){
313
inFile.write(byteBuffer,
0
,amount);

314
}
315
inFile.close();
316
ins.close();
317
s.close();
318
javax.swing.JOptionPane.showMessageDialog(
new

javax.swing.JFrame(),
319
"已接保存成功"
,
"提示!"
,javax.swing.JOptionPane.PLAIN_MESSAGE);
320
}
catch
(IOExceptione){
321
322
e.printStackTrace();
323
}
324
}
325
}
开放源码如下(android我使用的是4.03的SDK,其它版本请自行更改。2.3.3版本以下的请注意initCamera()里被注释掉的哪一行)

只能在android4.04系统的手机上运行成功哦。

下面是测试成功时的启动画面:




android_video.rar

转自:http://www.cnblogs.com/feifei1010/archive/2012/08/31/2664939.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: