2016-12-25 1 views
1

encode_text() 함수는 LSB 코딩 방법을 구현합니다. 처음 기록 된 메시지 길이 다음 메시지 자체.Strong은 1 비트를 변경할 때 WAV 파일을 변경합니다. 스테 가노 그래피

numberOfBits 메시지를 쓰는 데 할당 된 비트 수입니다. 1 비트 또는 2 또는 3 비트로 쓰기 ...

레코드에 대해 1 비트를 사용하여 인코딩하는이 방법은 소리가 눈에 띄지 않아야합니다. 눈의 변화뿐만 아니라 이미지. 그러나 이것은 사실이 아닙니다. 어떤 이유로, 소리의 시작 부분에 "잡음"로 변경됩니다. 그건 안된다. 저장

읽기()() 데이터 파일을 읽고 다음 구울 경우 OK, 변경 사항이 없습니다.

무엇이 문제입니까? encode_text() 기능이 잘못되었습니다. 아니면 뭔가 잘못 했나요?

import java.io.*; 
import java.util.Arrays; 

public class wavIO 
{ 

private String myPath; 
private long myChunkSize; 
private long mySubChunk1Size; 
private int myFormat; 
private long myChannels; 
private long mySampleRate; 
private long myByteRate; 
private int myBlockAlign; 
private int myBitsPerSample; 
private long myDataSize; 

public byte[] myData; 

public String getPath() 
{ 
    return myPath; 
} 
public void setPath(String newPath) 
{ 
    myPath = newPath; 
} 

public wavIO() 
    { 
    myPath = ""; 
    } 
public wavIO(String tmpPath) 
    { 
    myPath = tmpPath; 
    } 

// read a wav file into this class 
public boolean read() 
{ 
    DataInputStream inFile = null; 
    myData = null; 
    byte[] tmpLong = new byte[4]; 
    byte[] tmpInt = new byte[2]; 

    try 
    { 
     inFile = new DataInputStream(new FileInputStream(myPath)); 

     //System.out.println("Reading wav file...\n"); // for debugging only 

     String chunkID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the ChunkSize 
     myChunkSize = byteArrayToLong(tmpLong); 

     String format = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     // print what we've read so far 
     //System.out.println("chunkID:" + chunkID + " chunk1Size:" + myChunkSize + " format:" + format); // for debugging only 



     String subChunk1ID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the SubChunk1Size 
     mySubChunk1Size = byteArrayToLong(tmpLong); 

     inFile.read(tmpInt); // read the audio format. This should be 1 for PCM 
     myFormat = byteArrayToInt(tmpInt); 

     inFile.read(tmpInt); // read the # of channels (1 or 2) 
     myChannels = byteArrayToInt(tmpInt); 

     inFile.read(tmpLong); // read the samplerate 
     mySampleRate = byteArrayToLong(tmpLong); 

     inFile.read(tmpLong); // read the byterate 
     myByteRate = byteArrayToLong(tmpLong); 

     inFile.read(tmpInt); // read the blockalign 
     myBlockAlign = byteArrayToInt(tmpInt); 

     inFile.read(tmpInt); // read the bitspersample 
     myBitsPerSample = byteArrayToInt(tmpInt); 
     // print what we've read so far 
     //System.out.println("SubChunk1ID:" + subChunk1ID + " SubChunk1Size:" + mySubChunk1Size + " AudioFormat:" + myFormat + " Channels:" + myChannels + " SampleRate:" + mySampleRate); 


     // read the data chunk header - reading this IS necessary, because not all wav files will have the data chunk here - for now, we're just assuming that the data chunk is here 
     String dataChunkID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the size of the data 
     myDataSize = byteArrayToLong(tmpLong); 


     // read the data chunk 
     myData = new byte[(int)myDataSize]; 
     inFile.read(myData); 

     // close the input stream 
     inFile.close(); 

    } 
    catch(Exception e) 
    { 
     return false; 
    } 

    return true; // this should probably be something more descriptive 
} 

// write out the wav file 
public boolean save(String outputPath) 
{ 
    try 
    { 
     //DataOutputStream outFile = new DataOutputStream(new FileOutputStream(myPath)); 
     DataOutputStream outFile = new DataOutputStream(new FileOutputStream(outputPath)); 

     // write the wav file per the wav file format 
     outFile.writeBytes("RIFF");     // 00 - RIFF 
     outFile.write(intToByteArray((int)myChunkSize), 0, 4);  // 04 - how big is the rest of this file? 
     outFile.writeBytes("WAVE");     // 08 - WAVE 
     outFile.writeBytes("fmt ");     // 12 - fmt 
     outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4); // 16 - size of this chunk 
     outFile.write(shortToByteArray((short)myFormat), 0, 2);  // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation 
     outFile.write(shortToByteArray((short)myChannels), 0, 2); // 22 - mono or stereo? 1 or 2? (or 5 or ???) 
     outFile.write(intToByteArray((int)mySampleRate), 0, 4);  // 24 - samples per second (numbers per second) 
     outFile.write(intToByteArray((int)myByteRate), 0, 4);  // 28 - bytes per second 
     outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels 
     outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2); // 34 - how many bits in a sample(number)? usually 16 or 24 
     outFile.writeBytes("data");     // 36 - data 
     outFile.write(intToByteArray((int)myDataSize), 0, 4);  // 40 - how big is this data chunk 
     outFile.write(myData);      // 44 - the actual data itself - just a long string of numbers 
    } 
    catch(Exception e) 
    { 
     System.out.println(e.getMessage()); 
     return false; 
    } 

    return true; 
} 

// return a printable summary of the wav file 
public String getSummary() 
{ 
    //String newline = System.getProperty("line.separator"); 
    String newline = "<br>"; 
    String summary = "<html>Format: " + myFormat + newline + "Channels: " + myChannels + newline + "SampleRate: " + mySampleRate + newline + "ByteRate: " + myByteRate + newline + "BlockAlign: " + myBlockAlign + newline + "BitsPerSample: " + myBitsPerSample + newline + "DataSize: " + myDataSize + "</html>"; 
    return summary; 
} 


// =========================== 
// CONVERT BYTES TO JAVA TYPES 
// =========================== 

// these two routines convert a byte array to a unsigned short 
public static int byteArrayToInt(byte[] b) 
{ 
    int start = 0; 
    int low = b[start] & 0xff; 
    int high = b[start+1] & 0xff; 
    return (int)(high << 8 | low); 
} 


// these two routines convert a byte array to an unsigned integer 
public static long byteArrayToLong(byte[] b) 
{ 
    int start = 0; 
    int i = 0; 
    int len = 4; 
    int cnt = 0; 
    byte[] tmp = new byte[len]; 
    for (i = start; i < (start + len); i++) 
    { 
     tmp[cnt] = b[i]; 
     cnt++; 
    } 
    long accum = 0; 
    i = 0; 
    for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) 
    { 
     accum |= ((long)(tmp[i] & 0xff)) << shiftBy; 
     i++; 
    } 
    return accum; 
} 


// =========================== 
// CONVERT JAVA TYPES TO BYTES 
// =========================== 
// returns a byte array of length 4 
private static byte[] intToByteArray(int i) 
{ 
    byte[] b = new byte[4]; 
    b[0] = (byte) (i & 0x00FF); 
    b[1] = (byte) ((i >> 8) & 0x000000FF); 
    b[2] = (byte) ((i >> 16) & 0x000000FF); 
    b[3] = (byte) ((i >> 24) & 0x000000FF); 
    return b; 
} 

// convert a short to a byte array 
public static byte[] shortToByteArray(short data) 
{ 
    return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)}; 
} 


public void encode(String text, int numberOfBits) 
{ 
    byte[] byteMessage = text.getBytes(); 
    byte[] messageLength = bit_conversion(byteMessage.length); 
    encodeText(messageLength, myData, 0, numberOfBits); 
    encodeText(byteMessage, myData, 32, numberOfBits); 
} 

private void encodeText(byte[] addition, byte[] byteDataInputWav, int offset, int numberOfBits) 
{ 
    if(addition.length + offset > byteDataInputWav.length) 
    { 
     System.out.println("File not long enough!"); 
    } 
    else 
    { 
     for(int i=0; i<addition.length; ++i) 
     { 
      int add = addition[i]; 
      for(int bit=7; bit>=0; --bit, ++offset) 
      { 
       int b = (add >>> bit) & 1; 
       byteDataInputWav[offset] = (byte)((byteDataInputWav[offset] & numberOfBits) | b); 
      } 
     } 
    } 
} 

private byte[] bit_conversion(int i) 
{ 
    byte byte3 = (byte)((i & 0xFF000000) >>> 24); 
    byte byte2 = (byte)((i & 0x00FF0000) >>> 16); 
    byte byte1 = (byte)((i & 0x0000FF00) >>> 8); 
byte byte0 = (byte)((i & 0x000000FF)  ); 
return(new byte[]{byte3,byte2,byte1,byte0}); 
} 

public String decode(String inputPath) 
{ 
    byte[] byteDataOutputWav = myData; 
    int length = 0; 
int offset2 = 32; 
for(int i=0; i<32; ++i) 
{ 
    length = (length << 1) | (byteDataOutputWav[i] & 1); 
} 
byte[] result = new byte[length]; 
for(int b=0; b<result.length; ++b) 
{ 
     for(int i=0; i<8; ++i, ++offset2) 
     { 
      result[b] = (byte)((result[b] << 1) | (byteDataOutputWav[offset2] & 1)); 
     } 
} 
    return new String(result); 
} 


} 

답변

0

모든 바이트의 최하위 비트가 수정됩니다. 따라서 사운드 파일에서 한 샘플의 비트 수에 관계없이 ~ ~ 48dB의 전체 스케일의 노이즈가 유입됩니다. 이것은 분명히 조용한 Audible이 될 것입니다. 나는 소리의 시작 부분에서 당신이 의미하는 바를 추측합니다.

아마도 보통 -16 비트의 최하위 비트 만 수정하면 ~ -96dB의 노이즈 만 발생합니다.

16 비트 샘플의 LSB 만 수정하면 잡음이 훨씬 더 부드러워집니다. 그러나 큰 소리로 재생되는 볼륨에서 좋은 장비의 사운드 파일의 조용한 부분에 정상적인 청력을 느끼는 사람들은 여전히인지 할 수 있습니다. 오디오 편집기 등으로 사운드 파일을 보는 사람이라면 누구나 쉽게 알 수 있습니다. 효과적인 스테 가노 그래피를 위해서는 코딩을 시간에 따른 사운드 레벨에 맞춰야합니다 (적어도).

관련 문제