Apa cara yang benar untuk memperbaiki keyframe di FFmpeg untuk DASH?

38

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 scenecutkeyframe yang disuntikkan 3 detik oleh libx264, akankah keyframe berikutnya menjadi 5 detik kemudian atau 2 detik kemudian?

Bahkan, dokumentasi FFmpeg membedakan antara ini dan -gopsi, tetapi tidak benar-benar mengatakan bagaimana kedua opsi di atas sedikit berbeda (jelas, -gakan memerlukan frame rate tetap).

Mana yang benar

Tampaknya -force_key_framesakan 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 scenecutkeyframe.

Tampaknya juga -gtidak bisa bekerja tanpa memaksakan frame rate tetap ( -r) , karena tidak ada jaminan bahwa beberapa kali berjalan ffmpegdengan 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 keyintmetode hanya tampak seperti hack . Saya berharap dengan harapan bahwa ini bukan jawaban yang benar.

Referensi:

Contoh menggunakan -force_key_framesmetode

Contoh menggunakan keyintmetode

Bagian opsi video lanjutan FFmpeg

Mark Gerolimatos
sumber

Jawaban:

27

TL; DR

Saya akan merekomendasikan yang berikut ini:

  • libx264: (dan tambahkan opsional )-g X -keyint_min X-force_key_frames "expr:gte(t,n_forced*N)"
  • libx265: -x265-params "keyint=X:min-keyint=X"
  • libvpx-vp9: -g X

di mana Xinterval dalam bingkai dan Ninterval dalam detik. Misalnya, untuk interval 2 detik dengan video 30fps, X= 60 dan N= 2.

Catatan tentang berbagai jenis bingkai

Untuk menjelaskan topik ini dengan benar, pertama-tama kita harus mendefinisikan dua jenis bingkai-I / bingkai kunci:

  • Kerangka Decoder Segarkan Refresh (IDR) instan: Ini memungkinkan penguraian kode yang independen dari bingkai berikut, tanpa akses ke bingkai sebelum bingkai IDR.
  • Non-IDR-frames: Ini membutuhkan frame IDR sebelumnya agar decoding berfungsi. Bingkai non-IDR dapat digunakan untuk memotong adegan di tengah-tengah GOP (sekelompok gambar).

Apa yang disarankan untuk streaming?

Untuk kasus streaming, Anda ingin:

  • Pastikan semua frame IDR berada pada posisi reguler (mis. Pada 2, 4, 6, ... detik) sehingga video dapat dipecah menjadi segmen-segmen dengan panjang yang sama.
  • Aktifkan deteksi pemotongan adegan, sehingga dapat meningkatkan efisiensi / kualitas pengkodean. Ini berarti memungkinkan frame-I ditempatkan di antara frame-frame IDR. Anda masih dapat bekerja dengan deteksi potongan adegan dinonaktifkan (dan ini masih merupakan bagian dari banyak panduan), tetapi itu tidak perlu.

Apa yang dilakukan parameter?

Untuk mengkonfigurasi encoder, kita harus memahami apa yang dilakukan parameter keyframe. Saya melakukan beberapa tes dan menemukan yang berikut, untuk tiga penyandi libx264, libx265dan libvpx-vp9di FFmpeg:

  • libx264:

    • -g mengatur interval keyframe.
    • -keyint_min mengatur interval keyframe minimum.
    • -x264-params "keyint=x:min-keyint=y"sama dengan -g x -keyint_min y.
    • Catatan: Saat mengatur keduanya ke nilai yang sama, minimum ditetapkan secara internal setengah interval maksimum plus satu, seperti yang terlihat dalam x264kode:

      h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
      
  • libx265:

    • -g tidak diterapkan.
    • -x265-params "keyint=x:min-keyint=y" bekerja.
  • libvpx-vp9:

    • -g mengatur interval keyframe.
    • -keyint_min mengatur interval keyframe minimum
    • Catatan: Karena cara kerja FFmpeg, -keyint_minhanya diteruskan ke enkoder bila sama dengan -g. Dalam kode dari libvpxenc.cdalam FFmpeg kita dapat menemukan:

      if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
          enccfg.kf_min_dist = avctx->keyint_min;
      if (avctx->gop_size >= 0)
          enccfg.kf_max_dist = avctx->gop_size;
      

      Ini mungkin bug (atau kekurangan fitur?), Karena libvpxpasti mendukung pengaturan nilai yang berbeda untuk kf_min_dist.

Haruskah Anda gunakan -force_key_frames?

The -force_key_framespilihan paksa menyisipkan keyframe pada interval tertentu (ekspresi). Ini berfungsi untuk semua penyandi, tetapi mungkin mengacaukan mekanisme kontrol laju. Khusus untuk VP9, ​​saya perhatikan fluktuasi kualitas yang parah, jadi saya tidak bisa merekomendasikan menggunakannya dalam kasus ini.

slhck
sumber
Terima kasih! Ini umpan balik yang bagus. Satu pertanyaan yang saya miliki adalah bagaimana Anda membuat tabel yang luar biasa itu. Saya benar-benar bisa menggunakan sesuatu seperti itu.
Mark Gerolimatos
(Tampaknya tidak ada cara untuk menulis Anda secara langsung) Bisakah Anda mengarahkan saya ke tautan ke utas dalam diskusi ITU-T ini? Terima kasih!
Mark Gerolimatos
2
Saya baru saja membuatnya di Excel, menempelkan hasil yang saya dapatkan dari tiga proses 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.
slhck
Bisakah Anda mencoba kembali percobaan Anda dengan -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.
Mark Gerolimatos
Menarik. Saya percaya itu bernilai jawaban "nyata" yang terpisah jika Anda tahu itu berhasil. (Situs Stack Exchange tidak terlalu bagus untuk balasan gaya diskusi ini.) Terakhir kali saya memeriksa, -force_key_framestidak berfungsi untuk saya, jadi saya tidak pernah mencobanya lagi. Itu lebih dari setahun yang lalu. Mungkin itu bug. Saya akan coba lagi nanti.
slhck
12

Ini uang saya lima puluh sen untuk kasingnya.

Metode 1:

mengacaukan argumen libx264

-c: v libx264 -x264opts keyint = GOPSIZE: min-keyint = GOPSIZE: scenecut = -1

Hasilkan iframe hanya pada interval yang diinginkan.

Contoh 1:

ffmpeg -i test.mp4 -codec:v libx264 \
-r 23.976 \
-x264opts "keyint=48:min-keyint=48:no-scenecut" \
-c:a copy \
-y test_keyint_48.mp4

Hasilkan iframe seperti yang diharapkan seperti ini:

Iframes     Seconds
1           0
49          2
97          4
145         6
193         8
241         10
289         12
337         14
385         16
433         18
481         20
529         22
577         24
625         26
673         28
721         30
769         32
817         34
865         36
913         38
961         40
1009        42
1057        44
1105        46
1153        48
1201        50
1249        52
1297        54
1345        56
1393        58

Metode 2 disusutkan. Ommitted.

Metode 3:

masukkan bingkai kunci setiap N detik (MAYBE):

-force_key_frames expr: gte (t, n_forced * GOP_LEN_IN_SECONDS)

Contoh 2

ffmpeg -i test.mp4 -codec:v libx264 \
-r 23.976 \
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy \
-y test_fkf_2.mp4

Buat iframe dengan cara yang sedikit berbeda:

Iframes     Seconds
1           0
49          2
97          4
145         6
193         8
241         10
289         12
337         14
385         16
433         18
481         20
519         21.58333333
529         22
577         24
625         26
673         28
721         30
769         32
817         34
865         36
913         38
931         38.75
941         39.16666667
961         40
1008        42
1056        44
1104        46
1152        48
1200        50
1248        52
1296        54
1305        54.375
1344        56
1367        56.95833333
1392        58
1430        59.58333333
1440        60
1475        61.45833333
1488        62
1536        64
1544        64.33333333
1584        66
1591        66.29166667
1632        68
1680        70
1728        72
1765        73.54166667
1776        74
1811        75.45833333
1824        75.95833333
1853        77.16666667
1872        77.95833333
1896        78.95833333
1920        79.95833333
1939        80.75
1968        81.95833333

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.

Ara Saahov
sumber
Fantastis, terima kasih untuk 50 sen Anda!
BrunoFenzl
7

Karena itu jawabannya adalah:

  • Metode 1 diverifikasi untuk berfungsi, tetapi libx264spesifik dan harus dibayar dengan menghilangkan opsi yang sangat berguna scenecutdi libx264.
  • Metode 3 berfungsi pada versi FFMPEG April 2015, tetapi Anda harus memverifikasi hasil Anda dengan skrip yang disertakan di bagian bawah posting ini, karena dokumentasi FFMPEG tidak jelas mengenai efek dari opsi tersebut. Jika berhasil, itu adalah superior dari dua opsi.
  • JANGAN GUNAKAN Metode 2, -gtampaknya 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 -gopsi tersebut kemungkinan dimaksudkan untuk stream MPEG-2 (bahkan ada bait kode yang mengacu pada PAL dan NTSC!).

Juga:

  • File yang dihasilkan dengan Metode 3 mungkin sedikit lebih besar dari Metode 1, karena bingkai I interstitial (bingkai kunci) diizinkan.
  • Anda harus secara eksplisit mengatur flag "-r" di kedua kasus, meskipun Metode 3 menempatkan bingkai I di frameslot berikutnya pada atau setelah waktu yang ditentukan. Kegagalan untuk mengatur tanda "-r" menempatkan Anda pada belas kasihan file sumber, mungkin dengan laju bingkai variabel. Transisi DASH yang tidak kompatibel dapat terjadi.
  • Terlepas dari peringatan dalam dokumentasi FFMPEG, metode 3 TIDAK kurang efisien daripada yang lain. Bahkan, tes menunjukkan bahwa itu mungkin sedikit LEBIH efisien daripada metode 1.

Script untuk -force_key_framesopsi

Berikut 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_framesmetode ini juga akan berfungsi, dan memiliki manfaat tambahan untuk memungkinkan scenecutframe. 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.

#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsize\n";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
        or die "Blah";
while (<$pipe>) {
  if ($linenum > $expected) {
    # Won't catch all the misses. But even one is good enough to fail.
    print "Missed IFrame at $expected\n";
    $expected = (int($linenum/$gopsize) + 1)*$gopsize;
  }
  if (m/,I\s*$/) {
    if ($linenum < $expected) {
      # Don't care term, just an extra I frame. Snore.
      #print "Free IFrame at $linenum\n";
    } else {
      #print "IFrame HIT at $expected\n";
      $expected += $gopsize;
    }
  }
  $linenum += 1;
}
Mark Gerolimatos
sumber
Hanya sebuah catatan: Karena ini adalah situs tanya jawab dan bukan forum diskusi tempat pesan disusun secara kronologis, yang terbaik adalah memasukkan semua informasi ke dalam satu jawaban, sehingga orang yang mencari solusi hanya perlu membaca satu posting dan tidak melihat pada yang memposting apa, kapan :) Saya menggabungkan jawaban Anda dan memberi Anda +1 pada ini juga. Karena posting silang tidak diizinkan , saya sarankan Anda menghapus pertanyaan Anda di situs Video. Orang-orang akan menemukan jawabannya di sini.
slhck
1
Saya hanya punya satu pemikiran lagi (sebenarnya itu muncul di milis FFmpeg). Ketika Anda menggunakan force_key_frames, itu agak mengacaukan algoritma alokasi bit x264, sehingga dapat memberikan kualitas yang lebih buruk daripada hanya mengatur interval keyframe tetap.
slhck
Omong kosong Namun satu alasan lagi untuk memiliki FFMPEG menyediakan cara codec-nonspecfic untuk melakukan ini, sebuah argumen yang akan "melakukan hal terbaik untuk codec yang dimaksud". Saya mencoba untuk mengajukan tiket untuk ini dengan trac FFMPEG, tetapi memantul :-(
Mark Gerolimatos
@ Slhck: Bisakah Anda memberikan detail lebih lanjut? Saya telah melihat arsip milis pada Mei 2015 tetapi tidak dapat menemukan apa pun. Intinya adalah melupakan "Metode 3" dan berpegang pada "Metode 1".
schieferstapel
3
@MarkGerolimatos: about -g, Anda berkata, "Tampaknya tidak berfungsi, ... juga tidak tampaknya digunakan dalam kode.". Aku memeriksa dan masukan dari gdisimpan dalam avctx->gop_sizedan 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.mp4saya mendapatkan keyframe dengan tepat 0,37,74,111,148,185,222,259,296,333,370. GOP dapat dipotong pendek jika perubahan adegan dipicu, dan untuk itu -sc_thresholddapat diatur, yang juga diambil oleh x264.
Gyan
4

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:

  1. 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.

  2. -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE← Ini tidak melakukan apa yang Anda pikirkan. Saya butuh waktu beberapa saat untuk mencari tahu. Ternyata min-keyintterbatas pada kode. Itu tidak boleh lebih besar dari (keyint / 2) + 1. Jadi, menetapkan nilai yang sama untuk dua variabel ini menghasilkan nilai untuk min-keyintdirobohkan 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 keyintuntuk menggandakan ukuran GOP yang saya inginkan. Ini berarti bahwa min-keyintdapat 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 dari min-keyinit.

Dan akhirnya pengaturan force_key_frameopsi menimpa ukuran ganda keyint. Jadi, inilah yang bekerja:

Saya lebih suka segmen dalam potongan 2 detik, jadi GOPSIZE saya = Membingkai * 2

ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>

Anda dapat memverifikasi menggunakan ffprobe:

ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv

Dalam file CSV yang dihasilkan, setiap baris akan memberi tahu Anda frame, [is_an_IDR_?], [frame_type], [frame_number]::

frame,1,I,60  <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71  <-- frame 71, is I frame, 0 means not an IDR I_frame

Hasilnya adalah Anda hanya akan melihat IDR-Frame pada GOPSIZEinterval tetap , sedangkan semua frame I lainnya adalah IDR-frame non-dimasukkan sebagaimana diperlukan oleh deteksi adegan-potong.

Ruben
sumber
itu fantastis! Itu juga sangat berlawanan dengan intuisi, terima kasih telah berusaha. Dan untuk meringkas, saya menganggap definisi Anda tentang "I-frame" dan "i-frames" adalah konseptual (yaitu, tidak secara eksplisit dapat dikonfigurasi dalam libx264), dan bahwa "max * 2" adalah cara Anda menerapkannya?
Mark Gerolimatos
Ya itu konseptual, meskipun saya telah melihat orang menggunakan "I" vs "i" untuk membedakan antara IDR-frame I dan IDR-non. Dan ya, mengatur keyinit ke ukuran gop yang diinginkan * 2 adalah cara untuk memaksa semua frame I di dalam gop menjadi non-IDR I-frame. Kemudian ffmpeg -force-key-frames over-rides key-init di x264opts. Pada dasarnya ini adalah cara yang sangat mundur untuk mendapatkan hasil yang diinginkan yang mungkin terjadi jika kode x264 memungkinkan Anda untuk mengatur min-keyinit dan keyinit ke nilai yang sama.
Reuben
... sementara juga bisa mengaktifkan deteksi adegan-potong dihidupkan dan mendapatkan ukuran GOP diperbaiki.
Reuben
terima kasih lagi untuk pekerjaan Anda yang luar biasa! Kedengarannya seperti kita membutuhkan cara yang kurang "mundur" untuk mempengaruhinya
Mark Gerolimatos
Apakah rc-lookahead diperlukan di sini? Ini mempengaruhi mbtree dan VBV, tetapi apakah itu mempengaruhi generasi i-frame?
Alexander Svetkin
0

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

ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
TEB
sumber
0

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.

Misaki
sumber