I am trying to trim an audio using mp4Parser.
Is that possible?
I tried ffmpeg which is quite time consuming.
Our app does require both video and audio processing.
Any suggestions on this?
ffmpeg is fast. What command did you use? maybe you made ffmpeg transcode, which is slow?
What about
fmpeg -i audiofile.mp3 -ss 3 -t 5 -acodec copy outfile.mp3
This remuxes starting from second 3 for 5 seconds into outfile.mp3, very fast.
Yes, possible with mp4Parser and FFMPEG also.
You have to use some command key for faster processing in FFMPEG.
You could take a look into this library :
k4l-video-trimmer
Yes its possible to trim audio with mp4parser.
It should be something like following
private CroppedTrack getCroppedTrack(Track track, int startTimeMs, int endTimeMs)
{
long currentSample = 0;
double currentTime = 0;
long startSample = -1;
long endSample = -1;
double startTime = startTimeMs / 1000;
double endTime = endTimeMs / 1000;
for (int i = 0; i < track.getSampleDurations().length; i++)
{
if (currentTime <= startTime)
{
// current sample is still before the new starttime
startSample = currentSample;
}
if (currentTime <= endTime) {
// current sample is after the new start time and still before the new endtime
endSample = currentSample;
}
else
{
// current sample is after the end of the cropped video
break;
}
currentTime += (double) track.getSampleDurations()[i] / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
return new CroppedTrack(track, startSample, endSample);
}
Use the above method to trim track/tracks as per your desired start and end points.
movie.addTrack(getCroppedTrack(track, 0, 8000));
Related
My original video is 10.3 seconds.
I want to start cutting from sec 2.7 to sec 5.7
public static void startTrim(#NonNull File src, #NonNull String dst, long startMs, long endMs, #NonNull OnTrimVideoListener callback) throws IOException {
final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
final String fileName = "MP4_" + timeStamp + ".mp4";
final String filePath = dst;
File file = new File(filePath);
file.getParentFile().mkdirs();
Log.d(TAG, "Generated file path " + filePath);
genVideoUsingMp4Parser(src, file, startMs, endMs, callback);
}
private static void genVideoUsingMp4Parser(#NonNull File src, #NonNull File dst, long startMs, long endMs, #NonNull OnTrimVideoListener callback) throws IOException {
// NOTE: Switched to using FileDataSourceViaHeapImpl since it does not use memory mapping (VM).
// Otherwise we get OOM with large movie files.
Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
// remove all tracks we will create new tracks from the old
double startTime1 = startMs ; //2.7
double endTime1 = endMs, //5.7
boolean timeCorrected = false;
// Here we try to find a track that has sync samples. Since we can only start decoding
// at such a sample we SHOULD make sure that the start of the new fragment is exactly
// such a frame
for (Track track : tracks) {
if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
if (timeCorrected) {
// This exception here could be a false positive in case we have multiple tracks
// with sync samples at exactly the same positions. E.g. a single movie containing
// multiple qualities of the same video (Microsoft Smooth Streaming file)
throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
}
startTime1 = correctTimeToSyncSample(track, startTime1, false);
endTime1 = correctTimeToSyncSample(track, endTime1, true);
timeCorrected = true;
}
}
for (Track track : tracks) {
long currentSample = 0;
double currentTime = 0;
double lastTime = -1;
long startSample1 = -1;
long endSample1 = -1;
for (int i = 0; i < track.getSampleDurations().length; i++) {
long delta = track.getSampleDurations()[i];
if (currentTime > lastTime && currentTime <= startTime1) {
// current sample is still before the new starttime
startSample1 = currentSample;
}
if (currentTime > lastTime && currentTime <= endTime1) {
// current sample is after the new start time and still before the new endtime
endSample1 = currentSample;
}
lastTime = currentTime;
currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
movie.addTrack(new AppendTrack(new CroppedTrack(track, startSample1, endSample1)));
}
dst.getParentFile().mkdirs();
if (!dst.exists()) {
dst.createNewFile();
}
Container out = new DefaultMp4Builder().build(movie);
FileOutputStream fos = new FileOutputStream(dst);
FileChannel fc = fos.getChannel();
out.writeContainer(fc);
fc.close();
fos.close();
if (callback != null)
callback.getResult(Uri.parse(dst.toString()));
}
But after the method correctTimeToSyncSample is finished the startTime1 gets value 2.08... and endTime1 gets value 5.18...
startTime1 = 2.0830555555555557
endTime1 = 5.182877777777778
private static double correctTimeToSyncSample(#NonNull Track track, double cutHere, boolean next) {
double[] timeOfSyncSamples = new double[track.getSyncSamples().length];
long currentSample = 0;
double currentTime = 0;
for (int i = 0; i < track.getSampleDurations().length; i++) {
long delta = track.getSampleDurations()[i];
if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) {
// samples always start with 1 but we start with zero therefore +1
timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;
}
currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
double previous = 0;
for (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
if (next) {
return timeOfSyncSample;
} else {
return previous;
}
}
previous = timeOfSyncSample;
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
The video is successfully saved but not in the exact time I wanted..
Can anyone please help me with this
Video can only be cut at keyframes (called sync samples in mp4). A key frame is uasually every 1 to 10 seconds. To get an exact frame, you need to transcode using a tool like ffmpeg.
You can add edts/elst/stss/stsh/sdtp box to do it.
add edts/elst box to indicate the media-time and segment-duration, for your case, media-time of 'elst' box is set to the media time of 2.7s, and segment duration is set to 3 seconds with the unit of time-scale of movie.
Of course, you need add Sync Sample box, Shadow Sync Sample Box and Independent and Disposable Samples Box, to specify the dependency of your first frame if it is not a key frame.
The qualified mp4 player will find the dependent sync sample before the frame at your start time, and decode all of frames edited out by means of an edit list which is used for decoding your first dependent frame, but not to present them until the first frame you specified.
To learn android I'm making a tamagotchi like app. Its food lvl decreases 1 every hour so if you dont feed it for some hours it dies. I also have that between 8pm and 8am its asleep. Only there is a problem. To change its state to sleeping you need to open the app between 8pm and 8am. That gives the following problem:
If you feed it, lets say at 7pm, 1 hour before it sleeps, and you dont open the app between 8pm and 8 am but at 9am the following day he thinks 13 hours have elapsed instead of 1 (he shouldnt count the sleeping hours) Do you guys ahve any tips?
this is the sleepy and decay code
public void checkSleepyTime()
{
c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int daypart = c.get(Calendar.AM_PM);
if (hour >= 20 && daypart == 1)
{
foodButton.setText("ZZzz");
prefs.edit().remove("foodTime").commit();
buddy.setSleeping(true);
}
else
{
foodButton.setText("Awake");
buddy.setSleeping(false);
}
}
.
public void initBuddy()
{
debugView.setText("FoodLevel: " + buddy.getFoodLevel());
if(!buddy.getSleeping() && buddy.getAlive())
{
long currentTime = prefs.getLong("currentTime", getCurentTime());
long foodTime = prefs.getLong("foodTime", getCurentTime());
while (foodTime < currentTime)
{
if (currentTime - foodTime >= ONE_HOUR)
{
buddy.decayFood();
}
foodTime = foodTime + ONE_HOUR;
}
}
If the time since last feeding is longer than sleep time, check if the expected sleep period falls into that time. Then act accordingly (quick hack would be to add the sleep time to the time of last feeding). Also check if more than one day has passed since the feed time. Something like this:
if (currentTime - foodTime >= ONE_HOUR)
{
if (currentTime - foodTime >= WHOLE_NIGHT && sleepPeriodFitsInBetween(foodTime, currentTime))
{
foodTime+=WHOLE_NIGHT;
int numberOfFullDays=countNumberOfDays(currentTime - foodTime);
if(numberOfFullDays>1)
{
currentTime+=numberOfFullDays*(24-WHOLE_HIGHT); // assuming WHOLE_NIGHT is in hours.
}
}
...
}
I now have the following two methods that get the current time and the close time (saved in onStop();) and i converted it to days/weeks/months/years. I want to check how many nights there are between the closeTIme and the currentTIme but I'm not sure what to do with the info. Can anyone point me in the right direction ?
public void checkSleepTimes()
{
closeCalendar = timeHelper.convertLongToCal(loadCloseTime());
closeArray = loadDateArrayList(closeArray, closeCalendar);
currentCalendar = timeHelper.convertLongToCal(getCurentTime());
closeArray = loadDateArrayList(currentArray, currentCalendar);
long curTime = getCurentTime();
int times = 0;
long totalSleepTime = 0;
while (closeTime < curTime)
{
closeTime = closeTime + WHOLE_DAY;
times ++;
}
//TODO Check how many times it was between 08:00 and 20:00
totalSleepTime = SLEEP_TIME * times; // not sure if correct approach
}
public ArrayList loadDateArrayList(ArrayList arrayList, Calendar calendar)
{
arrayList.add(0,calendar.DATE);
arrayList.add(1,calendar.WEEK_OF_YEAR);
arrayList.add(2,calendar.MONTH);
arrayList.add(3,calendar.YEAR);
return arrayList;
}
How to get mp3 track duration without creating MediaPlayer instance? I just need to show mp3 song length in mp3 file list, so I think that I shouldn't create MediaPlayer object for each of tracks in the list
And another:
sometimes MediaPlayer returns wrong duration of the song ( I think its so because bitrate of those files is dinamic ). How can I get right duration of the song?
// load data file
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(filePath);
String out = "";
// get mp3 info
// convert duration to minute:seconds
String duration =
metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
Log.v("time", duration);
long dur = Long.parseLong(duration);
String seconds = String.valueOf((dur % 60000) / 1000);
Log.v("seconds", seconds);
String minutes = String.valueOf(dur / 60000);
out = minutes + ":" + seconds;
if (seconds.length() == 1) {
txtTime.setText("0" + minutes + ":0" + seconds);
}else {
txtTime.setText("0" + minutes + ":" + seconds);
}
Log.v("minutes", minutes);
// close object
metaRetriever.release();
You can use the MediaMetadataRetriever to get the duration of a song. Use the METADATA_KEY_DURATION in combination with the extractMetadata() funciton.
Here is the Kotlin version:
var metaRetriever:MediaMetadataRetriever = MediaMetadataRetriever()
metaRetriever.setDataSource(filePath)
var out:String = ""
var txtTime:String = ""
var duration:String = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
Log.d("DURATION VALUE", duration)
var dur:Long = duration.toLong()
var seconds:String = ((dur % 60000)/1000).toString()
Log.d("SECONDS VALUE", seconds)
var minutes:String = (dur / 60000).toString()
out = minutes + ":" + seconds
if (seconds.length == 1){
txtTime = "0" + minutes + ":0" + seconds
}
else {
txtTime = "0" + minutes + ":" + seconds
}
Log.d("MINUTES VALUE", minutes)
Log.d("FORMATTED TIME", txtTime)
metaRetriever.release()
If you want to support older Android versions, you can use a 3rd party library. For example http://www.jthink.net/jaudiotagger/ works fine, though it's relatively space consuming for an Android application (a little less than 1 MB).
True programmers would of course parse the duration from the binary file without using any libraries ;) I didn't have enough skill for this.
I found this more accurate getLength with FFmpeg
int soundLength = (int) new SoxController(context, new File(""), shell).getLength(soundPath);
I'm looking for Android code to do a digital timer display that looks like one of the standard timers that came (I think) with some HTC phones. The timer look is different than most in that it uses digits but has a mechanical scroll wheel look, as if the numbers were painted on a roller. It does not mimic an LED timer nor does it mimic a mechanic "flip" type digital timer. It may need graphic files to work.
There is code on googlesource that seems it may have what I want. But I can't find any index that has images of the code running. And it is not always easy (for me) to get the code running so I can see what it looks like. Some code that looks promising is the following:
(https://android.googlesource.com/device/htc/common/)
http://st.gsmarena.com/vv/reviewsimg/htc-droid-incredible-4g-lte/sshots/gsmarena_109.jpg">Link to image</a>">
See http://code.google.com/p/android-wheel/
You might be able to adapt it for your needs.
Here's code provided by a previous user:
private Handler mHandler = new Handler();
OnClickListener mStartListener = new OnClickListener()
{
public void onClick(View v)
{
if (mStartTime == 0L)
{
mStartTime = System.currentTimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}
}
};
.........
private Runnable mUpdateTimeTask = new Runnable()
{
public void run()
{
final long start = mStartTime;
long millis = SystemClock.uptimeMillis() - start;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
if (seconds < 10)
{
mTimeLabel.setText("" + minutes + ":0" + seconds);
}
else
{
mTimeLabel.setText("" + minutes + ":" + seconds);
}
mHandler.postAtTime(this,start + (((minutes * 60) + seconds + 1) * 1000));
}
};
https://stackoverflow.com/users/559090/khawar
How to get mp3 track duration without creating MediaPlayer instance? I just need to show mp3 song length in mp3 file list, so I think that I shouldn't create MediaPlayer object for each of tracks in the list
And another:
sometimes MediaPlayer returns wrong duration of the song ( I think its so because bitrate of those files is dinamic ). How can I get right duration of the song?
// load data file
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(filePath);
String out = "";
// get mp3 info
// convert duration to minute:seconds
String duration =
metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
Log.v("time", duration);
long dur = Long.parseLong(duration);
String seconds = String.valueOf((dur % 60000) / 1000);
Log.v("seconds", seconds);
String minutes = String.valueOf(dur / 60000);
out = minutes + ":" + seconds;
if (seconds.length() == 1) {
txtTime.setText("0" + minutes + ":0" + seconds);
}else {
txtTime.setText("0" + minutes + ":" + seconds);
}
Log.v("minutes", minutes);
// close object
metaRetriever.release();
You can use the MediaMetadataRetriever to get the duration of a song. Use the METADATA_KEY_DURATION in combination with the extractMetadata() funciton.
Here is the Kotlin version:
var metaRetriever:MediaMetadataRetriever = MediaMetadataRetriever()
metaRetriever.setDataSource(filePath)
var out:String = ""
var txtTime:String = ""
var duration:String = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
Log.d("DURATION VALUE", duration)
var dur:Long = duration.toLong()
var seconds:String = ((dur % 60000)/1000).toString()
Log.d("SECONDS VALUE", seconds)
var minutes:String = (dur / 60000).toString()
out = minutes + ":" + seconds
if (seconds.length == 1){
txtTime = "0" + minutes + ":0" + seconds
}
else {
txtTime = "0" + minutes + ":" + seconds
}
Log.d("MINUTES VALUE", minutes)
Log.d("FORMATTED TIME", txtTime)
metaRetriever.release()
If you want to support older Android versions, you can use a 3rd party library. For example http://www.jthink.net/jaudiotagger/ works fine, though it's relatively space consuming for an Android application (a little less than 1 MB).
True programmers would of course parse the duration from the binary file without using any libraries ;) I didn't have enough skill for this.
I found this more accurate getLength with FFmpeg
int soundLength = (int) new SoxController(context, new File(""), shell).getLength(soundPath);