11package com.example.wangduwei.demos.gles.media
22
33import android.graphics.BitmapFactory
4+ import android.graphics.Color
5+ import android.net.Uri
46import android.os.Bundle
57import android.os.Environment
8+ import android.provider.Settings
9+ import android.util.Log
610import android.view.LayoutInflater
711import android.view.View
812import android.view.ViewGroup
913import android.widget.TextView
1014import android.widget.Toast
11- import android.net.Uri
12- import android.provider.Settings
13- import android.util.Log
1415import com.example.lib_gles.video_filter.composer.Mp4Composer
16+ import com.example.lib_gles.video_filter.core.filter.GlFilter
1517import com.example.lib_gles.video_filter.core.filter.GlFilterGroup
1618import com.example.lib_gles.video_filter.core.filter.GlFilterList
1719import com.example.lib_gles.video_filter.core.filter.GlFilterPeriod
20+ import com.example.lib_gles.video_filter.core.filter.TimeScaleFilter
21+ import com.example.lib_gles.video_filter.filter_impl.GlDynamicMosaicFilter
22+ import com.example.lib_gles.video_filter.filter_impl.GlMosaicShiftCascadeFilter
23+ import com.example.lib_gles.video_filter.filter_impl.GlPulseVerticalScaleFilter
24+ import com.example.lib_gles.video_filter.filter_impl.GlPulseZoomFilter
25+ import com.example.lib_gles.video_filter.filter_impl.GlRadialSpreadColorFilter
1826import com.example.lib_gles.video_filter.filter_impl.GlSoulOutFilter
1927import com.example.lib_gles.video_filter.filter_impl.GlWatermarkFilter
2028import com.example.lib_processor.PageInfo
@@ -42,7 +50,7 @@ class MediaEditFragment: BaseSupportFragment() {
4250 ).absolutePath
4351
4452
45-
53+ private val duration : Long = 10000 ;
4654
4755 private val audioPath = File (
4856 Environment .getExternalStoragePublicDirectory(Environment .DIRECTORY_DOWNLOADS ),
@@ -65,6 +73,10 @@ class MediaEditFragment: BaseSupportFragment() {
6573 val audioOutput = view.findViewById<TextView >(R .id.video_plus_audio)
6674 val filterEffectOutput = view.findViewById<TextView >(R .id.video_plus_filter_effect)
6775
76+ val videoEffect1 = view.findViewById<TextView >(R .id.video_effect1)
77+ val videoEffect3 = view.findViewById<TextView >(R .id.video_effect3)
78+ val videoEffect4 = view.findViewById<TextView >(R .id.video_effect4)
79+
6880
6981 filterOutput.setOnClickListener {
7082 if (hasStoragePermission().not ()) {
@@ -247,6 +259,130 @@ class MediaEditFragment: BaseSupportFragment() {
247259 .start()
248260 }
249261
262+
263+ videoEffect1.setOnClickListener { onClickEffect1(videoEffect1) }
264+ videoEffect3.setOnClickListener { onClickEffect3(videoEffect3) }
265+ videoEffect4.setOnClickListener { onClickEffect4(videoEffect4) }
266+
267+ }
268+
269+ private fun onClickEffect1 (textView : TextView ) {
270+ val dynamicMosaicFilter = GlDynamicMosaicFilter ()
271+ .setRange(2f , 40f ) // 最小/最大马赛克块大小(px)
272+ .setDurationMs(1000f ) // 一个变化周期
273+ .setLoop(true ) // 循环
274+ .setPingPong(true )
275+
276+ val shiftMosaicFilter = GlMosaicShiftCascadeFilter ()
277+ .setHoldMs(1000f )
278+ .setStepMs(200f )
279+ .setShiftX(0.30f )
280+ .setMosaicLevels(40f , 20f , 10f , 0f )
281+
282+ val filterGroup = GlFilterGroup (
283+ GlFilterPeriod (1000L ,Long .MAX_VALUE , dynamicMosaicFilter),
284+ GlFilterPeriod (1000L ,Long .MAX_VALUE , shiftMosaicFilter),
285+ GlFilterPeriod (4000L ,8000L , TimeScaleFilter (0.5 )),
286+ )
287+
288+ val outFile = File (requireContext().externalCacheDir, " 特效一_${System .currentTimeMillis()} .mp4" )
289+ compose(filterGroup, textView, outFile)
290+ }
291+
292+ private fun onClickEffect3 (textView : TextView ) {
293+
294+ val radialColorFilter = GlRadialSpreadColorFilter ()
295+ .setCycleDurationSec(1.6f )
296+ .setMaxIntensity(0.55f )
297+ .setSpreadSoftness(0.10f )
298+ .setColorList(arrayListOf<Int >(
299+ Color .RED ,
300+ Color .YELLOW ,
301+ Color .DKGRAY ,
302+ Color .LTGRAY ,
303+ ))
304+
305+
306+ val zoomFilter = GlPulseZoomFilter (2f )
307+ .setZoomInDurationMs(500f )
308+ .setZoomOutDurationMs(500f )
309+
310+ val verticalScalefilter1 = GlPulseVerticalScaleFilter ()
311+ .setTargetScaleY(0.7f )
312+ .setShrinkDurationMs(200f )
313+ .setExpandDurationMs(200f )
314+ .setIntervalMs(3000f )
315+
316+ val filterGroup = GlFilterGroup (
317+ GlFilterPeriod (0 ,Long .MAX_VALUE , radialColorFilter),
318+ GlFilterPeriod (0 ,Long .MAX_VALUE , zoomFilter),
319+ GlFilterPeriod (0 ,Long .MAX_VALUE , verticalScalefilter1),
320+ )
321+
322+ val outFile = File (requireContext().externalCacheDir, " 特效三_${System .currentTimeMillis()} .mp4" )
323+ compose(filterGroup, textView, outFile)
324+ }
325+
326+ private fun onClickEffect4 (textView : TextView ) {
327+ val shiftMosaicFilter = GlMosaicShiftCascadeFilter ()
328+ .setHoldMs(1000f )
329+ .setStepMs(200f )
330+ .setShiftX(0.30f )
331+ .setMosaicLevels(40f , 20f , 10f , 0f )
332+
333+ val filterGroup = GlFilterGroup (
334+ GlFilterPeriod (1000L ,Long .MAX_VALUE , shiftMosaicFilter),
335+ GlFilterPeriod (4000L ,8000L , TimeScaleFilter (0.5 )),
336+ )
337+
338+ val outFile = File (requireContext().externalCacheDir, " 特效四_${System .currentTimeMillis()} .mp4" )
339+ compose(filterGroup, textView, outFile)
340+ }
341+
342+
343+ private fun compose (filter : GlFilter , textView : TextView , outFile : File ) {
344+ val glFilterList = GlFilterList ()
345+ glFilterList.putGlFilter(GlFilterPeriod (0 , Long .MAX_VALUE , filter))
346+ val defaultText = textView.text;
347+ Mp4Composer (videoPath, outFile.absolutePath)
348+ .size(720 , 1280 )
349+ .clip(0 , duration)
350+ .filterList(glFilterList)
351+ .listener(object : Mp4Composer .Listener {
352+ override fun onProgress (progress : Double ) {
353+ val percent = (progress * 100 ).toInt().coerceIn(0 , 100 )
354+ activity?.runOnUiThread {
355+ textView.text = " 处理中 ${percent} %"
356+ }
357+ }
358+
359+ override fun onCompleted () {
360+ activity?.runOnUiThread {
361+ textView.isEnabled = true
362+ textView.text = defaultText
363+ Toast .makeText(requireContext(), " 输出完成: ${outFile.absolutePath} " , Toast .LENGTH_SHORT ).show()
364+
365+ Log .d(" wdw-gl" ," path = ${outFile.absolutePath} " )
366+ }
367+ }
368+
369+ override fun onCanceled () {
370+ activity?.runOnUiThread {
371+ textView.isEnabled = true
372+ textView.text = defaultText
373+ Toast .makeText(requireContext(), " 已取消" , Toast .LENGTH_SHORT ).show()
374+ }
375+ }
376+
377+ override fun onFailed (exception : Exception ) {
378+ activity?.runOnUiThread {
379+ textView.isEnabled = true
380+ textView.text = defaultText
381+ Toast .makeText(requireContext(), " 输出失败: ${exception.message} " , Toast .LENGTH_SHORT ).show()
382+ }
383+ }
384+ })
385+ .start()
250386 }
251387
252388
0 commit comments