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.
Related
I am processing very large files (> 2Gig). Each input file is Base64 encoded, andI am outputting to new files after decoding. Depending on the buffer size (LARGE_BUF) and for a given input file, my input to output conversion either works fine, is missing one or more bytes, or throws an exception at the outputStream.write line (IllegalArgumentException: Last unit does not have enough bits). Here is the code snippet (could not cut and paste so my not be perfect):
.
.
final int LARGE_BUF = 1024;
byte[] inBuf = new byte[LARGE_BUF];
try(InputStream inputStream = new FileInputStream(inFile); OutputStream outStream new new FileOutputStream(outFile)) {
for(int len; (len = inputStream.read(inBuf)) > 0); ) {
String out = new String(inBuf, 0, len);
outStream.write(Base64.getMimeDecoder().decode(out.getBytes()));
}
}
For instance, for my sample input file, if LARGE_BUF is 1024, output file is 4 bytes too small, if 2*1024, I get the exception mentioned above, if 7*1024, it works correctly. Grateful for any ideas. Thank you.
First, you are converting bytes into a String, then immediately back into bytes. So, remove the use of String entirely.
Second, base64 encoding turns each sequence of three bytes into four bytes, so when decoding, you need four bytes to properly decode three bytes of original data. It is not safe to create a new decoder for each arbitrarily read sequence of bytes, which may or may not have a length which is an exact multiple of four.
Finally, Base64.Decoder has a wrap(InputStream) method which makes this considerably easier:
try (InputStream inputStream = Base64.getDecoder().wrap(
new BufferedInputStream(
Files.newInputStream(Paths.get(inFile))))) {
Files.copy(inputStream, Paths.get(outFile));
}
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.
I'm trying to make a file hexadecimal converter (input file -> output hex string of the file)
The code I came up with is
static String open2(String path) throws FileNotFoundException, IOException,OutOfMemoryError {
System.out.println("BEGIN LOADING FILE");
StringBuilder sb = new StringBuilder();
//sb.ensureCapacity(2147483648);
int size = 262144;
FileInputStream f = new FileInputStream(path);
FileChannel ch = f.getChannel( );
byte[] barray = new byte[size];
ByteBuffer bb = ByteBuffer.wrap( barray );
while (ch.read(bb) != -1)
{
//System.out.println(sb.capacity());
sb.append(bytesToHex(barray));
bb.clear();
}
System.out.println("FILE LOADED; BRING IT BACK");
return sb.toString();
}
I am sure that "path" is a valid filename.
The problem is with big files (>=
500mb), the compiler outputs a OutOfMemoryError: Java Heap Space on the StringBuilder.append.
To create this code I followed some tips from http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly but I got a doubt when I tried to force a space allocation for the StringBuilder sb: "2147483648 is too big for an int".
If I want to use this code even with very big files (let's say up to 2gb if I really have to stop somewhere) what's the better way to output a hexadecimal string conversion of the file in terms of speed?
I'm now working on copying the converted string into a file. Anyway I'm having problems of "writing the empty buffer on the file" after the eof of the original one.
static String open3(String path) throws FileNotFoundException, IOException {
System.out.println("BEGIN LOADING FILE (Hope this is the last change)");
FileWriter fos = new FileWriter("HEXTMP");
int size = 262144;
FileInputStream f = new FileInputStream(path);
FileChannel ch = f.getChannel( );
byte[] barray = new byte[size];
ByteBuffer bb = ByteBuffer.wrap( barray );
while (ch.read(bb) != -1)
{
fos.write(bytesToHex(barray));
bb.clear();
}
System.out.println("FILE LOADED; BRING IT BACK");
return "HEXTMP";
}
obviously the file HEXTMP created has a size multiple of 256k, but if the file is 257k it will be a 512 file with LOT of "000000" at the end.
I know I just have to create a last byte array with cut length.
(I used a file writer because i wanted to write the string of hex; otherwise it would have just copied the file as-is)
Why are you loading complete file?
You can load few bytes in buffer from input file, process bytes in buffer, then write processed bytes buffer to output file. Continue this till all bytes from input file are not processed.
FileInputStream fis = new FileInputStream("in file");
FileOutputStream fos = new FileOutputStream("out");
byte buffer [] = new byte[8192];
while(true){
int count = fis.read(buffer);
if(count == -1)
break;
byte[] processed = processBytesToConvert(buffer, count);
fos.write(processed);
}
fis.close();
fos.close();
So just read few bytes in buffer, convert it to hex string, get bytes from converted hex string, then write back these bytes to file, and continue for next few input bytes.
The problem here is that you try to read the whole file and store it in memory.
You should use stream, read some lines of your input file, convert them and write them in the output file. That way your program can scale, whatever the size of the input file is.
The key would be to read file in chunks instead of reading all of it in one go. Depending on its use you could vary size of the chunk. For example, if you are trying to make a hex viewer / editor determine how much content is being shown in the viewport and read only as much of data from file. Or if you are simply converting and dumping hex to another file use any chunk size that is small enough to fit in memory but big enough for performance. This should be tunable over some runs. Perhaps use filesystem NIO in Java 7 so that you can do all three tasks - reading, processing and writing - concurrently. The link included in question gives good primer on reading files.
In my program I had to remove certain frames from video and audio so that advertisments are removed. The video is stored in .rgb file and audio is stored in .wav file.
The video is working fine. But when I try and write only a few frames from one wav file to the output wav file it is giving an error while playing.
Though the program is writing it properly and I can play it in Real Player, the audio gives an error called mark/reset not supported and unable to get position error when I run it on the code same code to play wav file that professor has given.
I cant find the mistake in the writing audio function. Here is the function
public void do_audioWrite() throws IOException
{
long offset=0;
long offset2=0;
int audioInfoSize = 2; //audio info is in bytes
long FRAMESIZE= 352*288*(24/8);
double MAX_POSSIBLE_FRAMES=AdvRemove.file_len/FRAMESIZE;
double AUDIO_PER_FRAME = 2000;
long videoFrames=0;
byte[] bytes = new byte[4000];
byte[] head = new byte[44];
RandomAccessFile raf = new RandomAccessFile(AdvRemove.afilename,"r");
OutputStream outputStream = new FileOutputStream(AdvRemove.write_audio);
raf.seek(0);
raf.read(head);
outputStream.write(head);
for (offset=44; ((offset < raf.length()) && (videoFrames < MAX_POSSIBLE_FRAMES)); offset+=2*AUDIO_PER_FRAME)
{
if(Group1.size()>Group2.size())
{
if(Group1.contains((int)videoFrames))
{
raf.seek(offset);
raf.read(bytes);
outputStream.write(bytes);
}
}
else if(Group1.size()<Group2.size())
{
if(Group2.contains((int)videoFrames))
{
raf.seek(offset);
raf.read(bytes);
outputStream.write(bytes);
}
}
videoFrames++;
}
}
ABOVE IS MY FUNCTION TO WRITE THE AUDIO.
I only write an audio frame if the corresponding video frame is found in my arrayList called Group1 and Group2
First I took the header of input wav file and write it to the output wav file.
Then I check if corresponding video frame exists. If yes, I write the audio frames corresponding to that video frame.
You need to update the output file header to be correct for the new file you are creating.
outputStream.write(head);
Here you are simply copy the original files header, but it looks like in your loop you are not always copying a sample from the original file to your stripped file (i.e your output file is going to be shorter than the input file). The wav file format has information in the header regarding the size of the file (see https://ccrma.stanford.edu/courses/422-winter-2014/projects/WaveFormat/ for a break down of the header), you need to update the header to have the correct data length for your new file.
I have some working code in python that I need to convert to Java.
I have read quite a few threads on this forum but could not find an answer. I am reading in a JPG image and converting it into a byte array. I then write this buffer it to a different file. When I compare the written files from both Java and python code, the bytes at the end do not match. Please let me know if you have a suggestion. I need to use the byte array to pack the image into a message that needs to be sent over to a remote server.
Java code (Running on Android)
Reading the file:
File queryImg = new File(ImagePath);
int imageLen = (int)queryImg.length();
byte [] imgData = new byte[imageLen];
FileInputStream fis = new FileInputStream(queryImg);
fis.read(imgData);
Writing the file:
FileOutputStream f = new FileOutputStream(new File("/sdcard/output.raw"));
f.write(imgData);
f.flush();
f.close();
Thanks!
InputStream.read is not guaranteed to read any particular number of bytes and may read less than you asked it to. It returns the actual number read so you can have a loop that keeps track of progress:
public void pump(InputStream in, OutputStream out, int size) {
byte[] buffer = new byte[4096]; // Or whatever constant you feel like using
int done = 0;
while (done < size) {
int read = in.read(buffer);
if (read == -1) {
throw new IOException("Something went horribly wrong");
}
out.write(buffer, 0, read);
done += read;
}
// Maybe put cleanup code in here if you like, e.g. in.close, out.flush, out.close
}
I believe Apache Commons IO has classes for doing this kind of stuff so you don't need to write it yourself.
Your file length might be more than int can hold and than you end up having wrong array length, hence not reading entire file into the buffer.