Bahkan, artikel ini dikhususkan untuk pengembangan program untuk mengemas ulang video DVR dari satu wadah ke wadah lain, jika bisa disebut konversi. Meskipun, sepanjang hidup saya, saya berpikir bahwa konverter terlibat dalam mengkonversi (transcoding) format video. Artikel ini adalah bagian kedua dari publikasi terakhir saya, di mana saya berbicara secara rinci tentang mengakses semua rekaman video DVR. Tetapi pada awal publikasi, saya menetapkan tugas lain: mempelajari algoritma dimana program repacker standar 264-avi bekerja dan membuat program yang sama yang akan melakukan operasi yang sama, tetapi tidak pada satu, tetapi pada seluruh kelompok file, apalagi "Satu klik".
Saya akan menjelaskan sekali lagi esensi semua hal dalam bahasa yang sederhana.
Pengguna memiliki perekam video, misalnya, model QCM-08DL yang populer. Dia membutuhkan video untuk tanggal dan waktu tertentu. Ia dapat menghapusnya baik pada USB flash drive atau melalui antarmuka berbasis web dari DVR ke komputer. File video yang diekstraksi (ekstensi .264) hanya akan terbuka di program pemutar yang disertakan dengan DVR. Pemain itu sangat tidak nyaman. Anda masih dapat membukanya di pemutar VLC dengan mengatur mode RAW H264 di pengaturan demultiplexing (pengaturan untuk pengguna tingkat lanjut). Tetapi pada saat yang sama, ternyata, blok aliran audio, yang ditafsirkan sebagai video, dan tidak ada suara, mengganggu pemutaran normal. Dan untuk membuka video di pemutar mana pun, file .264 pertama-tama harus dikonversi ke beberapa format populer, misalnya avi. Program konversi juga disertakan dengan DVR. Tapi dia juga sangat tidak nyaman. Ketika datang ke satu file atau lebih, tidak ada masalah. Namun, ketika tugasnya adalah untuk mendapatkan akses ke semua video di hard drive, dan terlebih lagi untuk mengonversinya semua ke dalam format populer, alat standar praktis tidak cocok.

Masalah akses ke semua file telah dipecahkan. Ini adalah subjek publikasi terakhir. Kami melanjutkan untuk menyelesaikan masalah kedua. Saya sudah diberi "saran praktis": cukup untuk mengubah nama ekstensi dari "264" menjadi "avi" dalam nama file, dan semuanya akan salah, kata mereka, tidak ada yang mengganggu. Tapi ini adalah kesalahan paling umum dari pengguna biasa, yang, sebagai aturan, tidak memahami masalah yang relevan.
Dalam publikasi sebelumnya, saya sudah menulis secara singkat tentang struktur file sumber .264. Biarkan saya mengingatkan Anda.
Informasi utama dengan stream audio dan video berasal dari offset 65.536 byte. Blok aliran video dimulai dengan header 8 byte "01dcH264" (juga ditemukan "00dcH264"). 4 byte berikut ini menjelaskan ukuran blok saat ini dari aliran video dalam byte. Setelah 4 byte nol (00 00 00 00), blok aliran video itu sendiri dimulai. Blok stream audio memiliki judul "03wb" (meskipun, menurut pengamatan saya, karakter pertama dari header dalam beberapa kasus belum tentu "0"). Setelah - 12 byte informasi yang saya belum tahu. Dan dimulai dengan byte ke-17 - aliran audio dengan panjang tetap 160 byte. Tidak ada tag di akhir file.Saya akan mengomentari hal di atas. Segala sesuatu yang mencapai offset 65.536 byte ternyata tidak terpecahkan dan tidak perlu. Dari offset 65.536 byte ke header pertama dari aliran, ada celah kecil, yang isinya juga tidak terselesaikan, dan, apalagi, ketika saya memeriksa, itu tidak muncul dalam file output avi setelah konversi oleh program reguler.
Setiap blok aliran video mewakili satu bingkai. Karakter pertama di header blok aliran video secara opsional adalah "0". Saya tidak mengetahui tujuannya, karena, seperti yang saya ketahui, itu bukan kunci untuk menyelesaikan tugas. Karakter kedua dari tajuk aliran video dapat berupa "1" atau "0". Dalam kasus kedua, konten blok aliran video adalah bingkai referensi yang disebut. Dan dalam kasus pertama, konten blok aliran video adalah bingkai terkompresi yang dikodekan, yang tergantung pada bingkai referensi. Ukuran isi dari kerangka acuan secara signifikan lebih besar dari ukuran isi dari sub-bingkai yang dikompresi. Periode pengulangan bingkai referensi kemungkinan besar tergantung pada pengaturan rasio kompresi dalam DVR. Tetapi dalam kasus saya, periode pengulangan adalah 1 frame / detik.

Program reguler untuk mengemas ulang video dari wadah "264" ke wadah "avi" memberikan hasil yang berbeda terkait kecepatan bingkai. Dalam hal video yang direkam dalam mode resolusi tinggi (704 * 576), kecepatan bingkai adalah 20 bingkai / detik. Dan dalam kasus resolusi rendah (352 * 288) - 25 frame / detik. Informasi ini disediakan oleh utilitas MediaInfo. Ini juga memberi tahu bahwa ukuran video sama dalam hal apa pun: 720 * 576, dan ukuran aliran video (laporan utilitas ini) adalah 704 * 576 atau 352 * 288. Sebagian besar pemain dikerahkan khusus untuk ukuran aliran video. Namun, saya bertemu dengan pemain yang salah menampilkan mode setengah layar ketika memainkan file 352 * 288. Saya ingin memperbaiki kekurangan kecil dari pengemas ulang penuh-waktu ini dengan melihat byte dari konten aliran video dan mengeluarkan informasi tentang ukuran bingkai dari sana. Tetapi terburu-buru, saya tidak bisa melakukan ini. Di atas ditunjukkan pada gambar di bawah ini.

Sekarang tentang frame rate. Seperti yang saya ketahui, pembungkus ulang reguler tidak mengakses bidang header apa pun dari wadah “264”. Ini menilai frame rate dengan menghitung rasio jumlah blok video dan stream audio. Dan nilai ini dalam perhitungan bahkan tidak dibulatkan ke nilai keseluruhan terdekat, seperti yang dapat dilihat dari gambar di atas (dilingkari hijau). Seperti yang saya ketahui, jumlah blok stream audio per unit waktu selalu dan di mana saja (dalam file apa pun) tetap, yaitu 25 blok per detik. Jika Anda memeriksa file video dengan frekuensi 20 frame / detik, maka bingkai referensi (blok) terjadi setiap 19 frame terkompresi, dan dalam kasus 25 frame / detik. - setiap 24 frame terkompresi.
Kami terus mempelajari struktur tajuk aliran video. Kami menemukan delapan byte pertama: ini adalah label referensi atau bingkai terkompresi ditambah kata kunci "H264". Empat byte berikut menjelaskan, seperti yang saya temukan, bukan tepat, tetapi perkiraan ukuran isi aliran video. Repacker reguler membuang semua byte konten ini sepenuhnya, dan kemudian menulis ukuran yang dihasilkan ke bidang yang sesuai dari wadah avi. Dan nilai ini berbeda dari nilai yang ditentukan dalam bidang yang sesuai dari file .264 sumber.
Sebagian, saya menebak informasi dua belas byte setelah header blok aliran audio. Bagaimanapun, elemen kunci adalah 4 byte terakhir, setelah itu aliran audio dimulai. Ini adalah dua angka 16-bit yang menggambarkan parameter awal skema decoding berulang dari ADPCM ke PCM. Decoding meningkatkan ukuran aliran audio sebanyak 4 kali. Ketika meneliti file-file di muka, saya menemukan bahwa repacker full-time menerjemahkan audio, tetapi membiarkan konten video tidak berubah.
Tanpa pengetahuan mendalam, saya mencoba untuk waktu yang lama untuk mencari tahu algoritma decoding mana yang digunakan dalam kasus saya. Secara intuitif sudah menduga bahwa metode kompresi ADPCM diterapkan. Lebih tepatnya, tidak secara intuitif, tetapi dengan pendekatan yang kompeten, berdasarkan fakta bahwa aliran audio dikompresi tepat 4 kali. Dan ketika saya membuka sebuah fragmen di Adobe Audition sebagai RAW dalam berbagai format (dan membandingkan fragmen yang sama setelah dikemas ulang dengan program reguler), hasil suara yang sangat mirip (tetapi tidak akurat) diberikan kepada saya oleh ADPCM. Untuk menganalisis algoritma kompresi, informasi di situs
wiki.multimedia.cx/index.php/IMA_ADPCM membantu saya. Di sini saya belajar tentang dua parameter decoding awal, dan kemudian, menggunakan "metode poke", saya menyadari bahwa parameter awal ini direkam dalam 4 byte sebelum dimulainya aliran audio. Saya akan menjelaskan operasi algoritma dan memberikan interpretasi matematika yang kasar (di bawah spoiler).
Rincian Algoritma Dekode ADPCMAda urutan sampel
Selain itu, seperti yang telah disebutkan, ada dua parameter awal
dan
. Perlu untuk mendapatkan urutan sampel baru
. Seperti yang sudah bisa Anda tebak, sampel keluaran pertama sudah diketahui: itu bertepatan dengan salah satu parameter awal
. Ini adalah sesuatu selain "perpindahan awal". Perlu dicatat bahwa input (sumber) sampel dikodekan dalam empat bit. Untuk tipe yang ditandatangani, bilangan bulat dari -8 hingga 7, inklusif, termasuk dalam pengkodean. Bit yang paling signifikan, pada kenyataannya, bertanggung jawab atas tanda nomor tersebut. Sampel PCM keluaran, yang diperoleh setelah decoding, memiliki format standar 16-bit yang ditandatangani.
Menganalisis kode algoritma dalam C, Anda dapat melihat dua tabel. Mereka tercantum di bawah ini.
int ima_index_table[] = { -1, -1, -1, -1, 2, 4, 6, 8 };
int ima_step_table[] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
Dua array "ajaib" ini dapat dikatakan fungsi tabular, dalam argumen yang dua parameter awal yang sama diganti. Selama iterasi, dengan setiap langkah, parameter dihitung ulang dan diganti ke dalam tabel ini lagi. Pertama, mari kita lihat bagaimana ini diterapkan dalam kode.
Kami menyatakan yang diperlukan, termasuk variabel bantu.
int current1; int step; int stepindex1; int diff; int current; int stepindex; int value;
Sebelum memulai iterasi, Anda perlu menetapkan parameter awal ke variabel saat ini
, dan stepindex variabel adalah
. Ini dilakukan di luar algoritma yang dimaksud, jadi saya tidak mencerminkan ini dengan kode. Berikut ini adalah transformasi yang dilakukan dalam lingkaran (dalam satu lingkaran).
value = read(input_sample);
Pada langkah variabel bantu dari array ima_step_table, nilai pada indeks stepindex1 ditulis. Untuk iterasi pertama, ini adalah parameter awal
, untuk iterasi lebih lanjut ini adalah parameter yang dihitung ulang
. Kemudian nilai dari array ini dibagi dengan 8 (tampaknya, sepenuhnya) dengan operasi bit shift ke kanan, dan variabel diff diinisialisasi sebagai hasil dari divisi ini. Kemudian, tiga bit paling tidak signifikan dari nilai sampel input dianalisis dan, tergantung pada keadaan mereka, variabel diff dapat disesuaikan oleh tiga istilah. Istilahnya adalah pembagian bilangan bulat yang serupa dengan nilai diff sebesar 4 (>> 2), 2 (>> 1) atau diff tanpa perubahan (biarkan menjadi divisi dengan 1 untuk generalisasi). Kemudian, bit paling signifikan (ditandatangani) dari nilai sampel input dianalisis. Bergantung pada kondisinya, variabel diff yang dihasilkan sebelum ini ditambahkan atau dikurangi ke variabel current1. Ini akan menjadi nilai sampel keluaran. Untuk kebenarannya, nilainya terbatas pada bagian atas dan bawah. Kemudian stepindex1 disesuaikan dengan menambahkan nilai dari array ima_index_table dengan indeks nilai sampel input dengan tanda bit reset ke nol. Nilai stepindex1 juga tunduk pada batas. Di bagian paling akhir, sebelum mengulang algoritma ini, nilai saat ini dan stepindex ditetapkan dengan nilai yang baru diceritakan dari current1 dan stepindex1, dan algoritma tersebut diulangi lagi.
Anda dapat mencoba mencari tahu untuk memahami kira-kira bagaimana variabel diff terbentuk. Biarkan
. Ini adalah nilai-nilai dari variabel langkah pada setiap langkah ke-i dari iterasi, sebagai nilai-nilai fungsi (array) dari argumen
dimana
. Untuk kenyamanan, kami menyatakan variabel diff sebagai
. Mengikuti logika penalaran yang dijelaskan di atas, kami memiliki:
dimana
- rendah 3 bit angka
. Menuju ke penyebut yang sama, kami mengubah ungkapan ini ke bentuk yang lebih nyaman:
Konversi terakhir didasarkan pada fakta bahwa, dalam arti, paling sedikit tiga bit (0 atau 1) dari suatu angka
dengan koefisien yang disajikan ada sesuatu selain menulis nilai absolut dari angka ini, dan bit yang paling signifikan dari angka tersebut
akan cocok dengan tanda seluruh ekspresi. Selanjutnya sesuai dengan rumus
nilai sampel baru dihitung berdasarkan yang lama. Selain itu, nilai variabel baru dihitung.
:
Modul dalam rumus menunjukkan bahwa variabel
mulai berfungsi
mengecualikan bit tanda paling signifikan, yang tercermin dalam kode. Suatu fungsi
Apakah nilai array ima_index_table dengan indeks yang sesuai dengan argumen.
Dalam deskripsi rumus, saya mengabaikan operasi pembatasan di atas dan di bawah. Skema total iteratif terlihat seperti ini:
Sangat dalam dalam teori encoding / decoding ADPCM saya tidak menyelidiki. Namun, nilai-nilai tabel dari array ima_step_table (dari 89 buah), dilihat dari refleksi mereka pada grafik (lihat gambar di bawah), menggambarkan distribusi probabilistik sampel relatif terhadap garis nol. Dalam praktiknya, ini biasanya terjadi: semakin dekat sampel ke garis nol, semakin banyak terjadi. Oleh karena itu, ADPCM didasarkan pada model probabilistik, dan tidak berarti sumber apa pun dari sampel PCM 16-bit dapat dikonversi dengan benar menjadi sampel ADPCM 4-bit. Secara umum, ADPCM adalah PCM dengan langkah kuantisasi variabel. Rupanya, bagan ini mencerminkan langkah yang sangat bervariasi ini. Ia dipilih dengan benar, berdasarkan hukum distribusi data audio dalam praktiknya.

Sekarang mari kita beralih ke menggambarkan struktur wadah avi. Bahkan, itu adalah struktur hierarkis yang kompleks.
Tetapi, setelah menyederhanakan tugas untuk kasus khusus, saya mempresentasikan struktur avi dalam bentuk linier. Hasilnya adalah ini: file avi terdiri dari header besar, zero skip bytes (JUNK), area stream audio dan video (dengan header dan ukuran konten), dan daftar indeks. Yang terakhir berfungsi, khususnya, untuk menggulir video di pemutar. Tanpa daftar ini, bergulir tidak akan berfungsi (dicentang). Ini hanya daftar isi, yang mencantumkan nama-nama kunci dari blok aliran (cocok dengan nama dalam header blok), ukuran yang sesuai dari konten, dan nilai-nilai dari offset (alamat) relatif terhadap awal area aliran.
Sekarang Anda dapat melanjutkan ke pengembangan program. Deskripsi spesifik masalah adalah sebagai berikut.
Pada akar bagian X: ada direktori "DVR". Direktori ini berisi banyak subdirektori tidak kosong (dan hanya subdirektori) dengan nama yang sesuai dengan tanggal tertentu. Di setiap subdirektori ini ada banyak file dengan nama berbeda dan ekstensi "264". Diperlukan di bagian Y: buat direktori "DVR", dan di dalamnya subdirektori yang sama seperti di bagian X:. Isi setiap subdirektori ini dengan file dengan nama yang sesuai yang sama, tetapi dengan ekstensi bukan "264", tetapi "avi". File avi ini harus diperoleh dari 264 file asli dengan memprosesnya, yang, dengan satu atau lain cara, mengulangi algoritma program yang ada. Pemrosesan terdiri dari pengemasan ulang stream video secara langsung, pengemasan ulang dengan decoding stream audio, memformat file avi. Program harus diluncurkan dari baris perintah sebagai berikut: "264toavi.exe X: Y:", di mana "264toavi.exe" adalah nama program, "X:" adalah bagian sumber, "Y:" adalah bagian tujuan.Bahkan, untuk menyederhanakan tugas, dimungkinkan untuk menulis sebuah program yang hanya akan menangani konversi (pengemasan ulang) dari satu file, menjadikannya dua hari: nama file input dan nama file output. Dan kemudian, untuk menerapkan hanya pengemasan ulang grup, Anda dapat menulis file kumpulan perintah (bat) menggunakan alat lain, misalnya, Excel. Tapi saya menerapkan program yang lengkap, sangat rumit. Kode sumber tidak mungkin layak mendapat perhatian pembaca. Saya akan menjelaskan struktur kode program.
Program ini ditulis dalam C di lingkungan pengembangan Dev-C ++ dengan elemen WinAPI. Program ini mengimplementasikan tiga fungsi bantu besar: fungsi menghasilkan header avi awal, fungsi decoding sampel audio, dan fungsi pemindaian file sumber "264" dengan kata-kata. Dengan kata lain, saya memanggil bagian dari 4 byte. Telah diamati bahwa ukuran tajuk dan isi semua aliran adalah kelipatan empat byte. Fungsi pemindaian dapat mengembalikan lima nilai: 0 - jika itu biasa 4 byte dari aliran video untuk pengemasan ulang, 1 - jika itu adalah header dari blok aliran video dari bingkai referensi, 2 - jika itu adalah judul dari blok aliran video dari frame yang dikompresi, 3 - jika itu adalah header dari blok aliran audio, 4 - jika Blok "Corrupt" harus diabaikan selama pengemasan ulang. Sangat, sangat jarang, tetapi itu terjadi. Blok yang rusak (seperti yang saya sebutkan) adalah header seperti "\ 0 \ 0 \ 0 \ 0H264", di mana "\ 0" adalah byte nol. Pembungkus ulang reguler mengabaikan blok semacam ini. Tentu saja, isi dari blok semacam itu mungkin ternyata cukup berfungsi, tetapi saya mengabaikan blok tersebut untuk membawa program saya lebih dekat ke standar.
Dalam fungsi utama, selain mengatur direktori, file input dibaca oleh fungsi pemindaian. Bergantung pada apa fungsi ini dikembalikan, tindakan selanjutnya terjadi. Jika ini adalah header dari stream video, maka header yang sesuai akan dibentuk dalam file output avi. Di sana mereka dipanggil secara berbeda: "00db" adalah judul blok aliran video dari frame referensi, dan "00dc" adalah untuk frame terkompresi. Setelah operasi pengemasan ulang (penulisan ulang kata-kata) sebelum tajuk baru yang baru ditemui, ukuran konten yang dikemas kembali dihitung dan nilai ini ditulis ke bidang yang segera mengikuti tajuk aliran yang baru saja diproses. Jika tajuk aliran audio ditemukan selama pemindaian, nama tajuk “03wb” dihasilkan dalam file output avi dan aliran audio diterjemahkan dari ADPCM ke PCM dalam loop pada saat yang sama dengan konten yang didekodekan dituliskan ke file avi. Bersamaan dengan semua hal di atas, informasi singkat (daftar isi) dicatat dalam file indeks sementara "indeks". Anda tidak dapat melakukan fungsi pemindaian, tetapi menulis semuanya di fungsi utama. Tetapi kemudian programnya akan sangat rumit dan hampir sulit dibaca.
Pada akhir seluruh operasi, ketika file input "264" telah berakhir, sebelum pindah ke file baru, program ini secara kompeten menyelesaikan semua operasi. Pertama, bidang-bidang tertentu dalam header file avi disesuaikan, nilainya tergantung pada ukuran dan jumlah stream yang dibaca, dan kemudian isi dari file "index" sementara dilampirkan ke file avi yang hampir selesai, yang kemudian dihapus. Setelah operasi ini, file output avi siap diputar.
Saat program sedang berjalan, visualisasi teks terjadi pada baris perintah, yang menampilkan direktori saat ini, file, serta nomor blok aliran video per kerangka referensi dan titik waktu video yang terkait dalam menit dan detik. Dan jika file input tidak memiliki nama arbitrer, tetapi yang asli (berisi nomor saluran, tanggal dan waktu perekaman dimulai), maka visualisasi yang lebih interaktif berdasarkan aritmatika tanggal-waktu terjadi.
Saat menguji dan men-debug program, masalah utama yang saya alami saat bekerja dengan decoding suara. Aritmatika sederhana tidak berfungsi dengan benar jika, ketika mendeklarasikan variabel dalam fungsi decoding, saya tidak akan mengetikkan jenisnya dengan benar. Karena itu, beberapa blok aliran audio rusak, dan ada klik oleh telinga. Beberapa bidang header yang tidak dapat dipahami dari file 264 asli yang saya tidak tahu ternyata tidak peka terhadap hasilnya. Tidak seperti program reguler, program saya tidak membuang blok aliran terakhir yang tidak lengkap dari operasi pengemasan ulang. Meskipun, ketidakhadirannya tidak akan memainkan peran praktis apa pun. Program reguler lainnya, tidak seperti program saya, menyisakan sejumlah kecil "sampah" (ini adalah isi dari aliran terakhir) di bagian paling akhir dari file avi setelah indeks. Untuk semua ini, video diputar hampir sama. Dan program melakukan pengemasan ulang untuk periode waktu yang sama dengan program reguler.
Sebagai kesimpulan, saya akan memberikan ilustrasi yang menunjukkan struktur organisasi aliran dalam file .264 (dalam editor hex WinHex) menggunakan salah satu file sebagai contoh dan tampilan program RiffPad dengan file avi yang dikemas ulang dibuka di dalamnya. Program ini sangat menyederhanakan proses mempelajari struktur file avi. Ini dengan jelas menunjukkan struktur hierarkis, menunjukkan konten byte dari masing-masing anggota struktur, dan bahkan secara cerdik menginterpretasikan isi header dalam bentuk daftar parameter. Gambar, khususnya, menunjukkan fakta bahwa konten aliran video ditimpa tanpa perubahan.

