วิธีที่ถูกต้องในการแก้ไขคีย์เฟรมใน FFmpeg สำหรับ DASH คืออะไร


38

เมื่อปรับกระแสสำหรับการเล่น DASH จุดเชื่อมต่อแบบสุ่มต้องอยู่ในช่วงเวลาเดียวกันกับสตรีมทุกแหล่ง วิธีปกติในการทำเช่นนี้คือการบังคับให้อัตราเฟรมคงที่และความยาว GOP คงที่ (เช่นคีย์เฟรมทุกเฟรม N)

ใน FFmpeg อัตราเฟรมคงที่นั้นง่าย (-r NUMBER)

แต่สำหรับตำแหน่งคีย์เฟรมคงที่ (ความยาว GOP) มีสามวิธี ... วิธีใดที่ "ถูกต้อง" เอกสาร FFmpeg นั้นคลุมเครือในเรื่องนี้

วิธีที่ 1: ล้อเล่นกับอาร์กิวเมนต์ของ libx264

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

ดูเหมือนว่าจะมีการถกเถียงกันว่าควรเปิดฉากหรือไม่เพราะมันไม่ชัดเจนว่ามีการรีสตาร์ทเฟรมเมื่อมีการตัดฉาก

วิธีที่ 2: การตั้งค่าขนาด GOP คงที่:

-g GOP_LEN_IN_FRAMES

น่าเสียดายที่มีการบันทึกไว้เฉพาะในการส่งผ่านในเอกสาร FFMPEG และผลของการโต้แย้งนี้ก็ไม่ชัดเจน

วิธีที่ 3: แทรกคีย์เฟรมทุก ๆ N วินาที ( อาจเป็นไปได้ ):

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

นี่คือเอกสารอย่างชัดเจน แต่ก็ยังไม่ชัดเจนในทันทีหาก ​​"ตัวนับเวลา" รีสตาร์ทหลังจากทุกเฟรมหลัก ตัวอย่างเช่นใน GOP 5 วินาทีที่คาดไว้หากมีการกดscenecutคีย์เฟรม 3 วินาทีภายใน libx264 คีย์เฟรมถัดไปจะเป็น 5 วินาทีในภายหลังหรือ 2 วินาทีในภายหลังหรือไม่

ในความเป็นจริงเอกสาร FFmpeg สร้างความแตกต่างระหว่างสิ่งนี้และ-gตัวเลือก แต่มันไม่ได้พูดจริง ๆ ว่าตัวเลือกสองตัวด้านบนนั้นแตกต่างกันอย่างน้อยบิตอย่างไร (แน่นอนว่า-gจะต้องใช้อัตราเฟรมคงที่)

อะไรถูก

ดูเหมือนว่า-force_key_framesจะดีกว่าเนื่องจากจะไม่ต้องการอัตราเฟรมคงที่ อย่างไรก็ตามสิ่งนี้ต้องการสิ่งนั้น

  • เป็นไปตามข้อกำหนด GOP ใน H.264 ( ถ้ามี )
  • รับประกันว่าจะมีคีย์เฟรมในจังหวะการหมุนคงที่โดยไม่คำนึงถึง libx264 scenecutคีย์เฟรม

ดูเหมือนว่า-gมันจะไม่สามารถทำงานได้โดยไม่บังคับให้ใช้อัตราเฟรมคงที่ ( -r)เนื่องจากไม่มีการรับประกันว่าการรันหลาย ๆ ครั้งที่ffmpegมีอาร์กิวเมนต์ตัวแปลงสัญญาณที่แตกต่างกันจะให้อัตราเฟรมทันทีในแต่ละความละเอียด อัตราเฟรมคงที่อาจลดประสิทธิภาพการบีบอัด (สำคัญในสถานการณ์ DASH!)

สุดท้ายวิธีการก็ดูเหมือนว่าสับ ฉันหวังว่าจะมีความหวังว่านี่ไม่ใช่คำตอบที่ถูกต้องkeyint

อ้างอิง:

ตัวอย่างการใช้-force_key_framesวิธีการ

ตัวอย่างการใช้keyintวิธีการ

ส่วนตัวเลือกวิดีโอขั้นสูง FFmpeg

คำตอบ:


27

TL; DR

ฉันอยากจะแนะนำต่อไปนี้:

  • libx264: (และเพิ่มทางเลือก)-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

โดยที่Xเป็นช่วงเวลาในเฟรมและNเป็นช่วงเวลาเป็นวินาที ตัวอย่างเช่นสำหรับช่วงเวลา 2 วินาทีด้วยวิดีโอ 30fps, X= 60 และN= 2

หมายเหตุเกี่ยวกับประเภทเฟรมที่แตกต่างกัน

เพื่ออธิบายหัวข้อนี้อย่างถูกต้องอันดับแรกเราต้องกำหนด I-frames / keyframes สองประเภท:

  • เฟรมถอดรหัสการรีเฟรชทันที (IDR): อนุญาตการถอดรหัสเฟรมต่อไปนี้โดยไม่ต้องเข้าถึงเฟรมก่อนหน้าเฟรม IDR
  • Non-IDR-frames: สิ่งเหล่านี้จำเป็นต้องใช้เฟรม IDR ก่อนหน้าเพื่อให้การถอดรหัสทำงานได้ เฟรมที่ไม่ใช่ IDR สามารถใช้สำหรับการตัดฉากในช่วงกลางของ GOP (กลุ่มรูปภาพ)

สิ่งที่แนะนำสำหรับการสตรีม

สำหรับกรณีสตรีมมิ่งคุณต้องการ:

  • ตรวจสอบให้แน่ใจว่าเฟรม IDR ทั้งหมดอยู่ในตำแหน่งปกติ (เช่นที่ 2, 4, 6, ... วินาที) เพื่อให้วิดีโอสามารถแบ่งออกเป็นเซ็กเมนต์ที่มีความยาวเท่ากัน
  • เปิดใช้งานการตรวจจับฉากเพื่อปรับปรุงประสิทธิภาพ / คุณภาพการเข้ารหัส ซึ่งหมายความว่าช่วยให้สามารถวาง I-frames ระหว่างเฟรม IDR คุณยังคงสามารถใช้งานได้เมื่อปิดใช้งานการตรวจจับการตัดซีน (และนี่เป็นส่วนหนึ่งของคู่มือจำนวนมากยัง) แต่ก็ไม่จำเป็น

พารามิเตอร์ทำอะไร

เพื่อกำหนดค่าตัวเข้ารหัสเราต้องเข้าใจว่าพารามิเตอร์คีย์เฟรมทำอะไร ฉันไม่ได้ทดสอบบางอย่างและค้นพบต่อไปนี้สำหรับสาม encoders libx264, libx265และlibvpx-vp9ใน FFmpeg:

  • libx264:

    • -g กำหนดช่วงเวลาของเฟรม
    • -keyint_min กำหนดช่วงเวลาของเฟรมเฟรมต่ำสุด
    • -x264-params "keyint=x:min-keyint=y"-g x -keyint_min yเป็นเช่นเดียวกับ
    • หมายเหตุ:เมื่อตั้งค่าทั้งสองเป็นค่าเดียวกันค่าต่ำสุดจะถูกตั้งค่าภายในเป็นครึ่งหนึ่งของช่วงเวลาสูงสุดบวกหนึ่งค่าตามที่เห็นในx264รหัส:

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

    • -g ไม่ได้ใช้งาน
    • -x265-params "keyint=x:min-keyint=y" โรงงาน
  • libvpx-vp9:

    • -g กำหนดช่วงเวลาของเฟรม
    • -keyint_min กำหนดช่วงเวลาของเฟรมเฟรมต่ำสุด
    • หมายเหตุ:เนื่องจากวิธีการทำงาน FFmpeg, จะถูกส่งต่อเท่านั้นที่จะเข้ารหัสเมื่อมันเป็นเช่นเดียวกับ-keyint_min -gในรหัสจากlibvpxenc.cใน FFmpeg เราสามารถหา:

      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;
      

      นี้อาจจะมีข้อผิดพลาด (หรือขาดคุณสมบัติ?) ตั้งแต่แน่นอนสนับสนุนการตั้งค่าที่แตกต่างกันสำหรับlibvpxkf_min_dist

คุณควรใช้-force_key_frames?

-force_key_framesตัวเลือกบังคับแทรกคีย์เฟรมในช่วงเวลาที่กำหนด (expression) วิธีนี้ใช้ได้กับเครื่องเข้ารหัสทั้งหมด แต่อาจยุ่งกับกลไกการควบคุมอัตรา โดยเฉพาะอย่างยิ่งสำหรับ VP9 ฉันสังเกตเห็นความผันผวนของคุณภาพอย่างรุนแรงดังนั้นฉันจึงไม่แนะนำให้ใช้ในกรณีนี้


ขอขอบคุณ! นี่คือข้อเสนอแนะที่ดี คำถามหนึ่งที่ฉันมีคือวิธีที่คุณสร้างตารางที่ยอดเยี่ยม ฉันสามารถใช้บางอย่างเช่นนั้นได้ทั้งหมด
Mark Gerolimatos

(ดูเหมือนจะไม่มีทางเขียนถึงคุณโดยตรง) คุณช่วยชี้ทางลิงก์ไปยังกระทู้ต่างๆในการสนทนา ITU-T นี้ได้ไหม ขอบคุณ!
Mark Gerolimatos

2
ฉันเพิ่งทำสิ่งนั้นใน Excel วางผลลัพธ์ที่ฉันได้รับจากการวิ่งสามครั้งจากffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_typeนั้นระบายสีเซลล์ ฉันกลัวว่าจะไม่มีการพูดคุยในที่สาธารณะ แต่ฉันจะดูว่าฉันสามารถขุดลิงก์ที่ฉันพบได้ในตอนนั้นหรือไม่
slhck

คุณช่วยลองทดสอบกับ-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)ฟอร์มอีกครั้งได้ไหม ฉันลองมันและพบว่าในขณะที่มีเฟรมพิเศษในสตรีม DID ก็ดูเหมือนจะปฏิบัติตามกฎของฉัน โปรแกรม PERL จะทำตามเป็น "คำตอบ" เนื่องจากคุณไม่สามารถใช้มาร์กอัปในความคิดเห็นได้
Mark Gerolimatos

น่าสนใจ ฉันเชื่อว่ามันคุ้มค่าคำตอบ "ของจริง" แยกต่างหากถ้าคุณพบว่ามันใช้งานได้ (ไซต์แลกเปลี่ยนแบบสแต็กไม่ดีสำหรับการตอบกลับสไตล์การสนทนานี้) ครั้งสุดท้ายที่ฉันตรวจสอบ-force_key_framesไม่ได้ผลสำหรับฉันและดังนั้นฉันจึงไม่เคยลองอีกครั้ง นั่นเป็นมากกว่าปีที่แล้ว บางทีมันอาจเป็นข้อผิดพลาด ฉันจะลองอีกครั้งในไม่ช้า
slhck

12

นี่คือห้าสิบเซ็นต์ของฉันสำหรับกรณี

วิธีที่ 1:

ล้อเล่นกับอาร์กิวเมนต์ของ libx264

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

สร้าง iframes เท่านั้นตามช่วงเวลาที่ต้องการ

ตัวอย่างที่ 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

สร้าง iframes ตามที่คาดไว้เช่นนี้:

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

วิธีที่ 2 ถูกคิดค่าเสื่อมราคา Ommitted

วิธีที่ 3:

แทรกคีย์เฟรมทุก N วินาที (MAYBE):

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

ตัวอย่างที่ 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

สร้าง iframes ด้วยวิธีที่ต่างกันเล็กน้อย:

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

อย่างที่คุณเห็นมันวาง iframes ทุก ๆ 2 วินาทีและบน Scenecut (วินาทีที่มีส่วนที่ลอย) ซึ่งเป็นสิ่งสำคัญสำหรับความซับซ้อนของวิดีโอสตรีมในความคิดของฉัน

ขนาดไฟล์ที่สร้างขึ้นจะเหมือนกันทุกประการ แปลกมากที่มี keyframes มากกว่าในวิธีที่ 3บางครั้งก็สร้างไฟล์น้อยกว่าอัลกอริธึมไลบรารี x264 มาตรฐาน

สำหรับการสร้างไฟล์บิตเรตหลายไฟล์สำหรับสตรีม HLS เราเลือกวิธีที่สาม มันสอดคล้องอย่างสมบูรณ์กับ 2 วินาทีระหว่างชิ้นพวกเขามี iframe ที่จุดเริ่มต้นของทุก ๆ ชิ้นและพวกเขามี iframes เพิ่มเติมในฉากที่ซับซ้อนซึ่งให้ประสบการณ์ที่ดีขึ้นสำหรับผู้ใช้ที่มีอุปกรณ์ที่ล้าสมัยและไม่สามารถเล่นโปรไฟล์สูง x264

หวังว่าจะช่วยใครซักคน


เยี่ยมมากขอบคุณ 50 เซนต์ของคุณ!
BrunoFenzl

7

คำตอบน่าจะเป็น:

  • วิธีที่ 1 ที่มีการยืนยันในการทำงาน แต่libx264-specific และมาที่ค่าใช้จ่ายของการขจัดประโยชน์มากตัวเลือกในscenecutlibx264
  • วิธีที่ 3 ใช้งานได้กับเวอร์ชัน FFMPEG ของเดือนเมษายน 2558 แต่คุณควรตรวจสอบผลลัพธ์ของคุณพร้อมกับสคริปต์ที่รวมอยู่ที่ด้านล่างของโพสต์นี้เนื่องจากเอกสาร FFMPEG นั้นไม่ชัดเจนเกี่ยวกับผลกระทบของตัวเลือก ถ้ามันใช้งานได้มันยอดเยี่ยมของสองตัวเลือก
  • อย่าใช้วิธีที่ 2 -gดูเหมือนจะเลิกใช้แล้ว ไม่ปรากฏว่าทำงานหรือไม่ได้กำหนดไว้อย่างชัดเจนในเอกสารประกอบหรือไม่พบในความช่วยเหลือและไม่ปรากฏว่าจะใช้ในรหัส การตรวจสอบรหัสแสดงให้เห็นว่า-gตัวเลือกนั้นน่าจะมีความหมายสำหรับสตรีมแบบ MPEG-2 (มีแม้แต่โค้ดโค้ดที่อ้างถึง PAL และ NTSC!)

นอกจากนี้:

  • ไฟล์ที่สร้างด้วยวิธีที่ 3 อาจมีขนาดใหญ่กว่าวิธีที่ 1 เล็กน้อยเนื่องจากอนุญาตให้ใช้เฟรมคั่นระหว่างหน้า (คีย์เฟรม)
  • คุณควรตั้งค่าแฟล็ก "-r" อย่างชัดเจนในทั้งสองกรณีแม้ว่าวิธีที่ 3 จะวางเฟรม I ในเฟรมล็อตถัดไปในหรือหลังเวลาที่ระบุ ความล้มเหลวในการตั้งค่าสถานะ "-r" ทำให้คุณอยู่ในความเมตตาของไฟล์ต้นฉบับซึ่งอาจมีอัตราเฟรมที่ผันแปรได้ การเปลี่ยน DASH ที่เข้ากันไม่ได้อาจส่งผลให้
  • แม้จะมีคำเตือนในเอกสาร FFMPEG แต่วิธีที่ 3 นั้นไม่ได้มีประสิทธิภาพน้อยกว่าวิธีอื่น ๆ ในความเป็นจริงการทดสอบแสดงให้เห็นว่าอาจมีประสิทธิภาพมากกว่าวิธีที่ 1 เล็กน้อย

สคริปต์สำหรับ-force_key_framesตัวเลือก

นี่เป็นโปรแกรม PERL สั้น ๆ ที่ฉันใช้เพื่อตรวจสอบจังหวะการเต้นของเฟรม I ตามการส่งออกของคำแนะนำ ffprobe ของ slhck ดูเหมือนว่าจะตรวจสอบว่า-force_key_framesวิธีการนี้ยังใช้งานได้และมีประโยชน์เพิ่มเติมจากการอนุญาตให้ใช้scenecutเฟรม ฉันไม่รู้ว่า FFMPEG สร้างผลงานนี้ได้อย่างไรหรือถ้าฉันโชคดีออกมาเพราะลำธารของฉันมีสภาพดี

ในกรณีของฉันฉันเข้ารหัสที่ 30fps ด้วยขนาด GOP ที่คาดไว้ที่ 6 วินาทีหรือ 180 เฟรม ฉันใช้ 180 เป็นอาร์กิวเมนต์ gopsize ในโปรแกรมนี้ตรวจสอบเฟรม I ที่หลาย ๆ 180 แต่ตั้งค่าเป็น 181 (หรือหมายเลขอื่นใดที่ไม่ใช่พหุคูณของ 180) ทำให้มันบ่น

#!/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;
}

เพียงทราบ: เนื่องจากนี่เป็นเว็บไซต์ถาม - ตอบและไม่ใช่ฟอรัมการสนทนาที่โพสต์ตามลำดับเวลาจึงควรใส่ข้อมูลทั้งหมดไว้ในคำตอบเดียวเพื่อให้ผู้คนที่กำลังมองหาวิธีแก้ไขต้องอ่านโพสต์เดียวและไม่ต้องมอง ที่ใครโพสต์เมื่อไหร่ :) ฉันได้รวมคำตอบของคุณและให้ +1 กับคุณด้วย เนื่องจากไม่อนุญาตให้โพสต์ข้อความไขว้ฉันขอแนะนำให้คุณลบคำถามของคุณในเว็บไซต์วิดีโอ ผู้คนจะพบคำตอบได้ที่นี่
slhck

1
ฉันเพิ่งคิดอีกครั้ง (จริง ๆ แล้วมันถูกยกขึ้นในรายชื่อผู้รับจดหมาย FFmpeg) เมื่อคุณใช้force_key_framesมันทำให้อัลกอริทึมการจัดสรรบิต x264 ยุ่งเหยิงดังนั้นมันอาจทำให้คุณภาพแย่ลงกว่าการตั้งค่าช่วงเฟรมคงที่
slhck

อึศักดิ์สิทธิ์ ยังมีอีกเหตุผลที่จะให้ FFMPEG เป็นวิธีการทำ codec-nonspecfic ซึ่งเป็นอาร์กิวเมนต์ที่จะ "ทำสิ่งที่ดีที่สุดสำหรับ codec ที่เป็นปัญหา" ฉันพยายามยื่นตั๋วสำหรับเรื่องนี้ด้วย trac ของ FFMPEG แต่เด้ง :-(
Mark Gerolimatos

@slhck: โปรดให้รายละเอียดเพิ่มเติมหน่อยได้ไหม? ฉันได้ดูในรายการจดหมายข่าวในเดือนพฤษภาคม 2558 แต่ไม่พบอะไรเลย บรรทัดล่างคือการลืม "วิธีที่ 3" และติดกับ "วิธีที่ 1"
schieferstapel

3
@ MarkGerolimatos: เกี่ยวกับ-gคุณพูดว่า "มันดูเหมือนจะไม่ทำงาน ... และดูเหมือนว่าจะไม่ได้ใช้ในรหัส" ฉันจะตรวจสอบและการป้อนข้อมูลของgถูกเก็บไว้ในavctx->gop_sizeและ libx264 x4->params.i_keyint_max = avctx->gop_size;ทำให้การใช้งานของมัน เมื่อผมตรวจสอบไฟล์ทดสอบที่สร้างขึ้นนี้ฉันได้รับคีย์เฟรมที่ตรงffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4 0,37,74,111,148,185,222,259,296,333,370อาจมีการตัด GOP สั้น ๆ หากมีการเปลี่ยนฉากและ-sc_thresholdสามารถตั้งค่าได้ซึ่ง x264 เลือกด้วย
Gyan

4

ฉันต้องการเพิ่มข้อมูลบางส่วนที่นี่เนื่องจาก googling ของฉันดึงการสนทนานี้ขึ้นมาเล็กน้อยเพื่อค้นหาข้อมูลเกี่ยวกับการพยายามหาวิธีแบ่งกลุ่มการเข้ารหัส DASH ของฉันในแบบที่ฉันต้องการและไม่มีข้อมูลใดที่ฉันพบว่าถูกต้องทั้งหมด

ความเข้าใจผิดหลายประการแรกที่ต้องกำจัด:

  1. I-frames ไม่เหมือนกันทั้งหมด มีเฟรม "I" ขนาดใหญ่และเฟรม "i" เล็กน้อย หรือเพื่อใช้คำศัพท์ที่ถูกต้อง, IDR I-Frames และ I-Frames ที่ไม่ใช่ IDR IDR I-frames (บางครั้งเรียกว่า "keyframes") จะสร้าง GOP ใหม่ เฟรมที่ไม่ใช่ IDR จะไม่ทำงาน พวกมันมีประโยชน์ที่จะมีภายใน GOP ที่มีการเปลี่ยนฉาก

  2. -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE←สิ่งนี้ไม่ได้ทำในสิ่งที่คุณคิด ฉันใช้เวลาสักครู่เพื่อคิดออก ปรากฎว่าmin-keyintถูก จำกัด ในรหัส (keyint / 2) + 1มันไม่ได้รับอนุญาตให้เป็นมากกว่า ดังนั้นการกำหนดค่าเดียวกันให้กับตัวแปรทั้งสองนี้จะส่งผลให้มีค่าในmin-keyintการทำให้ล้มลงครึ่งหนึ่งเมื่อทำการเข้ารหัส

นี่คือสิ่งที่: การตัดฉากนั้นยอดเยี่ยมจริงๆโดยเฉพาะในวิดีโอที่มีการตัดอย่างรวดเร็ว มันทำให้มันดูดีและคมชัดดังนั้นฉันไม่ต้องการที่จะปิดการใช้งาน แต่ในเวลาเดียวกันฉันไม่สามารถรับขนาด GOP คงที่ตราบใดที่เปิดใช้งาน ฉันต้องการเปิดใช้งานซีนซีน แต่เพื่อให้มันใช้เฟรม I แบบไม่ IDR เท่านั้น แต่มันไม่ทำงาน จนกว่าฉันจะรู้ (จากการอ่านจำนวนมาก) เกี่ยวกับความเข้าใจผิด # 2

ปรากฎว่าฉันต้องตั้งค่าkeyintให้เพิ่มขนาด GOP ที่ต้องการเป็นสองเท่า ซึ่งหมายความว่าmin-keyintสามารถตั้งค่าให้เป็นขนาด GOP ที่ฉันต้องการ (โดยไม่มีการตัดโค้ดภายในครึ่งหนึ่ง) ซึ่งป้องกันการตรวจจับฉากตัดจากการใช้ IDR I- เฟรมภายในขนาด GOP เนื่องจากจำนวนเฟรมนับตั้งแต่ IDR I สุดท้ายของเฟรมคือ น้อยกว่าmin-keyinitเสมอ

และในที่สุดก็ตั้งค่าตัวเลือกแทนที่คู่ขนาดforce_key_frame keyintดังนั้นนี่คือสิ่งที่ใช้งานได้:

ฉันชอบกลุ่มใน 2 วินาทีดังนั้น GOPSIZE ของฉัน = Framerate * 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>

คุณสามารถตรวจสอบโดยใช้ ffprobe:

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

ในไฟล์ CSV ที่สร้างขึ้นแต่ละบรรทัดจะบอกคุณ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

ผลที่ได้คือคุณควรเห็น IDR I-เฟรมในGOPSIZEช่วงเวลาคงที่เท่านั้นในขณะที่เฟรม I อื่น ๆ ทั้งหมดนั้นใส่เฟรม I ที่ไม่ใช่ IDR ตามที่ต้องการโดยการตรวจจับฉาก


นั่นวิเศษมาก! มันเป็นเรื่องที่ใช้ง่ายมากขอบคุณสำหรับความพยายาม และโดยสรุปฉันถือว่าคำจำกัดความของคุณของ "I-frames" และ "i-frames" เป็นแนวคิด (นั่นคือไม่สามารถกำหนดค่าได้อย่างชัดเจนใน libx264) และ "max * 2" เป็นวิธีที่คุณบังคับใช้หรือไม่
Mark Gerolimatos

ใช่นั่นคือแนวคิดแม้ว่าฉันเคยเห็นคนใช้ "I" กับ "i" เพื่อแยกความแตกต่างระหว่าง IDR และ I-frames ที่ไม่ใช่ IDR และใช่การตั้งค่า keyinit ให้เป็นขนาด gop ที่ต้องการ * 2 เป็นวิธีบังคับให้เฟรม I ทั้งหมดที่อยู่ใน gop เป็น non-IDR I-frames จากนั้น ffmpeg -force-key-frames over-rides key-init ใน x264opts โดยทั่วไปแล้วเป็นวิธีย้อนกลับที่แท้จริงเพื่อให้ได้ผลลัพธ์ที่ต้องการซึ่งอาจเป็นไปได้หากรหัส x264 อนุญาตให้คุณตั้งค่า min-keyinit และ keyinit เป็นค่าเดียวกัน
รูเบน

... ในขณะที่ยังสามารถเปิดใช้งานการตรวจจับฉากและเปิดขนาด GOP คงที่
รูเบน

ขอบคุณอีกครั้งสำหรับผลงานยอดเยี่ยมของคุณ! ฟังดูเหมือนเราต้องการวิธี "ย้อนกลับ" ที่มีผลน้อยกว่า
Mark Gerolimatos

rc-lookahead จำเป็นไหมที่นี่? มันมีผลต่อ mbtree และ VBV แต่มันส่งผลกระทบต่อการสร้าง i-frame หรือไม่?
Alexander Svetkin

0

ดูเหมือนว่าไวยากรณ์นี้ไม่ได้ผลเลย .. ฉันได้ทดสอบเนื้อหา VOD ของเรามากมายรวมถึงเนื้อหาสด (ทิ้งไฟล์) และบางครั้ง Scenecut ไม่ทำงานและเรียกใช้ iframe ระหว่าง:

ไวยากรณ์สำหรับ i50-> p50 upconvertion, 2 วินาที gop / เซกเมนต์, IDR ตอนเริ่ม, iframes อยู่ด้านในถ้าจำเป็น

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

0

Twitch มีโพสต์เกี่ยวกับเรื่องนี้ พวกเขาอธิบายว่าพวกเขาตัดสินใจใช้โปรแกรมของตนเองด้วยเหตุผลหลายประการ หนึ่งในนั้นคือ ffmpeg ไม่อนุญาตให้คุณเรียกใช้อินสแตนซ์ x264 ที่แตกต่างกันในเธรดที่แตกต่างกัน แต่แทนที่จะอุทิศเธรดที่ระบุทั้งหมดให้เป็นหนึ่งเฟรมในหนึ่งเอาต์พุตก่อนที่จะย้ายไปยังเอาต์พุตถัดไป

หากคุณไม่ได้ทำการสตรีมแบบเรียลไทม์คุณจะมีความหรูหรามากกว่า วิธีการ 'ถูกต้อง' นั้นอาจจะเข้ารหัสที่ความละเอียดเดียวโดยมีขนาด GOP ที่ระบุด้วย -g แล้วเข้ารหัสความละเอียดอื่น ๆ เพื่อบังคับให้ใช้คีย์เฟรมในที่เดียวกัน

หากคุณต้องการทำเช่นนั้นคุณอาจใช้ ffprobe เพื่อรับเวลาเฟรมเวิร์กจากนั้นใช้เชลล์สคริปต์หรือภาษาการเขียนโปรแกรมจริงเพื่อแปลงให้เป็นคำสั่ง ffmpeg

แต่สำหรับเนื้อหาส่วนใหญ่มีความแตกต่างกันเล็กน้อยระหว่างการมีหนึ่งเฟรมหลักทุก 5 วินาทีและสองเฟรมหลักทุก 5 วินาที (หนึ่งถูกบังคับและอีกหนึ่งจาก Scenecut) นี่คือขนาดเฉลี่ยของเฟรม I เทียบกับขนาดของเฟรม P และเฟรม B ถ้าคุณใช้ x264 ด้วยการตั้งค่าทั่วไป (เหตุผลเดียวที่ฉันคิดว่าคุณควรทำทุกอย่างเพื่อส่งผลกระทบต่อสิ่งเหล่านี้คือถ้าคุณตั้งค่า -qmin เป็นวิธีที่ไม่ดีในการป้องกัน x264 จากการใช้บิตเรตกับเนื้อหาง่าย ๆ ฉันคิดว่า) และรับผลลัพธ์เช่นขนาดเฟรมเฉลี่ย 46 kB, P-frame 24 kB, B-frame 17 kB (ครึ่งบ่อยเท่า P-frames) จากนั้นเพิ่ม I-frame ทุกวินาทีที่ 30 เฟรมต่อวินาที เพิ่มขึ้นเพียง 3% ในขนาดไฟล์ ความแตกต่างระหว่าง h264 และ h263 อาจประกอบด้วยการลดลง 3% แต่สิ่งเดียวไม่สำคัญมาก

สำหรับเนื้อหาประเภทอื่นขนาดเฟรมจะแตกต่างกัน เพื่อความเป็นธรรมนี่เป็นเรื่องเกี่ยวกับความซับซ้อนทางโลกและไม่ใช่ความซับซ้อนเชิงพื้นที่ดังนั้นจึงไม่ใช่แค่เนื้อหาที่ง่ายเทียบกับเนื้อหาที่ยาก แต่โดยทั่วไปเว็บไซต์สตรีมวิดีโอจะมีขีด จำกัด บิตเรตและเนื้อหาที่มี I-frames ค่อนข้างใหญ่จะเป็นเนื้อหาที่ง่ายซึ่งจะถูกเข้ารหัสด้วยคุณภาพสูงไม่ว่าจะมีคีย์เฟรมเพิ่มจำนวนเท่าใด มันสิ้นเปลือง แต่ขยะนี้มักจะไม่ถูกสังเกต กรณีที่สิ้นเปลืองมากที่สุดน่าจะเป็นวิดีโอที่เป็นเพียงภาพนิ่งที่มาพร้อมกับเพลงโดยที่แต่ละคีย์เฟรมเหมือนกันทุกประการ

สิ่งหนึ่งที่ฉันไม่แน่ใจว่าเป็นอย่างไรคีย์บังคับเฟรมโต้ตอบกับตัว จำกัด อัตราที่กำหนดด้วย -maxrate และ -bufsize ฉันคิดว่าแม้ YouTube จะมีปัญหาเมื่อเร็ว ๆ นี้การกำหนดการตั้งค่าบัฟเฟอร์อย่างถูกต้องเพื่อให้มีคุณภาพที่สม่ำเสมอ หากคุณเพียงแค่ใช้การตั้งค่าบิตเรตเฉลี่ยที่สามารถเห็นได้ในบางเว็บไซต์ (เนื่องจากคุณสามารถตรวจสอบตัวเลือกของ x264 ในส่วนหัว / mov atom? ด้วยโปรแกรมแก้ไข hex) ดังนั้นรูปแบบบัฟเฟอร์ไม่เป็นปัญหา แต่ถ้าคุณ การให้บริการเนื้อหาที่ผู้ใช้สร้างขึ้นบิตเรตโดยเฉลี่ยสนับสนุนให้ผู้ใช้เพิ่มหน้าจอสีดำในตอนท้ายของวิดีโอ

ตัวเลือก -g ของ Ffmpeg หรือตัวเลือกตัวเข้ารหัสอื่น ๆ ที่คุณใช้นั้นจะถูกจับคู่กับตัวเลือกเฉพาะตัวเข้ารหัส ดังนั้น '-x264-params keyint = GOPSIZE' จึงเท่ากับ '-g GOPSIZE'

ปัญหาหนึ่งในการใช้การตรวจจับฉากคือถ้าคุณต้องการคีย์เฟรมใกล้ตัวเลขที่ระบุด้วยเหตุผลใดก็ตาม หากคุณระบุคีย์เฟรมในทุกๆ 5 วินาทีและใช้การตรวจจับฉากและมีการเปลี่ยนแปลงฉากที่ 4.5 ควรตรวจพบ แต่เฟรมหลักถัดไปจะเป็น 9.5 หากเวลาเพิ่มขึ้นเรื่อย ๆ เช่นนี้คุณสามารถจบลงด้วยคีย์เฟรมที่ 42.5, 47.5, 52.5 ฯลฯ แทน 40, 45, 50, 55 ตรงกันข้ามถ้ามีฉากเปลี่ยนที่ 5.5 ก็จะมี คีย์เฟรมที่ 5 และ 5.5 จะเร็วเกินไปสำหรับอีกเฟรมหนึ่ง Ffmpeg ไม่อนุญาตให้คุณระบุ "สร้างเฟรมหลักที่นี่หากไม่มีการเปลี่ยนแปลงฉากภายใน 30 เฟรมถัดไป" คนที่เข้าใจ C สามารถเพิ่มตัวเลือกนั้นได้

สำหรับวิดีโอที่มีอัตราเฟรมผันแปรเมื่อคุณไม่ได้สตรีมแบบสดเช่น Twitch คุณควรใช้การเปลี่ยนแปลงฉากโดยไม่ต้องแปลงเป็นเฟรมเรทคงที่อย่างถาวร หากคุณใช้ฟิลเตอร์ 'select' ใน ffmpeg และใช้ค่าคงที่ 'scene' ในนิพจน์จากนั้น debug output (-v debug หรือกด '+' หลายครั้งขณะเข้ารหัส) จะแสดงหมายเลขเปลี่ยนฉาก สิ่งนี้อาจแตกต่างจากและไม่มีประโยชน์เท่าจำนวนที่ใช้โดย x264 แต่ก็ยังมีประโยชน์

จากนั้นขั้นตอนอาจจะทำวิดีโอทดสอบสำหรับการเปลี่ยนแปลงเฟรมหลักเท่านั้น แต่อาจใช้สำหรับข้อมูลการควบคุมอัตราหากใช้ 2-pass (ไม่แน่ใจว่าข้อมูลที่สร้างขึ้นมีประโยชน์สำหรับความละเอียดและการตั้งค่าที่แตกต่างกันหรือไม่ข้อมูล macroblock-tree จะไม่ถูกแปลง) เป็นวิดีโอที่มีอัตราเฟรมคงที่ แต่ดูข้อผิดพลาดนี้เกี่ยวกับการพูดติดอ่างเอาต์พุต เพื่อใช้ตัวกรอง fps เพื่อวัตถุประสงค์อื่น เรียกใช้ผ่าน x264 ด้วยการตั้งค่าคีย์เฟรมและ GOP ที่คุณต้องการ

จากนั้นใช้เวลาเฟรมภาพเหล่านี้กับวิดีโออัตราเฟรมตัวแปรดั้งเดิม

หากคุณอนุญาตเนื้อหาที่ผู้ใช้สร้างขึ้นอย่างบ้าคลั่งโดยมีช่องว่าง 20 วินาทีระหว่างเฟรมดังนั้นสำหรับการเข้ารหัสอัตราเฟรมตัวแปรคุณสามารถแยกเอาท์พุทใช้ฟิลเตอร์ fps ใช้ตัวกรองที่เลือก (อาจสร้างนิพจน์ที่ยาวมาก ๆ ทุกครั้งที่คีย์เฟรม) ... หรือบางทีคุณอาจใช้วิดีโอทดสอบเป็นอินพุตและถอดรหัสเฉพาะคีย์เฟรมถ้าตัวเลือก ffmpeg นั้นทำงานหรือใช้ฟิลเตอร์ที่เลือกเพื่อเลือกคีย์เฟรม จากนั้นปรับขนาดให้เป็นขนาดที่ถูกต้อง (แม้จะมีตัวกรอง scale2ref สำหรับเรื่องนี้) และวางทับวิดีโอต้นฉบับไว้บน จากนั้นใช้ฟิลเตอร์ interleave เพื่อรวมคีย์เฟรมหลักแบบบังคับตามที่กำหนดไว้กับวิดีโอต้นฉบับ หากผลลัพธ์ในสองเฟรมที่ห่างกัน 0.001 วินาทีที่ตัวกรอง interleave ไม่ได้ป้องกันให้แก้ไขปัญหานี้ด้วยตัวคุณเองด้วยตัวกรองที่เลือกอีกตัว การจัดการกับข้อ จำกัด ของบัฟเฟอร์เฟรมสำหรับตัวกรอง interleave อาจเป็นปัญหาหลักที่นี่ สิ่งเหล่านี้สามารถใช้งานได้: ใช้ตัวกรองบางชนิดเพื่อบัฟเฟอร์กระแสหนาแน่น (ตัวกรอง Fifo?); อ้างถึงไฟล์อินพุตหลาย ๆ ครั้งดังนั้นจึงถอดรหัสได้มากกว่าหนึ่งครั้งและเฟรมไม่จำเป็นต้องเก็บไว้ ใช้ตัวกรอง 'streamselect' ซึ่งฉันไม่เคยทำในช่วงเวลาของเฟรมหลัก ปรับปรุงตัวกรอง interleave โดยเปลี่ยนพฤติกรรมเริ่มต้นหรือเพิ่มตัวเลือกในการส่งออกเฟรมที่เก่าแก่ที่สุดในบัฟเฟอร์แทนการวางเฟรม ซึ่งฉันไม่เคยทำในช่วงเวลาของเฟรมหลัก; ปรับปรุงตัวกรอง interleave โดยเปลี่ยนพฤติกรรมเริ่มต้นหรือเพิ่มตัวเลือกในการส่งออกเฟรมที่เก่าแก่ที่สุดในบัฟเฟอร์แทนการวางเฟรม ซึ่งฉันไม่เคยทำในช่วงเวลาของเฟรมหลัก; ปรับปรุงตัวกรอง interleave โดยเปลี่ยนพฤติกรรมเริ่มต้นหรือเพิ่มตัวเลือกในการส่งออกเฟรมที่เก่าแก่ที่สุดในบัฟเฟอร์แทนการวางเฟรม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.