Metode mengompresi/menyimpan data media dalam format WAVE dan JPEG, bagian 1

ЗдравствуйтС! Моя пСрвая сСрия статСй Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π° Π½Π° ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² сТатия ΠΈ хранСния ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ/Π·Π²ΡƒΠΊΠ°, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ JPEG (ΠΈΠ·ΠΎΠ±Ρ€.) ΠΈ WAVE (Π·Π²ΡƒΠΊ), Ρ‚Π°ΠΊΠΆΠ΅ Π² Π½ΠΈΡ… Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ с использованиСм этих Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΎΠ² (.jpg, .wav) Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅. Π’ этой части ΠΌΡ‹ рассмотрим ΠΈΠΌΠ΅Π½Π½ΠΎ WAVE.

Cerita

WAVE (Waveform Audio File Format) adalah format file kontainer untuk menyimpan rekaman aliran audio. Wadah ini biasanya digunakan untuk menyimpan audio termodulasi kode pulsa yang tidak terkompresi. (Diambil dari Wikipedia)

Ini ditemukan dan diterbitkan pada tahun 1991 bersama dengan RIFF oleh Microsoft dan IBM (Perusahaan IT terkemuka saat itu).

Struktur file

File tersebut memiliki bagian header, datanya sendiri, tetapi tidak ada footer. Header memiliki berat total 44 byte.
Header berisi pengaturan jumlah bit dalam sampel, laju sampel, kedalaman suara, dll. informasi yang diperlukan untuk kartu suara. (Semua nilai tabel numerik harus ditulis dalam urutan Little-Endian)

Nama blok
Ukuran blok (B)
Deskripsi/Tujuan
Nilai (untuk beberapa hal itu tetap

potonganId
4
Mendefinisikan file sebagai wadah media
0x52494646 dalam Big-Endian (β€œRIFF”)

ukuran potongan
4
Ukuran seluruh file tanpa chunkId dan chunkSize
UKURAN_FILE - 8

format
4
Ketik definisi dari RIFF
0x57415645 dalam Big-Endian (β€œGELOMBANG”)

subchunk1Id
4
Sehingga file tersebut memakan lebih banyak ruang sebagai kelanjutan formatnya
0x666d7420 dalam Big-Endian (β€œfmt”)

subchunk1Ukuran
4
Header yang tersisa (dalam byte)
16 secara default (untuk kasus tanpa kompresi aliran audio)

format audio
2
Аудио Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ (зависит ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° сТатия ΠΈ структуры Π°ΡƒΠ΄ΠΈΠΎΠ΄Π°Π½Π½Ρ‹Ρ…)
1 (untuk PCM, itulah yang kami pertimbangkan)

nomor saluran
2
Jumlah saluran
1/2, kita akan mengambil 1 saluran (3/4/5/6/7... - trek audio tertentu, misalnya 4 untuk audio quad, dll.)

tingkat sampel
4
Kecepatan pengambilan sampel audio (dalam Hertz)
Semakin tinggi, semakin baik suaranya, tetapi semakin banyak memori yang dibutuhkan untuk membuat trek audio dengan panjang yang sama, nilai yang disarankan adalah 48000 (kualitas suara yang paling dapat diterima)

byteRate
4
Jumlah byte per detik
tingkat sampel nomor saluran bitsPerSample (lebih lanjut)

blokSejajarkan
2
Jumlah byte untuk 1 sampel
numChannels * bitPerSample: 8

bitPerSample
2
Jumlah bit per 1 sampel (kedalaman)
Angka apa pun yang merupakan kelipatan 8. Semakin tinggi angkanya maka audionya akan semakin bagus dan berat, dari 32 bit tidak ada bedanya bagi manusia

subchunk2Id
4
Tanda referensi data (karena mungkin ada elemen header lain bergantung pada format audio)
0x64617461 dalam Big-Endian("data")

subchunk2Ukuran
4
Ukuran area data
ukuran data dalam int

data
byteRate * durasi audio
data audio
?

Contoh GELOMBANG

Tabel sebelumnya dapat dengan mudah diterjemahkan ke dalam struktur dalam C, tetapi bahasa kita saat ini adalah Python. Hal termudah yang dapat Anda lakukan adalah menggunakan β€œgelombang” - generator kebisingan. Untuk tugas ini kita tidak memerlukan byteRate dan kompresi yang tinggi.
Pertama, mari impor modul yang diperlukan:

# WAV.py

from struct import pack  # ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ py-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² Π±Π°Π·ΠΎΠ²Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ ΠΈΠ· C
from os import urandom  # функция для чтСния /dev/urandom, для windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)])  # лямбда ΠΏΠΎΠ΄ windows, Ρ‚.ΠΊ. urandom'Π° Π² Π²ΠΈΠ½Π΄Π΅ Π½Π΅Ρ‚
from sys import argv, exit  # Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊ ΠΏΡ€ΠΎΠ³Π΅ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄

if len(argv) != 3:  # +1 имя скрипта (-1, Ссли Π±ΡƒΠ΄Π΅Ρ‚Π΅ Π·Π°ΠΌΠΎΡ€Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒ)
    print('Usage: python3 WAV.py [num of samples] [output]')
    exit(1)

Selanjutnya, kita perlu membuat semua variabel yang diperlukan dari tabel sesuai dengan ukurannya. Nilai variabel di dalamnya hanya bergantung pada numSamples (jumlah sampel). Semakin banyak jumlahnya, semakin lama kebisingan kita berlangsung.

numSamples = int(argv[1])
output_path = argv[2]

chunkId = b'RIFF'
Format = b'WAVE'
subchunk1ID = b'fmt '
subchunk1Size = b'x10x00x00x00'  # 0d16
audioFormat = b'x01x00'
numChannels = b'x02x00'  # 2-Ρ… ΠΊΠ°Π½Π°Π»ΠΎΠ² Π±ΡƒΠ΄Π΅Ρ‚ достаточно (стСрСо)
sampleRate = pack('<L', 1000)  # 1000 Ρ…Π²Π°Ρ‚ΠΈΡ‚, Π½ΠΎ Ссли ΠΏΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ большС, Ρ‚ΠΎ ΡˆΡƒΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ»Ρ‹ΡˆΠ΅Π½ Π»ΡƒΡ‡ΡˆΠ΅. Π‘ 1000-ю ΠΎΠ½ Π·Π²ΡƒΡ‡ΠΈΡ‚, ΠΊΠ°ΠΊ Π²Π΅Ρ‚Π΅Ρ€
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (32 bit sound)
blockAlign = b'x08x00'  # numChannels * BPS / 8
subchunk2ID = b'data'
subchunk2Size = pack('<L', numSamples * 2 * 4)  # * numChannels * BPS / 8
chunkSize = pack('<L', 36 + numSamples * 2 * 4)  # 36 + subchunk2Size

data = urandom(1000 * 2 * 4 * numSamples)  # сам ΡˆΡƒΠΌ

Yang tersisa hanyalah menuliskannya dalam urutan yang diperlukan (seperti pada tabel):

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # записываСм

Jadi, siap. Untuk menggunakan skrip, kita perlu menambahkan argumen baris perintah yang diperlukan:
python3 WAV.py [num of samples] [output]
jumlah sampel - hitung. sampel
keluaran β€” jalur ke file keluaran

Berikut ini tautan ke file audio uji dengan noise, tetapi untuk menghemat memori saya menurunkan BPS ke 1b/s dan menurunkan jumlah saluran menjadi 1 (dengan aliran audio stereo 32-bit yang tidak terkompresi pada 64kbs, ternyata menjadi 80M file .wav murni, dan hanya 10): https://instaud.io/3Dcy

Seluruh kode (WAV.py) (Kode memiliki banyak nilai variabel duplikat, ini hanya sketsa):

from struct import pack  # ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ py-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² Π±Π°Π·ΠΎΠ²Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ ΠΈΠ· C
from os import urandom  # функция для чтСния /dev/urandom, для windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)])  # лямбда ΠΏΠΎΠ΄ windows, Ρ‚.ΠΊ. urandom'Π° Π² Π²ΠΈΠ½Π΄Π΅ Π½Π΅Ρ‚
from sys import argv, exit  # Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊ ΠΏΡ€ΠΎΠ³Π΅ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄

if len(argv) != 3:  # +1 имя скрипта (-1, Ссли Π±ΡƒΠ΄Π΅Ρ‚Π΅ Π·Π°ΠΌΠΎΡ€Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒ)
    print('Usage: python3 WAV.py [num of samples] [output]')
    exit(1)

numSamples = int(argv[1])
output_path = argv[2]

chunkId = b'RIFF'
Format = b'WAVE'
subchunk1ID = b'fmt '
subchunk1Size = b'x10x00x00x00'  # 0d16
audioFormat = b'x01x00'
numChannels = b'x02x00'  # 2-Ρ… ΠΊΠ°Π½Π°Π»ΠΎΠ² Π±ΡƒΠ΄Π΅Ρ‚ достаточно (стСрСо) 
sampleRate = pack('<L', 1000)  # 1000 Ρ…Π²Π°Ρ‚ΠΈΡ‚, Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈ большС.
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (32 bit sound)
blockAlign = b'x08x00'  # numChannels * BPS / 8
subchunk2ID = b'data'
subchunk2Size = pack('<L', numSamples * 2 * 4)  # * numChannels * BPS / 8
chunkSize = pack('<L', 36 + numSamples * 2 * 4)  # 36 + subchunk2Size

data = urandom(1000 * 2 * 4 * numSamples)  # сам ΡˆΡƒΠΌ

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # записываСм Π² Ρ„Π°ΠΉΠ» Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚

Total

Jadi, Anda telah belajar lebih banyak tentang suara digital dan cara penyimpanannya. Pada postingan kali ini kami tidak menggunakan kompresi (audioFormat), namun untuk mempertimbangkan masing-masing yang populer, diperlukan 10 artikel. Saya harap Anda mempelajari sesuatu yang baru untuk diri Anda sendiri dan ini akan membantu Anda dalam pengembangan di masa mendatang.
Terima kasih!

sumber

Struktur file WAV
WAV - Wikipedia

Sumber: www.habr.com

Tambah komentar