Welcome folks today in this blog post we will be seeing how to build mp4 video to mp3 audio
converter using MediaMuxer
class in java. All the full source code of the application is shown below.
Get Started
In order to get started you need to make a new android
project inside the android studio and then you will see the below directory
structure as shown below at the end
of the project.
Now we need to edit the AndroidManifest.xml
file and add the necessary permissions
for saving the mp3
file inside the external storage
and also we need to add the provider
tag as well as shown below
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.Mp4toMp3Project" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider> </application> </manifest> |
Here you need to replace your own package name
and structure and now we need to create this file_paths.xml
file inside the xml
directory which holds the path where we will be saving the mp3
files
xml/file_paths.xml
1 2 3 4 5 6 |
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="myapp" path="MyApp/Downloads" /> </paths> </paths> |
Editing the Main Layout
Now we need to edit the activity_main.xml
file for the project where we will have one button
to select the video
from the gallery as shown below.
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.mp4tomp3project.MainActivity"> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="89dp" android:text="Select Video" android:backgroundTint="@color/black" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.65" /> </androidx.constraintlayout.widget.ConstraintLayout> |
And now we need to edit the MainActivity.java
file and copy paste the following code
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
package com.example.mp4tomp3project; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.Manifest; import android.widget.Toast; import java.io.File; import java.io.IOException; public class MainActivity extends AppCompatActivity { private static final int REQUEST_PICK_VIDEO = 1; private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_READ_EXTERNAL_STORAGE); } } Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { pickVideoFromGallery(); } }); } private void pickVideoFromGallery() { Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI); intent.setType("video/mp4"); startActivityForResult(Intent.createChooser(intent, "Select Video"), REQUEST_PICK_VIDEO); } public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION_READ_EXTERNAL_STORAGE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission granted, you can now access files on external storage } else { // Permission denied, you cannot access files on external storage } } } @SuppressLint("WrongConstant") @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_PICK_VIDEO && resultCode == RESULT_OK && data != null) { Uri videoUri = data.getData(); try { File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "MyApp"); if (!dir.exists()) { dir.mkdirs(); } String fileName = "audio_" + System.currentTimeMillis() + ".mp3"; File outputFile = new File(dir, fileName); new AudioExtractor().genVideoUsingMuxer(videoUri.getPath(), outputFile.getPath(), -1, -1, true, false); Toast.makeText(this,"Mp3 Audio Created Successfully",Toast.LENGTH_LONG).show(); } catch (IOException e) { throw new RuntimeException(e); } } } } |
As you can see inside the java code we are using the AudioExtractor
class to basically convert the video
files that we select from the gallery to convert to mp3
audio files. And we are taking the permissions
at runtime from the user for android devices which are above 10
. And after that we are saving the mp3
audio files inside the external storage in the downloads
folder. And then we are showing the toast
message to the user that your mp3
file is generated successfully.
And now we need to create the AudioExtractor.java
class where we need to copy paste the below java
code as shown below
AudioExtractor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
package com.example.mp4tomp3project; import android.annotation.SuppressLint; import android.media.MediaCodec; import android.media.MediaExtractor; import android.media.MediaFormat; import android.media.MediaMetadataRetriever; import android.media.MediaMuxer; import android.util.Log; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; // Copyright (c) 2018 ArsalImam // All Rights Reserved // public class AudioExtractor { private static final int DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024; private static final String TAG = "AudioExtractorDecoder"; /** * @param srcPath the path of source video file. * @param dstPath the path of destination video file. * @param startMs starting time in milliseconds for trimming. Set to * negative if starting from beginning. * @param endMs end time for trimming in milliseconds. Set to negative if * no trimming at the end. * @param useAudio true if keep the audio track from the source. * @param useVideo true if keep the video track from the source. * @throws IOException */ @SuppressLint("NewApi") public void genVideoUsingMuxer(String srcPath, String dstPath, int startMs, int endMs, boolean useAudio, boolean useVideo) throws IOException { // Set up MediaExtractor to read from the source. MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(srcPath); int trackCount = extractor.getTrackCount(); // Set up MediaMuxer for the destination. MediaMuxer muxer; muxer = new MediaMuxer(dstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); // Set up the tracks and retrieve the max buffer size for selected // tracks. HashMap<Integer, Integer> indexMap = new HashMap<Integer, Integer>(trackCount); int bufferSize = -1; for (int i = 0; i < trackCount; i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); boolean selectCurrentTrack = false; if (mime.startsWith("audio/") && useAudio) { selectCurrentTrack = true; } else if (mime.startsWith("video/") && useVideo) { selectCurrentTrack = true; } if (selectCurrentTrack) { extractor.selectTrack(i); int dstIndex = muxer.addTrack(format); indexMap.put(i, dstIndex); if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) { int newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); bufferSize = newSize > bufferSize ? newSize : bufferSize; } } } if (bufferSize < 0) { bufferSize = DEFAULT_BUFFER_SIZE; } // Set up the orientation and starting time for extractor. MediaMetadataRetriever retrieverSrc = new MediaMetadataRetriever(); retrieverSrc.setDataSource(srcPath); String degreesString = retrieverSrc.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); if (degreesString != null) { int degrees = Integer.parseInt(degreesString); if (degrees >= 0) { muxer.setOrientationHint(degrees); } } if (startMs > 0) { extractor.seekTo(startMs * 1000, MediaExtractor.SEEK_TO_CLOSEST_SYNC); } // Copy the samples from MediaExtractor to MediaMuxer. We will loop // for copying each sample and stop when we get to the end of the source // file or exceed the end time of the trimming. int offset = 0; int trackIndex = -1; ByteBuffer dstBuf = ByteBuffer.allocate(bufferSize); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); muxer.start(); while (true) { bufferInfo.offset = offset; bufferInfo.size = extractor.readSampleData(dstBuf, offset); if (bufferInfo.size < 0) { Log.d(TAG, "Saw input EOS."); bufferInfo.size = 0; break; } else { bufferInfo.presentationTimeUs = extractor.getSampleTime(); if (endMs > 0 && bufferInfo.presentationTimeUs > (endMs * 1000)) { Log.d(TAG, "The current sample is over the trim end time."); break; } else { bufferInfo.flags = extractor.getSampleFlags(); trackIndex = extractor.getSampleTrackIndex(); muxer.writeSampleData(indexMap.get(trackIndex), dstBuf, bufferInfo); extractor.advance(); } } } muxer.stop(); muxer.release(); return; } } |
As you can see inside this java
code of the library we are using the MediaMuxer
class in the background to convert the input
video file to audio file.