diff --git a/PLDroidShortVideoDemo/app/build.gradle b/PLDroidShortVideoDemo/app/build.gradle
index 447d31b..1e79cfc 100644
--- a/PLDroidShortVideoDemo/app/build.gradle
+++ b/PLDroidShortVideoDemo/app/build.gradle
@@ -14,8 +14,8 @@ android {
applicationId "com.qiniu.pili.droid.shortvideo.demo"
minSdkVersion 18
targetSdkVersion 25
- versionCode 14
- versionName "1.9.0"
+ versionCode 15
+ versionName "1.10.0"
multiDexEnabled true
buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L"
ndk {
@@ -32,7 +32,7 @@ android {
dependencies {
compile 'com.qiniu:qiniu-android-sdk:7.3.10'
- compile files('libs/pldroid-shortvideo-1.9.0.jar')
+ compile files('libs/pldroid-shortvideo-1.10.0.jar')
compile files('libs/pldroid-player-2.0.5.jar')
compile files('libs/EasyAR.jar')
compile files('libs/EasyAR3D.jar')
@@ -52,4 +52,5 @@ dependencies {
compile files('libs/TuSDKFace-1.0.0.jar')
compile files('libs/TuSDKVideo-1.11.0.jar')
compile files('libs/universal-image-loader-1.9.4.jar')
+ compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.6'
}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.10.0.jar b/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.10.0.jar
new file mode 100644
index 0000000..d0ef0d7
Binary files /dev/null and b/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.10.0.jar differ
diff --git a/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.9.0.jar b/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.9.0.jar
deleted file mode 100644
index df6915f..0000000
Binary files a/PLDroidShortVideoDemo/app/libs/pldroid-shortvideo-1.9.0.jar and /dev/null differ
diff --git a/PLDroidShortVideoDemo/app/src/main/AndroidManifest.xml b/PLDroidShortVideoDemo/app/src/main/AndroidManifest.xml
index fbe57b6..cabc18b 100644
--- a/PLDroidShortVideoDemo/app/src/main/AndroidManifest.xml
+++ b/PLDroidShortVideoDemo/app/src/main/AndroidManifest.xml
@@ -14,10 +14,10 @@
@@ -27,8 +27,7 @@
-
+
@@ -72,11 +71,23 @@
+ android:theme="@style/AppTheme" />
+
+
+
diff --git a/PLDroidShortVideoDemo/app/src/main/assets/fonts/HappyZcool-2016.ttf b/PLDroidShortVideoDemo/app/src/main/assets/fonts/HappyZcool-2016.ttf
new file mode 100644
index 0000000..ba2ad8a
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/assets/fonts/HappyZcool-2016.ttf differ
diff --git a/PLDroidShortVideoDemo/app/src/main/assets/fonts/zcool-gdh.ttf b/PLDroidShortVideoDemo/app/src/main/assets/fonts/zcool-gdh.ttf
new file mode 100644
index 0000000..ee49dea
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/assets/fonts/zcool-gdh.ttf differ
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/ArRecordActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/ArRecordActivity.java
index bdffa47..cc81b2c 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/ArRecordActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/ArRecordActivity.java
@@ -180,8 +180,8 @@ private void initview() {
}
private String prepareUrl() {
- String timeStamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
- String fileName = "EasyAR_Recording_" + timeStamp + ".mp4";
+ String timestamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
+ String fileName = "EasyAR_Recording_" + timestamp + ".mp4";
File folder = new File(Config.VIDEO_STORAGE_DIR + "ArMovies");
if (!folder.exists())
folder.mkdirs();
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/MainActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/MainActivity.java
index 4cd2014..09b0d34 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/MainActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/MainActivity.java
@@ -133,6 +133,12 @@ public void onClickAR(View v) {
}
}
+ public void onClickTransitionMake(View v) {
+ if (isPermissionOK()) {
+ jumpToActivity(VideoDivideActivity.class);
+ }
+ }
+
public void onClickDraftBox(View v) {
if (isPermissionOK()) {
jumpToActivity(DraftBoxActivity.class);
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/TransitionMakeActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/TransitionMakeActivity.java
new file mode 100644
index 0000000..abec724
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/TransitionMakeActivity.java
@@ -0,0 +1,233 @@
+package com.qiniu.pili.droid.shortvideo.demo.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.PLVideoSaveListener;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition0;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition1;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition2;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition3;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition4;
+import com.qiniu.pili.droid.shortvideo.demo.transition.Transition5;
+import com.qiniu.pili.droid.shortvideo.demo.transition.TransitionBase;
+import com.qiniu.pili.droid.shortvideo.demo.utils.ToastUtils;
+import com.qiniu.pili.droid.shortvideo.demo.view.CustomProgressDialog;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionEditView;
+
+import java.lang.reflect.Constructor;
+
+import static com.qiniu.pili.droid.shortvideo.demo.activity.VideoFrameActivity.DATA_EXTRA_PATH;
+import static com.qiniu.pili.droid.shortvideo.demo.utils.Config.VIDEO_STORAGE_DIR;
+
+public class TransitionMakeActivity extends Activity {
+ private static final String TAG = "TransitionMakeActivity";
+
+ private static String[] TRANSITION_TITLE = {
+ "大标题", "章节", "简约", "引用", "标题与副标题", "片尾"
+ };
+ private static Class[] TRANSITION_CLASS = {
+ Transition0.class, Transition1.class, Transition2.class, Transition3.class, Transition4.class, Transition5.class
+ };
+
+ private RecyclerView mTransListView;
+ private CustomProgressDialog mProcessingDialog;
+
+ private TransitionBase[] mTransitions = new TransitionBase[6];
+ private TransitionBase mCurTransition;
+ private TransitionEditView mTransEditView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_transition);
+
+ initTransitions();
+
+ mTransListView = (RecyclerView) findViewById(R.id.recycler_transition);
+ mTransEditView = (TransitionEditView) findViewById(R.id.transition_edit_view);
+
+ LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
+ mTransListView.setLayoutManager(layoutManager);
+ mTransListView.setAdapter(new TransListAdapter());
+
+ //consumed the event
+ mTransEditView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true;
+ }
+ });
+
+ mProcessingDialog = new CustomProgressDialog(this);
+ mProcessingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mCurTransition.cancelSave();
+ }
+ });
+ }
+
+ private void initTransitions() {
+ final PLVideoEncodeSetting setting = new PLVideoEncodeSetting(TransitionMakeActivity.this);
+ setting.setEncodingSizeLevel(PLVideoEncodeSetting.VIDEO_ENCODING_SIZE_LEVEL.VIDEO_ENCODING_SIZE_LEVEL_720P_3);
+ for (int i = 0; i < mTransitions.length; i++) {
+ final ViewGroup viewGroup = (ViewGroup) findViewById(getResources().getIdentifier("transition_container" + i, "id", getPackageName()));
+ final int index = i;
+ viewGroup.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Constructor constructor = TRANSITION_CLASS[index].getConstructor(ViewGroup.class, PLVideoEncodeSetting.class);
+ TransitionBase transition = (TransitionBase) constructor.newInstance(viewGroup, setting);
+
+ mTransitions[index] = transition;
+
+ //default show first transition
+ if (index == 0) {
+ transition.setVisibility(View.VISIBLE);
+ mCurTransition = transition;
+ mTransEditView.setTransition(mCurTransition);
+ } else {
+ transition.setVisibility(View.INVISIBLE);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ ToastUtils.s(TransitionMakeActivity.this, "Can not init Transition : " + "Transition" + index);
+ }
+ }
+ });
+ }
+ }
+
+ public void onBackClicked(View view) {
+ finish();
+ }
+
+ public void onSaveClicked(View view) {
+ mProcessingDialog.show();
+ String path = VIDEO_STORAGE_DIR + "pl-transition-" + System.currentTimeMillis() + ".mp4";
+
+ mCurTransition.save(path, new PLVideoSaveListener() {
+ @Override
+ public void onSaveVideoSuccess(final String destFile) {
+ Log.i(TAG, "save success: " + destFile);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mProcessingDialog.dismiss();
+
+ Intent intent = new Intent();
+ intent.putExtra(DATA_EXTRA_PATH, destFile);
+ setResult(VideoFrameActivity.TRANSITION_REQUEST_CODE, intent);
+ finish();
+ }
+ });
+ }
+
+ @Override
+ public void onSaveVideoFailed(int errorCode) {
+ }
+
+ @Override
+ public void onSaveVideoCanceled() {
+ }
+
+ @Override
+ public void onProgressUpdate(final float percentage) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mProcessingDialog.setProgress((int) (100 * percentage));
+ }
+ });
+ }
+ });
+ }
+
+ public void onEditClicked(View view) {
+ mTransEditView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ for (int i = 0; i < mTransitions.length; i++) {
+ mTransitions[i].destroy();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mTransEditView.getVisibility() == View.VISIBLE) {
+ mTransEditView.setVisibility(View.GONE);
+ } else {
+ finish();
+ }
+ }
+
+ private class TransViewHolder extends RecyclerView.ViewHolder {
+ public TextView mTitle;
+ public View mItemView;
+
+ public TransViewHolder(View itemView) {
+ super(itemView);
+ mItemView = itemView;
+ mTitle = (TextView) itemView.findViewById(R.id.title_text);
+ }
+ }
+
+ private class TransListAdapter extends RecyclerView.Adapter {
+ private View mSelectedView;
+
+ @Override
+ public TransViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ Context context = parent.getContext();
+ LayoutInflater inflater = LayoutInflater.from(context);
+ View contactView = inflater.inflate(R.layout.item_transition_selector, parent, false);
+ TransViewHolder viewHolder = new TransViewHolder(contactView);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(final TransViewHolder holder, final int position) {
+ holder.mTitle.setText(TRANSITION_TITLE[position]);
+ holder.mItemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mSelectedView != null) {
+ mSelectedView.setSelected(false);
+ }
+ holder.mItemView.setSelected(true);
+ mSelectedView = holder.mItemView;
+
+ for (int i = 0; i < mTransitions.length; i++) {
+ mTransitions[i].setVisibility(View.GONE);
+ }
+ mTransitions[position].setVisibility(View.VISIBLE);
+ mTransitions[position].play();
+ mCurTransition = mTransitions[position];
+ mTransEditView.setTransition(mCurTransition);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return TRANSITION_TITLE.length;
+ }
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoComposeActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoComposeActivity.java
index 8926113..781738d 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoComposeActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoComposeActivity.java
@@ -130,11 +130,14 @@ public void onClickCompose(View v) {
ToastUtils.s(this, "请先添加至少 2 个视频");
return;
}
- mProcessingDialog.show();
PLVideoEncodeSetting setting = new PLVideoEncodeSetting(this);
setting.setEncodingSizeLevel(getEncodingSizeLevel(mEncodingSizeLevelSpinner.getSelectedItemPosition()));
setting.setEncodingBitrate(getEncodingBitrateLevel(mEncodingBitrateLevelSpinner.getSelectedItemPosition()));
- mShortVideoComposer.composeVideos(videos, Config.COMPOSE_FILE_PATH, setting, mVideoSaveListener);
+ if (mShortVideoComposer.composeVideos(videos, Config.COMPOSE_FILE_PATH, setting, mVideoSaveListener)) {
+ mProcessingDialog.show();
+ } else {
+ ToastUtils.s(this, "开始拼接失败!");
+ }
}
private PLVideoSaveListener mVideoSaveListener = new PLVideoSaveListener() {
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoDivideActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoDivideActivity.java
new file mode 100644
index 0000000..66fc755
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoDivideActivity.java
@@ -0,0 +1,597 @@
+package com.qiniu.pili.droid.shortvideo.demo.activity;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.MediaPlayer;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.VideoView;
+
+import com.qiniu.pili.droid.shortvideo.PLMediaFile;
+import com.qiniu.pili.droid.shortvideo.PLShortVideoTrimmer;
+import com.qiniu.pili.droid.shortvideo.PLVideoFrame;
+import com.qiniu.pili.droid.shortvideo.PLVideoSaveListener;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.utils.GetPathFromUri;
+import com.qiniu.pili.droid.shortvideo.demo.view.CustomProgressDialog;
+import com.qiniu.pili.droid.shortvideo.demo.view.FrameSelectorView;
+import com.qiniu.pili.droid.shortvideo.demo.view.ObservableHorizontalScrollView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static com.qiniu.pili.droid.shortvideo.demo.activity.VideoFrameActivity.DATA_EXTRA_JUMP;
+import static com.qiniu.pili.droid.shortvideo.demo.activity.VideoFrameActivity.DATA_EXTRA_PATHS;
+import static com.qiniu.pili.droid.shortvideo.demo.utils.Config.VIDEO_STORAGE_DIR;
+
+public class VideoDivideActivity extends Activity {
+ private static final String TAG = "VideoDivideActivity";
+
+ private PLShortVideoTrimmer mShortVideoTrimmer;
+ private PLMediaFile mMediaFile;
+
+ private CustomProgressDialog mProcessingDialog;
+ private VideoView mPreview;
+ private RecyclerView mFrameList;
+ private ViewGroup mFrameListParent;
+ private ObservableHorizontalScrollView mScrollView;
+ private FrameLayout mScrollViewParent;
+ private ImageButton mPlaybackButton;
+ private FrameSelectorView mCurSelectorView;
+
+ private long mDurationMs;
+ private int mVideoFrameCount;
+ private long mShowFrameIntervalMs;
+ private String mSrcVideoPath;
+
+ private FrameListAdapter mFrameListAdapter;
+
+ private int mFrameWidth;
+ private int mFrameHeight;
+ private int mCurTrimNum;
+
+ private ArrayList mSectionList = new ArrayList<>();
+ private ArrayList mPathList = new ArrayList<>();
+
+ private TimerTask mScrollTimerTask;
+ private Timer mScrollTimer;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ mProcessingDialog = new CustomProgressDialog(this);
+ mProcessingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mShortVideoTrimmer.cancelTrim();
+ }
+ });
+
+ Intent intent = new Intent();
+ if (Build.VERSION.SDK_INT < 19) {
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ intent.setType("video/*");
+ } else {
+ intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("video/*");
+ }
+ startActivityForResult(Intent.createChooser(intent, "选择要导入的视频"), 0);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == Activity.RESULT_OK) {
+ mSrcVideoPath = GetPathFromUri.getPath(this, data.getData());
+ Log.i(TAG, "Select file: " + mSrcVideoPath);
+ if (mSrcVideoPath != null && !"".equals(mSrcVideoPath)) {
+ init();
+ }
+ } else {
+ finish();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ play();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mScrollTimer != null) {
+ mScrollTimer.cancel();
+ mScrollTimer = null;
+ }
+ if (mScrollTimerTask != null) {
+ mScrollTimerTask.cancel();
+ mScrollTimerTask = null;
+ }
+ }
+
+ public void onClickBack(View view) {
+ finish();
+ }
+
+ public void onClickDone(View view) {
+ resetData();
+ if (mSectionList.size() > 0) {
+ trimOnce();
+ } else {
+ noTrimJump();
+ }
+ }
+
+ public void onClickAdd(View view) {
+ pausePlayback();
+ addSelectedRect();
+ addSelectorView();
+ }
+
+ public void onClickPlayback(View view) {
+ if (mPreview.isPlaying()) {
+ pausePlayback();
+ } else {
+ startPlayback();
+ }
+ }
+
+ private void init() {
+ initView();
+ initMediaInfo();
+ initVideoPlayer();
+ initFrameList();
+ initTimerTask();
+ }
+
+ private void initView() {
+ setContentView(R.layout.activity_video_divide);
+
+ mPreview = (VideoView) findViewById(R.id.preview);
+ mPlaybackButton = (ImageButton) findViewById(R.id.pause_playback);
+ mFrameListParent = (ViewGroup) findViewById(R.id.recycler_parent);
+ mFrameList = (RecyclerView) findViewById(R.id.recycler_frame_list);
+ mScrollViewParent = (FrameLayout) findViewById(R.id.scroll_view_parent);
+ mScrollView = (ObservableHorizontalScrollView) findViewById(R.id.scroll_view);
+
+ ImageView middleLineImage = (ImageView) findViewById(R.id.middle_line_image);
+ ViewGroup topGroup = (ViewGroup) findViewById(R.id.top_group);
+
+ WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ mFrameWidth = mFrameHeight = wm.getDefaultDisplay().getWidth() / 6;
+ middleLineImage.getLayoutParams().height = mFrameHeight;
+
+ mScrollView.setOnScrollListener(new OnViewScrollListener());
+ topGroup.setOnTouchListener(new OnTopViewTouchListener());
+ }
+
+ private void initMediaInfo() {
+ mMediaFile = new PLMediaFile(mSrcVideoPath);
+ mDurationMs = mMediaFile.getDurationMs();
+ // if the duration time > 10s, the interval time is 3s, else is 1s
+ mShowFrameIntervalMs = (mDurationMs >= 1000 * 10) ? 3000 : 1000;
+ Log.i(TAG, "video duration: " + mDurationMs);
+ mVideoFrameCount = mMediaFile.getVideoFrameCount(false);
+ Log.i(TAG, "video frame count: " + mVideoFrameCount);
+ }
+
+ private void initVideoPlayer() {
+ mPreview.setVideoPath(mSrcVideoPath);
+ mPreview.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mediaPlayer) {
+ play();
+ }
+ });
+ play();
+ }
+
+ private void initTimerTask() {
+ mScrollTimerTask = new TimerTask() {
+ @Override
+ public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final int position = mPreview.getCurrentPosition();
+ if (mPreview.isPlaying()) {
+ scrollToTime(position);
+ }
+ }
+ });
+ }
+ };
+ mScrollTimer = new Timer();
+ // scroll fps:20
+ mScrollTimer.schedule(mScrollTimerTask, 50, 50);
+ }
+
+ private void initFrameList() {
+ mFrameListAdapter = new FrameListAdapter();
+ mFrameList.setAdapter(mFrameListAdapter);
+ mFrameList.setItemViewCacheSize(getShowFrameCount());
+ LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
+ mFrameList.setLayoutManager(layoutManager);
+ }
+
+ private void resetData() {
+ mCurTrimNum = 0;
+ mPathList.clear();
+ }
+
+ private void trimOnce() {
+ if (mCurTrimNum < mSectionList.size()) {
+ mProcessingDialog.setProgress(0);
+ mProcessingDialog.setMessage("正在处理第 " + (mCurTrimNum + 1) + "/" + mSectionList.size() + " 段视频 ...");
+ mProcessingDialog.show();
+
+ SectionItem item = mSectionList.get(mCurTrimNum);
+ if (mShortVideoTrimmer != null) {
+ mShortVideoTrimmer.destroy();
+ }
+ mShortVideoTrimmer = new PLShortVideoTrimmer(this, mSrcVideoPath, item.mVideoPath);
+ mShortVideoTrimmer.trim(item.mStartTime, item.mEndTime, PLShortVideoTrimmer.TRIM_MODE.ACCURATE, mSaveListener);
+ mCurTrimNum += 1;
+ } else {
+ mProcessingDialog.dismiss();
+ jumpToActivity();
+ resetData();
+ }
+ }
+
+ private void noTrimJump() {
+ mPathList.add(mSrcVideoPath);
+ jumpToActivity();
+ resetData();
+ }
+
+ private void jumpToActivity() {
+ Intent intent = new Intent(this, VideoFrameActivity.class);
+ intent.putStringArrayListExtra(DATA_EXTRA_PATHS, mPathList);
+ boolean isJumpedTo = getIntent().getBooleanExtra(DATA_EXTRA_JUMP, false);
+ if (isJumpedTo) {
+ setResult(VideoFrameActivity.DIVIDE_REQUEST_CODE, intent);
+ } else {
+ startActivity(intent);
+ }
+ finish();
+ }
+
+ private void addSelectorView() {
+ mCurSelectorView = new FrameSelectorView(this);
+ final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mFrameListParent.getHeight());
+ mCurSelectorView.setVisibility(View.INVISIBLE);
+ mScrollViewParent.addView(mCurSelectorView, layoutParams);
+
+ mCurSelectorView.post(new Runnable() {
+ @Override
+ public void run() {
+ // put mCurSelectorView to the middle of the horizontal
+ layoutParams.leftMargin = (mScrollViewParent.getWidth() - mCurSelectorView.getWidth()) / 2;
+ mCurSelectorView.setLayoutParams(layoutParams);
+ mCurSelectorView.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+
+ public void addSelectedRect() {
+ if (mCurSelectorView == null) {
+ return;
+ }
+
+ int leftBorder = mCurSelectorView.getBodyLeft();
+ int rightBorder = mCurSelectorView.getBodyRight();
+ int width = mCurSelectorView.getBodyWidth();
+
+ boolean outOfLeft = leftBorder <= getHalfGroupWidth() - mScrollView.getScrollX();
+ boolean outOfRight = rightBorder >= getHalfGroupWidth() + (getTotalScrollLength() - mScrollView.getScrollX());
+
+ if (outOfLeft && !outOfRight) {
+ leftBorder = getHalfGroupWidth() - mScrollView.getScrollX();
+ width = rightBorder - leftBorder;
+ } else if (!outOfLeft && outOfRight) {
+ width = width - (rightBorder - getHalfGroupWidth() - (getTotalScrollLength() - mScrollView.getScrollX()));
+ } else if (outOfLeft && outOfRight) {
+ leftBorder = getHalfGroupWidth() - mScrollView.getScrollX();
+ width = getTotalScrollLength();
+ }
+
+ if (width <= 0) {
+ mCurSelectorView.setVisibility(View.GONE);
+ return;
+ }
+
+ final View rectView = new View(this);
+ rectView.setBackground(getResources().getDrawable(R.drawable.frame_selector_rect));
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, mFrameListParent.getHeight());
+ rectView.setOnTouchListener(new RectViewTouchListener());
+
+ int leftPosition = leftBorder + mScrollView.getScrollX();
+ int rightPosition = leftPosition + width;
+
+ layoutParams.leftMargin = leftPosition;
+ mFrameListParent.addView(rectView, layoutParams);
+
+ mCurSelectorView.setVisibility(View.GONE);
+
+ SectionItem item = addSection(leftPosition, rightPosition);
+ rectView.setTag(item);
+ }
+
+ private SectionItem addSection(int leftPosition, int rightPosition) {
+ String path = VIDEO_STORAGE_DIR + "pl-trim-" + System.currentTimeMillis() + ".mp4";
+ long startTime = getTimeByPosition(leftPosition);
+ long endTime = getTimeByPosition(rightPosition);
+ SectionItem sectionItem = new SectionItem(startTime, endTime, path);
+ mSectionList.add(sectionItem);
+ return sectionItem;
+ }
+
+ private long getTimeByPosition(int position) {
+ position = position - getHalfGroupWidth();
+ return (long) ((float) mDurationMs * position / getTotalScrollLength());
+ }
+
+ private int getTotalScrollLength() {
+ return getShowFrameCount() * mFrameWidth;
+ }
+
+ private int getHalfGroupWidth() {
+ return mFrameWidth * 3;
+ }
+
+ private int getScrollLengthByTime(long time) {
+ return (int) ((float) getTotalScrollLength() * time / mDurationMs);
+ }
+
+ private void scrollToTime(long time) {
+ int scrollLength = getScrollLengthByTime(time);
+ mScrollView.smoothScrollTo(scrollLength, 0);
+ }
+
+ private int getShowFrameCount() {
+ return (int) Math.ceil((float) mDurationMs / mShowFrameIntervalMs);
+ }
+
+ private void startPlayback() {
+ mPreview.start();
+ mPlaybackButton.setImageResource(R.mipmap.btn_pause);
+ }
+
+ private void pausePlayback() {
+ mPreview.pause();
+ mPlaybackButton.setImageResource(R.mipmap.btn_play);
+ }
+
+ private boolean isInRangeOfView(View view, MotionEvent ev) {
+ int[] location = new int[2];
+ view.getLocationOnScreen(location);
+ int x = location[0];
+ int y = location[1];
+ if (ev.getX() < x ||
+ ev.getX() > (x + view.getWidth()) ||
+ ev.getY() < y ||
+ ev.getY() > (y + view.getHeight())) {
+ return false;
+ }
+ return true;
+ }
+
+ private void play() {
+ if (mPreview != null) {
+ mPreview.seekTo(0);
+ startPlayback();
+ }
+ }
+
+ private PLVideoSaveListener mSaveListener = new PLVideoSaveListener() {
+ @Override
+ public void onSaveVideoSuccess(String destFile) {
+ mPathList.add(destFile);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ trimOnce();
+ }
+ });
+ }
+
+ @Override
+ public void onSaveVideoFailed(int errorCode) {
+ }
+
+ @Override
+ public void onSaveVideoCanceled() {
+ }
+
+ @Override
+ public void onProgressUpdate(final float percentage) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mProcessingDialog.setProgress((int) (100 * percentage));
+ }
+ });
+ }
+ };
+
+ private class RectViewTouchListener implements View.OnTouchListener {
+ private View mRectView;
+ private GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ SectionItem item = (SectionItem) mRectView.getTag();
+ mSectionList.remove(item);
+ mFrameListParent.removeView(mRectView);
+ return false;
+ }
+ };
+ private GestureDetector mGestureDetector = new GestureDetector(VideoDivideActivity.this, mSimpleOnGestureListener);
+
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ mRectView = view;
+ if (mGestureDetector.onTouchEvent(event)) {
+ return true;
+ }
+ return true;
+ }
+ }
+
+ private class OnTopViewTouchListener implements View.OnTouchListener {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (!isInRangeOfView(mScrollViewParent, event)) {
+ if (mCurSelectorView != null) {
+ addSelectedRect();
+ mCurSelectorView = null;
+ }
+ }
+ return false;
+ }
+ }
+
+ private class OnViewScrollListener implements ObservableHorizontalScrollView.OnScrollListener {
+ @Override
+ public void onScrollChanged(ObservableHorizontalScrollView scrollView, final int x, int y, int oldX, int oldY, boolean dragScroll) {
+ if (dragScroll) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mPreview.isPlaying()) {
+ pausePlayback();
+ }
+ int index = x / mFrameWidth;
+ mPreview.seekTo((int) (index * mShowFrameIntervalMs));
+ }
+ });
+ }
+ }
+ }
+
+ private class ItemViewHolder extends RecyclerView.ViewHolder {
+ public ImageView mImageView;
+
+ public ItemViewHolder(View itemView) {
+ super(itemView);
+ mImageView = (ImageView) itemView.findViewById(R.id.thumbnail);
+ }
+ }
+
+ private class FrameListAdapter extends RecyclerView.Adapter {
+
+ @Override
+ public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ Context context = parent.getContext();
+ LayoutInflater inflater = LayoutInflater.from(context);
+
+ View contactView = inflater.inflate(R.layout.item_devide_frame, parent, false);
+ ItemViewHolder viewHolder = new ItemViewHolder(contactView);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(final ItemViewHolder holder, final int position) {
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mFrameWidth, mFrameHeight);
+ params.width = mFrameWidth;
+ holder.mImageView.setLayoutParams(params);
+
+ // there are 6 dark frames in begin and end sides
+ if (position == 0 ||
+ position == 1 ||
+ position == 2 ||
+ position == getShowFrameCount() + 3 ||
+ position == getShowFrameCount() + 4 ||
+ position == getShowFrameCount() + 5) {
+ return;
+ }
+
+ long frameTime = (position - 3) * mShowFrameIntervalMs;
+ new ImageViewTask(holder.mImageView, frameTime, mFrameWidth, mFrameHeight, mMediaFile).execute();
+ }
+
+ @Override
+ public int getItemCount() {
+ return getShowFrameCount() + 6;
+ }
+
+ }
+
+ private static class ImageViewTask extends AsyncTask {
+ private WeakReference mImageViewWeakReference;
+ private long mFrameTime;
+ private int mFrameWidth;
+ private int mFrameHeight;
+ private PLMediaFile mMediaFile;
+
+ ImageViewTask(ImageView imageView, long frameTime, int frameWidth, int frameHeight, PLMediaFile mediaFile) {
+ mImageViewWeakReference = new WeakReference<>(imageView);
+ mFrameTime = frameTime;
+ mFrameWidth = frameWidth;
+ mFrameHeight = frameHeight;
+ mMediaFile = mediaFile;
+ }
+
+ @Override
+ protected PLVideoFrame doInBackground(Void... v) {
+ PLVideoFrame frame = mMediaFile.getVideoFrameByTime(mFrameTime, false, mFrameWidth, mFrameHeight);
+ return frame;
+ }
+
+ @Override
+ protected void onPostExecute(PLVideoFrame frame) {
+ super.onPostExecute(frame);
+ ImageView mImageView = mImageViewWeakReference.get();
+ if (mImageView == null) {
+ return;
+ }
+ if (frame != null) {
+ int rotation = frame.getRotation();
+ Bitmap bitmap = frame.toBitmap();
+ mImageView.setImageBitmap(bitmap);
+ mImageView.setRotation(rotation);
+ }
+ }
+ }
+
+ private class SectionItem {
+ long mStartTime;
+ long mEndTime;
+ String mVideoPath;
+
+ public SectionItem(long startTime, long endTime, String videoPath) {
+ mStartTime = startTime;
+ mEndTime = endTime;
+ mVideoPath = videoPath;
+ }
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoEditActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoEditActivity.java
index 2cab9c7..3a750b0 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoEditActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoEditActivity.java
@@ -1026,7 +1026,7 @@ public void onSurfaceDestroy() {
}
@Override
- public int onDrawFrame(int texId, int texWidth, int texHeight, long timeStampNs, float[] transformMatrix) {
+ public int onDrawFrame(int texId, int texWidth, int texHeight, long timestampNs, float[] transformMatrix) {
if (mCancelSave && mTuSDKManager.getPreviewFilterEngine() == null) {
mTuSDKManager.setupPreviewFilterEngine();
mTuSDKManager.getPreviewFilterEngine().onSurfaceCreated();
@@ -1083,8 +1083,8 @@ public void onSurfaceDestroy() {
}
@Override
- public int onDrawFrame(int texId, int texWidth, int texHeight, long timeStampNs, float[] transformMatrix) {
- long currentTimeMs = (long) Math.ceil(timeStampNs / 1000000L);
+ public int onDrawFrame(int texId, int texWidth, int texHeight, long timestampNs, float[] transformMatrix) {
+ long currentTimeMs = (long) Math.ceil(timestampNs / 1000000L);
if (startTimeMs == 0) {
startTimeMs = currentTimeMs;
}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoFrameActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoFrameActivity.java
new file mode 100644
index 0000000..4186fb2
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoFrameActivity.java
@@ -0,0 +1,179 @@
+package com.qiniu.pili.droid.shortvideo.demo.activity;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.SimpleItemAnimator;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
+import com.qiniu.pili.droid.shortvideo.PLShortVideoComposer;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.PLVideoSaveListener;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.utils.Config;
+import com.qiniu.pili.droid.shortvideo.demo.utils.ToastUtils;
+import com.qiniu.pili.droid.shortvideo.demo.view.CustomProgressDialog;
+import com.qiniu.pili.droid.shortvideo.demo.view.DragItemAdapter;
+
+import java.util.ArrayList;
+
+public class VideoFrameActivity extends Activity {
+ public static final int TRANSITION_REQUEST_CODE = 1;
+ public static final int DIVIDE_REQUEST_CODE = 2;
+ public static final String DATA_EXTRA_PATHS = "paths";
+ public static final String DATA_EXTRA_PATH = "path";
+ public static final String DATA_EXTRA_JUMP = "jump";
+
+ private RecyclerView mRecyclerView;
+ private RecyclerView.LayoutManager mLayoutManager;
+ private PLShortVideoComposer mShortVideoComposer;
+ private CustomProgressDialog mProcessingDialog;
+ private DragItemAdapter mDragItemAdapter;
+
+ private ArrayList mVideoPaths;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ setContentView(R.layout.activity_video_frame);
+ mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
+ mLayoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
+
+ ArrayList arrayList = getIntent().getStringArrayListExtra(DATA_EXTRA_PATHS);
+ mVideoPaths = (arrayList == null) ? new ArrayList() : arrayList;
+
+ mDragItemAdapter = new DragItemAdapter(mVideoPaths);
+ mDragItemAdapter.setOnItemMovedListener(new DragItemAdapter.OnItemMovedListener() {
+ @Override
+ public void onMoveItem(int fromPosition, int toPosition) {
+ String movedItem = mVideoPaths.remove(fromPosition);
+ mVideoPaths.add(toPosition, movedItem);
+ }
+ });
+
+ RecyclerViewDragDropManager dragDropManager = new RecyclerViewDragDropManager();
+ dragDropManager.setInitiateOnMove(false);
+ dragDropManager.setInitiateOnLongPress(true);
+
+ RecyclerView.Adapter adapter = dragDropManager.createWrappedAdapter(mDragItemAdapter);
+ mRecyclerView.setAdapter(adapter);
+ dragDropManager.attachRecyclerView(mRecyclerView);
+
+ mShortVideoComposer = new PLShortVideoComposer(this);
+ mProcessingDialog = new CustomProgressDialog(this);
+ mProcessingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mShortVideoComposer.cancelComposeVideos();
+ }
+ });
+ }
+
+ @Override
+ public void onBackPressed() {
+ showFinishDialog();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // TODO Auto-generated method stub
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == TRANSITION_REQUEST_CODE && data != null) {
+ String path = data.getStringExtra(DATA_EXTRA_PATH);
+ if (path != null) {
+ mVideoPaths.add(path);
+ }
+ } else if (requestCode == DIVIDE_REQUEST_CODE && data != null) {
+ ArrayList appendPaths = data.getStringArrayListExtra(DATA_EXTRA_PATHS);
+ if (appendPaths != null) {
+ mVideoPaths.addAll(appendPaths);
+ }
+ }
+ mDragItemAdapter.updatePaths(mVideoPaths);
+ mDragItemAdapter.notifyDataSetChanged();
+ }
+
+ public void onBack(View view) {
+ showFinishDialog();
+ }
+
+ public void onDone(View view) {
+ PLVideoEncodeSetting setting = new PLVideoEncodeSetting(this);
+ setting.setEncodingSizeLevel(PLVideoEncodeSetting.VIDEO_ENCODING_SIZE_LEVEL.VIDEO_ENCODING_SIZE_LEVEL_720P_2);
+
+ if (mShortVideoComposer.composeVideos(mVideoPaths, Config.VIDEO_DIVIDE_FILE_PATH, setting, mVideoSaveListener)) {
+ mProcessingDialog.show();
+ } else {
+ ToastUtils.s(this, "开始拼接失败!");
+ }
+ }
+
+ public void onClickAddVideo(View view) {
+ Intent intent = new Intent(this, VideoDivideActivity.class);
+ intent.putExtra(DATA_EXTRA_JUMP, true);
+ startActivityForResult(intent, DIVIDE_REQUEST_CODE);
+ }
+
+ public void onClickAddTransition(View view) {
+ startActivityForResult(new Intent(this, TransitionMakeActivity.class), TRANSITION_REQUEST_CODE);
+ }
+
+ private void showFinishDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("确定要放弃剪切的视频吗?")
+ .setPositiveButton("确定", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ finish();
+ }
+ })
+ .setNegativeButton("取消", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
+ builder.create().show();
+ }
+
+ private PLVideoSaveListener mVideoSaveListener = new PLVideoSaveListener() {
+ @Override
+ public void onSaveVideoSuccess(final String destFile) {
+ mProcessingDialog.dismiss();
+ PlaybackActivity.start(VideoFrameActivity.this, destFile);
+ }
+
+ @Override
+ public void onSaveVideoFailed(int errorCode) {
+
+ }
+
+ @Override
+ public void onSaveVideoCanceled() {
+
+ }
+
+ @Override
+ public void onProgressUpdate(final float percentage) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mProcessingDialog.setProgress((int) (100 * percentage));
+ }
+ });
+ }
+ };
+}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoRecordActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoRecordActivity.java
index c92d656..1345548 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoRecordActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoRecordActivity.java
@@ -249,7 +249,7 @@ public void onSurfaceDestroy() {
}
@Override
- public int onDrawFrame(int texId, int texWidth, int texHeight, long timeStampNs, float[] transformMatrix) {
+ public int onDrawFrame(int texId, int texWidth, int texHeight, long timestampNs, float[] transformMatrix) {
if (!isTrackerOnSurfaceChangedCalled) {
isTrackerOnSurfaceChangedCalled = true;
mKiwiTrackWrapper.onSurfaceChanged(surfaceWidth, surfaceHeight, texWidth, texHeight);
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTranscodeActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTranscodeActivity.java
index 37996c5..9a63f1f 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTranscodeActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTranscodeActivity.java
@@ -158,9 +158,7 @@ private void doTranscode(boolean isReverse) {
int transcodingWidth = Integer.parseInt(mTranscodingWidthEditText.getText().toString());
int transcodingHeight = Integer.parseInt(mTranscodingHeightEditText.getText().toString());
- mProcessingDialog.show();
-
- mShortVideoTranscoder.transcode(
+ boolean startResult = mShortVideoTranscoder.transcode(
transcodingWidth, transcodingHeight,
RecordSettings.ENCODING_BITRATE_LEVEL_ARRAY[transcodingBitrateLevel],
RecordSettings.ROTATION_LEVEL_ARRAY[transcodingRotationLevel],
@@ -209,6 +207,12 @@ public void run() {
});
}
});
+
+ if (startResult) {
+ mProcessingDialog.show();
+ } else {
+ ToastUtils.s(this, "开始转码失败!");
+ }
}
private void showChooseDialog(final String filePath) {
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTrimActivity.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTrimActivity.java
index 5c7f3e1..558f541 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTrimActivity.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/activity/VideoTrimActivity.java
@@ -38,8 +38,6 @@
import java.util.Locale;
import java.util.concurrent.TimeUnit;
-import static com.qiniu.pili.droid.shortvideo.PLErrorCode.ERROR_MULTI_CODEC_WRONG;
-
public class VideoTrimActivity extends Activity {
private static final String TAG = "VideoTrimActivity";
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition0.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition0.java
new file mode 100644
index 0000000..e573906
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition0.java
@@ -0,0 +1,57 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition0 extends TransitionBase {
+ public Transition0(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mTitle.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ private void initTransitions() {
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitle, fadeTransition);
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mTitle.getX(), (int) mTitle.getY(), (int) mTitle.getX(), (int) mTitle.getY() - mTitle.getHeight());
+ mTransitionMaker.addTransition(mTitle, positionTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ private void initPosition() {
+ int titleX = mWidth / 2 - mTitle.getWidth() / 2;
+ int titleY = mHeight / 2 + mTitle.getHeight() / 2;
+ mTitle.setTranslationX(titleX);
+ mTitle.setTranslationY(titleY);
+ }
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText("七月与安生");
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.WHITE);
+ mTitle.setTextSize(26);
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition1.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition1.java
new file mode 100644
index 0000000..f7bd0c4
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition1.java
@@ -0,0 +1,79 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition1 extends TransitionBase {
+ public Transition1(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ public void init() {
+ mTransitionMaker.setDuration(DURATION);
+ mTransitionMaker.setBackgroundColor(Color.BLACK);
+
+ initViews();
+ initPosAndTrans();
+ }
+
+ @Override
+ public void updateTransitions() {
+ mTransitionMaker.removeAllResource();
+ addViews();
+ initPosAndTrans();
+ }
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText("CHAPTER");
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.parseColor("#FFCC99"));
+ mTitle.setTextSize(14);
+
+ mSubtitle = new TransitionTextView(mContext);
+ mSubtitle.setText("第一章 七年");
+ mSubtitle.setPadding(0, 0, 0, 0);
+ mSubtitle.setTextColor(Color.WHITE);
+ mSubtitle.setTextSize(20);
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mSubtitle.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ private void initTransitions() {
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitle, fadeTransition);
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mSubtitle.getX(), (int) mSubtitle.getY(), (int) mSubtitle.getX() - mSubtitle.getWidth(), (int) mSubtitle.getY());
+ mTransitionMaker.addTransition(mSubtitle, positionTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ private void initPosition() {
+ mTitle.setTranslationX(mWidth - mTitle.getWidth());
+ mTitle.setTranslationY(mHeight / 2 - mTitle.getHeight());
+
+ mSubtitle.setTranslationX(mWidth);
+ mSubtitle.setTranslationY(mTitle.getY() + mTitle.getHeight());
+ }
+}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition2.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition2.java
new file mode 100644
index 0000000..4ef08d1
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition2.java
@@ -0,0 +1,78 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLImageView;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition2 extends TransitionBase {
+ private PLImageView mImageView;
+
+ public Transition2(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mImageView.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText("第二章 暖暖");
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.WHITE);
+ mTitle.setTextSize(22);
+
+ mImageView = new PLImageView(mContext);
+ mImageView.setImageDrawable(mContext.getResources().getDrawable(R.drawable.pink_line));
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+
+ private void initPosition() {
+ int titleY = mHeight / 2 - mTitle.getHeight();
+ mTitle.setTranslationX(0);
+ mTitle.setTranslationY(titleY);
+
+ mImageView.setTranslationY(mHeight / 2 - mTitle.getHeight() - mImageView.getHeight());
+ mImageView.setTranslationX(0);
+ }
+
+ private void initTransitions() {
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mImageView, fadeTransition);
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, -mTitle.getWidth(), (int) mTitle.getY(), (int) mTitle.getX(), (int) mTitle.getY());
+ mTransitionMaker.addTransition(mTitle, positionTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ @Override
+ protected void addViews() {
+ super.addViews();
+ mTransitionMaker.addImage(mImageView);
+ }
+
+ @Override
+ protected void setViewsVisible(int visible) {
+ super.setViewsVisible(visible);
+ mImageView.setVisibility(visible);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition3.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition3.java
new file mode 100644
index 0000000..6c38207
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition3.java
@@ -0,0 +1,88 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLImageView;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition3 extends TransitionBase {
+ private static final int MOVE_DISTANCE = 100;
+
+ private static final String TEXT_DISPLAY = "村上春树1949年1月12日出生在日本京都市伏见区,为国语教师村上千秋、村上美幸夫妇的长子。出生不久,家迁至兵库县西宫市夙川。村上春树1949年1月12日出生在日本京都市伏见区,为国语教师村上千秋、村上美幸夫妇的长子。出生不久,家迁至兵库县西宫市夙川。";
+
+ private PLImageView mImageView;
+
+ public Transition3(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mImageView.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText(TEXT_DISPLAY);
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.parseColor("#339900"));
+ mTitle.setTextSize(16);
+
+ mImageView = new PLImageView(mContext);
+ mImageView.setImageDrawable(mContext.getResources().getDrawable(R.drawable.green_quot));
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+
+ private void initTransitions() {
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mTitle.getX(), (int) mTitle.getY(), (int) mTitle.getX(), (int) mTitle.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mTitle, positionTransition);
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitle, fadeTransition);
+
+ positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mImageView.getX(), (int) mImageView.getY(), (int) mImageView.getX(), (int) mImageView.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mImageView, positionTransition);
+ fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mImageView, fadeTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ private void initPosition() {
+ int titleY = mHeight / 2 - mTitle.getHeight() / 2 + MOVE_DISTANCE;
+ mTitle.setTranslationX(0);
+ mTitle.setTranslationY(titleY);
+
+ int imageY = titleY - mImageView.getHeight();
+ mImageView.setTranslationY(imageY);
+ mImageView.setTranslationX(0);
+ }
+
+ @Override
+ protected void addViews() {
+ super.addViews();
+ mTransitionMaker.addImage(mImageView);
+ }
+
+ @Override
+ protected void setViewsVisible(int visible) {
+ super.setViewsVisible(visible);
+ mImageView.setVisibility(visible);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition4.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition4.java
new file mode 100644
index 0000000..889efc7
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition4.java
@@ -0,0 +1,75 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition4 extends TransitionBase {
+ private static final int MOVE_DISTANCE = 100;
+
+ public Transition4(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mSubtitle.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ private void initTransitions() {
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitle, fadeTransition);
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mTitle.getX(), (int) mTitle.getY(), (int) mTitle.getX(), (int) mTitle.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mTitle, positionTransition);
+
+ fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mSubtitle, fadeTransition);
+ positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mSubtitle.getX(), (int) mSubtitle.getY(), (int) mSubtitle.getX(), (int) mSubtitle.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mSubtitle, positionTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ private void initPosition() {
+ int titleX = mWidth / 2 - mTitle.getWidth() / 2;
+ int titleY = mHeight / 2 - mTitle.getHeight() + MOVE_DISTANCE;
+ mTitle.setTranslationX(titleX);
+ mTitle.setTranslationY(titleY);
+
+ int subtitleX = mWidth / 2 - mSubtitle.getWidth() / 2;
+ int subtitleY = titleY + mTitle.getHeight();
+ mSubtitle.setTranslationX(subtitleX);
+ mSubtitle.setTranslationY(subtitleY);
+ }
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText("挪威的森林");
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.WHITE);
+ mTitle.setTextSize(22);
+
+ mSubtitle = new TransitionTextView(mContext);
+ mSubtitle.setText("- 村上春树 -");
+ mSubtitle.setPadding(0, 0, 0, 0);
+ mSubtitle.setTextColor(Color.parseColor("#eed2b9"));
+ mSubtitle.setTextSize(15);
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition5.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition5.java
new file mode 100644
index 0000000..ee970dc
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/Transition5.java
@@ -0,0 +1,130 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLFadeTransition;
+import com.qiniu.pili.droid.shortvideo.PLPositionTransition;
+import com.qiniu.pili.droid.shortvideo.PLTextView;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class Transition5 extends TransitionBase {
+ private PLTextView mTitleTip;
+ private PLTextView mSubtitleTip;
+
+ private static final int MOVE_DISTANCE = 100;
+
+ public Transition5(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ super(viewGroup, setting);
+ }
+
+ @Override
+ protected void initPosAndTrans() {
+ //you should init positions and transitions in post runnable , because the view has been layout at that moment.
+ mSubtitle.post(new Runnable() {
+ @Override
+ public void run() {
+ initPosition();
+ initTransitions();
+ }
+ });
+ }
+
+ private void initTransitions() {
+ //title transitions
+ PLFadeTransition fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitle, fadeTransition);
+ PLPositionTransition positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mTitle.getX(), (int) mTitle.getY(), (int) mTitle.getX(), (int) mTitle.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mTitle, positionTransition);
+
+ //subtitle transitions
+ fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mSubtitle, fadeTransition);
+ positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mSubtitle.getX(), (int) mSubtitle.getY(), (int) mSubtitle.getX(), (int) mSubtitle.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mSubtitle, positionTransition);
+
+ //title tip transitions
+ fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mTitleTip, fadeTransition);
+ positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mTitleTip.getX(), (int) mTitleTip.getY(), (int) mTitleTip.getX(), (int) mTitleTip.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mTitleTip, positionTransition);
+
+ //subtitle tip transitions
+ fadeTransition = new PLFadeTransition(0, DURATION / 2, 0, 1);
+ mTransitionMaker.addTransition(mSubtitleTip, fadeTransition);
+ positionTransition = new PLPositionTransition(0, DURATION / 2, (int) mSubtitleTip.getX(), (int) mSubtitleTip.getY(), (int) mSubtitleTip.getX(), (int) mSubtitleTip.getY() - MOVE_DISTANCE);
+ mTransitionMaker.addTransition(mSubtitleTip, positionTransition);
+
+ mTransitionMaker.play();
+ setViewsVisible(View.VISIBLE);
+ }
+
+ private void initPosition() {
+ int titleX = mWidth / 2 - mTitle.getWidth() / 2;
+ int titleY = mHeight / 2 - mTitle.getHeight() + MOVE_DISTANCE;
+ mTitle.setTranslationX(titleX);
+ mTitle.setTranslationY(titleY);
+
+ int titleTipX = mWidth / 2 - mTitleTip.getWidth() / 2;
+ int titleTipY = titleY - mTitleTip.getHeight();
+ mTitleTip.setTranslationX(titleTipX);
+ mTitleTip.setTranslationY(titleTipY);
+
+ int subtitleTipX = mWidth / 2 - mSubtitleTip.getWidth() / 2;
+ int subtitleTipY = mHeight / 2 + MOVE_DISTANCE;
+ mSubtitleTip.setTranslationX(subtitleTipX);
+ mSubtitleTip.setTranslationY(subtitleTipY);
+
+ int subtitleX = mWidth / 2 - mSubtitle.getWidth() / 2;
+ int subtitleY = subtitleTipY + mSubtitleTip.getHeight();
+ mSubtitle.setTranslationX(subtitleX);
+ mSubtitle.setTranslationY(subtitleY);
+ }
+
+
+ @Override
+ protected void initViews() {
+ mTitle = new TransitionTextView(mContext);
+ mTitle.setText("七牛");
+ mTitle.setPadding(0, 0, 0, 0);
+ mTitle.setTextColor(Color.parseColor("#FFCC99"));
+ mTitle.setTextSize(16);
+
+ mTitleTip = new TransitionTextView(mContext);
+ mTitleTip.setText("DIRECTOR");
+ mTitleTip.setPadding(0, 0, 0, 0);
+ mTitleTip.setTextColor(Color.parseColor("#FFFFFF"));
+ mTitleTip.setTextSize(16);
+
+ mSubtitleTip = new TransitionTextView(mContext);
+ mSubtitleTip.setText("DATE&LOCATION");
+ mSubtitleTip.setPadding(0, 0, 0, 0);
+ mSubtitleTip.setTextColor(Color.parseColor("#FFFFFF"));
+ mSubtitleTip.setTextSize(16);
+
+ mSubtitle = new TransitionTextView(mContext);
+ mSubtitle.setText("2018.1.1 上海");
+ mSubtitle.setPadding(0, 0, 0, 0);
+ mSubtitle.setTextColor(Color.parseColor("#FFCC99"));
+ mSubtitle.setTextSize(16);
+
+ addViews();
+ setViewsVisible(View.INVISIBLE);
+ }
+
+ @Override
+ protected void addViews() {
+ super.addViews();
+ mTransitionMaker.addText(mTitleTip);
+ mTransitionMaker.addText(mSubtitleTip);
+ }
+
+ @Override
+ protected void setViewsVisible(int visible) {
+ super.setViewsVisible(visible);
+ mTitleTip.setVisibility(visible);
+ mSubtitleTip.setVisibility(visible);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/TransitionBase.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/TransitionBase.java
new file mode 100644
index 0000000..29e0df9
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/transition/TransitionBase.java
@@ -0,0 +1,102 @@
+package com.qiniu.pili.droid.shortvideo.demo.transition;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.ViewGroup;
+
+import com.qiniu.pili.droid.shortvideo.PLTransitionMaker;
+import com.qiniu.pili.droid.shortvideo.PLVideoEncodeSetting;
+import com.qiniu.pili.droid.shortvideo.PLVideoSaveListener;
+import com.qiniu.pili.droid.shortvideo.demo.view.TransitionTextView;
+
+public class TransitionBase {
+ protected static final int DURATION = 2500;
+
+ private ViewGroup mViewGroup;
+
+ protected PLTransitionMaker mTransitionMaker;
+ protected Context mContext;
+ protected TransitionTextView mTitle;
+ protected TransitionTextView mSubtitle;
+ protected int mWidth;
+ protected int mHeight;
+
+ public TransitionBase(ViewGroup viewGroup, PLVideoEncodeSetting setting) {
+ mViewGroup = viewGroup;
+ mContext = viewGroup.getContext();
+ mWidth = mViewGroup.getWidth();
+ mHeight = mViewGroup.getHeight();
+ mTransitionMaker = new PLTransitionMaker(mViewGroup, setting);
+ init();
+ }
+
+ public TransitionTextView getTitle() {
+ return mTitle;
+ }
+
+ public TransitionTextView getSubtitle() {
+ return mSubtitle;
+ }
+
+ public void init() {
+ mTransitionMaker.setDuration(DURATION);
+ mTransitionMaker.setBackgroundColor(Color.BLACK);
+
+ initViews();
+ initPosAndTrans();
+ }
+
+ public void save(String dstFilePath, PLVideoSaveListener saveListener) {
+ mTransitionMaker.save(dstFilePath, saveListener);
+ }
+
+ public void setVisibility(int visibility) {
+ mViewGroup.setVisibility(visibility);
+ }
+
+ public void play() {
+ mTransitionMaker.play();
+ }
+
+ public void stop() {
+ mTransitionMaker.stop();
+ }
+
+ public void destroy() {
+ mTransitionMaker.destroy();
+ }
+
+ public void cancelSave() {
+ mTransitionMaker.cancelSave();
+ }
+
+ public void updateTransitions() {
+ mTransitionMaker.removeAllResource();
+ addViews();
+ initPosAndTrans();
+ }
+
+ protected void initViews() {
+ }
+
+ protected void initPosAndTrans() {
+ }
+
+ protected void addViews() {
+ if (mTitle != null) {
+ mTransitionMaker.addText(mTitle);
+ }
+ if (mSubtitle != null) {
+ mTransitionMaker.addText(mSubtitle);
+ }
+ }
+
+ protected void setViewsVisible(int visible) {
+ if (mTitle != null) {
+ mTitle.setVisibility(visible);
+ }
+ if (mSubtitle != null) {
+ mSubtitle.setVisibility(visible);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/tusdk/TuSDKManager.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/tusdk/TuSDKManager.java
index e208537..6eba1c2 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/tusdk/TuSDKManager.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/tusdk/TuSDKManager.java
@@ -124,7 +124,7 @@ private TuSDKFilterEngine createFilterEngine() {
// 设置输入的图片朝向 如果输入的图片不是原始朝向 该选项必须配置
filterEngine.setInputImageOrientation(ImageOrientation.DownMirrored);
// 设置是否开启动态贴纸功能
- filterEngine.setEnableLiveSticker(true);
+ filterEngine.setEnableLiveSticker(false);
return filterEngine;
}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/utils/Config.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/utils/Config.java
index b4ddda0..4f0baea 100644
--- a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/utils/Config.java
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/utils/Config.java
@@ -19,4 +19,5 @@ public class Config {
public static final String SCREEN_RECORD_FILE_PATH = VIDEO_STORAGE_DIR + "screen_record.mp4";
public static final String COMPOSE_FILE_PATH = VIDEO_STORAGE_DIR + "composed.mp4";
public static final String IMAGE_COMPOSE_FILE_PATH = VIDEO_STORAGE_DIR + "image_composed.mp4";
+ public static final String VIDEO_DIVIDE_FILE_PATH = VIDEO_STORAGE_DIR + "divide_composed.mp4";
}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/DragItemAdapter.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/DragItemAdapter.java
new file mode 100644
index 0000000..1348dbf
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/DragItemAdapter.java
@@ -0,0 +1,142 @@
+package com.qiniu.pili.droid.shortvideo.demo.view;
+
+import android.graphics.Bitmap;
+import android.media.ThumbnailUtils;
+import android.provider.MediaStore;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
+import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
+import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableItemViewHolder;
+import com.qiniu.pili.droid.shortvideo.demo.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.media.ThumbnailUtils.OPTIONS_RECYCLE_INPUT;
+
+public class DragItemAdapter extends RecyclerView.Adapter
+ implements DraggableItemAdapter {
+
+ public interface OnItemMovedListener {
+ void onMoveItem(int fromPosition, int toPosition);
+ }
+
+ private List mItemList;
+ private OnItemMovedListener mOnItemMovedListener;
+
+ public DragItemAdapter(ArrayList paths) {
+ setHasStableIds(true);
+
+ mItemList = new ArrayList<>();
+ for (int i = 0; i < paths.size(); i++) {
+ mItemList.add(new FrameItem(i, paths.get(i)));
+ }
+ }
+
+ public void updatePaths(ArrayList paths) {
+ mItemList.clear();
+ for (int i = 0; i < paths.size(); i++) {
+ mItemList.add(new FrameItem(i, paths.get(i)));
+ }
+ }
+
+ public void setOnItemMovedListener(OnItemMovedListener onItemMovedListener) {
+ mOnItemMovedListener = onItemMovedListener;
+ }
+
+ @Override
+ public FrameItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ final View v = inflater.inflate(R.layout.item_image, parent, false);
+ return new FrameItemViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(final FrameItemViewHolder holder, int position) {
+ FrameItem item = mItemList.get(position);
+ final String filepath = item.mPath;
+
+ Bitmap bitmap = (item.mBitmap == null) ? getVideoThumbnail(filepath) : item.mBitmap;
+ if (bitmap != null) {
+ holder.mImageView.setImageBitmap(bitmap);
+ }
+ item.mBitmap = bitmap;
+ }
+
+ private Bitmap getVideoThumbnail(String videoPath) {
+ Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.FULL_SCREEN_KIND);
+ if (bitmap != null) {
+ return ThumbnailUtils.extractThumbnail(bitmap, 250, 250, OPTIONS_RECYCLE_INPUT);
+ }
+ return null;
+ }
+
+ public class FrameItemViewHolder extends AbstractDraggableItemViewHolder {
+ ImageView mImageView;
+
+ public FrameItemViewHolder(View v) {
+ super(v);
+ mImageView = (ImageView) v.findViewById(R.id.ImageThumbnail);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // requires static value, it means need to keep the same value
+ // even if the item position has been changed.
+ return mItemList.get(position).mID;
+ }
+
+
+ @Override
+ public int getItemCount() {
+ return mItemList.size();
+ }
+
+ @Override
+ public boolean onCheckCanStartDrag(FrameItemViewHolder holder, int position, int x, int y) {
+ View dragHandle = holder.mImageView;
+ int handleWidth = dragHandle.getWidth();
+ int handleHeight = dragHandle.getHeight();
+ int handleLeft = dragHandle.getLeft();
+ int handleTop = dragHandle.getTop();
+
+ return (x >= handleLeft) && (x < handleLeft + handleWidth) &&
+ (y >= handleTop) && (y < handleTop + handleHeight);
+ }
+
+ @Override
+ public ItemDraggableRange onGetItemDraggableRange(FrameItemViewHolder holder, int position) {
+ return null;
+ }
+
+ @Override
+ public void onMoveItem(int fromPosition, int toPosition) {
+ FrameItem movedItem = mItemList.remove(fromPosition);
+ mItemList.add(toPosition, movedItem);
+ if (mOnItemMovedListener != null) {
+ mOnItemMovedListener.onMoveItem(fromPosition, toPosition);
+ }
+ }
+
+ @Override
+ public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
+ return true;
+ }
+
+ static class FrameItem {
+ final long mID;
+ final String mPath;
+ Bitmap mBitmap;
+
+ public FrameItem(long id, String text) {
+ this.mID = id;
+ this.mPath = text;
+ }
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/FrameSelectorView.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/FrameSelectorView.java
new file mode 100644
index 0000000..62319f4
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/FrameSelectorView.java
@@ -0,0 +1,131 @@
+package com.qiniu.pili.droid.shortvideo.demo.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import com.qiniu.pili.droid.shortvideo.demo.R;
+
+public class FrameSelectorView extends RelativeLayout {
+ private ImageView mHandlerLeft;
+ private ImageView mHandlerRight;
+ private View mHandlerBody;
+ private FrameLayout.LayoutParams mGroupLayoutParam;
+
+ private float mOriginX;
+ private int mOriginWidth;
+ private ViewGroup.LayoutParams mOriginParam;
+ private int mOriginLeftMargin;
+
+ private boolean mIsTouching;
+
+ public FrameSelectorView(Context context) {
+ this(context, null);
+ }
+
+ public FrameSelectorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ View view = LayoutInflater.from(context).inflate(R.layout.frame_selector_view, this);
+
+ mHandlerLeft = (ImageView) view.findViewById(R.id.handler_left);
+ mHandlerRight = (ImageView) view.findViewById(R.id.handler_right);
+ mHandlerBody = view.findViewById(R.id.handler_body);
+
+ mHandlerLeft.setOnTouchListener(new HandlerLeftTouchListener());
+ mHandlerRight.setOnTouchListener(new HandlerRightTouchListener());
+ mHandlerBody.setOnTouchListener(new HandlerBodyTouchListener());
+
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mGroupLayoutParam = (FrameLayout.LayoutParams) getLayoutParams();
+ }
+ });
+ }
+
+ private class HandlerLeftTouchListener implements OnTouchListener {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mIsTouching) {
+ return false;
+ }
+ mOriginX = event.getRawX();
+ mOriginWidth = mHandlerBody.getWidth();
+ mOriginParam = mHandlerBody.getLayoutParams();
+ mOriginLeftMargin = mGroupLayoutParam.leftMargin;
+ mIsTouching = true;
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ int delta = (int) (event.getRawX() - mOriginX);
+ mOriginParam.width = mOriginWidth - delta;
+ mHandlerBody.setLayoutParams(mOriginParam);
+ mGroupLayoutParam.leftMargin = mOriginLeftMargin + delta;
+ setLayoutParams(mGroupLayoutParam);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mIsTouching = false;
+ }
+ return true;
+ }
+ }
+
+ private class HandlerRightTouchListener implements OnTouchListener {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mIsTouching) {
+ return false;
+ }
+ mOriginX = event.getRawX();
+ mOriginWidth = mHandlerBody.getWidth();
+ mOriginParam = mHandlerBody.getLayoutParams();
+ mIsTouching = true;
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ int delta = (int) (event.getRawX() - mOriginX);
+ mOriginParam.width = mOriginWidth + delta;
+ mHandlerBody.setLayoutParams(mOriginParam);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mIsTouching = false;
+ }
+ return true;
+ }
+ }
+
+ private class HandlerBodyTouchListener implements OnTouchListener {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mIsTouching) {
+ return false;
+ }
+ mOriginX = event.getRawX();
+ mOriginLeftMargin = mGroupLayoutParam.leftMargin;
+ mIsTouching = true;
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ int delta = (int) (event.getRawX() - mOriginX);
+ mGroupLayoutParam.leftMargin = mOriginLeftMargin + delta;
+ setLayoutParams(mGroupLayoutParam);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mIsTouching = false;
+ }
+ return true;
+ }
+ }
+
+ public int getBodyLeft() {
+ return mGroupLayoutParam.leftMargin + mHandlerLeft.getWidth();
+ }
+
+ public int getBodyWidth() {
+ return mHandlerBody.getWidth();
+ }
+
+ public int getBodyRight() {
+ return getBodyLeft() + mHandlerBody.getWidth();
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/ObservableHorizontalScrollView.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/ObservableHorizontalScrollView.java
new file mode 100644
index 0000000..e233aa7
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/ObservableHorizontalScrollView.java
@@ -0,0 +1,79 @@
+package com.qiniu.pili.droid.shortvideo.demo.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.HorizontalScrollView;
+
+public class ObservableHorizontalScrollView extends HorizontalScrollView {
+ public interface OnScrollListener {
+ void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY, boolean dragScroll);
+ }
+
+ private boolean mIsScrolling;
+ private boolean mIsTouching;
+ private boolean mIsDragScroll;
+ private Runnable mScrollingRunnable;
+ private OnScrollListener mOnScrollListener;
+
+ public ObservableHorizontalScrollView(Context context) {
+ this(context, null, 0);
+ }
+
+ public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ int action = ev.getAction();
+
+ if (action == MotionEvent.ACTION_MOVE) {
+ mIsTouching = true;
+ mIsScrolling = true;
+ mIsDragScroll = true;
+ } else if (action == MotionEvent.ACTION_UP) {
+ mIsTouching = false;
+ }
+
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
+ super.onScrollChanged(x, y, oldX, oldY);
+
+ if (Math.abs(oldX - x) > 0) {
+ if (mScrollingRunnable != null) {
+ removeCallbacks(mScrollingRunnable);
+ }
+
+ mScrollingRunnable = new Runnable() {
+ public void run() {
+ if (mIsScrolling && !mIsTouching) {
+ if (mOnScrollListener != null) {
+ mIsDragScroll = false;
+ }
+ }
+ mIsScrolling = false;
+ mScrollingRunnable = null;
+ }
+ };
+ postDelayed(mScrollingRunnable, 200);
+ } else {
+ mIsDragScroll = false;
+ }
+
+ if (mOnScrollListener != null) {
+ mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY, mIsDragScroll);
+ }
+ }
+
+ public void setOnScrollListener(OnScrollListener onScrollListener) {
+ this.mOnScrollListener = onScrollListener;
+ }
+}
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionEditView.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionEditView.java
new file mode 100644
index 0000000..35524b0
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionEditView.java
@@ -0,0 +1,241 @@
+package com.qiniu.pili.droid.shortvideo.demo.view;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.NumberPicker;
+import android.widget.TextView;
+
+import com.qiniu.pili.droid.shortvideo.demo.R;
+import com.qiniu.pili.droid.shortvideo.demo.transition.TransitionBase;
+import com.qiniu.pili.droid.shortvideo.demo.utils.ToastUtils;
+
+public class TransitionEditView extends LinearLayout {
+ public static final String[] TEXT_COLOR_TIPS_ARRAY = {
+ "#FFFFFF", "#FF3D49", "#FFEE00", "#578BFF", "#00C6FF", "#EACFD4", "#F8EADA", "#CEFFC6", "#C3CADA", "#000000"
+ };
+ public static final String[] TEXT_SIZE_TIPS_ARRAY = {
+ "46", "50", "54", "58", "62", "66", "70", "74", "78", "82", "86", "90"
+ };
+ public static final String[] TEXT_TYPEFFACE_TIPS_ARRAY = {
+ "Sans_Serif", "Default_Bold", "zcool-gdh", "HappyZcool-2016"
+ };
+
+ private TransitionBase mTransition;
+ private Button mBackBtn;
+ private EditText mTitleEditText;
+ private EditText mSubtitleEditText;
+
+ private TransitionTextView mTransitionTitle;
+ private TransitionTextView mTransitionSubtitle;
+ private EditText mCurFocusText;
+ private NumberPicker mNumberPicker;
+ private ViewGroup mNumberPickerGroup;
+ private TextView mConfirmText;
+
+ private Typeface[] mTypefaces;
+
+ private ViewGroup mColorGroup;
+ private ViewGroup mSizeGroup;
+ private ViewGroup mTypefaceGroup;
+
+ private Context mContext;
+
+ public TransitionEditView(Context context) {
+ this(context, null);
+ }
+
+ public TransitionEditView(final Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ View view = LayoutInflater.from(context).inflate(R.layout.transition_edit_view, this);
+ mBackBtn = (Button) view.findViewById(R.id.back_button);
+ mTitleEditText = (EditText) view.findViewById(R.id.title_edit_text);
+ mSubtitleEditText = (EditText) view.findViewById(R.id.subtitle_edit_text);
+ mNumberPicker = (NumberPicker) view.findViewById(R.id.number_picker);
+ mColorGroup = (ViewGroup) view.findViewById(R.id.color_group);
+ mSizeGroup = (ViewGroup) view.findViewById(R.id.size_group);
+ mTypefaceGroup = (ViewGroup) view.findViewById(R.id.typeface_group);
+ mNumberPickerGroup = (ViewGroup) view.findViewById(R.id.number_picker_group);
+ mConfirmText = (TextView) view.findViewById(R.id.text_confirm);
+
+ mConfirmText.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mNumberPickerGroup.setVisibility(GONE);
+
+ if (mCurFocusText == mTitleEditText && null != mTransitionTitle) {
+ cloneEditText(mTransitionTitle, mCurFocusText);
+ }
+ if (mCurFocusText == mSubtitleEditText && null != mTransitionSubtitle) {
+ cloneEditText(mTransitionSubtitle, mCurFocusText);
+ }
+
+ mTransition.updateTransitions();
+ }
+ });
+
+ mColorGroup.setOnClickListener(mOnClickListener);
+ mSizeGroup.setOnClickListener(mOnClickListener);
+ mTypefaceGroup.setOnClickListener(mOnClickListener);
+ mTitleEditText.setOnFocusChangeListener(mOnFocusChangeListener);
+ mSubtitleEditText.setOnFocusChangeListener(mOnFocusChangeListener);
+
+ mBackBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hideSoftInput();
+ setVisibility(GONE);
+ }
+ });
+
+ initTypeFaces();
+ }
+
+ private void initTypeFaces() {
+ mTypefaces = new Typeface[4];
+ mTypefaces[0] = Typeface.SANS_SERIF;
+ mTypefaces[1] = Typeface.DEFAULT_BOLD;
+ mTypefaces[2] = Typeface.createFromAsset(mContext.getAssets(), "fonts/zcool-gdh.ttf");
+ mTypefaces[3] = Typeface.createFromAsset(mContext.getAssets(), "fonts/HappyZcool-2016.ttf");
+ }
+
+ private OnClickListener mOnClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showNumberPicker(v);
+ }
+ };
+
+ private void hideSoftInput() {
+ InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(mCurFocusText.getWindowToken(), 0);
+ }
+ }
+
+ private void showNumberPicker(final View view) {
+ if (null == mCurFocusText) {
+ ToastUtils.s(mContext, "请先选中需要修改的文字");
+ return;
+ }
+
+ hideSoftInput();
+
+ mNumberPickerGroup.setVisibility(VISIBLE);
+ String[] array;
+ switch (view.getId()) {
+ case R.id.color_group:
+ array = TEXT_COLOR_TIPS_ARRAY;
+ break;
+ case R.id.size_group:
+ array = TEXT_SIZE_TIPS_ARRAY;
+ break;
+ default:
+ array = TEXT_TYPEFFACE_TIPS_ARRAY;
+ break;
+ }
+ mNumberPicker.setDisplayedValues(null);
+ mNumberPicker.setMinValue(0);
+ mNumberPicker.setMaxValue(array.length - 1);
+ mNumberPicker.setDisplayedValues(array);
+ mNumberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+ @Override
+ public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+ switch (view.getId()) {
+ case R.id.color_group:
+ mCurFocusText.setTextColor(Color.parseColor(TEXT_COLOR_TIPS_ARRAY[newVal]));
+ break;
+ case R.id.size_group:
+ mCurFocusText.setTextSize(TypedValue.COMPLEX_UNIT_PX, Integer.parseInt(TEXT_SIZE_TIPS_ARRAY[newVal]));
+ break;
+ default:
+ mCurFocusText.setTypeface(mTypefaces[newVal]);
+ break;
+ }
+ }
+ });
+ }
+
+ private OnFocusChangeListener mOnFocusChangeListener = new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ mCurFocusText = (EditText) v;
+ }
+ }
+ };
+
+ public void setTransition(TransitionBase transition) {
+ mTransition = transition;
+ mTransitionTitle = mTransition.getTitle();
+ mTransitionSubtitle = mTransition.getSubtitle();
+
+ mTitleEditText.setVisibility(GONE);
+ mSubtitleEditText.setVisibility(GONE);
+
+ if (mTransitionTitle != null) {
+ mTitleEditText.setVisibility(VISIBLE);
+ mCurFocusText = mTitleEditText;
+ cloneEditText(mTitleEditText, mTransitionTitle);
+ mTitleEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (getVisibility() == View.VISIBLE) {
+ cloneEditText(mTransitionTitle, mTitleEditText);
+ mTransition.updateTransitions();
+ }
+ }
+ });
+ }
+
+ if (mTransitionSubtitle != null) {
+ mSubtitleEditText.setVisibility(VISIBLE);
+ cloneEditText(mSubtitleEditText, mTransitionSubtitle);
+ mSubtitleEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (getVisibility() == View.VISIBLE) {
+ cloneEditText(mTransitionSubtitle, mSubtitleEditText);
+ mTransition.updateTransitions();
+ }
+ }
+ });
+ }
+ }
+
+ private void cloneEditText(EditText dstText, EditText srcText) {
+ dstText.setText(srcText.getText());
+ dstText.setTextColor(srcText.getTextColors());
+ dstText.setTypeface(srcText.getTypeface());
+ dstText.setTextSize(TypedValue.COMPLEX_UNIT_PX, srcText.getTextSize());
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionTextView.java b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionTextView.java
new file mode 100644
index 0000000..3a42341
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/java/com/qiniu/pili/droid/shortvideo/demo/view/TransitionTextView.java
@@ -0,0 +1,20 @@
+package com.qiniu.pili.droid.shortvideo.demo.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.qiniu.pili.droid.shortvideo.PLTextView;
+
+public class TransitionTextView extends PLTextView{
+ public TransitionTextView(Context context) {
+ this(context, null);
+ }
+
+ public TransitionTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setFocusable(false);
+ setFocusableInTouchMode(false);
+ setClickable(false);
+ setPadding(0, 0, 0, 0);
+ }
+}
diff --git a/PLDroidShortVideoDemo/app/src/main/jniLibs/armeabi-v7a/libpldroid_beauty.so b/PLDroidShortVideoDemo/app/src/main/jniLibs/armeabi-v7a/libpldroid_beauty.so
index f4b9d07..5e65e6a 100755
Binary files a/PLDroidShortVideoDemo/app/src/main/jniLibs/armeabi-v7a/libpldroid_beauty.so and b/PLDroidShortVideoDemo/app/src/main/jniLibs/armeabi-v7a/libpldroid_beauty.so differ
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/green_quot.png b/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/green_quot.png
new file mode 100644
index 0000000..685bee8
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/green_quot.png differ
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/pink_line.png b/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/pink_line.png
new file mode 100644
index 0000000..30f4936
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/res/drawable-xhdpi/pink_line.png differ
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_body.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_body.xml
new file mode 100644
index 0000000..ed921b8
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_body.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_left.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_left.xml
new file mode 100644
index 0000000..21139b8
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_left.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_middle_line.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_middle_line.xml
new file mode 100644
index 0000000..f2be314
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_middle_line.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_rect.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_rect.xml
new file mode 100644
index 0000000..f53780d
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_rect.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_right.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_right.xml
new file mode 100644
index 0000000..2929c04
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/frame_selector_right.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/drawable/shape_transition_selector.xml b/PLDroidShortVideoDemo/app/src/main/res/drawable/shape_transition_selector.xml
new file mode 100644
index 0000000..e9a2390
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/drawable/shape_transition_selector.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/activity_main.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_main.xml
index f6740c0..019116c 100644
--- a/PLDroidShortVideoDemo/app/src/main/res/layout/activity_main.xml
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_main.xml
@@ -89,6 +89,14 @@
android:onClick="onClickDraftBox"
android:text="@string/title_from_draft_box" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_divide.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_divide.xml
new file mode 100644
index 0000000..b274a38
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_divide.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_frame.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_frame.xml
new file mode 100644
index 0000000..6383bb3
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/activity_video_frame.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/frame_selector_view.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/frame_selector_view.xml
new file mode 100644
index 0000000..cb8e95b
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/frame_selector_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/item_devide_frame.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/item_devide_frame.xml
new file mode 100644
index 0000000..9367e9c
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/item_devide_frame.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/item_transition_selector.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/item_transition_selector.xml
new file mode 100644
index 0000000..722d203
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/item_transition_selector.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/PLDroidShortVideoDemo/app/src/main/res/layout/transition_edit_view.xml b/PLDroidShortVideoDemo/app/src/main/res/layout/transition_edit_view.xml
new file mode 100644
index 0000000..b7528ad
--- /dev/null
+++ b/PLDroidShortVideoDemo/app/src/main/res/layout/transition_edit_view.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_left.png b/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_left.png
new file mode 100644
index 0000000..cbd5195
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_left.png differ
diff --git a/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_right.png b/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_right.png
new file mode 100644
index 0000000..b1016ed
Binary files /dev/null and b/PLDroidShortVideoDemo/app/src/main/res/mipmap-hdpi/frame_selector_right.png differ
diff --git a/PLDroidShortVideoDemo/app/src/main/res/values/colors.xml b/PLDroidShortVideoDemo/app/src/main/res/values/colors.xml
index 2edd744..76c6aa6 100644
--- a/PLDroidShortVideoDemo/app/src/main/res/values/colors.xml
+++ b/PLDroidShortVideoDemo/app/src/main/res/values/colors.xml
@@ -43,4 +43,10 @@
#ffdddddd
#2d2b39
+ #575558
+ #80575558
+ #ffffff
+ #8061dcff
+ #222222
+ #1a1a1a
diff --git a/PLDroidShortVideoDemo/app/src/main/res/values/strings.xml b/PLDroidShortVideoDemo/app/src/main/res/values/strings.xml
index a117d28..0a87736 100644
--- a/PLDroidShortVideoDemo/app/src/main/res/values/strings.xml
+++ b/PLDroidShortVideoDemo/app/src/main/res/values/strings.xml
@@ -25,6 +25,8 @@
AR 特效
草稿箱
草稿列表
+ 视频分割
+ 过场字幕
输入草稿标题
保存
@@ -56,4 +58,12 @@
快"
极快"
+ 编辑"
+ 确定"
+ 双击片段可以删除"
+ 剪一段"
+ 添加视频"
+ 长按缩略图排序"
+ 视频合成"
+ 添加过场字幕"
diff --git a/README.md b/README.md
index bb175cb..540d0dd 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,7 @@ PLDroidShortVideo 是七牛推出的一款适用于 Android 平台的短视频 S
| 多个视频拼接 | 1.5.0(+) |
| 制作 GIF 封面 | 1.3.0(+) |
| 图片合成 MP4 | 1.6.0(+) |
+| 制作过场字幕 | 1.10.0(+) |
### 1.2.5 视频转码
diff --git a/ReleaseNotes/release-notes-1.10.0.md b/ReleaseNotes/release-notes-1.10.0.md
new file mode 100644
index 0000000..81b7465
--- /dev/null
+++ b/ReleaseNotes/release-notes-1.10.0.md
@@ -0,0 +1,18 @@
+# PLDroidShortVideo Release Notes for 1.10.0
+
+### 简介
+PLDroidShortVideo 是七牛推出的一款适用于 Android 平台的短视频 SDK,提供了包括美颜、滤镜、水印、断点录制、分段回删、视频编辑、混音特效、本地/云端存储在内的多种功能,支持高度定制以及二次开发。
+
+### 版本
+* 发布 pldroid-shortvideo-1.10.0.jar
+* 更新 libpldroid_beauty.so
+
+### 功能
+* 新增制作过场字幕功能
+* 新增视频分段功能
+* PLShortAudioRecorder 和 PLShortVideoRecorder 中新增 deleteAllSections() 接口,用于删除所有录制的片段
+* 支持导入 H.265 的 mp4 进行编辑处理
+
+### 缺陷
+* 修复录制不调用 PLShortVideoRecorder.setRecordSpeed 导致回调的时间错误
+* 修复上传类不设置回调进度监听会发生崩溃的问题
\ No newline at end of file
diff --git a/releases/arm64-v8a/libpldroid_beauty.so b/releases/arm64-v8a/libpldroid_beauty.so
index 121d85b..53819c7 100755
Binary files a/releases/arm64-v8a/libpldroid_beauty.so and b/releases/arm64-v8a/libpldroid_beauty.so differ
diff --git a/releases/armeabi-v7a/libpldroid_beauty.so b/releases/armeabi-v7a/libpldroid_beauty.so
index 23b3c74..5e65e6a 100755
Binary files a/releases/armeabi-v7a/libpldroid_beauty.so and b/releases/armeabi-v7a/libpldroid_beauty.so differ
diff --git a/releases/armeabi/libpldroid_beauty.so b/releases/armeabi/libpldroid_beauty.so
index 70bd29a..64945b7 100755
Binary files a/releases/armeabi/libpldroid_beauty.so and b/releases/armeabi/libpldroid_beauty.so differ
diff --git a/releases/pldroid-shortvideo-1.10.0.jar b/releases/pldroid-shortvideo-1.10.0.jar
new file mode 100644
index 0000000..d0ef0d7
Binary files /dev/null and b/releases/pldroid-shortvideo-1.10.0.jar differ
diff --git a/releases/pldroid-shortvideo-1.9.0.jar b/releases/pldroid-shortvideo-1.9.0.jar
deleted file mode 100644
index df6915f..0000000
Binary files a/releases/pldroid-shortvideo-1.9.0.jar and /dev/null differ
diff --git a/releases/x86/libpldroid_beauty.so b/releases/x86/libpldroid_beauty.so
index 74cd1a5..02d6688 100755
Binary files a/releases/x86/libpldroid_beauty.so and b/releases/x86/libpldroid_beauty.so differ