is there anyway to remove header information from mp3 file such that mp3 file can't be played?
regards,
hitendrasinh gohil
You have to do more than remove the header to make an mp3 unplayable. If you take my other answer to your question and apply it to the whole file there should be no way it can be played:
RandomAccessFile raf = new RandomAccessFile("input.mp3", "rw");
byte[] buf = new byte[65536];
long pos = 0;
int len;
Random random = new Random(34);
while ((len = raf.read(buf)) != -1) {
for (int i = 0; i < len; i++) {
buf[i] ^= random.nextInt();
}
raf.seek(pos);
raf.write(buf);
pos = raf.getFilePointer();
}
raf.close();
This will XOR every byte in the file. The only reason I suggested in the other answer to only do the first 64k was for performance since you're on an Android device. For me that made it unplayable on my desktop. If doing the whole file doesn't work for you then I suspect you're doing something else wrong. There no way it'll play the original music if every byte is changed like this. You can run this again to undo it and make the mp3 playable again.
MP3s are organized in frames so you can often still play them even you only have a part of them.
Related
I have a file:
RandomAccessFile file = new RandomAccessFile("files/bank.txt", "r");
And I am reading and writing data to/from this file using:
for (int pos = 0; pos < 1000; pos++) {
file.seek(40 * pos + 30);
double money = file.readDouble();
if (pos == num) {
money += i;
System.out.println(money+" "+i);
file.seek(40 * pos + 30);
file.writeDouble(money);
}
}
In this way it reads the double - works correctly, and then it should overwrite that double with the value it held previously plus i. However this is not working as the value doesn't change. What have I done wrong?
You have opened file only for reading:
RandomAccessFile("files/bank.txt", "r");
you should open it with:
new RandomAccessFile("files/bank.txt", "rws");
which opens for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device.
or with:
new RandomAccessFile("files/bank.txt", "rwd");
which opens for reading and writing, as with "rw", and also require that every update to the file's content be written synchronously to the underlying storage device.
You have the file open for reading only:
RandomAccessFile file = new RandomAccessFile("files/bank.txt", "r");
Change that line to:
RandomAccessFile file = new RandomAccessFile("files/bank.txt", "rw");
And you will be able to update with the code you have above. :)
This is a classic debug error, you should've breakpointed at money += i to see the value change, the document not changing is another issue and should have been addressed as the possibility of the file not being writable. i.e. you should've opened for writing.
I'm trying to copy part of a file from a filechannel to another (writing a new file, in effect, equals to the first one).
So, I'm reading chunks of 256kb, then putting them back into another channel
static void openfile(String str) throws FileNotFoundException, IOException {
int size=262144;
FileInputStream fis = new FileInputStream(str);
FileChannel fc = fis.getChannel();
byte[] barray = new byte[size];
ByteBuffer bb = ByteBuffer.wrap(barray);
FileOutputStream fos = new FileOutputStream(str+"2" /**/);
FileChannel fo = fos.getChannel();
StringBuilder sb;
while (fc.read(bb) != -1) {
fo.write(bb /**/);
bb.clear();
}
}
The problem is that fo.write (I think) writes again from the beginning of the channel, so the new file is made only of the last chunk read.
I tried with fo.write (bb, bb.position()) but it didn't work as I expected (does the pointer returns to the beginning of the channel?) and with FileOutputStream(str+"2", true) thinking it would append to the end of the new file, but it didn't.
I need to work with chunks of 256kb, so I can't change much the structure of the program (unless I am doing something terribly wrong)
Resolved with bb.flip();
while (fi.read(bb) != -1) {
bb.flip();
fo.write(bb);
bb.clear();
}
This is a very old question but I stumbled upon it and though I might add another answer that has potentially better performance using using FileChannel.transferTo or FileChannel.transferFrom. As per the javadoc:
This method is potentially much more efficient than a simple loop that reads from the source channel and writes to this channel. Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them.
public static void copy(FileChannel src, FileChannel dst) throws IOException {
long size = src.size();
long transferred = 0;
do {
transferred += src.transferTo(0, size, dst);
} while (transferred < size);
}
on most cases a simple src.transferTo(0, src.size(), dst); will work if non of the channels are non-blocking.
The canonical way to copy between channels is as follows:
while (in.read(bb) > 0 || bb.position() > 0)
{
bb.flip();
out.write(bb);
bb.compact();
}
The simplified version in your edited answer doesn't work in all circumstances, e.g. when 'out' is non-blocking.
I am trying to copy a file of about 80 megabytes from the assets folder of an Android application to the SD card.
The file is another apk. For various reasons I have to do it this way and can't simply link to an online apk or put it on the Android market.
The application works fine with smaller apks but for this large one I am getting an out of memory error.
I'm not sure exactly how this works but I am assuming that here I am trying to write the full 80 megabytes to memory.
try {
int length = 0;
newFile.createNewFile();
InputStream inputStream = ctx.getAssets().open(
"myBigFile.apk");
FileOutputStream fOutputStream = new FileOutputStream(
newFile);
byte[] buffer = new byte[inputStream.available()];
while ((length = inputStream.read(buffer)) > 0) {
fOutputStream.write(buffer, 0, length);
}
fOutputStream.flush();
fOutputStream.close();
inputStream.close();
} catch (Exception ex) {
if (ODP_App.getInstance().isInDebugMode())
Log.e(TAG, ex.toString());
}
I found this interesting -
A question about an out of memory issue with Bitmaps
Unless I've misunderstood, in the case of Bitmaps, there appears to be some way to split the stream to reduce memory usage using BitmapFactory.Options.
Is this do-able in my scenario or is there any other possible solution?
The trick is not to try to read the whole file in one go, but rather read it in small chunks and write each chunk before reading the next one into the same memory segment. The following version will read it in 1K chunks. It's for example only - you need to determine the right chunk size.
try {
int length = 0;
newFile.createNewFile();
InputStream inputStream = ctx.getAssets().open(
"myBigFile.apk");
FileOutputStream fOutputStream = new FileOutputStream(
newFile);
//note the following line
byte[] buffer = new byte[1024];
while ((length = inputStream.read(buffer)) > 0) {
fOutputStream.write(buffer, 0, length);
}
fOutputStream.flush();
fOutputStream.close();
inputStream.close();
} catch (Exception ex) {
if (ODP_App.getInstance().isInDebugMode())
Log.e(TAG, ex.toString());
}
Do not read the whole file into memory; read 64k at a time, then write them, repeat until you reach the end of file. Or use IOUtils from Apache Commons IO.
AssetManager mngr = getAssets();
test_file = mngr.open("sample.txt");
above test_file variable is of InputStream type. Any way to calculate the file size of sample.txt from it?
I have an alternative to get size of a file in assets using AssetFileDescriptor:
AssetFileDescriptor fd = getAssets().openFd("test.png");
Long size = fd.getLength();
Hope it helps.
test_file.available();
Is not a very reliable method to get the file length as is stated in the docs.
size = fd.getLength();
Using the FileDescriptor as shown by Ayublin is!
His answer should be promoted to the correct answer.
inputStream.available() might match the file size if the file is very small, but for larger files it isn't expected to match.
For a compressed asset, the only way to get the size reliably is to copy it to the filesystem, ex: context.getCacheDir() then read the length of the file from there. Here's some sample code that does this. It probably then also makes sense to use the file from the cache dir as opposed to the assets after this.
String filename = "sample.txt";
InputStream in = context.getAssets().open(filename);
File outFile = new File(context.getCacheDir(), filename);
OutputStream out = new FileOutputStream(outFile);
try {
int len;
byte[] buff = new byte[1024];
while ((len = in.read(buff)) > 0) {
out.write(buff, 0, len);
}
} finally {
// close in & out
}
long theRealFileSizeInBytes = outFile.length();
You should also delete the file from the cache dir when you are done with it (and the entire cache dir will also be deleted automatically when uninstalling the app).
for a project I'm working on, I want to be able to concatenate multiple .wav files.
Through my research I was able to come up with this code:
File sample1 = new File("F:\\Programming\\Resources\\Java_Sound\\trumpet1.wav");
File sample2 = new File("F:\\Programming\\Resources\\Java_Sound\\trumpet2.wav");
File fileOut = new File("F:\\Programming\\Resources\\Java_Sound\\Test.wav");
AudioInputStream audio1 = AudioSystem.getAudioInputStream(sample1);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(sample2);
AudioInputStream audioBuild = new AudioInputStream(new SequenceInputStream(audio1, audio2), audio1.getFormat(), audio1.getFrameLength() + audio2.getFrameLength());
//for(int i = 0; i < 5; i++){
// audioBuild = new AudioInputStream(new SequenceInputStream(audioBuild, audio2), audioBuild.getFormat(), audioBuild.getFrameLength() + audio2.getFrameLength());
//}
AudioSystem.write(audioBuild, AudioFileFormat.Type.WAVE, fileOut);
it works fine for combining two .wav files, however when I uncomment the for loop the produced .wav file only plays audio for the first concatenation. The audio track appears to end early, as wmp's duration bar only goes about 1\5 of the way across the screen.
I've assumed that the problem is with the header in the created .wav file. I've researched many different web pages discussing how a header in constructed, but all of them had slightly different definitions, but all said the header should be in hex. When converting the stream (not the audio stream, a standard FileInputStream) the headers I had were in decimal. Additionally, after the RIFF part, and before the WAVE part, is supposed to be the size of the whole file, not including the first 8 bytes. However some of mine included hyphens. To be honest I have no clue what those mean. Ignoring them however, the size of the test file after uncommenting the code above is still a larger number.
So after researching both how to concatenate multiple audio files, and how to create\manage .wav headers, I still have no clue why the rest of my audio isn't playing, if it even exists. Any help is greatly appreciated. Thanks in advance.
It might be because the input streams cannot be read more than once. Once you read an input stream, it will be at its end and attempt to read further will read no more bytes from that stream.
This should work with a slight modification, keep creating new audio input streams in your loop:
File sample1 = new File("f1.wav");
File sample2 = new File("f2.wav");
File fileOut = new File("combined.wav");
AudioInputStream audio1 = AudioSystem.getAudioInputStream(sample1);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(sample2);
AudioInputStream audioBuild = new AudioInputStream(new SequenceInputStream(audio1, audio2), audio1.getFormat(), audio1.getFrameLength() + audio2.getFrameLength());
for(int i = 0; i < 5; i++)
{
audioBuild = new AudioInputStream(new SequenceInputStream(audioBuild, /* keep creating new input streams */ AudioSystem.getAudioInputStream(sample2)), audioBuild.getFormat(), audioBuild.getFrameLength() + audio2.getFrameLength());
}
AudioSystem.write(audioBuild, AudioFileFormat.Type.WAVE, fileOut);
Also, ensure your audio formats for the files are exactly the same. That is, same sample rate, same channel count, same bits per sample. Otherwise you'll need additional code to do sample conversion.
This is what I used to join any amount of wave files. I looped through a list of the string values for the wave file paths, and each time I join the previous resulting AudioInputStream with the next clip.
List<String> paths;
AudioInputStream clip1 = null;
for (String path : paths)
{
if(clip1 == null)
{
clip1 = AudioSystem.getAudioInputStream(new File(path));
continue;
}
AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(path));
AudioInputStream appendedFiles = new AudioInputStream(
new SequenceInputStream(clip1, clip2),
clip1.getFormat(),
clip1.getFrameLength() + clip2.getFrameLength());
clip1 = appendedFiles;
}
AudioSystem.write(clip1, AudioFileFormat.Type.WAVE, new File("exported.wav"));