├── assets ├── Common.zip ├── FilterAssets.zip ├── MusicAssets.zip └── MusicVideoAssets.zip ├── libs ├── gson-2.2.4.jar ├── recorderlibrary.jar ├── android-support-v13.jar └── armeabi-v7a │ ├── libwsld.so │ ├── libffmpeg.so │ ├── libvcamera.so │ └── libopenh264.so ├── res ├── raw │ └── test_cbr.mp3 ├── drawable-xhdpi │ ├── empty.png │ ├── play_big.png │ ├── loading_icon.png │ ├── record_back.png │ ├── video_focus.png │ ├── title_text_left.png │ ├── toast_tip_bg.9.png │ ├── record_next_press.png │ ├── tips_record_up.9.png │ ├── title_text_right.png │ ├── import_image_default.png │ ├── import_image_right.png │ ├── preview_music_bg.9.png │ ├── preview_music_theme.png │ ├── record_cancel_normal.png │ ├── record_cancel_press.png │ ├── record_delete_normal.png │ ├── record_delete_press.png │ ├── record_next_normal.png │ ├── record_tips_move_lr.png │ ├── uploader_dialog_bg.9.png │ ├── video_pause_big_def.png │ ├── croptips_withnone_bg.9.png │ ├── img_loading_blank_icon.png │ ├── preview_music_original.png │ ├── record_theme_selected.png │ ├── video_pause_big_press.png │ ├── checkbox_play_mode_full.png │ ├── priview_orig_volumn_close.png │ ├── priview_orig_volumn_open.png │ ├── priview_theme_volumn_open.png │ ├── record_controller_normal.png │ ├── record_controller_press.png │ ├── record_delete_check_press.png │ ├── title_text_left_default.png │ ├── title_text_left_pressed.png │ ├── video_edit_tab_split_line.png │ ├── video_online_progress_img.png │ ├── preview_music_theme_disable.png │ ├── priview_theme_volumn_close.png │ ├── record_camera_switch_normal.png │ ├── record_delete_check_normal.png │ ├── video_edit_tab_selected_bg.png │ ├── checkbox_play_mode_fitcenter.png │ ├── preview_music_original_disable.png │ ├── record_camera_switch_disable.png │ ├── record_camera_switch_pressed.png │ ├── record_theme_square_selected.png │ ├── video_selection_seek_normal.9.png │ ├── video_selection_seek_press.9.png │ ├── record_camera_flash_led_off_disable.png │ ├── record_camera_flash_led_off_normal.png │ ├── record_camera_flash_led_off_pressed.png │ ├── record_camera_flash_led_on_disable.png │ ├── record_camera_flash_led_on_normal.png │ ├── record_camera_flash_led_on_pressed.png │ ├── checkbox_play_mode_background_black_normal.png │ ├── checkbox_play_mode_background_white_normal.png │ ├── checkbox_play_mode_background_black_checked.png │ └── checkbox_play_mode_background_white_checked.png ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xxhdpi │ ├── import_video_normal.png │ ├── import_video_press.png │ └── record_preview_theme_download.png ├── layout │ ├── view_radio_item.xml │ ├── activity_single_fragment.xml │ ├── activity_video_import_video_selection.xml │ ├── activity_theme_download.xml │ ├── toast_layout.xml │ ├── dialog_encoding_novalue.xml │ ├── view_music_item.xml │ ├── dialog_record_transcoding.xml │ ├── activity_video_import_image_folder.xml │ ├── activity_video_player.xml │ ├── include_loading.xml │ ├── list_item_import_image_folder.xml │ ├── include_listview.xml │ ├── include_tilte_record.xml │ ├── menu_record_import.xml │ ├── view_theme_item.xml │ ├── activity_import_video.xml │ ├── theme_shop_theme_item.xml │ ├── include_title.xml │ ├── list_item_import_video.xml │ ├── activity_media_recorder.xml │ ├── activity_video_import_video.xml │ ├── view_video_selection.xml │ └── activity_media_preview.xml ├── drawable │ ├── video_cut_bg.xml │ ├── record_next_seletor.xml │ ├── loading_progress.xml │ ├── import_folder_selector.xml │ ├── gt10_progressbar.xml │ ├── priview_theme_volumn_selector.xml │ ├── priview_orig_volumn_selector.xml │ ├── video_selection_seek_selector.xml │ ├── checkbox_play_video_switch_mode.xml │ ├── play_mode_background_black_bg.xml │ ├── play_mode_background_white_bg.xml │ ├── import_video_selector.xml │ ├── record_cancel_seletor.xml │ ├── video_pause_big_selector.xml │ ├── priview_edit_tab_selector.xml │ ├── record_controller_seletor.xml │ ├── title_left_selector.xml │ ├── record_camera_switch_selector.xml │ ├── record_delete_selector.xml │ └── record_camera_flash_led_selector.xml ├── color │ ├── text_color_selector.xml │ ├── video_edit_text_color_selector.xml │ └── record_text_color_selector.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml ├── values │ ├── integers.xml │ ├── attrs.xml │ ├── drawables.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── anim │ └── record_focus.xml ├── proguard └── proguard.jar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── com │ └── yixia │ └── camera │ └── demo │ ├── ui │ ├── record │ │ ├── UnknownStreamException.java │ │ ├── InvalidStreamException.java │ │ ├── NetworkException.java │ │ ├── VDownloaderConfigHelper.java │ │ ├── views │ │ │ ├── HorizontalScrollViewEx.java │ │ │ ├── ThemeRadioButton.java │ │ │ ├── ThemeGroupLayout.java │ │ │ ├── BitmapImageView.java │ │ │ ├── ThemeView.java │ │ │ ├── VideoThumbImageView.java │ │ │ ├── SelectionView.java │ │ │ └── ProgressView.java │ │ ├── IOUtils.java │ │ ├── Crypto.java │ │ ├── VideoPlayerActivity.java │ │ ├── adapter │ │ │ ├── ImportVideoFolderAdapter.java │ │ │ └── ImportVideoSelectionAdapter.java │ │ └── ImportVideoSelectActivity.java │ ├── LaunchActivity.java │ └── BaseActivity.java │ ├── util │ ├── Constant.java │ └── ViewHolderUtils.java │ ├── common │ └── CommonIntentExtra.java │ ├── po │ ├── VideoThumb.java │ └── Video.java │ ├── VCameraDemoApplication.java │ ├── os │ └── ThreadTask.java │ └── media │ └── MediaPlayer.java ├── CHANGELOG.md ├── .gitignore ├── .classpath ├── project.properties ├── proguard-project.txt ├── gradle.properties ├── .project ├── gradlew.bat ├── README.md ├── AndroidManifest.xml └── gradlew /assets/Common.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/assets/Common.zip -------------------------------------------------------------------------------- /libs/gson-2.2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/gson-2.2.4.jar -------------------------------------------------------------------------------- /res/raw/test_cbr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/raw/test_cbr.mp3 -------------------------------------------------------------------------------- /assets/FilterAssets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/assets/FilterAssets.zip -------------------------------------------------------------------------------- /assets/MusicAssets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/assets/MusicAssets.zip -------------------------------------------------------------------------------- /proguard/proguard.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/proguard/proguard.jar -------------------------------------------------------------------------------- /libs/recorderlibrary.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/recorderlibrary.jar -------------------------------------------------------------------------------- /assets/MusicVideoAssets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/assets/MusicVideoAssets.zip -------------------------------------------------------------------------------- /libs/android-support-v13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/android-support-v13.jar -------------------------------------------------------------------------------- /libs/armeabi-v7a/libwsld.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/armeabi-v7a/libwsld.so -------------------------------------------------------------------------------- /res/drawable-xhdpi/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/empty.png -------------------------------------------------------------------------------- /libs/armeabi-v7a/libffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/armeabi-v7a/libffmpeg.so -------------------------------------------------------------------------------- /libs/armeabi-v7a/libvcamera.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/armeabi-v7a/libvcamera.so -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /libs/armeabi-v7a/libopenh264.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/libs/armeabi-v7a/libopenh264.so -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/play_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/play_big.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/loading_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/loading_icon.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_back.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_focus.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/title_text_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/title_text_left.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/toast_tip_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/toast_tip_bg.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_next_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_next_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/tips_record_up.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/tips_record_up.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/title_text_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/title_text_right.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/import_image_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/import_image_default.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/import_image_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/import_image_right.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/preview_music_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/preview_music_bg.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/preview_music_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/preview_music_theme.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_cancel_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_cancel_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_cancel_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_cancel_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_delete_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_delete_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_delete_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_delete_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_next_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_next_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_tips_move_lr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_tips_move_lr.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/uploader_dialog_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/uploader_dialog_bg.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_pause_big_def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_pause_big_def.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/import_video_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xxhdpi/import_video_normal.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/import_video_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xxhdpi/import_video_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/croptips_withnone_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/croptips_withnone_bg.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/img_loading_blank_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/img_loading_blank_icon.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/preview_music_original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/preview_music_original.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_theme_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_theme_selected.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_pause_big_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_pause_big_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_full.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/priview_orig_volumn_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/priview_orig_volumn_close.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/priview_orig_volumn_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/priview_orig_volumn_open.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/priview_theme_volumn_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/priview_theme_volumn_open.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_controller_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_controller_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_controller_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_controller_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_delete_check_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_delete_check_press.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/title_text_left_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/title_text_left_default.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/title_text_left_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/title_text_left_pressed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_edit_tab_split_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_edit_tab_split_line.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_online_progress_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_online_progress_img.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/preview_music_theme_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/preview_music_theme_disable.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/priview_theme_volumn_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/priview_theme_volumn_close.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_switch_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_switch_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_delete_check_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_delete_check_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_edit_tab_selected_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_edit_tab_selected_bg.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_fitcenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_fitcenter.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/preview_music_original_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/preview_music_original_disable.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_switch_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_switch_disable.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_switch_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_switch_pressed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_theme_square_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_theme_square_selected.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_selection_seek_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_selection_seek_normal.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/video_selection_seek_press.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/video_selection_seek_press.9.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/record_preview_theme_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xxhdpi/record_preview_theme_download.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_off_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_off_disable.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_off_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_off_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_off_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_off_pressed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_on_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_on_disable.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_on_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_on_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/record_camera_flash_led_on_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/record_camera_flash_led_on_pressed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_background_black_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_background_black_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_background_white_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_background_white_normal.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_background_black_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_background_black_checked.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/checkbox_play_mode_background_white_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightq/VitamioRecorderSampleFor/HEAD/res/drawable-xhdpi/checkbox_play_mode_background_white_checked.png -------------------------------------------------------------------------------- /res/layout/view_radio_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/UnknownStreamException.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record; 2 | 3 | public class UnknownStreamException extends Exception { 4 | private static final long serialVersionUID = 6910304461954479568L; 5 | } -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/InvalidStreamException.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record; 2 | 3 | public class InvalidStreamException extends Exception { 4 | private static final long serialVersionUID = -7287854603988271545L; 5 | } 6 | -------------------------------------------------------------------------------- /res/layout/activity_single_fragment.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/video_cut_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 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.10-all.zip 7 | -------------------------------------------------------------------------------- /res/drawable/record_next_seletor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/loading_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/util/Constant.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.util; 2 | 3 | public class Constant { 4 | 5 | public static final String RECORD_VIDEO_KEY = "key"; 6 | public static final String RECORD_VIDEO_PATH = "path"; 7 | public static final String RECORD_VIDEO_CAPTURE = "capture"; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /res/drawable/import_folder_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/gt10_progressbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /res/drawable/priview_theme_volumn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/priview_orig_volumn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/video_selection_seek_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/color/text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/drawable/checkbox_play_video_switch_mode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/LaunchActivity.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | public class LaunchActivity extends Activity { 7 | // launcher 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /res/drawable/play_mode_background_black_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/play_mode_background_white_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/import_video_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/color/video_edit_text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/color/record_text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/drawable/record_cancel_seletor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | version 1.2.0 *(2014-05-18)* 5 | --------------------------- 6 | 7 | * 支持连续对焦(部分设备不支持) 8 | * 修复ZTE 9 | 10 | version 1.1.0 *(2014-05-18)* 11 | --------------------------- 12 | 13 | * 支持gif主题 14 | * 支持本地图片和视频导入 15 | 16 | version 1.0.0 *(2014-5-4)* 17 | --------------------------- 18 | 19 | * 支持视频分段拍摄、回删 20 | * 支持视频拍摄实时滤镜(八种滤镜) 21 | * 支持水印、声音主题合成 22 | * 支持FFMPEG命令行操作 23 | -------------------------------------------------------------------------------- /res/drawable/video_pause_big_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/drawable/priview_edit_tab_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/drawable/record_controller_seletor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/drawable/title_left_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/layout/activity_video_import_video_selection.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | 10 | # built application files 11 | # *.apk 12 | *.ap_ 13 | 14 | # files for the dex VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # generated files 21 | bin/ 22 | gen/ 23 | build/ 24 | .gradle/ 25 | 26 | .settings/org.eclipse.ltk.core.refactoring.prefs 27 | 28 | # Intellij IDEA 29 | .idea 30 | -------------------------------------------------------------------------------- /res/drawable/record_camera_switch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/NetworkException.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record; 2 | 3 | import java.net.SocketException; 4 | import java.net.SocketTimeoutException; 5 | import java.net.UnknownHostException; 6 | 7 | public class NetworkException { 8 | public static boolean isNetworkException(Exception e) { 9 | return (e instanceof SocketException) || (e instanceof SocketTimeoutException) || (e instanceof UnknownHostException); 10 | } 11 | } -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0 5 | 0 6 | 1 7 | 0 8 | 1 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/VDownloaderConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record; 2 | 3 | import com.yixia.camera.demo.R; 4 | 5 | 6 | public final class VDownloaderConfigHelper { 7 | public static Class NOTIFICATION_CLASS; 8 | public static int NOTIFICATION_ICON = R.drawable.ic_launcher; 9 | public static String AUTHORITY = "com.yixia.videoeditor.vdownloader"; 10 | public static String PACKAGE_NAME = "com.yixia.videoeditor"; 11 | public static String NOTIFICATION_CONTENT_TITLE; 12 | public static String NOTIFICATION_CONTENT_TEXT; 13 | } 14 | -------------------------------------------------------------------------------- /res/drawable/record_delete_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /res/layout/activity_theme_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /res/layout/toast_layout.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/common/CommonIntentExtra.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.common; 2 | 3 | public class CommonIntentExtra { 4 | 5 | /** 是否退出 */ 6 | public final static String USER_IS_LOGOUT = "is_logout"; 7 | 8 | /** 录制时间控制 */ 9 | public final static String RECORD_TIME_INTENT = "RECORD_TIME"; 10 | 11 | /** 录制信息存储 */ 12 | public final static String EXTRA_MEDIA_OBJECT = "extra_media_object"; 13 | 14 | /** 是否图片导入 */ 15 | public final static String EXTRA_MEDIA_IMPORT_IMAGE = "extra_media_import_image"; 16 | 17 | /** 是否视频导入 */ 18 | public final static String EXTRA_MEDIA_IMPORT_VIDEO = "extra_media_import_video"; 19 | 20 | /** 是否在线视频导入 */ 21 | public final static String EXTRA_MEDIA_IMPORT_VIDEO_ONLINE = "extra_media_import_video_online"; 22 | 23 | /** 多格视频 */ 24 | public final static String EXTRA_MEDIA_VIDEO_MULTI = "extra_media_video_multi"; 25 | } 26 | -------------------------------------------------------------------------------- /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 | #Tue Mar 15 11:40:48 CST 2016 16 | systemProp.http.proxyHost=127.0.0.1 17 | systemProp.http.proxyPort=1080 18 | -------------------------------------------------------------------------------- /res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /res/drawable/record_camera_flash_led_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/util/ViewHolderUtils.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.util; 2 | 3 | import android.util.SparseArray; 4 | import android.view.View; 5 | 6 | public class ViewHolderUtils { 7 | 8 | /** 9 | * 用法: ImageView bananaView = ViewHolder.get(convertView, R.id.banana); 10 | * 11 | * @param convertView 12 | * @param id 13 | * @return 14 | */ 15 | @SuppressWarnings("unchecked") 16 | public static T getView(View convertView, int id) { 17 | SparseArray viewHolder = (SparseArray) convertView.getTag(); 18 | if (viewHolder == null) { 19 | viewHolder = new SparseArray(); 20 | convertView.setTag(viewHolder); 21 | } 22 | View childView = viewHolder.get(id); 23 | if (childView == null) { 24 | childView = convertView.findViewById(id); 25 | viewHolder.put(id, childView); 26 | } 27 | return (T) childView; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | VitamioRecorderSampleFor 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /res/layout/dialog_encoding_novalue.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /res/layout/view_music_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 15 | 16 | 26 | 27 | -------------------------------------------------------------------------------- /res/values/drawables.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #2c2c2c 5 | #fcb840 6 | #929292 7 | #00000000 8 | #F2F2F2 9 | #E5E5E5 10 | #64000000 11 | #ffffff 12 | #c3c3c3 13 | 14 | #1E1E1E 15 | 16 | #252527 17 | #000000 18 | 19 | #c3c3c3 20 | 21 | #434345 22 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/po/VideoThumb.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.po; 2 | 3 | import java.util.Locale; 4 | 5 | public class VideoThumb { 6 | 7 | public String url; 8 | public String thumb; 9 | public long _id; 10 | /** 视频有问题,截图失败 */ 11 | public boolean faild; 12 | 13 | @Override 14 | public int hashCode() { 15 | final int prime = 31; 16 | int result = 1; 17 | result = prime * result + ((url == null) ? 0 : url.toLowerCase(Locale.CHINESE).hashCode()); 18 | return result; 19 | } 20 | 21 | @Override 22 | public boolean equals(Object obj) { 23 | if (this == obj) 24 | return true; 25 | if (obj == null) 26 | return false; 27 | if (getClass() != obj.getClass()) 28 | return false; 29 | VideoThumb other = (VideoThumb) obj; 30 | if (url == null) { 31 | if (other.url != null) 32 | return false; 33 | } else if (!url.toLowerCase(Locale.CHINESE).equals(other.url.toLowerCase(Locale.CHINESE))) 34 | return false; 35 | return true; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/po/Video.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.po; 2 | 3 | public final class Video extends VideoThumb { 4 | public boolean checked; 5 | public com.yixia.weibo.sdk.model.MediaObject$MediaPart part; 6 | public long added; 7 | public int duration; 8 | public long size; 9 | public int orientation; 10 | /** md5值 */ 11 | public String key; 12 | 13 | // public Video(String url) { 14 | // this.url = url; 15 | // } 16 | 17 | public Video(String url, long added, long size) { 18 | this.url = url; 19 | this.added = added; 20 | this.size = size; 21 | } 22 | 23 | public Video(String url, long added, int duration) { 24 | this.url = url; 25 | this.added = added; 26 | this.duration = duration; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (obj != null && getClass() == obj.getClass() && url != null && url.equals(((Video) obj).url)) { 32 | // 继续比较相等性或直接返回true 33 | return true; 34 | } 35 | return false; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /res/layout/dialog_record_transcoding.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 23 | 24 | -------------------------------------------------------------------------------- /res/anim/record_focus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 19 | 25 | 37 | 38 | -------------------------------------------------------------------------------- /res/layout/activity_video_import_image_folder.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /res/layout/activity_video_player.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 24 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /res/layout/include_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 21 | 22 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/HorizontalScrollViewEx.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.widget.HorizontalScrollView; 7 | 8 | public class HorizontalScrollViewEx extends HorizontalScrollView { 9 | 10 | private OnFlingListener mOnFlingListener; 11 | 12 | public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyle) { 13 | super(context, attrs, defStyle); 14 | } 15 | 16 | public HorizontalScrollViewEx(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public void setOnFlingListener(OnFlingListener l) { 21 | this.mOnFlingListener = l; 22 | } 23 | 24 | @Override 25 | protected int computeHorizontalScrollOffset() { 26 | if (mOnFlingListener != null) 27 | mOnFlingListener.onFlingScrollChange(); 28 | return super.computeHorizontalScrollOffset(); 29 | } 30 | 31 | @Override 32 | protected void onScrollChanged(int l, int t, int oldl, int oldt) { 33 | if (mOnFlingListener != null) 34 | mOnFlingListener.onFlingScrollChange(); 35 | super.onScrollChanged(l, t, oldl, oldt); 36 | } 37 | 38 | public static interface OnFlingListener { 39 | void onFlingScrollChange(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/ThemeRadioButton.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.CompoundButton; 6 | import android.widget.RadioButton; 7 | 8 | import com.yixia.camera.demo.R; 9 | 10 | public class ThemeRadioButton extends RadioButton implements android.widget.CompoundButton.OnCheckedChangeListener { 11 | 12 | private int mColorNormal, mColorSelected; 13 | 14 | public ThemeRadioButton(Context context, AttributeSet attrs, int defStyle) { 15 | super(context, attrs, defStyle); 16 | init(); 17 | } 18 | 19 | public ThemeRadioButton(Context context, AttributeSet attrs) { 20 | super(context, attrs); 21 | init(); 22 | } 23 | 24 | public ThemeRadioButton(Context context) { 25 | super(context); 26 | init(); 27 | } 28 | 29 | private void init() { 30 | mColorNormal = getResources().getColor(R.color.transparent); 31 | mColorSelected = getResources().getColor(R.color.camera_theme_selected_bgcolor); 32 | setOnCheckedChangeListener(this); 33 | } 34 | 35 | @Override 36 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 37 | if (isChecked) 38 | setBackgroundColor(mColorSelected); 39 | else 40 | setBackgroundColor(mColorNormal); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/ThemeGroupLayout.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.LinearLayout; 6 | 7 | import java.util.Observable; 8 | 9 | public class ThemeGroupLayout extends LinearLayout { 10 | 11 | public ThemeGroupLayout(Context context, AttributeSet attrs) { 12 | super(context, attrs); 13 | } 14 | 15 | public ThemeGroupLayout(Context context) { 16 | super(context); 17 | } 18 | 19 | public void addView(ThemeView child, android.view.ViewGroup.LayoutParams params) { 20 | super.addView(child, params); 21 | mObservable.addObserver(child); 22 | } 23 | 24 | public void addView(ThemeView child, int index, android.view.ViewGroup.LayoutParams params) { 25 | super.addView(child, index, params); 26 | mObservable.addObserver(child); 27 | } 28 | 29 | @Override 30 | public void removeAllViews() { 31 | super.removeAllViews(); 32 | mObservable.deleteObservers(); 33 | } 34 | 35 | public Observable mObservable = new Observable() { 36 | @Override 37 | public void notifyObservers() { 38 | setChanged(); 39 | super.notifyObservers(); 40 | clearChanged(); 41 | } 42 | 43 | @Override 44 | public void notifyObservers(Object data) { 45 | setChanged(); 46 | super.notifyObservers(data); 47 | clearChanged(); 48 | }; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /res/layout/list_item_import_image_folder.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /res/layout/include_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 22 | 23 | 24 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /res/layout/include_tilte_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/IOUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 YIXIA.COM 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.yixia.camera.demo.ui.record; 17 | 18 | import java.io.Closeable; 19 | import java.io.FileReader; 20 | 21 | import android.database.Cursor; 22 | import android.os.ParcelFileDescriptor; 23 | import android.util.Log; 24 | 25 | public class IOUtils { 26 | 27 | private static final String TAG = "IOUtils"; 28 | 29 | public static void closeSilently(Closeable c) { 30 | if (c == null) 31 | return; 32 | try { 33 | c.close(); 34 | } catch (Throwable t) { 35 | Log.w(TAG, "fail to close", t); 36 | } 37 | } 38 | 39 | public static void closeSilently(FileReader c) { 40 | if (c == null) 41 | return; 42 | try { 43 | c.close(); 44 | } catch (Throwable t) { 45 | Log.w(TAG, "fail to close", t); 46 | } 47 | } 48 | 49 | public static void closeSilently(ParcelFileDescriptor c) { 50 | if (c == null) 51 | return; 52 | try { 53 | c.close(); 54 | } catch (Throwable t) { 55 | Log.w(TAG, "fail to close", t); 56 | } 57 | } 58 | 59 | public static void closeSilently(Cursor cursor) { 60 | try { 61 | if (cursor != null) cursor.close(); 62 | } catch (Throwable t) { 63 | Log.w(TAG, "fail to close", t); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /res/layout/menu_record_import.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | -------------------------------------------------------------------------------- /res/layout/view_theme_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 21 | 22 | 29 | 30 | 41 | 42 | 52 | 53 | -------------------------------------------------------------------------------- /res/layout/activity_import_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 19 | 20 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 37 | 38 | 42 | 43 | 47 | 48 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/BitmapImageView.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.util.AttributeSet; 7 | import android.widget.ImageView; 8 | 9 | import com.yixia.camera.demo.log.Logger; 10 | import com.yixia.weibo.sdk.util.StringUtils; 11 | 12 | /** 13 | * 专门用来处理Bitmap类型的ImageView,onDetachedFromWindow时释放,防止内存泄露 14 | * 15 | * @author tangjun 16 | * 17 | */ 18 | public class BitmapImageView extends ImageView { 19 | 20 | private Bitmap mBitmap; 21 | private String mPath; 22 | 23 | public BitmapImageView(Context context) { 24 | super(context); 25 | } 26 | 27 | public BitmapImageView(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | } 30 | 31 | public void setImagePath(String path) { 32 | release(); 33 | if (StringUtils.isNotEmpty(path)) { 34 | try { 35 | mBitmap = BitmapFactory.decodeFile(path); 36 | if (mBitmap != null && !mBitmap.isRecycled()) { 37 | mPath = path; 38 | setImageBitmap(mBitmap); 39 | } 40 | } catch (OutOfMemoryError e) { 41 | Logger.e(e); 42 | } catch (Exception e) { 43 | Logger.e(e); 44 | } 45 | } 46 | } 47 | 48 | public void setImageUrl(String path) { 49 | release(); 50 | if (StringUtils.isNotEmpty(path)) { 51 | try { 52 | mBitmap = BitmapFactory.decodeFile(path); 53 | if (mBitmap != null && !mBitmap.isRecycled()) { 54 | mPath = path; 55 | setImageBitmap(mBitmap); 56 | } 57 | } catch (OutOfMemoryError e) { 58 | Logger.e(e); 59 | } catch (Exception e) { 60 | Logger.e(e); 61 | } 62 | } 63 | } 64 | 65 | @Override 66 | protected void onAttachedToWindow() { 67 | super.onAttachedToWindow(); 68 | if (StringUtils.isNotEmpty(mPath)) { 69 | setImagePath(mPath); 70 | } 71 | } 72 | 73 | @Override 74 | protected void onDetachedFromWindow() { 75 | super.onDetachedFromWindow(); 76 | release(); 77 | } 78 | 79 | public void release() { 80 | if (mBitmap != null) { 81 | if (!mBitmap.isRecycled()) 82 | mBitmap.recycle(); 83 | mBitmap = null; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #404040ff 5 | #000 6 | #FF0000 7 | #0ff0ff 8 | #c0c0c0ff 9 | #ffffffff 10 | #ff0f81d9 11 | #ff666666 12 | #ffC3C3C3 13 | #ff6699ff 14 | #66ffffff 15 | #00000000 16 | #ff000000 17 | #f0f0f0 18 | #2c2c2c 19 | #2980B9 20 | #005084 21 | #24ff00 22 | #1b5d89 23 | #2980B9 24 | #1b1c1f 25 | #fcb840 26 | #f68b2b 27 | #CC000000 28 | #7f000000 29 | #66000000 30 | #DA000000 31 | #4D000000 32 | #FF434345 33 | #e7e7e7 34 | 35 | #23232b 36 | 37 | #1c1b20 38 | 39 | #919191 40 | #F5F5F5 41 | #ffc800 42 | #23232b 43 | #23232b 44 | #FF151515 45 | #BF000000 46 | #424253 47 | #FF515154 48 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/VCameraDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo; 2 | 3 | import java.io.File; 4 | 5 | import android.app.Application; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.os.Environment; 9 | import android.support.multidex.MultiDexApplication; 10 | 11 | import com.yixia.camera.demo.service.AssertService; 12 | import com.yixia.weibo.sdk.VCamera; 13 | import com.yixia.weibo.sdk.util.DeviceUtils; 14 | import com.yixia.weibo.sdk.util.FileUtils; 15 | import com.yixia.weibo.sdk.util.ToastUtils; 16 | 17 | public class VCameraDemoApplication extends MultiDexApplication { 18 | 19 | private static VCameraDemoApplication application; 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | application = this; 25 | 26 | // 设置拍摄视频缓存路径 27 | File dcim = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); 28 | if (DeviceUtils.isZte()) { 29 | if (dcim.exists()) { 30 | VCamera.setVideoCachePath(dcim + "/Camera/VCameraDemo/"); 31 | } else { 32 | VCamera.setVideoCachePath(dcim.getPath().replace("/sdcard/", "/sdcard-ext/") + "/Camera/VCameraDemo/"); 33 | } 34 | } else { 35 | VCamera.setVideoCachePath(dcim + "/Camera/VCameraDemo/"); 36 | } 37 | // 开启log输出,ffmpeg输出到logcat 38 | VCamera.setDebugMode(true); 39 | // 初始化拍摄SDK,必须 40 | VCamera.initialize(this); 41 | 42 | //解压assert里面的文件 43 | startService(new Intent(this, AssertService.class)); 44 | } 45 | 46 | public static Context getContext() { 47 | return application; 48 | } 49 | 50 | public static File getGifCacheDirectory() { 51 | if (application != null) 52 | return FileUtils.getCacheDiskPath(application, "gif");//vineApplication.getExternalCacheDir() + "/cache/gif/"; 53 | return null; 54 | } 55 | 56 | 57 | public final static int AVAILABLE_SPACE = 200;//M 58 | /** 59 | * 检测用户手机是否剩余可用空间200M以上 60 | * @return 61 | */ 62 | public static boolean isAvailableSpace() { 63 | if (application == null) { 64 | return false; 65 | } 66 | //检测磁盘空间 67 | if (FileUtils.showFileAvailable(application) < AVAILABLE_SPACE) { 68 | ToastUtils.showToast(application, application.getString(R.string.record_check_available_faild, AVAILABLE_SPACE)); 69 | return false; 70 | } 71 | 72 | return true; 73 | } 74 | 75 | /** 视频截图目录 */ 76 | public static File getThumbCacheDirectory() { 77 | if (application != null) 78 | return FileUtils.getCacheDiskPath(application, "thumbs");//vineApplication.getExternalCacheDir() + "/cache/thumbs/"; 79 | return null; 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /res/layout/theme_shop_theme_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 28 | 29 | 37 | 38 | 51 | 52 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/os/ThreadTask.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.os; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | import android.os.Looper; 6 | import android.os.Message; 7 | 8 | public abstract class ThreadTask { 9 | 10 | private HandlerThread mHandlerThread; 11 | private TaskHandler mHandler; 12 | private TaskHandler mUiHandler; 13 | private Params[] mParams; 14 | private boolean mRunning = true; 15 | private long mStartTime; 16 | private long mEndTime; 17 | 18 | private static final int MESSAGE_INBACKGROUND = 0; 19 | private static final int MESSAGE_POSTEXECUTE = 1; 20 | private static final int MESSAGE_PROGRESS = 2; 21 | 22 | public ThreadTask() { 23 | //降低线程的优先级 24 | mHandlerThread = new HandlerThread("ThreadTask", android.os.Process.THREAD_PRIORITY_BACKGROUND); 25 | mHandlerThread.start(); 26 | 27 | mHandler = new TaskHandler(mHandlerThread.getLooper()); 28 | mUiHandler = new TaskHandler(Looper.getMainLooper()); 29 | } 30 | 31 | public synchronized boolean isRunning() { 32 | return mRunning; 33 | } 34 | 35 | protected abstract Result doInBackground(Params... params); 36 | 37 | protected void onPreExecute() { 38 | } 39 | 40 | protected synchronized void onProgressUpdate(Progress... values) { 41 | } 42 | 43 | protected final void publishProgress(Progress... values) { 44 | mUiHandler.obtainMessage(MESSAGE_PROGRESS, values).sendToTarget(); 45 | } 46 | 47 | protected synchronized void onPostExecute(Result result) { 48 | } 49 | 50 | public final boolean isCancelled() { 51 | return !mRunning; 52 | } 53 | 54 | public void cancel() { 55 | mRunning = false; 56 | mHandlerThread.quit(); 57 | } 58 | 59 | public void execute(Params... params) { 60 | mRunning = true; 61 | mParams = params; 62 | onPreExecute(); 63 | mHandler.sendEmptyMessage(MESSAGE_INBACKGROUND); 64 | } 65 | 66 | /** 获取doInBackground的执行时间 毫秒 */ 67 | public long getExecuteTime() { 68 | return mEndTime - mStartTime; 69 | } 70 | 71 | private class TaskHandler extends Handler { 72 | 73 | public TaskHandler(Looper looper) { 74 | super(looper); 75 | } 76 | 77 | @SuppressWarnings("unchecked") 78 | @Override 79 | public void handleMessage(Message msg) { 80 | switch (msg.what) { 81 | case MESSAGE_INBACKGROUND: 82 | mStartTime = System.currentTimeMillis(); 83 | mUiHandler.obtainMessage(MESSAGE_POSTEXECUTE, doInBackground(mParams)).sendToTarget(); 84 | break; 85 | case MESSAGE_POSTEXECUTE: 86 | mEndTime = System.currentTimeMillis(); 87 | mRunning = false; 88 | onPostExecute((Result) msg.obj); 89 | try { 90 | mHandlerThread.quit(); 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } 94 | break; 95 | case MESSAGE_PROGRESS: 96 | onProgressUpdate((Progress[]) msg.obj); 97 | break; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /res/layout/include_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 27 | 28 | 43 | 44 | 59 | 60 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VCamera 2 | =============== 3 | 4 | VCamera SDK Android版(短视频拍摄SDK)是炫一下(北京)科技有限公司官方推出的Android平台使用的软件开发工具包,为Android开发者提供简单、快捷的接口,帮助开发者实现Android平台上的短视频应用开发。 5 | 6 | 7 | ## 使用android studio编译 8 | 9 | >####1.如果使用android studio 开发,在使用 muldex 并打开的情况下,由于vitamio 的jar是混效过的,所以会导致再次打包的时候混淆一个混淆过的jar包的错误: 10 | 11 | > `java.io.IOException: Can't read [ /build/intermediates/transforms/jarMerging/aliyun/debug/jars/1/1f/combined.jar] (Can't process class [com/yixia/camera/demo/ui/record/helper/ThemeHelper.class] (Unknown verification type [10] in stack map frame))` 12 | 13 | >####2.如下是我的解决方案: 14 | > 15 | > 1. 首先在 [《Proguard源码库》](https://sourceforge.net/projects/proguard/) 右下角 Tags 选择一个版本(eg. 5.2.1)的标签, 然后点击左边的 Download Snapshot 按钮进行下载这个版本的源码。 16 | > 2. 解压放到您的android studio 的 sdk/tools 目录下并以 proguard5.2.1 命名,以便与sdk自带的proguard包区分。 17 | > 3. 参考 [《修改proguard源码》](http://innodroid.com/blog/post/use-a-custom-proguard-build-with-gradle) 修改 tools/proguard5.2.1/src/ClassContacts.java 里面的 18 |
`public static final String ATTR_StackMapTable = "StackMapTable";` 19 |
替换为: 20 |
`public static final String ATTR_StackMapTable = "dummy";` 21 |
在 proguard5.2.1/buildscripts 目录下使用 [ant命令](http://ant.apache.org/) 编译 (如没有安装自寻在网上搜索安装).编译完成后会在 proguard5.2.1/lib 目录下生成 proguard.jar 等文件. 22 | > 4. 需要在项目工程里面配置使用新版本的依赖和引用: 23 |
在根目录创建 proguard 目录,并将上面生成的 proguard.jar 拷入其中 24 |
在根目录的 build.gradle 里面添加: 25 |

26 | buildscript {
27 |     repositories {
28 |         // 引用 proguard 包
29 |         flatDir { dirs 'proguard' }
30 |         jcenter()
31 |     }
32 |     dependencies {
33 |         // 这里的 5.2.1 是根据你下载的版本号填写
34 |         classpath 'proguard.io:proguard:5.2.1'
35 |         classpath 'com.android.tools.build:gradle:2.0.0-beta5' 
36 |     }
37 | }
38 | 39 | >####3.clear 您的工程。进行编译就行了。 40 | 41 | 后话 42 | ----------- 43 | 44 | > 1.在demo中这样修改已经能正常使用了。但是在我的工程中,因为使用一些其它库,可能会导致 AsyncTask 被卡死,不能尽快的执行,可能要等很久才执行,就会导致录视频之后 encode 要很久都不开始执行,是因为jar包中有一些耗时操作是使用了 AsyncTask 这个类,所以导致很久都不开始执行。 45 | > 目前,可以在 AndroidManifest.xml 里面的 MediaRecorderActivity 生命的地方加上 46 | >
`android:process="vitamio.record.video"` 47 | >
这里进程名字可以自定义,这样录制部分在新进程中执行就不会受到其它地方的影响了。 48 | > 49 | > 2.作如下修改可以使用新版本的混淆工具,虽然并没有什么明显的东西~~~如下: 50 | > 把 sdk/tools 里面的 proguard 使用新版本: 51 | > 52 | > 1. 将 sdk/tools/proguard 里面的 53 |
proguard-android-optimize.txt 54 |
proguard-android.txt 55 |
proguard-project.txt 56 |
三个配置文件拷入 sdk/tools/proguard5.2.1 57 | > 2. 将 sdk/tools/proguard 重命名为 sdk/tools/proguardold 58 | > 3. 将 sdk/tools/proguard5.2.1 重命名为 sdk/tools/proguard。 59 | 60 | > 经过这样的修改,我的工程中能一样完美的使用 vitamio 了。 61 | 62 | Developed By 63 | ============ 64 | * NightQ 65 | 66 | 参考 67 | ------ 68 | > * https://sourceforge.net/p/proguard/bugs/420/?page=0 69 | > * http://innodroid.com/blog/post/use-a-custom-proguard-build-with-gradle 70 | > * https://sourceforge.net/projects/proguard/ 71 | 72 | ##支持特性 73 | 74 | > * 支持分段拍摄、回删 75 | > * 支持静态/动态水印、声音主题合成 76 | > * 支持FFmpeg命令行 77 | > * 支持ARMV7 CPU 78 | 79 | 如何使用 80 | ---------- 81 | 82 | 请参考[VCamera Android SDK用户手册](http://wscdn.miaopai.com/download/VCameraRecorder3.1.pdf) 83 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | 8 | import android.app.Activity; 9 | import android.app.ProgressDialog; 10 | import android.view.Window; 11 | 12 | import com.google.gson.Gson; 13 | import com.yixia.camera.demo.log.Logger; 14 | import com.yixia.weibo.sdk.model.MediaObject; 15 | import com.yixia.weibo.sdk.model.MediaObject$MediaPart; 16 | import com.yixia.weibo.sdk.util.FileUtils; 17 | import com.yixia.weibo.sdk.util.Log; 18 | import com.yixia.weibo.sdk.util.StringUtils; 19 | 20 | 21 | public class BaseActivity extends Activity { 22 | 23 | protected ProgressDialog mProgressDialog; 24 | 25 | public ProgressDialog showProgress(String title, String message) { 26 | return showProgress(title, message, -1); 27 | } 28 | 29 | public ProgressDialog showProgress(String title, String message, int theme) { 30 | if (mProgressDialog == null) { 31 | if (theme > 0) 32 | mProgressDialog = new ProgressDialog(this, theme); 33 | else 34 | mProgressDialog = new ProgressDialog(this); 35 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 36 | mProgressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 37 | mProgressDialog.setCanceledOnTouchOutside(false);// 不能取消 38 | mProgressDialog.setIndeterminate(true);// 设置进度条是否不明确 39 | } 40 | 41 | if (!StringUtils.isEmpty(title)) 42 | mProgressDialog.setTitle(title); 43 | mProgressDialog.setMessage(message); 44 | mProgressDialog.show(); 45 | return mProgressDialog; 46 | } 47 | 48 | public void hideProgress() { 49 | if (mProgressDialog != null) { 50 | mProgressDialog.dismiss(); 51 | } 52 | } 53 | 54 | @Override 55 | protected void onStop() { 56 | super.onStop(); 57 | 58 | hideProgress(); 59 | mProgressDialog = null; 60 | } 61 | 62 | /** 反序列化对象 */ 63 | protected static MediaObject restoneMediaObject(String obj) { 64 | try { 65 | String str = FileUtils.readFile(new File(obj)); 66 | Gson gson = new Gson(); 67 | MediaObject result = gson.fromJson(str.toString(), MediaObject.class); 68 | result.getCurrentPart(); 69 | preparedMediaObject(result); 70 | return result; 71 | } catch (Exception e) { 72 | if (e != null) 73 | Log.e("VCamera", "readFile", e); 74 | } 75 | return null; 76 | } 77 | 78 | /** 预处理数据对象 */ 79 | public static void preparedMediaObject(MediaObject mMediaObject) { 80 | if (mMediaObject != null && mMediaObject.getMedaParts() != null) { 81 | int duration = 0; 82 | for (com.yixia.weibo.sdk.model.MediaObject$MediaPart part : (LinkedList)mMediaObject.getMedaParts()) { 83 | part.startTime = duration; 84 | part.endTime = part.startTime + part.duration; 85 | duration += part.duration; 86 | } 87 | } 88 | } 89 | 90 | /** 序列号保存视频数据 */ 91 | public static boolean saveMediaObject(MediaObject mMediaObject) { 92 | if (mMediaObject != null) { 93 | try { 94 | if (StringUtils.isNotEmpty(mMediaObject.getObjectFilePath())) { 95 | FileOutputStream out = new FileOutputStream(mMediaObject.getObjectFilePath()); 96 | Gson gson = new Gson(); 97 | out.write(gson.toJson(mMediaObject).getBytes()); 98 | out.flush(); 99 | out.close(); 100 | return true; 101 | } 102 | } catch (Exception e) { 103 | Logger.e(e); 104 | } 105 | } 106 | return false; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 26 | 29 | 30 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | 55 | 59 | 60 | 64 | 65 | 69 | 70 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /res/layout/list_item_import_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | 50 | 51 | 52 | 59 | 60 | 70 | 71 | 72 | 78 | 79 | 86 | 87 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/ThemeView.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import java.util.Observable; 4 | import java.util.Observer; 5 | 6 | import android.content.Context; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.RelativeLayout; 11 | import android.widget.TextView; 12 | 13 | import com.yixia.camera.demo.R; 14 | import com.yixia.weibo.sdk.model.VideoEffectModel; 15 | import com.yixia.weibo.sdk.util.IsUtils; 16 | 17 | public class ThemeView extends RelativeLayout implements Observer { 18 | 19 | /** 图标 */ 20 | private ImageView mSelectedIcon, isDownloadImageview; 21 | private BitmapImageView mIcon; 22 | /** 标题 */ 23 | private TextView mTitle, progressTitle; 24 | /** 当前主题 */ 25 | private VideoEffectModel mTheme; 26 | 27 | public VideoEffectModel getTheme() { 28 | return mTheme; 29 | } 30 | 31 | public void setTheme(VideoEffectModel mTheme) { 32 | this.mTheme = mTheme; 33 | } 34 | 35 | public ThemeView(Context context, VideoEffectModel theme) { 36 | super(context); 37 | this.mTheme = theme; 38 | 39 | LayoutInflater.from(context).inflate(R.layout.view_theme_item, this); 40 | 41 | isDownloadImageview = (ImageView) findViewById(R.id.icon_need_download); 42 | 43 | progressTitle = (TextView) findViewById(R.id.progress); 44 | 45 | mIcon = (BitmapImageView) findViewById(R.id.icon); 46 | mSelectedIcon = (ImageView) findViewById(R.id.selected); 47 | mTitle = (TextView) findViewById(R.id.title); 48 | 49 | if (theme.isDownloaded()){ 50 | mTitle.setText(mTheme.effectNameChinese+" downlaoded"); 51 | }else if (theme.isLocal()){ 52 | mTitle.setText(mTheme.effectNameChinese+" local"); 53 | } 54 | else { 55 | mTitle.setText(mTheme.effectNameChinese); 56 | } 57 | 58 | 59 | if (!mTheme.isMV()) { 60 | //高级编辑全部变成方的 61 | // if (mTheme.isWatermark() || mTheme.isSoundEffect() || mTheme.isFilter() || mTheme.isSpeed()) 62 | mSelectedIcon.setImageResource(R.drawable.record_theme_square_selected); 63 | } 64 | if (mTheme.isEmpty() && mTheme.isMV()) { 65 | mSelectedIcon.setVisibility(View.VISIBLE); 66 | } 67 | } 68 | 69 | public void setProgress(int progress){ 70 | progressTitle.setText("" + progress); 71 | } 72 | 73 | /** 刷新视频 */ 74 | public void refreshView() { 75 | if (mTheme != null) { 76 | if (mTheme.isDownloading()) { 77 | //正在下载 78 | progressTitle.setText("" + mTheme.downloadProgress); 79 | isDownloadImageview.setVisibility(View.GONE); 80 | } else if (mTheme.isOnline()) { 81 | //需要显示下载按钮 82 | isDownloadImageview.setVisibility(View.VISIBLE); 83 | progressTitle.setVisibility(View.GONE); 84 | } else { 85 | //已经下载,或已经是内置的 86 | isDownloadImageview.setVisibility(View.GONE); 87 | } 88 | 89 | } 90 | } 91 | 92 | /** 获取主题图标 */ 93 | public BitmapImageView getIcon() { 94 | return mIcon; 95 | } 96 | 97 | @Override 98 | public void update(Observable observable, Object data) { 99 | 100 | try { 101 | if (data != null && mTheme != null) {// && !IsUtils.equals(mTheme.themeName, "default") 102 | String[] strs = (String[]) data; 103 | 104 | if (strs != null && strs.length > 1) { 105 | if (strs[1].equalsIgnoreCase("true")) { 106 | if (IsUtils.equals(mTheme.effectName, strs[0]) && mTheme.isMV()) { 107 | //mRootView.setBackgroundColor(mColorSelected); 108 | mSelectedIcon.setVisibility(View.VISIBLE); 109 | } else if (mTheme.isMV()) { 110 | // mRootView.setBackgroundColor(mColorNormal); 111 | mSelectedIcon.setVisibility(View.GONE); 112 | } 113 | } else { 114 | if (IsUtils.equals(mTheme.effectName, strs[0])) { 115 | //mRootView.setBackgroundColor(mColorSelected); 116 | mSelectedIcon.setVisibility(View.VISIBLE); 117 | } else { 118 | // mRootView.setBackgroundColor(mColorNormal); 119 | mSelectedIcon.setVisibility(View.GONE); 120 | } 121 | } 122 | } 123 | 124 | } 125 | } catch (Exception e) { 126 | // TODO: handle exception 127 | } 128 | 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | VCameraDemo 4 | 提示 5 | 6 | 7 | 返回 8 | 取消 9 | 确定 10 | 1.0.0 11 | 12 | %1$s 作品 13 | 拍摄 14 | 返回 15 | 下一步 16 | 回删 17 | 延迟 18 | 滤镜 19 | 初始化视频存储路径失败 20 | 正在转码… 21 | 手机满了!至少需要200M存储空间才能继续拍摄! 22 | 无法打开录音设备! 23 | 视频信息保存失败! 24 | 是否放弃这段视频? 25 | 是否删除已下载音乐? 26 | 导入 27 | 照片 28 | 从本地照片选择 29 | 导入照片失败 30 | 视频 31 | 截\t取 32 | 从本地视频选择 33 | 导入视频失败 34 | 焦点 35 | 闪光 36 | 幽灵 37 | 编辑 38 | 拍摄 39 | 下一步 40 | 确定 41 | 取消 42 | 视频转码失败 43 | 视频保存在:%s 44 | 拍摄信息读取失败!请检查SD卡,稍后重试! 45 | 主题 46 | 预览 47 | 原始 48 | 主题加载失败 49 | 正在转码… 50 | 转码中\t%d%% 51 | 52 | 主题 53 | 滤镜 54 | 视频生成中… 55 | 下载完成 56 | 下载失败 57 | 58 | 加载中… 59 | 没有数据 60 | 相册 61 | 视频处理中... 62 | 拖动画面可以调整\n视频的显示位置 63 | 左右滑动时间轴,截取你想要的视频片段 64 | 背景颜色: 65 | 下一步 66 | 裁剪 67 | 视频不存在 68 | 导入Gif失败 69 | 正在缓冲... 70 | 正在进行格式转换... 71 | 视频太短 72 | 手机满了!至少需要%sM存储空间才能继续拍摄! 73 | 视频转码失败 74 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/Crypto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 YIXIA.COM 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.yixia.camera.demo.ui.record; 17 | 18 | import android.util.Base64; 19 | 20 | import java.io.BufferedInputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.ObjectInputStream; 24 | import java.io.UnsupportedEncodingException; 25 | import java.math.BigInteger; 26 | import java.security.MessageDigest; 27 | import java.security.PublicKey; 28 | import java.security.spec.AlgorithmParameterSpec; 29 | 30 | import javax.crypto.Cipher; 31 | import javax.crypto.SecretKey; 32 | import javax.crypto.spec.IvParameterSpec; 33 | import javax.crypto.spec.SecretKeySpec; 34 | 35 | import com.yixia.weibo.sdk.util.Log; 36 | 37 | public class Crypto { 38 | private Cipher ecipher; 39 | 40 | public Crypto(String key) { 41 | try { 42 | SecretKeySpec skey = new SecretKeySpec(generateKey(key), "AES"); 43 | setupCrypto(skey); 44 | } catch (Exception e) { 45 | Log.e("Crypto", e); 46 | } 47 | } 48 | 49 | private void setupCrypto(SecretKey key) { 50 | byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; 51 | AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv); 52 | try { 53 | ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 54 | ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 55 | } catch (Exception e) { 56 | ecipher = null; 57 | Log.e("setupCrypto", e); 58 | } 59 | } 60 | 61 | public String encrypt(String plaintext) { 62 | if (ecipher == null) 63 | return ""; 64 | 65 | try { 66 | byte[] ciphertext = ecipher.doFinal(plaintext.getBytes("UTF-8")); 67 | return Base64.encodeToString(ciphertext, Base64.NO_WRAP); 68 | } catch (Exception e) { 69 | Log.e("encryp", e); 70 | return ""; 71 | } 72 | } 73 | 74 | public static String md5(String plain) { 75 | try { 76 | MessageDigest m = MessageDigest.getInstance("MD5"); 77 | m.update(plain.getBytes()); 78 | byte[] digest = m.digest(); 79 | BigInteger bigInt = new BigInteger(1, digest); 80 | String hashtext = bigInt.toString(16); 81 | while (hashtext.length() < 32) { 82 | hashtext = "0" + hashtext; 83 | } 84 | return hashtext; 85 | } catch (Exception e) { 86 | return ""; 87 | } 88 | } 89 | 90 | private static byte[] generateKey(String input) { 91 | try { 92 | byte[] bytesOfMessage = input.getBytes("UTF-8"); 93 | MessageDigest md = MessageDigest.getInstance("SHA256"); 94 | return md.digest(bytesOfMessage); 95 | } catch (Exception e) { 96 | Log.e("generateKey", e); 97 | return null; 98 | } 99 | } 100 | 101 | private PublicKey readKeyFromStream(InputStream keyStream) throws IOException { 102 | ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(keyStream)); 103 | try { 104 | PublicKey pubKey = (PublicKey) oin.readObject(); 105 | return pubKey; 106 | } catch (Exception e) { 107 | Log.e("readKeyFromStream", e); 108 | return null; 109 | } finally { 110 | oin.close(); 111 | } 112 | } 113 | 114 | public String rsaEncrypt(InputStream keyStream, String data) { 115 | try { 116 | return rsaEncrypt(keyStream, data.getBytes("UTF-8")); 117 | } catch (UnsupportedEncodingException e) { 118 | return ""; 119 | } 120 | } 121 | 122 | public String rsaEncrypt(InputStream keyStream, byte[] data) { 123 | try { 124 | PublicKey pubKey = readKeyFromStream(keyStream); 125 | Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 126 | cipher.init(Cipher.ENCRYPT_MODE, pubKey); 127 | byte[] cipherData = cipher.doFinal(data); 128 | return Base64.encodeToString(cipherData, Base64.NO_WRAP); 129 | } catch (Exception e) { 130 | Log.e("rsaEncrypt", e); 131 | return ""; 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/VideoThumbImageView.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import java.io.File; 4 | 5 | import com.yixia.camera.demo.log.Logger; 6 | import com.yixia.weibo.sdk.util.FileUtils; 7 | import com.yixia.weibo.sdk.util.StringUtils; 8 | 9 | import android.content.Context; 10 | import android.graphics.Rect; 11 | import android.net.Uri; 12 | import android.widget.ImageView; 13 | 14 | /** 15 | * 视频截图 16 | * 17 | * @author tangjun 18 | * 19 | */ 20 | public class VideoThumbImageView extends ImageView { 21 | 22 | /** 截图存放路径 */ 23 | private String mThumbPath; 24 | /** 屏幕宽度 */ 25 | private int mWindowWidth; 26 | /** 索引 */ 27 | private int mIndex; 28 | /** 当前时间 */ 29 | private int mPosition; 30 | /** 是否已经加载了图片 */ 31 | private boolean mNeedLoad; 32 | 33 | public VideoThumbImageView(Context context, String thumbPath, int mWindowWidth, int index, int position) { 34 | super(context); 35 | this.mWindowWidth = mWindowWidth; 36 | // this.mThumbPosition = position; 37 | this.mThumbPath = thumbPath; 38 | this.mNeedLoad = true; 39 | this.mIndex = index; 40 | this.mPosition = position; 41 | // this.mVideoPath = videoPath; 42 | // int wh = ConvertToUtils.dipToPX(getContext(), 56); 43 | // mThumbWH = String.format("%dx%d", wh, wh); 44 | // if (firstDraw) 45 | // loadImage(); 46 | } 47 | 48 | // public void scrollY() { 49 | // //是否已经截图并且加载了,是否正在处理 50 | // if (!mScroll && StringUtils.isNotEmpty(mThumbPath) && StringUtils.isNotEmpty(mVideoPath)) { 51 | // mScroll = true; 52 | // 53 | // //检测是否在显示区域 54 | // Rect rect = new Rect(); 55 | // getGlobalVisibleRect(rect); 56 | // 57 | // if (rect.right <= mWindowWidth) { 58 | // loadImage(); 59 | // } else { 60 | // mScroll = false; 61 | // } 62 | // } 63 | // } 64 | // public String getVideoPath() { 65 | // return mThumbPath; 66 | // } 67 | 68 | /** 获取截图对应的时间戳 */ 69 | public int getThumbPosition() { 70 | return mPosition; 71 | } 72 | 73 | public int getThumbIndex() { 74 | return mIndex; 75 | } 76 | 77 | public String getThumbPath() { 78 | return mThumbPath; 79 | } 80 | 81 | public void log() { 82 | Rect rect = new Rect(); 83 | getGlobalVisibleRect(rect); 84 | Logger.d("[VideoThumbImageView]mNeedLoad:" + mNeedLoad + " checkVisible:" + checkVisible() + ":getLeft:" + getLeft() + ":getRight:" + getRight() + " checkThumb:" + checkThumb() + " " + new File(mThumbPath).getName()); 85 | } 86 | 87 | /** 检测是否需要显示 */ 88 | public boolean checkVisible() { 89 | if (StringUtils.isNotEmpty(mThumbPath)) { 90 | Rect rect = new Rect(); 91 | getGlobalVisibleRect(rect); 92 | 93 | if (rect.right <= mWindowWidth && rect.right > 0) 94 | return true; 95 | } 96 | return false; 97 | } 98 | 99 | /** 检测是否需要截图 */ 100 | public boolean checkThumb() { 101 | File f = new File(mThumbPath); 102 | if (f.exists() && f.canRead() && f.length() > 0) { 103 | return true; 104 | } 105 | return false; 106 | } 107 | 108 | /** 检查是否需要加载 */ 109 | public boolean needLoad() { 110 | return mNeedLoad; 111 | } 112 | 113 | public static Uri getFileUri(String path) { 114 | 115 | Logger.e("simon", "getFile Uri>>>" + path); 116 | 117 | return Uri.parse("file:///" + path); 118 | } 119 | 120 | /** 开始截图 */ 121 | public void loadImage() { 122 | if (FileUtils.checkFile(mThumbPath)) { 123 | setImageURI(getFileUri(mThumbPath)); 124 | mNeedLoad = false; 125 | } 126 | } 127 | 128 | // else { 129 | // new AsyncTask() { 130 | // 131 | // @Override 132 | // protected Boolean doInBackground(Void... params) { 133 | // String cmd = String.format("ffmpeg %s -ss %.3f -i \"%s\" -s %s -vframes 1 \"%s\"", FFMpegUtils.getLogCommand(), mThumbPosition / 1000F, mVideoPath, mThumbWH, mThumbPath); 134 | // return UtilityAdapter.FFmpegRun("", cmd) == 0; 135 | // } 136 | // 137 | // @Override 138 | // protected void onPostExecute(Boolean result) { 139 | // super.onPostExecute(result); 140 | // // if (result && new File(mMediaPart.thumbPath).exists()) { 141 | // // loadLocalImage(mMediaPart.thumbPath); 142 | // // } else { 143 | // // //mIconView.setImageResource(R.drawable.video_part_thumb_default); 144 | // // } 145 | // if (mImageFetcher != null) 146 | // mImageFetcher.loadLocalImage(mThumbPath, VideoThumbImageView.this); 147 | // 148 | // mScroll = false; 149 | // } 150 | // }.execute(); 151 | // } 152 | } 153 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/SelectionView.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import com.yixia.camera.demo.R; 10 | 11 | public class SelectionView extends View { 12 | /** 进度条 */ 13 | private Paint mPaint; 14 | private Paint mMaskPaint; 15 | private int mMargin, mMinRightMargin, mLeftMargin, mRightMargin; 16 | private Paint mLinePaint; 17 | private long mPosition; 18 | private int mStarTime; 19 | private int mEndTime; 20 | private boolean mClearLineStatus = false; 21 | private boolean isDrawMargin; 22 | 23 | public SelectionView(Context context) { 24 | this(context, null); 25 | } 26 | 27 | public SelectionView(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | 30 | mPaint = new Paint(); 31 | mPaint.setColor(getResources().getColor(R.color.translucent_background_75)); 32 | mPaint.setStyle(Paint.Style.FILL); 33 | 34 | mMaskPaint = new Paint(); 35 | mMaskPaint.setColor(getResources().getColor(R.color.import_video_thumb_mask)); 36 | mMaskPaint.setStyle(Paint.Style.FILL); 37 | 38 | mLinePaint = new Paint(); 39 | mLinePaint.setColor(getResources().getColor(R.color.white)); 40 | mLinePaint.setStyle(Paint.Style.STROKE); 41 | mLinePaint.setStrokeWidth((float) 5.0); 42 | } 43 | 44 | public void setMargin(int margin) { 45 | if (mMargin == 0 && margin > 0) 46 | mMargin = margin; 47 | } 48 | 49 | /** 设置左边距 */ 50 | public void setLeftMargin(int leftMargin) { 51 | mLeftMargin = leftMargin; 52 | invalidate(); 53 | } 54 | 55 | /** 设置右边距 */ 56 | public void setRightMargin(int rightMargin) { 57 | mRightMargin = rightMargin; 58 | invalidate(); 59 | } 60 | 61 | public int getLeftMargin() { 62 | return mLeftMargin; 63 | } 64 | 65 | public int getRightMargin() { 66 | return mRightMargin; 67 | } 68 | 69 | /** 获取当前的宽度 */ 70 | public int getCurrentWidth() { 71 | return getWidth() - mLeftMargin - mRightMargin - mMargin - mMargin; 72 | } 73 | 74 | /** 设置最小右边距 */ 75 | public void setMinRightMargin(int rightMargin) { 76 | this.mMinRightMargin = rightMargin; 77 | setRightMargin(rightMargin); 78 | } 79 | 80 | public int getMinRightMargin() { 81 | return mMinRightMargin; 82 | } 83 | 84 | /** 85 | * 设置进度线 86 | * @param position 当前位置 87 | * @param starTime 起始时间 88 | * @param endTime 结束时间 89 | */ 90 | public void setLinePosition(long position, int starTime, int endTime) { 91 | this.mPosition = position; 92 | this.mStarTime = starTime; 93 | this.mEndTime = endTime; 94 | mClearLineStatus = false; 95 | invalidate(); 96 | } 97 | 98 | /** 清除进度线*/ 99 | public void clearLine() { 100 | mClearLineStatus = true; 101 | invalidate(); 102 | } 103 | 104 | @Override 105 | protected void onDraw(Canvas canvas) { 106 | super.onDraw(canvas); 107 | if (mMargin > 0) { 108 | int width = getMeasuredWidth(); 109 | final int height = getMeasuredHeight(); 110 | //画左边阴影 111 | // if (mLeftMargin > 0) { 112 | // Logger.systemErr("mLeftMargin"); 113 | // canvas.drawRect(0, 0, mLeftMargin + mMargin, height, mPaint); 114 | // } 115 | // 116 | // //画右边阴影 117 | // if (mRightMargin > 0 || mMinRightMargin > 0) { 118 | // Logger.systemErr("mRightMargin > 0 || mMinRightMargin > 0"); 119 | // canvas.drawRect(width - mMargin - mRightMargin, 0, width, height, mPaint); 120 | // } 121 | 122 | canvas.drawRect(0, 0, mLeftMargin + mMargin, height, mPaint); 123 | canvas.drawRect(width - mMargin - mRightMargin, 0, width, height, mPaint); 124 | 125 | // if (!(mLeftMargin > 0) && !(mRightMargin > 0 || mMinRightMargin > 0)) { 126 | // isDrawMargin = true; 127 | 128 | // } 129 | 130 | //覆盖右边不应该显示的图片 131 | if (mMinRightMargin > 0) { 132 | canvas.drawRect(width - mMinRightMargin - mMargin, 0, width - mMargin, height, mMaskPaint); 133 | } 134 | //添加进度线条 135 | if (!mClearLineStatus) { 136 | int mWidth = getCurrentWidth(); 137 | if (mWidth > 0 && mPosition > 0 && mEndTime > 0) { 138 | int delayMillis = mEndTime - mStarTime; 139 | if (delayMillis > 0) { 140 | // if (delayMillis > RecorderHelper.getMaxDuration()) { 141 | // if (mPosition > RecorderHelper.getMaxDuration()) { 142 | // 143 | // mPosition = mPosition - (int) (mPosition / delayMillis) * delayMillis; 144 | // } 145 | // } else { 146 | if (mStarTime != 0) { 147 | mPosition = mPosition - mStarTime; 148 | } 149 | // } 150 | } 151 | 152 | 153 | float x = (mWidth * mPosition / delayMillis) + mMargin + mLeftMargin; 154 | 155 | // android.util.Log.e("simon","setLinePosition::StartTime>>"+mStarTime+">>>endTime>>>"+mEndTime+">>>position>>"+mPosition); 156 | // 157 | // android.util.Log.e("simon","XXXXXX>>"+x+">>>mMargin>>>"+mMargin+">>>mLeftMargin>>"+mLeftMargin); 158 | // 159 | // android.util.Log.e("simon","mWidth>>"+mWidth+">>>mPosition>>>"+mPosition+">>>delayMillis>>"+delayMillis); 160 | 161 | 162 | canvas.drawLine(x, 0, x, height, mLinePaint); 163 | } 164 | } 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /res/layout/activity_media_recorder.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 21 | 22 | 26 | 27 | 34 | 35 | 42 | 43 | 47 | 48 | 57 | 58 | 59 | 64 | 65 | 70 | 71 | 77 | 78 | 79 | 83 | 84 | 91 | 92 | 93 | 94 | 95 | 96 | 103 | 104 | 113 | 114 | 120 | 121 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | 16 | 17 | 21 | 22 | 26 | 27 | 38 | 39 | 54 | 55 | 66 | 67 | 68 | 79 | 80 | 95 | 96 | 109 | 110 | -------------------------------------------------------------------------------- /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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/VideoPlayerActivity.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record; 2 | 3 | import android.annotation.TargetApi; 4 | import android.media.MediaPlayer; 5 | import android.media.MediaPlayer.OnCompletionListener; 6 | import android.media.MediaPlayer.OnErrorListener; 7 | import android.media.MediaPlayer.OnInfoListener; 8 | import android.media.MediaPlayer.OnPreparedListener; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.view.KeyEvent; 12 | import android.view.View; 13 | import android.view.View.OnClickListener; 14 | import android.view.WindowManager; 15 | 16 | import com.yixia.camera.demo.R; 17 | import com.yixia.camera.demo.ui.BaseActivity; 18 | import com.yixia.camera.demo.ui.widget.SurfaceVideoView; 19 | import com.yixia.camera.demo.util.Constant; 20 | import com.yixia.weibo.sdk.util.DeviceUtils; 21 | import com.yixia.weibo.sdk.util.StringUtils; 22 | 23 | /** 24 | * 通用单独播放界面 25 | * 26 | * @author tangjun 27 | * 28 | */ 29 | public class VideoPlayerActivity extends BaseActivity implements SurfaceVideoView.OnPlayStateListener, OnErrorListener, OnPreparedListener, OnClickListener, OnCompletionListener, OnInfoListener { 30 | 31 | /** 播放控件 */ 32 | private SurfaceVideoView mVideoView; 33 | /** 暂停按钮 */ 34 | private View mPlayerStatus; 35 | private View mLoading; 36 | 37 | /** 播放路径 */ 38 | private String mPath; 39 | /** 视频截图路径 */ 40 | private String mCoverPath; 41 | 42 | /** 是否需要回复播放 */ 43 | private boolean mNeedResume; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | // 防止锁屏 49 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 50 | 51 | mPath = getIntent().getStringExtra(Constant.RECORD_VIDEO_PATH); 52 | mCoverPath = getIntent().getStringExtra(Constant.RECORD_VIDEO_CAPTURE); 53 | if (StringUtils.isEmpty(mPath)) { 54 | finish(); 55 | return; 56 | } 57 | 58 | setContentView(R.layout.activity_video_player); 59 | mVideoView = (SurfaceVideoView) findViewById(R.id.videoview); 60 | mPlayerStatus = findViewById(R.id.play_status); 61 | mLoading = findViewById(R.id.loading); 62 | 63 | mVideoView.setOnPreparedListener(this); 64 | mVideoView.setOnPlayStateListener(this); 65 | mVideoView.setOnErrorListener(this); 66 | mVideoView.setOnClickListener(this); 67 | mVideoView.setOnInfoListener(this); 68 | mVideoView.setOnCompletionListener(this); 69 | 70 | mVideoView.getLayoutParams().height = DeviceUtils.getScreenWidth(this); 71 | 72 | findViewById(R.id.root).setOnClickListener(this); 73 | mVideoView.setVideoPath(mPath); 74 | } 75 | 76 | @Override 77 | public void onResume() { 78 | super.onResume(); 79 | if (mVideoView != null && mNeedResume) { 80 | mNeedResume = false; 81 | if (mVideoView.isRelease()) 82 | mVideoView.reOpen(); 83 | else 84 | mVideoView.start(); 85 | } 86 | } 87 | 88 | @Override 89 | public void onPause() { 90 | super.onPause(); 91 | if (mVideoView != null) { 92 | if (mVideoView.isPlaying()) { 93 | mNeedResume = true; 94 | mVideoView.pause(); 95 | } 96 | } 97 | } 98 | 99 | @Override 100 | protected void onDestroy() { 101 | if (mVideoView != null) { 102 | mVideoView.release(); 103 | mVideoView = null; 104 | } 105 | super.onDestroy(); 106 | } 107 | 108 | @Override 109 | public void onPrepared(MediaPlayer mp) { 110 | mVideoView.setVolume(SurfaceVideoView.getSystemVolumn(this)); 111 | mVideoView.start(); 112 | // new Handler().postDelayed(new Runnable() { 113 | // 114 | // @SuppressWarnings("deprecation") 115 | // @Override 116 | // public void run() { 117 | // if (DeviceUtils.hasJellyBean()) { 118 | // mVideoView.setBackground(null); 119 | // } else { 120 | // mVideoView.setBackgroundDrawable(null); 121 | // } 122 | // } 123 | // }, 300); 124 | mLoading.setVisibility(View.GONE); 125 | } 126 | 127 | @Override 128 | public boolean dispatchKeyEvent(KeyEvent event) { 129 | switch (event.getKeyCode()) {//跟随系统音量走 130 | case KeyEvent.KEYCODE_VOLUME_DOWN: 131 | case KeyEvent.KEYCODE_VOLUME_UP: 132 | mVideoView.dispatchKeyEvent(this, event); 133 | break; 134 | } 135 | return super.dispatchKeyEvent(event); 136 | } 137 | 138 | @Override 139 | public void onStateChanged(boolean isPlaying) { 140 | mPlayerStatus.setVisibility(isPlaying ? View.GONE : View.VISIBLE); 141 | } 142 | 143 | @Override 144 | public boolean onError(MediaPlayer mp, int what, int extra) { 145 | if (!isFinishing()) { 146 | //播放失败 147 | } 148 | finish(); 149 | return false; 150 | } 151 | 152 | @Override 153 | public void onClick(View v) { 154 | switch (v.getId()) { 155 | case R.id.root: 156 | finish(); 157 | break; 158 | case R.id.videoview: 159 | if (mVideoView.isPlaying()) 160 | mVideoView.pause(); 161 | else 162 | mVideoView.start(); 163 | break; 164 | } 165 | } 166 | 167 | @Override 168 | public void onCompletion(MediaPlayer mp) { 169 | if (!isFinishing()) 170 | mVideoView.reOpen(); 171 | } 172 | 173 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 174 | @Override 175 | public boolean onInfo(MediaPlayer mp, int what, int extra) { 176 | switch (what) { 177 | case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: 178 | //音频和视频数据不正确 179 | break; 180 | case MediaPlayer.MEDIA_INFO_BUFFERING_START: 181 | if (!isFinishing()) 182 | mVideoView.pause(); 183 | break; 184 | case MediaPlayer.MEDIA_INFO_BUFFERING_END: 185 | if (!isFinishing()) 186 | mVideoView.start(); 187 | break; 188 | case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: 189 | if (DeviceUtils.hasJellyBean()) { 190 | mVideoView.setBackground(null); 191 | } else { 192 | mVideoView.setBackgroundDrawable(null); 193 | } 194 | break; 195 | } 196 | return false; 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/media/MediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.media; 2 | 3 | import java.io.IOException; 4 | 5 | import android.content.Context; 6 | import android.content.res.AssetFileDescriptor; 7 | import android.net.Uri; 8 | import android.os.Handler; 9 | import android.os.Message; 10 | import android.util.Log; 11 | import android.view.SurfaceHolder; 12 | 13 | import com.yixia.camera.demo.log.Logger; 14 | 15 | public class MediaPlayer extends android.media.MediaPlayer { 16 | 17 | private static final String TAG = "[MediaPlayer]"; 18 | 19 | @Override 20 | public void start() { 21 | try { 22 | super.start(); 23 | } catch (IllegalStateException e) { 24 | Logger.e(e); 25 | } catch (Exception e) { 26 | Logger.e(e); 27 | } 28 | } 29 | 30 | @Override 31 | public void setVolume(float leftVolume, float rightVolume) { 32 | try { 33 | super.setVolume(leftVolume, rightVolume); 34 | } catch (IllegalStateException e) { 35 | Logger.e(e); 36 | } catch (Exception e) { 37 | Logger.e(e); 38 | } 39 | } 40 | 41 | private static final int HANDLER_MESSAGE_PARSE = 0; 42 | private static final int HANDLER_MESSAGE_LOOP = 1; 43 | 44 | private Handler mVideoHandler = new Handler() { 45 | @Override 46 | public void handleMessage(Message msg) { 47 | switch (msg.what) { 48 | case HANDLER_MESSAGE_PARSE: 49 | pause(); 50 | break; 51 | case HANDLER_MESSAGE_LOOP: 52 | if (isPlaying()) { 53 | seekTo(msg.arg1); 54 | sendMessageDelayed(mVideoHandler.obtainMessage(HANDLER_MESSAGE_LOOP, msg.arg1, msg.arg2), msg.arg2); 55 | } 56 | break; 57 | default: 58 | break; 59 | } 60 | super.handleMessage(msg); 61 | } 62 | }; 63 | 64 | /** 区域内循环播放 */ 65 | public void loopDelayed(int startTime, int endTime) { 66 | int delayMillis = endTime - startTime; 67 | seekTo(startTime); 68 | if (!isPlaying()) 69 | start(); 70 | mVideoHandler.removeMessages(HANDLER_MESSAGE_LOOP); 71 | mVideoHandler.sendMessageDelayed(mVideoHandler.obtainMessage(HANDLER_MESSAGE_LOOP, getCurrentPosition(), delayMillis), delayMillis); 72 | } 73 | 74 | @Override 75 | public void seekTo(int msec) { 76 | try { 77 | super.seekTo(msec); 78 | } catch (IllegalStateException e) { 79 | Logger.e(e); 80 | } catch (Exception e) { 81 | Logger.e(e); 82 | } 83 | } 84 | 85 | public void loopDelayed(int endTime) { 86 | int delayMillis = endTime; 87 | //if (!isPlaying()) 88 | start(); 89 | mVideoHandler.removeMessages(HANDLER_MESSAGE_LOOP); 90 | mVideoHandler.sendMessageDelayed(mVideoHandler.obtainMessage(HANDLER_MESSAGE_LOOP, 0, delayMillis), delayMillis); 91 | } 92 | 93 | public void pauseClearDelayed() { 94 | pause(); 95 | mVideoHandler.removeMessages(HANDLER_MESSAGE_PARSE); 96 | mVideoHandler.removeMessages(HANDLER_MESSAGE_LOOP); 97 | } 98 | 99 | @Override 100 | public int getCurrentPosition() { 101 | try { 102 | return super.getCurrentPosition(); 103 | } catch (IllegalStateException e) { 104 | Logger.e(e); 105 | } catch (Exception e) { 106 | Logger.e(e); 107 | } 108 | return 0; 109 | } 110 | 111 | @Override 112 | public int getDuration() { 113 | try { 114 | return super.getDuration(); 115 | } catch (IllegalStateException e) { 116 | Logger.e(e); 117 | } catch (Exception e) { 118 | Logger.e(e); 119 | } 120 | return 0; 121 | } 122 | 123 | @Override 124 | public int getVideoWidth() { 125 | try { 126 | return super.getVideoWidth(); 127 | } catch (IllegalStateException e) { 128 | Logger.e(e); 129 | } catch (Exception e) { 130 | Logger.e(e); 131 | } 132 | return 0; 133 | } 134 | 135 | @Override 136 | public int getVideoHeight() { 137 | try { 138 | return super.getVideoHeight(); 139 | } catch (IllegalStateException e) { 140 | Logger.e(e); 141 | } catch (Exception e) { 142 | Logger.e(e); 143 | } 144 | return 0; 145 | } 146 | 147 | @Override 148 | public void stop() { 149 | try { 150 | super.stop(); 151 | } catch (IllegalStateException e) { 152 | Logger.e(e); 153 | } catch (Exception e) { 154 | Logger.e(e); 155 | } 156 | } 157 | 158 | @Override 159 | public void pause() throws IllegalStateException { 160 | try { 161 | super.pause(); 162 | } catch (IllegalStateException e) { 163 | Logger.e(e); 164 | } catch (Exception e) { 165 | Logger.e(e); 166 | } 167 | } 168 | 169 | @Override 170 | public boolean isPlaying() { 171 | try { 172 | return super.isPlaying(); 173 | } catch (IllegalStateException e) { 174 | Logger.e(e); 175 | } catch (Exception e) { 176 | Logger.e(e); 177 | } 178 | return false; 179 | } 180 | 181 | @Override 182 | public void reset() { 183 | try { 184 | super.reset(); 185 | } catch (IllegalStateException e) { 186 | Logger.e(e); 187 | } catch (Exception e) { 188 | Logger.e(e); 189 | } 190 | } 191 | 192 | @Override 193 | public void release() { 194 | try { 195 | super.release(); 196 | } catch (IllegalStateException e) { 197 | Logger.e(e); 198 | } catch (Exception e) { 199 | Logger.e(e); 200 | } 201 | } 202 | 203 | public static MediaPlayer create(Context context, Uri uri) { 204 | return create(context, uri, null); 205 | } 206 | 207 | public static MediaPlayer create(Context context, int resid) { 208 | try { 209 | AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid); 210 | if (afd == null) 211 | return null; 212 | 213 | MediaPlayer mp = new MediaPlayer(); 214 | mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 215 | afd.close(); 216 | mp.prepare(); 217 | return mp; 218 | } catch (IOException ex) { 219 | Log.d(TAG, "create failed:", ex); 220 | // fall through 221 | } catch (IllegalArgumentException ex) { 222 | Log.d(TAG, "create failed:", ex); 223 | // fall through 224 | } catch (SecurityException ex) { 225 | Log.d(TAG, "create failed:", ex); 226 | // fall through 227 | } catch (Exception ex) { 228 | Log.d(TAG, "create failed:", ex); 229 | // fall through 230 | } 231 | return null; 232 | } 233 | 234 | public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder) { 235 | 236 | try { 237 | MediaPlayer mp = new MediaPlayer(); 238 | mp.setDataSource(context, uri); 239 | if (holder != null) { 240 | mp.setDisplay(holder); 241 | } 242 | mp.prepare(); 243 | return mp; 244 | } catch (IOException ex) { 245 | Log.e(TAG, "create failed:", ex); 246 | // fall through 247 | } catch (IllegalArgumentException ex) { 248 | Log.e(TAG, "create failed:", ex); 249 | // fall through 250 | } catch (SecurityException ex) { 251 | Log.e(TAG, "create failed:", ex); 252 | // fall through 253 | } 254 | 255 | return null; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /res/layout/activity_video_import_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 20 | 21 | 27 | 28 | 31 | 32 | 36 | 37 | 38 | 47 | 48 | 55 | 56 | 63 | 64 | 74 | 75 | 76 | 84 | 85 | 103 | 104 | 105 | 106 | 107 | 108 | 115 | 116 | 120 | 121 | 122 | 123 | 139 | 140 | 146 | 147 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/views/ProgressView.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.views; 2 | 3 | import java.util.Iterator; 4 | 5 | import android.content.Context; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.os.Handler; 9 | import android.os.Message; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | 13 | import com.yixia.camera.demo.R; 14 | import com.yixia.weibo.sdk.model.MediaObject; 15 | import com.yixia.weibo.sdk.util.DeviceUtils; 16 | 17 | public class ProgressView extends View { 18 | 19 | /** 进度条 */ 20 | private Paint mProgressPaint; 21 | /** 闪 */ 22 | private Paint mActivePaint; 23 | /** 暂停/中断色块 */ 24 | private Paint mPausePaint; 25 | /** 回删 */ 26 | private Paint mRemovePaint; 27 | /** 三秒 */ 28 | private Paint mThreePaint; 29 | /** 超时 */ 30 | private Paint mOverflowPaint; 31 | private boolean mStop, mProgressChanged; 32 | private boolean mActiveState; 33 | private MediaObject mMediaObject; 34 | /** 最长时长 */ 35 | private int mMaxDuration, mVLineWidth; 36 | 37 | public ProgressView(Context paramContext) { 38 | super(paramContext); 39 | init(); 40 | } 41 | 42 | public ProgressView(Context paramContext, AttributeSet paramAttributeSet) { 43 | super(paramContext, paramAttributeSet); 44 | init(); 45 | } 46 | 47 | public ProgressView(Context paramContext, AttributeSet paramAttributeSet, int paramInt) { 48 | super(paramContext, paramAttributeSet, paramInt); 49 | init(); 50 | } 51 | 52 | private void init() { 53 | mProgressPaint = new Paint(); 54 | mActivePaint = new Paint(); 55 | mPausePaint = new Paint(); 56 | mRemovePaint = new Paint(); 57 | mThreePaint = new Paint(); 58 | mOverflowPaint = new Paint(); 59 | 60 | mVLineWidth = DeviceUtils.dipToPX(getContext(), 1); 61 | 62 | setBackgroundColor(getResources().getColor(R.color.camera_bg)); 63 | mProgressPaint.setColor(getResources().getColor(R.color.title_background_color)); 64 | mProgressPaint.setStyle(Paint.Style.FILL); 65 | 66 | mActivePaint.setColor(getResources().getColor(R.color.white)); 67 | mActivePaint.setStyle(Paint.Style.FILL); 68 | 69 | mPausePaint.setColor(getResources().getColor(R.color.camera_progress_split)); 70 | mPausePaint.setStyle(Paint.Style.FILL); 71 | 72 | mRemovePaint.setColor(getResources().getColor(R.color.camera_progress_delete)); 73 | mRemovePaint.setStyle(Paint.Style.FILL); 74 | 75 | mThreePaint.setColor(getResources().getColor(R.color.camera_progress_three)); 76 | mThreePaint.setStyle(Paint.Style.FILL); 77 | 78 | mOverflowPaint.setColor(getResources().getColor(R.color.camera_progress_overflow)); 79 | mOverflowPaint.setStyle(Paint.Style.FILL); 80 | } 81 | 82 | /** 闪动 */ 83 | private final static int HANDLER_INVALIDATE_ACTIVE = 0; 84 | /** 录制中 */ 85 | private final static int HANDLER_INVALIDATE_RECORDING = 1; 86 | 87 | private Handler mHandler = new Handler() { 88 | @Override 89 | public void dispatchMessage(Message msg) { 90 | switch (msg.what) { 91 | case HANDLER_INVALIDATE_ACTIVE: 92 | invalidate(); 93 | mActiveState = !mActiveState; 94 | if (!mStop) 95 | sendEmptyMessageDelayed(0, 300); 96 | break; 97 | case HANDLER_INVALIDATE_RECORDING: 98 | invalidate(); 99 | if (mProgressChanged) 100 | sendEmptyMessageDelayed(0, 50); 101 | break; 102 | } 103 | super.dispatchMessage(msg); 104 | } 105 | }; 106 | 107 | @Override 108 | protected void onDraw(Canvas canvas) { 109 | super.onDraw(canvas); 110 | 111 | final int width = getMeasuredWidth(), height = getMeasuredHeight(); 112 | int left = 0, right = 0, duration = 0; 113 | if (mMediaObject != null && mMediaObject.getMedaParts() != null) { 114 | 115 | left = right = 0; 116 | Iterator iterator = mMediaObject.getMedaParts().iterator(); 117 | boolean hasNext = iterator.hasNext(); 118 | 119 | // final int duration = vp.getDuration(); 120 | int maxDuration = mMaxDuration; 121 | boolean hasOutDuration = false; 122 | int currentDuration = mMediaObject.getDuration(); 123 | hasOutDuration = currentDuration > mMaxDuration; 124 | if (hasOutDuration) 125 | maxDuration = currentDuration; 126 | 127 | while (hasNext) { 128 | com.yixia.weibo.sdk.model.MediaObject$MediaPart vp = iterator.next(); 129 | final int partDuration = vp.getDuration(); 130 | // Logger.e("[ProgressView]partDuration" + partDuration + " maxDuration:" + maxDuration); 131 | left = right; 132 | right = left + (int) (partDuration * 1.0F / maxDuration * width); 133 | 134 | if (vp.remove) { 135 | //回删 136 | canvas.drawRect(left, 0.0F, right, height, mRemovePaint); 137 | } else { 138 | //画进度 139 | if (hasOutDuration) { 140 | //超时拍摄 141 | //前段 142 | right = left + (int) ((mMaxDuration - duration) * 1.0F / maxDuration * width); 143 | canvas.drawRect(left, 0.0F, right, height, mProgressPaint); 144 | 145 | //超出的段 146 | left = right; 147 | right = left + (int) ((partDuration - (mMaxDuration - duration)) * 1.0F / maxDuration * width); 148 | canvas.drawRect(left, 0.0F, right, height, mOverflowPaint); 149 | } else { 150 | canvas.drawRect(left, 0.0F, right, height, mProgressPaint); 151 | } 152 | } 153 | 154 | hasNext = iterator.hasNext(); 155 | if (hasNext) { 156 | // left = right - mVLineWidth; 157 | canvas.drawRect(right - mVLineWidth, 0.0F, right, height, mPausePaint); 158 | } 159 | 160 | duration += partDuration; 161 | //progress = vp.progress; 162 | } 163 | } 164 | 165 | //画三秒 166 | if (duration < 3000) { 167 | left = (int) (3000F / mMaxDuration * width); 168 | canvas.drawRect(left, 0.0F, left + mVLineWidth, height, mThreePaint); 169 | } 170 | 171 | //删 172 | // 173 | //闪 174 | if (mActiveState) { 175 | if (right + 8 >= width) 176 | right = width - 8; 177 | canvas.drawRect(right, 0.0F, right + 8, getMeasuredHeight(), mActivePaint); 178 | } 179 | } 180 | 181 | @Override 182 | protected void onAttachedToWindow() { 183 | super.onAttachedToWindow(); 184 | mStop = false; 185 | mHandler.sendEmptyMessage(HANDLER_INVALIDATE_ACTIVE); 186 | } 187 | 188 | @Override 189 | protected void onDetachedFromWindow() { 190 | super.onDetachedFromWindow(); 191 | mStop = true; 192 | mHandler.removeMessages(HANDLER_INVALIDATE_ACTIVE); 193 | } 194 | 195 | // public void addProgress(MediaPart part) { 196 | // if (part != null) { 197 | // part.index = mVideoParts.size(); 198 | // mVideoParts.add(part); 199 | // } 200 | // } 201 | 202 | public void setData(MediaObject mMediaObject) { 203 | this.mMediaObject = mMediaObject; 204 | } 205 | 206 | public void setMaxDuration(int duration) { 207 | this.mMaxDuration = duration; 208 | } 209 | 210 | public void start() { 211 | mProgressChanged = true; 212 | } 213 | 214 | public void stop() { 215 | mProgressChanged = false; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /res/layout/view_video_selection.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 27 | 28 | 29 | 30 | 31 | 42 | 43 | 50 | 51 | 59 | 60 | 66 | 67 | 68 | 79 | 80 | 81 | 89 | 90 | 96 | 97 | 104 | 105 | 111 | 112 | 113 | 114 | 115 | 126 | 127 | 132 | 133 | 136 | 137 | 138 | 139 | 140 | 141 | 148 | 149 | 156 | 157 | 164 | 165 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/adapter/ImportVideoFolderAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.adapter; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.WeakHashMap; 9 | 10 | import android.app.Activity; 11 | import android.content.ContentResolver; 12 | import android.content.Context; 13 | import android.database.Cursor; 14 | import android.graphics.Bitmap; 15 | import android.net.Uri; 16 | import android.provider.MediaStore; 17 | import android.view.LayoutInflater; 18 | import android.view.View; 19 | import android.view.ViewGroup; 20 | import android.widget.BaseAdapter; 21 | import android.widget.ImageView; 22 | import android.widget.TextView; 23 | 24 | import com.yixia.camera.demo.R; 25 | import com.yixia.camera.demo.VCameraDemoApplication; 26 | import com.yixia.camera.demo.log.Logger; 27 | import com.yixia.camera.demo.po.Video; 28 | import com.yixia.camera.demo.ui.record.Crypto; 29 | import com.yixia.camera.demo.ui.record.ImportVideoFolderActivity.VideoFolder; 30 | import com.yixia.camera.demo.util.ViewHolderUtils; 31 | import com.yixia.weibo.sdk.FFMpegUtils; 32 | import com.yixia.weibo.sdk.util.FileUtils; 33 | import com.yixia.weibo.sdk.util.StringUtils; 34 | 35 | public class ImportVideoFolderAdapter extends BaseAdapter { 36 | 37 | private Context mContext; 38 | private List videoFolderList; 39 | private static Map mImageViews; 40 | /** 缩略图缓存目录 */ 41 | private File mThumbCacheDir; 42 | private static final String[] THUMB_PROJECT = { MediaStore.Video.Thumbnails.DATA, MediaStore.Video.Thumbnails.VIDEO_ID }; 43 | 44 | public ImportVideoFolderAdapter(Context context) { 45 | this.mContext = context; 46 | videoFolderList = new ArrayList(); 47 | mImageViews = Collections.synchronizedMap(new WeakHashMap()); 48 | mThumbCacheDir = VCameraDemoApplication.getThumbCacheDirectory(); 49 | if (mThumbCacheDir != null && !mThumbCacheDir.exists()) { 50 | mThumbCacheDir.mkdirs(); 51 | } 52 | } 53 | 54 | public void updateVideoFolderData(List result){ 55 | this.videoFolderList = result; 56 | this.notifyDataSetChanged(); 57 | } 58 | 59 | @Override 60 | public int getCount() { 61 | return videoFolderList.size(); 62 | } 63 | 64 | @Override 65 | public Object getItem(int position) { 66 | return videoFolderList.get(position); 67 | } 68 | 69 | @Override 70 | public long getItemId(int position) { 71 | return position; 72 | } 73 | 74 | @Override 75 | public View getView(int position, View convertView, ViewGroup parent) { 76 | if (convertView == null) { 77 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_import_image_folder, null); 78 | } 79 | 80 | final VideoFolder item = (VideoFolder) getItem(position); 81 | ImageView icon = ViewHolderUtils.getView(convertView, R.id.icon); 82 | TextView title = ViewHolderUtils.getView(convertView, R.id.title); 83 | TextView count = ViewHolderUtils.getView(convertView, R.id.count); 84 | 85 | if (StringUtils.isNotEmpty(item.url)) { 86 | if (item.faild) { 87 | 88 | } else { 89 | /** 加载视频截图 */ 90 | loadVideoThumb(icon, item.video); 91 | } 92 | } 93 | icon.setTag(item); 94 | 95 | title.setText(item.name);// + "\n" + item.path);// 96 | count.setText(item.count + ""); 97 | 98 | return convertView; 99 | } 100 | 101 | public Uri getFileUri(String path) { 102 | 103 | Logger.e("simon", "getFile Uri>>>" + path); 104 | 105 | return Uri.parse("file:///" + path); 106 | } 107 | 108 | private void loadVideoThumb(final ImageView view, final Video video){ 109 | if (mThumbCacheDir == null || video == null || StringUtils.isEmpty(video.url)) { 110 | return; 111 | } 112 | 113 | final String videoPath = video.url; 114 | 115 | mImageViews.put(view, videoPath); 116 | 117 | if (StringUtils.isNotEmpty(video.thumb)) { 118 | view.setImageURI(getFileUri(video.thumb)); 119 | return; 120 | } 121 | new Thread(new Runnable() { 122 | 123 | /** 现实缩略图 */ 124 | private void showThumb() { 125 | if (video != null && !Thread.currentThread().isInterrupted() && mContext != null) { 126 | ((Activity) mContext).runOnUiThread(new Runnable() { 127 | @Override 128 | public void run() { 129 | String tag = mImageViews.get(view); 130 | if (tag != null && tag.equals(videoPath)) { 131 | // if (video.equals(view.getTag())) { 132 | // Logger.e("[ImportHelper]loadVideoThumb...1" 133 | // + video.faild); 134 | if (video.faild) { 135 | view.setImageResource(R.drawable.import_image_default); 136 | } else if (StringUtils.isNotEmpty(video.thumb)) { 137 | view.setImageURI(getFileUri(video.thumb)); 138 | } 139 | } 140 | } 141 | }); 142 | } 143 | } 144 | 145 | @Override 146 | public void run() { 147 | // Logger.e("[ImportHelper]loadVideoThumb...2" + 148 | // video.faild); 149 | // 先检测截图缓存文件夹是否已经存在截图 150 | final String key = Crypto.md5(videoPath); 151 | final File thumbFile = new File(mThumbCacheDir, key + ".jpg"); 152 | if (FileUtils.checkFile(thumbFile)) { 153 | video.thumb = thumbFile.getPath(); 154 | showThumb(); 155 | return; 156 | } 157 | 158 | // Logger.e("[ImportHelper]loadVideoThumb...3" + 159 | // video.faild); 160 | 161 | // 从系统相册缓冲中取 162 | final ContentResolver mContentResolver = mContext.getContentResolver(); 163 | if (mContentResolver != null) { 164 | Cursor thumbCursor = mContentResolver.query(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, THUMB_PROJECT, MediaStore.Video.Thumbnails.VIDEO_ID + "=" + video._id, null, null); 165 | if (thumbCursor != null) { 166 | // 检测有没有截图,没有截图马上截图 167 | if (thumbCursor.getCount() == 0) { 168 | try { 169 | Bitmap bitmap = MediaStore.Video.Thumbnails.getThumbnail(mContentResolver, video._id, MediaStore.Video.Thumbnails.MINI_KIND, null); 170 | if (bitmap != null) { 171 | if (!bitmap.isRecycled()) 172 | bitmap.recycle(); 173 | bitmap = null; 174 | } 175 | } catch (OutOfMemoryError e) { 176 | Logger.e(e); 177 | } catch (Exception e) { 178 | Logger.e(e); 179 | } 180 | thumbCursor.close(); 181 | thumbCursor = mContentResolver.query(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, THUMB_PROJECT, MediaStore.Video.Thumbnails.VIDEO_ID + "=" + video._id, null, null); 182 | } 183 | 184 | if (thumbCursor != null && thumbCursor.moveToFirst()) { 185 | String thumb = thumbCursor.getString(0); 186 | thumbCursor.close(); 187 | if (FileUtils.checkFile(thumb)) { 188 | video.thumb = thumb; 189 | showThumb(); 190 | return; 191 | } 192 | } 193 | if (thumbCursor != null && !thumbCursor.isClosed()) 194 | thumbCursor.close(); 195 | } 196 | } 197 | 198 | if (Thread.currentThread().isInterrupted()) 199 | return; 200 | 201 | // 系统截图失败,调用FFMPEG截图,截图第一帧 202 | try { 203 | Logger.e("samuel", "调用ffmpeg截屏"); 204 | if (FFMpegUtils.captureThumbnails(videoPath, thumbFile.getPath(), video.orientation)) { 205 | if (Thread.currentThread().isInterrupted()) 206 | return; 207 | if (FileUtils.checkFile(thumbFile)) { 208 | video.thumb = thumbFile.getPath(); 209 | showThumb(); 210 | return; 211 | } 212 | } 213 | } catch (Exception e) { 214 | Logger.e(e); 215 | } 216 | 217 | if (Thread.currentThread().isInterrupted()) 218 | return; 219 | 220 | // 截图完全失败,视频有问题 221 | video.faild = true; 222 | showThumb(); 223 | } 224 | }).run(); 225 | 226 | } 227 | 228 | } 229 | -------------------------------------------------------------------------------- /src/com/yixia/camera/demo/ui/record/adapter/ImportVideoSelectionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yixia.camera.demo.ui.record.adapter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.graphics.Bitmap; 10 | import android.media.MediaMetadataRetriever; 11 | import android.os.Bundle; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.View.OnClickListener; 15 | import android.view.ViewGroup; 16 | import android.widget.BaseAdapter; 17 | import android.widget.ImageView; 18 | import android.widget.RelativeLayout; 19 | import android.widget.TextView; 20 | 21 | import com.yixia.camera.demo.R; 22 | import com.yixia.camera.demo.po.Video; 23 | import com.yixia.camera.demo.ui.record.ImportVideoActivity; 24 | import com.yixia.camera.demo.ui.record.ImportVideoSelectActivity.VideoRow; 25 | import com.yixia.weibo.sdk.util.DateUtil; 26 | import com.yixia.weibo.sdk.util.StringUtils; 27 | 28 | public class ImportVideoSelectionAdapter extends BaseAdapter { 29 | 30 | private ArrayList selectionVideoList; 31 | private Context mContext; 32 | /** 一行显示个数 */ 33 | private static final int ROW_ITEM_COUNT = 3; 34 | private int mItemHeight; 35 | 36 | public ImportVideoSelectionAdapter(Context context, int itemWidth) { 37 | this.mContext = context; 38 | this.mItemHeight = itemWidth; 39 | selectionVideoList = new ArrayList(); 40 | } 41 | 42 | public void updateVideoData(ArrayList result) { 43 | selectionVideoList = result; 44 | this.notifyDataSetChanged(); 45 | } 46 | 47 | @Override 48 | public int getCount() { 49 | return selectionVideoList.size(); 50 | } 51 | 52 | @Override 53 | public Object getItem(int position) { 54 | return selectionVideoList.get(position); 55 | } 56 | 57 | @Override 58 | public long getItemId(int position) { 59 | return position; 60 | } 61 | 62 | @Override 63 | public View getView(int position, View convertView, ViewGroup parent) { 64 | final ViewHolder holder; 65 | if (convertView == null) { 66 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_import_video, null); 67 | holder = new ViewHolder(convertView); 68 | 69 | View.OnClickListener mCheckedOnClickListener = new OnClickListener() { 70 | 71 | @Override 72 | public void onClick(View v) { 73 | Video video = (Video) v.getTag(); 74 | // 去剪切页面 75 | if (video != null) { 76 | Intent intent = new Intent(mContext, ImportVideoActivity.class); 77 | Bundle bundle = ((Activity) mContext).getIntent().getExtras(); 78 | if (bundle == null) 79 | bundle = new Bundle(); 80 | bundle.putString("source", video.url); 81 | if (StringUtils.isNotEmpty(video.url) && video.url.endsWith(".gif")) 82 | bundle.putBoolean("gif", true); 83 | 84 | bundle.putInt("orientation", video.orientation); 85 | intent.putExtras(bundle); 86 | 87 | // intent.putExtra("title", 88 | // R.string.record_camera_import_video_title); 89 | // if (mFromMulti) { 90 | // startActivityForResult(intent, REQUEST_CODE_MULTI); 91 | // } else { 92 | mContext.startActivity(intent); 93 | // } 94 | // if (getActivity() != null) 95 | // getActivity().overridePendingTransition(R.anim.activity_right_in, R.anim.activity_right_out); 96 | } 97 | } 98 | }; 99 | 100 | for (int i = 0; i < ROW_ITEM_COUNT; i++) { 101 | ViewGroup.LayoutParams lp = holder.layout[i].getLayoutParams(); 102 | lp.width = mItemHeight; 103 | lp.height = mItemHeight; 104 | holder.icon[i].setOnClickListener(mCheckedOnClickListener); 105 | } 106 | 107 | convertView.setTag(holder); 108 | } else { 109 | holder = (ViewHolder) convertView.getTag(); 110 | } 111 | 112 | final VideoRow item = (VideoRow) getItem(position); 113 | 114 | final List