-
-
Save jpxiong/e0870d3235dfb27ccc06ecf9eb3aacbb to your computer and use it in GitHub Desktop.
VoiceRecorder edit recorded file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.ByteBuffer; | |
import java.util.HashMap; | |
import android.util.Log; | |
public class EditAACUnit extends EditUnit | |
{ | |
public EditAACUnit(File voiceFile) | |
{ | |
mvoiceFile = voiceFile; | |
try | |
{ | |
mOffset = 0; | |
stream = new FileInputStream(mvoiceFile); | |
} | |
catch(FileNotFoundException e) | |
{ | |
e.printStackTrace(); | |
} | |
} | |
private File mvoiceFile; | |
private FileInputStream stream; | |
// private FileOutputStream out; | |
private HashMap<Integer, Block> mAtomMap; | |
int mSampleRate; | |
int mSamplesPerFrame; | |
private int mOffset; | |
private int mMdatOffset; | |
private int mMinGain; | |
private int mMaxGain; | |
private int mNumFrames; | |
private int[] mFrameOffsets; | |
private int[] mFrameLens; | |
private int[] mFrameGains; | |
public static final int _FTYP = 0x66747970; | |
public static final int _MOOV = 0x6d6f6f76; | |
public static final int _MVHD = 0x6d766864; | |
public static final int _TRAK = 0x7472616b; | |
public static final int _TKHD = 0x746b6864; | |
public static final int _MDIA = 0x6d646961; | |
public static final int _MDHD = 0x6d646864; | |
public static final int _HDLR = 0x68646c72; | |
public static final int _MINF = 0x6d696e66; | |
public static final int _DINF = 0x64696e66; | |
public static final int _STBL = 0x7374626c; | |
public static final int _STSD = 0x73747364; | |
public static final int _MP4A = 0x6d703461; | |
public static final int _STTS = 0x73747473; | |
public static final int _STSZ = 0x7374737a; | |
public static final int _STSC = 0x73747363; | |
public static final int _STCO = 0x7374636f; | |
public static final int _SMHD = 0x736d6864; | |
public static final int _FREE = 0x66726565; | |
public static final int _MDAT = 0x6d646174; | |
class Block { | |
public int start; | |
public int len; // including header | |
public byte[] header; | |
public byte[] data; | |
}; | |
void readFrameAndComputeGain(InputStream stream, int frameIndex) | |
throws java.io.IOException { | |
if (mFrameLens[frameIndex] < 4) { | |
mFrameGains[frameIndex] = 0; | |
stream.skip(mFrameLens[frameIndex]); | |
return; | |
} | |
int initialOffset = mOffset; | |
byte[] data = new byte[4]; | |
stream.read(data, 0, 4); | |
mOffset += 4; | |
int idSynEle = (0xe0 & data[0]) >> 5; | |
switch(idSynEle) { | |
case 0: // ID_SCE: mono | |
int monoGain = ((0x01 & data[0]) << 7) | ((0xfe & data[1]) >> 1); | |
mFrameGains[frameIndex] = monoGain; | |
break; | |
case 1: // ID_CPE: stereo | |
int windowSequence = (0x60 & data[1]) >> 5; | |
int windowShape = (0x10 & data[1]) >> 4; | |
int maxSfb; | |
int scaleFactorGrouping; | |
int maskPresent; | |
int startBit; | |
if (windowSequence == 2) { | |
maxSfb = 0x0f & data[1]; | |
scaleFactorGrouping = (0xfe & data[2]) >> 1; | |
maskPresent = | |
((0x01 & data[2]) << 1) | | |
((0x80 & data[3]) >> 7); | |
startBit = 25; | |
} else { | |
maxSfb = | |
((0x0f & data[1]) << 2) | | |
((0xc0 & data[2]) >> 6); | |
scaleFactorGrouping = -1; | |
maskPresent = (0x18 & data[2]) >> 3; | |
startBit = 21; | |
} | |
if (maskPresent == 1) { | |
int sfgZeroBitCount = 0; | |
for (int b = 0; b < 7; b++) { | |
if ((scaleFactorGrouping & (1 << b)) == 0) { | |
sfgZeroBitCount++; | |
} | |
} | |
int numWindowGroups = 1 + sfgZeroBitCount; | |
int skip = maxSfb * numWindowGroups; | |
startBit += skip; | |
} | |
int bytesNeeded = 1 + ((startBit + 7) / 8); | |
byte[] oldData = data; | |
data = new byte[bytesNeeded]; | |
data[0] = oldData[0]; | |
data[1] = oldData[1]; | |
data[2] = oldData[2]; | |
data[3] = oldData[3]; | |
stream.read(data, 4, bytesNeeded - 4); | |
mOffset += (bytesNeeded - 4); | |
int firstChannelGain = 0; | |
for (int b = 0; b < 8; b++) { | |
int b0 = (b + startBit) / 8; | |
int b1 = 7 - ((b + startBit) % 8); | |
int add = (((1 << b1) & data[b0]) >> b1) << (7 - b); | |
firstChannelGain += add; | |
} | |
mFrameGains[frameIndex] = firstChannelGain; | |
break; | |
default: | |
if (frameIndex > 0) { | |
mFrameGains[frameIndex] = mFrameGains[frameIndex - 1]; | |
} else { | |
mFrameGains[frameIndex] = 0; | |
} | |
break; | |
} | |
int skip = mFrameLens[frameIndex] - (mOffset - initialOffset); | |
stream.skip(skip); | |
mOffset += skip; | |
} | |
private void parsingAtoms(int atomType) throws IOException | |
{ | |
byte[] header; | |
byte[] data; | |
int length; | |
switch(atomType) | |
{ | |
// header | |
case _MOOV: | |
case _TRAK: | |
case _MDIA: | |
case _MINF: | |
case _STBL: | |
{ | |
header = new byte[8]; | |
data = new byte[0]; | |
stream.read(header, 0, 8); | |
length = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
mOffset += 8; | |
break; | |
} | |
case _STSZ: | |
{ | |
header = new byte[20]; | |
stream.read(header, 0, 20); | |
length = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
mNumFrames = | |
((0xff & header[16]) << 24) | | |
((0xff & header[17]) << 16) | | |
((0xff & header[18]) << 8) | | |
((0xff & header[19])); | |
Log.e("writeFile", "mNumFrames : "+mNumFrames); | |
mFrameOffsets = new int[mNumFrames]; | |
mFrameLens = new int[mNumFrames]; | |
mFrameGains = new int[mNumFrames]; | |
byte[] frameLenBytes = new byte[4 * mNumFrames]; | |
stream.read(frameLenBytes, 0, 4 * mNumFrames); | |
mOffset += 4 * mNumFrames; | |
for (int i = 0; i < mNumFrames; i++) { | |
mFrameLens[i] = | |
((0xff & frameLenBytes[4 * i + 0]) << 24) | | |
((0xff & frameLenBytes[4 * i + 1]) << 16) | | |
((0xff & frameLenBytes[4 * i + 2]) << 8) | | |
((0xff & frameLenBytes[4 * i + 3])); | |
} | |
data = new byte[length-20]; | |
data = frameLenBytes; | |
break; | |
} | |
case _STTS: | |
{ | |
header = new byte[16]; | |
stream.read(header, 0, 16); | |
length = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
mSamplesPerFrame = | |
((0xff & header[12]) << 24) | | |
((0xff & header[13]) << 16) | | |
((0xff & header[14]) << 8) | | |
((0xff & header[15])); | |
data = new byte[length-16]; | |
stream.read(data, 0, length-16); | |
break; | |
} | |
case _MDAT: | |
{ | |
header = new byte[8]; | |
stream.read(header, 0, 8); | |
length = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
data = new byte[length-8]; | |
stream.read(data, 0, length-8); | |
int initialOffset = mMdatOffset; | |
mOffset = initialOffset; | |
Log.e("parseMdat", "mOffset : "+mMdatOffset); | |
for (int i = 0; i < mNumFrames; i++) { | |
mFrameOffsets[i] = mOffset; | |
if (mOffset - initialOffset + mFrameLens[i] > length - 16) { | |
mFrameGains[i] = 0; | |
} else { | |
readFrameAndComputeGain(stream, i); | |
} | |
if (mFrameGains[i] < mMinGain) | |
mMinGain = mFrameGains[i]; | |
if (mFrameGains[i] > mMaxGain) | |
mMaxGain = mFrameGains[i]; | |
} | |
break; | |
} | |
default: | |
{ | |
header = new byte[8]; | |
stream.read(header, 0, 8); | |
length = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
data = new byte[length-8]; | |
stream.read(data, 0, length-8); | |
break; | |
} | |
} | |
Block atom = new Block(); | |
atom.header = header; | |
atom.data = data; | |
atom.len = length; | |
Log.e("parsingAtoms", "atom.len : "+atom.len); | |
Log.e("parsingAtoms", "mOffset : "+mOffset); | |
// FREE | |
if (header[0] == 0 && | |
header[4] == 'f' && | |
header[5] == 'r' && | |
header[6] == 'e' && | |
header[7] == 'e') | |
{ | |
//pass | |
} | |
else | |
{ | |
mAtomMap.put(atomType, atom); | |
} | |
if(atomType == _STCO) | |
{ | |
mMdatOffset = ((0xff & data[8]) << 24) | | |
((0xff & data[9]) << 16) | | |
((0xff & data[10]) << 8) | | |
((0xff & data[11])); | |
Log.e("parsingAtom", "mMdatOffset : "+mMdatOffset); | |
} | |
if(atomType == _STSD) | |
{ | |
Log.e("parseMp4aFromStsd", "data[40] : "+data[40]); | |
Log.e("parseMp4aFromStsd", "data[41] : "+data[41]); | |
setSampleRate(((0xff & data[40]) << 8) | ((0xff & data[41]))); | |
} | |
if(atomType == _STTS) | |
{ | |
setSamplePerFrame(((0xff & data[4]) << 24) | | |
((0xff & data[5]) << 16) | | |
((0xff & data[6]) << 8) | | |
((0xff & data[7]))); | |
} | |
} | |
private void parseAAC() | |
{ | |
mAtomMap = new HashMap<Integer, Block>(); | |
try | |
{ | |
if(getFTYP()) | |
{ | |
parseMOOV(); | |
parseFREE(); | |
parseMDAT(); | |
} | |
} | |
catch(IOException e) | |
{ | |
e.printStackTrace(); | |
} | |
} | |
private boolean getFTYP() throws IOException | |
{ | |
byte[] header = new byte[8]; | |
stream.read(header, 0, 8); | |
if (header[0] == 0 && | |
header[4] == 'f' && | |
header[5] == 't' && | |
header[6] == 'y' && | |
header[7] == 'p') | |
{ | |
Block atom = new Block(); | |
atom.start = mOffset; | |
atom.header = header; | |
atom.len = ((0xff & header[0]) << 24) | | |
((0xff & header[1]) << 16) | | |
((0xff & header[2]) << 8) | | |
((0xff & header[3])); | |
byte [] data = new byte[atom.len-8]; | |
stream.read(data, 0, atom.len-8); | |
atom.data = data; | |
mOffset += atom.len; | |
mAtomMap.put(_FTYP, atom); | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
private void parseMOOV() throws IOException | |
{ | |
parsingAtoms(_MOOV); | |
parseMVHD(); | |
parseTRAK(); | |
} | |
private void parseMVHD() throws IOException | |
{ | |
parsingAtoms(_MVHD); | |
} | |
private void parseTRAK() throws IOException | |
{ | |
parsingAtoms(_TRAK); | |
parseTKHD(); | |
parseMDIA(); | |
} | |
private void parseTKHD() throws IOException | |
{ | |
parsingAtoms(_TKHD); | |
} | |
private void parseMDIA() throws IOException | |
{ | |
parsingAtoms(_MDIA); | |
parseMDHD(); | |
parseHDLR(); | |
parseMINF(); | |
} | |
private void parseMDHD() throws IOException | |
{ | |
parsingAtoms(_MDHD); | |
} | |
private void parseHDLR() throws IOException | |
{ | |
parsingAtoms(_HDLR); | |
} | |
private void parseMINF() throws IOException | |
{ | |
parsingAtoms(_MINF); | |
parseSMHD(); | |
parseDINF(); | |
parseSTBL(); | |
} | |
private void parseSMHD() throws IOException | |
{ | |
parsingAtoms(_SMHD); | |
} | |
private void parseDINF() throws IOException | |
{ | |
parsingAtoms(_DINF); | |
} | |
private void parseSTBL() throws IOException | |
{ | |
parsingAtoms(_STBL); | |
parseSTSD(); | |
parseSTTS(); | |
parseSTSZ(); | |
parseSTSC(); | |
parseSTCO(); | |
} | |
private void parseSTSD() throws IOException | |
{ | |
parsingAtoms(_STSD); | |
} | |
private void parseSTTS() throws IOException | |
{ | |
parsingAtoms(_STTS); | |
} | |
private void parseSTSZ() throws IOException | |
{ | |
parsingAtoms(_STSZ); | |
} | |
private void parseSTSC() throws IOException | |
{ | |
parsingAtoms(_STSC); | |
} | |
private void parseSTCO() throws IOException | |
{ | |
parsingAtoms(_STCO); | |
} | |
private void parseFREE() throws IOException | |
{ | |
parsingAtoms(_FREE); | |
} | |
private void parseMDAT() throws IOException | |
{ | |
mMinGain = 255; | |
mMaxGain = 0; | |
parsingAtoms(_MDAT); | |
} | |
private void setSampleRate(int rate) | |
{ | |
mSampleRate = rate; | |
} | |
private void setSamplePerFrame(int sample) | |
{ | |
mSamplesPerFrame = sample; | |
} | |
public void SetAtomData(int atomType, byte[] data) { | |
Block atom = mAtomMap.get(atomType); | |
if (atom == null) { | |
atom = new Block(); | |
mAtomMap.put(atomType, atom); | |
} | |
if(atomType == _STSZ) | |
{ | |
atom.len = data.length + 20; | |
} | |
else | |
{ | |
atom.len = data.length + 8; | |
} | |
atom.header[0] = (byte)((atom.len >> 24) & 0xff); | |
atom.header[1] = (byte)((atom.len >> 16) & 0xff); | |
atom.header[2] = (byte)((atom.len >> 8) & 0xff); | |
atom.header[3] = (byte)(atom.len & 0xff); | |
if(atomType == _STTS) | |
{ | |
atom.header[8] = data[0]; | |
atom.header[9] = data[1]; | |
atom.header[10] = data[2]; | |
atom.header[11] = data[3]; | |
atom.header[12] = data[4]; | |
atom.header[13] = data[5]; | |
atom.header[14] = data[6]; | |
atom.header[15] = data[7]; | |
byte[] tempdata = new byte[8]; | |
for(int i = 0; i < 8; i++) | |
{ | |
tempdata[i] = data[8+i]; | |
} | |
data = null; | |
data = tempdata; | |
} | |
if(atomType == _STSZ) | |
{ | |
atom.header[16] = (byte)((mNumFrames >> 24) & 0xff); | |
atom.header[17] = (byte)((mNumFrames >> 16) & 0xff); | |
atom.header[18] = (byte)((mNumFrames >> 8) & 0xff); | |
atom.header[19] = (byte)(mNumFrames & 0xff); | |
} | |
atom.data = data; | |
} | |
private byte[] editFile(int startValue, int numFrames) throws IOException | |
{ | |
mOffset = 0; | |
mMdatOffset = 0; | |
setFTYP(); | |
setMOOV(startValue, numFrames); | |
setMDAT(startValue, numFrames); | |
// out = new FileOutputStream(mvoiceFile); | |
return mergeByte(); | |
// out.close(); | |
} | |
private void setFTYP() | |
{ | |
SetAtomData(_FTYP, new byte[] { | |
'i', 's', 'o', 'm', | |
0, 0, 0, 0, | |
'i', 's', 'o', 'm', | |
'3', 'g', 'p', '4' | |
}); | |
} | |
private void setMOOV(int startFrame, int numFrames) | |
{ | |
setTRAK(startFrame, numFrames); | |
mAtomMap.get(_MOOV).len = | |
8 + | |
mAtomMap.get(_MVHD).len + | |
mAtomMap.get(_TRAK).len; | |
setHeaderLength(_MOOV, mAtomMap.get(_MOOV).len); | |
mMdatOffset = mAtomMap.get(_FTYP).len + mAtomMap.get(_MOOV).len + 8; | |
setSTCO(); | |
} | |
private void setTRAK(int startFrame, int numFrames) | |
{ | |
setMDIA(startFrame, numFrames); | |
mAtomMap.get(_TRAK).len = | |
8 + | |
mAtomMap.get(_TKHD).len + | |
mAtomMap.get(_MDIA).len; | |
setHeaderLength(_TRAK, mAtomMap.get(_TRAK).len); | |
} | |
private void setMDIA(int startFrame, int numFrames) | |
{ | |
setMINF(startFrame, numFrames); | |
mAtomMap.get(_MDIA).len = | |
8 + | |
mAtomMap.get(_MDHD).len + | |
mAtomMap.get(_HDLR).len + | |
mAtomMap.get(_MINF).len; | |
setHeaderLength(_MDIA, mAtomMap.get(_MDIA).len); | |
} | |
private void setMINF(int startFrame, int numFrames) | |
{ | |
setSTBL(startFrame, numFrames); | |
mAtomMap.get(_MINF).len = | |
8 + | |
mAtomMap.get(_DINF).len + | |
mAtomMap.get(_SMHD).len + | |
mAtomMap.get(_STBL).len; | |
setHeaderLength(_MINF, mAtomMap.get(_MINF).len); | |
} | |
private void setSTBL(int startFrame, int numFrames) | |
{ | |
setSTTS(startFrame, numFrames); | |
setSTSZ(startFrame, numFrames); | |
setSTSC(startFrame, numFrames); | |
mAtomMap.get(_STBL).len = | |
8 + | |
mAtomMap.get(_STSD).len + | |
mAtomMap.get(_STTS).len + | |
mAtomMap.get(_STSC).len + | |
mAtomMap.get(_STSZ).len + | |
mAtomMap.get(_STCO).len; | |
setHeaderLength(_STBL, mAtomMap.get(_STBL).len); | |
} | |
private void setSTTS(int startVaue, int numFrames) | |
{ | |
SetAtomData(_STTS, new byte[] { | |
0, 0, 0, 0, // version / flags | |
0, 0, 0, 1, // entry count | |
(byte) ((numFrames >> 24) & 0xff), | |
(byte) ((numFrames >> 16) & 0xff), | |
(byte) ((numFrames >> 8) & 0xff), | |
(byte) (numFrames & 0xff), | |
(byte) ((mSamplesPerFrame >> 24) & 0xff), | |
(byte) ((mSamplesPerFrame >> 16) & 0xff), | |
(byte) ((mSamplesPerFrame >> 8) & 0xff), | |
(byte) (mSamplesPerFrame & 0xff) | |
}); | |
} | |
private void setSTSZ(int startFrame, int numFrames) | |
{ | |
byte[] stszData = new byte[4 * numFrames]; | |
mNumFrames = numFrames; | |
for (int i = 0; i < numFrames; i++) { | |
stszData[4 * i] = | |
(byte)((mFrameLens[startFrame + i] >> 24) & 0xff); | |
stszData[1 + 4 * i] = | |
(byte)((mFrameLens[startFrame + i] >> 16) & 0xff); | |
stszData[2 + 4 * i] = | |
(byte)((mFrameLens[startFrame + i] >> 8) & 0xff); | |
stszData[3 + 4 * i] = | |
(byte)(mFrameLens[startFrame + i] & 0xff); | |
} | |
SetAtomData(_STSZ, stszData); | |
} | |
private void setSTSC(double startVaue, int numFrames) | |
{ | |
SetAtomData(_STSC, new byte[] { | |
0, 0, 0, 0, | |
0, 0, 0, 1, | |
0, 0, 0, 1, | |
(byte) ((numFrames >> 24) & 0xff), | |
(byte) ((numFrames >> 16) & 0xff), | |
(byte) ((numFrames >> 8) & 0xff), | |
(byte) (numFrames & 0xff), | |
0, 0, 0, 1 | |
}); | |
} | |
private void setHeaderLength(int atomType, int length) | |
{ | |
mAtomMap.get(atomType).header[0] = (byte)((length >> 24) & 0xff); | |
mAtomMap.get(atomType).header[1] = (byte)((length >> 16) & 0xff); | |
mAtomMap.get(atomType).header[2] = (byte)((length >> 8) & 0xff); | |
mAtomMap.get(atomType).header[3] = (byte)(length & 0xff); | |
} | |
private void setSTCO() | |
{ | |
mAtomMap.get(_STCO).data[8] = (byte)((mMdatOffset >> 24) & 0xff); | |
mAtomMap.get(_STCO).data[9] = (byte)((mMdatOffset >> 16) & 0xff); | |
mAtomMap.get(_STCO).data[10] = (byte)((mMdatOffset >> 8) & 0xff); | |
mAtomMap.get(_STCO).data[11] = (byte)(mMdatOffset & 0xff); | |
} | |
private void setMDAT(int startFrame, int numFrames) | |
{ | |
int maxFrameLen = 0; | |
for (int i = 0; i < numFrames; i++) { | |
if (mFrameLens[startFrame + i] > maxFrameLen) | |
maxFrameLen = mFrameLens[startFrame + i]; | |
} | |
byte[] buffer; | |
byte[] tempbuffer = new byte[mAtomMap.get(_MDAT).data.length]; | |
setHeaderLength(_MDAT, maxFrameLen); | |
int pos = 0; | |
int mdatpos = 0; | |
int start = 0; | |
int end = 0; | |
tempbuffer = mAtomMap.get(_MDAT).data; | |
for (int i = 0; i < numFrames; i++) { | |
int skip = mFrameOffsets[startFrame + i] - pos - 2835032; | |
int len = mFrameLens[startFrame + i]; | |
if (skip < 0) { | |
continue; | |
} | |
if (skip > 0) { | |
if(start == 0) | |
{ | |
start = skip; | |
end = start; | |
} | |
} | |
end += len; | |
} | |
buffer = new byte[end-start]; | |
for(int j = start; j < end; j++) | |
{ | |
buffer[j - start] = mAtomMap.get(_MDAT).data[j]; | |
} | |
mAtomMap.get(_MDAT).data = null; | |
mAtomMap.get(_MDAT).data = buffer; | |
} | |
private byte[] mergeByte() | |
{ | |
byte bkFTYP[] = byteMerger(mAtomMap.get(_FTYP).header, mAtomMap.get(_FTYP).data); | |
byte bkMOOV[] = byteMerger(mAtomMap.get(_MOOV).header, byteMerger(mAtomMap.get(_MVHD).header, mAtomMap.get(_MVHD).data)); | |
byte bkTRAK[] = byteMerger(mAtomMap.get(_TRAK).header, byteMerger(mAtomMap.get(_TKHD).header, byteMerger(mAtomMap.get(_TKHD).data, mAtomMap.get(_MDIA).header))); | |
byte bkMDHD[] = byteMerger(mAtomMap.get(_MDHD).header, byteMerger(mAtomMap.get(_MDHD).data, byteMerger(mAtomMap.get(_HDLR).header, byteMerger(mAtomMap.get(_HDLR).data, mAtomMap.get(_MINF).header)))); | |
byte bkDINF[] = byteMerger(mAtomMap.get(_DINF).header, byteMerger(mAtomMap.get(_DINF).data, mAtomMap.get(_STBL).header)); | |
byte bkSTSD[] = byteMerger(mAtomMap.get(_STSD).header, | |
byteMerger(mAtomMap.get(_STSD).data, | |
byteMerger(mAtomMap.get(_STTS).header, | |
byteMerger(mAtomMap.get(_STTS).data, | |
byteMerger(mAtomMap.get(_STSZ).header, | |
byteMerger(mAtomMap.get(_STSZ).data, | |
byteMerger(mAtomMap.get(_STSC).header, | |
byteMerger(mAtomMap.get(_STSC).data, | |
byteMerger(mAtomMap.get(_STCO).header, mAtomMap.get(_STCO).data))))))))); | |
byte bkSMHD[] = byteMerger(mAtomMap.get(_SMHD).header, mAtomMap.get(_SMHD).data); | |
byte bkMDAT[] = byteMerger(mAtomMap.get(_MDAT).header, mAtomMap.get(_MDAT).data); | |
byte byteMerged[] = byteMerger(bkFTYP, byteMerger(bkMOOV, byteMerger(bkTRAK, byteMerger(bkMDHD, byteMerger(bkDINF, byteMerger(bkSTSD, byteMerger(bkSMHD, bkMDAT))))))); | |
return byteMerged; | |
} | |
private void setDuration(int duration) | |
{ | |
mAtomMap.get(_MVHD).data[16] = (byte)((duration >> 24) & 0xff); | |
mAtomMap.get(_MVHD).data[17] = (byte)((duration >> 16) & 0xff); | |
mAtomMap.get(_MVHD).data[18] = (byte)((duration >> 8) & 0xff); | |
mAtomMap.get(_MVHD).data[19] = (byte)(duration & 0xff); | |
mAtomMap.get(_TKHD).data[20] = (byte)((duration >> 24) & 0xff); | |
mAtomMap.get(_TKHD).data[21] = (byte)((duration >> 16) & 0xff); | |
mAtomMap.get(_TKHD).data[22] = (byte)((duration >> 8) & 0xff); | |
mAtomMap.get(_TKHD).data[23] = (byte)(duration & 0xff); | |
} | |
public byte[] editVoiceFile(double start, double end) | |
{ | |
parseAAC(); | |
int startValue = secondsToFrame(start/1000.0); | |
int endValue = secondsToFrame(end/1000.0); | |
setDuration((int)(end - start)); | |
int numFrames = endValue - startValue; | |
//write | |
try | |
{ | |
return editFile(startValue, numFrames); | |
} | |
catch (IOException e) | |
{ | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
private int secondsToFrame(double seconds) | |
{ | |
Log.e("secondsToFrame", "seconds : "+seconds); | |
Log.e("secondsToFrame", "mSampleRate : "+mSampleRate); | |
return (int)(1.0 * seconds * mSampleRate / mSamplesPerFrame + 0.5); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedOutputStream; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
public class EditAMRUnit extends EditUnit{ | |
public EditAMRUnit(File f,long duration){ | |
super.mVoiceFile = f; | |
super.mDuration = duration; | |
mPacketUnit = 13; | |
mHeaderNumSeparator = 6; | |
} | |
public void setSecondFile(File f){ | |
super.mVoiceFileSecond = f; | |
} | |
public void mergeVoiceFile(){ | |
byte byteHeader[] = getHeader(); | |
byte byteBody1[] = getBody(mVoiceFile); | |
byte byteBody2[] = getBody(mVoiceFileSecond); | |
byte byteMerged[] = byteMerger(byteBody1,byteBody2); | |
byte byteResult[] = byteMerger(byteHeader,byteMerged); | |
try{ | |
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(mVoiceFile.getAbsolutePath())); | |
bos.write(byteResult); | |
bos.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
} | |
public void mergeVoiceFileForPause(){ | |
byte byteHeader[] = getHeader(); | |
byte byteBody1[] = getBody(tempSavedData); | |
byte byteBody2[] = getBody(mVoiceFile); | |
byte byteMerged[] = byteMerger(byteBody1,byteBody2); | |
byte byteResult[] = byteMerger(byteHeader,byteMerged); | |
tempSavedData = new byte[(int)byteResult.length]; | |
tempSavedData = byteResult; | |
} | |
public byte[] editVoiceFile(int startValue,int endValue){ | |
byte byteHeader[] = getHeader(); | |
byte byteBody[] = getBody(mVoiceFile); | |
byte byteModifiedBody[] = getModifiedBody(byteBody, startValue, endValue); | |
byte byteResult[] = byteMerger(byteHeader, byteModifiedBody); | |
return byteResult; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedOutputStream; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
public class EditQCPUnit extends EditUnit{ | |
private int mEditPoint[] ={4, 182, 190, 194}; | |
private long xorHelper1 = 0x000000FF; | |
private long xorHelper2 = xorHelper1 << 8; | |
private long xorHelper3 = xorHelper1 << 16; | |
private long xorHelper4 = xorHelper1 << 24; | |
public EditQCPUnit(File f,long duration){ | |
super.mVoiceFile = f; | |
super.mDuration = duration; | |
mPacketUnit = 35; | |
mHeaderNumSeparator = 194; | |
} | |
public void setSecondFile(File f){ | |
super.mVoiceFileSecond = f; | |
} | |
public byte[] getModifiedHeader(byte[] headerBuffer, byte[] bodyBuffer){ | |
int thirdModifyByte = bodyBuffer.length; | |
int firstModifyByte = thirdModifyByte + 186; //BA = 186 | |
int secondModifyByte = thirdModifyByte/35; | |
byte[] buffer = new byte[headerBuffer.length]; | |
byte[] firstByteArray = new byte[4]; | |
byte[] secondByteArray = new byte[4]; | |
byte[] thirdByteArray = new byte[4]; | |
firstByteArray[0] = (byte)(firstModifyByte & xorHelper1); | |
firstByteArray[1] = (byte)((firstModifyByte & xorHelper2) >> 8); | |
firstByteArray[2] = (byte)((firstModifyByte & xorHelper3) >> 16); | |
firstByteArray[3] = (byte)((firstModifyByte & xorHelper4) >> 24); | |
secondByteArray[0] = (byte)(secondModifyByte & xorHelper1); | |
secondByteArray[1] = (byte)((secondModifyByte & xorHelper2) >> 8); | |
secondByteArray[2] = (byte)((secondModifyByte & xorHelper3) >> 16); | |
secondByteArray[3] = (byte)((secondModifyByte & xorHelper4) >> 24); | |
thirdByteArray[0] = (byte)(thirdModifyByte & xorHelper1); | |
thirdByteArray[1] = (byte)((thirdModifyByte & xorHelper2) >> 8); | |
thirdByteArray[2] = (byte)((thirdModifyByte & xorHelper3) >> 16); | |
thirdByteArray[3] = (byte)((thirdModifyByte& xorHelper4) >> 24); | |
for(int i=0;i<mEditPoint[3];i++){ | |
if(i == mEditPoint[0] || i == (mEditPoint[0]+1)|| i == (mEditPoint[0]+2) || i == (mEditPoint[0]+3) ){ | |
if(i == mEditPoint[0]){ | |
buffer[i] = firstByteArray[0] ; | |
}else if(i == mEditPoint[0]+1){ | |
buffer[i] = firstByteArray[1] ; | |
}else if(i == mEditPoint[0]+2){ | |
buffer[i] = firstByteArray[2] ; | |
}else{ | |
buffer[i] = firstByteArray[3] ; | |
} | |
}else if(i == mEditPoint[1] || i == (mEditPoint[1]+1) || i == (mEditPoint[1]+2) || i == (mEditPoint[1]+3)){ | |
if(i == mEditPoint[1]){ | |
buffer[i] = secondByteArray[0] ; | |
}else if(i == mEditPoint[1]+1){ | |
buffer[i] = secondByteArray[1] ; | |
}else if(i == mEditPoint[1]+2){ | |
buffer[i] = secondByteArray[2] ; | |
}else{ | |
buffer[i] = secondByteArray[3] ; | |
} | |
}else if(i == mEditPoint[2] || i == (mEditPoint[2]+1) || i == (mEditPoint[2]+2) || i == (mEditPoint[2]+3)){ | |
if(i == mEditPoint[2]){ | |
buffer[i] = thirdByteArray[0] ; | |
}else if(i == mEditPoint[2]+1){ | |
buffer[i] = thirdByteArray[1] ; | |
}else if(i == mEditPoint[2]+2){ | |
buffer[i] = thirdByteArray[2] ; | |
}else{ | |
buffer[i] = thirdByteArray[3] ; | |
} | |
}else{ | |
buffer[i]=(byte)headerBuffer[i]; | |
} | |
} | |
return buffer; | |
} | |
public void mergeVoiceFile(){ | |
byte byteHeader[] = getHeader(); | |
byte byteBody1[] = getBody(mVoiceFile); | |
byte byteBody2[] = getBody(mVoiceFileSecond); | |
byte byteMerged[] = byteMerger(byteBody1,byteBody2); | |
byte byteModifiedHeader[] = getModifiedHeader(byteHeader, byteMerged); | |
byte byteResult[] = byteMerger(byteModifiedHeader,byteMerged); | |
try{ | |
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(mVoiceFile.getAbsolutePath())); | |
bos.write(byteResult); | |
bos.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
} | |
public void mergeVoiceFileForPause(){ | |
byte byteHeader[] = getHeader(); | |
byte byteBody1[] = getBody(tempSavedData); | |
byte byteBody2[] = getBody(mVoiceFile); | |
byte byteMerged[] = byteMerger(byteBody1,byteBody2); | |
byte byteModifiedHeader[] = getModifiedHeader(byteHeader, byteMerged); | |
byte byteResult[] = byteMerger(byteModifiedHeader,byteMerged); | |
tempSavedData = new byte[(int)byteResult.length]; | |
tempSavedData = byteResult; | |
} | |
public byte[] editVoiceFile(int startValue,int endValue){ | |
byte byteBody[] = getBody(mVoiceFile); | |
byte byteHeader[] = getModifiedHeader(getHeader(),byteBody); | |
byte byteModifiedBody[] = getModifiedBody(byteBody, startValue, endValue); | |
byte byteResult[] = byteMerger(byteHeader, byteModifiedBody); | |
return byteResult; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedInputStream; | |
import java.io.BufferedOutputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileOutputStream; | |
import java.nio.ByteBuffer; | |
import android.app.Activity; | |
import android.util.Log; | |
public class EditUnit { | |
protected File mVoiceFile; | |
protected File mVoiceFileSecond; | |
protected int mHeaderNumSeparator; | |
protected long mDuration; | |
protected int mPacketUnit; | |
protected Activity mActivity; | |
protected byte[] tempSavedData; | |
public void mergeVoiceFile(){}; | |
public void setChangeFile(File f,long duration){ | |
mVoiceFile = f; | |
mDuration = duration; | |
} | |
public byte[] getHeader(){ | |
byte[] headerBuffer = new byte[mHeaderNumSeparator]; | |
try{ | |
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(mVoiceFile)); | |
bis.read(headerBuffer,0,mHeaderNumSeparator); | |
bis.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
return headerBuffer; | |
} | |
public byte[] getBody(File f){ | |
ByteBuffer bodyByteBuffer = ByteBuffer.allocateDirect((int)f.length()-mHeaderNumSeparator); | |
byte[] bodyBuffer = new byte[(int)f.length()]; | |
try{ | |
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f)); | |
bis.read(bodyBuffer); | |
bis.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
bodyByteBuffer.position(0); | |
bodyByteBuffer.put(bodyBuffer, mHeaderNumSeparator, (int)f.length()-mHeaderNumSeparator); | |
return bodyByteBuffer.array(); | |
} | |
public byte[] getBody(byte[] b){ | |
ByteBuffer bodyByteBuffer = ByteBuffer.allocateDirect((int)b.length-mHeaderNumSeparator); | |
bodyByteBuffer.position(0); | |
bodyByteBuffer.put(b, mHeaderNumSeparator, (int)b.length-mHeaderNumSeparator); | |
return bodyByteBuffer.array(); | |
} | |
public byte[] getModifiedBody(byte[] bodyBuffer, int startDuration, int finishDuration){ | |
int duration100ms = (int)mDuration/100; | |
int totalSt100ms = startDuration/100; | |
int totalEd100ms = finishDuration/100; | |
int bitTo100msFile = bodyBuffer.length * 8 / duration100ms; | |
int countOfStPacketRemoving = (bitTo100msFile * totalSt100ms)/mPacketUnit/8 ; | |
int countOfEdPacketRemoving = (bitTo100msFile * (duration100ms-totalEd100ms))/mPacketUnit/8; | |
int stremovingByte = (countOfStPacketRemoving) * mPacketUnit; | |
int edremovingByte = (countOfEdPacketRemoving) * mPacketUnit; | |
ByteBuffer bodyByteBuffer = ByteBuffer.allocateDirect(bodyBuffer.length - stremovingByte - edremovingByte); | |
bodyByteBuffer.position(0); | |
bodyByteBuffer.put(bodyBuffer,stremovingByte,bodyBuffer.length - stremovingByte - edremovingByte); | |
bodyByteBuffer.position(0); | |
return bodyByteBuffer.array(); | |
} | |
public byte[] byteMerger(byte[] byte1, byte[] byte2){ | |
ByteBuffer buffer = ByteBuffer.allocateDirect(byte1.length+byte2.length); | |
buffer.position(0); | |
buffer.put(byte1); | |
buffer.position(byte1.length); | |
buffer.put(byte2); | |
buffer.position(0); | |
return buffer.array(); | |
} | |
public void saveTempFile(){ | |
tempSavedData = new byte[(int)mVoiceFile.length()]; | |
try{ | |
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(mVoiceFile)); | |
bis.read(tempSavedData); | |
bis.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
} | |
public void saveOutputFileForPause(){ | |
try{ | |
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(mVoiceFile.getAbsolutePath())); | |
bos.write(tempSavedData); | |
bos.close(); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment