diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index ca487c7b0fc8662c1524f072c4264f103faddf61..fb0c453ec519dbb3aa25c9c23fb1d0e6edaa92f8 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="deploymentTargetDropDown"> - <multipleDevicesSelectedInDropDown value="true" /> - <runningDeviceTargetsSelectedWithDialog> - <Target> - <type value="RUNNING_DEVICE_TARGET" /> - <deviceKey> - <Key> - <type value="SERIAL_NUMBER" /> - <value value="R3CR60HNFLW" /> - </Key> - </deviceKey> - </Target> + <runningDeviceTargetSelectedWithDropDown> <Target> <type value="RUNNING_DEVICE_TARGET" /> <deviceKey> @@ -21,6 +11,7 @@ </Key> </deviceKey> </Target> - </runningDeviceTargetsSelectedWithDialog> + </runningDeviceTargetSelectedWithDropDown> + <timeTargetWasSelectedWithDropDown value="2022-04-15T17:09:08.556417400Z" /> </component> </project> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 85eb33098c4538bcf450227d3613e7a7aa086ecc..e15b18e769bab09fa686de4890996a76c3856bc1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' - implementation 'com.arthenica:ffmpeg-kit-full:4.5.1-1' + implementation 'com.arthenica:ffmpeg-kit-full-gpl:4.5.1-1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 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 357a9a9cbcd6328513a7901aefe8f6b3ace42155..5d99192eb64812b1842c36a6688fee4e10396b46 100644 --- a/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java +++ b/app/src/main/java/com/slprojects/sl_videocompressor/MainActivity.java @@ -11,6 +11,7 @@ import android.content.pm.PackageManager; import android.media.MediaMetadataRetriever; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; @@ -27,6 +28,8 @@ import com.arthenica.ffmpegkit.FFmpegSession; import com.arthenica.ffmpegkit.ReturnCode; import java.io.File; +import java.util.LinkedList; +import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener { @@ -93,7 +96,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe intent.setType("video/*"); startActivityForResult(intent, 123); }else if(v == encodeVideoBtn){ - Log.d("MainActivity", "Encode video"); + Log.i("MainActivity", "Encode video"); // On va vérifier que l'utilisateur a renté une taille de fichier if(targetFileSizeInput.getText().toString().equals("")){ Toast.makeText(this, "Veuillez rentrer une taille de fichier", Toast.LENGTH_SHORT).show(); @@ -107,7 +110,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } // On peut lancer l'encodage - encodeVideo(video_url, targetFileSizeInput.getText().toString(), encodeQuality.getSelectedItem().toString()); + encodeVideo(video_url, Integer.parseInt(targetFileSizeInput.getText().toString()), encodeQuality.getSelectedItem().toString()); } } @@ -177,7 +180,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe retriever.setDataSource(video_url); String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); long timeInMillisec = Long.parseLong(time); - return (int) timeInMillisec; + return (int) (timeInMillisec / 1000); } public Integer getVideoSizeInBytes(String video_url) { @@ -187,22 +190,22 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } // Fonction de conversion - public void encodeVideo(String video_url, String targetFileSize, String quality) { + 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 = Integer.parseInt(targetFileSize) * 1000 * 8; + targetFileSizeInKiloBit = targetFileSize * 1000 * 8; }else if(sizeUnit.getSelectedItem().toString().equals("MB")) { - targetFileSizeInKiloBit = Integer.parseInt(targetFileSize) * 1000 * 8; + targetFileSizeInKiloBit = targetFileSize * 1000 * 8; }else{ Toast.makeText(this, "Unité de taille \"" + sizeUnit.getSelectedItem().toString() + "\" non reconnue. M", Toast.LENGTH_SHORT).show(); } - // On va appliquer une marge de 10% à la taille cible - targetFileSizeInKiloBit = (int) targetFileSizeInKiloBit * 9 / 10; - Log.d("targetFileSizeInKiloBit", targetFileSizeInKiloBit.toString()); + //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 @@ -211,30 +214,124 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } // On va calculer le bitrate de la video en fonction de la bande son - Integer videoBitrate = (int) (targetFileSizeInKiloBit / videoDurationInSeconds) - audioBitrate; + 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(); + } - String outputFileName = video_url.substring(0, video_url.length() - 4) + "_" + targetFileSize + "_" + quality + ".mp4"; - String ffmpegCommand = "-i " + video_url + " -b:v " + videoBitrate + "k -c:a aac -b:a " + audioBitrate + "k " + outputFileName; - Log.d("FFMPEG", ffmpegCommand); + + // 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 session = FFmpegKit.execute(ffmpegCommand); - if (ReturnCode.isSuccess(session.getReturnCode())) { + 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(session.getReturnCode())) { + } else if (ReturnCode.isCancel(secondPass.getReturnCode())) { // CANCEL } else { // FAILURE - Log.d("Main", String.format("Command failed with state %s and rc %s.%s", session.getState(), session.getReturnCode(), session.getFailStackTrace())); - Toast.makeText(this, "Erreur lors de l'encodage de la vidéo", Toast.LENGTH_SHORT).show(); + 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); }