กลับไปที่บล็อก
13 สิงหาคม 2569Sergei Solod31 นาทีในการอ่าน

วิธีแปลง WebP แบบเคลื่อนไหว, GIF และ APNG เป็น H.264 MP4 โดยไม่ทำให้เฟรมหรือเวลาเสีย

กระบวนการใช้งานจริงของผมสร้างเฟรมเต็มที่ผู้ใช้เห็นจริงขึ้นใหม่ รักษาเวลาเดิม เลือก CFR หนึ่งค่าต่อ MP4 สุดท้าย ใช้แคนวาสร่วมที่เล็กที่สุดโดยไม่ขยายภาพ เข้ารหัสเซกเมนต์ H.264 ที่เข้ากันได้ ต่อเข้าด้วยกันโดยไม่เข้ารหัสแบบสูญเสียรอบสอง และตรวจทั้งไฟล์กับการส่งผ่าน HTTP ในผลที่วัดจริงหนึ่งครั้ง WebP แบบเคลื่อนไหว 217 ไฟล์รวม 1.49 GB กลายเป็น H.264 MP4 ขนาด 78.49 MB หนึ่งไฟล์

H.264FFmpegMP4WebP แบบเคลื่อนไหวGIFAPNGการบีบอัดวิดีโอการประมวลผลสื่อ

ผมไม่ได้สร้างกระบวนการนี้ขึ้นมาเพื่อทดลองตัวแปลงสัญญาณหลายแบบ แต่สร้างเพราะภาพเคลื่อนไหวกลายเป็นวิธีที่แพงในการส่งสิ่งที่ในทางปฏิบัติก็คือวิดีโอสั้นแบบไม่มีเสียง

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

ส่วนที่ยากไม่ใช่การเรียก FFmpeg ภาพเคลื่อนไหวไม่ได้รับประกันว่าจะเป็นชุดภาพเต็มขนาดที่เรียงกันด้วยอัตราเฟรมคงที่ มันอาจมีสี่เหลี่ยมย่อย กฎการผสมและการล้างเฟรม ช่องอัลฟา ช่วงหน่วงที่ไม่สม่ำเสมอ เฟรมที่มีระยะเวลาเป็นศูนย์ ทิศทางภาพต่างกัน และข้อมูลเวลาที่เครื่องมือตรวจทั่วไปอาจสรุปได้อย่างทำให้เข้าใจผิด

ผมจึงมองการแปลงเป็นชุดข้อกำหนดที่ต้องรักษาไว้ทุกขั้น ไม่ใช่เพียงคำสั่งเดียว:

WebP แบบเคลื่อนไหว / GIF / APNG
        ↓
สร้างสถานะแคนวาสเต็มที่ผู้ใช้เห็นจริง
        ↓
กู้และปรับเวลาเดิมให้ถูกต้อง
        ↓
วิเคราะห์แหล่งทั้งหมดในลำดับสุดท้าย
        ↓
เลือก CFR หนึ่งค่าให้ MP4 สุดท้าย
        ↓
คำนวณแคนวาสร่วมที่เล็กที่สุดโดยไม่ขยายภาพ
        ↓
เข้ารหัสส่วน H.264 ที่เข้ากันได้
        ↓
ตรวจสัญญาของสตรีม
        ↓
ต่อด้วยการคัดลอกสตรีม
        ↓
ปรับและตรวจเส้นเวลาแพ็กเก็ต
        ↓
ตรวจการส่งผ่าน HTTP
        ↓
เผยแพร่โดยสลับไฟล์ในขั้นตอนเดียว

ตัวแปลงสัญญาณมีความสำคัญ แต่การรักษาว่าแอนิเมชันเดิมแสดงอะไรจริง ๆ สำคัญกว่า

ผลจริงที่วัดได้: WebP แบบเคลื่อนไหว 217 ไฟล์กลายเป็น MP4 ขนาด 78.49 MB หนึ่งไฟล์

ข้อมูลนำเข้า ไม่ใช่วิดีโอไฟล์เดียวขนาด 1.49 GB แต่เป็น WebP แบบเคลื่อนไหวแยกกัน 217 ไฟล์ มีเฟรมที่แสดงจริงรวม 10,633 เฟรม และมีขนาดรวมประมาณ 1.49 GB

ข้อมูลนำเข้า
WebP แบบเคลื่อนไหว 217 ไฟล์
รวม 1.49 GB
10,633 เฟรมที่แสดงจริง

ผลลัพธ์
H.264 MP4 1 ไฟล์
78.49 MB
0.98 Mbps
1264×720
30 fps CFR
Main@3.1 / CRF 28 / veryslow

ไฟล์ H.264 ที่ได้มีขนาด 78.49 MB ที่อัตราบิตประมาณ 0.98 Mbps เมื่อเทียบกับไบต์รวมของแอนิเมชันต้นฉบับ ผลลัพธ์เล็กลงประมาณ 19 เท่า หรือใช้ข้อมูลน้อยลงประมาณ 94.7%

นี่คือผลที่วัดจากกระบวนการตั้งแต่ต้นจนจบ ไม่ใช่การทดสอบ A/B แบบตรงไปตรงมาระหว่าง “H.264 เก่า” กับ “H.264 ใหม่” เพราะรูปแบบการแทนข้อมูลเปลี่ยนจากภาพเคลื่อนไหวหลายร้อยไฟล์เป็นวิดีโอเดียวที่ใช้การบีบอัดตามเวลา ผมจึงไม่ยกผลต่าง 19 เท่าทั้งหมดให้ CRF 28, veryslow หรือค่าตัวเข้ารหัสเพียงค่าเดียว

ขั้นแรกต้องสร้างภาพเต็มที่ผู้ชมเห็นจริง

ทางลัดที่อันตรายที่สุดคือสมมติว่าเฟรมทุกเฟรมที่เก็บอยู่ในไฟล์แอนิเมชันเป็นภาพเต็มที่แทนภาพก่อนหน้าได้ทั้งหมด

เฟรมของ WebP แบบเคลื่อนไหวสามารถระบุสี่เหลี่ยมในตำแหน่งหนึ่งพร้อมพฤติกรรมการผสมและการล้างได้ APNG มีออฟเซ็ต ขนาด ระยะหน่วง การล้าง และการผสม ส่วน GIF ก็สามารถคงแคนวาสเดิม ล้างบางบริเวณ หรือคืนสถานะก่อนหน้าได้

ดังนั้นเฟรมที่เก็บไว้อาจเป็นเพียงชิ้นส่วนเล็ก ๆ ที่ต้องอาศัยแคนวาสจากเฟรมก่อนหน้า หากนำชิ้นส่วนเหล่านี้ไปเข้ารหัสเหมือนเป็นภาพเต็ม ผลที่ได้ไม่ใช่แอนิเมชันเดิมที่เล็กลง แต่เป็นแอนิเมชันที่ผิด

หน่วยที่ผมดึงออกมาคือ สถานะแคนวาสเต็มที่แสดงจริง ซึ่งก็คือพิกเซลที่ประกอบเสร็จแล้วทั้งหมดหลังใช้กฎการล้างของเฟรมก่อนหน้าและกฎการผสมของเฟรมปัจจุบัน

นี่คือเงื่อนไขความถูกต้องข้อแรกของกระบวนการ หากเฟรมย่อยที่ผิดถูกทำให้แบนลงใน H.264 แล้ว ค่า CRF, พรีเซ็ต หรือการรวมสตรีมภายหลังไม่สามารถซ่อมได้

เวลาเฟรมคือข้อมูลจากต้นฉบับ ไม่ใช่ค่า FPS ที่เดาเอา

รูปแบบแอนิเมชันเก็บเวลาไม่เหมือนกัน WebP แบบเคลื่อนไหวเก็บระยะเวลาของแต่ละเฟรมเป็นหน่วย 1 ms, GIF เก็บระยะหน่วงเป็นหนึ่งในร้อยวินาที ส่วน APNG เก็บตัวเศษและตัวส่วนของระยะหน่วงต่อเฟรม และหากตัวส่วนเป็นศูนย์ ข้อกำหนด PNG ให้ถือเป็น 100

ค่าหน่วงเหล่านี้ต่างหากคือเส้นเวลาจริง ค่า FPS ที่เครื่องมือตรวจทั่วไปแสดงเป็นเพียงค่ารวมและอาจทำให้เข้าใจผิดได้

WebP จริงหนึ่งไฟล์ในกระบวนการของผมมีขนาด 1264×720 และ 49 เฟรมที่แสดงจริง ระยะหน่วงสลับระหว่าง 62 และ 63 ms รวมเป็น 3.063 วินาที ซึ่งโดยพฤติกรรมคือจังหวะประมาณ 16 fps เพราะหนึ่งเฟรมที่ 16 fps มีระยะ 62.5 ms

แต่เครื่องมือตรวจทั่วไปกลับรายงานต้นฉบับนี้เป็น 25 fps ถ้าเชื่อตัวเลขนั้น ผมจะเปลี่ยนเวลาของต้นฉบับหรือสร้างเฟรมซ้ำที่ไม่จำเป็น

ผมยังต้องมีนโยบายสำหรับระยะหน่วงที่เสียหรือกำกวม WebP ปล่อยการตีความระยะเฟรมเป็นศูนย์ และมักรวมถึงค่าที่สั้นมาก ให้ขึ้นกับการนำไปใช้จริง GIF อาจมีระยะหน่วงเป็นศูนย์ และ APNG อนุญาตตัวเศษเป็นศูนย์ ซึ่งหมายถึงให้แสดงเฟรมถัดไปเร็วที่สุดเท่าที่ทำได้ แม้ตัวแสดงอาจกำหนดค่าต่ำสุดในทางปฏิบัติ

นโยบายของผมรักษาเวลาไว้ที่ความละเอียดมิลลิวินาที ใช้ขั้นต่ำ 10 ms สำหรับระยะที่เป็นศูนย์หรือสั้นผิดปกติ และใช้ 100 ms เป็นค่าทดแทนเฉพาะเมื่อไม่มีข้อมูลเวลาที่ใช้ได้จริง ตัวเลขเหล่านี้เป็นนโยบายของผม ไม่ใช่มาตรฐานสากล

เลือก CFR หนึ่งค่าให้ MP4 ทั้งไฟล์ แทนการบังคับ 30 fps

เมื่อสร้างสถานะภาพและระยะเวลาได้แล้ว ผมแมปเส้นเวลาต้นฉบับเข้าสู่เส้นเวลาวิดีโอ โดยไม่เข้ารหัสทุกอย่างที่ 30 fps แบบตาบอด

สำหรับต้นฉบับทุกตัวที่จะอยู่ใน MP4 สุดท้ายเดียวกัน ผมประเมินชุดตัวเลือกเล็ก ๆ นี้:

10, 12, 15, 16, 18, 20, 24, 25, 30 fps

ตัวเลือกจะเลือกระดับ CFR ต่ำสุดที่ยังแทนลำดับสุดท้ายทั้งหมดได้ดีพอ MP4 คนละไฟล์เลือกอัตราต่างกันได้ แต่ทุกเซกเมนต์ที่เข้ารหัสแยกกันภายใน MP4 เดียวต้องใช้ CFR เดียวกัน

ตัวอย่าง 3.063 วินาทีเห็นความต่างชัดเจน ที่ 16 fps ต้องมีประมาณ 49 เฟรม ขณะที่ 30 fps ต้องมีประมาณ 92 เฟรม หากต้นฉบับตัวอื่นใน MP4 เดียวกันต้องการ 30 fps จริง ๆ ทั้งชุดจะใช้ 30 fps ผมไม่ผสมอัตราเฟรมของเซกเมนต์ภายในสตรีมสุดท้ายเดียวกัน

ผมใช้มาตราเวลา 90,000 Hz สำหรับแทร็กวิดีโอ เพราะ CFR ทุกค่าที่อนุญาตให้ระยะเฟรมเป็นจำนวนเต็มของติ๊กได้พอดี:

10 fps → 9000 ticks
12 fps → 7500 ticks
15 fps → 6000 ticks
16 fps → 5625 ticks
18 fps → 5000 ticks
20 fps → 4500 ticks
24 fps → 3750 ticks
25 fps → 3600 ticks
30 fps → 3000 ticks

มาตราเวลาของแทร็กวิดีโอนี้เป็นตัวกำหนดกริดเฟรมที่แน่นอน ผมตั้งมาตราเวลารวมของ MP4 เป็น 90,000 ด้วยเพื่อความสอดคล้อง แต่เป็นนาฬิกาคนละส่วนของคอนเทนเนอร์ ตัวตรวจสอบจึงตรวจแพ็กเก็ตวิดีโอกับกริดจำนวนเต็มโดยตรง ไม่อาศัยระยะทศนิยมที่ถูกปัด

ขีดจำกัดความละเอียดคือเพดาน ไม่ใช่ขนาดแคนวาสที่ต้องใช้เสมอ

เพดานการส่งของผมประมาณ 1280×720 สำหรับแนวนอน, 720×1280 สำหรับแนวตั้ง และสำหรับเนื้อหาที่มีหลายทิศทาง ทั้งความกว้างและความสูงต้องไม่เกิน 960

กฎที่ห้ามต่อรองคือ ไม่ขยายภาพ ต้นฉบับ 900×600 ไม่ได้มีรายละเอียดเพิ่มเมื่อทำเป็น 1280×720 มีเพียงพิกเซลที่คำนวณแทรกเพิ่มขึ้นและตัวเข้ารหัสต้องอธิบายพิกเซลเหล่านั้น

กฎที่สองสำคัญและมองข้ามง่าย: 960×960 เป็นเพียงกรอบสูงสุด ไม่ใช่แคนวาสสี่เหลี่ยมบังคับ

ผมคำนวณขนาดส่วนที่ใช้งานของต้นฉบับแต่ละตัวด้วยการลดขนาดเท่านั้นก่อน จากนั้นลำดับสุดท้ายใช้แคนวาสร่วมขนาดเลขคู่ที่เล็กที่สุดซึ่งใส่สี่เหลี่ยมส่วนที่ใช้งานที่ปรับขนาดแล้วทั้งหมดได้

ตัวอย่าง หากลำดับสุดท้ายต้องใช้ภาพแนวนอน 960×540 และแนวตั้ง 500×900 แคนวาสร่วมสามารถเป็น 960×900 ไม่จำเป็นต้อง 960×960 ทุกเซกเมนต์ยังมีขนาดที่เข้ารหัสเท่ากัน จึงต่อด้วยการคัดลอกสตรีมได้ แต่ไม่ต้องเข้ารหัสพื้นที่สีดำที่ไม่มีประโยชน์

ผมรักษาอัตราส่วนภาพและเติมพื้นที่เหลือแทนการยืดภาพ ในกระบวนการนี้พื้นที่เติมเป็นสีดำ และเพราะ H.264/yuv420p ปกติไม่เก็บช่องอัลฟาของต้นฉบับ ความโปร่งใสจึงถูกผสานลงบนพื้นหลังนี้อย่างตั้งใจ ไม่ใช่หายไปโดยบังเอิญ

ทำไม H.264 MP4 จึงเหมาะกับปัญหาการส่งนี้

GIF, APNG และ WebP แบบเคลื่อนไหวไม่ใช่รูปแบบดั้งเดิมแบบง่าย ๆ มันสามารถเลี่ยงการวาดพื้นที่เดิมซ้ำได้ ดังนั้นคำว่า “วิดีโอเล็กกว่าเสมอ” จึงไม่จริง

แต่ H.264 ถูกออกแบบมาสำหรับการคาดการณ์ตามเวลาระหว่างภาพ วนซ้ำแบบภาพวาดสั้น ๆ ที่พื้นหลังคงที่และมีพื้นที่เล็ก ๆ เคลื่อนไหวเหมาะกับภาพอ้างอิง การคาดการณ์ระหว่างเฟรม และเฟรม P/B มาก

คำแนะนำ Safari ปัจจุบันของ Apple แนะนำ MP4 ที่เข้ารหัสด้วย H.264 สำหรับวิดีโอคงที่ และระบุว่า GIF แบบเคลื่อนไหวอาจใช้แบนด์วิดท์สูงถึง 12 เท่าและพลังงานราว 2 เท่าของตัวแปลงสัญญาณวิดีโอสมัยใหม่ ตัวเลข 12× เป็นตัวอย่างของ Apple ไม่ใช่ผลการวัดของผม

ดังนั้นผลจริง 19× ของผมเป็นข้อสังเกตจากการใช้งานจริงที่มีประโยชน์ แต่ผมยังวัดแต่ละกรณีโดยตรง และไม่สมมติว่า WebP แบบเคลื่อนไหวทุกไฟล์ที่เล็กและปรับให้เหมาะแล้วจะต้องแพ้ MP4

แต่ละแอนิเมชันถูกเข้ารหัสเป็นเซกเมนต์ภายใต้ข้อกำหนดสตรีมเดียวกัน

เมื่อถึงขั้นตัวเข้ารหัส กระบวนการรู้อยู่แล้วว่าเฟรมที่แสดงจริงคืออะไร CFR ของทั้งชุดเป็นเท่าใด แคนวาสสุดท้ายมีขนาดเท่าไร และระยะเวลาที่คาดไว้คือเท่าใด

ส่วนกลางของคำสั่งเข้ารหัสเซกเมนต์มีลักษณะประมาณนี้:

ffmpeg -framerate "$COLLECTION_FPS" -i frame-%06d.png \
  -c:v libx264 \
  -preset veryslow \
  -tune animation \
  -crf 28 \
  -profile:v main \
  -level:v 3.1 \
  -pix_fmt yuv420p \
  -tag:v avc1 \
  -refs 4 \
  -bf 5 \
  -g "$GOP_FRAMES" \
  -maxrate:v 4M \
  -bufsize:v 8M \
  -x264-params "stitchable=1:open-gop=0:b-pyramid=normal:nal-hrd=none" \
  -color_range tv \
  -color_primaries bt709 \
  -color_trc bt709 \
  -colorspace bt709 \
  -fps_mode passthrough \
  -map_metadata -1 \
  -map_chapters -1 \
  -an -sn -dn \
  -video_track_timescale 90000 \
  -movie_timescale 90000 \
  -t "$EXPECTED_DURATION" \
  segment.mp4

ขีดจำกัด GOP อยู่ที่ประมาณห้าวินาทีตาม CFR ที่เลือก: 80 เฟรมที่ 16 fps, 120 ที่ 24 fps และ 150 ที่ 30 fps

-t "$EXPECTED_DURATION" ไม่ได้มีไว้ประดับ ในรายการเฟรมของผม ภาพสุดท้ายถูกทำซ้ำเป็นตัวชี้จุดจบเพื่อให้ระยะเวลาของเฟรมจริงก่อนหน้าถูกใช้ หากไม่มีขีดจำกัดระยะเวลาที่ชัดเจน ตัวชี้จุดจบอาจกลายเป็นตัวอย่างปลายทางเพิ่มอีกหนึ่งรายการ

ผมทำซ้ำกรณีนี้ได้กับไฟล์ 49 เฟรมยาว 3.063 วินาที หากไม่มี -t จะได้ 50 เฟรมที่ 16 fps และ 94 เฟรมที่ 30 fps เมื่อใช้ -t 3.063 จะกลับมาเป็นค่าที่ตั้งใจคือ 49 เฟรมที่ 16 fps และ 92 เฟรมที่ 30 fps

การต่อด้วยการคัดลอกสตรีมปลอดภัยก็ต่อเมื่อผ่านการตรวจความเข้ากันได้อย่างเข้มงวด

ตัวแยกสัญญาณสำหรับการต่อของ FFmpeg คาดว่าไฟล์ต่าง ๆ จะมีสตรีมชนิดเดียวกัน รวมทั้งตัวแปลงสัญญาณและฐานเวลา และใช้ระยะเวลาของแต่ละไฟล์เพื่อวางไฟล์ถัดไป ดังนั้นเมทาดาทาระยะเวลาที่ผิดจึงทำให้เส้นเวลาบิดเบือนได้

ผมไม่ใช้ขั้นตอนการต่อเพื่อทำให้ไฟล์ที่เข้ากันไม่ได้กลายเป็นไฟล์ที่เข้ากันได้ เซกเมนต์ต้องผ่านข้อกำหนดทั้งหมดก่อนจึงจะยอมรับ:

CFR ของทั้งชุด = เหมือนกัน
ฐานเวลาของสตรีม = เหมือนกัน
มาตราเวลาของแทร็กวิดีโอ MP4 = เหมือนกัน
ขนาดแคนวาส / SAR = เหมือนกัน
โปรไฟล์ / ระดับ / รูปแบบพิกเซล = เหมือนกัน
การระบุสี = เหมือนกัน
avcC / ข้อมูลเสริม AVC = เหมือนกันทุกไบต์

ผมใช้ stitchable=1 ของ x264 เพราะเซกเมนต์ถูกเข้ารหัสแยกกัน แต่ไม่ถือว่าตัวเลือกนี้พิสูจน์ว่าการตั้งค่า AVC ตรงกัน ผมยังเปรียบเทียบไบต์ของการตั้งค่าจริงก่อนต่อ

เมื่อข้อกำหนดครบถ้วน การต่อสุดท้ายไม่ต้องเพิ่มการบีบอัดแบบสูญเสียอีกรุ่นหนึ่งในระดับบิตสตรีมวิดีโอ:

ffmpeg -f concat -safe 0 -i segments.ffconcat \
  -c:v copy \
  -an -sn -dn \
  -movflags +faststart \
  final.mp4

-c:v copy ป้องกันไม่ให้เซกเมนต์ H.264 ที่เข้ารหัสแล้วถูกถอดรหัสและบีบอัดซ้ำอีกครั้ง

การตรวจสอบครอบคลุมทั้งไฟล์ MP4 และวิธีส่งจริงผ่านเครือข่าย

ผมไม่เผยแพร่ไฟล์เพียงเพราะ FFmpeg จบด้วยรหัส 0

ตัวตรวจสอบเคยจับความผิดพลาดด้านเวลาที่เกิดซ้ำอย่างแน่นอนได้จริง: ที่ 16 fps พบ 5580 ติ๊กแทน 5625 ที่ข้อกำหนดต้องการ และภายหลังผลลัพธ์ 24 fps มี 3751 แทน 3750 พอดี เรื่องความคลาดเคลื่อนหนึ่งติ๊กเป็นหัวข้ออีกบทความหนึ่ง บทเรียนตรงนี้คือการรันการเข้ารหัสเดิมซ้ำไม่แก้ข้อผิดพลาดเส้นเวลาที่กำหนดตายตัว

สำหรับตัวไฟล์ ผมตรวจจำนวนสตรีมที่คาดไว้ โปรไฟล์/ระดับ H.264 รูปแบบพิกเซล ขนาดที่วางแผนไว้อย่างแม่นยำ SAR การระบุสี มาตราเวลา 90 kHz ของแทร็กวิดีโอ ระยะเวลาแพ็กเก็ต จำนวนเฟรม/แพ็กเก็ต ระยะเวลารวม ความสัมพันธ์ PTS/DTS การตั้งค่า AVC ที่เหมือนกันระหว่างเซกเมนต์ การที่ moov อยู่ก่อน mdat และการถอดรหัสทั้งไฟล์พร้อมการจัดการข้อผิดพลาดแบบเข้มงวด

ffprobe -v error \
  -select_streams v:0 \
  -show_streams \
  -show_packets \
  -of json \
  final.mp4

ffmpeg -v error -xerror -err_detect explode \
  -i final.mp4 -f null -

แต่ MP4 ที่ถูกต้องบนเครื่องยังอาจถูกส่งผิดผ่านเว็บได้ ผมจึงตรวจเส้นทาง HTTP ด้วย: Content-Type ตามที่คาดไว้, Content-Length ที่ถูกต้อง, การรองรับคำขอแบบช่วงไบต์, การตอบกลับ 206 Partial Content ที่ถูกต้อง และ Content-Range ที่ถูกต้อง

เมื่อเปลี่ยนข้อกำหนดตัวเข้ารหัส ผมไม่ถือ ffprobe เป็นหลักฐานว่าฮาร์ดแวร์ทุกชนิดเข้ากันได้ แต่รันการทดสอบขนาดเล็กบนอุปกรณ์และเบราว์เซอร์จริงด้วย ผมทดสอบเริ่มเล่น เลื่อนไปตำแหน่ง วนซ้ำ สลับไปพื้นหลังแล้วกลับมา และเล่นแบบช่วงบน iPhone/Safari รุ่นปัจจุบัน อุปกรณ์ Android ระดับทั่วไป และเบราว์เซอร์เดสก์ท็อปหลัก

ไฟล์และเส้นทางการส่งต้องผ่านข้อกำหนดทั้งคู่ก่อนที่ผมจะสลับไฟล์ที่ใช้งานจริงในขั้นตอนเดียว

ข้อมูลที่กระบวนการนี้ตั้งใจยอมเสีย

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

ผมไม่ใช้กระบวนการนี้เมื่อจำเป็นต้องรักษาความโปร่งใสเพื่อประกอบภาพบนพื้นหลังใดก็ได้ เมื่อเวลาต่อเฟรมที่ไม่สม่ำเสมออย่างแม่นยำมีความหมายต่อเนื้อหา เมื่อสร้างต้นฉบับสำหรับเก็บถาวร หรือเมื่อแอปพลิเคชันมีระบบวิดีโอหลายตัวแปลงสัญญาณแบบปรับตัวที่แก้ปัญหาการส่งในอีกแบบอยู่แล้ว

สำหรับ WebP แบบเคลื่อนไหวที่เล็กและปรับให้เหมาะมากอยู่แล้ว ผมยังวัดโดยตรงแทนการสมมติว่า MP4 ต้องชนะ

ลำดับการใช้งานจริงที่ผมใช้ตอนนี้

  1. ตรวจหารูปแบบที่มีการเคลื่อนไหวและอ่านเมทาดาทาควบคุมเฟรมจริง
  2. สร้างสถานะแคนวาสเต็มที่แสดงจริงขึ้นใหม่ตามความหมายของการผสมและการล้างของรูปแบบ
  3. กู้คืนระยะเวลาของแต่ละเฟรมและแก้ค่าที่ไม่ถูกต้อง
  4. สร้างเส้นเวลาต้นฉบับที่เชื่อถือได้ด้วยความละเอียดระดับมิลลิวินาที
  5. วิเคราะห์ต้นฉบับทุกตัวที่จะอยู่ใน MP4 สุดท้ายเดียวกัน
  6. เลือก CFR หนึ่งค่าร่วมกันทั้งชุดจาก 10/12/15/16/18/20/24/25/30
  7. แมปสถานะที่แสดงจริงลงบนเส้นเวลา CFR ที่เลือก
  8. คำนวณขนาดส่วนที่ใช้งานด้วยการลดขนาดเท่านั้น ไม่ขยายภาพ
  9. สร้างแคนวาสร่วมขนาดเลขคู่ที่เล็กที่สุดซึ่งลำดับสุดท้ายต้องการ
  10. เติมพื้นที่โดยไม่ยืดภาพ และผสานช่องอัลฟาลงพื้นหลังอย่างตั้งใจ
  11. เข้ารหัสต้นฉบับแต่ละตัวเป็น H.264 Main@3.1 / yuv420p / avc1 ภายใต้ข้อกำหนดสตรีมเดียวกัน
  12. จำกัดแต่ละเซกเมนต์ด้วยระยะเวลาที่คาดไว้
  13. ปฏิเสธเซกเมนต์ที่การตั้งค่า AVC จริงหรือเวลาไม่ผ่านข้อกำหนด
  14. ต่อเซกเมนต์ที่ยอมรับแล้วด้วย -c:v copy
  15. ปรับและตรวจสอบเส้นเวลาแพ็กเก็ตสุดท้าย
  16. ถอดรหัสผลลัพธ์ทั้งไฟล์
  17. ตรวจสอบส่วนหัว HTTP ช่วงไบต์ และพฤติกรรมของเนื้อหาแบบบางส่วน
  18. รันทดสอบบนอุปกรณ์/เบราว์เซอร์หลังเปลี่ยนโปรไฟล์ตัวเข้ารหัส
  19. เผยแพร่โดยสลับไฟล์ในขั้นตอนเดียวเมื่อการตรวจทั้งหมดผ่านแล้วเท่านั้น

เส้นเวลา ไม่ใช่นามสกุลไฟล์ คือแหล่งอ้างอิงจริง

WebP แบบเคลื่อนไหว, GIF หรือ APNG ไม่ใช่เพียงโฟลเดอร์ของรูปภาพ แต่เป็นลำดับตามเวลาของสถานะแคนวาสเต็มที่แสดงจริง

H.264 ใช้ความซ้ำซ้อนตามเวลาได้ดีมาก แต่ซ่อมการประกอบภาพที่ผิด เวลาที่แต่งขึ้น หรือเมทาดาทาเซกเมนต์ที่เข้ากันไม่ได้ไม่ได้ งานวิศวกรรมส่วนใหญ่ที่ทำให้กระบวนการนี้เชื่อถือได้เกิดก่อนและหลัง x264

บทเรียนที่ผมเก็บไว้คือ เปลี่ยนรูปแบบการแทนข้อมูลก็ต่อเมื่ออธิบายได้อย่างแม่นยำว่าอะไรต้องคงเดิม

เอกสารหลัก