Bagaimana cara membungkus H264 dengan benar ke dalam FLV dengan FFMPEG?

Pertama-tama, "benar" dalam judul mengacu pada ini pertanyaan terkait, yang jawabannya tidak menyelesaikan masalah saya.

tl;dr: Ada perbedaan antara menyandikan video dan menyimpannya langsung ke dalam FLV dan melakukan ini dalam dua langkah terpisah. Saya perlu melakukannya secara terpisah, bagaimana cara mendapatkan hasil yang sama dengan melakukannya secara langsung?

Encoder perangkat keras Nvidia, NVENC, menghasilkan data mentah H.264 tanpa wadah, yang sulit diputar di sebagian besar pemutar video. Untuk aplikasi Adobe AIR, saya perlu membungkus video ke dalam format FLV, yang ingin saya gunakan FFMPEG:

ffmpeg -f h264 -i "input.h264" -c copy -f flv "output.flv"

Hal ini tidak berjalan sesuai harapan, karena frame pertama dari setiap video yang diperlakukan dengan cara ini tidak ditampilkan. Setiap video hanya ditampilkan dari frame kedua, yang sangat disayangkan untuk video frame tunggal (menggunakan encoder perangkat keras GPU untuk kompresi gambar secepat kilat saja).

Untuk pemeriksaan, saya sekarang mengkodekan ulang video input dua kali: sekali langsung ke output FLV

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

dan sekali ke H.264, lalu memasukkannya ke FLV sesudahnya.

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"
ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

Video pertama diputar dengan baik, video kedua tidak. FLV yang dihasilkan dari pendekatan langsung (A.flv, lihat di bawah) memiliki struktur file yang sedikit berbeda, terutama unit NAL yang berbeda, yang saya duga merupakan alasan untuk perilaku yang berbeda.

Jadi pertanyaan saya adalah: Jika saya sudah memiliki video H.264 dan hanya ingin disalin ke wadah FLV tanpa ditranskode, tetapi header file dan frame harus diisi dengan benar seperti yang dilakukan ketika sebenarnya melakukan transcoding, bagaimana caranya Saya mengatakan ini kepada FFMPEG? Apakah ada perintah untuk ini, seperti "-c copy butGenerateValidHeader"?

Berikut bagian file yang relevan:

Pendekatan langsung

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

A.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
B8 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 08 00 08 64 75 72 61
74 69 6F 6E 00 3F A0 E5 60 41 89 37 4C 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 40 9E
84 80 00 00 00 00 00 09 66 72 61 6D 65 72 61 74
65 00 40 3E 00 00 00 00 00 00 00 0C 76 69 64 65
6F 63 6F 64 65 63 69 64 00 40 1C 00 00 00 00 00
00 00 07 65 6E 63 6F 64 65 72 02 00 0D 4C 61 76
66 35 37 2E 37 31 2E 31 30 30 00 08 66 69 6C 65
73 69 7A 65 00 40 F9 5C B0 00 00 00 00 00 00 09

00 00 00 C3 09 00 00 2B 00 00 00 00 00 00 00 17 // AVC sequence start
00 00 00 00
            01 4D 40 20 FF E1 00 17             // ?
                                    67 4D 40 20 // Sequence parameter set
95 A0 13 81 F7 EB 01 10 00 00 3E 80 00 0E A6 08
F1 C3 2A
         01 00 04                               // ?
                  68 EE 3C 80                   // Picture parameter set
                              00 00 00 36 09 01 // AVC NALU
94 9A 00 00 00 00 00 00 00 17 01 00 00 00
                                          00 01 // ?
94 91
      65                                        // IDR frame
        [B8 04 1D FF ...]
00 01 94 A5 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

Pengkodean terlebih dahulu

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"

kode ulang.h264

00 00 00 01 67 4D 40 20 95 A0 13 81 F7 EB 01 10 // Sequence parameter set
00 00 3E 80 00 0E A6 08 F1 C3 2A
                                 00 00 00 01 68 // Picture parameter set
EE 3C 80
         00 00 00 01 65                         // IDR frame
                       [B8 04 1D FF ...]        // Frame data

Peras ke dalam wadah

ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

B.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
A4 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 07 00 08 64 75 72 61
74 69 6F 6E 00 3F A4 7A E1 47 AE 14 7B 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 00 00
00 00 00 00 00 00 00 0C 76 69 64 65 6F 63 6F 64
65 63 69 64 00 40 1C 00 00 00 00 00 00 00 07 65
6E 63 6F 64 65 72 02 00 0D 4C 61 76 66 35 37 2E
37 31 2E 31 30 30 00 08 66 69 6C 65 73 69 7A 65
00 40 F9 5B 40 00 00 00 00 00 00 09
                                    00 00 00 AF // AVC sequence start
09 00 00 05 00 00 00 00 00 00 00 17 00 00 00 00

00 00 00 10 09 01 94 BD 00 00 00 00 00 00 00 17 // AVC NALU
01 00 00
         00 00 00 00 01 67 4D 40 20 95 A0 13 81 // Sequence parameter set
F7 EB 01 10 00 00 3E 80 00 0E A6 08 F1 C3 2A
                                             00 // Picture parameter set
00 00 01 68 EE 3C 80
                     00 00 00 01 65             // IDR frame
                                   [B8 04 1D FF // Frame data
...]
00 01 94 C8 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

Pembaruan 08.08.2017: Menambahkan file input dan output untuk pemeriksaan


person mOfl    schedule 03.08.2017    source sumber
comment
Apakah Anda keberatan berbagi berbagai file video Anda?   -  person Markus Schumann    schedule 03.08.2017
comment
Coba ffmpeg -f h264 -i "reencode.h264" -c copy -bsf:v extract_extradata -f flv "B.flv" baris perintah yaitu dengan filter bitstream ekstrak_extradata.   -  person nobody555    schedule 03.08.2017
comment
@Markus Schumann: Saya menambahkan file di akhir pertanyaan.   -  person mOfl    schedule 08.08.2017
comment
@nobody555: Terima kasih atas tip Anda, tetapi tidak berhasil. Videonya tidak hanya tidak muncul di Adobe AIR, tetapi juga tidak muncul lagi di MPC-HC.   -  person mOfl    schedule 08.08.2017
comment
Pertama-tama, deskripsi Anda tentang struktur file bertentangan dengan struktur sebenarnya dalam biner A.flv dan B.flv Anda (keduanya terbelakang). Jadi hasil mana yang benar-benar Anda inginkan A.flv (dengan kode awal: 00 00 00 01 67 .. 00 00 00 01 68 .. 00 00 00 01 65) atau B.flv (avcC: 00 17 67 .. 00 04 68 . .00 01 94 91 65)? Format standar untuk FLV seperti B.flv dengan avcC (tanpa kode awal) dan diproduksi secara default dengan: ffmpeg -i "reencode.h264" -c copy "C.flv": C. flv. Jika ini berhasil, coba perbarui ffmpeg Anda. Adapun format dengan kode awal, saya tidak tahu bagaimana cara memproduksinya.   -  person nobody555    schedule 08.08.2017
comment
@ nobody555 Tolong, Pak, jadikan ini jawaban dan terima kasih telah menyediakan file itu. Saya menyadari bahwa file Anda memiliki Lavf57.76.100 sebagai encoder sedangkan file saya memiliki Lavf57.71.100. Jadi saya memperbarui FFMPEG dari 3.3.2 ke 3.3.3 (nightly build 20170807-1bef008) dan sekarang FLV yang dimuxed diputar di AIR sesuai keinginan.   -  person mOfl    schedule 09.08.2017
comment
@mOfl apakah solusi ini masih memerlukan input h.264 untuk dikodekan ulang terlebih dahulu ke h.264 kedua yang baru? Lalu h.264 baru (reencoded.h264) dikemas sebagai FLV? Jika Anda tidak keberatan melewatkan FFmpeg sama sekali, saya akan menunjukkan kode AS3 yang menampilkan input.h264 langsung di dalam aplikasi AIR. Apakah hanya untuk gambar diam h264?   -  person VC.One    schedule 09.08.2017
comment
@VC.One Tidak, input.h264 tidak harus dikodekan ulang. Saya melakukan ini hanya untuk melihat perbedaan file yang dihasilkan FFMPEG. Saya ingin melewatkan FFMPEG dan FLV jika ada cara untuk langsung memutar gambar diam h264 (dalam format Lampiran B) di AIR!   -  person mOfl    schedule 10.08.2017


Jawaban (2)


Pertama-tama, deskripsi Anda tentang struktur file bertentangan dengan struktur sebenarnya dalam biner A.flv dan B.flv Anda (keduanya terbelakang). Jadi, hasil manakah yang sebenarnya Anda inginkan? Suka A.flv dengan kode awal: 00 00 00 01 67 .. 00 00 00 01 68 .. 00 00 00 01 65 atau suka B.flv dengan avcC + 00 17 67 .. 00 04 68 .. 00 01 94 91 65?

Format standar untuk FLV seperti B.flv dengan avcC (tanpa kode awal) dan diproduksi secara default dengan: ffmpeg -i "reencode.h264" -c copy "C.flv": inilah hasil C.flv.

Jika file ini berfungsi untuk Anda, cobalah perbarui ffmpeg Anda (saya menggunakan versi kompilasi sendiri dari cabang master). Adapun format dengan kode awal, saya tidak tahu bagaimana cara memproduksinya.

person nobody555    schedule 09.08.2017

(1)

"Jika saya sudah memiliki video H.264 dan hanya ingin disalin ke wadah FLV tanpa ditranskode, tetapi header file dan frame harus diisi dengan benar seperti yang dilakukan saat sebenarnya transcoding, bagaimana cara memberitahukan ini ke FFMPEG?"

Anda ingin muxing : Coba perintah di bawah ini (langsung salin data H.264 ke dalam wadah FLV).

ffmpeg -i input.h264 -c:v copy output.flv

(2)

Bingkai pertama setiap video yang diperlakukan dengan cara ini tidak ditampilkan. Setiap video hanya ditampilkan dari frame kedua, yang disayangkan untuk video frame tunggal...

Bagaimana Anda memeriksa bingkai untuk mengetahui bahwa itu hanya menampilkan bingkai 2 dan seterusnya? Apakah dengan kode AS3 netStream.pause() atau dengan pemutar media seperti VLC?

Dalam FLV setiap frame video masuk ke Video Tag. Dengan codec lain kita dapat mengatakan meletakkan bingkai #1 ke dalam videoTag #1 dll.. tetapi dengan H.264 tag pertama selalu menyimpan data "Konfigurasi Dekoder AVC" sehingga pikselnya bingkai video input #1 akan ada di videoTag #2 FLV.
Juga dengan byte pertama yang ditampilkan... di bagian "AVC NALU" yang 17 01 memberi tahu Anda bahwa ini adalah keyframe (frame pertama selalu berupa keyframe), decoder MPEG tidak akan pernah menampilkan frame kedua (biasanya P-frame) jika tidak pada decode keyframe pertama (I-frame). Gambar bingkai #1 Anda ada di suatu tempat...

Saya tidak dapat membuat ulang masalah ini dengan video H.264 dengan hitungan mundur beberapa kode waktu. Frame pertama dimulai pada 00hh:00mm:00ss:00msec dan mdetik naik frame demi frame. Setelah menggunakan perintah yang ditunjukkan pada poin (1), saya melihat frame pertama di VLC & MPC-HC dan juga di AS3 jika saya menggunakan appendBytes untuk memberi makan decoder hanya dengan data satu frame (byteArray dikemas sebagai FLV 1-frame).

person VC.One    schedule 06.08.2017
comment
Sayangnya, remuxing seperti yang disarankan tidak berhasil. Periksa pertanyaan saya yang diperbarui untuk video hasil (copy.flv). Meskipun diputar di MPC-HC, ia tidak muncul di AIR (AS3, menggunakan netStream.appendBytes). - person mOfl; 08.08.2017