Trying to write raw PCM to WAV and only getting header - java

I am currently using this code:
File wavFile=new File("tmp"+File.separator+"recordings"+File.separator+uuid.toString()+".wav");
try{
FileInputStream pcmInputStream=new FileInputStream(file);
FileOutputStream wavOutputStream=new FileOutputStream(wavFile);
AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(IOUtils.toByteArray(pcmInputStream)),
new AudioFormat(48000,16,2,true,
true),IOUtils.toByteArray(pcmInputStream).length/4),
AudioFileFormat.Type.WAVE,wavOutputStream);
wavOutputStream.flush();
wavOutputStream.close();
pcmInputStream.close();
fileOutputStream.close();
}catch(IOException e){
e.printStackTrace();
}
Having checked, I can confirm that the PCM has 30 seconds of data and is approximately 4.7MB. This writes the .wav file however it is only 44 bytes and not playable, I reckon that this 44 bytes is the RIFF header but am unsure of how to solve it. I have tried using different lengths and different combinations of File/ByteArray OutputStreams.

When creating the AudioInputStream, you call IOUtils.toByteArray(pcmInputStream) twice, and on the second call, the input stream is already advanced to the end, so toByteArray returns an empty array. This results in 0 getting passed as the argument to the AudioInputStream constructor's length.
new AudioInputStream(
new ByteArrayInputStream( IOUtils.toByteArray(pcmInputStream) ),
new AudioFormat(48000,16,2,true,true),
( IOUtils.toByteArray(pcmInputStream) ).length/4
)
You should save the byte array to a temporary variable instead of trying to call toByteArray twice on the same input stream.

Related

How to properly read an InputStream with multiple contents

public static void main(String[] args) throws Exception
{
// Server sends 3 numbers to the client
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(1000);
bos.write(2000);
bos.write(3000);
// Client receive the bytes
final byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
System.out.println(bis.read());
System.out.println(bis.read());
System.out.println(bis.read());
}
The code above is breaking because bis.read() returns an int in the range 0 to 255
How can I receive those numbers properly? Should I use a delimiter and keep reading the stream until I find it? If so, what if I'm sending multiple files, I think if the delimiter as a single byte it could matched somewhere in the file and also break.
Use decorators for your streams!
All you have to do is to wrap your Output- and InputStream by java.io.ObjectOutputStream / and java.io.ObjectInputStream. These classes support writing and reading ints (a 4-byte value) with a single method call to writeInt/readInt.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeInt(1000);
os.writeInt(2000);
os.writeInt(3000);
os.close();
// Client receive the bytes
final byte[] bytes = bos.toByteArray();
ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytes));
System.out.println(is.readInt());
System.out.println(is.readInt());
System.out.println(is.readInt());
Don't forget to close the streams. Use try/finally or try-with-resources.
Byte stream is a stream of bytes. So if you're reading stream and want to differentiate between different parts of the stream then you should "create" some sort of protocol.
Here are some ideas that can be relevant:
Use delimiter as you've stated by yourself, If you're concerned about the length - do not one byte length, but something more unique - something that you're sure you won't see in the parts themselves.
At the beginning of the part allocate N bytes (2-4 or maybe more, depending on data) and write the size of the part that will follow.
So that when you create the stream (writer), before actually streaming the "part" - calculate its size and encode it. This is a protocol between reader and writer.
When you read - read the size (=N bytes for example), and then read N bytes. Now you know that the part is ended, and the next part (again, size + content) will follow
Can you try ByteBuffer class?
ByteStream is just a stream of bytes. It doesn't understand integer which actually needs more than one byte. If you print bytes.length it will return you 3. Surely you need more bytes than that. Allocate 4 bytes before you write an integer and then write to it. Check out this class above. Hope that helps!

what is the variable "data" storing in this java program?

My code is working. I just need to know about the role of a specific variable in the code.
I tried to print the value in the variable "data", but it gives me some numbers i cant understand.
public static void main(String[] args) throws IOException {
FileInputStream fileinputstream = new FileInputStream ("c:\\Users\\USER\\Desktop\\read.TXT");
FileOutputStream fileoutputstream = new FileOutputStream("c:\\Users\\USER\\Desktop\\write.TXT");
while (fileinputstream.available() > 0) {
int data = fileinputstream.read();
fileoutputstream.write(data);
}
fileinputstream.close();
fileoutputstream.close();
}
You can look at the docs for FileInputStream.read, which says:
Reads a byte of data from this input stream. This method blocks if no input is yet available.
Returns:
the next byte of data, or -1 if the end of the file is reached.
So the integer you got (i.e. the number stored in data) is the byte read from the file. Since your file is a text file, it is the ASCII value of the characters in that file (assuming your file is encoded in ASCII).
FileInputStream#read() reads a single byte of information from the underlying file.
Since these files are text files (according to their extensions), you probably should be using a FileInputStream, but a FileReader, to properly handle characters, and not the bytes that make them up.
fileinputstream.read() returns "the next byte of data, or -1 if the end of the file is reached."
You can read more here

Read a single line from a text file Java [duplicate]

Hey I'm trying to open a file and read just from an offset for a certain length!
I read this topic:
How to read a specific line using the specific line number from a file in Java?
in there it said that it's not to possible read a certain line without reading the lines before, but I'm wondering about bytes!
FileReader location = new FileReader(file);
BufferedReader inputFile = new BufferedReader(location);
// Read from bytes 1000 to 2000
// Something like this
inputFile.read(1000,2000);
Is it possible to read certain bytes from a known offset?
RandomAccessFile exposes a function:
seek(long pos)
Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs.
FileInputStream.getChannel().position(123)
This is another possibility in addition to RandomAccessFile:
File f = File.createTempFile("aaa", null);
byte[] out = new byte[]{0, 1, 2};
FileOutputStream o = new FileOutputStream(f);
o.write(out);
o.close();
FileInputStream i = new FileInputStream(f);
i.getChannel().position(1);
assert i.read() == out[1];
i.close();
f.delete();
This should be OK since the docs for FileInputStream#getChannel say that:
Changing the channel's position, either explicitly or by reading, will change this stream's file position.
I don't know how this method compares to RandomAccessFile however.

How to run methods against the entire bytes of a large file

My program needs to do calculations against the entire bytes of a file and it breaks whenever the file gets above a certain size.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
I know I can allocate the amount of memory to my program using command line switches, but I'm wondering if there is a more effective way of handling this in my program?
I'm basically trying to figure out a way to read the file in chunks and pass those chunks to another method and essentially rebuild the file in that method.
This is the problem method. I need these bytes to be used in another method.
This method converts the stream to a byte array:
private byte[] inputStreamToByteArray(InputStream inputStream) {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = null;
try {
bis = new BufferedInputStream(inputStream);
baos = new ByteArrayOutputStream(bis);
byte[] buffer = new byte[1024];
int nRead;
while((nRead = bis.read(buffer)) != -1) {
baos.write(buffer, 0, nRead);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
return baos.toByteArray();
}
This method checks the file type:
private final boolean isMyFileType(byte[] bytes) {
// do stuff
return theBoolean;
}
The reason it is breaking makes sense to me - the byte array ends up being gigantic if I have a gigantic file AND I'm passing around a gigantic byte array.
My goal, I want to read the bytes from a file, determine what type of file it is using another method I wrote, run compression/decompression method against those bytes after determining the file type.
I have most of my goal completed, I just don't know how to handle file streams and large byte arrays effectively.
You are already using a BufferedInputStream. Use the "mark" method to place a mark in the steam. Make sure the "readlimit" argument to "mark" is large enough for you to detect the file type. Read the first X bytes from the stream (but not more than readlimit) and try to figure out the content. Then call reset() to set the stream back to the beginning and continue withw whatever you want to do with the stream.

Audio stegnography

i am working on my final year project in JAVA
1)hiding text in a image
2)image in a image
3)text in a audio file (WAVE)
i have successfully completed 1) and 2) and have attached the source code if anybody may need it.
i am having trouble in the 3rd one i.e hiding data in a audio file .
I create a audioinputstream out of a wave file and read it's data into a byte array
but many things are not clear,while reading i'm guessing the 1st 44 bytes are the header bytes?(since the file is of WAVE format) or the header is not copied at all.
The Problem is ....
at the time of decoding again i have to read the data from the newly created audio file in a byte array. And i'm not able to locate the bytes where i have hidden data.
Can anybody tell me what exactly happens when we read data into a byte array from a audioinputstream , i mean what actually gets read into the byte array?
File fileIn = new File("C:\\Users\\Rahul\\Desktop\\pro\\Don't Stay.wav");
AudioInputStream audioInputStream =
AudioSystem.getAudioInputStream(fileIn);
int avail= audioInputStream.available();
System.out.println("bytes available " +avail);
System.out.println(audioInputStream.markSupported());
int bytesPerFrame =
audioInputStream.getFormat().getFrameSize();
// Set an arbitrary buffer size of 1024 frames.
int numBytes = 1024 * bytesPerFrame;
byte[] audioBytes = new byte[numBytes];
audioInputStream.read(audioBytes);
byte btext[]=Stego_text("good morning!");
byte bcoded[]=steg.encoding(audioBytes,btext,0);
byte[] stg= a.decode_text(audioBytes);
String obtain= new String(stg);
System.out.println(">>>"+ obtain); //the hidden message gets successfully displayed here
try {
//
AudioSystem.write(audioInputStream, Type.WAVE, new File("C:\\Users\\Rahul\\Desktop\\pro\\Don't Stay_restored.wav"));
} catch (Exception e) {
e.printStackTrace();
}
byte[] audioBytesNew = new byte[numBytes];
audioInputStream.read(audioBytesNew);
byte[] stg1= a.decode_text(audioBytesNew);
String obtain1= new String(stg1);
System.out.println(">>>"+ obtain1); //the hidden message does not get displayed
if i decode the byte array just after editing , then it works fine and displays the hidden message, but after again creating a byte array and reading into it audioinputsream data and then decoding that byte array .. it does not work. i wonder WHY? please help me.
The first 44 bytes are indeed the header of the WAV (see https://ccrma.stanford.edu/courses/422/projects/WaveFormat/)
If you open the file in an HEX editor, you'll see what it looks like (http://imgur.com/iliA40R)
If you compare the data in the file and the data read by your InputStream, it matches.
You should close and re-open your stream if you need to read the file again.
If you can mark the file, you could mark it before reading, and call reset() after the first read is done.

Categories