├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── LICENSE
├── README.md
├── libs
├── android-support-v4.jar
├── commons-lang3-3.3.2.jar
└── core.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ ├── ic_1.png
│ ├── ic_3.png
│ ├── ic_4.png
│ ├── ic_launcher.png
│ └── main.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── layout
│ ├── activity.xml
│ ├── info.xml
│ ├── main.xml
│ └── match.xml
├── values-zh
│ └── strings.xml
└── values
│ ├── color.xml
│ ├── dimens.xml
│ └── strings.xml
└── src
└── tw
└── jwzhuang
└── ipcam
├── IPCam.java
├── InfoService.java
├── IntentType.java
├── MenuClickedListener.java
├── MyApplication.java
├── RecordService.java
├── Utils.java
├── h264
├── H264Header.java
├── H264Protocol.java
├── ParcelableByteArray.aidl
└── ParcelableByteArray.java
├── qrcode
├── Match.java
└── QRCodeEncoder.java
└── server
├── SocketServer.java
├── StreamServer.java
└── WorkerRunnable.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | H264Stream
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/=UTF-8
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.7
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.7
12 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
46 |
47 |
50 |
51 |
52 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 2.1, February 1999
3 |
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | (This is the first released version of the Lesser GPL. It also counts
10 | as the successor of the GNU Library Public License, version 2, hence
11 | the version number 2.1.)
12 |
13 | Preamble
14 |
15 | The licenses for most software are designed to take away your
16 | freedom to share and change it. By contrast, the GNU General Public
17 | Licenses are intended to guarantee your freedom to share and change
18 | free software--to make sure the software is free for all its users.
19 |
20 | This license, the Lesser General Public License, applies to some
21 | specially designated software packages--typically libraries--of the
22 | Free Software Foundation and other authors who decide to use it. You
23 | can use it too, but we suggest you first think carefully about whether
24 | this license or the ordinary General Public License is the better
25 | strategy to use in any particular case, based on the explanations below.
26 |
27 | When we speak of free software, we are referring to freedom of use,
28 | not price. Our General Public Licenses are designed to make sure that
29 | you have the freedom to distribute copies of free software (and charge
30 | for this service if you wish); that you receive source code or can get
31 | it if you want it; that you can change the software and use pieces of
32 | it in new free programs; and that you are informed that you can do
33 | these things.
34 |
35 | To protect your rights, we need to make restrictions that forbid
36 | distributors to deny you these rights or to ask you to surrender these
37 | rights. These restrictions translate to certain responsibilities for
38 | you if you distribute copies of the library or if you modify it.
39 |
40 | For example, if you distribute copies of the library, whether gratis
41 | or for a fee, you must give the recipients all the rights that we gave
42 | you. You must make sure that they, too, receive or can get the source
43 | code. If you link other code with the library, you must provide
44 | complete object files to the recipients, so that they can relink them
45 | with the library after making changes to the library and recompiling
46 | it. And you must show them these terms so they know their rights.
47 |
48 | We protect your rights with a two-step method: (1) we copyright the
49 | library, and (2) we offer you this license, which gives you legal
50 | permission to copy, distribute and/or modify the library.
51 |
52 | To protect each distributor, we want to make it very clear that
53 | there is no warranty for the free library. Also, if the library is
54 | modified by someone else and passed on, the recipients should know
55 | that what they have is not the original version, so that the original
56 | author's reputation will not be affected by problems that might be
57 | introduced by others.
58 |
59 | Finally, software patents pose a constant threat to the existence of
60 | any free program. We wish to make sure that a company cannot
61 | effectively restrict the users of a free program by obtaining a
62 | restrictive license from a patent holder. Therefore, we insist that
63 | any patent license obtained for a version of the library must be
64 | consistent with the full freedom of use specified in this license.
65 |
66 | Most GNU software, including some libraries, is covered by the
67 | ordinary GNU General Public License. This license, the GNU Lesser
68 | General Public License, applies to certain designated libraries, and
69 | is quite different from the ordinary General Public License. We use
70 | this license for certain libraries in order to permit linking those
71 | libraries into non-free programs.
72 |
73 | When a program is linked with a library, whether statically or using
74 | a shared library, the combination of the two is legally speaking a
75 | combined work, a derivative of the original library. The ordinary
76 | General Public License therefore permits such linking only if the
77 | entire combination fits its criteria of freedom. The Lesser General
78 | Public License permits more lax criteria for linking other code with
79 | the library.
80 |
81 | We call this license the "Lesser" General Public License because it
82 | does Less to protect the user's freedom than the ordinary General
83 | Public License. It also provides other free software developers Less
84 | of an advantage over competing non-free programs. These disadvantages
85 | are the reason we use the ordinary General Public License for many
86 | libraries. However, the Lesser license provides advantages in certain
87 | special circumstances.
88 |
89 | For example, on rare occasions, there may be a special need to
90 | encourage the widest possible use of a certain library, so that it becomes
91 | a de-facto standard. To achieve this, non-free programs must be
92 | allowed to use the library. A more frequent case is that a free
93 | library does the same job as widely used non-free libraries. In this
94 | case, there is little to gain by limiting the free library to free
95 | software only, so we use the Lesser General Public License.
96 |
97 | In other cases, permission to use a particular library in non-free
98 | programs enables a greater number of people to use a large body of
99 | free software. For example, permission to use the GNU C Library in
100 | non-free programs enables many more people to use the whole GNU
101 | operating system, as well as its variant, the GNU/Linux operating
102 | system.
103 |
104 | Although the Lesser General Public License is Less protective of the
105 | users' freedom, it does ensure that the user of a program that is
106 | linked with the Library has the freedom and the wherewithal to run
107 | that program using a modified version of the Library.
108 |
109 | The precise terms and conditions for copying, distribution and
110 | modification follow. Pay close attention to the difference between a
111 | "work based on the library" and a "work that uses the library". The
112 | former contains code derived from the library, whereas the latter must
113 | be combined with the library in order to run.
114 |
115 | GNU LESSER GENERAL PUBLIC LICENSE
116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117 |
118 | 0. This License Agreement applies to any software library or other
119 | program which contains a notice placed by the copyright holder or
120 | other authorized party saying it may be distributed under the terms of
121 | this Lesser General Public License (also called "this License").
122 | Each licensee is addressed as "you".
123 |
124 | A "library" means a collection of software functions and/or data
125 | prepared so as to be conveniently linked with application programs
126 | (which use some of those functions and data) to form executables.
127 |
128 | The "Library", below, refers to any such software library or work
129 | which has been distributed under these terms. A "work based on the
130 | Library" means either the Library or any derivative work under
131 | copyright law: that is to say, a work containing the Library or a
132 | portion of it, either verbatim or with modifications and/or translated
133 | straightforwardly into another language. (Hereinafter, translation is
134 | included without limitation in the term "modification".)
135 |
136 | "Source code" for a work means the preferred form of the work for
137 | making modifications to it. For a library, complete source code means
138 | all the source code for all modules it contains, plus any associated
139 | interface definition files, plus the scripts used to control compilation
140 | and installation of the library.
141 |
142 | Activities other than copying, distribution and modification are not
143 | covered by this License; they are outside its scope. The act of
144 | running a program using the Library is not restricted, and output from
145 | such a program is covered only if its contents constitute a work based
146 | on the Library (independent of the use of the Library in a tool for
147 | writing it). Whether that is true depends on what the Library does
148 | and what the program that uses the Library does.
149 |
150 | 1. You may copy and distribute verbatim copies of the Library's
151 | complete source code as you receive it, in any medium, provided that
152 | you conspicuously and appropriately publish on each copy an
153 | appropriate copyright notice and disclaimer of warranty; keep intact
154 | all the notices that refer to this License and to the absence of any
155 | warranty; and distribute a copy of this License along with the
156 | Library.
157 |
158 | You may charge a fee for the physical act of transferring a copy,
159 | and you may at your option offer warranty protection in exchange for a
160 | fee.
161 |
162 | 2. You may modify your copy or copies of the Library or any portion
163 | of it, thus forming a work based on the Library, and copy and
164 | distribute such modifications or work under the terms of Section 1
165 | above, provided that you also meet all of these conditions:
166 |
167 | a) The modified work must itself be a software library.
168 |
169 | b) You must cause the files modified to carry prominent notices
170 | stating that you changed the files and the date of any change.
171 |
172 | c) You must cause the whole of the work to be licensed at no
173 | charge to all third parties under the terms of this License.
174 |
175 | d) If a facility in the modified Library refers to a function or a
176 | table of data to be supplied by an application program that uses
177 | the facility, other than as an argument passed when the facility
178 | is invoked, then you must make a good faith effort to ensure that,
179 | in the event an application does not supply such function or
180 | table, the facility still operates, and performs whatever part of
181 | its purpose remains meaningful.
182 |
183 | (For example, a function in a library to compute square roots has
184 | a purpose that is entirely well-defined independent of the
185 | application. Therefore, Subsection 2d requires that any
186 | application-supplied function or table used by this function must
187 | be optional: if the application does not supply it, the square
188 | root function must still compute square roots.)
189 |
190 | These requirements apply to the modified work as a whole. If
191 | identifiable sections of that work are not derived from the Library,
192 | and can be reasonably considered independent and separate works in
193 | themselves, then this License, and its terms, do not apply to those
194 | sections when you distribute them as separate works. But when you
195 | distribute the same sections as part of a whole which is a work based
196 | on the Library, the distribution of the whole must be on the terms of
197 | this License, whose permissions for other licensees extend to the
198 | entire whole, and thus to each and every part regardless of who wrote
199 | it.
200 |
201 | Thus, it is not the intent of this section to claim rights or contest
202 | your rights to work written entirely by you; rather, the intent is to
203 | exercise the right to control the distribution of derivative or
204 | collective works based on the Library.
205 |
206 | In addition, mere aggregation of another work not based on the Library
207 | with the Library (or with a work based on the Library) on a volume of
208 | a storage or distribution medium does not bring the other work under
209 | the scope of this License.
210 |
211 | 3. You may opt to apply the terms of the ordinary GNU General Public
212 | License instead of this License to a given copy of the Library. To do
213 | this, you must alter all the notices that refer to this License, so
214 | that they refer to the ordinary GNU General Public License, version 2,
215 | instead of to this License. (If a newer version than version 2 of the
216 | ordinary GNU General Public License has appeared, then you can specify
217 | that version instead if you wish.) Do not make any other change in
218 | these notices.
219 |
220 | Once this change is made in a given copy, it is irreversible for
221 | that copy, so the ordinary GNU General Public License applies to all
222 | subsequent copies and derivative works made from that copy.
223 |
224 | This option is useful when you wish to copy part of the code of
225 | the Library into a program that is not a library.
226 |
227 | 4. You may copy and distribute the Library (or a portion or
228 | derivative of it, under Section 2) in object code or executable form
229 | under the terms of Sections 1 and 2 above provided that you accompany
230 | it with the complete corresponding machine-readable source code, which
231 | must be distributed under the terms of Sections 1 and 2 above on a
232 | medium customarily used for software interchange.
233 |
234 | If distribution of object code is made by offering access to copy
235 | from a designated place, then offering equivalent access to copy the
236 | source code from the same place satisfies the requirement to
237 | distribute the source code, even though third parties are not
238 | compelled to copy the source along with the object code.
239 |
240 | 5. A program that contains no derivative of any portion of the
241 | Library, but is designed to work with the Library by being compiled or
242 | linked with it, is called a "work that uses the Library". Such a
243 | work, in isolation, is not a derivative work of the Library, and
244 | therefore falls outside the scope of this License.
245 |
246 | However, linking a "work that uses the Library" with the Library
247 | creates an executable that is a derivative of the Library (because it
248 | contains portions of the Library), rather than a "work that uses the
249 | library". The executable is therefore covered by this License.
250 | Section 6 states terms for distribution of such executables.
251 |
252 | When a "work that uses the Library" uses material from a header file
253 | that is part of the Library, the object code for the work may be a
254 | derivative work of the Library even though the source code is not.
255 | Whether this is true is especially significant if the work can be
256 | linked without the Library, or if the work is itself a library. The
257 | threshold for this to be true is not precisely defined by law.
258 |
259 | If such an object file uses only numerical parameters, data
260 | structure layouts and accessors, and small macros and small inline
261 | functions (ten lines or less in length), then the use of the object
262 | file is unrestricted, regardless of whether it is legally a derivative
263 | work. (Executables containing this object code plus portions of the
264 | Library will still fall under Section 6.)
265 |
266 | Otherwise, if the work is a derivative of the Library, you may
267 | distribute the object code for the work under the terms of Section 6.
268 | Any executables containing that work also fall under Section 6,
269 | whether or not they are linked directly with the Library itself.
270 |
271 | 6. As an exception to the Sections above, you may also combine or
272 | link a "work that uses the Library" with the Library to produce a
273 | work containing portions of the Library, and distribute that work
274 | under terms of your choice, provided that the terms permit
275 | modification of the work for the customer's own use and reverse
276 | engineering for debugging such modifications.
277 |
278 | You must give prominent notice with each copy of the work that the
279 | Library is used in it and that the Library and its use are covered by
280 | this License. You must supply a copy of this License. If the work
281 | during execution displays copyright notices, you must include the
282 | copyright notice for the Library among them, as well as a reference
283 | directing the user to the copy of this License. Also, you must do one
284 | of these things:
285 |
286 | a) Accompany the work with the complete corresponding
287 | machine-readable source code for the Library including whatever
288 | changes were used in the work (which must be distributed under
289 | Sections 1 and 2 above); and, if the work is an executable linked
290 | with the Library, with the complete machine-readable "work that
291 | uses the Library", as object code and/or source code, so that the
292 | user can modify the Library and then relink to produce a modified
293 | executable containing the modified Library. (It is understood
294 | that the user who changes the contents of definitions files in the
295 | Library will not necessarily be able to recompile the application
296 | to use the modified definitions.)
297 |
298 | b) Use a suitable shared library mechanism for linking with the
299 | Library. A suitable mechanism is one that (1) uses at run time a
300 | copy of the library already present on the user's computer system,
301 | rather than copying library functions into the executable, and (2)
302 | will operate properly with a modified version of the library, if
303 | the user installs one, as long as the modified version is
304 | interface-compatible with the version that the work was made with.
305 |
306 | c) Accompany the work with a written offer, valid for at
307 | least three years, to give the same user the materials
308 | specified in Subsection 6a, above, for a charge no more
309 | than the cost of performing this distribution.
310 |
311 | d) If distribution of the work is made by offering access to copy
312 | from a designated place, offer equivalent access to copy the above
313 | specified materials from the same place.
314 |
315 | e) Verify that the user has already received a copy of these
316 | materials or that you have already sent this user a copy.
317 |
318 | For an executable, the required form of the "work that uses the
319 | Library" must include any data and utility programs needed for
320 | reproducing the executable from it. However, as a special exception,
321 | the materials to be distributed need not include anything that is
322 | normally distributed (in either source or binary form) with the major
323 | components (compiler, kernel, and so on) of the operating system on
324 | which the executable runs, unless that component itself accompanies
325 | the executable.
326 |
327 | It may happen that this requirement contradicts the license
328 | restrictions of other proprietary libraries that do not normally
329 | accompany the operating system. Such a contradiction means you cannot
330 | use both them and the Library together in an executable that you
331 | distribute.
332 |
333 | 7. You may place library facilities that are a work based on the
334 | Library side-by-side in a single library together with other library
335 | facilities not covered by this License, and distribute such a combined
336 | library, provided that the separate distribution of the work based on
337 | the Library and of the other library facilities is otherwise
338 | permitted, and provided that you do these two things:
339 |
340 | a) Accompany the combined library with a copy of the same work
341 | based on the Library, uncombined with any other library
342 | facilities. This must be distributed under the terms of the
343 | Sections above.
344 |
345 | b) Give prominent notice with the combined library of the fact
346 | that part of it is a work based on the Library, and explaining
347 | where to find the accompanying uncombined form of the same work.
348 |
349 | 8. You may not copy, modify, sublicense, link with, or distribute
350 | the Library except as expressly provided under this License. Any
351 | attempt otherwise to copy, modify, sublicense, link with, or
352 | distribute the Library is void, and will automatically terminate your
353 | rights under this License. However, parties who have received copies,
354 | or rights, from you under this License will not have their licenses
355 | terminated so long as such parties remain in full compliance.
356 |
357 | 9. You are not required to accept this License, since you have not
358 | signed it. However, nothing else grants you permission to modify or
359 | distribute the Library or its derivative works. These actions are
360 | prohibited by law if you do not accept this License. Therefore, by
361 | modifying or distributing the Library (or any work based on the
362 | Library), you indicate your acceptance of this License to do so, and
363 | all its terms and conditions for copying, distributing or modifying
364 | the Library or works based on it.
365 |
366 | 10. Each time you redistribute the Library (or any work based on the
367 | Library), the recipient automatically receives a license from the
368 | original licensor to copy, distribute, link with or modify the Library
369 | subject to these terms and conditions. You may not impose any further
370 | restrictions on the recipients' exercise of the rights granted herein.
371 | You are not responsible for enforcing compliance by third parties with
372 | this License.
373 |
374 | 11. If, as a consequence of a court judgment or allegation of patent
375 | infringement or for any other reason (not limited to patent issues),
376 | conditions are imposed on you (whether by court order, agreement or
377 | otherwise) that contradict the conditions of this License, they do not
378 | excuse you from the conditions of this License. If you cannot
379 | distribute so as to satisfy simultaneously your obligations under this
380 | License and any other pertinent obligations, then as a consequence you
381 | may not distribute the Library at all. For example, if a patent
382 | license would not permit royalty-free redistribution of the Library by
383 | all those who receive copies directly or indirectly through you, then
384 | the only way you could satisfy both it and this License would be to
385 | refrain entirely from distribution of the Library.
386 |
387 | If any portion of this section is held invalid or unenforceable under any
388 | particular circumstance, the balance of the section is intended to apply,
389 | and the section as a whole is intended to apply in other circumstances.
390 |
391 | It is not the purpose of this section to induce you to infringe any
392 | patents or other property right claims or to contest validity of any
393 | such claims; this section has the sole purpose of protecting the
394 | integrity of the free software distribution system which is
395 | implemented by public license practices. Many people have made
396 | generous contributions to the wide range of software distributed
397 | through that system in reliance on consistent application of that
398 | system; it is up to the author/donor to decide if he or she is willing
399 | to distribute software through any other system and a licensee cannot
400 | impose that choice.
401 |
402 | This section is intended to make thoroughly clear what is believed to
403 | be a consequence of the rest of this License.
404 |
405 | 12. If the distribution and/or use of the Library is restricted in
406 | certain countries either by patents or by copyrighted interfaces, the
407 | original copyright holder who places the Library under this License may add
408 | an explicit geographical distribution limitation excluding those countries,
409 | so that distribution is permitted only in or among countries not thus
410 | excluded. In such case, this License incorporates the limitation as if
411 | written in the body of this License.
412 |
413 | 13. The Free Software Foundation may publish revised and/or new
414 | versions of the Lesser General Public License from time to time.
415 | Such new versions will be similar in spirit to the present version,
416 | but may differ in detail to address new problems or concerns.
417 |
418 | Each version is given a distinguishing version number. If the Library
419 | specifies a version number of this License which applies to it and
420 | "any later version", you have the option of following the terms and
421 | conditions either of that version or of any later version published by
422 | the Free Software Foundation. If the Library does not specify a
423 | license version number, you may choose any version ever published by
424 | the Free Software Foundation.
425 |
426 | 14. If you wish to incorporate parts of the Library into other free
427 | programs whose distribution conditions are incompatible with these,
428 | write to the author to ask for permission. For software which is
429 | copyrighted by the Free Software Foundation, write to the Free
430 | Software Foundation; we sometimes make exceptions for this. Our
431 | decision will be guided by the two goals of preserving the free status
432 | of all derivatives of our free software and of promoting the sharing
433 | and reuse of software generally.
434 |
435 | NO WARRANTY
436 |
437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446 |
447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456 | DAMAGES.
457 |
458 | END OF TERMS AND CONDITIONS
459 |
460 | How to Apply These Terms to Your New Libraries
461 |
462 | If you develop a new library, and you want it to be of the greatest
463 | possible use to the public, we recommend making it free software that
464 | everyone can redistribute and change. You can do so by permitting
465 | redistribution under these terms (or, alternatively, under the terms of the
466 | ordinary General Public License).
467 |
468 | To apply these terms, attach the following notices to the library. It is
469 | safest to attach them to the start of each source file to most effectively
470 | convey the exclusion of warranty; and each file should have at least the
471 | "copyright" line and a pointer to where the full notice is found.
472 |
473 | {description}
474 | Copyright (C) {year} {fullname}
475 |
476 | This library is free software; you can redistribute it and/or
477 | modify it under the terms of the GNU Lesser General Public
478 | License as published by the Free Software Foundation; either
479 | version 2.1 of the License, or (at your option) any later version.
480 |
481 | This library is distributed in the hope that it will be useful,
482 | but WITHOUT ANY WARRANTY; without even the implied warranty of
483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 | Lesser General Public License for more details.
485 |
486 | You should have received a copy of the GNU Lesser General Public
487 | License along with this library; if not, write to the Free Software
488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
489 | USA
490 |
491 | Also add information on how to contact you by electronic and paper mail.
492 |
493 | You should also get your employer (if you work as a programmer) or your
494 | school, if any, to sign a "copyright disclaimer" for the library, if
495 | necessary. Here is a sample; alter the names:
496 |
497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the
498 | library `Frob' (a library for tweaking knobs) written by James Random
499 | Hacker.
500 |
501 | {signature of Ty Coon}, 1 April 1990
502 | Ty Coon, President of Vice
503 |
504 | That's all there is to it!
505 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | H264Stream
2 | ==========
3 |
4 | Sent H264 Stream to H264Viewer
5 |
6 | This app is write in nexus5 + android 4.x
7 |
8 | Not test on andorid 5.x and android 6
9 |
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/libs/commons-lang3-3.3.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/libs/commons-lang3-3.3.2.jar
--------------------------------------------------------------------------------
/libs/core.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/libs/core.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library.reference.1=../satellite-menu
16 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-hdpi/ic_1.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-hdpi/ic_3.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-hdpi/ic_4.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-hdpi/main.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwzhuang/Android_H264Stream/259d92ff5ce0df477fe5d88a1dc53accc3897431/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/layout/activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
16 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/res/layout/info.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
18 |
19 |
27 |
28 |
29 |
30 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/res/layout/match.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | H264Stream
5 | 客戶端數
6 | IP 位址
7 | 再按一次離開
8 |
9 |
--------------------------------------------------------------------------------
/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFF00
4 |
5 |
6 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 | 120dip
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | H264Stream
5 | Clients
6 | IP Address
7 | Press once again to exit
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/IPCam.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import org.json.JSONException;
4 |
5 | import tw.jwzhuang.ipcam.qrcode.Match;
6 | import android.app.Activity;
7 | import android.app.ActivityManager;
8 | import android.app.ActivityManager.RunningServiceInfo;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.os.Bundle;
12 | import android.view.View;
13 | import android.widget.Toast;
14 |
15 | import com.google.zxing.WriterException;
16 |
17 | public class IPCam extends Activity {
18 |
19 | private static long back_pressed;
20 |
21 | @Override
22 | public void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity);
25 | }
26 |
27 | public void click_rec(View view) {
28 | startService(new Intent(this, RecordService.class));
29 | }
30 |
31 | public void click_qrcode(View view) throws WriterException, JSONException {
32 | startActivity(new Intent(this,Match.class));
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | }
39 |
40 | @Override
41 | public void onBackPressed() {
42 |
43 | if(!isMyServiceRunning(RecordService.class)){
44 | this.sendBroadcast(new Intent(IntentType.ExitApp));
45 | super.onBackPressed();
46 | return;
47 | }
48 |
49 | if (back_pressed + 2000 > System.currentTimeMillis()){
50 | this.sendBroadcast(new Intent(IntentType.ExitApp));
51 | super.onBackPressed();
52 | }else{
53 | Toast.makeText(getBaseContext(), R.string.pressagain,
54 | Toast.LENGTH_SHORT).show();
55 | }
56 | back_pressed = System.currentTimeMillis();
57 |
58 | }
59 |
60 | private boolean isMyServiceRunning(Class> serviceClass) {
61 | ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
62 | for (RunningServiceInfo service : manager
63 | .getRunningServices(Integer.MAX_VALUE)) {
64 | if (serviceClass.getName().equals(service.service.getClassName())) {
65 | return true;
66 | }
67 | }
68 | return false;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/InfoService.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import java.lang.ref.WeakReference;
4 |
5 | import android.app.Service;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.graphics.PixelFormat;
11 | import android.os.Handler;
12 | import android.os.IBinder;
13 | import android.os.Message;
14 | import android.view.Gravity;
15 | import android.view.LayoutInflater;
16 | import android.view.View;
17 | import android.view.WindowManager;
18 | import android.widget.TextView;
19 |
20 | public class InfoService extends Service {
21 |
22 | private WindowManager wm = null;
23 | private WindowManager.LayoutParams wmParams = null;
24 | private View view;
25 | private BroadcastReceiver m_br = null;
26 | private InfoHandler infoHandler = new InfoHandler(this);
27 | private int startId = -1;
28 | private TextView clients_tx = null;
29 | private TextView ip_tx = null;
30 |
31 | @Override
32 | public void onCreate() {
33 | super.onCreate();
34 | view = LayoutInflater.from(this).inflate(R.layout.info, null);
35 | clients_tx = (TextView) view.findViewById(R.id.clients_tx);
36 | ip_tx = (TextView) view.findViewById(R.id.ip_tx);
37 | ip_tx.setText(Utils.getLocalIpAddress());
38 | createView();
39 | }
40 |
41 | private void createView() {
42 | // 获取WindowManager
43 | wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
44 |
45 | // 设置LayoutParams(全局变量)相关参数
46 | wmParams = ((MyApplication) getApplication()).getMywmParams();
47 | wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
48 | wmParams.flags |= WindowManager.LayoutParams.FORMAT_CHANGED;
49 | wmParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
50 | wmParams.gravity = Gravity.LEFT | Gravity.TOP; // 调整悬浮窗口至左上角
51 | // wmParams.gravity = Gravity.LEFT | Gravity.CENTER; // 调整悬浮窗口至左上角
52 | // 以屏幕左上角为原点,设置x、y初始值
53 | wmParams.x = 0;
54 | // 设置悬浮窗口长宽数据
55 | wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
56 | wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
57 | wmParams.format = PixelFormat.RGBA_8888;
58 | wm.addView(view, wmParams);
59 | // view.setVisibility(View.GONE);
60 | }
61 |
62 | @Override
63 | public int onStartCommand(Intent intent, int flags, int startId) {
64 | if(this.startId > -1){
65 | stopSelf(this.startId);
66 | }
67 | this.startId = startId;
68 | _RegisterReceiver();
69 | sendBroadcast(new Intent(IntentType.ClientInfo));
70 | return super.onStartCommand(intent, Service.START_STICKY, startId);
71 | }
72 |
73 | @Override
74 | public void onDestroy() {
75 | if (m_br != null) {
76 | unregisterReceiver(m_br);
77 | m_br = null;
78 | }
79 |
80 | wm.removeView(view);
81 | android.os.Process.killProcess(android.os.Process.myPid());
82 | super.onDestroy();
83 | }
84 |
85 |
86 | @Override
87 | public IBinder onBind(Intent intent) {
88 | return null;
89 | }
90 |
91 | /**
92 | * 註冊動態Receiver
93 | */
94 | private void _RegisterReceiver() {
95 | m_br = new BroadcastReceiver() {
96 | @Override
97 | public void onReceive(Context context, Intent intent) {
98 | String strAction = intent.getAction();
99 | Message msg = Message.obtain();
100 | if(strAction.equals(IntentType.ExitApp) || strAction.equals(IntentType.ExitClientInfo)){
101 | msg.obj = CMD.EXITAPP;
102 | }else if(strAction.equals(IntentType.NewClient)){
103 | msg.obj = CMD.NEWCLIENT;
104 | msg.arg1 = intent.getExtras().getInt("clients");
105 | }
106 | infoHandler.sendMessage(msg);
107 | }
108 | };
109 |
110 | IntentFilter filter = new IntentFilter();
111 | filter.addAction(IntentType.NewClient);
112 | filter.addAction(IntentType.ExitApp);
113 | filter.addAction(IntentType.ExitClientInfo);
114 | registerReceiver(m_br, filter, null, null);
115 | }
116 |
117 | private static class InfoHandler extends Handler{
118 | WeakReference srv;
119 |
120 | public InfoHandler(InfoService srv){
121 | this.srv = new WeakReference(srv);
122 | }
123 |
124 | @Override
125 | public void handleMessage(Message msg) {
126 | super.handleMessage(msg);
127 |
128 | InfoService s = srv.get();
129 |
130 | switch((CMD) msg.obj){
131 | case EXITAPP:
132 | s.stopSelf(s.startId);
133 | break;
134 | case NEWCLIENT:
135 | s.clients_tx.setText(String.valueOf(msg.arg1));
136 | break;
137 | default:
138 | break;
139 | }
140 | }
141 |
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/IntentType.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 |
4 | enum CMD {
5 | EXITAPP, NEWCLIENT, CLIENTINFO, EXITCLIENTINFO
6 | }
7 |
8 | public class IntentType {
9 | public final static String ExitApp = IntentType.class.getName() + ".ExitApp";
10 | public final static String ClientInfo = IntentType.class.getName() + ".ClientInfo";
11 | public final static String NewClient = IntentType.class.getName() + ".NewClient";
12 | public final static String ExitClientInfo = IntentType.class.getName() + ".ExitClientInfo";
13 | public final static String Hide = IntentType.class.getName() + ".Hide";
14 | }
15 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/MenuClickedListener.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.view.ext.SatelliteMenu.SateliteClickedListener;
6 |
7 | public class MenuClickedListener implements SateliteClickedListener {
8 | private Context context = null;
9 | private boolean showedInfo = false;
10 | private boolean write_file = false;
11 |
12 | public MenuClickedListener(Context c) {
13 | context = c;
14 | }
15 |
16 | @Override
17 | public void eventOccured(int id) {
18 | switch(id){
19 | case 0:
20 | context.sendBroadcast(new Intent(IntentType.ExitApp));
21 | break;
22 | case 1:
23 | if(showedInfo){
24 | showedInfo = false;
25 | context.sendBroadcast(new Intent(IntentType.ExitClientInfo));
26 | break;
27 | }
28 | showedInfo = true;
29 | context.startService(new Intent(context, InfoService.class));
30 | break;
31 | case 2:
32 | if(write_file){
33 | write_file = false;
34 | }else{
35 | write_file = true;
36 | }
37 | ((RecordService)context).startCacheBuf_WriteFile(write_file);
38 | break;
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/MyApplication.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.app.Activity;
7 | import android.app.Application;
8 | import android.view.WindowManager;
9 |
10 | public class MyApplication extends Application {
11 |
12 | private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();
13 | private static MyApplication instance;
14 | //取得Application实例
15 | public static MyApplication getInstance() {
16 | return instance;
17 | }
18 | //存储打开的Activity
19 | private List mActivities = new ArrayList();
20 | // private List mService = new ArrayList();
21 | //增加Activity
22 | public void addActivity(Activity activity)
23 | {
24 | mActivities.add(activity);
25 | }
26 |
27 | // public void addService(Service service)
28 | // {
29 | // mService.add(service);
30 | // }
31 |
32 | @Override
33 | public void onCreate() {
34 | super.onCreate();
35 | instance = this; //这句很重要。不初始化就没法用到Application了。
36 | }
37 |
38 | @Override
39 | public void onTerminate()
40 | {
41 | super.onTerminate(); //首先要调用这个
42 |
43 | // for(Service service : mService) //遍历Activity,一个个finish
44 | // service.stopSelf();
45 |
46 | for(Activity activity : mActivities) //遍历Activity,一个个finish
47 | activity.finish();
48 | System.exit(0); //退出程序
49 | }
50 |
51 |
52 | public WindowManager.LayoutParams getMywmParams(){
53 | return wmParams;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/RecordService.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.DataInputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import org.apache.commons.lang3.ArrayUtils;
14 |
15 | import tw.jwzhuang.ipcam.h264.H264Header;
16 | import tw.jwzhuang.ipcam.h264.H264Protocol;
17 | import tw.jwzhuang.ipcam.h264.ParcelableByteArray;
18 | import tw.jwzhuang.ipcam.server.StreamServer;
19 | import android.app.Service;
20 | import android.content.BroadcastReceiver;
21 | import android.content.ComponentName;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.IntentFilter;
25 | import android.content.ServiceConnection;
26 | import android.content.SharedPreferences;
27 | import android.content.SharedPreferences.Editor;
28 | import android.content.res.Configuration;
29 | import android.graphics.Color;
30 | import android.graphics.PixelFormat;
31 | import android.hardware.Camera;
32 | import android.hardware.Camera.Parameters;
33 | import android.media.MediaRecorder;
34 | import android.net.LocalServerSocket;
35 | import android.net.LocalSocket;
36 | import android.net.LocalSocketAddress;
37 | import android.os.Build;
38 | import android.os.Environment;
39 | import android.os.Handler;
40 | import android.os.IBinder;
41 | import android.os.Message;
42 | import android.os.PowerManager;
43 | import android.os.PowerManager.WakeLock;
44 | import android.util.Log;
45 | import android.util.TypedValue;
46 | import android.view.Gravity;
47 | import android.view.LayoutInflater;
48 | import android.view.SurfaceHolder;
49 | import android.view.SurfaceView;
50 | import android.view.View;
51 | import android.view.WindowManager;
52 | import android.view.ext.SatelliteMenu;
53 | import android.view.ext.SatelliteMenuItem;
54 | import android.widget.FrameLayout;
55 |
56 |
57 | public class RecordService extends Service implements SurfaceHolder.Callback, MediaRecorder.OnErrorListener,
58 | MediaRecorder.OnInfoListener{
59 |
60 | private WindowManager wm = null;
61 | private WindowManager.LayoutParams wmParams = null;
62 | private View view;
63 | private BroadcastReceiver m_br = null;
64 | private RecordHandler recHandler = new RecordHandler();
65 | private int startId = -1;
66 |
67 | private final String TAG = "RecordService";
68 | private final byte[] SOI_MARKER = { (byte) 0xFF, (byte) 0xD8 };
69 | private final byte[] EOF_MARKER = { (byte) 0xFF, (byte) 0xD9 };
70 | private LocalSocket receiver, sender;
71 | private LocalServerSocket lss;
72 | private MediaRecorder mMediaRecorder = null;
73 | private boolean mMediaRecorderRecording = false;
74 | private SurfaceView mSurfaceView = null;
75 | private SurfaceHolder mSurfaceHolder = null;
76 | private boolean startRecording = false;
77 | private List bufferList = null;
78 | private Thread t;
79 | private H264Header h264Header = null;
80 | // private int videoWidth = 176;
81 | // private int videoHeight = 144;
82 | private int videoWidth = 320;
83 | private int videoHeight = 240;
84 | private int videoRate = 30; //至少20張解碼才正常
85 | private SharedPreferences sharedPreferences;
86 | private final String mediaShare = "media";
87 | private String fd = Environment.getExternalStorageDirectory()+"/videotest.mp4";
88 | private final int MAXFRAMEBUFFER = 2048*videoRate;//*10;//20K
89 | private ServiceConnection mServiceConn = null;
90 | private StreamServer mStreamServer = null;
91 | private int cacheBufferforStreamServer = 0;
92 | private boolean cacheBufferforWriteFile = false;
93 | private boolean createFile = false;
94 | private Camera camera = null;
95 | private Parameters mParameters = null;
96 | private boolean isLighOn = false;
97 | private WakeLock wl = null;
98 | private FrameLayout fLayout = null;
99 |
100 | @Override
101 | public void onCreate() {
102 | super.onCreate();
103 |
104 | PowerManager pm = ((PowerManager)getSystemService(Context.POWER_SERVICE));
105 | wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BackLight");
106 |
107 | sharedPreferences = this.getSharedPreferences(mediaShare, MODE_PRIVATE);
108 | createView();
109 |
110 | bufferList = new ArrayList();
111 | mSurfaceView = (SurfaceView) view.findViewById(R.id.surface_camera);
112 | SurfaceHolder holder = mSurfaceView.getHolder();
113 | holder.addCallback(this);
114 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
115 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
116 | mSurfaceView.setVisibility(View.VISIBLE);
117 |
118 | initializeMenu();
119 |
120 | initializeServiceConnection();
121 | if(mStreamServer == null){
122 | bindService(new Intent(this,StreamServer.class), mServiceConn, BIND_AUTO_CREATE);
123 | }
124 |
125 | }
126 |
127 | private void createView() {
128 | // 获取WindowManager
129 | wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
130 | // 设置LayoutParams(全局变量)相关参数
131 | wmParams = ((MyApplication) getApplication()).getMywmParams();
132 | wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
133 | wmParams.flags |= WindowManager.LayoutParams.FORMAT_CHANGED;
134 | wmParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
135 | wmParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
136 | wmParams.gravity = Gravity.CENTER | Gravity.TOP; // 调整悬浮窗口至左上角
137 | // 以屏幕左上角为原点,设置x、y初始值
138 | wmParams.x = 0;
139 | // 设置悬浮窗口长宽数据
140 | wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
141 | wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
142 | wmParams.format = PixelFormat.RGBA_8888;
143 |
144 | view = LayoutInflater.from(this).inflate(R.layout.main, null);
145 |
146 | wm.addView(view, wmParams);
147 | view.setVisibility(View.INVISIBLE);
148 | view.setVisibility(View.VISIBLE);
149 | }
150 |
151 | @Override
152 | public int onStartCommand(Intent intent, int flags, int startId) {
153 | if(this.startId > -1){
154 | stopSelf(this.startId);
155 | }
156 |
157 | this.startId = startId;
158 | _RegisterReceiver();
159 |
160 | if(initializeLocalSocket() == false){
161 | this.stopSelf(startId);
162 | }
163 |
164 | if (wl != null)
165 | wl.acquire();
166 |
167 | return super.onStartCommand(intent, Service.START_STICKY, startId);
168 | }
169 |
170 | @Override
171 | public void onDestroy() {
172 |
173 | if (wl != null){
174 | wl.release();
175 | }
176 |
177 | cacheBufferforStreamServer = 0;
178 | cacheBufferforWriteFile = false;
179 | if(mStreamServer != null){
180 | mStreamServer.exitStreamServer();
181 | mStreamServer = null;
182 | unbindService(mServiceConn);
183 | }
184 |
185 | if (mMediaRecorderRecording) {
186 | h264Header = null;
187 | stopVideoRecording();
188 | try {
189 | lss.close();
190 | receiver.close();
191 | sender.close();
192 | } catch (IOException e) {
193 | e.printStackTrace();
194 | }
195 | }
196 |
197 | mSurfaceView = null;
198 | mSurfaceHolder = null;
199 | mMediaRecorder = null;
200 | if (t != null) {
201 | startRecording = false;
202 | }
203 |
204 | if (m_br != null) {
205 | unregisterReceiver(m_br);
206 | m_br = null;
207 | }
208 |
209 | wm.removeView(view);
210 | android.os.Process.killProcess(android.os.Process.myPid());
211 | super.onDestroy();
212 | }
213 |
214 |
215 | @Override
216 | public IBinder onBind(Intent intent) {
217 | return null;
218 | }
219 |
220 | /**
221 | * 註冊動態Receiver
222 | */
223 | private void _RegisterReceiver() {
224 | m_br = new BroadcastReceiver() {
225 | @Override
226 | public void onReceive(Context context, Intent intent) {
227 | String strAction = intent.getAction();
228 | Message msg = Message.obtain();
229 | if(strAction.equals(IntentType.ExitApp)){
230 | msg.obj = CMD.EXITAPP;
231 | }else if(strAction.equals(IntentType.ClientInfo)){
232 | msg.obj = CMD.CLIENTINFO;
233 | }
234 | recHandler.sendMessage(msg);
235 | }
236 | };
237 |
238 | IntentFilter filter = new IntentFilter();
239 | filter.addAction(IntentType.ExitApp);
240 | filter.addAction(IntentType.ClientInfo);
241 | registerReceiver(m_br, filter, null, null);
242 | }
243 |
244 | private class RecordHandler extends Handler{
245 | @Override
246 | public void handleMessage(Message msg) {
247 | super.handleMessage(msg);
248 | CMD cmd = (CMD) msg.obj;
249 | switch(cmd){
250 | case EXITAPP:
251 | stopSelf(startId);
252 | break;
253 | case CLIENTINFO:
254 | Intent it = new Intent(IntentType.NewClient);
255 | it.putExtra("clients", cacheBufferforStreamServer);
256 | sendBroadcast(it);
257 | break;
258 | }
259 | }
260 |
261 | }
262 |
263 | @Override
264 | public void onInfo(MediaRecorder mr, int what, int extra) {
265 | switch (what) {
266 | case MediaRecorder.MEDIA_RECORDER_INFO_UNKNOWN:
267 | System.out.println("MEDIA_RECORDER_INFO_UNKNOWN");
268 | break;
269 | case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:
270 | System.out.println("MEDIA_RECORDER_INFO_MAX_DURATION_REACHED");
271 | break;
272 | case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:
273 | System.out.println("MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED");
274 | break;
275 | }
276 | }
277 |
278 | @Override
279 | public void onError(MediaRecorder mr, int what, int extra) {
280 | if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
281 | System.out.println("MEDIA_RECORDER_ERROR_UNKNOWN");
282 | this.stopSelf(startId);
283 | }
284 | }
285 |
286 | @Override
287 | public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
288 | // TODO Auto-generated method stub
289 |
290 | }
291 |
292 | @Override
293 | public void surfaceCreated(SurfaceHolder holder) {
294 | mSurfaceHolder = holder;
295 | if (!mMediaRecorderRecording) {
296 | loadSPSAndPPS();
297 | initializeVideo();
298 | startVideoRecording();
299 | }
300 | }
301 |
302 | @Override
303 | public void surfaceDestroyed(SurfaceHolder holder) {
304 | // TODO Auto-generated method stub
305 |
306 | }
307 |
308 | private void stopVideoRecording() {
309 | System.out.println("stopVideoRecording");
310 | if (mMediaRecorderRecording || mMediaRecorder != null) {
311 | if (t != null)
312 | startRecording = false;
313 | // t.interrupt();
314 | releaseMediaRecorder();
315 | }
316 | }
317 |
318 | private void startVideoRecording() {
319 | (t = new Thread() {
320 |
321 | public void run() {
322 |
323 | try {
324 | if(h264Header == null) {
325 | Log.e(TAG, "Rlease MediaRecorder and get SPS and PPS");
326 | Thread.sleep(3000);
327 | //释放MediaRecorder资源
328 | releaseMediaRecorder();
329 | //从已采集的视频数据中获取SPS和PPS
330 | h264Header = H264Protocol.findSPSAndPPS(fd,videoWidth,videoHeight);
331 | if(h264Header != null){
332 | //记录到xml文件里
333 | String mdatStr = String.format("mdat_%d%d.mdat",videoWidth,videoHeight);
334 | Editor editor = sharedPreferences.edit();
335 | editor.putInt(mdatStr, h264Header.getStartMdatIndex());
336 | editor.commit();
337 |
338 | //save ftyp
339 | FileOutputStream file_out = RecordService.this.openFileOutput(
340 | String.format("%d%d.ftyp",videoWidth,videoHeight), Context.MODE_PRIVATE);
341 | file_out.write(h264Header.getFTYP());
342 | file_out.close();
343 |
344 | //save sps
345 | file_out = RecordService.this.openFileOutput(
346 | String.format("%d%d.sps",videoWidth,videoHeight), Context.MODE_PRIVATE);
347 | file_out.write(h264Header.getSPS());
348 | file_out.close();
349 |
350 | //save pps
351 | file_out = RecordService.this.openFileOutput(
352 | String.format("%d%d.pps",videoWidth,videoHeight), Context.MODE_PRIVATE);
353 | file_out.write(h264Header.getPPS());
354 | file_out.close();
355 | }
356 | //
357 | //找到后重新初始化MediaRecorder
358 | initializeVideo();
359 | }
360 | } catch (Exception e) {
361 | return;
362 | }
363 |
364 | startRecording = true;
365 | processData();
366 | DataInputStream dis = null;
367 | try {
368 | dis = new DataInputStream(new BufferedInputStream(receiver.getInputStream(),MAXFRAMEBUFFER)); //BufferedInputStream 為了使用mark 與 reset
369 | // dis.read(buffer, 0, 32); //過濾多餘的ftyp
370 | } catch (IOException e1) {
371 | return;
372 | }
373 | while (startRecording) {
374 | try {
375 | int h264length = dis.readInt();
376 | //
377 | if(h264length > 0){
378 | dis.mark(MAXFRAMEBUFFER);
379 | //取得mdat index
380 | int mDatIndex = H264Protocol.findMdatIndex(dis,MAXFRAMEBUFFER);
381 | dis.reset();
382 | dis.skip(mDatIndex);
383 | // byte [] mdat = new byte[4];
384 | // dis.readFully(mdat);
385 | // dis.reset();
386 | dis.skip(4); //Mdat Length
387 | }
388 | while (startRecording && h264length > 0) {
389 | byte [] frameData = H264Protocol.readH264Bytes(dis,MAXFRAMEBUFFER);
390 |
391 | if(cacheBufferforStreamServer > 0 || cacheBufferforWriteFile){
392 | if((frameData[0] & 0x1F) == 5){
393 | bufferList = new ArrayList();
394 | for(int i=bufferList.size() -1 ;i> 0;i--){
395 | bufferList.remove(i);
396 | }
397 | }
398 | ParcelableByteArray byteArray = new ParcelableByteArray(frameData);
399 | bufferList.add(byteArray);
400 | }
401 | }
402 |
403 | } catch (IOException e) {
404 | break;
405 | }
406 | }
407 | }
408 | }).start();
409 | }
410 |
411 | private void initializeMenu(){
412 | SatelliteMenu menu = new SatelliteMenu(this);
413 | float distance = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 170, getResources().getDisplayMetrics());
414 | menu.setSatelliteDistance((int) distance);
415 | menu.setExpandDuration(500);
416 | menu.setCloseItemsOnClick(true);
417 | menu.setTotalSpacingDegree(90);
418 | menu.setMainImage(R.drawable.main);
419 | List items = new ArrayList();
420 | items.add(new SatelliteMenuItem(0, R.drawable.ic_1)); //Exit App
421 | items.add(new SatelliteMenuItem(1, R.drawable.ic_3)); //Show Info
422 | items.add(new SatelliteMenuItem(2, R.drawable.ic_4)); //Write File
423 | menu.addItems(items);
424 | menu.setOnItemClickedListener(new MenuClickedListener(this));
425 | menu.setBackgroundColor(Color.TRANSPARENT);
426 | int wh = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());
427 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
428 | wh, wh);
429 | params.gravity=Gravity.BOTTOM | Gravity.LEFT;
430 | params.leftMargin = 5;
431 | params.bottomMargin = 5;
432 | fLayout = (FrameLayout) view.findViewById(R.id.layout);
433 | fLayout.addView(menu,params);
434 | }
435 |
436 | private boolean initializeLocalSocket(){
437 | receiver = new LocalSocket();
438 | try {
439 | lss = new LocalServerSocket("VideoCamera");
440 | receiver.connect(new LocalSocketAddress("VideoCamera"));
441 | receiver.setReceiveBufferSize(500000);
442 | receiver.setSendBufferSize(500000);
443 | sender = lss.accept();
444 | sender.setReceiveBufferSize(500000);
445 | sender.setSendBufferSize(500000);
446 | } catch (IOException e) {
447 | return false;
448 | }
449 | return true;
450 | }
451 |
452 | private void initializeServiceConnection(){
453 | mServiceConn = new ServiceConnection(){
454 |
455 | @Override
456 | public void onServiceConnected(ComponentName name, IBinder binder) {
457 | mStreamServer = ((StreamServer.ServiceBinder)binder).getService();
458 | mStreamServer.setWidth(videoWidth);
459 | mStreamServer.setHeight(videoHeight);
460 | mStreamServer.setRate(videoRate);
461 | mStreamServer.setB(RecordService.this);
462 | }
463 |
464 | @Override
465 | public void onServiceDisconnected(ComponentName name) {
466 | Log.i(TAG, String.format("Stream Service Disconneciton %s", name.getClassName()));
467 | }
468 | };
469 | }
470 |
471 | private boolean initializeVideo() {
472 | System.out.println("initializeVideo");
473 | if (mSurfaceHolder == null)
474 | return false;
475 | mMediaRecorderRecording = true;
476 | if (mMediaRecorder == null)
477 | mMediaRecorder = new MediaRecorder();
478 | else
479 | mMediaRecorder.reset();
480 | camera = Camera.open();
481 | if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
482 | camera.setDisplayOrientation(90);
483 | else
484 | camera.setDisplayOrientation(0);
485 | camera.unlock();
486 | mMediaRecorder.setCamera(camera);
487 | mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
488 | // mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
489 | mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
490 | //CamcorderProfile camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
491 | //mediaRecorder.setProfile(camcorderProfile);//构造CamcorderProfile,使用高质量视频录制
492 | mMediaRecorder.setVideoFrameRate(videoRate);
493 | mMediaRecorder.setVideoSize(videoWidth, videoHeight);
494 | mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
495 | mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
496 | mMediaRecorder.setMaxDuration(0);
497 | mMediaRecorder.setMaxFileSize(0);
498 | if(h264Header == null)
499 | {
500 | Log.e(TAG, "============== SPS is null!!!!!!!!!!");
501 | try {
502 | File file = new File(fd);
503 | if (file.exists())
504 | file.delete();
505 | } catch (Exception ex) {
506 | Log.v("System.out", ex.toString());
507 | }
508 | mMediaRecorder.setOutputFile(fd);
509 | }
510 | else
511 | {
512 | Log.e(TAG,"=============== SPS have value!!!!!!!");
513 | mMediaRecorder.setOutputFile(sender.getFileDescriptor());
514 | }
515 | try {
516 | mMediaRecorder.setOnInfoListener(this);
517 | mMediaRecorder.setOnErrorListener(this);
518 | mMediaRecorder.prepare();
519 | mMediaRecorder.start();
520 | } catch (IOException exception) {
521 | releaseMediaRecorder();
522 | stopSelf(startId);
523 | return false;
524 | }
525 | return true;
526 | }
527 |
528 | private void releaseCamera() throws IOException{
529 | if(camera == null){
530 | return;
531 | }
532 | mParameters = camera.getParameters();
533 | if(mParameters.getFlashMode() == Camera.Parameters.FLASH_MODE_TORCH){
534 | mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
535 | camera.setParameters(mParameters);
536 | }
537 |
538 | camera.reconnect();
539 | camera.stopPreview();
540 | camera.release();
541 | camera = null;
542 | }
543 |
544 | private void releaseMediaRecorder() {
545 | System.out.println("Releasing media recorder.");
546 | if (mMediaRecorder != null) {
547 | if (mMediaRecorderRecording) {
548 | try {
549 | System.out.println("Releasing media recorder2");
550 | mMediaRecorder.setOnErrorListener(null);
551 | mMediaRecorder.setOnInfoListener(null);
552 | mMediaRecorder.stop();
553 | releaseCamera();
554 | } catch (RuntimeException e) {
555 | System.out.println("stop fail: " + e.getMessage());
556 | } catch (IOException e) {
557 | System.out.println("stop fail: " + e.getMessage());
558 | }
559 | mMediaRecorderRecording = false;
560 | }
561 | mMediaRecorder.reset();
562 | mMediaRecorder.release();
563 | mMediaRecorder = null;
564 | }
565 | }
566 |
567 | public byte[] getSPS(){
568 | return h264Header.getSPS();
569 | }
570 |
571 | public byte[] getPPS(){
572 | return h264Header.getPPS();
573 | }
574 |
575 | // 得到序列参数集SPS和图像参数集PPS,如果已经存储在本地
576 | private void loadSPSAndPPS() {
577 |
578 | int mdatIndex = sharedPreferences.getInt(
579 | String.format("mdat_%d%d.mdat", videoWidth, videoHeight), -1);
580 |
581 | if (mdatIndex != -1) {
582 | h264Header = new H264Header();
583 | h264Header.setStartMdatIndex(mdatIndex);
584 | byte[] temp = new byte[100];
585 | try {
586 |
587 | FileInputStream file_in = openFileInput(String.format("%d%d.ftyp", videoWidth, videoHeight));
588 |
589 | int index = 0;
590 | int read = 0;
591 | while (true) {
592 | read = file_in.read(temp, index, 10);
593 | if (read == -1)
594 | break;
595 | else
596 | index += read;
597 | }
598 | Log.e(TAG, "=====get ftyp length:" + index);
599 | h264Header.setFTYP(temp,index);
600 |
601 | file_in.close();
602 |
603 |
604 | file_in = openFileInput(String.format("%d%d.sps", videoWidth, videoHeight));
605 |
606 | index = 0;
607 | while (true) {
608 | read = file_in.read(temp, index, 10);
609 | if (read == -1)
610 | break;
611 | else
612 | index += read;
613 | }
614 | Log.e(TAG, "=====get sps length:" + index);
615 | h264Header.setSPS(temp, index);
616 |
617 | file_in.close();
618 |
619 | index = 0;
620 | // read PPS
621 | file_in = openFileInput(String.format("%d%d.pps", videoWidth, videoHeight));
622 | while (true) {
623 | read = file_in.read(temp, index, 10);
624 | if (read == -1)
625 | break;
626 | else
627 | index += read;
628 | }
629 | Log.e(TAG, "==========get pps length:" + index);
630 | h264Header.setPPS(temp, index);
631 | } catch (FileNotFoundException e) {
632 | Log.e(TAG, e.toString());
633 | } catch (IOException e) {
634 | Log.e(TAG, e.toString());
635 | }
636 | } else {
637 | Log.e(TAG, "==============StartMdatPlace = -1");
638 | h264Header = null;
639 | }
640 | }
641 |
642 | public void startCacheBuf_StreamServer(int i){
643 | cacheBufferforStreamServer += i;
644 |
645 | if(cacheBufferforStreamServer < 0){
646 | return;
647 | }
648 |
649 | Intent it = new Intent(IntentType.NewClient);
650 | it.putExtra("clients", cacheBufferforStreamServer);
651 | sendBroadcast(it);
652 |
653 | if(cacheBufferforStreamServer < 1){
654 | return;
655 | }
656 |
657 | byte[] dd = ArrayUtils.addAll(SOI_MARKER, null);
658 | dd = ArrayUtils.addAll(dd,h264Header.getHead());
659 | dd = ArrayUtils.addAll(dd,h264Header.getSPS());
660 | dd = ArrayUtils.addAll(dd,EOF_MARKER);
661 | mStreamServer.setBuffer(dd);
662 |
663 | dd = ArrayUtils.addAll(SOI_MARKER, null);
664 | dd = ArrayUtils.addAll(dd,h264Header.getHead());
665 | dd = ArrayUtils.addAll(dd,h264Header.getPPS());
666 | dd = ArrayUtils.addAll(dd,EOF_MARKER);
667 | mStreamServer.setBuffer(dd);
668 | }
669 |
670 | public void startCacheBuf_WriteFile(boolean b){
671 | cacheBufferforWriteFile = b;
672 | createFile = b;
673 | }
674 |
675 | public void processData(){
676 | new Thread(){
677 | @Override
678 | public void run() {
679 | super.run();
680 | try {
681 | FileOutputStream fos = null;
682 | while(startRecording){
683 | if(bufferList.size() > 0){
684 | if(cacheBufferforWriteFile){
685 | if(createFile){
686 | String name = Environment.getExternalStorageDirectory() + "/my.h264";//TODO changefile
687 | fos = new FileOutputStream(name);
688 | // fos.write(h264Header.getFTYP());
689 | fos.write(h264Header.getHead());
690 | fos.write(h264Header.getSPS());
691 | fos.write(h264Header.getHead());
692 | fos.write(h264Header.getPPS());
693 | createFile = false;
694 | }
695 |
696 | fos.write(h264Header.getHead());
697 | fos.write(bufferList.get(0).get_byte());
698 | }
699 | if(cacheBufferforStreamServer > 0 && mStreamServer != null){
700 | byte[] dd = ArrayUtils.addAll(SOI_MARKER, null);
701 | dd = ArrayUtils.addAll(dd,h264Header.getHead());
702 | dd = ArrayUtils.addAll(dd,copyLastBufferData());
703 | dd = ArrayUtils.addAll(dd,EOF_MARKER);
704 | mStreamServer.setBuffer(dd);
705 | }
706 | bufferList.remove(0);
707 | // bufferList.clear();
708 | }
709 | }
710 |
711 | if(fos != null){
712 | fos.close();
713 | }
714 |
715 |
716 | } catch (FileNotFoundException e) {
717 | } catch (IOException e) {
718 | } finally{
719 | bufferList.clear();
720 | }
721 | }
722 | }.start();
723 | }
724 |
725 | private byte[] copyLastBufferData(){
726 | // return ArrayUtils.addAll(bufferList.get(0).get_byte(), null);
727 | return ArrayUtils.addAll(bufferList.get(0).get_byte(), null);
728 | // return ArrayUtils.addAll(bufferList.get(bufferList.size()-1).get_byte(), null);
729 | }
730 |
731 | public void flashLight() {
732 | if (camera == null) {
733 | return;
734 | }
735 | mParameters = camera.getParameters();
736 | if (isLighOn) {
737 | Log.i("info", "torch is turn off!");
738 | mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
739 | camera.setParameters(mParameters);
740 | isLighOn = false;
741 | } else {
742 | Log.i("info", "torch is turn on1");
743 | mParameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
744 | Log.i("info", "torch is turn on2");
745 | camera.setParameters(mParameters);
746 | Log.i("info", "torch is turn on3");
747 | isLighOn = true;
748 | }
749 | }
750 | }
751 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/Utils.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam;
2 |
3 | import java.net.Inet4Address;
4 | import java.net.InetAddress;
5 | import java.net.NetworkInterface;
6 | import java.net.SocketException;
7 | import java.net.UnknownHostException;
8 | import java.util.Enumeration;
9 |
10 | import android.graphics.Point;
11 | import android.util.Log;
12 | import android.view.Display;
13 | import android.view.WindowManager;
14 |
15 | public class Utils {
16 |
17 | /**
18 | * 取得螢幕大小
19 | * @param wm WindowManager
20 | * @return
21 | */
22 | public static Point getScreenSize(WindowManager wm){
23 | Display display = wm.getDefaultDisplay();
24 | Point size = new Point();
25 | display.getSize(size);
26 | return size;
27 | }
28 |
29 | /**
30 | * 取得裝置的IP位址
31 | *
32 | * @return
33 | * @throws UnknownHostException
34 | */
35 | public static String getLocalIpAddress() {
36 | try {
37 | for (Enumeration en = NetworkInterface
38 | .getNetworkInterfaces(); en.hasMoreElements();) {
39 | NetworkInterface intf = en.nextElement();
40 | for (Enumeration enumIpAddr = intf
41 | .getInetAddresses(); enumIpAddr.hasMoreElements();) {
42 | InetAddress inetAddress = enumIpAddr.nextElement();
43 | if (!inetAddress.isLoopbackAddress()
44 | && (inetAddress instanceof Inet4Address)) {
45 | return inetAddress.getHostAddress().toString();
46 | }
47 | }
48 | }
49 | } catch (SocketException ex) {
50 | Log.e("ExFunctions", ex.toString());
51 | }
52 | return null;
53 | }
54 |
55 | /**
56 | * 產生亂數密碼
57 | * @param digitOfSet
58 | * @param set
59 | * @return String
60 | */
61 | public static String pwdGenerator(int digitOfSet, int set) {
62 | String newPwd = "";
63 | String pwdSet = "";
64 | // System.Random rand = new System.Random(); // for C#
65 | int num = 0;
66 | for (int i = 0; i < set; i++) {
67 | if(i > 0)
68 | newPwd += "-"; //各組英數之間的分隔號
69 | pwdSet = "";
70 | while (pwdSet.length() < digitOfSet) {
71 | num = (int)(Math.random()*(90-50+1))+50; // for Java
72 | if (num > 57 && num < 65)
73 | continue; //排除 58~64 這區間的非英數符號
74 | else if (num == 79 || num == 73)
75 | continue; //排除 I 和 O
76 | pwdSet += (char)num; //將數字轉換為字元
77 |
78 | }
79 | newPwd += pwdSet;
80 | }
81 | return newPwd;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/h264/H264Header.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam.h264;
2 |
3 | public class H264Header {
4 | protected int startMdatIndex = 0;
5 | protected byte[] SPS;
6 | protected byte[] PPS;
7 | protected byte[] FTYP;
8 |
9 | protected final byte[] mHead = new byte[]{0x00,0x00,0x00,0x01};
10 | protected final static byte [] mMdat = new byte[] { (byte) 0x6D, (byte) 0x64, (byte) 0x61, (byte) 0x74 };
11 |
12 | public byte[] getHead() {
13 | return mHead;
14 | }
15 |
16 | public byte[] getFTYP() {
17 | return FTYP;
18 | }
19 |
20 | public void setFTYP(byte[] fTYP) {
21 | FTYP = fTYP;
22 | }
23 |
24 | public void setFTYP(byte[] temp, int index) {
25 | FTYP = new byte[index];
26 | System.arraycopy(temp, 0, FTYP, 0, index);
27 | }
28 |
29 | public int getStartMdatIndex() {
30 | return startMdatIndex;
31 | }
32 |
33 | public void setStartMdatIndex(int startMdatIndex) {
34 | this.startMdatIndex = startMdatIndex;
35 | }
36 |
37 | public byte[] getSPS() {
38 | return SPS;
39 | }
40 |
41 | public void setSPS(byte[] sPS) {
42 | SPS = sPS;
43 | }
44 |
45 | public void setSPS(byte[] temp, int index) {
46 | SPS = new byte[index];
47 | System.arraycopy(temp, 0, SPS, 0, index);
48 | }
49 |
50 | public byte[] getPPS() {
51 | return PPS;
52 | }
53 |
54 | public void setPPS(byte[] pPS) {
55 | PPS = pPS;
56 | }
57 |
58 | public void setPPS(byte[] temp, int index) {
59 | PPS = new byte[index];
60 | System.arraycopy(temp, 0, PPS, 0, index);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/h264/H264Protocol.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam.h264;
2 |
3 | import java.io.DataInputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 |
8 | import android.util.Log;
9 |
10 | public class H264Protocol extends H264Header {
11 |
12 | public static int findMdatIndex(DataInputStream in, int MAXFRAMEBUFFER)
13 | throws IOException {
14 | int seqIndex = 0;
15 | byte c;
16 | for (int i = 0; i < MAXFRAMEBUFFER; i++) {
17 | c = (byte) in.readUnsignedByte();
18 | if (c == mMdat[seqIndex]) {
19 | seqIndex++;
20 | if (seqIndex == mMdat.length)
21 | return (i + 1) - mMdat.length;
22 | } else
23 | seqIndex = 0;
24 | }
25 | return -1;
26 | }
27 |
28 | public static byte[] readH264Bytes(DataInputStream in, int MAXFRAMEBUFFER) throws IOException{
29 | //重新定位在frame 長度 00 00 xx xx
30 | in.mark(MAXFRAMEBUFFER);
31 | in.reset();
32 | //取得frame length
33 | byte [] len = new byte[4];
34 | in.readFully(len);
35 | in.reset();
36 | in.skip(len.length);
37 | in.mark(MAXFRAMEBUFFER);
38 | int DataLength = ((len[2] & 0xFF) << 8) | (len[3] & 0xFF);
39 |
40 | //取得frame Data
41 | byte [] content = new byte[DataLength];
42 | in.readFully(content);
43 | in.reset();
44 | in.skip(content.length);
45 | return content;
46 | }
47 |
48 | public static H264Header findSPSAndPPS(String samplefile, int videoWidth, int videoHeight) throws Exception{
49 | H264Header h264Header = null;
50 | final String TAG = "H264Protocol";
51 | int startMdatIndex = 0;
52 | byte[] SPS;
53 | byte[] PPS;
54 | byte[] ftyp = new byte[28];
55 |
56 | File file = new File(samplefile);
57 | FileInputStream fileInput = new FileInputStream(file);
58 |
59 | int length = (int)file.length();
60 | byte[] data = new byte[length];
61 |
62 | fileInput.read(data);
63 | fileInput.close();
64 | final byte[] mdat = new byte[]{0x6D,0x64,0x61,0x74};
65 | final byte[] avcc = new byte[]{0x61,0x76,0x63,0x43};
66 |
67 | for(int i=0 ; i hints = null;
58 | String encoding = guessAppropriateEncoding(contentsToEncode);
59 | if (encoding != null) {
60 | hints = new EnumMap<>(EncodeHintType.class);
61 | hints.put(EncodeHintType.CHARACTER_SET, encoding);
62 | }
63 | BitMatrix result;
64 | try {
65 | result = new MultiFormatWriter().encode(contentsToEncode, format, dimension, dimension, hints);
66 | } catch (IllegalArgumentException iae) {
67 | // Unsupported format
68 | return null;
69 | }
70 | int width = result.getWidth();
71 | int height = result.getHeight();
72 | int[] pixels = new int[width * height];
73 | for (int y = 0; y < height; y++) {
74 | int offset = y * width;
75 | for (int x = 0; x < width; x++) {
76 | pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
77 | }
78 | }
79 |
80 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
81 | bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
82 | return bitmap;
83 | }
84 |
85 | private static String guessAppropriateEncoding(CharSequence contents) {
86 | // Very crude at the moment
87 | for (int i = 0; i < contents.length(); i++) {
88 | if (contents.charAt(i) > 0xFF) {
89 | return "UTF-8";
90 | }
91 | }
92 | return null;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/server/SocketServer.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam.server;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.IOException;
6 | import java.io.UnsupportedEncodingException;
7 | import java.net.ServerSocket;
8 | import java.net.Socket;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.regex.Matcher;
12 | import java.util.regex.Pattern;
13 |
14 | import org.json.JSONObject;
15 |
16 | import android.util.Log;
17 |
18 | public class SocketServer implements Runnable {
19 |
20 | private final String TAG = "H264 Stream Server";
21 | private ServerSocket serverSocket = null;
22 | private Boolean readStream = true;
23 | private final int ServerPort = 47226;
24 | private StreamServer streamServer = null;
25 | private List workers = null;
26 |
27 | public SocketServer(StreamServer streamServer) {
28 | this.streamServer = streamServer;
29 | workers = new ArrayList();
30 | }
31 |
32 | @Override
33 | public void run() {
34 | Log.d(TAG, String.format("%s Run %d", this.getClass().getSimpleName(),
35 | ServerPort));
36 | try {
37 | // 建立serverSocket
38 | serverSocket = new ServerSocket(ServerPort);
39 | // boolean verify = false;
40 | // 等待連線
41 | while (readStream) {
42 | Socket client = serverSocket.accept();
43 | WorkerRunnable worker = new WorkerRunnable(client);
44 | workers.add(worker);
45 | new Thread(worker).start();
46 | }
47 | } catch (Exception e) {
48 | }
49 | }
50 |
51 | public void closeServer() throws IOException {
52 | readStream = false;
53 | if (serverSocket != null) {
54 | serverSocket.close();
55 | serverSocket = null;
56 | Log.d(TAG, "null connect");
57 | }
58 |
59 | for(int i = 0;i < workers.size();i++){
60 | WorkerRunnable worker = workers.get(0);
61 | if(worker != null){
62 | worker.closeAll();
63 | }
64 | workers.clear();
65 | }
66 | }
67 |
68 | public class WorkerRunnable implements Runnable {
69 |
70 | private Socket client = null;
71 | private boolean isConnected = false;
72 | private int aliveMsg = 3;
73 | private BufferedInputStream in = null;
74 | private BufferedOutputStream out = null;
75 |
76 | public WorkerRunnable(Socket clientSocket) {
77 | this.client = clientSocket;
78 | this.isConnected = true;
79 | // checkAlive();
80 | }
81 |
82 | public void sentMsg(String str) {
83 | sentMsg(str.getBytes());
84 | }
85 |
86 | public void sentMsg(final byte[] data) {
87 | if (null != out) {
88 | new Thread() {
89 | public void run() {
90 | try {
91 | // 送出字串
92 | out.write(data);
93 | out.flush();
94 | // Log.d(VideoDBSet.ServiceTAG, new String(m));
95 |
96 | } catch (Exception e) {
97 | try {
98 | closeAll();
99 | } catch (Exception e1) {
100 | e1.printStackTrace();
101 | }
102 | }
103 | }
104 | }.start();
105 | }
106 | }
107 |
108 | public void closeAll() throws IOException{
109 |
110 | streamServer.removeWorker(this);
111 |
112 | if (in != null) {
113 | in.close();
114 | in = null;
115 | Log.d(TAG, "null in");
116 | }
117 |
118 | if (out != null) {
119 | out.close();
120 | out = null;
121 | Log.d(TAG, "null out");
122 | }
123 |
124 | if(client != null){
125 | client.close();
126 | }
127 | }
128 |
129 | private String getSocketStr(String str) throws UnsupportedEncodingException {
130 | String groupStr = "";
131 | // String patternStr = "([\\S]+)";
132 |
133 | String patternStr = String.format("([^%s]+)", new String(new byte[1]));
134 | Pattern pattern = Pattern.compile(patternStr);
135 | Matcher matcher = pattern.matcher(str);
136 | while (matcher.find()) {
137 | for (int i = 0; i <= matcher.groupCount() - 1; i++) {
138 | if (groupStr.length() < matcher.group(i).length()) {
139 | groupStr = matcher.group(i);
140 | }
141 | }
142 | }
143 | return groupStr;
144 | }
145 |
146 | @Override
147 | public void run() {
148 | try {
149 | out = new BufferedOutputStream(client.getOutputStream());
150 | in = new BufferedInputStream(client.getInputStream());
151 | boolean verify = false;
152 | while (isConnected && readStream) {// 接收連線
153 | byte[] content = new byte[1024];
154 | in.read(content);
155 | String input = getSocketStr(new String(content, "UTF8"));
156 | Log.d("ddd", input);
157 | JSONObject jobj = new JSONObject(input);
158 | if (jobj.optString("cmd") != null) {
159 | if (jobj.getString("cmd").equals("login")) {
160 | verify = streamServer.verifyUser(
161 | jobj.getString("pwd"),this);
162 | } else if (jobj.getString("cmd").equals("alive")) {
163 | aliveMsg++;
164 | } else if (jobj.getString("cmd").equals("getparams")
165 | && verify) {
166 | streamServer.sentVideoParams(this);
167 | } else if (jobj.getString("cmd").equals("getstream")
168 | && verify) {
169 | streamServer.sentVideoStream(true,this);
170 | }else if (jobj.getString("cmd").equals("flashlight")
171 | && verify) {
172 | streamServer.flashLight();
173 | }
174 | }
175 | }
176 | } catch (Exception e) {
177 | }
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/server/StreamServer.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam.server;
2 |
3 | import java.io.IOException;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | import org.json.JSONException;
8 | import org.json.JSONObject;
9 |
10 | import tw.jwzhuang.ipcam.RecordService;
11 | import tw.jwzhuang.ipcam.server.SocketServer.WorkerRunnable;
12 | import android.app.Service;
13 | import android.content.Intent;
14 | import android.content.SharedPreferences;
15 | import android.os.Binder;
16 | import android.os.Handler;
17 | import android.os.HandlerThread;
18 | import android.os.IBinder;
19 | import android.util.Base64;
20 | import android.util.Log;
21 |
22 | public class StreamServer extends Service {
23 |
24 | private final String TAG = this.getClass().getSimpleName();
25 | private byte[] buffer = null;
26 | private int startId = -1;
27 | public int videoWidth = 320;
28 | public int videoHeight = 240;
29 | private int videoRate = 20;
30 | private SocketServer server = null;
31 | private HandlerThread mThread = null;
32 | private Handler mThreadHandler;
33 | private ServiceBinder mBinder = null;
34 | private RecordService activity = null;
35 | private List streamToWorkers = null;
36 | private SharedPreferences preferences = null;
37 |
38 | @Override
39 | public void onCreate() {
40 | super.onCreate();
41 | mBinder = new ServiceBinder();
42 | streamToWorkers = new ArrayList();
43 | preferences = getSharedPreferences("code", MODE_PRIVATE);
44 | }
45 |
46 | @Override
47 | public int onStartCommand(Intent intent, int flags, int startId) {
48 | stopServerSocket();
49 | startServerSocket();
50 | if(startId != -1){
51 | this.stopSelf(startId);
52 | }
53 | this.startId = startId;
54 | return super.onStartCommand(intent, START_STICKY, startId);
55 | }
56 |
57 | @Override
58 | public void onDestroy() {
59 | stopServerSocket();
60 | super.onDestroy();
61 | }
62 |
63 | public void exitStreamServer(){
64 | stopSelf(startId);
65 | }
66 |
67 | public void setB(RecordService recordService) {
68 | this.activity = recordService;
69 | }
70 |
71 | public void setBuffer(byte[] bf){
72 | this.buffer = bf;
73 |
74 | //add length at byte[0] , byte[1]
75 | for(int i=0; i< streamToWorkers.size(); i++){
76 | WorkerRunnable worker = streamToWorkers.get(0);
77 | worker.sentMsg(buffer);
78 | }
79 | }
80 |
81 | public void setHeight(int h){
82 | this.videoHeight = h;
83 | }
84 |
85 | public void setRate(int r){
86 | this.videoRate = r;
87 | }
88 |
89 | public void setWidth(int w){
90 | this.videoWidth = w;
91 | }
92 |
93 | private void startServerSocket(){
94 | mThread = new HandlerThread("name");
95 | mThread.start();
96 |
97 | mThreadHandler=new Handler(mThread.getLooper());
98 | mThreadHandler.post(server = new SocketServer(this));
99 | }
100 |
101 | public void removeWorker(WorkerRunnable worker) {
102 | activity.startCacheBuf_StreamServer(-1);
103 | streamToWorkers.remove(worker);
104 | }
105 |
106 | private void stopServerSocket(){
107 |
108 | for(int i = 0;i < streamToWorkers.size(); i++){
109 | removeWorker(streamToWorkers.get(0));
110 | }
111 |
112 | if(server != null){
113 | try {
114 | server.closeServer();
115 | server = null;
116 | } catch (IOException e) {
117 | Log.e(TAG, e.getMessage());
118 | }
119 | }
120 |
121 | if (mThreadHandler != null) {
122 | mThreadHandler.removeCallbacksAndMessages(null);
123 | }
124 |
125 | if (mThread != null) {
126 | mThread.quit();
127 | }
128 |
129 | activity = null;
130 | }
131 |
132 | @Override
133 | public IBinder onBind(Intent arg0) {
134 | stopServerSocket();
135 | startServerSocket();
136 | return mBinder;
137 | }
138 |
139 | public class ServiceBinder extends Binder {
140 |
141 | public StreamServer getService(){
142 | return StreamServer.this;
143 | }
144 | }
145 |
146 | public boolean verifyUser(String pwd, WorkerRunnable worker) throws JSONException {
147 | JSONObject jobj = new JSONObject();
148 | jobj.put("cmd", "login");
149 |
150 | if(preferences.getString("randomcode", "*^(&%)&(%^*(").equals(pwd)){
151 | jobj.put("state", 0);
152 | }else{
153 | jobj.put("state", 1);
154 | }
155 | worker.sentMsg(jobj.toString());
156 |
157 | return true;
158 | }
159 |
160 | public void sentVideoParams(WorkerRunnable worker) throws JSONException {
161 | JSONObject jobj = new JSONObject();
162 | jobj.put("cmd", "getparams");
163 | jobj.put("state", 0);
164 | jobj.put("sps", Base64.encodeToString(activity.getSPS(), Base64.DEFAULT));
165 | jobj.put("pps", Base64.encodeToString(activity.getPPS(), Base64.DEFAULT));
166 | jobj.put("rate", videoRate);
167 | worker.sentMsg(jobj.toString());
168 | }
169 |
170 | public void sentVideoStream(boolean isSent, WorkerRunnable worker) throws JSONException, InterruptedException {
171 | JSONObject jobj = new JSONObject();
172 | jobj.put("cmd", "getstream");
173 | jobj.put("state", 0);
174 | worker.sentMsg(jobj.toString());
175 | Thread.sleep(1000);
176 | streamToWorkers.add(worker);
177 | activity.startCacheBuf_StreamServer(1);
178 | }
179 |
180 | public void flashLight(){
181 | activity.flashLight();
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/tw/jwzhuang/ipcam/server/WorkerRunnable.java:
--------------------------------------------------------------------------------
1 | package tw.jwzhuang.ipcam.server;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.Socket;
7 |
8 | public class WorkerRunnable implements Runnable {
9 |
10 | protected Socket clientSocket = null;
11 | protected String serverText = null;
12 |
13 | public WorkerRunnable(Socket clientSocket, String serverText) {
14 | this.clientSocket = clientSocket;
15 | this.serverText = serverText;
16 | }
17 |
18 | @Override
19 | public void run() {
20 | try {
21 | InputStream input = clientSocket.getInputStream();
22 | OutputStream output = clientSocket.getOutputStream();
23 | long time = System.currentTimeMillis();
24 | output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: "
25 | + this.serverText + " - " + time + "").getBytes());
26 | output.close();
27 | input.close();
28 | System.out.println("Request processed: " + time);
29 | } catch (IOException e) {
30 | // report exception somewhere.
31 | e.printStackTrace();
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------