The rest of the code is highlighted in the comments below. The errors I keep on encounting are: “Cannot resolve method MergeVideoClips”,”Cannot resolve Method AddAudio()”,
//I want to create a java activity in android studio studio java. I want to create an activity //that
//will allow the app to edit photos and videos as done in professional applications // like Premier
//Pro and Photoshop.
package com.example.self_editor;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.VideoView;
import android.widget.Toast;`
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import org.videolan.libvlc.LibVLC;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.arthenica.ffmpegkit.FFmpegKit;
import android.net.Uri;
public class VideoEditorActivity extends AppCompatActivity {
private static final int PICK_IMAGE_REQUEST = 1;
private static final int PICK_VIDEO_REQUEST = 2;
private static final int RETURN_CODE_SUCCESS = 0 ;
private VideoView videoView;
private ImageView imageView;
private Bitmap selectedImage;
private LibVLC libVLC;
private Uri currentVideoUri;
private static final int REQUEST_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_editor);
videoView = findViewById(R.id.videoView);
imageView = findViewById(R.id.imageView);
Button buttonSelectImage = findViewById(R.id.buttonSelectImage);
Button buttonSelectVideo = findViewById(R.id.buttonSelectVideo);
Button buttonApplyFilter = findViewById(R.id.buttonApplyFilter);
Button buttonAddText = findViewById(R.id.buttonAddText);
Button buttonCombineMedia = findViewById(R.id.buttonCombineMedia);
Button buttonAddAudio = findViewById(R.id.buttonAddAudio);
buttonSelectImage.setOnClickListener(v -> openImageChooser());
buttonSelectVideo.setOnClickListener(v -> openVideoChooser());
buttonApplyFilter.setOnClickListener(v -> applyVideoFilter());
buttonAddText.setOnClickListener(v -> addTextToImage());
buttonCombineMedia.setOnClickListener(v -> mergeVideoClips());
buttonAddAudio.setOnClickListener(v -> addAudio());
// This code is used toi call the various methods
ArrayList<String> options = new ArrayList<>();
options.add("--no-plugins-cache");
libVLC = new LibVLC(this, options);
}
// To request permissions.
private void requestPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_PERMISSIONS);
}
}
//To select Images
private void openImageChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "Select Image"), PICK_IMAGE_REQUEST);
}
// To choose videos
private void openVideoChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*");
startActivityForResult(Intent.createChooser(intent, "Select Video"), PICK_VIDEO_REQUEST);
}
// The implementation to get videos.
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null && data.getData() != null) {
Uri uri = data.getData();
if (requestCode == PICK_IMAGE_REQUEST) {
try {
selectedImage = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
imageView.setImageBitmap(selectedImage);
imageView.setVisibility(View.VISIBLE);
videoView.setVisibility(View.GONE);
} catch (IOException e) {
e.printStackTrace();
}
} else if (requestCode == PICK_VIDEO_REQUEST) {
currentVideoUri = uri; // Save the URI
videoView.setVideoURI(uri);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(videoView);
videoView.setMediaController(mediaController);
videoView.start();
videoView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
}
}
}
//Code that allows you to apply a filter over the video.
private void applyVideoFilter() {
if (videoView.isShown()) {
if (currentVideoUri != null) {
String inputPath = getPathFromUri(currentVideoUri);
String outputPath = getExternalFilesDir(null) + "/filtered_video.mp4";
String[] com= {
"-i", inputPath, // Input file
"-vf", "hue=s=0", // Video filter: hue=s=0 applies grayscale
"-c:a", "copy", // Copy the audio as is
outputPath // Output file
};
executeFFmpegCommand(com);
} else {
Toast.makeText(this, "No video selected", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Select a video first", Toast.LENGTH_SHORT).show();
}
}
// Code to get android permissions.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permissions granted
applyVideoFilter();
} else {
// Permissions denied
Toast.makeText(this, "Permissions denied", Toast.LENGTH_SHORT).show();
}
}
}
// Code to get information about the video
private String getPathFromUri(Uri uri) {
// Convert URI to file path
String[] projection = {MediaStore.Video.Media.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
return null;
}
//Code to add text to image.
private void addTextToImage() {
if (videoView.isShown() && currentVideoUri != null) {
String inputPath = getPathFromUri(currentVideoUri);
if (inputPath == null) {
Toast.makeText(this, "Unable to get video path", Toast.LENGTH_SHORT).show();
return;
}
String outputPath = getExternalFilesDir(null) + "/text_added_video.mp4";
String text = "Sample Text"; // Or get input from user
String[] cmd = {
"-i", inputPath,
"-vf", "drawtext=text='" + text + "':x=10:y=10:fontsize=24:fontcolor=white",
"-c:a", "copy",
outputPath
};
executeFFmpegCommand(cmd);
} else {
Toast.makeText(this, "No video selected or video not visible", Toast.LENGTH_SHORT).show();
}
}
// Code to merge video clips in one sequence.
private void mergeVideoClips(List<Uri> videoUris) {
StringBuilder concatFile = new StringBuilder();
for (Uri uri : videoUris) {
concatFile.append("file '").append(getPathFromUri(uri)).append("'n");
}
File fileList = new File(getExternalFilesDir(null), "concat_list.txt");
try (FileOutputStream fos = new FileOutputStream(fileList)) {
fos.write(concatFile.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
String outputPath = getExternalFilesDir(null) + "/merged_video.mp4";
String[] cmd = {
"-f", "concat",
"-safe", "0",
"-i", fileList.getAbsolutePath(),
"-c", "copy",
outputPath
};
executeFFmpegCommand(cmd);
}
// Code to add Audio.
private void addAudio(Uri videoUri, Uri audioUri) {
String videoPath = getPathFromUri(videoUri);
String audioPath = getPathFromUri(audioUri);
String outputPath = getExternalFilesDir(null) + "/video_with_audio.mp4";
String[] cmd = {
"-i", videoPath,
"-i", audioPath,
"-c:v", "copy",
"-c:a", "aac",
"-strict", "experimental",
outputPath
};
executeFFmpegCommand(cmd);
}private void mergeVideoClips(List<Uri> videoUris) {
StringBuilder concatFile = new StringBuilder();
for (Uri uri : videoUris) {
concatFile.append("file '").append(getPathFromUri(uri)).append("'n");
}
File fileList = new File(getExternalFilesDir(null), "concat_list.txt");
try (FileOutputStream fos = new FileOutputStream(fileList)) {
fos.write(concatFile.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
String outputPath = getExternalFilesDir(null) + "/merged_video.mp4";
String[] cmd = {
"-f", "concat",
"-safe", "0",
"-i", fileList.getAbsolutePath(),
"-c", "copy",
outputPath
};
executeFFmpegCommand(cmd);
}
//Code to implement FFmpegKit implementation.
private void executeFFmpegCommand(String[] cmd) {
FFmpegKit.executeAsync(String.join(" ", cmd), (executionId, returnCode) -> {
if (returnCode.equals("0")) {
Toast.makeText(this, "Operation completed successfully", Toast.LENGTH_SHORT).show();
// Handle post-processing if necessary
} else {
Toast.makeText(this, "Operation failed with return code: " + returnCode, Toast.LENGTH_SHORT).show();
}
});
}
}//(This is the java code )
I just do not know what to do. I can’t seem to find anything useful online. The code below is my xml file for the video editor activity.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/buttonSelectImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Image" />
<Button
android:id="@+id/buttonSelectVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Video" />
<Button
android:id="@+id/buttonApplyFilter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Apply Filter" />
<Button
android:id="@+id/buttonAddText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Text" />
<Button
android:id="@+id/buttonCombineMedia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Combine Media" />
<Button
android:id="@+id/buttonAddAudio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Audio" />
</LinearLayout>
</LinearLayout>
Th code below is my gradle app module.
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.self_editor'
compileSdk 31
defaultConfig {
applicationId "com.example.self_editor"
minSdk 30
targetSdk 31
versionCode 1
versionName "1.0"
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.31"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.activity:activity-ktx:1.2.4'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.github.zomato:android-libs:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'com.github.bumptop:videofilters:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'org.videolan.android:libvlc-all:3.4.4'
implementation 'com.arthenica:ffmpeg-kit-full:6.0-2'
}
New contributor
Nkosinathi Mathaba is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.