├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ ├── 2_0.xml
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── AndroidVideoPlayer.iml
├── LICENSE
├── README.md
├── VideoPlayer.iml
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── android
│ │ └── tedcoder
│ │ └── androidvideoplayer
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── android
│ │ └── tedcoder
│ │ └── androidvideoplayer
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img
├── Screenshot_20151028-195103.png
└── Screenshot_20151028-195113.png
├── settings.gradle
└── wkvideoplayer
├── .gitignore
├── build.gradle
├── libs
└── clink210.jar
├── proguard-rules.pro
├── src
├── androidTest
│ └── java
│ │ └── com
│ │ └── android
│ │ └── tedcoder
│ │ └── wkvideoplayer
│ │ └── ApplicationTest.java
└── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── android
│ │ └── tedcoder
│ │ └── wkvideoplayer
│ │ ├── dlna
│ │ ├── engine
│ │ │ ├── DLNAContainer.java
│ │ │ ├── MultiPointController.java
│ │ │ └── SearchThread.java
│ │ ├── inter
│ │ │ └── IController.java
│ │ ├── service
│ │ │ └── DLNAService.java
│ │ └── util
│ │ │ ├── DLNAUtil.java
│ │ │ ├── LogUtil.java
│ │ │ └── NetUtil.java
│ │ ├── model
│ │ ├── Video.java
│ │ └── VideoUrl.java
│ │ ├── util
│ │ └── DensityUtil.java
│ │ └── view
│ │ ├── DeviceAdapter.java
│ │ ├── EasySwitcher.java
│ │ ├── MediaController.java
│ │ ├── SuperVideoPlayer.java
│ │ └── SuperVideoView.java
│ └── res
│ ├── anim
│ ├── anim_enter_from_bottom.xml
│ ├── anim_exit_from_bottom.xml
│ └── biz_news_detailpage_loading_large_anim.xml
│ ├── color
│ └── switcher_item_text_selector.xml
│ ├── drawable-hdpi
│ └── biz_video_progress_thumb.png
│ ├── drawable-xhdpi
│ ├── biz_video_danmaku_switcher_bg.9.png
│ ├── biz_video_danmaku_write.png
│ ├── biz_video_expand.png
│ ├── biz_video_pause.png
│ ├── biz_video_play.png
│ ├── biz_video_progress_thumb.png
│ ├── biz_video_shrink.png
│ ├── ic_action_bulb.png
│ ├── ic_action_music_2.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── biz_audio_sublist_item_img_icon.png
│ ├── biz_news_detailpage_loading_large_icon.png
│ ├── biz_news_list_ad_video_close_btn.png
│ ├── biz_video_list_play_icon_big.png
│ ├── ic_action_bulb.png
│ ├── ic_action_music_2.png
│ ├── icon_tv.png
│ ├── icon_tv_big.png
│ ├── icon_tv_small.png
│ ├── icon_tv_small_gray.png
│ ├── icon_tv_small_white.png
│ ├── shipin_shang.png
│ └── shipin_xia.png
│ ├── drawable
│ ├── bg_black_a10_selector.xml
│ ├── biz_video_bar_bg.9.png
│ ├── biz_video_progressbar.xml
│ ├── btn_exit_dlna_bg_bg.xml
│ ├── dlna_tv_btn_bg_selector.xml
│ └── video_format_switcher_bg.xml
│ ├── layout
│ ├── biz_video_media_controller.xml
│ ├── item_lv_main.xml
│ ├── super_vodeo_player_layout.xml
│ └── video_easy_switcher_layout.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colos.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── wkvideoplayer.iml
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | VideoPlayer
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AndroidVideoPlayer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 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 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #AndroidVideoPlayer
2 | >Notice:由于代码中的测试视频地址使用了我在七牛存储的视频,导致我的七牛空间下载流量大增,甚至一天5G多。所以我删除了相关视频,导致demo直接运行时无法播放视频的,各位找一个在线视频地址替换即可。
3 |
4 | ###Android Video Player , Like NetEaseNews Video Player.
5 | >Only Support mp4 & 3gp format
6 | >Support play at partial view & fullscreen
7 |
8 | ###Update Logs
9 | *1、Add DLNA Support*
10 | *2、Fix bugs*
11 |
12 |
13 | `Screenshots`
14 | ##NetEaseNews Player
15 | 
16 | ##Play At Part
17 | 
18 | ##Play Fullscreen
19 | 
20 |
--------------------------------------------------------------------------------
/VideoPlayer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.android.tedcoder.androidvideoplayer"
9 | minSdkVersion 10
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | lintOptions {
22 | abortOnError false
23 | }
24 | }
25 |
26 | dependencies {
27 | compile fileTree(dir: 'libs', include: ['*.jar'])
28 | compile project(':wkvideoplayer')
29 | compile 'com.android.support:appcompat-v7:22.2.1'
30 | }
31 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android_sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/android/tedcoder/androidvideoplayer/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.androidvideoplayer;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/tedcoder/androidvideoplayer/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.androidvideoplayer;
2 |
3 | import android.content.Intent;
4 | import android.content.pm.ActivityInfo;
5 | import android.content.res.Configuration;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.View;
9 | import android.view.WindowManager;
10 |
11 | import com.android.tedcoder.wkvideoplayer.dlna.engine.DLNAContainer;
12 | import com.android.tedcoder.wkvideoplayer.dlna.service.DLNAService;
13 | import com.android.tedcoder.wkvideoplayer.model.Video;
14 | import com.android.tedcoder.wkvideoplayer.model.VideoUrl;
15 | import com.android.tedcoder.wkvideoplayer.util.DensityUtil;
16 | import com.android.tedcoder.wkvideoplayer.view.MediaController;
17 | import com.android.tedcoder.wkvideoplayer.view.SuperVideoPlayer;
18 |
19 | import java.util.ArrayList;
20 |
21 |
22 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
23 | private SuperVideoPlayer mSuperVideoPlayer;
24 | private View mPlayBtnView;
25 |
26 | private SuperVideoPlayer.VideoPlayCallbackImpl mVideoPlayCallback = new SuperVideoPlayer.VideoPlayCallbackImpl() {
27 | @Override
28 | public void onCloseVideo() {
29 | mSuperVideoPlayer.close();
30 | mPlayBtnView.setVisibility(View.VISIBLE);
31 | mSuperVideoPlayer.setVisibility(View.GONE);
32 | resetPageToPortrait();
33 | }
34 |
35 | @Override
36 | public void onSwitchPageType() {
37 | if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
38 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
39 | mSuperVideoPlayer.setPageType(MediaController.PageType.SHRINK);
40 | } else {
41 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
42 | mSuperVideoPlayer.setPageType(MediaController.PageType.EXPAND);
43 | }
44 | }
45 |
46 | @Override
47 | public void onPlayFinish() {
48 |
49 | }
50 | };
51 |
52 | @Override
53 | public void onClick(View view) {
54 | mPlayBtnView.setVisibility(View.GONE);
55 | mSuperVideoPlayer.setVisibility(View.VISIBLE);
56 | mSuperVideoPlayer.setAutoHideController(false);
57 |
58 | Video video = new Video();
59 | VideoUrl videoUrl1 = new VideoUrl();
60 | videoUrl1.setFormatName("720P");
61 | videoUrl1.setFormatUrl("http://7xkbzx.com1.z0.glb.clouddn.com/SampleVideo_1080x720_20mb.mp4");
62 | VideoUrl videoUrl2 = new VideoUrl();
63 | videoUrl2.setFormatName("480P");
64 | videoUrl2.setFormatUrl("http://7xkbzx.com1.z0.glb.clouddn.com/SampleVideo_720x480_20mb.mp4");
65 | ArrayList arrayList1 = new ArrayList<>();
66 | arrayList1.add(videoUrl1);
67 | arrayList1.add(videoUrl2);
68 | video.setVideoName("测试视频一");
69 | video.setVideoUrl(arrayList1);
70 |
71 | Video video2 = new Video();
72 | VideoUrl videoUrl3 = new VideoUrl();
73 | videoUrl3.setFormatName("720P");
74 | videoUrl3.setFormatUrl("http://7xkbzx.com1.z0.glb.clouddn.com/SampleVideo_1080x720_10mb.mp4");
75 | VideoUrl videoUrl4 = new VideoUrl();
76 | videoUrl4.setFormatName("480P");
77 | videoUrl4.setFormatUrl("http://7xkbzx.com1.z0.glb.clouddn.com/SampleVideo_720x480_10mb.mp4");
78 | ArrayList arrayList2 = new ArrayList<>();
79 | arrayList2.add(videoUrl3);
80 | arrayList2.add(videoUrl4);
81 | video2.setVideoName("测试视频二");
82 | video2.setVideoUrl(arrayList2);
83 |
84 | ArrayList videoArrayList = new ArrayList<>();
85 | videoArrayList.add(video);
86 | videoArrayList.add(video2);
87 |
88 | mSuperVideoPlayer.loadMultipleVideo(videoArrayList,0,0,0);
89 | }
90 |
91 | @Override
92 | protected void onDestroy() {
93 | super.onDestroy();
94 | stopDLNAService();
95 | }
96 |
97 | /***
98 | * 旋转屏幕之后回调
99 | *
100 | * @param newConfig newConfig
101 | */
102 | @Override
103 | public void onConfigurationChanged(Configuration newConfig) {
104 | super.onConfigurationChanged(newConfig);
105 | if (null == mSuperVideoPlayer) return;
106 | /***
107 | * 根据屏幕方向重新设置播放器的大小
108 | */
109 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
110 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
111 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
112 | getWindow().getDecorView().invalidate();
113 | float height = DensityUtil.getWidthInPx(this);
114 | float width = DensityUtil.getHeightInPx(this);
115 | mSuperVideoPlayer.getLayoutParams().height = (int) width;
116 | mSuperVideoPlayer.getLayoutParams().width = (int) height;
117 | } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
118 | final WindowManager.LayoutParams attrs = getWindow().getAttributes();
119 | attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
120 | getWindow().setAttributes(attrs);
121 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
122 | float width = DensityUtil.getWidthInPx(this);
123 | float height = DensityUtil.dip2px(this, 200.f);
124 | mSuperVideoPlayer.getLayoutParams().height = (int) height;
125 | mSuperVideoPlayer.getLayoutParams().width = (int) width;
126 | }
127 | }
128 |
129 |
130 | @Override
131 | protected void onCreate(Bundle savedInstanceState) {
132 | super.onCreate(savedInstanceState);
133 | setContentView(R.layout.activity_main);
134 | mSuperVideoPlayer = (SuperVideoPlayer) findViewById(R.id.video_player_item_1);
135 | mPlayBtnView = findViewById(R.id.play_btn);
136 | mPlayBtnView.setOnClickListener(this);
137 | mSuperVideoPlayer.setVideoPlayCallback(mVideoPlayCallback);
138 | startDLNAService();
139 | }
140 |
141 | /***
142 | * 恢复屏幕至竖屏
143 | */
144 | private void resetPageToPortrait() {
145 | if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
146 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
147 | mSuperVideoPlayer.setPageType(MediaController.PageType.SHRINK);
148 | }
149 | }
150 |
151 | private void startDLNAService() {
152 | // Clear the device container.
153 | DLNAContainer.getInstance().clear();
154 | Intent intent = new Intent(getApplicationContext(), DLNAService.class);
155 | startService(intent);
156 | }
157 |
158 | private void stopDLNAService() {
159 | Intent intent = new Intent(getApplicationContext(), DLNAService.class);
160 | stopService(intent);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0dp
4 | 0dp
5 |
6 |
7 | 0dp
8 | 2dp
9 | 4dp
10 | 48dp
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | VideoPlayer
3 |
4 | Hello world!
5 | Settings
6 | Impossible to play the video.
7 | Impossible to play the progressive video.
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | mavenCentral()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Mon Sep 07 18:34:32 CST 2015
16 | systemProp.http.proxyHost=127.0.0.1
17 | systemProp.http.proxyPort=1080
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/img/Screenshot_20151028-195103.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/img/Screenshot_20151028-195103.png
--------------------------------------------------------------------------------
/img/Screenshot_20151028-195113.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/img/Screenshot_20151028-195113.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':wkvideoplayer'
3 |
--------------------------------------------------------------------------------
/wkvideoplayer/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/wkvideoplayer/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 10
9 | targetSdkVersion 21
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | lintOptions {
22 | abortOnError false
23 | }
24 | }
25 |
26 | dependencies {
27 | compile fileTree(dir: 'libs', include: ['*.jar'])
28 | }
29 |
--------------------------------------------------------------------------------
/wkvideoplayer/libs/clink210.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/libs/clink210.jar
--------------------------------------------------------------------------------
/wkvideoplayer/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android_sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/androidTest/java/com/android/tedcoder/wkvideoplayer/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.wkvideoplayer;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/engine/DLNAContainer.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.engine;
19 |
20 | import com.android.tedcoder.wkvideoplayer.dlna.util.DLNAUtil;
21 | import com.android.tedcoder.wkvideoplayer.dlna.util.LogUtil;
22 |
23 | import org.cybergarage.upnp.Device;
24 |
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | public class DLNAContainer {
29 | private List mDevices;
30 | private Device mSelectedDevice;
31 | private DeviceChangeListener mDeviceChangeListener;
32 | private static final DLNAContainer mDLNAContainer = new DLNAContainer();
33 | private static final String TAG = "DLNAContainer";
34 |
35 | private DLNAContainer() {
36 | mDevices = new ArrayList();
37 | }
38 |
39 | public static DLNAContainer getInstance() {
40 | return mDLNAContainer;
41 | }
42 |
43 | public synchronized void addDevice(Device d) {
44 | if (!DLNAUtil.isMediaRenderDevice(d))
45 | return;
46 | int size = mDevices.size();
47 | for (int i = 0; i < size; i++) {
48 | String udnString = mDevices.get(i).getUDN();
49 | if (d.getUDN().equalsIgnoreCase(udnString)) {
50 | return;
51 | }
52 | }
53 |
54 | mDevices.add(d);
55 | LogUtil.d(TAG, "Devices add a device" + d.getDeviceType());
56 | if (mDeviceChangeListener != null) {
57 | mDeviceChangeListener.onDeviceChange(d);
58 | }
59 | }
60 |
61 | public synchronized void removeDevice(Device d) {
62 | if (!DLNAUtil.isMediaRenderDevice(d)) {
63 | return;
64 | }
65 | int size = mDevices.size();
66 | for (int i = 0; i < size; i++) {
67 | String udnString = mDevices.get(i).getUDN();
68 | if (d.getUDN().equalsIgnoreCase(udnString)) {
69 | Device device = mDevices.remove(i);
70 | LogUtil.d(TAG, "Devices remove a device");
71 |
72 | boolean ret = false;
73 | if (mSelectedDevice != null) {
74 | ret = mSelectedDevice.getUDN().equalsIgnoreCase(
75 | device.getUDN());
76 | }
77 | if (ret) {
78 | mSelectedDevice = null;
79 | }
80 | if (mDeviceChangeListener != null) {
81 | mDeviceChangeListener.onDeviceChange(d);
82 | }
83 | break;
84 | }
85 | }
86 | }
87 |
88 | public synchronized void clear() {
89 | if (mDevices != null) {
90 | mDevices.clear();
91 | mSelectedDevice = null;
92 | }
93 | }
94 |
95 | public Device getSelectedDevice() {
96 | return mSelectedDevice;
97 | }
98 |
99 | public void setSelectedDevice(Device mSelectedDevice) {
100 | this.mSelectedDevice = mSelectedDevice;
101 | }
102 |
103 | public void setDeviceChangeListener(
104 | DeviceChangeListener deviceChangeListener) {
105 | mDeviceChangeListener = deviceChangeListener;
106 | }
107 |
108 | public List getDevices() {
109 | return mDevices;
110 | }
111 |
112 | public interface DeviceChangeListener {
113 | void onDeviceChange(Device device);
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/engine/MultiPointController.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.engine;
19 |
20 | import android.text.TextUtils;
21 | import org.cybergarage.upnp.Action;
22 | import org.cybergarage.upnp.Device;
23 | import org.cybergarage.upnp.Service;
24 | import com.android.tedcoder.wkvideoplayer.dlna.inter.IController;
25 |
26 |
27 | public class MultiPointController implements IController {
28 | private static final String AVTransport1 = "urn:schemas-upnp-org:service:AVTransport:1";
29 | private static final String SetAVTransportURI = "SetAVTransportURI";
30 | private static final String RenderingControl = "urn:schemas-upnp-org:service:RenderingControl:1";
31 | private static final String Play = "Play";
32 |
33 | @Override
34 | public boolean play(Device device, String path) {
35 | Service service = device.getService(AVTransport1);
36 |
37 | if (service == null) {
38 | return false;
39 | }
40 |
41 | final Action action = service.getAction(SetAVTransportURI);
42 | if (action == null) {
43 | return false;
44 | }
45 |
46 | final Action playAction = service.getAction(Play);
47 | if (playAction == null) {
48 | return false;
49 | }
50 |
51 | if (TextUtils.isEmpty(path)) {
52 | return false;
53 | }
54 |
55 | action.setArgumentValue("InstanceID", 0);
56 | action.setArgumentValue("CurrentURI", path);
57 | action.setArgumentValue("CurrentURIMetaData", 0);
58 | if (!action.postControlAction()) {
59 | return false;
60 | }
61 |
62 | playAction.setArgumentValue("InstanceID", 0);
63 | playAction.setArgumentValue("Speed", "1");
64 | return playAction.postControlAction();
65 | }
66 |
67 | @Override
68 | public boolean goon(Device device, String pausePosition) {
69 |
70 | Service localService = device.getService(AVTransport1);
71 | if (localService == null)
72 | return false;
73 |
74 | final Action localAction = localService.getAction("Seek");
75 | if (localAction == null)
76 | return false;
77 | localAction.setArgumentValue("InstanceID", "0");
78 | // if (mUseRelTime) {
79 | // } else {
80 | // localAction.setArgumentValue("Unit", "ABS_TIME");
81 | // }
82 | // LogUtil.e(tag, "继续相对时间:"+mUseRelTime);
83 | // 测试解决播放暂停后时间不准确
84 | localAction.setArgumentValue("Unit", "ABS_TIME");
85 | localAction.setArgumentValue("Target", pausePosition);
86 | localAction.postControlAction();
87 |
88 | Action playAction = localService.getAction("Play");
89 | if (playAction == null) {
90 | return false;
91 | }
92 |
93 | playAction.setArgumentValue("InstanceID", 0);
94 | playAction.setArgumentValue("Speed", "1");
95 | return playAction.postControlAction();
96 | }
97 |
98 | @Override
99 | public String getTransportState(Device device) {
100 | Service localService = device.getService(AVTransport1);
101 | if (localService == null) {
102 | return null;
103 | }
104 |
105 | final Action localAction = localService.getAction("GetTransportInfo");
106 | if (localAction == null) {
107 | return null;
108 | }
109 |
110 | localAction.setArgumentValue("InstanceID", "0");
111 |
112 | if (localAction.postControlAction()) {
113 | return localAction.getArgumentValue("CurrentTransportState");
114 | } else {
115 | return null;
116 | }
117 | }
118 |
119 | public String getVolumeDbRange(Device device, String argument) {
120 | Service localService = device.getService(RenderingControl);
121 | if (localService == null) {
122 | return null;
123 | }
124 | Action localAction = localService.getAction("GetVolumeDBRange");
125 | if (localAction == null) {
126 | return null;
127 | }
128 | localAction.setArgumentValue("InstanceID", "0");
129 | localAction.setArgumentValue("Channel", "Master");
130 | if (!localAction.postControlAction()) {
131 | return null;
132 | } else {
133 | return localAction.getArgumentValue(argument);
134 | }
135 | }
136 |
137 | @Override
138 | public int getMinVolumeValue(Device device) {
139 | String minValue = getVolumeDbRange(device, "MinValue");
140 | if (TextUtils.isEmpty(minValue)) {
141 | return 0;
142 | }
143 | return Integer.parseInt(minValue);
144 | }
145 |
146 | @Override
147 | public int getMaxVolumeValue(Device device) {
148 | String maxValue = getVolumeDbRange(device, "MaxValue");
149 | if (TextUtils.isEmpty(maxValue)) {
150 | return 100;
151 | }
152 | return Integer.parseInt(maxValue);
153 | }
154 |
155 | @Override
156 | public boolean seek(Device device, String targetPosition) {
157 | Service localService = device.getService(AVTransport1);
158 | if (localService == null)
159 | return false;
160 |
161 | Action localAction = localService.getAction("Seek");
162 | if (localAction == null) {
163 | return false;
164 | }
165 | localAction.setArgumentValue("InstanceID", "0");
166 | // if (mUseRelTime) {
167 | // localAction.setArgumentValue("Unit", "REL_TIME");
168 | // } else {
169 | localAction.setArgumentValue("Unit", "ABS_TIME");
170 | // }
171 | localAction.setArgumentValue("Target", targetPosition);
172 | boolean postControlAction = localAction.postControlAction();
173 | if (!postControlAction) {
174 | localAction.setArgumentValue("Unit", "REL_TIME");
175 | localAction.setArgumentValue("Target", targetPosition);
176 | return localAction.postControlAction();
177 | } else {
178 | return postControlAction;
179 | }
180 |
181 | }
182 |
183 | @Override
184 | public String getPositionInfo(Device device) {
185 | Service localService = device.getService(AVTransport1);
186 |
187 | if (localService == null)
188 | return null;
189 |
190 | final Action localAction = localService.getAction("GetPositionInfo");
191 | if (localAction == null) {
192 | return null;
193 | }
194 |
195 | localAction.setArgumentValue("InstanceID", "0");
196 | boolean isSuccess = localAction.postControlAction();
197 | if (isSuccess) {
198 | return localAction.getArgumentValue("AbsTime");
199 | } else {
200 | return null;
201 | }
202 | }
203 |
204 | @Override
205 | public String getMediaDuration(Device device) {
206 | Service localService = device.getService(AVTransport1);
207 | if (localService == null) {
208 | return null;
209 | }
210 |
211 | final Action localAction = localService.getAction("GetMediaInfo");
212 | if (localAction == null) {
213 | return null;
214 | }
215 |
216 | localAction.setArgumentValue("InstanceID", "0");
217 | if (localAction.postControlAction()) {
218 | return localAction.getArgumentValue("MediaDuration");
219 | } else {
220 | return null;
221 | }
222 |
223 | }
224 |
225 | @Override
226 | public boolean setMute(Device mediaRenderDevice, String targetValue) {
227 | Service service = mediaRenderDevice.getService(RenderingControl);
228 | if (service == null) {
229 | return false;
230 | }
231 | final Action action = service.getAction("SetMute");
232 | if (action == null) {
233 | return false;
234 | }
235 |
236 | action.setArgumentValue("InstanceID", "0");
237 | action.setArgumentValue("Channel", "Master");
238 | action.setArgumentValue("DesiredMute", targetValue);
239 | return action.postControlAction();
240 | }
241 |
242 | @Override
243 | public String getMute(Device device) {
244 | Service service = device.getService(RenderingControl);
245 | if (service == null) {
246 | return null;
247 | }
248 |
249 | final Action getAction = service.getAction("GetMute");
250 | if (getAction == null) {
251 | return null;
252 | }
253 | getAction.setArgumentValue("InstanceID", "0");
254 | getAction.setArgumentValue("Channel", "Master");
255 | getAction.postControlAction();
256 | return getAction.getArgumentValue("CurrentMute");
257 | }
258 |
259 | @Override
260 | public boolean setVoice(Device device, int value) {
261 | Service service = device.getService(RenderingControl);
262 | if (service == null) {
263 | return false;
264 | }
265 |
266 | final Action action = service.getAction("SetVolume");
267 | if (action == null) {
268 | return false;
269 | }
270 |
271 | action.setArgumentValue("InstanceID", "0");
272 | action.setArgumentValue("Channel", "Master");
273 | action.setArgumentValue("DesiredVolume", value);
274 | return action.postControlAction();
275 |
276 | }
277 |
278 | @Override
279 | public int getVoice(Device device) {
280 | Service service = device.getService(RenderingControl);
281 | if (service == null) {
282 | return -1;
283 | }
284 |
285 | final Action getAction = service.getAction("GetVolume");
286 | if (getAction == null) {
287 | return -1;
288 | }
289 | getAction.setArgumentValue("InstanceID", "0");
290 | getAction.setArgumentValue("Channel", "Master");
291 | if (getAction.postControlAction()) {
292 | return getAction.getArgumentIntegerValue("CurrentVolume");
293 | } else {
294 | return -1;
295 | }
296 |
297 | }
298 |
299 | @Override
300 | public boolean stop(Device device) {
301 | Service service = device.getService(AVTransport1);
302 |
303 | if (service == null) {
304 | return false;
305 | }
306 | final Action stopAction = service.getAction("Stop");
307 | if (stopAction == null) {
308 | return false;
309 | }
310 |
311 | stopAction.setArgumentValue("InstanceID", 0);
312 | return stopAction.postControlAction();
313 |
314 | }
315 |
316 | @Override
317 | public boolean pause(Device mediaRenderDevice) {
318 |
319 | Service service = mediaRenderDevice.getService(AVTransport1);
320 | if (service == null) {
321 | return false;
322 | }
323 | final Action pauseAction = service.getAction("Pause");
324 | if (pauseAction == null) {
325 | return false;
326 | }
327 | pauseAction.setArgumentValue("InstanceID", 0);
328 | return pauseAction.postControlAction();
329 | }
330 |
331 | }
332 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/engine/SearchThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.engine;
19 |
20 | import com.android.tedcoder.wkvideoplayer.dlna.util.LogUtil;
21 |
22 | import org.cybergarage.upnp.ControlPoint;
23 | import org.cybergarage.upnp.Device;
24 | import org.cybergarage.upnp.device.DeviceChangeListener;
25 |
26 | /**
27 | * A thread to search the devices all the time.
28 | *
29 | * @author CharonChui
30 | */
31 | public class SearchThread extends Thread {
32 | private boolean flag = true;
33 | private ControlPoint mControlPoint;
34 | private boolean mStartComplete;
35 | private int mSearchTimes;
36 | private static final int mFastInternalTime = 15000;
37 | private static final int mNormalInternalTime = 3600000;
38 | private static final String TAG = "SearchThread";
39 |
40 | public SearchThread(ControlPoint mControlPoint) {
41 | super();
42 | this.mControlPoint = mControlPoint;
43 | this.mControlPoint.addDeviceChangeListener(mDeviceChangeListener);
44 | }
45 |
46 | @Override
47 | public void run() {
48 | while (flag) {
49 | if (mControlPoint == null) {
50 | break;
51 | }
52 | searchDevices();
53 | }
54 | }
55 |
56 | /**
57 | * Search for the DLNA devices.
58 | */
59 | private void searchDevices() {
60 | try {
61 | if (mStartComplete) {
62 | mControlPoint.search();
63 | LogUtil.d(TAG, "controlpoint search...");
64 | } else {
65 | mControlPoint.stop();
66 | boolean startRet = mControlPoint.start();
67 | LogUtil.d(TAG, "controlpoint start:" + startRet);
68 | if (startRet) {
69 | mStartComplete = true;
70 | }
71 | }
72 | } catch (Exception e) {
73 | e.printStackTrace();
74 | }
75 | // Search the devices five times fast, and after that we can make it
76 | // search lowly to save the power.
77 | synchronized (this) {
78 | try {
79 | mSearchTimes++;
80 | if (mSearchTimes >= 5) {
81 | wait(mNormalInternalTime);
82 | } else {
83 | wait(mFastInternalTime);
84 | }
85 | } catch (Exception e) {
86 | e.printStackTrace();
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * Set the search times, set this to 0 to make it search fast.
93 | *
94 | * @param searchTimes
95 | * The times we have searched.
96 | */
97 | public synchronized void setSearchTimes(int searchTimes) {
98 | this.mSearchTimes = searchTimes;
99 | }
100 |
101 | /**
102 | * Notify all the thread.
103 | */
104 | public void awake() {
105 | synchronized (this) {
106 | notifyAll();
107 | }
108 | }
109 |
110 | /**
111 | * Stop the thread, if quit this application we should use this method to
112 | * stop the thread.
113 | */
114 | public void stopThread() {
115 | flag = false;
116 | awake();
117 | }
118 |
119 | private DeviceChangeListener mDeviceChangeListener = new DeviceChangeListener() {
120 |
121 | @Override
122 | public void deviceRemoved(Device dev) {
123 | LogUtil.d(TAG, "control point remove a device");
124 | DLNAContainer.getInstance().removeDevice(dev);
125 | }
126 |
127 | @Override
128 | public void deviceAdded(Device dev) {
129 | LogUtil.d(TAG, "control point add a device..." + dev.getDeviceType() + dev.getFriendlyName());
130 | DLNAContainer.getInstance().addDevice(dev);
131 | }
132 | };
133 | }
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/inter/IController.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.inter;
19 |
20 | import org.cybergarage.upnp.Device;
21 |
22 | public interface IController {
23 |
24 | /**
25 | * Play the video with the video path.
26 | *
27 | * @param device
28 | * The device be controlled.
29 | * @param path
30 | * The path of the video.
31 | * @return If is success to play the video.
32 | */
33 | boolean play(Device device, String path);
34 |
35 | /**
36 | * Go on playing the video from the position.
37 | *
38 | * @param device
39 | * The device be controlled.
40 | * @param pausePosition
41 | * The format must be 00:00:00.
42 | */
43 | boolean goon(Device device, String pausePosition);
44 |
45 | /**
46 | * All the state is "STOPPED" // "PLAYING" // "TRANSITIONING"//
47 | * "PAUSED_PLAYBACK"// "PAUSED_RECORDING"// "RECORDING" //
48 | * "NO_MEDIA_PRESENT//
49 | */
50 | String getTransportState(Device device);
51 |
52 | /**
53 | * Get the min volume value,this must be 0.
54 | *
55 | * @param device
56 | * @return
57 | */
58 | int getMinVolumeValue(Device device);
59 |
60 | /**
61 | * Get the max volume value, usually it is 100.
62 | *
63 | * @param device
64 | * The device be controlled.
65 | * @return The max volume value.
66 | */
67 | int getMaxVolumeValue(Device device);
68 |
69 | /**
70 | * Seek the playing video to a target position.
71 | *
72 | * @param device
73 | * The device be controlled.
74 | * @param targetPosition
75 | * Target position we want to set.
76 | * @return
77 | */
78 | boolean seek(Device device, String targetPosition);
79 |
80 | /**
81 | * Get the current playing position of the video.
82 | *
83 | * @param device
84 | * The device be controlled.
85 | * @return Current playing position is 00:00:00
86 | */
87 | String getPositionInfo(Device device);
88 |
89 | /**
90 | * Get the duration of the video playing.
91 | *
92 | * @param device
93 | * The device be controlled.
94 | * @return The media duration like 00:00:00,if get failed it will return
95 | * null.
96 | */
97 | String getMediaDuration(Device device);
98 |
99 | /**
100 | * Mute the device or not.
101 | *
102 | * @param device
103 | * The device be controlled.
104 | * @param targetValue
105 | * 1 is that want mute, 0 if you want make it off of mute.
106 | * @return If is success to mute the device.
107 | */
108 | boolean setMute(Device device, String targetValue);
109 |
110 | /**
111 | * Get if the device is mute.
112 | *
113 | * @param device
114 | * The device be controlled.
115 | * @return 1 is mute, otherwise will return 0.
116 | */
117 | String getMute(Device device);
118 |
119 | /**
120 | * Set the device's voice.
121 | *
122 | * @param device
123 | * The device be controlled.
124 | * @param value
125 | * Target voice want be set.
126 | * @return
127 | */
128 | boolean setVoice(Device device, int value);
129 |
130 | /**
131 | * Get the current voice of the device.
132 | *
133 | * @param device
134 | * The device be controlled.
135 | * @return Current voice.
136 | */
137 | int getVoice(Device device);
138 |
139 | /**
140 | * Stop to play.
141 | *
142 | * @param device
143 | * The device to controlled.
144 | * @return If if success to stop the video.
145 | */
146 | boolean stop(Device device);
147 |
148 | /**
149 | * Pause the playing video.
150 | *
151 | * @param device
152 | * The device to controlled.
153 | * @return If if success to pause the video.
154 | */
155 | boolean pause(Device device);
156 | }
157 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/service/DLNAService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.service;
19 |
20 | import android.app.Service;
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.IntentFilter;
25 | import android.net.ConnectivityManager;
26 | import android.net.wifi.WifiManager;
27 | import android.os.Bundle;
28 | import android.os.IBinder;
29 |
30 |
31 | import com.android.tedcoder.wkvideoplayer.dlna.engine.SearchThread;
32 | import com.android.tedcoder.wkvideoplayer.dlna.util.LogUtil;
33 |
34 | import org.cybergarage.upnp.ControlPoint;
35 |
36 | /**
37 | * The service to search the DLNA Device in background all the time.
38 | *
39 | * @author CharonChui
40 | *
41 | */
42 | public class DLNAService extends Service {
43 | private static final String TAG = "DLNAService";
44 | private ControlPoint mControlPoint;
45 | private SearchThread mSearchThread;
46 | private WifiStateReceiver mWifiStateReceiver;
47 |
48 | @Override
49 | public IBinder onBind(Intent intent) {
50 | return null;
51 | }
52 |
53 | @Override
54 | public void onCreate() {
55 | super.onCreate();
56 | init();
57 | }
58 |
59 | @Override
60 | public void onDestroy() {
61 | super.onDestroy();
62 | unInit();
63 | }
64 |
65 | @Override
66 | public int onStartCommand(Intent intent, int flags, int startId) {
67 | startThread();
68 | return super.onStartCommand(intent, flags, startId);
69 | }
70 |
71 | private void init() {
72 | mControlPoint = new ControlPoint();
73 | mSearchThread = new SearchThread(mControlPoint);
74 | registerWifiStateReceiver();
75 | }
76 |
77 | private void unInit() {
78 | stopThread();
79 | unregisterWifiStateReceiver();
80 | }
81 |
82 | /**
83 | * Make the thread start to search devices.
84 | */
85 | private void startThread() {
86 | if (mSearchThread != null) {
87 | LogUtil.d(TAG, "thread is not null");
88 | mSearchThread.setSearchTimes(0);
89 | } else {
90 | LogUtil.d(TAG, "thread is null, create a new thread");
91 | mSearchThread = new SearchThread(mControlPoint);
92 | }
93 |
94 | if (mSearchThread.isAlive()) {
95 | LogUtil.d(TAG, "thread is alive");
96 | mSearchThread.awake();
97 | } else {
98 | LogUtil.d(TAG, "start the thread");
99 | mSearchThread.start();
100 | }
101 | }
102 |
103 | private void stopThread() {
104 | if (mSearchThread != null) {
105 | mSearchThread.stopThread();
106 | mControlPoint.stop();
107 | mSearchThread = null;
108 | mControlPoint = null;
109 | LogUtil.w(TAG, "stop dlna service");
110 | }
111 | }
112 |
113 | private void registerWifiStateReceiver() {
114 | if (mWifiStateReceiver == null) {
115 | mWifiStateReceiver = new WifiStateReceiver();
116 | registerReceiver(mWifiStateReceiver, new IntentFilter(
117 | ConnectivityManager.CONNECTIVITY_ACTION));
118 | }
119 | }
120 |
121 | private void unregisterWifiStateReceiver() {
122 | if (mWifiStateReceiver != null) {
123 | unregisterReceiver(mWifiStateReceiver);
124 | mWifiStateReceiver = null;
125 | }
126 | }
127 |
128 | private class WifiStateReceiver extends BroadcastReceiver {
129 | @Override
130 | public void onReceive(Context c, Intent intent) {
131 | Bundle bundle = intent.getExtras();
132 | int statusInt = bundle.getInt("wifi_state");
133 | switch (statusInt) {
134 | case WifiManager.WIFI_STATE_UNKNOWN:
135 | break;
136 | case WifiManager.WIFI_STATE_ENABLING:
137 | break;
138 | case WifiManager.WIFI_STATE_ENABLED:
139 | LogUtil.e(TAG, "wifi enable");
140 | startThread();
141 | break;
142 | case WifiManager.WIFI_STATE_DISABLING:
143 | break;
144 | case WifiManager.WIFI_STATE_DISABLED:
145 | LogUtil.e(TAG, "wifi disabled");
146 | break;
147 | default:
148 | break;
149 | }
150 | }
151 | }
152 |
153 | }
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/util/DLNAUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.util;
19 |
20 | import org.cybergarage.upnp.Device;
21 |
22 | public class DLNAUtil {
23 | private static final String MEDIARENDER = "urn:schemas-upnp-org:device:MediaRenderer:1";
24 |
25 | /**
26 | * Check if the device is a media render device
27 | *
28 | * @param device
29 | * @return
30 | */
31 | public static boolean isMediaRenderDevice(Device device) {
32 | if (device != null
33 | && MEDIARENDER.equalsIgnoreCase(device.getDeviceType())) {
34 | return true;
35 | }
36 |
37 | return false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/util/LogUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.util;
19 |
20 | import android.util.Log;
21 |
22 | /**
23 | * Log utilities that can control whether print the log.
24 | */
25 | public class LogUtil {
26 | private static final int LOG_LEVEL = 6;
27 |
28 | private static final int VERBOSE = 5;
29 | private static final int DEBUG = 4;
30 | private static final int INFO = 3;
31 | private static final int WARN = 2;
32 | private static final int ERROR = 1;
33 |
34 | public static void v(String tag, String msg) {
35 | if (LOG_LEVEL > VERBOSE) {
36 | Log.v(tag, msg);
37 | }
38 | }
39 |
40 | public static void d(String tag, String msg) {
41 | if (LOG_LEVEL > DEBUG) {
42 | Log.d(tag, msg);
43 | }
44 | }
45 |
46 | public static void i(String tag, String msg) {
47 | if (LOG_LEVEL > INFO) {
48 | Log.i(tag, msg);
49 | }
50 | }
51 |
52 | public static void w(String tag, String msg) {
53 | if (LOG_LEVEL > WARN) {
54 | Log.w(tag, msg);
55 | }
56 | }
57 |
58 | public static void e(String tag, String msg) {
59 | if (LOG_LEVEL > ERROR) {
60 | Log.e(tag, msg);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/dlna/util/NetUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.dlna.util;
19 |
20 | import android.content.Context;
21 | import android.net.ConnectivityManager;
22 | import android.net.NetworkInfo;
23 | import android.net.wifi.WifiManager;
24 |
25 | /**
26 | * 网络连接的一些工具类
27 | */
28 | public class NetUtil {
29 |
30 | /**
31 | * 判断当前网络是否可用
32 | */
33 | public static boolean isNetAvailable(Context context) {
34 | ConnectivityManager connectivityManager = (ConnectivityManager) context
35 | .getSystemService(Context.CONNECTIVITY_SERVICE);
36 | NetworkInfo activeNetworkInfo = connectivityManager
37 | .getActiveNetworkInfo();
38 | return activeNetworkInfo != null && activeNetworkInfo.isAvailable();
39 | }
40 |
41 | /**
42 | * 判断WIFI是否使用
43 | */
44 | public static boolean isWIFIActivate(Context context) {
45 | return ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
46 | .isWifiEnabled();
47 | }
48 |
49 | /**
50 | * 修改WIFI状态
51 | *
52 | * @param status
53 | * true为开启WIFI,false为关闭WIFI
54 | */
55 | public static void changeWIFIStatus(Context context, boolean status) {
56 | ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
57 | .setWifiEnabled(status);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/model/Video.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.model;
19 |
20 | import java.util.ArrayList;
21 |
22 | /**
23 | * Created by Ted on 2015/9/2.
24 | * 视频对象
25 | */
26 | public class Video {
27 | private String mVideoName;//视频名称 如房源视频、小区视频
28 | private ArrayList mVideoUrl;//视频的地址列表
29 |
30 | /***************请看注释***************************/
31 | private VideoUrl mPlayUrl;//当前正在播放的地址。 外界不用传
32 |
33 | public String getVideoName() {
34 | return mVideoName;
35 | }
36 |
37 | public void setVideoName(String videoName) {
38 | mVideoName = videoName;
39 | }
40 |
41 | public ArrayList getVideoUrl() {
42 | return mVideoUrl;
43 | }
44 |
45 | public void setVideoUrl(ArrayList videoUrl) {
46 | mVideoUrl = videoUrl;
47 | }
48 |
49 | public VideoUrl getPlayUrl() {
50 | return mPlayUrl;
51 | }
52 |
53 | public void setPlayUrl(VideoUrl playUrl) {
54 | mPlayUrl = playUrl;
55 | }
56 |
57 | public void setPlayUrl(int position){
58 | if(position < 0 || position >= mVideoUrl.size())return;
59 | setPlayUrl(mVideoUrl.get(position));
60 | }
61 |
62 | public boolean equal(Video video){
63 | if(null != video){
64 | return mVideoName.equals(video.getVideoName());
65 | }
66 | return false;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/model/VideoUrl.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.model;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | /**
24 | * Created by Ted on 2015/9/2.
25 | */
26 | public class VideoUrl implements Parcelable {
27 | private String mFormatName;//视频格式名称,例如高清,标清,720P等等
28 | private String mFormatUrl;//视频Url
29 | private boolean isOnlineVideo = true;//是否在线视频 默认在线视频
30 |
31 | public String getFormatName() {
32 | return mFormatName;
33 | }
34 |
35 | public void setFormatName(String formatName) {
36 | mFormatName = formatName;
37 | }
38 |
39 | public String getFormatUrl() {
40 | return mFormatUrl;
41 | }
42 |
43 | public void setFormatUrl(String formatUrl) {
44 | mFormatUrl = formatUrl;
45 | }
46 |
47 | public boolean isOnlineVideo() {
48 | return isOnlineVideo;
49 | }
50 |
51 | public void setIsOnlineVideo(boolean isOnlineVideo) {
52 | this.isOnlineVideo = isOnlineVideo;
53 | }
54 |
55 | public boolean equal(VideoUrl url) {
56 | if (null != url) {
57 | return getFormatName().equals(url.getFormatName()) && getFormatUrl().equals(url.getFormatUrl());
58 | }
59 | return false;
60 | }
61 |
62 |
63 | @Override
64 | public int describeContents() {
65 | return 0;
66 | }
67 |
68 | public VideoUrl() {
69 | }
70 |
71 | public VideoUrl(Parcel source) {
72 | mFormatName = source.readString();
73 | mFormatUrl = source.readString();
74 | isOnlineVideo = source.readInt() == 1;
75 | }
76 |
77 |
78 | @Override
79 | public void writeToParcel(Parcel dest, int flags) {
80 | dest.writeString(mFormatName);
81 | dest.writeString(mFormatUrl);
82 | dest.writeInt(isOnlineVideo ? 1 : 0);
83 | }
84 |
85 |
86 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
87 |
88 | @Override
89 | public VideoUrl[] newArray(int size) {
90 | return new VideoUrl[size];
91 | }
92 |
93 | @Override
94 | public VideoUrl createFromParcel(Parcel source) {
95 | return new VideoUrl(source);
96 | }
97 | };
98 | }
99 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/util/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.wkvideoplayer.util;
2 |
3 | import android.content.Context;
4 |
5 | public class DensityUtil {
6 |
7 | public static final float getHeightInPx(Context context) {
8 | final float height = context.getResources().getDisplayMetrics().heightPixels;
9 | return height;
10 | }
11 |
12 | public static final float getWidthInPx(Context context) {
13 | final float width = context.getResources().getDisplayMetrics().widthPixels;
14 | return width;
15 | }
16 |
17 | public static final int getHeightInDp(Context context) {
18 | final float height = context.getResources().getDisplayMetrics().heightPixels;
19 | int heightInDp = px2dip(context, height);
20 | return heightInDp;
21 | }
22 |
23 | public static final int getWidthInDp(Context context) {
24 | final float height = context.getResources().getDisplayMetrics().heightPixels;
25 | int widthInDp = px2dip(context, height);
26 | return widthInDp;
27 | }
28 |
29 | public static int dip2px(Context context, float dpValue) {
30 | final float scale = context.getResources().getDisplayMetrics().density;
31 | return (int) (dpValue * scale + 0.5f);
32 | }
33 |
34 | public static int px2dip(Context context, float pxValue) {
35 | final float scale = context.getResources().getDisplayMetrics().density;
36 | return (int) (pxValue / scale + 0.5f);
37 | }
38 |
39 | public static int px2sp(Context context, float pxValue) {
40 | final float scale = context.getResources().getDisplayMetrics().density;
41 | return (int) (pxValue / scale + 0.5f);
42 | }
43 |
44 | public static int sp2px(Context context, float spValue) {
45 | final float scale = context.getResources().getDisplayMetrics().density;
46 | return (int) (spValue * scale + 0.5f);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/view/DeviceAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.view;
19 |
20 | import android.content.Context;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.widget.BaseAdapter;
24 | import android.widget.TextView;
25 |
26 | import com.android.tedcoder.wkvideoplayer.R;
27 |
28 | /**
29 | * Created by Ted on 2015/10/28.
30 | */
31 | class DeviceAdapter extends BaseAdapter {
32 | private Context mContext;
33 | private SuperVideoPlayer mSuperVideoPlayer;
34 |
35 | public DeviceAdapter(SuperVideoPlayer superVideoPlayer,Context context) {
36 | mSuperVideoPlayer = superVideoPlayer;
37 | mContext = context;
38 | }
39 |
40 | @Override
41 | public int getCount() {
42 | if (mSuperVideoPlayer.getDevices() == null) {
43 | return 0;
44 | } else {
45 | return mSuperVideoPlayer.getDevices().size();
46 | }
47 | }
48 |
49 | @Override
50 | public Object getItem(int position) {
51 | if (mSuperVideoPlayer.getDevices() != null) {
52 | return mSuperVideoPlayer.getDevices().get(position);
53 | }
54 |
55 | return null;
56 | }
57 |
58 | @Override
59 | public long getItemId(int position) {
60 | return position;
61 | }
62 |
63 | @Override
64 | public View getView(int position, View convertView, ViewGroup parent) {
65 | ViewHolder holder;
66 | if (convertView == null) {
67 | convertView = View.inflate(mContext,R.layout.item_lv_main, null);
68 | holder = new ViewHolder();
69 | convertView.setTag(holder);
70 | } else {
71 | holder = (ViewHolder) convertView.getTag();
72 | }
73 | holder.tv_name_item = (TextView) convertView
74 | .findViewById(R.id.tv_name_item);
75 | holder.tv_name_item.setText(mSuperVideoPlayer.getDevices().get(position)
76 | .getFriendlyName());
77 | return convertView;
78 | }
79 |
80 | static class ViewHolder {
81 | private TextView tv_name_item;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/view/EasySwitcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.view;
19 |
20 | import android.content.Context;
21 | import android.graphics.drawable.Drawable;
22 | import android.util.AttributeSet;
23 | import android.util.TypedValue;
24 | import android.view.Gravity;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.LinearLayout;
28 | import android.widget.TextView;
29 |
30 | import com.android.tedcoder.wkvideoplayer.R;
31 | import com.android.tedcoder.wkvideoplayer.util.DensityUtil;
32 |
33 | import java.util.ArrayList;
34 |
35 | /**
36 | * Created by Ted on 2015/9/1.
37 | * EasySwitcher
38 | */
39 | public class EasySwitcher extends LinearLayout{
40 | private final int NORMAL_ICON = R.drawable.shipin_shang;
41 | private final int SELECT_ICON = R.drawable.shipin_xia;
42 |
43 | private Context mContext;
44 | private LinearLayout mItemContainer;
45 | private TextView mSelectItemTxt;
46 | private ArrayList mAllItemArray;
47 | private int mDefaultSelection;
48 |
49 | private EasySwitcherCallbackImpl mEasySwitcherCallback;
50 |
51 |
52 |
53 | public EasySwitcher(Context context) {
54 | super(context);
55 | mContext = context;
56 | mAllItemArray = new ArrayList<>();
57 | mDefaultSelection = 0;
58 | initBaseView();
59 | }
60 |
61 | public EasySwitcher(Context context, AttributeSet attrs) {
62 | super(context, attrs);
63 | mContext = context;
64 | mAllItemArray = new ArrayList<>();
65 | mDefaultSelection = 0;
66 | initBaseView();
67 | }
68 |
69 | public EasySwitcher(Context context, AttributeSet attrs, int defStyleAttr) {
70 | super(context, attrs, defStyleAttr);
71 | mContext = context;
72 | mAllItemArray = new ArrayList<>();
73 | mDefaultSelection = 0;
74 | initBaseView();
75 | }
76 |
77 | private OnClickListener mItemOnClickListener = new OnClickListener() {
78 | @Override
79 | public void onClick(View v) {
80 | if(null != v && v instanceof TextView){
81 | int position = (int)v.getTag();
82 | String name = ((TextView)v).getText().toString();
83 | closeSwitchList();
84 | mSelectItemTxt.setText(name);
85 | setSelectItemStyle(false);
86 | mDefaultSelection = position;
87 | mEasySwitcherCallback.onSelectItem(position,name);
88 | }
89 | }
90 | };
91 |
92 | private OnClickListener mSelectItemOnClickListener = new OnClickListener() {
93 | @Override
94 | public void onClick(View v) {
95 | if(closeSwitchList()){
96 | return;
97 | }
98 | mEasySwitcherCallback.onShowList();
99 | showItemList();
100 | }
101 | };
102 |
103 | public void initData(ArrayList allItemArray){
104 | mAllItemArray.clear();
105 | mAllItemArray.addAll(allItemArray);
106 | updateSelectItem(0);
107 | }
108 |
109 | public void updateSelectItem(int selectPosition){
110 | if(null == mAllItemArray || selectPosition < 0 || selectPosition >= mAllItemArray.size())return;
111 | mDefaultSelection = selectPosition;
112 | mSelectItemTxt.setText(mAllItemArray.get(selectPosition));
113 | mItemContainer.removeAllViews();
114 | mSelectItemTxt.setSelected(false);
115 | }
116 |
117 | /***
118 | * 关闭弹出的选择列表
119 | * @return 是否消耗了执行事件。 如果没有,就代表没有列表不需要关闭
120 | */
121 | public boolean closeSwitchList(){
122 | if(mItemContainer.getChildCount() > 0){
123 | mItemContainer.removeAllViews();
124 | setSelectItemStyle(false);
125 | return true;
126 | }
127 | return false;
128 | }
129 |
130 |
131 | private void showItemList(){
132 | setSelectItemStyle(true);
133 | mItemContainer.removeAllViews();
134 | for(int i = 0;i < mAllItemArray.size();i++){
135 | mItemContainer.addView(getItemView(i));
136 | mItemContainer.addView(getDividerView());
137 | }
138 | }
139 |
140 | private void initBaseView(){
141 | View.inflate(mContext, R.layout.video_easy_switcher_layout, this);
142 | mItemContainer = (LinearLayout)findViewById(R.id.switcher_item_container);
143 | mSelectItemTxt = (TextView)findViewById(R.id.switcher_select);
144 | setSelected(false);
145 | mSelectItemTxt.setOnClickListener(mSelectItemOnClickListener);
146 | }
147 |
148 | private void setSelectItemStyle(boolean isSelect){
149 | mSelectItemTxt.setSelected(isSelect);
150 | Drawable rightDrawable = mContext.getResources().getDrawable(isSelect?SELECT_ICON:NORMAL_ICON);
151 | if (null != rightDrawable)
152 | rightDrawable.setBounds(0, 0, rightDrawable.getMinimumWidth(), rightDrawable.getMinimumHeight());
153 | mSelectItemTxt.setCompoundDrawables(null, null, rightDrawable, null);
154 | }
155 |
156 | private View getItemView(int position){
157 | TextView textView = new TextView(mContext);
158 | textView.setTextAppearance(mContext, R.style.switcher_item_text_style);
159 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
160 | DensityUtil.dip2px(mContext,35));
161 | textView.setLayoutParams(layoutParams);
162 | textView.setSelected(position == mDefaultSelection);
163 | textView.setGravity(Gravity.CENTER);
164 | textView.setText(mAllItemArray.get(position));
165 | textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12.0f);
166 | textView.setOnClickListener(mItemOnClickListener);
167 | textView.setTag(position);
168 | return textView;
169 | }
170 |
171 | private View getDividerView(){
172 | View view = new View(mContext);
173 | view.setBackgroundColor(mContext.getResources().getColor(R.color.divider_color));
174 | view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,3));
175 | return view;
176 | }
177 |
178 | public void setEasySwitcherCallback(EasySwitcherCallbackImpl easySwitcherCallback) {
179 | mEasySwitcherCallback = easySwitcherCallback;
180 | }
181 |
182 | public interface EasySwitcherCallbackImpl{
183 | void onSelectItem(int position,String name);
184 |
185 | void onShowList();
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/view/MediaController.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.wkvideoplayer.view;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.widget.FrameLayout;
8 | import android.widget.ImageView;
9 | import android.widget.SeekBar;
10 | import android.widget.TextView;
11 |
12 | import com.android.tedcoder.wkvideoplayer.R;
13 | import com.android.tedcoder.wkvideoplayer.model.Video;
14 | import com.android.tedcoder.wkvideoplayer.model.VideoUrl;
15 |
16 | import java.text.DateFormat;
17 | import java.text.SimpleDateFormat;
18 | import java.util.ArrayList;
19 | import java.util.Date;
20 |
21 | /**
22 | * Created by Ted on 2015/8/4.
23 | * MediaController
24 | */
25 | public class MediaController extends FrameLayout implements SeekBar.OnSeekBarChangeListener, View.OnClickListener {
26 | private ImageView mPlayImg;//播放按钮
27 | private SeekBar mProgressSeekBar;//播放进度条
28 | private TextView mTimeTxt;//播放时间
29 | private ImageView mExpandImg;//最大化播放按钮
30 | private ImageView mShrinkImg;//缩放播放按钮
31 | private EasySwitcher mVideoSrcSwitcher;//视频源切换器
32 | private EasySwitcher mVideoFormatSwitcher;//视频清晰度切换器
33 | private View mMenuView;
34 | private View mMenuViewPlaceHolder;
35 |
36 | private MediaControlImpl mMediaControl;
37 |
38 | @Override
39 | public void onProgressChanged(SeekBar seekBar, int progress, boolean isFromUser) {
40 | if (isFromUser)
41 | mMediaControl.onProgressTurn(ProgressState.DOING, progress);
42 | }
43 |
44 | @Override
45 | public void onStartTrackingTouch(SeekBar seekBar) {
46 | mMediaControl.onProgressTurn(ProgressState.START, 0);
47 | }
48 |
49 | @Override
50 | public void onStopTrackingTouch(SeekBar seekBar) {
51 | mMediaControl.onProgressTurn(ProgressState.STOP, 0);
52 | }
53 |
54 | private EasySwitcher.EasySwitcherCallbackImpl mSrcSwitcherCallback = new EasySwitcher.EasySwitcherCallbackImpl() {
55 | @Override
56 | public void onSelectItem(int position, String name) {
57 | mMediaControl.onSelectSrc(position);
58 | }
59 |
60 | @Override
61 | public void onShowList() {
62 | mMediaControl.alwaysShowController();
63 | mVideoFormatSwitcher.closeSwitchList();
64 | }
65 | };
66 |
67 | private EasySwitcher.EasySwitcherCallbackImpl mFormatSwitcherCallback = new EasySwitcher.EasySwitcherCallbackImpl() {
68 | @Override
69 | public void onSelectItem(int position, String name) {
70 | mMediaControl.onSelectFormat(position);
71 | }
72 |
73 | @Override
74 | public void onShowList() {
75 | mMediaControl.alwaysShowController();
76 | mVideoSrcSwitcher.closeSwitchList();
77 | }
78 | };
79 |
80 | @Override
81 | public void onClick(View view) {
82 | if (view.getId() == R.id.pause) {
83 | mMediaControl.onPlayTurn();
84 | } else if (view.getId() == R.id.expand) {
85 | mMediaControl.onPageTurn();
86 | } else if (view.getId() == R.id.shrink) {
87 | mMediaControl.onPageTurn();
88 | }
89 | }
90 |
91 | public void initVideoList(ArrayList videoList) {
92 | ArrayList name = new ArrayList<>();
93 | for (Video video : videoList) {
94 | name.add(video.getVideoName());
95 | }
96 | mVideoSrcSwitcher.initData(name);
97 | }
98 |
99 | public void initPlayVideo(Video video) {
100 | ArrayList format = new ArrayList<>();
101 | for (VideoUrl url : video.getVideoUrl()) {
102 | format.add(url.getFormatName());
103 | }
104 | mVideoFormatSwitcher.initData(format);
105 | }
106 |
107 | public void closeAllSwitchList() {
108 | mVideoFormatSwitcher.closeSwitchList();
109 | mVideoSrcSwitcher.closeSwitchList();
110 | }
111 |
112 | /**
113 | * 初始化精简模式
114 | */
115 | public void initTrimmedMode() {
116 | mMenuView.setVisibility(GONE);
117 | mMenuViewPlaceHolder.setVisibility(GONE);
118 | mExpandImg.setVisibility(INVISIBLE);
119 | mShrinkImg.setVisibility(INVISIBLE);
120 | }
121 |
122 | /***
123 | * 强制横屏模式
124 | */
125 | public void forceLandscapeMode(){
126 | mExpandImg.setVisibility(INVISIBLE);
127 | mShrinkImg.setVisibility(INVISIBLE);
128 | }
129 |
130 |
131 | public void setProgressBar(int progress, int secondProgress) {
132 | if (progress < 0) progress = 0;
133 | if (progress > 100) progress = 100;
134 | if (secondProgress < 0) secondProgress = 0;
135 | if (secondProgress > 100) secondProgress = 100;
136 | mProgressSeekBar.setProgress(progress);
137 | mProgressSeekBar.setSecondaryProgress(secondProgress);
138 | }
139 |
140 | public void setPlayState(PlayState playState) {
141 | mPlayImg.setImageResource(playState.equals(PlayState.PLAY) ? R.drawable.biz_video_pause : R.drawable.biz_video_play);
142 | }
143 |
144 | public void setPageType(PageType pageType) {
145 | mExpandImg.setVisibility(pageType.equals(PageType.EXPAND) ? GONE : VISIBLE);
146 | mShrinkImg.setVisibility(pageType.equals(PageType.SHRINK) ? GONE : VISIBLE);
147 | }
148 |
149 | public void setPlayProgressTxt(int nowSecond, int allSecond) {
150 | mTimeTxt.setText(getPlayTime(nowSecond, allSecond));
151 | }
152 |
153 | public void playFinish(int allTime) {
154 | mProgressSeekBar.setProgress(0);
155 | setPlayProgressTxt(0, allTime);
156 | setPlayState(PlayState.PAUSE);
157 | }
158 |
159 | public void setMediaControl(MediaControlImpl mediaControl) {
160 | mMediaControl = mediaControl;
161 | }
162 |
163 | public MediaController(Context context) {
164 | super(context);
165 | initView(context);
166 | }
167 |
168 | public MediaController(Context context, AttributeSet attrs, int defStyleAttr) {
169 | super(context, attrs, defStyleAttr);
170 | initView(context);
171 | }
172 |
173 | public MediaController(Context context, AttributeSet attrs) {
174 | super(context, attrs);
175 | initView(context);
176 | }
177 |
178 | private void initView(Context context) {
179 | View.inflate(context, R.layout.biz_video_media_controller, this);
180 | mPlayImg = (ImageView) findViewById(R.id.pause);
181 | mProgressSeekBar = (SeekBar) findViewById(R.id.media_controller_progress);
182 | mVideoSrcSwitcher = (EasySwitcher) findViewById(R.id.video_src_switcher);
183 | mVideoFormatSwitcher = (EasySwitcher) findViewById(R.id.video_format_switcher);
184 | mTimeTxt = (TextView) findViewById(R.id.time);
185 | mExpandImg = (ImageView) findViewById(R.id.expand);
186 | mShrinkImg = (ImageView) findViewById(R.id.shrink);
187 | mMenuView = findViewById(R.id.view_menu);
188 | mMenuViewPlaceHolder = findViewById(R.id.view_menu_placeholder);
189 | initData();
190 | }
191 |
192 | private void initData() {
193 | mProgressSeekBar.setOnSeekBarChangeListener(this);
194 | mPlayImg.setOnClickListener(this);
195 | mShrinkImg.setOnClickListener(this);
196 | mExpandImg.setOnClickListener(this);
197 | setPageType(PageType.SHRINK);
198 | setPlayState(PlayState.PAUSE);
199 | mVideoFormatSwitcher.setEasySwitcherCallback(mFormatSwitcherCallback);
200 | mVideoSrcSwitcher.setEasySwitcherCallback(mSrcSwitcherCallback);
201 | }
202 |
203 | @SuppressLint("SimpleDateFormat")
204 | private String formatPlayTime(long time) {
205 | DateFormat formatter = new SimpleDateFormat("mm:ss");
206 | return formatter.format(new Date(time));
207 | }
208 |
209 | private String getPlayTime(int playSecond, int allSecond) {
210 | String playSecondStr = "00:00";
211 | String allSecondStr = "00:00";
212 | if (playSecond > 0) {
213 | playSecondStr = formatPlayTime(playSecond);
214 | }
215 | if (allSecond > 0) {
216 | allSecondStr = formatPlayTime(allSecond);
217 | }
218 | return playSecondStr + "/" + allSecondStr;
219 | }
220 |
221 | /**
222 | * 播放样式 展开、缩放
223 | */
224 | public enum PageType {
225 | EXPAND, SHRINK
226 | }
227 |
228 | /**
229 | * 播放状态 播放 暂停
230 | */
231 | public enum PlayState {
232 | PLAY, PAUSE
233 | }
234 |
235 | public enum ProgressState {
236 | START, DOING, STOP
237 | }
238 |
239 |
240 | public interface MediaControlImpl {
241 | void onPlayTurn();
242 |
243 | void onPageTurn();
244 |
245 | void onProgressTurn(ProgressState state, int progress);
246 |
247 | void onSelectSrc(int position);
248 |
249 | void onSelectFormat(int position);
250 |
251 | void alwaysShowController();
252 | }
253 |
254 | }
255 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/view/SuperVideoPlayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2015 TedXiong xiong-wei@hotmail.com
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.android.tedcoder.wkvideoplayer.view;
19 |
20 | import android.content.Context;
21 | import android.media.MediaPlayer;
22 | import android.net.Uri;
23 | import android.os.Handler;
24 | import android.os.Message;
25 | import android.text.TextUtils;
26 | import android.util.AttributeSet;
27 | import android.util.Log;
28 | import android.view.MotionEvent;
29 | import android.view.View;
30 | import android.view.animation.Animation;
31 | import android.view.animation.AnimationUtils;
32 | import android.widget.RelativeLayout;
33 | import android.widget.TextView;
34 | import android.widget.Toast;
35 |
36 | import com.android.tedcoder.wkvideoplayer.R;
37 | import com.android.tedcoder.wkvideoplayer.dlna.engine.DLNAContainer;
38 | import com.android.tedcoder.wkvideoplayer.dlna.engine.MultiPointController;
39 | import com.android.tedcoder.wkvideoplayer.dlna.inter.IController;
40 | import com.android.tedcoder.wkvideoplayer.model.Video;
41 | import com.android.tedcoder.wkvideoplayer.model.VideoUrl;
42 |
43 | import org.cybergarage.upnp.Device;
44 |
45 | import java.util.ArrayList;
46 | import java.util.List;
47 | import java.util.Timer;
48 | import java.util.TimerTask;
49 |
50 | /**
51 | * Created by Ted on 2015/8/6.
52 | * SuperVideoPlayer
53 | */
54 | public class SuperVideoPlayer extends RelativeLayout {
55 |
56 | private final int MSG_HIDE_CONTROLLER = 10;
57 | private final int MSG_UPDATE_PLAY_TIME = 11;
58 | private final int MSG_PLAY_ON_TV_RESULT = 12;
59 | private final int MSG_EXIT_FORM_TV_RESULT = 13;
60 | private MediaController.PageType mCurrPageType = MediaController.PageType.SHRINK;//当前是横屏还是竖屏
61 |
62 | private Context mContext;
63 | private SuperVideoView mSuperVideoView;
64 | private MediaController mMediaController;
65 | private Timer mUpdateTimer;
66 | private VideoPlayCallbackImpl mVideoPlayCallback;
67 |
68 | private View mProgressBarView;
69 | private View mCloseBtnView;
70 | private View mTvBtnView;
71 | private View mDLNARootLayout;
72 |
73 | private ArrayList mAllVideo;
74 | private Video mNowPlayVideo;
75 |
76 | private List mDevices;
77 | private IController mController;
78 | private Device mSelectDevice;
79 | //是否自动隐藏控制栏
80 | private boolean mAutoHideController = true;
81 |
82 | private Handler mHandler = new Handler(new Handler.Callback() {
83 | @Override
84 | public boolean handleMessage(Message msg) {
85 | if (msg.what == MSG_UPDATE_PLAY_TIME) {
86 | updatePlayTime();
87 | updatePlayProgress();
88 | } else if (msg.what == MSG_HIDE_CONTROLLER) {
89 | showOrHideController();
90 | } else if (msg.what == MSG_PLAY_ON_TV_RESULT) {
91 | shareToTvResult(msg);
92 | } else if (msg.what == MSG_EXIT_FORM_TV_RESULT) {
93 | exitFromTvResult(msg);
94 | }
95 | return false;
96 | }
97 | });
98 |
99 | /**
100 | * 可推送设备列表改变的监听回调
101 | */
102 | @SuppressWarnings("unused")
103 | private DLNAContainer.DeviceChangeListener mDeviceChangeListener = new DLNAContainer.DeviceChangeListener() {
104 | @Override
105 | public void onDeviceChange(Device device) {
106 |
107 | }
108 | };
109 |
110 | private View.OnClickListener mOnClickListener = new OnClickListener() {
111 | @Override
112 | public void onClick(View view) {
113 | if (view.getId() == R.id.video_close_view) {
114 | mVideoPlayCallback.onCloseVideo();
115 | } else if (view.getId() == R.id.video_share_tv_view) {
116 | shareToTv();
117 | } else if (view.getId() == R.id.txt_dlna_exit) {
118 | goOnPlayAtLocal();
119 | }
120 | }
121 | };
122 |
123 | private View.OnTouchListener mOnTouchVideoListener = new OnTouchListener() {
124 | @Override
125 | public boolean onTouch(View view, MotionEvent motionEvent) {
126 | if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
127 | showOrHideController();
128 | }
129 | return mCurrPageType == MediaController.PageType.EXPAND;
130 | }
131 | };
132 |
133 | private MediaController.MediaControlImpl mMediaControl = new MediaController.MediaControlImpl() {
134 | @Override
135 | public void alwaysShowController() {
136 | SuperVideoPlayer.this.alwaysShowController();
137 | }
138 |
139 | @Override
140 | public void onSelectSrc(int position) {
141 | Video selectVideo = mAllVideo.get(position);
142 | if (selectVideo.equal(mNowPlayVideo)) return;
143 | mNowPlayVideo = selectVideo;
144 | mNowPlayVideo.setPlayUrl(0);
145 | mMediaController.initPlayVideo(mNowPlayVideo);
146 | loadAndPlay(mNowPlayVideo.getPlayUrl(), 0);
147 | }
148 |
149 | @Override
150 | public void onSelectFormat(int position) {
151 | VideoUrl videoUrl = mNowPlayVideo.getVideoUrl().get(position);
152 | if (mNowPlayVideo.getPlayUrl().equal(videoUrl)) return;
153 | mNowPlayVideo.setPlayUrl(position);
154 | playVideoAtLastPos();
155 | }
156 |
157 | @Override
158 | public void onPlayTurn() {
159 | if (mSuperVideoView.isPlaying()) {
160 | pausePlay(true);
161 | } else {
162 | goOnPlay();
163 | }
164 | }
165 |
166 | @Override
167 | public void onPageTurn() {
168 | mVideoPlayCallback.onSwitchPageType();
169 | }
170 |
171 | @Override
172 | public void onProgressTurn(MediaController.ProgressState state, int progress) {
173 | if (state.equals(MediaController.ProgressState.START)) {
174 | mHandler.removeMessages(MSG_HIDE_CONTROLLER);
175 | } else if (state.equals(MediaController.ProgressState.STOP)) {
176 | resetHideTimer();
177 | } else {
178 | int time = progress * mSuperVideoView.getDuration() / 100;
179 | mSuperVideoView.seekTo(time);
180 | updatePlayTime();
181 | }
182 | }
183 | };
184 |
185 | private MediaPlayer.OnPreparedListener mOnPreparedListener = new MediaPlayer.OnPreparedListener() {
186 | @Override
187 | public void onPrepared(MediaPlayer mediaPlayer) {
188 | mediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
189 | @Override
190 | public boolean onInfo(MediaPlayer mp, int what, int extra) {
191 | /*
192 | * add what == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING
193 | * fix : return what == 700 in Lenovo low configuration Android System
194 | */
195 | if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START
196 | || what == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
197 | mProgressBarView.setVisibility(View.GONE);
198 | setCloseButton(true);
199 | initDLNAInfo();
200 | return true;
201 | }
202 | return false;
203 | }
204 | });
205 |
206 | }
207 | };
208 |
209 | private MediaPlayer.OnCompletionListener mOnCompletionListener = new MediaPlayer.OnCompletionListener() {
210 | @Override
211 | public void onCompletion(MediaPlayer mediaPlayer) {
212 | stopUpdateTimer();
213 | stopHideTimer(true);
214 | mMediaController.playFinish(mSuperVideoView.getDuration());
215 | mVideoPlayCallback.onPlayFinish();
216 | Toast.makeText(mContext, "视频播放完成", Toast.LENGTH_SHORT).show();
217 | }
218 | };
219 |
220 | public void setVideoPlayCallback(VideoPlayCallbackImpl videoPlayCallback) {
221 | mVideoPlayCallback = videoPlayCallback;
222 | }
223 |
224 | /**
225 | * 如果在地图页播放视频,请先调用该接口
226 | */
227 | @SuppressWarnings("unused")
228 | public void setSupportPlayOnSurfaceView() {
229 | mSuperVideoView.setZOrderMediaOverlay(true);
230 | }
231 |
232 | @SuppressWarnings("unused")
233 | public SuperVideoView getSuperVideoView() {
234 | return mSuperVideoView;
235 | }
236 |
237 | public void setPageType(MediaController.PageType pageType) {
238 | mMediaController.setPageType(pageType);
239 | mCurrPageType = pageType;
240 | }
241 |
242 | /***
243 | * 强制横屏模式
244 | */
245 | @SuppressWarnings("unused")
246 | public void forceLandscapeMode() {
247 | mMediaController.forceLandscapeMode();
248 | }
249 |
250 | /***
251 | * 播放本地视频 只支持横屏播放
252 | *
253 | * @param fileUrl fileUrl
254 | */
255 | @SuppressWarnings("unused")
256 | public void loadLocalVideo(String fileUrl) {
257 | VideoUrl videoUrl = new VideoUrl();
258 | videoUrl.setIsOnlineVideo(false);
259 | videoUrl.setFormatUrl(fileUrl);
260 | videoUrl.setFormatName("本地视频");
261 | Video video = new Video();
262 | ArrayList videoUrls = new ArrayList<>();
263 | videoUrls.add(videoUrl);
264 | video.setVideoUrl(videoUrls);
265 | video.setPlayUrl(0);
266 |
267 | mNowPlayVideo = video;
268 |
269 | /***
270 | * 初始化控制条的精简模式
271 | */
272 | mMediaController.initTrimmedMode();
273 | loadAndPlay(mNowPlayVideo.getPlayUrl(), 0);
274 | }
275 |
276 | /**
277 | * 播放多个视频,默认播放第一个视频,第一个格式
278 | *
279 | * @param allVideo 所有视频
280 | */
281 | public void loadMultipleVideo(ArrayList allVideo) {
282 | loadMultipleVideo(allVideo, 0, 0);
283 | }
284 |
285 | /**
286 | * 播放多个视频
287 | *
288 | * @param allVideo 所有的视频
289 | * @param selectVideo 指定的视频
290 | * @param selectFormat 指定的格式
291 | */
292 | public void loadMultipleVideo(ArrayList allVideo, int selectVideo, int selectFormat) {
293 | loadMultipleVideo(allVideo, selectVideo, selectFormat, 0);
294 | }
295 |
296 | /***
297 | *
298 | * @param allVideo 所有的视频
299 | * @param selectVideo 指定的视频
300 | * @param selectFormat 指定的格式
301 | * @param seekTime 开始进度
302 | */
303 | public void loadMultipleVideo(ArrayList allVideo, int selectVideo, int selectFormat, int seekTime) {
304 | if (null == allVideo || allVideo.size() == 0) {
305 | Toast.makeText(mContext, "视频列表为空", Toast.LENGTH_SHORT).show();
306 | return;
307 | }
308 | mAllVideo.clear();
309 | mAllVideo.addAll(allVideo);
310 | mNowPlayVideo = mAllVideo.get(selectVideo);
311 | mNowPlayVideo.setPlayUrl(selectFormat);
312 | mMediaController.initVideoList(mAllVideo);
313 | mMediaController.initPlayVideo(mNowPlayVideo);
314 | loadAndPlay(mNowPlayVideo.getPlayUrl(), seekTime);
315 | }
316 |
317 | /**
318 | * 暂停播放
319 | *
320 | * @param isShowController 是否显示控制条
321 | */
322 | public void pausePlay(boolean isShowController) {
323 | mSuperVideoView.pause();
324 | mMediaController.setPlayState(MediaController.PlayState.PAUSE);
325 | stopHideTimer(isShowController);
326 | }
327 |
328 | /***
329 | * 继续播放
330 | */
331 | public void goOnPlay() {
332 | mSuperVideoView.start();
333 | mMediaController.setPlayState(MediaController.PlayState.PLAY);
334 | resetHideTimer();
335 | resetUpdateTimer();
336 | }
337 |
338 | /**
339 | * 关闭视频
340 | */
341 | public void close() {
342 | mMediaController.setPlayState(MediaController.PlayState.PAUSE);
343 | stopHideTimer(true);
344 | stopUpdateTimer();
345 | mSuperVideoView.pause();
346 | mSuperVideoView.stopPlayback();
347 | mSuperVideoView.setVisibility(GONE);
348 | }
349 |
350 | /***
351 | * 获取支持的DLNA设备
352 | *
353 | * @return DLNA设备列表
354 | */
355 | public List getDevices() {
356 | return mDevices;
357 | }
358 |
359 | public boolean isAutoHideController() {
360 | return mAutoHideController;
361 | }
362 |
363 | public void setAutoHideController(boolean autoHideController) {
364 | mAutoHideController = autoHideController;
365 | }
366 |
367 | public SuperVideoPlayer(Context context) {
368 | super(context);
369 | initView(context);
370 | }
371 |
372 | public SuperVideoPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
373 | super(context, attrs, defStyleAttr);
374 | initView(context);
375 | }
376 |
377 | public SuperVideoPlayer(Context context, AttributeSet attrs) {
378 | super(context, attrs);
379 | initView(context);
380 | }
381 |
382 | private void initView(Context context) {
383 | mContext = context;
384 | View.inflate(context, R.layout.super_vodeo_player_layout, this);
385 | mSuperVideoView = (SuperVideoView) findViewById(R.id.video_view);
386 | mMediaController = (MediaController) findViewById(R.id.controller);
387 | mProgressBarView = findViewById(R.id.progressbar);
388 | mCloseBtnView = findViewById(R.id.video_close_view);
389 | mTvBtnView = findViewById(R.id.video_share_tv_view);
390 | mDLNARootLayout = findViewById(R.id.rel_dlna_root_layout);
391 |
392 | mMediaController.setMediaControl(mMediaControl);
393 | mSuperVideoView.setOnTouchListener(mOnTouchVideoListener);
394 |
395 | setDLNAButton(false);
396 | setCloseButton(false);
397 | mDLNARootLayout.setVisibility(GONE);
398 | showProgressView(false);
399 |
400 | mDLNARootLayout.setOnClickListener(mOnClickListener);
401 | mDLNARootLayout.findViewById(R.id.txt_dlna_exit).setOnClickListener(mOnClickListener);
402 | mCloseBtnView.setOnClickListener(mOnClickListener);
403 | mTvBtnView.setOnClickListener(mOnClickListener);
404 | mProgressBarView.setOnClickListener(mOnClickListener);
405 |
406 | mAllVideo = new ArrayList<>();
407 | }
408 |
409 | /**
410 | * 检测DLNA信息,如果有支持的设备,显示按钮
411 | */
412 | private void initDLNAInfo() {
413 | mDevices = DLNAContainer.getInstance().getDevices();
414 | setController(new MultiPointController());
415 | setDLNAButton(mDevices.size() > 0);
416 | }
417 |
418 | /**
419 | * 显示DLNA可以推送的按钮
420 | */
421 | private void setDLNAButton(boolean isShow) {
422 | mTvBtnView.setVisibility(isShow ? VISIBLE : INVISIBLE);
423 | }
424 |
425 | /**
426 | * 显示关闭视频的按钮
427 | *
428 | * @param isShow isShow
429 | */
430 | private void setCloseButton(boolean isShow) {
431 | mCloseBtnView.setVisibility(isShow ? VISIBLE : INVISIBLE);
432 | }
433 |
434 | /**
435 | * 更换清晰度地址时,续播
436 | */
437 | private void playVideoAtLastPos() {
438 | int playTime = mSuperVideoView.getCurrentPosition();
439 | mSuperVideoView.stopPlayback();
440 | loadAndPlay(mNowPlayVideo.getPlayUrl(), playTime);
441 | }
442 |
443 | /**
444 | * 加载并开始播放视频
445 | *
446 | * @param videoUrl videoUrl
447 | */
448 | private void loadAndPlay(VideoUrl videoUrl, int seekTime) {
449 | showProgressView(seekTime > 0);
450 | setCloseButton(true);
451 | if (TextUtils.isEmpty(videoUrl.getFormatUrl())) {
452 | Log.e("TAG", "videoUrl should not be null");
453 | return;
454 | }
455 | mSuperVideoView.setOnPreparedListener(mOnPreparedListener);
456 | if (videoUrl.isOnlineVideo()) {
457 | mSuperVideoView.setVideoPath(videoUrl.getFormatUrl());
458 | } else {
459 | Uri uri = Uri.parse(videoUrl.getFormatUrl());
460 | mSuperVideoView.setVideoURI(uri);
461 | }
462 | mSuperVideoView.setVisibility(VISIBLE);
463 | startPlayVideo(seekTime);
464 | }
465 |
466 | /**
467 | * 播放视频
468 | * should called after setVideoPath()
469 | */
470 | private void startPlayVideo(int seekTime) {
471 | if (null == mUpdateTimer) resetUpdateTimer();
472 | resetHideTimer();
473 | mSuperVideoView.setOnCompletionListener(mOnCompletionListener);
474 | mSuperVideoView.start();
475 | if (seekTime > 0) {
476 | mSuperVideoView.seekTo(seekTime);
477 | }
478 | mMediaController.setPlayState(MediaController.PlayState.PLAY);
479 | }
480 |
481 | /**
482 | * 更新播放的进度时间
483 | */
484 | private void updatePlayTime() {
485 | int allTime = mSuperVideoView.getDuration();
486 | int playTime = mSuperVideoView.getCurrentPosition();
487 | mMediaController.setPlayProgressTxt(playTime, allTime);
488 | }
489 |
490 | /**
491 | * 更新播放进度条
492 | */
493 | private void updatePlayProgress() {
494 | int allTime = mSuperVideoView.getDuration();
495 | int playTime = mSuperVideoView.getCurrentPosition();
496 | int loadProgress = mSuperVideoView.getBufferPercentage();
497 | int progress = playTime * 100 / allTime;
498 | mMediaController.setProgressBar(progress, loadProgress);
499 | }
500 |
501 | /**
502 | * 显示loading圈
503 | *
504 | * @param isTransparentBg isTransparentBg
505 | */
506 | private void showProgressView(Boolean isTransparentBg) {
507 | mProgressBarView.setVisibility(VISIBLE);
508 | if (!isTransparentBg) {
509 | mProgressBarView.setBackgroundResource(android.R.color.black);
510 | } else {
511 | mProgressBarView.setBackgroundResource(android.R.color.transparent);
512 | }
513 | }
514 |
515 | /***
516 | *
517 | */
518 | private void showOrHideController() {
519 | mMediaController.closeAllSwitchList();
520 | if (mMediaController.getVisibility() == View.VISIBLE) {
521 | Animation animation = AnimationUtils.loadAnimation(mContext,
522 | R.anim.anim_exit_from_bottom);
523 | animation.setAnimationListener(new AnimationImp() {
524 | @Override
525 | public void onAnimationEnd(Animation animation) {
526 | super.onAnimationEnd(animation);
527 | mMediaController.setVisibility(View.GONE);
528 | }
529 | });
530 | mMediaController.startAnimation(animation);
531 | } else {
532 | mMediaController.setVisibility(View.VISIBLE);
533 | mMediaController.clearAnimation();
534 | Animation animation = AnimationUtils.loadAnimation(mContext,
535 | R.anim.anim_enter_from_bottom);
536 | mMediaController.startAnimation(animation);
537 | resetHideTimer();
538 | }
539 | }
540 |
541 | private void alwaysShowController() {
542 | mHandler.removeMessages(MSG_HIDE_CONTROLLER);
543 | mMediaController.setVisibility(View.VISIBLE);
544 | }
545 |
546 | private void resetHideTimer() {
547 | if (!isAutoHideController()) return;
548 | mHandler.removeMessages(MSG_HIDE_CONTROLLER);
549 | int TIME_SHOW_CONTROLLER = 4000;
550 | mHandler.sendEmptyMessageDelayed(MSG_HIDE_CONTROLLER, TIME_SHOW_CONTROLLER);
551 | }
552 |
553 | private void stopHideTimer(boolean isShowController) {
554 | mHandler.removeMessages(MSG_HIDE_CONTROLLER);
555 | mMediaController.clearAnimation();
556 | mMediaController.setVisibility(isShowController ? View.VISIBLE : View.GONE);
557 | }
558 |
559 | private void resetUpdateTimer() {
560 | mUpdateTimer = new Timer();
561 | int TIME_UPDATE_PLAY_TIME = 1000;
562 | mUpdateTimer.schedule(new TimerTask() {
563 | @Override
564 | public void run() {
565 | mHandler.sendEmptyMessage(MSG_UPDATE_PLAY_TIME);
566 | }
567 | }, 0, TIME_UPDATE_PLAY_TIME);
568 | }
569 |
570 | private void stopUpdateTimer() {
571 | if (mUpdateTimer != null) {
572 | mUpdateTimer.cancel();
573 | mUpdateTimer = null;
574 | }
575 | }
576 |
577 | private void setController(IController controller) {
578 | mController = controller;
579 | }
580 |
581 | private void shareToTv() {
582 | Toast.makeText(mContext, "开始连接电视中", Toast.LENGTH_SHORT).show();
583 | showProgressView(true);
584 | DLNAContainer.getInstance().setSelectedDevice(mDevices.get(0));
585 | mSelectDevice = DLNAContainer.getInstance().getSelectedDevice();
586 | setController(new MultiPointController());
587 | if (mController == null || DLNAContainer.getInstance().getSelectedDevice() == null) {
588 | Toast.makeText(mContext, "数据异常", Toast.LENGTH_SHORT).show();
589 | return;
590 | }
591 | playVideoOnTv(mNowPlayVideo.getPlayUrl().getFormatUrl());
592 | }
593 |
594 |
595 | /**
596 | * 处理电视播放的结果,是否成功
597 | *
598 | * @param message message
599 | */
600 | private void shareToTvResult(Message message) {
601 | boolean isSuccess = message.arg1 == 1;
602 | if (isSuccess) {
603 | showDLNAController();
604 | setDLNAButton(false);
605 | setCloseButton(false);
606 | pausePlay(false);
607 | mProgressBarView.setVisibility(View.GONE);
608 | } else {
609 | mDLNARootLayout.setVisibility(GONE);
610 | Toast.makeText(mContext, "推送到电视播放失败了", Toast.LENGTH_SHORT).show();
611 | }
612 | }
613 |
614 | /**
615 | * 从电视播放退出的结果
616 | *
617 | * @param message message
618 | */
619 | private void exitFromTvResult(Message message) {
620 | boolean isSuccess = message.arg1 == 1;
621 | mDLNARootLayout.setVisibility(GONE);
622 | initDLNAInfo();
623 | playVideoAtLastPos();
624 | if (!isSuccess) {
625 | Toast.makeText(mContext, "电视播放退出失败,请手动退出", Toast.LENGTH_SHORT).show();
626 | }
627 | mProgressBarView.setVisibility(GONE);
628 | }
629 |
630 | /**
631 | * 显示推送视频播放控制页面
632 | */
633 | private void showDLNAController() {
634 | String name = DLNAContainer.getInstance().getSelectedDevice().getFriendlyName();
635 | String title = mContext.getResources().getString(R.string.dlna_device_title, TextUtils.isEmpty(name) ? "您的电视" : name);
636 | mDLNARootLayout.setVisibility(VISIBLE);
637 | ((TextView) mDLNARootLayout.findViewById(R.id.txt_dlna_title)).setText(title);
638 | }
639 |
640 | /**
641 | * Start to play the video.
642 | *
643 | * @param path The video path.
644 | */
645 | private synchronized void playVideoOnTv(final String path) {
646 | new Thread() {
647 | public void run() {
648 | final boolean isSuccess = mController.play(mSelectDevice, path);
649 | Message message = new Message();
650 | message.what = MSG_PLAY_ON_TV_RESULT;
651 | message.arg1 = isSuccess ? 1 : 0;
652 | mHandler.sendMessage(message);
653 | }
654 | }.start();
655 | }
656 |
657 | /**
658 | * 继续在本地播放
659 | */
660 | private synchronized void goOnPlayAtLocal() {
661 | showProgressView(true);
662 | new Thread() {
663 | @Override
664 | public void run() {
665 | final boolean isSuccess = mController.stop(mSelectDevice);
666 | Message message = new Message();
667 | message.what = MSG_EXIT_FORM_TV_RESULT;
668 | message.arg1 = isSuccess ? 1 : 0;
669 | mHandler.sendMessage(message);
670 | }
671 | }.start();
672 | }
673 |
674 | private class AnimationImp implements Animation.AnimationListener {
675 |
676 | @Override
677 | public void onAnimationEnd(Animation animation) {
678 |
679 | }
680 |
681 | @Override
682 | public void onAnimationRepeat(Animation animation) {
683 | }
684 |
685 | @Override
686 | public void onAnimationStart(Animation animation) {
687 | }
688 | }
689 |
690 | public interface VideoPlayCallbackImpl {
691 | void onCloseVideo();
692 |
693 | void onSwitchPageType();
694 |
695 | void onPlayFinish();
696 | }
697 |
698 | }
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/java/com/android/tedcoder/wkvideoplayer/view/SuperVideoView.java:
--------------------------------------------------------------------------------
1 | package com.android.tedcoder.wkvideoplayer.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.VideoView;
6 |
7 | /**
8 | * Created by Ted on 2015/8/6.
9 | */
10 | public class SuperVideoView extends VideoView {
11 |
12 | public SuperVideoView(Context context) {
13 | super(context);
14 | }
15 |
16 | public SuperVideoView(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | public SuperVideoView(Context context, AttributeSet attrs, int defStyle) {
21 | super(context, attrs, defStyle);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/anim/anim_enter_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/anim/anim_exit_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/anim/biz_news_detailpage_loading_large_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/color/switcher_item_text_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
23 |
24 |
26 |
27 |
29 |
30 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-hdpi/biz_video_progress_thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-hdpi/biz_video_progress_thumb.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_danmaku_switcher_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_danmaku_switcher_bg.9.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_danmaku_write.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_danmaku_write.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_expand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_expand.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_pause.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_play.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_progress_thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_progress_thumb.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_shrink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/biz_video_shrink.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/ic_action_bulb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/ic_action_bulb.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/ic_action_music_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/ic_action_music_2.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_audio_sublist_item_img_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_audio_sublist_item_img_icon.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_news_detailpage_loading_large_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_news_detailpage_loading_large_icon.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_news_list_ad_video_close_btn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_news_list_ad_video_close_btn.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_video_list_play_icon_big.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/biz_video_list_play_icon_big.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/ic_action_bulb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/ic_action_bulb.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/ic_action_music_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/ic_action_music_2.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_big.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_big.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small_gray.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/icon_tv_small_white.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/shipin_shang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/shipin_shang.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable-xxhdpi/shipin_xia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable-xxhdpi/shipin_xia.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/bg_black_a10_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/biz_video_bar_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiongwei-git/AndroidVideoPlayer/1a249ea7d028f12c0e41a2b7b9868935aa1f9f99/wkvideoplayer/src/main/res/drawable/biz_video_bar_bg.9.png
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/biz_video_progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 | -
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/btn_exit_dlna_bg_bg.xml:
--------------------------------------------------------------------------------
1 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/dlna_tv_btn_bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
20 |
22 |
23 |
25 |
26 |
28 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/drawable/video_format_switcher_bg.xml:
--------------------------------------------------------------------------------
1 |
17 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/layout/biz_video_media_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
34 |
35 |
42 |
43 |
52 |
53 |
54 |
58 |
59 |
62 |
63 |
71 |
72 |
80 |
81 |
82 |
83 |
84 |
85 |
93 |
94 |
100 |
101 |
107 |
108 |
114 |
115 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/layout/item_lv_main.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
22 |
23 |
24 |
33 |
34 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/layout/super_vodeo_player_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
26 |
27 |
32 |
33 |
38 |
39 |
50 |
51 |
57 |
58 |
73 |
74 |
75 |
80 |
81 |
87 |
88 |
93 |
94 |
95 |
101 |
102 |
107 |
108 |
109 |
116 |
117 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/layout/video_easy_switcher_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
23 |
24 |
30 |
31 |
32 |
33 |
36 |
37 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/values/colos.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #00b2ff
4 | #ffffff
5 | #6b6666
6 |
7 | #aa000000
8 | #00b2ff
9 | #ffffffff
10 | #55504a
11 |
12 | #1a000000
13 |
14 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
7 | 14sp
8 | 32dip
9 | 32dip
10 | 80dip
11 | 12dip
12 | 48dip
13 | 52dip
14 | 71dip
15 |
16 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LFVideoPlayer
3 |
4 | "%s"正在播放中
5 |
6 |
--------------------------------------------------------------------------------
/wkvideoplayer/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
19 |
20 |
30 |
31 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/wkvideoplayer/wkvideoplayer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------