Saat mengkondisikan streaming untuk pemutaran DASH, titik akses acak harus berada pada waktu aliran sumber yang sama persis di semua aliran. Cara biasa untuk melakukan ini adalah dengan memaksa frame rate tetap dan panjang GOP tetap (yaitu keyframe setiap N frame).
Dalam FFmpeg, frame rate tetap mudah (-r NUMBER).
Tetapi untuk lokasi keyframe tetap (panjang GOP), ada tiga metode ... mana yang "benar"? Dokumentasi FFmpeg sangat tidak jelas dalam hal ini.
Metode 1: mengacaukan argumen libx264
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Tampaknya ada beberapa perdebatan apakah scenecut harus dimatikan atau tidak, karena tidak jelas apakah "counter" keyframe dimulai kembali ketika adegan terputus terjadi.
Metode 2: mengatur ukuran GOP tetap:
-g GOP_LEN_IN_FRAMES
Sayangnya ini hanya didokumentasikan secara sepintas dalam dokumentasi FFMPEG, dan dengan demikian efek argumen ini sangat tidak jelas.
Metode 3: masukkan keyframe setiap N detik ( Mungkin? ):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Ini adalah secara eksplisit didokumentasikan. Tetapi masih belum jelas apakah "penghitung waktu" restart setelah setiap bingkai kunci. Misalnya, dalam GOP 5 detik yang diharapkan, jika ada scenecut
keyframe yang disuntikkan 3 detik oleh libx264, akankah keyframe berikutnya menjadi 5 detik kemudian atau 2 detik kemudian?
Bahkan, dokumentasi FFmpeg membedakan antara ini dan -g
opsi, tetapi tidak benar-benar mengatakan bagaimana kedua opsi di atas sedikit berbeda (jelas, -g
akan memerlukan frame rate tetap).
Mana yang benar
Tampaknya -force_key_frames
akan lebih unggul , karena tidak akan memerlukan frame rate yang tetap. Namun, ini mensyaratkan hal itu
- itu sesuai dengan spesifikasi GOP di H.264 ( jika ada )
- dijamin bahwa akan ada keyframe dalam irama tetap, terlepas dari libx264
scenecut
keyframe.
Tampaknya juga -g
tidak bisa bekerja tanpa memaksakan frame rate tetap ( -r
) , karena tidak ada jaminan bahwa beberapa kali berjalan ffmpeg
dengan argumen codec yang berbeda akan memberikan frame rate instan yang sama di setiap resolusi. Frame rate yang diperbaiki dapat mengurangi kinerja kompresi (PENTING dalam skenario DASH!).
Akhirnya, yang keyint
metode hanya tampak seperti hack . Saya berharap dengan harapan bahwa ini bukan jawaban yang benar.
Referensi:
Contoh menggunakan -force_key_frames
metode
sumber
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, lalu mewarnai sel. Saya khawatir tidak ada diskusi publik, tetapi saya akan melihat apakah saya dapat menggali beberapa tautan yang saya temukan saat itu.-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
formulir? Saya baru saja mencobanya dan menemukan bahwa meskipun ada frame I tambahan dalam aliran, itu tampaknya mematuhi aturan saya. Program PERL akan mengikuti sebagai "jawaban", karena Anda tampaknya tidak dapat menggunakan markup dalam komentar.-force_key_frames
tidak berfungsi untuk saya, jadi saya tidak pernah mencobanya lagi. Itu lebih dari setahun yang lalu. Mungkin itu bug. Saya akan coba lagi nanti.Ini uang saya lima puluh sen untuk kasingnya.
Hasilkan iframe hanya pada interval yang diinginkan.
Contoh 1:
Hasilkan iframe seperti yang diharapkan seperti ini:
Metode 2 disusutkan. Ommitted.
Contoh 2
Buat iframe dengan cara yang sedikit berbeda:
Seperti yang Anda lihat, tempat iframe setiap 2 detik DAN pada scenecut (detik dengan bagian mengambang) yang penting untuk kompleksitas aliran video menurut saya.
Ukuran file yang dihasilkan cukup sama. Sangat aneh bahwa bahkan dengan lebih banyak keyframes di Metode 3 , kadang-kadang menghasilkan file lebih sedikit daripada algoritma perpustakaan x264 standar.
Untuk menghasilkan beberapa file bitrate untuk aliran HLS kami memilih metode tiga. Ini selaras sempurna dengan 2 detik antara potongan, mereka memiliki iframe di awal setiap potongan dan mereka memiliki iframe tambahan pada adegan kompleks yang memberikan pengalaman yang lebih baik bagi pengguna yang memiliki perangkat usang dan tidak dapat memutar profil tinggi x264.
Semoga ini bisa membantu seseorang.
sumber
Karena itu jawabannya adalah:
libx264
spesifik dan harus dibayar dengan menghilangkan opsi yang sangat bergunascenecut
dilibx264
.-g
tampaknya sudah usang. Tampaknya tidak berfungsi, juga tidak secara eksplisit didefinisikan dalam dokumentasi, juga tidak ditemukan dalam bantuan, juga tidak tampak digunakan dalam kode. Inspeksi kode menunjukkan bahwa-g
opsi tersebut kemungkinan dimaksudkan untuk stream MPEG-2 (bahkan ada bait kode yang mengacu pada PAL dan NTSC!).Juga:
Script untuk
-force_key_frames
opsiBerikut ini adalah program PERL pendek yang saya gunakan untuk memverifikasi irama frame I berdasarkan output dari saran ffprobe slhck. Tampaknya untuk memverifikasi bahwa
-force_key_frames
metode ini juga akan berfungsi, dan memiliki manfaat tambahan untuk memungkinkanscenecut
frame. Saya sama sekali tidak tahu bagaimana FFMPEG membuat ini bekerja, atau jika saya beruntung entah bagaimana karena aliran saya kebetulan dikondisikan dengan baik.Dalam kasus saya, saya dikodekan pada 30fps dengan ukuran GOP yang diharapkan 6 detik, atau 180 frame. Saya menggunakan 180 sebagai argumen gopsi untuk program ini memverifikasi kerangka I di setiap kelipatan 180, tetapi menetapkannya ke 181 (atau nomor lain yang bukan kelipatan 180) membuatnya mengeluh.
sumber
force_key_frames
, itu agak mengacaukan algoritma alokasi bit x264, sehingga dapat memberikan kualitas yang lebih buruk daripada hanya mengatur interval keyframe tetap.-g
, Anda berkata, "Tampaknya tidak berfungsi, ... juga tidak tampaknya digunakan dalam kode.". Aku memeriksa dan masukan darig
disimpan dalamavctx->gop_size
dan bahwa merek libx264 menggunakan itu:x4->params.i_keyint_max = avctx->gop_size;
. Ketika saya menyelidiki file tesis yang dihasilkan ini:,ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
saya mendapatkan keyframe dengan tepat0,37,74,111,148,185,222,259,296,333,370
. GOP dapat dipotong pendek jika perubahan adegan dipicu, dan untuk itu-sc_threshold
dapat diatur, yang juga diambil oleh x264.Saya ingin menambahkan beberapa info di sini karena googling saya menarik diskusi ini sedikit dalam pencarian saya untuk menemukan info tentang mencoba menemukan cara untuk segmentasi DASH saya pengkodean seperti yang saya inginkan, dan tidak ada info yang saya temukan benar-benar benar.
Beberapa kesalahpahaman pertama untuk dihilangkan:
Tidak semua I-frame sama. Ada bingkai "aku" besar dan bingkai "aku" kecil. Atau untuk menggunakan terminologi yang benar, IDR I-Frames dan non-IDR I-Frames. Bingkai-I IDR (kadang-kadang disebut "bingkai kunci") akan membuat GOP baru. Frame non-IDR tidak akan. Mereka berguna untuk memiliki bagian dalam GOP di mana ada perubahan adegan.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← Ini tidak melakukan apa yang Anda pikirkan. Saya butuh waktu beberapa saat untuk mencari tahu. Ternyatamin-keyint
terbatas pada kode. Itu tidak boleh lebih besar dari(keyint / 2) + 1
. Jadi, menetapkan nilai yang sama untuk dua variabel ini menghasilkan nilai untukmin-keyint
dirobohkan setengah saat pengkodean.Begini: adegan-cut sangat bagus, terutama dalam video yang memiliki potongan cepat. Itu membuatnya bagus dan segar, jadi saya tidak ingin menonaktifkannya, tetapi pada saat yang sama saya tidak bisa mendapatkan ukuran GOP yang tetap selama itu diaktifkan. Saya ingin mengaktifkan cut-scene, tetapi hanya menggunakan non-IDR I-frames. Tapi itu tidak berhasil. Sampai saya menemukan (dari banyak membaca) tentang kesalahpahaman # 2.
Ternyata saya perlu mengatur
keyint
untuk menggandakan ukuran GOP yang saya inginkan. Ini berarti bahwamin-keyint
dapat diatur ke ukuran GOP yang saya inginkan (tanpa kode internal memotongnya menjadi dua), yang mencegah deteksi adegan-potong dari menggunakan IDR-frame di dalam ukuran GOP karena jumlah frame sejak IDR-Frame terakhir adalah selalu kurang darimin-keyinit
.Dan akhirnya pengaturan
force_key_frame
opsi menimpa ukuran gandakeyint
. Jadi, inilah yang bekerja:Saya lebih suka segmen dalam potongan 2 detik, jadi GOPSIZE saya = Membingkai * 2
Anda dapat memverifikasi menggunakan ffprobe:
Dalam file CSV yang dihasilkan, setiap baris akan memberi tahu Anda
frame, [is_an_IDR_?], [frame_type], [frame_number]
::Hasilnya adalah Anda hanya akan melihat IDR-Frame pada
GOPSIZE
interval tetap , sedangkan semua frame I lainnya adalah IDR-frame non-dimasukkan sebagaimana diperlukan oleh deteksi adegan-potong.sumber
Tampaknya sintaks ini tidak selalu berfungsi .. Saya sudah menguji cukup banyak pada konten VOD kami serta konten langsung (file dumps) dan kadang-kadang scenecut tidak berfungsi dan memicu inbetween iframe:
Sintaks untuk konversi i50-> p50, gop / segmen 2 detik, IDR di awal, iframe antara jika diperlukan
sumber
Kedutan memiliki pos tentang ini. Mereka menjelaskan bahwa mereka memutuskan untuk menggunakan program mereka sendiri karena beberapa alasan; salah satunya adalah bahwa ffmpeg tidak membiarkan Anda menjalankan instance x264 yang berbeda di utas yang berbeda, tetapi sebaliknya mengabdikan semua utas yang ditentukan ke satu bingkai dalam satu output sebelum beralih ke output berikutnya.
Jika Anda tidak melakukan streaming real-time, Anda memiliki lebih banyak kemewahan. Cara 'benar' mungkin untuk menyandikan pada satu resolusi hanya dengan ukuran GOP yang ditentukan dengan -g, dan kemudian menyandikan resolusi lain yang memaksa kerangka kunci di tempat yang sama.
Jika Anda ingin melakukan itu, Anda bisa menggunakan ffprobe untuk mendapatkan waktu keyframe dan kemudian menggunakan skrip shell atau bahasa pemrograman yang sebenarnya untuk mengubahnya menjadi perintah ffmpeg.
Tetapi untuk sebagian besar konten, ada sedikit perbedaan antara memiliki satu kerangka kunci setiap 5 detik dan dua kerangka kunci setiap 5 detik (satu dipaksa dan satu dari scenecut). Ini adalah tentang ukuran I-frame rata-rata vs ukuran P-frame dan B-frame. Jika Anda menggunakan x264 dengan pengaturan tipikal (satu-satunya alasan saya pikir Anda harus melakukan apa pun untuk memengaruhi ini adalah jika Anda mengatur -qmin, sebagai cara yang buruk untuk mencegah x264 dari menggunakan bitrate pada konten yang mudah; ini membatasi semua jenis bingkai dengan nilai yang sama , Saya pikir) dan dapatkan hasil seperti ukuran rata-rata I-frame 46 kB, P-frame 24 kB, B-frame 17 kB (setengah lebih sering dari frame-P), lalu frame-I ekstra setiap detik pada 30 fps hanya peningkatan 3% dalam ukuran file. Perbedaan antara h264 dan h263 mungkin terdiri dari sekelompok penurunan 3%, tetapi satu saja tidak terlalu penting.
Pada jenis konten lain, ukuran bingkai akan berbeda. Agar adil, ini tentang kompleksitas temporal dan bukan kompleksitas spasial, jadi ini bukan hanya konten yang mudah vs konten yang sulit. Tetapi secara umum, situs video streaming memiliki batas bitrate, dan konten dengan I-frame yang relatif besar adalah konten yang mudah yang akan dikodekan pada kualitas tinggi tidak peduli berapa banyak frame kunci tambahan yang ditambahkan. Ini boros, tetapi limbah ini biasanya tidak akan diperhatikan. Kasing yang paling boros mungkin adalah video yang hanya berupa gambar statis yang menyertai sebuah lagu, di mana setiap frame kunci persis sama.
Satu hal yang saya tidak yakin adalah bagaimana keyframe yang dipaksakan berinteraksi dengan rate limiter yang diset dengan -maxrate dan -bufsize. Saya pikir bahkan YouTube memiliki masalah baru-baru ini dengan benar mengkonfigurasi pengaturan buffer untuk memberikan kualitas yang konsisten. Jika Anda hanya menggunakan pengaturan bitrate rata-rata seperti yang dapat dilihat oleh beberapa situs (karena Anda dapat memeriksa opsi x264 di header / mov atom? Dengan hex editor) maka model buffer tidak menjadi masalah, tetapi jika Anda melayani konten yang dibuat pengguna, bitrate rata-rata mendorong pengguna untuk menambahkan layar hitam di akhir video mereka.
Opsi -g Ffmpeg, atau opsi enkoder lain apa pun yang Anda gunakan, dipetakan ke opsi khusus enkoder. Jadi '-x264-params keyint = GOPSIZE' sama dengan '-g GOPSIZE'.
Salah satu masalah dengan menggunakan deteksi adegan adalah jika Anda lebih suka bingkai kunci di dekat angka tertentu untuk alasan apa pun. Jika Anda menentukan keyframe setiap 5 detik dan menggunakan deteksi adegan, dan ada perubahan adegan di 4,5, maka itu harus dideteksi, tetapi kemudian keyframe berikutnya berada pada 9,5. Jika waktu terus ditingkatkan seperti ini, Anda bisa berakhir dengan keyframe di 42,5, 47,5, 52,5, dll., Bukannya 40, 45, 50, 55. Sebaliknya, jika ada perubahan adegan di 5,5, maka akan ada bingkai kunci di 5 dan 5.5 akan terlalu dini untuk yang lain. Ffmpeg tidak membiarkan Anda menentukan "buat keyframe di sini jika tidak ada perubahan adegan dalam 30 frame berikutnya". Seseorang yang mengerti C dapat menambahkan opsi itu.
Untuk video kecepatan bingkai variabel, saat Anda tidak streaming langsung seperti Twitch, Anda harus dapat menggunakan perubahan pemandangan tanpa mengkonversi secara permanen ke laju bingkai konstan. Jika Anda menggunakan filter 'select' di ffmpeg dan menggunakan konstanta 'scene' dalam ekspresi, maka output debug (-v debug atau tekan '+' beberapa kali saat encoding) menunjukkan nomor perubahan adegan. Ini mungkin berbeda dari, dan tidak berguna seperti, angka yang digunakan oleh x264, tetapi masih bisa berguna.
Prosedurnya, kemudian, mungkin akan melakukan tes video yang hanya untuk perubahan keyframe, tetapi mungkin dapat digunakan untuk data kontrol tingkat jika menggunakan 2-pass. (Tidak yakin apakah data yang dihasilkan sama sekali berguna untuk resolusi dan pengaturan yang berbeda; data macroblock-tree tidak akan.) Konversikan ke video framerate konstan, tetapi lihat bug ini tentang gagap output ketika membagi dua framerate jika Anda memutuskan untuk menggunakan filter fps untuk keperluan lain. Jalankan melalui x264 dengan kerangka kunci dan pengaturan GOP yang Anda inginkan.
Kemudian gunakan waktu keyframe ini dengan video frame-rate variabel asli.
Jika Anda mengizinkan konten yang dibuat pengguna yang benar-benar gila dengan celah 20 detik di antara frame, maka untuk pengkodean frame-rate variabel, Anda dapat membagi output, menggunakan filter fps, entah bagaimana menggunakan filter pilih (mungkin membangun ekspresi yang sangat panjang yang memiliki setiap waktu keyframe) ... atau mungkin Anda bisa menggunakan video uji sebagai input dan mendekodekan hanya keyframe, jika opsi ffmpeg bekerja, atau gunakan filter pilih untuk memilih keyframe. Kemudian skala ke ukuran yang benar (bahkan ada filter scale2ref untuk ini) dan overlay video asli di dalamnya. Kemudian gunakan filter interleave untuk menggabungkan keyframe yang ditakdirkan ini dengan video asli. Jika ini menghasilkan dua frame yang terpisah 0,001 detik sehingga filter interleave tidak mencegah, maka selesaikan sendiri masalah ini dengan filter pilih lainnya. Berurusan dengan batas buffer bingkai untuk filter interleave bisa menjadi masalah utama di sini. Ini semua bisa bekerja: gunakan beberapa jenis filter untuk buffer aliran lebih padat (filter fifo?); lihat file input beberapa kali sehingga diterjemahkan lebih dari satu kali dan frame tidak harus disimpan; gunakan filter 'streamselect', yang belum pernah saya lakukan, tepat pada waktu keyframe; tingkatkan filter interleave dengan mengubah perilaku default atau menambahkan opsi untuk menampilkan frame tertua dalam buffer alih-alih menjatuhkan frame. yang belum pernah saya lakukan, tepat pada waktu keyframe; tingkatkan filter interleave dengan mengubah perilaku default atau menambahkan opsi untuk menampilkan frame tertua dalam buffer alih-alih menjatuhkan frame. yang belum pernah saya lakukan, tepat pada waktu keyframe; tingkatkan filter interleave dengan mengubah perilaku default atau menambahkan opsi untuk menampilkan frame tertua dalam buffer alih-alih menjatuhkan frame.
sumber