在python中读取WAV文件

时间:2016-02-20 03:46:41

标签: python wav unpack steganography

api

我使用上面的代码从python中的立体声wav文件中提取字节。但是,我得到了一些乱码而不是字节。使用import wave,struct f = wave.open('bird.wav', 'r') for i in range(5,10): frame = f.readframes(i) print frame struct.unpack('<H',frame) 函数我收到以下错误

  

&#34; unpack需要一个长度为2&#34;

的字符串参数

我在代码中进行哪些更改以在1&0和0&#39;中打印这些字节?我想稍后修改用于隐写术的音频帧的LSB。

2 个答案:

答案 0 :(得分:1)

我不确定你为什么要用二进制文件打印这些字节,但这样做很容易。

您需要将字节转换为整数,然后使用str.format方法对其进行格式化,旧的% - 样式格式化不会做位。

执行转换的简单方法是使用ord函数,但对于大量字节,最好通过创建bytearray来在一次点击中转换它们。

#Some bytes, using hexadecimal escape codes
s = '\x01\x07\x0f\x35\xad\xff'
print ' '.join(['{0:08b}'.format(ord(c)) for c in s])

b = bytearray(s)
print ' '.join(['{0:08b}'.format(u) for u in b])

<强>输出

00000001 00000111 00001111 00110101 10101101 11111111
00000001 00000111 00001111 00110101 10101101 11111111

通常,十六进制表示法比二进制表示更方便。

from binascii import hexlify

print hexlify(s)
print ' '.join(['%02X' % u for u in b])
print ' '.join(['%02X' % ord(c) for c in s])
print ' '.join(['{0:02X}'.format(ord(c)) for c in s])    

<强>输出

01070f35adff
01 07 0F 35 AD FF
01 07 0F 35 AD FF
01 07 0F 35 AD FF

我刚刚看到你的评论重新隐写。翻转字节位的最方便的方法是使用bytearray。您可以使用bytearray函数轻松地将str转换回字符串。

print hexlify(str(b))        

<强>输出

01070f35adff

字符串格式化选项在官方Python文档中描述。对于旧% - 样式格式,请参阅5.6.2. String Formatting Operations。对于现代str.format选项,请参阅7.1.3. Format String Syntax7.1.3.1. Format Specification Mini-Language

{0:08b}中冒号之前的0是字段位置(在最近的Python版本中可以省略)。它表示我们希望将此格式代码应用于.format的第一个参数,即索引为零的参数。例如,

'{0} {2} {1}'.format('one', 'two', 'three') 

打印

one three two

b表示我们要将数字打印为二进制数。 08表示我们希望输出宽度为8个字符,对于小于8位的二进制数,填充为零。

%02X中,大写X表示我们要将数字打印为十六进制,对于大于9的数字使用大写字母A-F,我们可以使用小写x来获取小写字母。 02表示我们希望输出宽度为2个字符,对于小于2个十六进制数字的十六进制数字,填充为零。

答案 1 :(得分:1)

如果要修改字节的lsb,则无法将值表示为二进制字符串。实际上,你会做一些事情(伪代码):

<%= link_to fa_icon("close"), wiki_collaborator_path(@wiki, c), method: :delete, remote: true %>

有更多直接有效的方法来修改位值,而bitwise operators则更新。例如,假设我们要将01001001(十进制73)更改为01001000.我们要创建一个位掩码11111110,其十进制值为254,byte = '\x6h' binary = convert_to_bits(byte) # some way of getting 1s and 0s in a string binary = binary[:7] + my_bit_string byte = convert_to_byte(binary) 表示我们的值。

AND

当你将一个位嵌入一个字节时,lsb可能会改变,也可能不会改变。有很多方法可以解决这个问题,但最直接的方法是将lsb归零,然后使用>>> value = 73 & 254 >>> value 72 >>> '{0:08b}'.format(value) '01001000' 覆盖它(如果你还希望嵌入多个位,则非常通用)。

OR

您也可以使用byte = (byte & 254) | my_bit 将lsb归零,然后使用right shift,但这需要2次操作而不是1次。

left shift

或者您可以检查lsb和您的位是否不同并使用byte = ((byte >> 1) << 1) | my_bit 翻转它。但是,此方法使用分支并且效率最低。

XOR

因此,您需要做的就是将字节转换为整数数组。您可以使用if (byte & 1) != my_bit: byte = byte ^ 1 # no need to do anything if they are the same ,但有更高效的内置方式。使用bytearray()bytes()

[ord(byte) for byte in frame]

使用array.array()(对于数十万字节来说,这似乎有点慢):

>>> frame = '\x0f\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
>>> frame_bytes = bytearray(frame)
>>> frame_bytes[0]
15
>>> frame_bytes[0] = 14       # modify
>>> bytes(frame_bytes)        # convert back to bytes
'\x0e\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'

嵌入和提取的示例。

>>> import array
>>> frame = '\x0f\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'
>>> frame_bytes = array.array('B', frame)
>>> frame_bytes[0]
15
>>> frame_bytes[0] = 14       # modify
>>> frame_bytes.tostring()    # convert back to bytes; in Python 3 use `tobytes()`
'\x0e\x02\x0e\x02\xf7\x00\xf7\x00T\xffT\xff'

如果您的秘密是一个字符串或一系列字节,则convert them to a list of 1s and 0s很容易。

最后,请确保不要修改任何标头数据,因为这可能会使文件无法读取。