parent
48f8bd8018
commit
d506d87487
@ -1,217 +0,0 @@ |
||||
package com.frank.ffmpeg.view; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.SurfaceTexture; |
||||
import android.text.TextUtils; |
||||
import android.util.AttributeSet; |
||||
import android.util.Log; |
||||
import android.view.LayoutInflater; |
||||
import android.view.Surface; |
||||
import android.view.TextureView; |
||||
import android.view.View; |
||||
import android.widget.RelativeLayout; |
||||
import android.widget.SeekBar; |
||||
import android.widget.TextView; |
||||
|
||||
import com.frank.ffmpeg.R; |
||||
import com.frank.ffmpeg.hardware.HardwareDecode; |
||||
import com.frank.ffmpeg.util.ScreenUtil; |
||||
import com.frank.ffmpeg.util.TimeUtil; |
||||
|
||||
/** |
||||
* the custom view of preview SeekBar |
||||
* Created by frank on 2019/11/16. |
||||
*/ |
||||
|
||||
public class VideoPreviewBar extends RelativeLayout implements HardwareDecode.OnDataCallback { |
||||
|
||||
private final static String TAG = VideoPreviewBar.class.getSimpleName(); |
||||
|
||||
private TextureView texturePreView; |
||||
|
||||
private SeekBar previewBar; |
||||
|
||||
private TextView txtVideoProgress; |
||||
|
||||
private TextView txtVideoDuration; |
||||
|
||||
private HardwareDecode hardwareDecode; |
||||
|
||||
private PreviewBarCallback mPreviewBarCallback; |
||||
|
||||
private int duration; |
||||
|
||||
private int screenWidth; |
||||
|
||||
private int moveEndPos = 0; |
||||
|
||||
private int previewHalfWidth; |
||||
|
||||
public VideoPreviewBar(Context context) { |
||||
super(context); |
||||
initView(context); |
||||
} |
||||
|
||||
public VideoPreviewBar(Context context, AttributeSet attributeSet) { |
||||
super(context, attributeSet); |
||||
initView(context); |
||||
} |
||||
|
||||
private void initView(Context context) { |
||||
View view = LayoutInflater.from(context).inflate(R.layout.preview_video, this); |
||||
previewBar = view.findViewById(R.id.preview_bar); |
||||
texturePreView = view.findViewById(R.id.texture_preview); |
||||
txtVideoProgress = view.findViewById(R.id.txt_video_progress); |
||||
txtVideoDuration = view.findViewById(R.id.txt_video_duration); |
||||
setListener(); |
||||
screenWidth = ScreenUtil.INSTANCE.getScreenWidth(context); |
||||
} |
||||
|
||||
@Override |
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) { |
||||
super.onLayout(changed, l, t, r, b); |
||||
if (moveEndPos == 0) { |
||||
int previewWidth = texturePreView.getWidth(); |
||||
previewHalfWidth = previewWidth / 2; |
||||
int marginEnd = 0; |
||||
MarginLayoutParams layoutParams = (MarginLayoutParams) texturePreView.getLayoutParams(); |
||||
if (layoutParams != null) { |
||||
marginEnd = layoutParams.getMarginEnd(); |
||||
} |
||||
moveEndPos = screenWidth - previewWidth - marginEnd; |
||||
Log.i(TAG, "previewWidth=" + previewWidth); |
||||
} |
||||
} |
||||
|
||||
private void setPreviewCallback(final String filePath, TextureView texturePreView) { |
||||
texturePreView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { |
||||
@Override |
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { |
||||
doPreview(filePath, new Surface(surface)); |
||||
} |
||||
|
||||
@Override |
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) { |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void doPreview(String filePath, Surface surface) { |
||||
if (surface == null || TextUtils.isEmpty(filePath)) { |
||||
return; |
||||
} |
||||
release(); |
||||
hardwareDecode = new HardwareDecode(surface, filePath, this); |
||||
hardwareDecode.decode(); |
||||
} |
||||
|
||||
private void setListener() { |
||||
previewBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { |
||||
@Override |
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { |
||||
if (!fromUser) { |
||||
return; |
||||
} |
||||
previewBar.setProgress(progress); |
||||
if (hardwareDecode != null && progress < duration) { |
||||
// us to ms
|
||||
hardwareDecode.seekTo(progress * 1000); |
||||
} |
||||
int percent = progress * screenWidth / duration; |
||||
if (percent > previewHalfWidth && percent < moveEndPos && texturePreView != null) { |
||||
texturePreView.setTranslationX(percent - previewHalfWidth); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStartTrackingTouch(SeekBar seekBar) { |
||||
if (texturePreView != null) { |
||||
texturePreView.setVisibility(VISIBLE); |
||||
} |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode.setPreviewing(true); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStopTrackingTouch(SeekBar seekBar) { |
||||
if (texturePreView != null) { |
||||
texturePreView.setVisibility(GONE); |
||||
} |
||||
if (mPreviewBarCallback != null) { |
||||
mPreviewBarCallback.onStopTracking(seekBar.getProgress()); |
||||
} |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode.setPreviewing(false); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void onData(long duration) { |
||||
//us to ms
|
||||
final int durationMs = (int) (duration / 1000); |
||||
Log.i(TAG, "duration=" + duration); |
||||
this.duration = durationMs; |
||||
post(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
previewBar.setMax(durationMs); |
||||
txtVideoDuration.setText(TimeUtil.INSTANCE.getVideoTime(durationMs)); |
||||
texturePreView.setVisibility(GONE); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void checkArgument(String videoPath) { |
||||
if (texturePreView == null) { |
||||
throw new IllegalStateException("Must init TextureView first..."); |
||||
} |
||||
if (videoPath == null || videoPath.isEmpty()) { |
||||
throw new IllegalStateException("videoPath is empty..."); |
||||
} |
||||
} |
||||
|
||||
public void init(String videoPath, PreviewBarCallback previewBarCallback) { |
||||
checkArgument(videoPath); |
||||
this.mPreviewBarCallback = previewBarCallback; |
||||
doPreview(videoPath, new Surface(texturePreView.getSurfaceTexture())); |
||||
} |
||||
|
||||
public void initDefault(String videoPath, PreviewBarCallback previewBarCallback) { |
||||
checkArgument(videoPath); |
||||
this.mPreviewBarCallback = previewBarCallback; |
||||
setPreviewCallback(videoPath, texturePreView); |
||||
} |
||||
|
||||
public void updateProgress(int progress) { |
||||
if (progress >= 0 && progress <= duration) { |
||||
txtVideoProgress.setText(TimeUtil.INSTANCE.getVideoTime(progress)); |
||||
previewBar.setProgress(progress); |
||||
} |
||||
} |
||||
|
||||
public void release() { |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode.release(); |
||||
hardwareDecode = null; |
||||
} |
||||
} |
||||
|
||||
public interface PreviewBarCallback { |
||||
void onStopTracking(long progress); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,197 @@ |
||||
package com.frank.ffmpeg.view |
||||
|
||||
import android.content.Context |
||||
import android.graphics.SurfaceTexture |
||||
import android.text.TextUtils |
||||
import android.util.AttributeSet |
||||
import android.util.Log |
||||
import android.view.* |
||||
import android.widget.RelativeLayout |
||||
import android.widget.SeekBar |
||||
import android.widget.TextView |
||||
|
||||
import com.frank.ffmpeg.R |
||||
import com.frank.ffmpeg.hardware.HardwareDecode |
||||
import com.frank.ffmpeg.util.ScreenUtil |
||||
import com.frank.ffmpeg.util.TimeUtil |
||||
|
||||
/** |
||||
* the custom view of preview SeekBar |
||||
* Created by frank on 2019/11/16. |
||||
*/ |
||||
|
||||
class VideoPreviewBar : RelativeLayout, HardwareDecode.OnDataCallback { |
||||
|
||||
private var texturePreView: TextureView? = null |
||||
|
||||
private var previewBar: SeekBar? = null |
||||
|
||||
private var txtVideoProgress: TextView? = null |
||||
|
||||
private var txtVideoDuration: TextView? = null |
||||
|
||||
private var hardwareDecode: HardwareDecode? = null |
||||
|
||||
private var mPreviewBarCallback: PreviewBarCallback? = null |
||||
|
||||
private var duration: Int = 0 |
||||
|
||||
private var screenWidth: Int = 0 |
||||
|
||||
private var moveEndPos = 0 |
||||
|
||||
private var previewHalfWidth: Int = 0 |
||||
|
||||
constructor(context: Context) : super(context) { |
||||
initView(context) |
||||
} |
||||
|
||||
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { |
||||
initView(context) |
||||
} |
||||
|
||||
private fun initView(context: Context) { |
||||
val view = LayoutInflater.from(context).inflate(R.layout.preview_video, this) |
||||
previewBar = view.findViewById(R.id.preview_bar) |
||||
texturePreView = view.findViewById(R.id.texture_preview) |
||||
txtVideoProgress = view.findViewById(R.id.txt_video_progress) |
||||
txtVideoDuration = view.findViewById(R.id.txt_video_duration) |
||||
setListener() |
||||
screenWidth = ScreenUtil.getScreenWidth(context) |
||||
} |
||||
|
||||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { |
||||
super.onLayout(changed, l, t, r, b) |
||||
if (moveEndPos == 0) { |
||||
val previewWidth = texturePreView!!.width |
||||
previewHalfWidth = previewWidth / 2 |
||||
val marginEnd: Int |
||||
val layoutParams = texturePreView!!.layoutParams as MarginLayoutParams |
||||
marginEnd = layoutParams.marginEnd |
||||
moveEndPos = screenWidth - previewWidth - marginEnd |
||||
Log.i(TAG, "previewWidth=$previewWidth") |
||||
} |
||||
} |
||||
|
||||
private fun setPreviewCallback(filePath: String, texturePreView: TextureView) { |
||||
texturePreView.surfaceTextureListener = object : TextureView.SurfaceTextureListener { |
||||
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { |
||||
doPreview(filePath, Surface(surface)) |
||||
} |
||||
|
||||
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) { |
||||
|
||||
} |
||||
|
||||
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { |
||||
return false |
||||
} |
||||
|
||||
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun doPreview(filePath: String, surface: Surface?) { |
||||
if (surface == null || TextUtils.isEmpty(filePath)) { |
||||
return |
||||
} |
||||
release() |
||||
hardwareDecode = HardwareDecode(surface, filePath, this) |
||||
hardwareDecode!!.decode() |
||||
} |
||||
|
||||
private fun setListener() { |
||||
previewBar!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { |
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { |
||||
if (!fromUser) { |
||||
return |
||||
} |
||||
previewBar!!.progress = progress |
||||
if (hardwareDecode != null && progress < duration) { |
||||
// us to ms |
||||
hardwareDecode!!.seekTo((progress * 1000).toLong()) |
||||
} |
||||
val percent = progress * screenWidth / duration |
||||
if (percent in (previewHalfWidth + 1) until moveEndPos && texturePreView != null) { |
||||
texturePreView!!.translationX = (percent - previewHalfWidth).toFloat() |
||||
} |
||||
} |
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) { |
||||
if (texturePreView != null) { |
||||
texturePreView!!.visibility = View.VISIBLE |
||||
} |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode!!.setPreviewing(true) |
||||
} |
||||
} |
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) { |
||||
if (texturePreView != null) { |
||||
texturePreView!!.visibility = View.GONE |
||||
} |
||||
if (mPreviewBarCallback != null) { |
||||
mPreviewBarCallback!!.onStopTracking(seekBar.progress.toLong()) |
||||
} |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode!!.setPreviewing(false) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
override fun onData(duration: Long) { |
||||
//us to ms |
||||
val durationMs = (duration / 1000).toInt() |
||||
Log.i(TAG, "duration=$duration") |
||||
this.duration = durationMs |
||||
post { |
||||
previewBar!!.max = durationMs |
||||
txtVideoDuration!!.text = TimeUtil.getVideoTime(durationMs.toLong()) |
||||
texturePreView!!.visibility = View.GONE |
||||
} |
||||
} |
||||
|
||||
private fun checkArgument(videoPath: String?) { |
||||
checkNotNull(texturePreView) { "Must init TextureView first..." } |
||||
check(!(videoPath == null || videoPath.isEmpty())) { "videoPath is empty..." } |
||||
} |
||||
|
||||
fun init(videoPath: String, previewBarCallback: PreviewBarCallback) { |
||||
checkArgument(videoPath) |
||||
this.mPreviewBarCallback = previewBarCallback |
||||
doPreview(videoPath, Surface(texturePreView!!.surfaceTexture)) |
||||
} |
||||
|
||||
fun initDefault(videoPath: String, previewBarCallback: PreviewBarCallback) { |
||||
checkArgument(videoPath) |
||||
this.mPreviewBarCallback = previewBarCallback |
||||
setPreviewCallback(videoPath, texturePreView!!) |
||||
} |
||||
|
||||
fun updateProgress(progress: Int) { |
||||
if (progress in 0..duration) { |
||||
txtVideoProgress!!.text = TimeUtil.getVideoTime(progress.toLong()) |
||||
previewBar!!.progress = progress |
||||
} |
||||
} |
||||
|
||||
fun release() { |
||||
if (hardwareDecode != null) { |
||||
hardwareDecode!!.release() |
||||
hardwareDecode = null |
||||
} |
||||
} |
||||
|
||||
interface PreviewBarCallback { |
||||
fun onStopTracking(progress: Long) |
||||
} |
||||
|
||||
companion object { |
||||
|
||||
private val TAG = VideoPreviewBar::class.java.simpleName |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue