เกินโควต้าการบัฟเฟอร์

โจ เมดเลย์
โจ้ เมดเลย์

หากคุณทำงานกับส่วนขยายแหล่งที่มาของสื่อ (MSE) สิ่งหนึ่งที่คุณจะต้องจัดการในท้ายที่สุดคือบัฟเฟอร์ที่มากเกินไป เมื่อเกิดเหตุการณ์นี้ คุณจะได้รับสิ่งที่เรียกว่า QuotaExceededError ในบทความนี้ ผมจะพูดถึงบางวิธี ในการจัดการปัญหานี้

QuotaExceededError คืออะไร

โดยทั่วไปแล้ว QuotaExceededError คือสิ่งที่คุณจะได้รับหากพยายามเพิ่มข้อมูลมากเกินไปลงในออบเจ็กต์ SourceBuffer (การเพิ่มออบเจ็กต์ SourceBuffer ในองค์ประกอบ MediaSource ระดับบนสุดอาจทำให้เกิดข้อผิดพลาดนี้ได้เช่นกัน ซึ่งอยู่นอกเหนือขอบเขตของบทความนี้) หาก SourceBuffer มีข้อมูลมากเกินไป การเรียกใช้ SourceBuffer.appendBuffer() จะทริกเกอร์ข้อความต่อไปนี้ในหน้าต่างคอนโซลของ Chrome

ข้อผิดพลาดในคอนโซลโควต้า

มี 2-3 อย่างที่ควรทราบเกี่ยวกับเรื่องนี้ ขั้นแรก โปรดทราบว่าชื่อ QuotaExceededError จะไม่ปรากฏในข้อความ หากต้องการดูจุดนี้ ให้กำหนดเบรกพอยท์ ณ ตำแหน่งที่คุณสามารถตรวจจับข้อผิดพลาดและตรวจสอบใน นาฬิกาหรือหน้าต่างขอบเขตได้ เราแสดงไว้ด้านล่างนี้

หน้าต่างการดูโควต้า

ประการที่ 2 ไม่มีวิธีที่แน่นอนในการค้นหาปริมาณข้อมูลที่ SourceBuffer จะจัดการได้

ลักษณะการทำงานในเบราว์เซอร์อื่น

ตอนที่เขียน Safari ไม่ได้ใช้ QuotaExceededError ในบิวด์หลายๆ รุ่น แต่จะนำเฟรมออกโดยใช้อัลกอริทึมแบบ 2 ขั้นตอนแทน และจะหยุดเมื่อมีพื้นที่เพียงพอที่จะจัดการ appendBuffer() ข้อแรก จะทำให้เฟรมว่างระหว่าง 0 ถึง 30 วินาทีก่อนเวลาปัจจุบันในช่วงเวลา 30 วินาที จากนั้นจะปล่อยเฟรมจากระยะเวลา 30 วินาทีจากระยะเวลาย้อนกลับไปจนถึง 30 วินาทีหลังจาก currentTime คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ใน Webkit Changeset จากปี 2014

อย่างไรก็ตาม นอกจาก Chrome, Edge และ Firefox จะพบข้อผิดพลาดนี้แล้ว หากใช้เบราว์เซอร์อื่น คุณจะต้องทำการทดสอบด้วยตนเอง แม้ว่าอาจไม่ใช่สิ่งที่คุณสร้างสำหรับโปรแกรมเล่นสื่อในชีวิตจริง แต่การทดสอบขีดจำกัดบัฟเฟอร์ต้นทางของ François Beaufort จะช่วยให้คุณสังเกตพฤติกรรมได้

ฉันสามารถเพิ่มข้อมูลได้มากน้อยแค่ไหน

ตัวเลขที่แน่นอนจะแตกต่างกันไปตามแต่ละเบราว์เซอร์ เนื่องจากคุณไม่สามารถค้นหาจำนวน ข้อมูลที่ต่อท้ายในปัจจุบันได้ คุณจะต้องติดตามจำนวนเงินที่เพิ่ม เองด้วย สำหรับข้อมูลที่จะดู นี่เป็นข้อมูลที่ดีที่สุด ที่เราสามารถรวบรวมได้ตอนที่เขียน สำหรับ Chrome ตัวเลขเหล่านี้เป็นขีดจำกัดสูงสุด หมายความว่าตัวเลขจะน้อยลงเมื่อระบบพบปริมาณหน่วยความจำ

Chrome Chromecast* Firefox Safari Edge
วิดีโอ 150MB 30MB 100 MB 290MB ไม่ทราบ
เสียง 12MB 2MB 15 MB 14MB ไม่ทราบ
  • หรืออุปกรณ์ Chrome ที่มีหน่วยความจำจำกัดอื่นๆ

แล้วฉันต้องทำอย่างไร

เนื่องจากปริมาณข้อมูลที่รองรับมีความแตกต่างกันมาก คุณจึงไม่เห็นจำนวนข้อมูลใน SourceBuffer คุณจึงต้องรับข้อมูลโดยอ้อมโดยการจัดการ QuotaExceededError มาดูวิธีทำกันเลย

วิธีการจัดการกับ QuotaExceededError มีอยู่หลายวิธี ในความเป็นจริงการใช้หลายๆ วิธีรวมกันจะดีที่สุด วิธีการของคุณควรอิงตามจำนวนที่คุณดึงข้อมูลและพยายามเพิ่มต่อท้าย HTMLMediaElement.currentTime และปรับขนาดตาม QuotaExceededError นอกจากนี้ การใช้ไฟล์ Manifest บางประเภท เช่น ไฟล์ mpd (MPEG-DASH) หรือไฟล์ m3u8 (HLS) จะช่วยให้คุณติดตามข้อมูลที่คุณเพิ่มลงในบัฟเฟอร์ได้

ตอนนี้เรามาดูวิธีต่างๆ ในการจัดการกับ QuotaExceededError กัน

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

แม้ว่าจะใช้ผสมกันได้ แต่เราจะบดบังผลิตภัณฑ์ทีละรายการ

นำข้อมูลที่ไม่จำเป็นออกแล้วเพิ่มกลับเข้าไปใหม่

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

การนำข้อมูลล่าสุดออกไม่ใช่เรื่องง่ายเหมือนการโทรหา SourceBuffer.remove() หากต้องการนำข้อมูลออกจาก SourceBuffer แฟล็กการอัปเดตนั้นต้องเป็น "เท็จ" หากไม่ใช่ ให้เรียกใช้ SourceBuffer.abort() ก่อนที่จะนำข้อมูลออก

สิ่งที่ควรคำนึงถึงเมื่อโทรหา SourceBuffer.remove() มีดังนี้

  • วิธีนี้อาจส่งผลเสียต่อการเล่น ตัวอย่างเช่น หากคุณต้องการให้วิดีโอเล่นซ้ำหรือเล่นวนซ้ำในเร็วๆ นี้ คุณอาจไม่ต้องการลบช่วงต้นของวิดีโอ ในทำนองเดียวกัน หากคุณหรือผู้ใช้ค้นหาส่วนของวิดีโอที่นำข้อมูลออก คุณจะต้องต่อข้อมูลดังกล่าวอีกครั้งเพื่อตอบสนองความต้องการดังกล่าว
  • โปรดนำออกอย่างระมัดระวังที่สุดเท่าที่จะทำได้ โปรดระวังการนำกลุ่มเฟรมที่กำลังเล่นอยู่ออก ซึ่งเริ่มต้นจากคีย์เฟรม ณ หรือก่อน currentTime เนื่องจากการทำเช่นนั้นอาจทำให้การเล่นค้าง เว็บแอปอาจต้องแยกวิเคราะห์ข้อมูลดังกล่าวออกจากไบท์สตรีม หากไม่มีอยู่ในไฟล์ Manifest ไฟล์ Manifest ของสื่อหรือความรู้เกี่ยวกับช่วงคีย์เฟรมในสื่อจะช่วยแนะแนวทางในการเลือกช่วงการนำออกของแอปเพื่อป้องกันไม่ให้มีการนำสื่อที่กำลังเล่นอยู่ออก ไม่ว่าคุณจะนำภาพใดออก อย่านำกลุ่มภาพที่กำลังเล่นอยู่ออก หรือแม้แต่รูปแรกๆ ไม่กี่รูป โดยทั่วไป อย่านำเวลาปัจจุบันออก เว้นแต่คุณแน่ใจว่าไม่จำเป็นต้องสื่อนั้นแล้ว หากนำออกไปไว้ใกล้กับส่วนหัวของตัวควบคุมการเล่น อาจทำให้หยุดทำงาน
  • Safari 9 และ Safari 10 ไม่ได้ติดตั้งใช้งาน SourceBuffer.abort() อย่างถูกต้อง อันที่จริงแล้ว แอปอาจมีข้อผิดพลาดที่ทำให้หยุดเล่นได้ โชคดีที่มีเครื่องมือติดตามข้อบกพร่อง ที่เปิดไว้ที่นี่ และที่นี่ ในระหว่างนี้ คุณจะต้องแก้ปัญหานี้ก่อน Shaka Player ทำได้ โดยตัดฟังก์ชัน abort() ที่ว่างเปล่าใน Safari เวอร์ชันเหล่านั้น

ต่อท้ายส่วนย่อยที่เล็กกว่า

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

const pieces = new Uint8Array([data]);
(function appendFragments(pieces) {
    if (sourceBuffer.updating) {
    return;
    }
    pieces.forEach(piece => {
    try {
        sourceBuffer.appendBuffer(piece);
    }
    catch e {
        if (e.name !== 'QuotaExceededError') {
        throw e;
        }

        // Reduction schedule: 80%, 60%, 40%, 20%, 16%, 12%, 8%, 4%, fail.
        const reduction = pieces[0].byteLength * 0.8;
        if (reduction / data.byteLength < 0.04) {
        throw new Error('MediaSource threw QuotaExceededError too many times');
        }
        const newPieces = [
        pieces[0].slice(0, reduction),
        pieces[0].slice(reduction, pieces[0].byteLength)
        ];
        pieces.splice(0, 1, newPieces[0], newPieces[1]);
        appendBuffer(pieces);  
    }
    });
})(pieces);

ลดความละเอียดในการเล่น

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

เมื่อใช้เทคนิคนี้ คุณควรคำนึงถึงสิ่งต่อไปนี้

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