Split video into smaller timed segments in Java - java

I am looking to take a large video files (3hours+) and pass in segments of the video that I would like to split.
For example, I could pass in a 3 hour video - and want from 00:10 to 00:11 to be split into a separate file.
I currently have the below code - that takes my video and splits it into a split no. of segments, but how would I go about splitting the video by time instead?
Code:
try {
File file = new File("//Users//robeves//Desktop//Videos to split//TestVideo.mp4");//File read from Source folder to Split.
if (file.exists()) {
String videoFileName = file.getName().substring(0, file.getName().lastIndexOf(".")); // Name of the videoFile without extension
File splitFile = new File("//Users//robeves//Desktop//Videos to split//Converted//"+ videoFileName);//Destination folder to save.
if (!splitFile.exists()) {
splitFile.mkdirs();
System.out.println("Directory Created -> "+ splitFile.getAbsolutePath());
}
int i = 01;// Files count starts from 1
InputStream inputStream = new FileInputStream(file);
String videoFile = splitFile.getAbsolutePath() +"/"+ String.format("%02d", i) +"_"+ file.getName();// Location to save the files which are Split from the original file.
OutputStream outputStream = new FileOutputStream(videoFile);
System.out.println("File Created Location: "+ videoFile);
int totalPartsToSplit = 20;// Total files to split.
int splitSize = inputStream.available() / totalPartsToSplit;
int streamSize = 0;
int read = 0;
while ((read = inputStream.read()) != -1) {
if (splitSize == streamSize) {
if (i != totalPartsToSplit) {
i++;
String fileCount = String.format("%02d", i); // output will be 1 is 01, 2 is 02
videoFile = splitFile.getAbsolutePath() +"/"+ fileCount +"_"+ file.getName();
outputStream = new FileOutputStream(videoFile);
System.out.println("File Created Location: "+ videoFile);
streamSize = 0;
}
}
outputStream.write(read);
streamSize++;
}
inputStream.close();
outputStream.close();
System.out.println("Total files Split ->"+ totalPartsToSplit);
} else {
System.err.println(file.getAbsolutePath() +" File Not Found.");
}
} catch (Exception e) {
e.printStackTrace();
}
}

If you do want to be able to play the segments individually, then the above code may not work if it is just splitting the file at arbitrary points, as many video formats need to finish on a good 'boundary' to enable proper playback.
As Binkan suggests, using a video library like ffmpeg, either in cmd line, wrapped cmd line or by using its associated C libraries, will allow you safely split a video in most common formats.
For example the following ffmpeg cmd line will create a segment from an mp4 video:
ffmpeg -i inputVideo.mp4 -ss 00:00:00 -t 00:00:10 -c copy outputVideoSegment.mp4
The following code uses this utility in a 'wrapper' to segment a video file into chunks:
int chunkSize = videoDurationSecs/(numberOfChunks + 1);
int startSecs = 0;
for (int i=0; i<numberOfChunks; i++) {
//Create video chunk
String startTime = convertSecsToTimeString(startSecs);
int endSecs = startSecs + ((i+1)*chunkSize);
if (endSecs > videoDurationSecs) {
//make sure rounding does not mean we go beyond end of video
endSecs = videoDurationSecs;
}
String endTime = convertSecsToTimeString(endSecs);
//Call ffmpeg to create this chunk of the video using a ffmpeg wrapper
String argv[] = {"ffmpeg", "-i", videoPath,
"-ss",startTime, "-t", endTime,
"-c","copy", segmentVideoPath[i]};
int ffmpegWrapperReturnCode = ffmpegWrapper(argv);
}
String convertSecsToTimeString(int timeSeconds) {
//Convert number of seconds into hours:mins:seconds string
int hours = timeSeconds / 3600;
int mins = (timeSeconds % 3600) / 60;
int secs = timeSeconds % 60;
String timeString = String.format("%02d:%02d:%02d", hours, mins, secs);
return timeString;
}
Examples of wrappers are here, but you can also use the ffmpeg libraries directly if you would rather avoid the wrapper approach (which does have the disadvantage that ffmpeg cmd line is not really intended to be wrapped in this way):
http://www.sauronsoftware.it/projects/jave/
https://github.com/jhotovy/android-ffmpeg (Android based)

Related

How two find unique difference between to files in Java and print their line numbers?

I have to text files and I want to print the line numbers where the contents of the second file is modified?
file 1:
1/ hi
2/
3/
4/ start
5/ {
6/
7/ while(){
8/ }
9/ }
file 2:
1/ hi
2/
3/
4/
5/ start
6/
7/
8/ {
9/ if(
10/ while(){
11/ }
12/ }.
The output should be: 9 (as an extra if is added in the file 2). Note, there might be unnecessary tabs and newlines.Can anyone help me with this problem?
import java.util.Scanner;
//convert a file into a file_simple form
File simplified(String src , String srcPath , String name) throws FileNotFoundException{
File fileSrc = new File(src);
File fileDest = new File(srcPath + "\\" + name + "_simple");
Scanner scSrc = new Scanner(fileSrc);
PrintWriter pw = new PrintWriter(fileDest);
while(scSrc.hasNextLine()) {
String take = scSrc.nextLine();
if(take.equals("")) {
continue;
}
String take1 = take.trim();
pw.println(take1);
}
pw.close();
scSrc.close();
return fileDest;
}
//write what difference the second file has
void differenceInTwoFiles(File file1 , File file2 , String logPath , String UserName) throws FileNotFoundException {
File file1Simple = simplified(file1.getAbsolutePath() , file1.getParentFile().getAbsolutePath() , file1.getName());
File file2Simple = simplified(file2.getAbsolutePath() , file2.getParentFile().getAbsolutePath() , file2.getName());
System.out.println(file2.getAbsolutePath() +" " + file2.getParentFile().getAbsolutePath() +" "+ file2.getName());
File log = new File(logPath);
PrintWriter pwLog = new PrintWriter(log);
Scanner scF1 = new Scanner(file1Simple);
Scanner scF2 = new Scanner(file2Simple);
while(scF1.hasNextLine() && scF2.hasNextLine()) {
String first = scF1.nextLine();
String second = scF2.nextLine();
if(!first.equals(second)) {
pwLog.println(UserName + " has MODIFIED in " + file2.getName() + " : " + second);
}
}
pwLog.close();
scF1.close();
scF2.close();
}
}
I vote for not using Java to handle this task, because there are already very good tools out there for doing along the lines of what you want. For example, Linux has a diff tool which might work well here:
diff file1.txt file2.txt
At the very least, the output from diff would flag every line which were in disagreement between the two files, and maybe just that would be enough to meet your requirements.

How to get special file offest in zip using java

I use ZipEntry and ZipInputStream and ZipFile in java to get some information of zip archive. But still I cannot get one information.
Python can do like this:
otazip = zipfile.ZipFile(sys.argv[1], 'r')
load_info = otazip.getinfo('load.bin')
load_offset = load_info.header_offset + len(load_info.FileHeader())
Can anyone help me to get the load_offsetusing java like python does?
In Java there is no method to get offset from ZipEntry.
I tried below solution and it's working fine for me:
public long getZipEntryOffset() {
String path = ota.zip;
final String loadString = "load.bin";
long offset = 0;
File zipFile = new File(path);
ZipInputStream zis = new ZipInputStream(new FileInputStream(path));
try {
ZipEntry loadEntry = zisp.getNextEntry();
while( loadEntry != null){
long fileSize = 0;
long extra = loadEntry.getExtra() == null ? 0 : loadEntry.getExtra().length;
String fileName = loadEntry.getName();
Offset += 30 + loadEntry.getName().length() + extra;
if(!loadEntry.isDirectory()){
fileSize = loadEntry.getCompressedSize();
}
if (fileName.equals(loadString )) {
loadSize = loadEntry.getSize();
break;
}
offset += fileSize;
loadEntry = zisp.getNextEntry();
}
zisp.closeEntry();
}finally {
zis.close();
}
return offset ;
}
The offset is comprised of 30 bytes of standard zip header info + the file name length + some possible extra OS-specific flags + the data itself

File already existing - repeated name

i am creating a file and when i create that file, i check if it already exists. If it already exists, i want to create it with the same name, but with the (1) after it. I am able to do that and here is the code :
File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + ".apk");
if(apkReceived.exists()){
apkReceived=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + "(1)"+".apk");
}
byte[] buffer = new byte [8192];
FileOutputStream fos=new FileOutputStream(apkReceived);
then it would continue... (i am writing things on the file).
This works but the problem is that in this situation :
FileTest.apk
FileTest(1).apk
If I receive another Filetest, it will sub my FileTest(1), since it will create it again.
A solution for this would be to check if the file exists again, but then i would have to be doing that for ever.
My goal would be to create (1) and then (2) , etc.
Does any one of you know how to do this ?
EDIT: Obviously i could use a cicle to check it. The problem is on how to get the (1) and then the (2) and don't get the (1)(2)
To avoid reinventing the wheel I suggest using Timestamp it hardly ever will have collisions.
java.util.Date date= new java.util.Date();
Timestamp tstamp = new Timestamp(date.getTime());
File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + tstamp + ".apk");
Do Something like this
File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + ".apk");
if(apkReceived.exists()){
int new_int_postfix;
//Below _MAX is max numbers of file eg. _MAX = 100
for(int i = 1; i < _MAX; i++) {
apkReceived = = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName +"("+ i +")"+".apk");
if(!apkReceived.exists()) {
String []name_without_pre = receivedApkName.split("\\(");
receivedApkName = name_without_pre[0];
new_int_postfix = i;
break;
}
}
apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + "("+new_int_postfix+")"+".apk");
}
byte[] buffer = new byte [8192];
FileOutputStream fos=new FileOutputStream(apkReceived);
Some pseudocode to get you started:
Fetch a list of all files in the directory
For the one you want to copy: check if you already have one or more copies
If you already have "file_(n)"; use "file_(n+1)" as new filename.
Obviously: you should clarify your requirements on the "maximum" n you want to allow; and what to happen when n copies were created; and another is asked for.
If you only store that one type of file in your directory you can do:
File folder = new File("your/path");
File[] listOfFiles = folder.listFiles();
count the size and size + 1 for your next filename.
you can also separate each file with similiar filename on their own directory.
try this
String filename =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+receivedApkName + ".apk";
File f = new File(filename);
String extension = ".apk";
int g = 0;
while(f.exists()) {
int i = f.lastIndexOf('.');
if (i > 0)
{ extension = fileName.substring(i+1); }
f.renameTo(f.getPath() + "\" + (f.getName() + g) + "." + extension)
}

Cannot Open .txt file to read integers

i am having an issue opening a file and getting my program to read the integers in the file. In the code below, to get my car data i can either have it randomly generated to get my duration time for a car, and the chance that a car arrives. Or read integers from a file. The file is already given by our professor and her is what is in the file:
37259 9819
46363 22666
46161 79934
5693 31416
91459 8272
72792 9493
83603 8372
77842 64629
84792 747
1299 178
Apparently I am unable to open the file even using the absolute path, or data = dataFile.nextInt() isn't the correct format to use. Any help would be appreciated i am absolutely stumped on this part, my whole program works but files are my Achilles heel.
if (dataSource == 1) {
System.out.printf("Enter a filename \t :");
String aName = input.next();
java.io.File file = new java.io.File(aName);
try {
dataFile = new Scanner(file);
} catch (Exception e) {
System.out.println("Can't open file");
}
} else {
dataRandom = new Random();
System.out.println("Is Random Active");
}
input.close();
}
private void getCarData() {
if (dataSource == 1) {
int data1;
int data2;
data1 = dataFile.nextInt();
data2 = dataFile.nextInt();
anyNewArrival = (((data1%100) + 1) <= chancesOfArrival);
serviceDuration = (data2%maxDuration) + 1;
System.out.println("New Car has arrived with Duration Time: " + serviceDuration);//}
}
If running from Netbeans or Ecplise, you can use the relative path "text.txt" And make sure your file structure is something like this
ProjectRoot
src
build
text.txt

How do I get a mp3 file's total time in Java?

The answers provided in How do I get a sound file’s total time in Java? work well for wav files, but not for mp3 files.
They are (given a file):
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = audioInputStream.getFormat();
long frames = audioInputStream.getFrameLength();
double durationInSeconds = (frames+0.0) / format.getFrameRate();
and:
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = audioInputStream.getFormat();
long audioFileLength = file.length();
int frameSize = format.getFrameSize();
float frameRate = format.getFrameRate();
float durationInSeconds = (audioFileLength / (frameSize * frameRate));
They give the same correct result for wav files, but wrong and different results for mp3 files.
Any idea what do I have to do to get the mp3 file's duration?
Using MP3SPI:
private static void getDurationWithMp3Spi(File file) throws UnsupportedAudioFileException, IOException {
AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);
if (fileFormat instanceof TAudioFileFormat) {
Map<?, ?> properties = ((TAudioFileFormat) fileFormat).properties();
String key = "duration";
Long microseconds = (Long) properties.get(key);
int mili = (int) (microseconds / 1000);
int sec = (mili / 1000) % 60;
int min = (mili / 1000) / 60;
System.out.println("time = " + min + ":" + sec);
} else {
throw new UnsupportedAudioFileException();
}
}
Here is the way I get the total time of a file .mp3, I'm using the library is Jlayer 1.0.1
Header h = null;
FileInputStream file = null;
try {
file = new FileInputStream(filename);
} catch (FileNotFoundException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
bitstream = new Bitstream(file);
try {
h = bitstream.readFrame();
} catch (BitstreamException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
int size = h.calculate_framesize();
float ms_per_frame = h.ms_per_frame();
int maxSize = h.max_number_of_frames(10000);
float t = h.total_ms(size);
long tn = 0;
try {
tn = file.getChannel().size();
} catch (IOException ex) {
Logger.getLogger(MP3.class.getName()).log(Level.SEVERE, null, ex);
}
//System.out.println("Chanel: " + file.getChannel().size());
int min = h.min_number_of_frames(500);
return h.total_ms((int) tn)/1000;
Here is a detailed explanation of the MP3 File structure
http://www.autohotkey.com/forum/topic29420.html
Use jave-1.0.1.jar library.
It passed my test on wave file formats such as: wav-pcm8/16,
wav-alaw, wav-ulaw, wav-gsm, wav-adpcm;
It passed my test on some MP3 file formats: cbr vs vbr, stereo vs
SingleChannel;
It can support video formats, which I haven't tested on.
Code sample:
File source = new File("C:\\22.mp3");
Encoder encoder = new Encoder();
try {
MultimediaInfo mi = encoder.getInfo(source);
long ls = mi.getDuration();
System.out.println("duration(sec) = "+ ls/1000);
} catch (Exception e) {
e.printStackTrace();
}
I've tried Jlayer 1.0.1, but it failed for some MP3 format. As for another libaray jaudiotagger-2.0.3.jar, it works fine for MP3 formats, but it can only support wav-pcm8/16.
I'm old-fashioned in this, but I always simply get the specs for MP3, write a function that searches the right bits, and find it out.
If Winamp can determine this by reading the bitstream of an MP3 file, then so can I right?
And so can you, I believe in you mate!

Categories