├── .gitignore
├── README.md
├── assets
├── sample1.png
├── sample2.png
└── sample3.png
├── library
├── AndroidManifest.xml
├── LICENSE.txt
├── ant.properties
├── build.xml
├── proguard-project.txt
├── project.properties
└── src
│ └── com
│ └── dd
│ └── crop
│ └── TextureVideoView.java
└── sample
├── AndroidManifest.xml
├── ant.properties
├── build.xml
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-ldpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── layout
│ └── main.xml
└── values
│ └── strings.xml
└── src
└── com
└── dd
└── sample
└── crop
└── SampleActivity.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
22 | # IDEA project files
23 | *.iml
24 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | :small_red_triangle: **Before using this library, read information below** :small_red_triangle:
2 | ```
3 | This library is not more supported.
4 | If you want to add new feature or fix a bug, grab source code and do it. If you think your
5 | fix or feature would be useful to other developers, I can add link of your repository to
6 | this README file. Use following e-mail to contact me: dmytrodanylyk@gmail.com
7 | Thank you for using my libraries.
8 |
9 | ```
10 |
11 | ## Preview
12 |
13 |
14 |
15 |
16 |
17 | ## Description
18 |
19 | [`TextureVideoView`](/library/src/com/dd/crop/TextureVideoView.java) is custom view based on android [`TextureView`](http://developer.android.com/reference/android/view/TextureView.html) which gives you ability easily play and crop video. It's very similar to [`ImageView#setScaleType`](http://developer.android.com/reference/android/widget/ImageView.html#setScaleType(android.widget.ImageView.ScaleType))
20 |
21 | Crop modes:
22 |
23 | - TOP
24 | - CENTER_CROP
25 | - BOTTOM
26 |
27 | ## Usage
28 |
29 | Include library module to your project or copy [`TextureVideoView`](/library/src/com/dd/crop/TextureVideoView.java) class to your package.
30 |
31 |
32 | ```xml
33 |
37 | ```
38 |
39 | ```java
40 | TextureVideoView cropTextureView = (TextureVideoView) findViewById(R.id.cropTextureView);
41 | // Use `setScaleType` method to crop video
42 | cropTextureView.setScaleType(TextureVideoView.ScaleType.TOP);
43 | // Use `setDataSource` method to set data source, this could be url, assets folder or path
44 | cropTextureView.setDataSource("http://www.w3schools.com/html/mov_bbb.mp4");
45 | cropTextureView.play();
46 | ```
47 |
48 | ## How it works?
49 |
50 | Read [Texture View - Video Cropping](http://goo.gl/WAikcl) Article
51 |
52 | ## API
53 |
54 | ver 1.0
55 |
56 | ```java
57 |
58 | /**
59 | * Play or resume video. Video will be played as soon as view is available and media player is
60 | * prepared.
61 | *
62 | * If video is stopped or ended and play() method was called, video will start over.
63 | */
64 | TextureVideoView.play()
65 |
66 | /**
67 | * Pause video. If video is already paused, stopped or ended nothing will happen.
68 | */
69 | TextureVideoView.pause()
70 |
71 | /**
72 | * Stop video (pause and seek to beginning). If video is already stopped or ended nothing will
73 | * happen.
74 | */
75 | TextureVideoView.stop()
76 |
77 | /**
78 | * Sets the data source (file-path or http/rtsp URL) to use.
79 | */
80 | TextureVideoView.setDataSource(String)
81 |
82 | /**
83 | * Sets the data source as a content Uri.
84 | */
85 | TextureVideoView.setDataSource(Context, Uri)
86 |
87 | /**
88 | * Sets the data source (FileDescriptor) to use.
89 | */
90 | TextureVideoView.setDataSource(AssetFileDescriptor)
91 |
92 | /**
93 | * Sets the player to be looping or non-looping.
94 | */
95 | TextureVideoView.setLooping(boolean)
96 |
97 | /**
98 | * Seeks to specified time position. (milliseconds)
99 | */
100 | TextureVideoView.seekTo(int)
101 |
102 | /**
103 | * Gets the duration of the file.
104 | */
105 | TextureVideoView.getDuration()
106 |
107 | /**
108 | * Listener trigger `onVideoPrepared` and `onVideoEnd` events
109 | */
110 | TextureVideoView.setListener(MediaPlayerListener)
111 | ```
112 |
113 | ## License
114 |
115 | ```
116 | The MIT License (MIT)
117 |
118 | Copyright (c) 2014 Danylyk Dmytro
119 |
120 | Permission is hereby granted, free of charge, to any person obtaining a copy
121 | of this software and associated documentation files (the "Software"), to deal
122 | in the Software without restriction, including without limitation the rights
123 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
124 | copies of the Software, and to permit persons to whom the Software is
125 | furnished to do so, subject to the following conditions:
126 |
127 | The above copyright notice and this permission notice shall be included in all
128 | copies or substantial portions of the Software.
129 |
130 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
131 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
132 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
133 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
134 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
135 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
136 | SOFTWARE.
137 | ```
138 |
--------------------------------------------------------------------------------
/assets/sample1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/assets/sample1.png
--------------------------------------------------------------------------------
/assets/sample2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/assets/sample2.png
--------------------------------------------------------------------------------
/assets/sample3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/assets/sample3.png
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/library/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Danylyk Dmytro
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/library/ant.properties:
--------------------------------------------------------------------------------
1 | # This file is used to override default values used by the Ant build system.
2 | #
3 | # This file must be checked into Version Control Systems, as it is
4 | # integral to the build system of your project.
5 |
6 | # This file is only used by the Ant script.
7 |
8 | # You can use this to override default values such as
9 | # 'source.dir' for the location of your java source folder and
10 | # 'out.dir' for the location of your output folder.
11 |
12 | # You can also use it define how the release builds are signed by declaring
13 | # the following properties:
14 | # 'key.store' for the location of your keystore and
15 | # 'key.alias' for the name of the key to use.
16 | # The password will be asked during the build when you use the 'release' target.
17 |
18 |
--------------------------------------------------------------------------------
/library/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
55 |
56 |
68 |
69 |
70 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/library/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | android.library=true
14 | # Project target.
15 | target=android-14
16 |
--------------------------------------------------------------------------------
/library/src/com/dd/crop/TextureVideoView.java:
--------------------------------------------------------------------------------
1 | package com.dd.crop;
2 |
3 | import android.content.Context;
4 | import android.content.res.AssetFileDescriptor;
5 | import android.graphics.Matrix;
6 | import android.graphics.SurfaceTexture;
7 | import android.media.MediaPlayer;
8 | import android.net.Uri;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.view.Surface;
12 | import android.view.TextureView;
13 |
14 | import java.io.IOException;
15 |
16 | /*
17 | * The MIT License (MIT)
18 | *
19 | * Copyright (c) 2014 Danylyk Dmytro
20 | *
21 | * Permission is hereby granted, free of charge, to any person obtaining a copy
22 | * of this software and associated documentation files (the "Software"), to deal
23 | * in the Software without restriction, including without limitation the rights
24 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | * copies of the Software, and to permit persons to whom the Software is
26 | * furnished to do so, subject to the following conditions:
27 | *
28 | * The above copyright notice and this permission notice shall be included in all
29 | * copies or substantial portions of the Software.
30 | *
31 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | * SOFTWARE.
38 | */
39 |
40 | public class TextureVideoView extends TextureView implements TextureView.SurfaceTextureListener {
41 |
42 | // Indicate if logging is on
43 | public static final boolean LOG_ON = true;
44 |
45 | // Log tag
46 | private static final String TAG = TextureVideoView.class.getName();
47 |
48 | private MediaPlayer mMediaPlayer;
49 |
50 | private float mVideoHeight;
51 | private float mVideoWidth;
52 |
53 | private boolean mIsDataSourceSet;
54 | private boolean mIsViewAvailable;
55 | private boolean mIsVideoPrepared;
56 | private boolean mIsPlayCalled;
57 |
58 | private ScaleType mScaleType;
59 | private State mState;
60 |
61 | public enum ScaleType {
62 | CENTER_CROP, TOP, BOTTOM
63 | }
64 |
65 | public enum State {
66 | UNINITIALIZED, PLAY, STOP, PAUSE, END
67 | }
68 |
69 | public TextureVideoView(Context context) {
70 | super(context);
71 | initView();
72 | }
73 |
74 | public TextureVideoView(Context context, AttributeSet attrs) {
75 | super(context, attrs);
76 | initView();
77 | }
78 |
79 | public TextureVideoView(Context context, AttributeSet attrs, int defStyle) {
80 | super(context, attrs, defStyle);
81 | initView();
82 | }
83 |
84 | private void initView() {
85 | initPlayer();
86 | setScaleType(ScaleType.CENTER_CROP);
87 | setSurfaceTextureListener(this);
88 | }
89 |
90 | public void setScaleType(ScaleType scaleType) {
91 | mScaleType = scaleType;
92 | }
93 |
94 | private void updateTextureViewSize() {
95 | float viewWidth = getWidth();
96 | float viewHeight = getHeight();
97 |
98 | float scaleX = 1.0f;
99 | float scaleY = 1.0f;
100 |
101 | if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
102 | scaleX = mVideoWidth / viewWidth;
103 | scaleY = mVideoHeight / viewHeight;
104 | } else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
105 | scaleY = viewWidth / mVideoWidth;
106 | scaleX = viewHeight / mVideoHeight;
107 | } else if (viewWidth > mVideoWidth) {
108 | scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
109 | } else if (viewHeight > mVideoHeight) {
110 | scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
111 | }
112 |
113 | // Calculate pivot points, in our case crop from center
114 | int pivotPointX;
115 | int pivotPointY;
116 |
117 | switch (mScaleType) {
118 | case TOP:
119 | pivotPointX = 0;
120 | pivotPointY = 0;
121 | break;
122 | case BOTTOM:
123 | pivotPointX = (int) (viewWidth);
124 | pivotPointY = (int) (viewHeight);
125 | break;
126 | case CENTER_CROP:
127 | pivotPointX = (int) (viewWidth / 2);
128 | pivotPointY = (int) (viewHeight / 2);
129 | break;
130 | default:
131 | pivotPointX = (int) (viewWidth / 2);
132 | pivotPointY = (int) (viewHeight / 2);
133 | break;
134 | }
135 |
136 | Matrix matrix = new Matrix();
137 | matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
138 |
139 | setTransform(matrix);
140 | }
141 |
142 | private void initPlayer() {
143 | if (mMediaPlayer == null) {
144 | mMediaPlayer = new MediaPlayer();
145 | } else {
146 | mMediaPlayer.reset();
147 | }
148 | mIsVideoPrepared = false;
149 | mIsPlayCalled = false;
150 | mState = State.UNINITIALIZED;
151 | }
152 |
153 | /**
154 | * @see android.media.MediaPlayer#setDataSource(String)
155 | */
156 | public void setDataSource(String path) {
157 | initPlayer();
158 |
159 | try {
160 | mMediaPlayer.setDataSource(path);
161 | mIsDataSourceSet = true;
162 | prepare();
163 | } catch (IOException e) {
164 | Log.d(TAG, e.getMessage());
165 | }
166 | }
167 |
168 | /**
169 | * @see android.media.MediaPlayer#setDataSource(android.content.Context, android.net.Uri)
170 | */
171 | public void setDataSource(Context context, Uri uri) {
172 | initPlayer();
173 |
174 | try {
175 | mMediaPlayer.setDataSource(context, uri);
176 | mIsDataSourceSet = true;
177 | prepare();
178 | } catch (IOException e) {
179 | Log.d(TAG, e.getMessage());
180 | }
181 | }
182 |
183 | /**
184 | * @see android.media.MediaPlayer#setDataSource(java.io.FileDescriptor)
185 | */
186 | public void setDataSource(AssetFileDescriptor afd) {
187 | initPlayer();
188 |
189 | try {
190 | long startOffset = afd.getStartOffset();
191 | long length = afd.getLength();
192 | mMediaPlayer.setDataSource(afd.getFileDescriptor(), startOffset, length);
193 | mIsDataSourceSet = true;
194 | prepare();
195 | } catch (IOException e) {
196 | Log.d(TAG, e.getMessage());
197 | }
198 | }
199 |
200 | private void prepare() {
201 | try {
202 | mMediaPlayer.setOnVideoSizeChangedListener(
203 | new MediaPlayer.OnVideoSizeChangedListener() {
204 | @Override
205 | public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
206 | mVideoWidth = width;
207 | mVideoHeight = height;
208 | updateTextureViewSize();
209 | }
210 | }
211 | );
212 | mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
213 | @Override
214 | public void onCompletion(MediaPlayer mp) {
215 | mState = State.END;
216 | log("Video has ended.");
217 |
218 | if (mListener != null) {
219 | mListener.onVideoEnd();
220 | }
221 | }
222 | });
223 |
224 | // don't forget to call MediaPlayer.prepareAsync() method when you use constructor for
225 | // creating MediaPlayer
226 | mMediaPlayer.prepareAsync();
227 |
228 | // Play video when the media source is ready for playback.
229 | mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
230 | @Override
231 | public void onPrepared(MediaPlayer mediaPlayer) {
232 | mIsVideoPrepared = true;
233 | if (mIsPlayCalled && mIsViewAvailable) {
234 | log("Player is prepared and play() was called.");
235 | play();
236 | }
237 |
238 | if (mListener != null) {
239 | mListener.onVideoPrepared();
240 | }
241 | }
242 | });
243 |
244 | } catch (IllegalArgumentException e) {
245 | Log.d(TAG, e.getMessage());
246 | } catch (SecurityException e) {
247 | Log.d(TAG, e.getMessage());
248 | } catch (IllegalStateException e) {
249 | Log.d(TAG, e.toString());
250 | }
251 | }
252 |
253 | /**
254 | * Play or resume video. Video will be played as soon as view is available and media player is
255 | * prepared.
256 | *
257 | * If video is stopped or ended and play() method was called, video will start over.
258 | */
259 | public void play() {
260 | if (!mIsDataSourceSet) {
261 | log("play() was called but data source was not set.");
262 | return;
263 | }
264 |
265 | mIsPlayCalled = true;
266 |
267 | if (!mIsVideoPrepared) {
268 | log("play() was called but video is not prepared yet, waiting.");
269 | return;
270 | }
271 |
272 | if (!mIsViewAvailable) {
273 | log("play() was called but view is not available yet, waiting.");
274 | return;
275 | }
276 |
277 | if (mState == State.PLAY) {
278 | log("play() was called but video is already playing.");
279 | return;
280 | }
281 |
282 | if (mState == State.PAUSE) {
283 | log("play() was called but video is paused, resuming.");
284 | mState = State.PLAY;
285 | mMediaPlayer.start();
286 | return;
287 | }
288 |
289 | if (mState == State.END || mState == State.STOP) {
290 | log("play() was called but video already ended, starting over.");
291 | mState = State.PLAY;
292 | mMediaPlayer.seekTo(0);
293 | mMediaPlayer.start();
294 | return;
295 | }
296 |
297 | mState = State.PLAY;
298 | mMediaPlayer.start();
299 | }
300 |
301 | /**
302 | * Pause video. If video is already paused, stopped or ended nothing will happen.
303 | */
304 | public void pause() {
305 | if (mState == State.PAUSE) {
306 | log("pause() was called but video already paused.");
307 | return;
308 | }
309 |
310 | if (mState == State.STOP) {
311 | log("pause() was called but video already stopped.");
312 | return;
313 | }
314 |
315 | if (mState == State.END) {
316 | log("pause() was called but video already ended.");
317 | return;
318 | }
319 |
320 | mState = State.PAUSE;
321 | if (mMediaPlayer.isPlaying()) {
322 | mMediaPlayer.pause();
323 | }
324 | }
325 |
326 | /**
327 | * Stop video (pause and seek to beginning). If video is already stopped or ended nothing will
328 | * happen.
329 | */
330 | public void stop() {
331 | if (mState == State.STOP) {
332 | log("stop() was called but video already stopped.");
333 | return;
334 | }
335 |
336 | if (mState == State.END) {
337 | log("stop() was called but video already ended.");
338 | return;
339 | }
340 |
341 | mState = State.STOP;
342 | if (mMediaPlayer.isPlaying()) {
343 | mMediaPlayer.pause();
344 | mMediaPlayer.seekTo(0);
345 | }
346 | }
347 |
348 | /**
349 | * @see android.media.MediaPlayer#setLooping(boolean)
350 | */
351 | public void setLooping(boolean looping) {
352 | mMediaPlayer.setLooping(looping);
353 | }
354 |
355 | /**
356 | * @see android.media.MediaPlayer#seekTo(int)
357 | */
358 | public void seekTo(int milliseconds) {
359 | mMediaPlayer.seekTo(milliseconds);
360 | }
361 |
362 | /**
363 | * @see android.media.MediaPlayer#getDuration()
364 | */
365 | public int getDuration() {
366 | return mMediaPlayer.getDuration();
367 | }
368 |
369 | static void log(String message) {
370 | if (LOG_ON) {
371 | Log.d(TAG, message);
372 | }
373 | }
374 |
375 | private MediaPlayerListener mListener;
376 |
377 | /**
378 | * Listener trigger 'onVideoPrepared' and `onVideoEnd` events
379 | */
380 | public void setListener(MediaPlayerListener listener) {
381 | mListener = listener;
382 | }
383 |
384 | public interface MediaPlayerListener {
385 |
386 | public void onVideoPrepared();
387 |
388 | public void onVideoEnd();
389 | }
390 |
391 | @Override
392 | public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
393 | Surface surface = new Surface(surfaceTexture);
394 | mMediaPlayer.setSurface(surface);
395 | mIsViewAvailable = true;
396 | if (mIsDataSourceSet && mIsPlayCalled && mIsVideoPrepared) {
397 | log("View is available and play() was called.");
398 | play();
399 | }
400 | }
401 |
402 | @Override
403 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
404 |
405 | }
406 |
407 | @Override
408 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
409 | return false;
410 | }
411 |
412 | @Override
413 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
414 |
415 | }
416 | }
417 |
--------------------------------------------------------------------------------
/sample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
15 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/sample/ant.properties:
--------------------------------------------------------------------------------
1 | # This file is used to override default values used by the Ant build system.
2 | #
3 | # This file must be checked into Version Control Systems, as it is
4 | # integral to the build system of your project.
5 |
6 | # This file is only used by the Ant script.
7 |
8 | # You can use this to override default values such as
9 | # 'source.dir' for the location of your java source folder and
10 | # 'out.dir' for the location of your output folder.
11 |
12 | # You can also use it define how the release builds are signed by declaring
13 | # the following properties:
14 | # 'key.store' for the location of your keystore and
15 | # 'key.alias' for the name of the key to use.
16 | # The password will be asked during the build when you use the 'release' target.
17 |
18 |
--------------------------------------------------------------------------------
/sample/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
55 |
56 |
68 |
69 |
70 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/sample/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/sample/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-14
15 | android.library.reference.1=../library
16 |
--------------------------------------------------------------------------------
/sample/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/sample/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/sample/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmytrodanylyk/video-crop/ba9ff500fd780ce02f4705ff8292de8675bb1564/sample/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/sample/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | video-crop
4 | Play
5 | Pause
6 | Resume
7 | Stop
8 |
9 |
10 | - Crop Center
11 | - Crop Top
12 | - Crop Bottom
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/src/com/dd/sample/crop/SampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.dd.sample.crop;
2 |
3 | import com.dd.crop.TextureVideoView;
4 |
5 | import android.app.ActionBar;
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.net.ConnectivityManager;
9 | import android.net.NetworkInfo;
10 | import android.os.Bundle;
11 | import android.view.View;
12 | import android.widget.ArrayAdapter;
13 | import android.widget.SpinnerAdapter;
14 | import android.widget.Toast;
15 |
16 | public class SampleActivity extends Activity implements View.OnClickListener,
17 | ActionBar.OnNavigationListener {
18 |
19 | // Video file url
20 | private static final String FILE_URL = "http://www.w3schools.com/html/mov_bbb.mp4";
21 | private TextureVideoView mTextureVideoView;
22 |
23 | @Override
24 | public void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.main);
27 |
28 | initView();
29 | initActionBar();
30 |
31 | if (!isWIFIOn(getBaseContext())) {
32 | Toast.makeText(getBaseContext(), "You need internet connection to stream video",
33 | Toast.LENGTH_LONG).show();
34 | }
35 | }
36 |
37 | private void initActionBar() {
38 | ActionBar actionBar = getActionBar();
39 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
40 | actionBar.setDisplayShowTitleEnabled(false);
41 |
42 | SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
43 | android.R.layout.simple_spinner_dropdown_item);
44 | actionBar.setListNavigationCallbacks(mSpinnerAdapter, this);
45 | }
46 |
47 | private void initView() {
48 | mTextureVideoView = (TextureVideoView) findViewById(R.id.cropTextureView);
49 |
50 | findViewById(R.id.btnPlay).setOnClickListener(this);
51 | findViewById(R.id.btnPause).setOnClickListener(this);
52 | findViewById(R.id.btnStop).setOnClickListener(this);
53 | }
54 |
55 | @Override
56 | public void onClick(View v) {
57 | switch (v.getId()) {
58 | case R.id.btnPlay:
59 | mTextureVideoView.play();
60 | break;
61 | case R.id.btnPause:
62 | mTextureVideoView.pause();
63 | break;
64 | case R.id.btnStop:
65 | mTextureVideoView.stop();
66 | break;
67 | }
68 | }
69 |
70 | final int indexCropCenter = 0;
71 | final int indexCropTop = 1;
72 | final int indexCropBottom = 2;
73 |
74 | @Override
75 | public boolean onNavigationItemSelected(int itemPosition, long itemId) {
76 | switch (itemPosition) {
77 | case indexCropCenter:
78 | mTextureVideoView.stop();
79 | mTextureVideoView.setScaleType(TextureVideoView.ScaleType.CENTER_CROP);
80 | mTextureVideoView.setDataSource(FILE_URL);
81 | mTextureVideoView.play();
82 | break;
83 | case indexCropTop:
84 | mTextureVideoView.stop();
85 | mTextureVideoView.setScaleType(TextureVideoView.ScaleType.TOP);
86 | mTextureVideoView.setDataSource(FILE_URL);
87 | mTextureVideoView.play();
88 | break;
89 | case indexCropBottom:
90 | mTextureVideoView.stop();
91 | mTextureVideoView.setScaleType(TextureVideoView.ScaleType.BOTTOM);
92 | mTextureVideoView.setDataSource(FILE_URL);
93 | mTextureVideoView.play();
94 | break;
95 | }
96 | return true;
97 | }
98 |
99 | public static boolean isWIFIOn(Context context) {
100 | ConnectivityManager connMgr =
101 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
102 | NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
103 |
104 | return (networkInfo != null && networkInfo.isConnected());
105 | }
106 | }
107 |
--------------------------------------------------------------------------------