Android sdk cut/trim video file
Asked Answered
H

6

18

Is there any way to cut a video (mp4 or 3gp) on android, like use only the last 5 seconds of the movie... on iphone this is possible using the AVAssetExportSession but on android I haven't found anything similar, just maybe some references to ffmpeg library which seems complicated. Is there any easier way to do it?

Hypochondriac answered 26/6, 2012 at 10:24 Comment(1)
A
15

You can do this with my mp4parser library. Have a look at the ShortenExample it does exactly what the name suggests. Since the library cannot re-encode the video it can only cut the video at I-frames. So the points in time where you can make a cut are quite coarse.

On Android 4.1 you can access the hardware codecs via MediaCodec API which could be an option (but I haven't seen any example of that yet)

Armes answered 18/7, 2012 at 23:8 Comment(13)
Is this only for mp4 files or does it work for other extensions? and where can I find the ShortenExample link?Hypochondriac
3gp files are basically MP4 files with some minor restrictions. My lib also works on 3gpp (and quicktime) files but not on other containers like avi or mkv.Armes
I need a general available library that should work with all the video formats the android phone can save, like mp4, 3gp, mkv maybe :(Hypochondriac
Also is your library able to merge several files into one as well or just trim the videos?Hypochondriac
You can merge files that have been recorded with the same encoder settings. As I told you in my previous comment 3gp and mp4 are supported. Can Android save mkv? To my knowledge this is a no. There is no general library except perhaps the whole ffmpeg with libav stack. But seriously - you don't want to go there on a phone.Armes
Also what android SDK is the minimum for this library?Hypochondriac
It's pure Java and not relying on any Android SDK specific functionality.Armes
I made Android application TestMp4parser with mp4parser's AppendExample and ShortenExample.Faery
@dadachi I want to provide facility to user to cut video from XYZ min to XYZ min timeline of video..Can i implement this facility using your libraryMithridatism
@dadachi hello i download your project and i got one error in pom file...error is something lifecycle ..can you please guide me to install your project in eclipse..i install m2e and m2e connector but still i got errorMithridatism
when I trim the portrait video it displays in landscape mode and the video rotation also changes.can u please help me to how to do this?Kenney
@dadachi: I downloaded the example. What .jar files are u including in your projectRubious
@prasanth you might go to the trouble of reading what's written on googlecode. It indicates that the project moved to github. Using google helps too - try "mp4parser" -> 1st hitArmes
B
9

We can cut video using ffmpeg in Android.

For integrating FFmpeg in android we can use precompiled libraries like ffmpeg-android.

To cut a video with re-encoding ,we can use below command-

String[] complexCommand = {"-ss", "" + startMs / 1000, "-y", "-i", inputFileAbsolutePath, "-t", "" + (endMs - startMs) / 1000, "-s", "320x240", "-r", "15", "-vcodec", "mpeg4", "-b:v", "2097152", "-b:a", "48000", "-ac", "2", "-ar", "22050", outputFileAbsolutePath};

Below mentioned that which command is work for what.

-ss seeks to position

-y Overwrite output files without asking.

-i FFmpeg reads from an arbitrary number of input “files” specified by the -i option

-t Limit the duration of data read from the input file

-s Video output size

-r Set frame rate

-vcodec Set the video codec.

-b:v Set the video bitrate

-b:a Set the audio bitrate

-ac Set the number of audio channels.

-ar Sets the sampling rate for audio streams if encoded

startMs Start time of video in milliseconds from where you want to cut

endMs end time of video in milliseconds up to which you want to cut

To cut a video without re-encoding ,we can use below command-

String[] complexCommand = { "-y", "-i", inputFileAbsolutePath,"-ss", "" + startMs / 1000, "-t", "" + (endMs - startMs) / 1000, "-c","copy", outputFileAbsolutePath};

Here,

"-c", "copy" copies the video, audio and bit stream from the input to the output file without re-encoding them.

I have created a sample android project on editing videos using FFMpeg which includes cutting video.Check it out-

https://github.com/bhuvnesh123/FFmpeg-Video-Editor-Android

and its tutorial at-

https://androidlearnersite.wordpress.com/2017/03/17/ffmpeg-video-editor/

Bartolome answered 20/3, 2017 at 6:21 Comment(7)
Thanks for the detailed answer. Could you please confirm if all these commands(i.e. -ar, -ac, -b:v, -b:a etc) are mandatory for trimming the video?Filch
hi is there a way to split the file faster? it takes too long to split.Lechner
@Lechner FFmpeg provides certain presets which are collection of options that provide certain speed to the process. Presets in descending order of speed are: ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow. The default preset is medium.Utrafast preset is specially useful where command is taking too much time to execute and you want to speed up the process.To use preset just add “-preset”, “ultrafast” to the command.Bartolome
@Filch No these command are not mandatory and are used for reencoding.To cut video without reencoding you can just use- {"-i", inputFileAbsolutePath,"-ss", "" + startMs / 1000, "-t", "" + (endMs - startMs) / 1000, "-c","copy", outputFileAbsolutePath}Bartolome
@SiddarthG It depends what you want to do or show user when editing operation fails!Bartolome
thanks bro, i resolved this by using ultrafast. parameter.Lechner
does the job but after adding the library(ffmpeg-andoid) the apk size after shrinking is 70mbs, who is going to download my 70mbs app the simply cuts videos yet there are 2mbs apps the do the same job on playstoreExclamatory
I
5

try this

Intent trimVideoIntent = new Intent("com.android.camera.action.TRIM");

// The key for the extra has been discovered from com.android.gallery3d.app.PhotoPage.KEY_MEDIA_ITEM_PATH
trimVideoIntent.putExtra("media-item-path",FilePath);
trimVideoIntent.setData(videoUri);

// Check if the device can handle the Intent
List<ResolveInfo> list = getPackageManager().queryIntentActivities(trimVideoIntent, 0);
if (null != list && list.size() > 0) {
    startActivity(trimVideoIntent); // Fires TrimVideo activity into being active
}else {
    Toast.makeText(this, "not supported",Toast.LENGTH_SHORT).show();
}

its work on Gallery2 package installed devices

Induct answered 16/9, 2014 at 12:39 Comment(0)
W
5

You can use MediaCodec API in android.

import android.media.MediaCodec.BufferInfo
import android.media.MediaExtractor
import android.media.MediaFormat
import android.media.MediaMetadataRetriever
import android.media.MediaMuxer
import java.io.IOException
import java.nio.ByteBuffer
import android.os.Handler
import android.os.Looper


class VideoUtils {
    companion object {
        /**
         * @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
         */
        @Throws(IOException::class)
        fun startTrim(
            srcPath: String, dstPath: String,
            startMs: Int, endMs: Int, useAudio: Boolean, useVideo: Boolean,
            listener: Listener
        ) {
            runOnUiThread {
                listener.onStart()
            }
            // Set up MediaExtractor to read from the source.
            val extractor = MediaExtractor()
            extractor.setDataSource(srcPath)
            val trackCount = extractor.trackCount
            // Set up MediaMuxer for the destination.
            val muxer = MediaMuxer(dstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
            // Set up the tracks and retrieve the max buffer size for selected
            // tracks.
            val indexMap = HashMap<Int, Int>(trackCount)
            var bufferSize = -1
            for (i in 0 until trackCount) {
                val format = extractor.getTrackFormat(i)
                val mime = format.getString(MediaFormat.KEY_MIME)
                var selectCurrentTrack = false
                if (mime!!.startsWith("audio/") && useAudio) {
                    selectCurrentTrack = true
                } else if (mime.startsWith("video/") && useVideo) {
                    selectCurrentTrack = true
                }
                if (selectCurrentTrack) {
                    extractor.selectTrack(i)
                    val dstIndex = muxer.addTrack(format)
                    indexMap[i] = dstIndex
                    if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
                        val newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
                        bufferSize = if (newSize > bufferSize) newSize else bufferSize
                    }
                }
            }
            if (bufferSize < 0) {
                bufferSize = DEFAULT_BUFFER_SIZE
            }
            // Set up the orientation and starting time for extractor.
            val retrieverSrc = MediaMetadataRetriever()
            retrieverSrc.setDataSource(srcPath)
            val degreesString = retrieverSrc.extractMetadata(
                MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION
            )
            if (degreesString != null) {
                val degrees = degreesString.toInt()
                if (degrees >= 0) {
                    muxer.setOrientationHint(degrees)
                }
            }
            if (startMs > 0) {
                extractor.seekTo((startMs * 1000).toLong(), 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.
            val offset = 0
            var trackIndex: Int
            val dstBuf = ByteBuffer.allocate(bufferSize)
            val bufferInfo = BufferInfo()
            val totalTimeMs = endMs - startMs
            try {
                muxer.start()
                while (true) {
                    bufferInfo.offset = offset
                    bufferInfo.size = extractor.readSampleData(dstBuf, offset)
                    if (bufferInfo.size < 0) {
                        runOnUiThread {
                            listener.onComplete()
                        }
                        bufferInfo.size = 0
                        break
                    } else {
                        bufferInfo.presentationTimeUs = extractor.sampleTime
                        if (endMs > 0 && bufferInfo.presentationTimeUs > endMs * 1000) {
                            runOnUiThread {
                                listener.onComplete()
                            }
                            break
                        } else {
                            bufferInfo.flags = extractor.sampleFlags
                            trackIndex = extractor.sampleTrackIndex
                            muxer.writeSampleData(
                                indexMap[trackIndex]!!, dstBuf,
                                bufferInfo
                            )
                            runOnUiThread {
                                listener.onProgress((bufferInfo.presentationTimeUs / 1000 - startMs).toFloat() / totalTimeMs)
                            }
                            extractor.advance()
                        }
                    }
                }
                muxer.stop()
            } catch (e: IllegalStateException) {
                runOnUiThread {
                    listener.onError("The source video file is malformed")
                }
            } finally {
                muxer.release()
            }
            return
        }
    }

    interface Listener {
        fun onStart()
        fun onProgress(value: Float)
        fun onComplete()
        fun onError(message: String)
    }
}

private val mHandler = Handler(Looper.getMainLooper())

fun runOnUiThread(closure: () -> Unit) {
    mHandler.post {
        closure()
    }
}

References: https://android.googlesource.com/platform/packages/apps/Gallery2/+/refs/heads/master/src/com/android/gallery3d/app/VideoUtils.java

Wallie answered 20/6, 2021 at 16:41 Comment(0)
O
1

You can try INDE Media for Mobile - https://software.intel.com/en-us/articles/intel-inde-media-pack-for-android-tutorials

It has transcoding\remuxing functionality as MediaComposer class and a possibility to select segments for resulted files. Since it uses MediaCodec API inside it is very battery friendly and works as fast as possible

enter image description here

Oilskin answered 15/1, 2015 at 12:23 Comment(0)
M
1

Use this Android-video-trimmer android library.which is using Exoplayer2 and FFmpeg for video trimming

Money answered 20/7, 2020 at 8:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.