diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index decaca8..60743fa 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -50,8 +50,8 @@ set_target_properties( ffmpeg ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libffmpeg.so ) # third-party library: sox -add_subdirectory(src/main/cpp/sox) -include_directories(src/main/cpp/sox) +#add_subdirectory(src/main/cpp/sox) +#include_directories(src/main/cpp/sox) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") @@ -72,7 +72,7 @@ find_library( # Sets the name of the path variable. target_link_libraries( # Specifies the target library. media-handle ffmpeg - sox +# sox -landroid #native_window -ljnigraphics #bitmap -lOpenSLES #openSLES diff --git a/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.kt index 155332e..79e21cc 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.kt @@ -73,10 +73,13 @@ class AudioHandleActivity : BaseActivity() { infoBuilder.toString(), Toast.LENGTH_LONG).show() infoBuilder = null } + if (!outputPath.isNullOrEmpty() && !this@AudioHandleActivity.isDestroyed) { + showToast("Save to:$outputPath") + outputPath = "" + } } MSG_PROGRESS -> { val progress = msg.arg1 - val duration = msg.arg2 if (progress > 0) { txtProgress!!.visibility = View.VISIBLE txtProgress!!.text = String.format(Locale.getDefault(), "%d%%", progress) @@ -161,17 +164,17 @@ class AudioHandleActivity : BaseActivity() { } when (currentPosition) { 0 -> if (useFFmpeg) { //use FFmpeg to transform - val transformFile = PATH + File.separator + "transformAudio.mp3" - commandLine = FFmpegUtil.transformAudio(srcFile, transformFile) + outputPath = PATH + File.separator + "transformAudio.mp3" + commandLine = FFmpegUtil.transformAudio(srcFile, outputPath) } else { //use MediaCodec and libmp3lame to transform Thread { - val transformPath = PATH + File.separator + "transformAudio.mp3" + outputPath = PATH + File.separator + "transformAudio.mp3" try { mHandler.obtainMessage(MSG_BEGIN).sendToTarget() val clazz = Class.forName("com.frank.mp3.Mp3Converter") val instance = clazz.newInstance() val method = clazz.getDeclaredMethod("convertToMp3", String::class.java, String::class.java) - method.invoke(instance, srcFile, transformPath) + method.invoke(instance, srcFile, outputPath) mHandler.obtainMessage(MSG_FINISH).sendToTarget() } catch (e: Exception) { Log.e("AudioHandleActivity", "convert mp3 error=" + e.message) @@ -184,8 +187,8 @@ class AudioHandleActivity : BaseActivity() { if (suffix == null || suffix.isEmpty()) { return } - val cutFile = PATH + File.separator + "cutAudio" + suffix - commandLine = FFmpegUtil.cutAudio(srcFile, 10.5f, 15.0f, cutFile) + outputPath = PATH + File.separator + "cutAudio" + suffix + commandLine = FFmpegUtil.cutAudio(srcFile, 10.5f, 15.0f, outputPath) } 2 //concat audio -> { @@ -205,11 +208,11 @@ class AudioHandleActivity : BaseActivity() { return } commandLine = if (mixAudio) { - val mixAudio = PATH + File.separator + "mix" + mixSuffix - FFmpegUtil.mixAudio(srcFile, appendFile, mixAudio) + outputPath = PATH + File.separator + "mix" + mixSuffix + FFmpegUtil.mixAudio(srcFile, appendFile, outputPath) } else { - val mergeAudio = PATH + File.separator + "merge" + mixSuffix - FFmpegUtil.mergeAudio(srcFile, appendFile, mergeAudio) + outputPath = PATH + File.separator + "merge" + mixSuffix + FFmpegUtil.mergeAudio(srcFile, appendFile, outputPath) } } 4 //use AudioTrack to play audio @@ -222,26 +225,26 @@ class AudioHandleActivity : BaseActivity() { 5 //change audio speed -> { val speed = 2.0f // funny effect, range from 0.5 to 100.0 - val speedPath = PATH + File.separator + "speed.mp3" - commandLine = FFmpegUtil.changeAudioSpeed(srcFile, speedPath, speed) + outputPath = PATH + File.separator + "speed.mp3" + commandLine = FFmpegUtil.changeAudioSpeed(srcFile, outputPath, speed) } 6 // setting echo effect -> { val echo = 1000 // echo effect, range from 0 to 90000 - val echoPath = PATH + File.separator + "echo.mp3" - commandLine = FFmpegUtil.audioEcho(srcFile, echo, echoPath) + outputPath = PATH + File.separator + "echo.mp3" + commandLine = FFmpegUtil.audioEcho(srcFile, echo, outputPath) } 7 //tremolo effect -> { val frequency = 5 // range from 0.1 to 20000.0 val depth = 0.9f // range from 0 to 1 - val tremoloPath = PATH + File.separator + "tremolo.mp3" - commandLine = FFmpegUtil.audioTremolo(srcFile, frequency, depth, tremoloPath) + outputPath = PATH + File.separator + "tremolo.mp3" + commandLine = FFmpegUtil.audioTremolo(srcFile, frequency, depth, outputPath) } 8 //audio denoise -> { - val noisePath = PATH + File.separator + "denoise.mp3" - commandLine = FFmpegUtil.audioDenoise(srcFile, noisePath) + outputPath = PATH + File.separator + "denoise.mp3" + commandLine = FFmpegUtil.audioDenoise(srcFile, outputPath) } 9 // equalizer plus -> { @@ -253,8 +256,8 @@ class AudioHandleActivity : BaseActivity() { bandList.add("12b=2") bandList.add("14b=1") bandList.add("16b=0") - val equalizePath = PATH + File.separator + "equalize.mp3" - commandLine = FFmpegUtil.audioEqualizer(srcFile, bandList, equalizePath) + outputPath = PATH + File.separator + "equalize.mp3" + commandLine = FFmpegUtil.audioEqualizer(srcFile, bandList, outputPath) } 10 //silence detect -> { @@ -263,18 +266,18 @@ class AudioHandleActivity : BaseActivity() { 11 // modify volume -> { val volume = 0.5f // 0.0-1.0 - val volumePath = PATH + File.separator + "volume.mp3" - commandLine = FFmpegUtil.audioVolume(srcFile, volume, volumePath) + outputPath = PATH + File.separator + "volume.mp3" + commandLine = FFmpegUtil.audioVolume(srcFile, volume, outputPath) } 12 //audio encode -> { val pcmFile = PATH + File.separator + "raw.pcm" - val wavFile = PATH + File.separator + "convert.mp3" + outputPath= PATH + File.separator + "convert.mp3" //sample rate, normal is 8000/16000/44100 val sampleRate = 44100 //channel num of pcm val channel = 2 - commandLine = FFmpegUtil.encodeAudio(pcmFile, wavFile, sampleRate, channel) + commandLine = FFmpegUtil.encodeAudio(pcmFile, outputPath, sampleRate, channel) } 13 //concat PCM streams -> { @@ -329,6 +332,8 @@ class AudioHandleActivity : BaseActivity() { private const val useFFmpeg = true private const val mixAudio = true + + private var outputPath :String ?= null } } diff --git a/app/src/main/java/com/frank/ffmpeg/activity/BaseActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/BaseActivity.kt index 0413d8e..a799b2c 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/BaseActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/BaseActivity.kt @@ -13,6 +13,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Toast +import com.frank.ffmpeg.FFmpegApplication import com.frank.ffmpeg.R import com.frank.ffmpeg.util.ContentUtil @@ -104,7 +105,7 @@ abstract class BaseActivity : AppCompatActivity(), View.OnClickListener { if (TextUtils.isEmpty(msg)) { return } - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() + Toast.makeText(FFmpegApplication.getInstance(), msg, Toast.LENGTH_SHORT).show() } protected fun showSelectFile() { diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.kt index efaec71..231e266 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.kt @@ -49,6 +49,10 @@ class MediaHandleActivity : BaseActivity() { MSG_FINISH -> { layoutProgress!!.visibility = View.GONE layoutMediaHandle!!.visibility = View.VISIBLE + if (!outputPath.isNullOrEmpty() && !this@MediaHandleActivity.isDestroyed) { + showToast("Save to:$outputPath") + outputPath = "" + } } MSG_PROGRESS -> { val progress = msg.arg1 @@ -120,13 +124,13 @@ class MediaHandleActivity : BaseActivity() { } R.id.btn_extract_audio//extract audio -> { - val extractAudio = PATH + File.separator + "extractAudio.aac" - commandLine = FFmpegUtil.extractAudio(srcFile, extractAudio) + outputPath = PATH + File.separator + "extractAudio.aac" + commandLine = FFmpegUtil.extractAudio(srcFile, outputPath) } R.id.btn_extract_video//extract video -> { - val extractVideo = PATH + File.separator + "extractVideo.mp4" - commandLine = FFmpegUtil.extractVideo(srcFile, extractVideo) + outputPath = PATH + File.separator + "extractVideo.mp4" + commandLine = FFmpegUtil.extractVideo(srcFile, outputPath) } R.id.btn_dubbing//dubbing -> { @@ -185,5 +189,6 @@ class MediaHandleActivity : BaseActivity() { private val TAG = MediaHandleActivity::class.java.simpleName private val PATH = Environment.getExternalStorageDirectory().path + private var outputPath :String ?= null } } diff --git a/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.kt index f82da4d..e74d9b2 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.kt @@ -70,6 +70,10 @@ class VideoHandleActivity : BaseActivity() { FileUtil.deleteFile(outputPath2) FileUtil.deleteFile(listPath) } + if (!outputPath.isNullOrEmpty() && !this@VideoHandleActivity.isDestroyed) { + showToast("Save to:$outputPath") + outputPath = "" + } } MSG_PROGRESS -> { val progress = msg.arg1 @@ -172,23 +176,23 @@ class VideoHandleActivity : BaseActivity() { when (currentPosition) { 0 //transform format -> { - val transformVideo = PATH + File.separator + "transformVideo.mp4" - commandLine = FFmpegUtil.transformVideo(srcFile, transformVideo) + outputPath = PATH + File.separator + "transformVideo.mp4" + commandLine = FFmpegUtil.transformVideo(srcFile, outputPath) } 1 //cut video -> { - val cutVideo = PATH + File.separator + "cutVideo" + suffix + outputPath = PATH + File.separator + "cutVideo" + suffix val startTime = 5.5f val duration = 20.0f - commandLine = FFmpegUtil.cutVideo(srcFile, startTime, duration, cutVideo) + commandLine = FFmpegUtil.cutVideo(srcFile, startTime, duration, outputPath) } 2 //concat video together -> concatVideo(srcFile) 3 //video snapshot -> { - val screenShot = PATH + File.separator + "screenShot.jpg" + outputPath = PATH + File.separator + "screenShot.jpg" val time = 10.5f - commandLine = FFmpegUtil.screenShot(srcFile, time, screenShot) + commandLine = FFmpegUtil.screenShot(srcFile, time, outputPath) } 4 //add watermark to video -> { @@ -208,23 +212,22 @@ class VideoHandleActivity : BaseActivity() { TYPE_IMAGE// image -> { val photo = PATH + File.separator + "hello.png" - val photoMark = PATH + File.separator + "photoMark.mp4" - commandLine = FFmpegUtil.addWaterMarkImg(srcFile, photo, location, bitRate, offsetXY, photoMark) + outputPath = PATH + File.separator + "photoMark.mp4" + commandLine = FFmpegUtil.addWaterMarkImg(srcFile, photo, location, bitRate, offsetXY, outputPath) } TYPE_GIF// gif -> { val gifPath = PATH + File.separator + "ok.gif" - val gifWaterMark = PATH + File.separator + "gifWaterMark.mp4" - commandLine = FFmpegUtil.addWaterMarkGif(srcFile, gifPath, location, bitRate, offsetXY, gifWaterMark) + outputPath = PATH + File.separator + "gifWaterMark.mp4" + commandLine = FFmpegUtil.addWaterMarkGif(srcFile, gifPath, location, bitRate, offsetXY, outputPath) } TYPE_TEXT// text -> { val text = "Hello,FFmpeg" val textPath = PATH + File.separator + "text.png" val result = BitmapUtil.textToPicture(textPath, text, Color.BLUE, 20) - Log.i(TAG, "text to picture result=$result") - val textMark = PATH + File.separator + "textMark.mp4" - commandLine = FFmpegUtil.addWaterMarkImg(srcFile, textPath, location, bitRate, offsetXY, textMark) + outputPath = PATH + File.separator + "textMark.mp4" + commandLine = FFmpegUtil.addWaterMarkImg(srcFile, textPath, location, bitRate, offsetXY, outputPath) } else -> { } @@ -232,14 +235,14 @@ class VideoHandleActivity : BaseActivity() { } 5 //Remove logo from video, or use to mosaic video -> { - val removeLogoPath = PATH + File.separator + "removeLogo" + suffix + outputPath = PATH + File.separator + "removeLogo" + suffix val widthL = 64 val heightL = 40 - commandLine = FFmpegUtil.removeLogo(srcFile, 10, 10, widthL, heightL, removeLogoPath) + commandLine = FFmpegUtil.removeLogo(srcFile, 10, 10, widthL, heightL, outputPath) } 7 //convert video into gif -> { - val video2Gif = PATH + File.separator + "video2Gif.gif" + outputPath = PATH + File.separator + "video2Gif.gif" val gifStart = 10 val gifDuration = 3 val width = 320 @@ -251,39 +254,39 @@ class VideoHandleActivity : BaseActivity() { val paletteCmd = FFmpegUtil.generatePalette(srcFile, gifStart, gifDuration, frameRate, width, palettePath) val gifCmd = FFmpegUtil.generateGifByPalette(srcFile, palettePath, gifStart, gifDuration, - frameRate, width, video2Gif) + frameRate, width, outputPath) val cmdList = ArrayList>() cmdList.add(paletteCmd) cmdList.add(gifCmd) ffmpegHandler!!.executeFFmpegCmds(cmdList) } else { - convertGifInHighQuality(video2Gif, srcFile, gifStart, gifDuration, frameRate) + convertGifInHighQuality(outputPath!!, srcFile, gifStart, gifDuration, frameRate) } } 8 //combine video which layout could be horizontal of vertical -> { val input1 = PATH + File.separator + "input1.mp4" val input2 = PATH + File.separator + "input2.mp4" - val outputFile = PATH + File.separator + "multi.mp4" + outputPath = PATH + File.separator + "multi.mp4" if (!FileUtil.checkFileExist(input1) || !FileUtil.checkFileExist(input2)) { return } - commandLine = FFmpegUtil.multiVideo(input1, input2, outputFile, VideoLayout.LAYOUT_HORIZONTAL) + commandLine = FFmpegUtil.multiVideo(input1, input2, outputPath, VideoLayout.LAYOUT_HORIZONTAL) } 9 //video reverse -> { - val output = PATH + File.separator + "reverse.mp4" - commandLine = FFmpegUtil.reverseVideo(srcFile, output) + outputPath = PATH + File.separator + "reverse.mp4" + commandLine = FFmpegUtil.reverseVideo(srcFile, outputPath) } 10 //noise reduction of video -> { - val denoise = PATH + File.separator + "denoise.mp4" - commandLine = FFmpegUtil.denoiseVideo(srcFile, denoise) + outputPath = PATH + File.separator + "denoise.mp4" + commandLine = FFmpegUtil.denoiseVideo(srcFile, outputPath) } 11 //convert video to picture -> { - val imagePath = PATH + File.separator + "Video2Image/" - val imageFile = File(imagePath) + outputPath = PATH + File.separator + "Video2Image/" + val imageFile = File(outputPath) if (!imageFile.exists()) { if (!imageFile.mkdir()) { return @@ -292,7 +295,7 @@ class VideoHandleActivity : BaseActivity() { val mStartTime = 10//start time val mDuration = 5//duration val mFrameRate = 10//frameRate - commandLine = FFmpegUtil.videoToImage(srcFile, mStartTime, mDuration, mFrameRate, imagePath) + commandLine = FFmpegUtil.videoToImage(srcFile, mStartTime, mDuration, mFrameRate, outputPath) } 12 //combine into picture-in-picture video -> { @@ -305,8 +308,8 @@ class VideoHandleActivity : BaseActivity() { //For example: full video is 320x240, small video is 120x90, so x=200 y=150 val x = 200 val y = 150 - val picInPic = PATH + File.separator + "PicInPic.mp4" - commandLine = FFmpegUtil.picInPicVideo(inputFile1, inputFile2, x, y, picInPic) + outputPath = PATH + File.separator + "PicInPic.mp4" + commandLine = FFmpegUtil.picInPicVideo(inputFile1, inputFile2, x, y, outputPath) } 13 //moov box moves ahead, which is behind mdat box of mp4 video -> { @@ -317,48 +320,48 @@ class VideoHandleActivity : BaseActivity() { val filePath = FileUtil.getFilePath(srcFile) var fileName = FileUtil.getFileName(srcFile) fileName = "moov_" + fileName!! - val moovPath = filePath + File.separator + fileName + outputPath = filePath + File.separator + fileName if (useFFmpegCmd) { - commandLine = FFmpegUtil.moveMoovAhead(srcFile, moovPath) + commandLine = FFmpegUtil.moveMoovAhead(srcFile, outputPath) } else { val ffmpegCmd = FFmpegCmd() - val result = ffmpegCmd.moveMoovAhead(srcFile, moovPath) + val result = ffmpegCmd.moveMoovAhead(srcFile, outputPath) Log.e(TAG, "result=" + (result == 0)) } } 14 //playing speed of video -> { - val speed = PATH + File.separator + "speed.mp4" - commandLine = FFmpegUtil.changeSpeed(srcFile, speed, 2f, false) + outputPath = PATH + File.separator + "speed.mp4" + commandLine = FFmpegUtil.changeSpeed(srcFile, outputPath, 2f, false) } 15 // insert thumbnail into video -> { val thumbnailPath = PATH + File.separator + "thumb.jpg" - val thumbVideoPath = PATH + File.separator + "thumbnailVideo" + suffix - commandLine = FFmpegUtil.insertPicIntoVideo(srcFile, thumbnailPath, thumbVideoPath) + outputPath = PATH + File.separator + "thumbnailVideo" + suffix + commandLine = FFmpegUtil.insertPicIntoVideo(srcFile, thumbnailPath, outputPath) } 16 //add subtitle into video -> { val subtitlePath = PATH + File.separator + "test.ass" - val addSubtitlePath = PATH + File.separator + "subtitle.mkv" - commandLine = FFmpegUtil.addSubtitleIntoVideo(srcFile, subtitlePath, addSubtitlePath) + outputPath = PATH + File.separator + "subtitle.mkv" + commandLine = FFmpegUtil.addSubtitleIntoVideo(srcFile, subtitlePath, outputPath) } 17 // set the rotate degree of video -> { val rotateDegree = 90 - val addSubtitlePath = PATH + File.separator + "rotate" + rotateDegree + suffix - commandLine = FFmpegUtil.rotateVideo(srcFile, rotateDegree, addSubtitlePath) + outputPath = PATH + File.separator + "rotate" + rotateDegree + suffix + commandLine = FFmpegUtil.rotateVideo(srcFile, rotateDegree, outputPath) } 18 // change the gop(key frame interval) of video -> { val gop = 30 - val gopPath = PATH + File.separator + "gop" + gop + suffix - commandLine = FFmpegUtil.changeGOP(srcFile, gop, gopPath) + outputPath = PATH + File.separator + "gop" + gop + suffix + commandLine = FFmpegUtil.changeGOP(srcFile, gop, outputPath) } 19 // change video from RGB to gray -> { - val grayPath = PATH + File.separator + "gray" + suffix - commandLine = FFmpegUtil.toGrayVideo(srcFile, grayPath) + outputPath = PATH + File.separator + "gray" + suffix + commandLine = FFmpegUtil.toGrayVideo(srcFile, outputPath) } else -> { } @@ -472,6 +475,7 @@ class VideoHandleActivity : BaseActivity() { private val TAG = VideoHandleActivity::class.java.simpleName private val PATH = Environment.getExternalStorageDirectory().path + private var outputPath :String ?= null private const val useFFmpegCmd = true private const val TYPE_IMAGE = 1 diff --git a/app/src/main/java/com/frank/ffmpeg/util/ThreadPoolUtil.kt b/app/src/main/java/com/frank/ffmpeg/util/ThreadPoolUtil.kt index 7861f68..f01840f 100644 --- a/app/src/main/java/com/frank/ffmpeg/util/ThreadPoolUtil.kt +++ b/app/src/main/java/com/frank/ffmpeg/util/ThreadPoolUtil.kt @@ -5,8 +5,9 @@ import java.util.concurrent.Executors object ThreadPoolUtil { + private val executor = Executors.newSingleThreadExecutor() + fun executeSingleThreadPool(runnable: Runnable): ExecutorService { - val executor = Executors.newSingleThreadExecutor() executor.submit(runnable) return executor }