diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index fb0c453ec519dbb3aa25c9c23fb1d0e6edaa92f8..0ed02ef649b1adff6cc4e752c72107b866899283 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -12,6 +12,27 @@ </deviceKey> </Target> </runningDeviceTargetSelectedWithDropDown> - <timeTargetWasSelectedWithDropDown value="2022-04-15T17:09:08.556417400Z" /> + <timeTargetWasSelectedWithDropDown value="2022-04-16T12:57:56.675856100Z" /> + <multipleDevicesSelectedInDropDown value="true" /> + <runningDeviceTargetsSelectedWithDialog> + <Target> + <type value="RUNNING_DEVICE_TARGET" /> + <deviceKey> + <Key> + <type value="SERIAL_NUMBER" /> + <value value="R3CR60HNFLW" /> + </Key> + </deviceKey> + </Target> + <Target> + <type value="RUNNING_DEVICE_TARGET" /> + <deviceKey> + <Key> + <type value="SERIAL_NUMBER" /> + <value value="da1d6329" /> + </Key> + </deviceKey> + </Target> + </runningDeviceTargetsSelectedWithDialog> </component> </project> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e15b18e769bab09fa686de4890996a76c3856bc1..e167883c48e30595aca86ff64c19e2ab591a0607 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "com.slprojects.sl_videocompressor" minSdk 24 - targetSdk 31 + targetSdk 29 versionCode 1 versionName "1.0" diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..7912d565e45e1025c6ba1320a2ae5f1ca75cff5b --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.slprojects.sl_videocompressor", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java b/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java index 5d99192eb64812b1842c36a6688fee4e10396b46..8e33bb3b5c715269b0b2a9d20c3a01d1c2e7aa12 100644 --- a/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java +++ b/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java @@ -37,11 +37,11 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private TextView videoInformations; private String video_url; private LinearLayout weHaveTheVideo; - private Spinner sizeUnit; + public Spinner sizeUnit; private EditText targetFileSizeInput; - private Spinner encodeQuality; - private Button encodeVideoBtn; - private CheckBox deleteSoundTrack; + public Spinner encodeQuality; + public Button encodeVideoBtn; + public CheckBox deleteSoundTrack; @Override protected void onCreate(Bundle savedInstanceState) { @@ -110,7 +110,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } // On peut lancer l'encodage - encodeVideo(video_url, Integer.parseInt(targetFileSizeInput.getText().toString()), encodeQuality.getSelectedItem().toString()); + encodeVideo encodage = new encodeVideo(this, video_url, Integer.parseInt(targetFileSizeInput.getText().toString()), encodeQuality.getSelectedItem().toString()); + encodage.execute(); } } @@ -188,151 +189,4 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe long size = file.length(); return (int) size; } - - // Fonction de conversion - public void encodeVideo(String video_url, Integer targetFileSize, String quality) { - // On récupère la taille cible du fichier selon l'unité choisie - Integer targetFileSizeInKiloBit = 0; - if(sizeUnit.getSelectedItem().toString().equals("Mo")) { - targetFileSizeInKiloBit = targetFileSize * 1000 * 8; - }else if(sizeUnit.getSelectedItem().toString().equals("MB")) { - targetFileSizeInKiloBit = targetFileSize * 1000 * 8; - }else{ - Toast.makeText(this, "Unité de taille \"" + sizeUnit.getSelectedItem().toString() + "\" non reconnue. M", Toast.LENGTH_SHORT).show(); - } - //targetFileSizeInKiloBit = (int) (targetFileSizeInKiloBit * (9 / 10)); - Log.i("targetFileSizeInKiloBit", targetFileSizeInKiloBit.toString()); - - // On récupère la durée de la vidéo - Integer videoDurationInSeconds = getVideoDurationInSeconds(video_url); - Log.i("videoDurationInSeconds", videoDurationInSeconds.toString()); - - // On regarde si on garde l'audio ou pas - Integer audioBitrate = 0; // en kBits - if(!deleteSoundTrack.isChecked()) { - audioBitrate = 128; - } - - // On va calculer le bitrate de la video en fonction de la bande son - Integer videoBitrate = (int) ((targetFileSizeInKiloBit / videoDurationInSeconds) - audioBitrate); - Log.i("videoBitrate", videoBitrate.toString()); - - // On regarde si a notre dossier de créé - File folder = new File(Environment.getExternalStorageDirectory() + "/SL-Video Compressor/"); - if(!folder.exists()) { - folder.mkdir(); - } - - String outputFileName = folder.getAbsolutePath() + "/" + video_url.substring(this.video_url.lastIndexOf("/") + 1, this.video_url.lastIndexOf(".")) + "_" + targetFileSize + "_" + quality + ".mp4"; - String logPath = "'" + folder.getAbsolutePath() + "/'"; - - // On supprime le fichier s'il existe déjà - File file = new File(outputFileName); - if(file.exists()) { - file.delete(); - } - - - // FFMPEG - List<String> pass1Commands = new LinkedList<>(); - pass1Commands.add("-y"); - pass1Commands.add("-i"); - pass1Commands.add('"' + video_url + '"'); - pass1Commands.add("-codec:v"); - pass1Commands.add("libx264"); - pass1Commands.add("-passlogfile"); - pass1Commands.add(logPath); - pass1Commands.add("-preset"); - pass1Commands.add(encodeQuality.getSelectedItem().toString()); - pass1Commands.add("-b:v"); - pass1Commands.add(videoBitrate.toString() + "k"); - pass1Commands.add("-maxrate"); - pass1Commands.add(videoBitrate.toString() + "k"); - pass1Commands.add("-bufsize"); - pass1Commands.add("1000k"); - pass1Commands.add("-pass"); - pass1Commands.add("1"); - pass1Commands.add("-an"); - - pass1Commands.add("-f"); - pass1Commands.add("null"); - pass1Commands.add("-"); - - String ffmpegCommand = ""; - for(String command : pass1Commands) { - ffmpegCommand += command + " "; - } - Log.i("FFMPEG", ffmpegCommand); - - // On lance l'encodage - Toast.makeText(this, "Encodage en cours...", Toast.LENGTH_SHORT).show(); - encodeVideoBtn.setEnabled(false); - - FFmpegSession firstPass = FFmpegKit.execute(ffmpegCommand); - if (ReturnCode.isSuccess(firstPass.getReturnCode())) { - - // SUCCESS - Toast.makeText(this, "1ère passe terminée", Toast.LENGTH_SHORT).show(); - - } else if (ReturnCode.isCancel(firstPass.getReturnCode())) { - - // CANCEL - - } else { - // FAILURE - Log.i("Main", String.format("Command failed with state %s and rc %s.%s", firstPass.getState(), firstPass.getReturnCode(), firstPass.getFailStackTrace())); - Toast.makeText(this, "Erreur lors de l'encodage de la 1ère passe", Toast.LENGTH_SHORT).show(); - } - - List<String> pass2Commands = new LinkedList<>(); - pass2Commands.add("-i"); - pass2Commands.add('"' + video_url + '"'); - pass2Commands.add("-codec:v"); - pass2Commands.add("libx264"); - pass2Commands.add("-passlogfile"); - pass2Commands.add(logPath); - pass2Commands.add("-preset"); - pass2Commands.add(encodeQuality.getSelectedItem().toString()); - pass2Commands.add("-b:v"); - pass2Commands.add(videoBitrate.toString() + "k"); - pass2Commands.add("-maxrate"); - pass2Commands.add(videoBitrate.toString() + "k"); - pass2Commands.add("-bufsize"); - pass2Commands.add("1000k"); - pass2Commands.add("-pass"); - pass2Commands.add("2"); - - // On regarde si on garde la piste audio - if(deleteSoundTrack.isChecked()) { - pass2Commands.add("-c:a"); - pass2Commands.add("aac"); - pass2Commands.add("-b:a"); - pass2Commands.add(audioBitrate.toString() + "k"); - } - - pass2Commands.add("'" + outputFileName + "'"); - - ffmpegCommand = ""; - for(String command : pass2Commands) { - ffmpegCommand += command + " "; - } - Log.i("FFMPEG", ffmpegCommand); - - FFmpegSession secondPass = FFmpegKit.execute(ffmpegCommand); - if (ReturnCode.isSuccess(firstPass.getReturnCode())) { - - // SUCCESS - Toast.makeText(this, "Encodage terminé: " + outputFileName, Toast.LENGTH_LONG).show(); - - } else if (ReturnCode.isCancel(secondPass.getReturnCode())) { - - // CANCEL - - } else { - // FAILURE - Log.i("Main", String.format("Command failed with state %s and rc %s.%s", secondPass.getState(), secondPass.getReturnCode(), secondPass.getFailStackTrace())); - Toast.makeText(this, "Erreur lors de l'encodage de la 2nd passe", Toast.LENGTH_SHORT).show(); - } - encodeVideoBtn.setEnabled(true); - } } \ No newline at end of file diff --git a/app/src/main/java/com/slprojects/sl_videocompressor/encodeVideo.java b/app/src/main/java/com/slprojects/sl_videocompressor/encodeVideo.java new file mode 100644 index 0000000000000000000000000000000000000000..a6d8bfd85eeb96730a95ffa8c85c77546b39911a --- /dev/null +++ b/app/src/main/java/com/slprojects/sl_videocompressor/encodeVideo.java @@ -0,0 +1,213 @@ +package com.slprojects.sl_videocompressor; + +import android.os.AsyncTask; +import android.os.Environment; +import android.util.Log; +import android.widget.Toast; + +import com.arthenica.ffmpegkit.FFmpegKit; +import com.arthenica.ffmpegkit.FFmpegSession; +import com.arthenica.ffmpegkit.ReturnCode; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +public class encodeVideo extends AsyncTask<String, Void, Void> { + private final MainActivity activity; + private final String video_url; + private final Integer targetFileSize; + private final String quality; + + public encodeVideo(MainActivity activity, String video_url, Integer targetFileSize, String quality) { + this.activity = activity; + this.video_url = video_url; + this.targetFileSize = targetFileSize; + this.quality = quality; + } + + @Override + protected Void doInBackground(String... params) { + // On récupère la taille cible du fichier selon l'unité choisie + Integer targetFileSizeInKiloBit = 0; + if(activity.sizeUnit.getSelectedItem().toString().equals("Mo")) { + targetFileSizeInKiloBit = targetFileSize * 1000 * 8; + }else if(activity.sizeUnit.getSelectedItem().toString().equals("MB")) { + targetFileSizeInKiloBit = targetFileSize * 1000 * 8; + }else{ + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "Unité de taille \"" + activity.sizeUnit.getSelectedItem().toString() + "\" non reconnue. M", Toast.LENGTH_SHORT).show(); + } + }); + } + //targetFileSizeInKiloBit = (int) (targetFileSizeInKiloBit * (9 / 10)); + Log.i("targetFileSizeInKiloBit", targetFileSizeInKiloBit.toString()); + + // On récupère la durée de la vidéo + Integer videoDurationInSeconds = activity.getVideoDurationInSeconds(video_url); + Log.i("videoDurationInSeconds", videoDurationInSeconds.toString()); + + // On regarde si on garde l'audio ou pas + Integer audioBitrate = 0; // en kBits + if(!activity.deleteSoundTrack.isChecked()) { + audioBitrate = 128; + } + + // On va calculer le bitrate de la video en fonction de la bande son + Integer videoBitrate = (int) ((targetFileSizeInKiloBit / videoDurationInSeconds) - audioBitrate); + Log.i("videoBitrate", videoBitrate.toString()); + + // On regarde si a notre dossier de créé + File folder = new File(Environment.getExternalStorageDirectory() + "/SL-Video Compressor/"); + if(!folder.exists()) { + Log.w("folder", Environment.getExternalStorageDirectory() + "/SL-Video Compressor/ does not exist"); + folder.mkdir(); + Log.i("folder", "created"); + } + + String outputFileName = folder.getAbsolutePath() + "/" + video_url.substring(this.video_url.lastIndexOf("/") + 1, this.video_url.lastIndexOf(".")) + "_" + targetFileSize + "_" + quality + ".mp4"; + String logPath = "'" + folder.getAbsolutePath() + "/'"; + + // On supprime le fichier s'il existe déjà + File file = new File(outputFileName); + if(file.exists()) { + file.delete(); + } + + + // FFMPEG + List<String> pass1Commands = new LinkedList<>(); + pass1Commands.add("-y"); + pass1Commands.add("-i"); + pass1Commands.add('"' + video_url + '"'); + pass1Commands.add("-codec:v"); + pass1Commands.add("libx264"); + pass1Commands.add("-passlogfile"); + pass1Commands.add(logPath); + pass1Commands.add("-preset"); + pass1Commands.add(activity.encodeQuality.getSelectedItem().toString()); + pass1Commands.add("-b:v"); + pass1Commands.add(videoBitrate.toString() + "k"); + pass1Commands.add("-maxrate"); + pass1Commands.add(videoBitrate.toString() + "k"); + pass1Commands.add("-bufsize"); + pass1Commands.add("1000k"); + pass1Commands.add("-pass"); + pass1Commands.add("1"); + pass1Commands.add("-an"); + + pass1Commands.add("-f"); + pass1Commands.add("null"); + pass1Commands.add("-"); + + String ffmpegCommand = ""; + for(String command : pass1Commands) { + ffmpegCommand += command + " "; + } + Log.i("FFMPEG", ffmpegCommand); + + // On lance l'encodage + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "Encodage en cours...", Toast.LENGTH_SHORT).show(); + activity.encodeVideoBtn.setEnabled(false); + } + }); + + FFmpegSession firstPass = FFmpegKit.execute(ffmpegCommand); + if (ReturnCode.isSuccess(firstPass.getReturnCode())) { + + // SUCCESS + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "1ère passe terminée", Toast.LENGTH_SHORT).show(); + } + }); + } else if (ReturnCode.isCancel(firstPass.getReturnCode())) { + + // CANCEL + + } else { + // FAILURE + Log.i("Main", String.format("Command failed with state %s and rc %s.%s", firstPass.getState(), firstPass.getReturnCode(), firstPass.getFailStackTrace())); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "Erreur lors de l'encodage de la 1ère passe", Toast.LENGTH_SHORT).show(); + } + }); + } + + List<String> pass2Commands = new LinkedList<>(); + pass2Commands.add("-i"); + pass2Commands.add('"' + video_url + '"'); + pass2Commands.add("-codec:v"); + pass2Commands.add("libx264"); + pass2Commands.add("-passlogfile"); + pass2Commands.add(logPath); + pass2Commands.add("-preset"); + pass2Commands.add(activity.encodeQuality.getSelectedItem().toString()); + pass2Commands.add("-b:v"); + pass2Commands.add(videoBitrate.toString() + "k"); + pass2Commands.add("-maxrate"); + pass2Commands.add(videoBitrate.toString() + "k"); + pass2Commands.add("-bufsize"); + pass2Commands.add("1000k"); + pass2Commands.add("-pass"); + pass2Commands.add("2"); + + // On regarde si on garde la piste audio + if(activity.deleteSoundTrack.isChecked()) { + pass2Commands.add("-an"); + }else{ + pass2Commands.add("-c:a"); + pass2Commands.add("aac"); + pass2Commands.add("-b:a"); + pass2Commands.add(audioBitrate.toString() + "k"); + } + + pass2Commands.add("'" + outputFileName + "'"); + + ffmpegCommand = ""; + for(String command : pass2Commands) { + ffmpegCommand += command + " "; + } + Log.i("FFMPEG", ffmpegCommand); + + FFmpegSession secondPass = FFmpegKit.execute(ffmpegCommand); + if (ReturnCode.isSuccess(firstPass.getReturnCode())) { + + // SUCCESS + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "Encodage terminé: " + outputFileName, Toast.LENGTH_LONG).show(); + } + }); + } else if (ReturnCode.isCancel(secondPass.getReturnCode())) { + + // CANCEL + + } else { + // FAILURE + Log.i("Main", String.format("Command failed with state %s and rc %s.%s", secondPass.getState(), secondPass.getReturnCode(), secondPass.getFailStackTrace())); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(activity, "Erreur lors de l'encodage de la 2nd passe", Toast.LENGTH_SHORT).show(); + } + }); + } + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.encodeVideoBtn.setEnabled(true); + } + }); + return null; + } +} diff --git a/builds/sl-video-compressor-1.0.apk b/builds/sl-video-compressor-1.0.apk new file mode 100644 index 0000000000000000000000000000000000000000..7407002041433ae4cc3d6dfed25c121e1b686b8a Binary files /dev/null and b/builds/sl-video-compressor-1.0.apk differ