In my android application i am downloading Facebook video and audio separately and merging it in an output file. The reason is Facebook videos URLs have no sound and audio URL is separate. I have tried using this mp4Parser for merging audio and video and it works pretty well in most of devices but having issues in Redmi/MI devices when playing from device files.
Steps i followed
- Download NO SOUND Video in mp4 format.
- Download audio in m4a format.
- Merge both files and create an output file with mp4 format.
- After merging is done deleted no sound video and temporary audio.
Below is my code
Dependencies
implementation 'com.iceteck.silicompressorr:silicompressor:2.2.4'
implementation('com.googlecode.mp4parser:isoparser:1.0.6') {
exclude group: 'org.aspectj', module: 'aspectjrt'
}
Merging code
private fun mergeAudioAndVideo(
id: Int,
model: DatabaseDownloadItem?,
file: File?,
activityInstance: LocaleAwareCompatActivity?
) {
val mergingDetail = sharedPreferencesManager.getItemInMergingList(id)
if (mergingDetail != null) {
val timeInMillis = System.currentTimeMillis()
var list: ArrayList<DatabaseDownloadItem>? = sharedViewmodel.pendingMerge.value
if (list == null) {
list = arrayListOf()
}
list.add(model!!)
sharedViewmodel.pendingMerge.postValue(list)
sharedViewmodel.pendingMerge.value?.add(model!!)
CoroutineScope(Dispatchers.Main).launch {
var mergePendingItems: ArrayList<Int>? =
tinyDB?.getMergeList(AppConstants.MERGE_PENDING_DOWNLOADS)
if (mergePendingItems == null) {
mergePendingItems = arrayListOf()
}
if (!mergePendingItems.contains(model.id)) {
mergePendingItems.add(model.id)
}
tinyDB?.putMergeList(AppConstants.MERGE_PENDING_DOWNLOADS, mergePendingItems)
adapter.notifyDataSetChanged()
CoroutineScope(Dispatchers.IO + exceptionHandler).async {
val audiopath = mergingDetail.audioPath
val videopath = mergingDetail.videoPath
/*
following comment is kept for reference
val audiopath = "/storage/emulated/0/VideoDownloader/tempAudio_1643715180488.m4a"
val videopath = "/storage/emulated/0/VideoDownloader/1643715180480.mp4"*/
val output: String
val outputName = "output_${mergingDetail.originalFileName}"
mergingDetail.outputFileName = outputName
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val file = File(
getDownloaderFolderFromDownloads(),
"$outputName.mp4"
)
output = file.absolutePath
mergingDetail.outputFile = file
} else {
val file = File(
Environment.getExternalStorageDirectory()
.toString() + "/VideoDownloader/",
"$outputName.mp4"
)
output = file.absolutePath
mergingDetail.outputFile = file
}
var videoOutput: Movie? = null
var audioOutput: Movie? = null
kotlin.runCatching {
videoOutput = MovieCreator.build(videopath)
audioOutput = MovieCreator.build(audiopath)
}
val finalTrack: MutableList<Track> = ArrayList()
for (track in videoOutput?.tracks!!) {
if (track.handler.equals("vide")) finalTrack.add(track)
}
for (track in audioOutput?.tracks!!) {
if (track.handler.equals("soun")) finalTrack.add(track)
}
videoOutput?.tracks = finalTrack
val mp4file: Container = DefaultMp4Builder().build(videoOutput)
kotlin.runCatching {
val fc: FileChannel = FileOutputStream(File(output)).getChannel()
mp4file.writeContainer(fc)
fc.close()
}.onFailure { error ->
val abc = error
}.onSuccess { someFuncReturnValue ->
val abc = "dss"
}
}.await()
Toast.makeText(activityInstance, "Audio Video Merging Done", Toast.LENGTH_SHORT)
.show()
mergingDetail.isMergingDone = true
sharedPreferencesManager.updateItemInMergingList(id, mergingDetail)
executeDownloadCompletion(model, file, activityInstance)
deleteTempAudioFile(File(mergingDetail.audioPath!!), activityInstance)
deleteOldMutedVideo(File(mergingDetail.videoPath!!), activityInstance)
renameOutputFileWithDBName(mergingDetail, activityInstance)
var list: ArrayList<DatabaseDownloadItem>? = sharedViewmodel.pendingMerge.value
if (list != null && list!!.size > 0) {
list!!.remove(model!!)
sharedViewmodel.pendingMerge.postValue(list)
sharedViewmodel.pendingMerge.value?.add(model!!)
}
notificationWork(model, file, activityInstance)
sharedPreferencesManager.deleteItemInMergingList(id)
}
}
}
This works fine in most of devices but in MI Devices (i.e Redmi S2, MUI Version MUI Global 12.0.2) i am having an issue while playing the output file its corrupted and cannot be played. The error which shows up is just with title unknown.
Please note that i have also tried the following combination of dependencies, but this was generating lags in output file so removed these two.
implementation 'org.mp4parser:isoparser:1.9.41'
implementation 'org.mp4parser:muxer:1.9.41
Can somebody please suggest the proper usgae and dependency version of mp4parser for merging audio file and video file.
Any help will be appreciated.
Thank you
Use FFmpeg library and it will do all the job. You just have to provide a Facebook Audio and Video link and the storage path of your directory which you will get through File API. It will download the audio and video and then merge them.
This simple command will do all the magic.