WebAssembly ช่วยให้เราขยายการทำงานของเบราว์เซอร์ด้วยฟีเจอร์ใหม่ๆ บทความนี้จะแสดงวิธีพอร์ตตัวถอดรหัสวิดีโอ AV1 และเล่นวิดีโอ AV1 ในเบราว์เซอร์รุ่นใหม่
หนึ่งในสิ่งที่ดีที่สุดเกี่ยวกับ WebAssembly คือการทดสอบความสามารถด้วยความสามารถใหม่ๆ และนำแนวคิดใหม่ๆ มาใช้ก่อนที่เบราว์เซอร์จะจัดส่งฟีเจอร์เหล่านั้นโดยกำเนิด (หรือไม่ใช้เลย) ลองคิดว่าการใช้ WebAssembly เป็นกลไก Polyfill ที่มีประสิทธิภาพสูง ซึ่งคุณจะเขียนฟีเจอร์ใน C/C++ หรือ Rust แทนการใช้ JavaScript ได้
เพราะมีโค้ดจำนวนมากมายมหาศาลที่พร้อมสำหรับการย้ายระบบ ทำให้เป็นไปได้ที่จะทำสิ่งต่างๆ ในเบราว์เซอร์ที่ใช้งานไม่ได้จนกว่า WebAssembly จะเข้ามาดำเนินการ
บทความนี้จะแนะนำตัวอย่างวิธีนำซอร์สโค้ดตัวแปลงรหัสวิดีโอ AV1 ที่มีอยู่ สร้าง Wrapper สำหรับโค้ดนั้น แล้วนำไปลองใช้ในเบราว์เซอร์ รวมถึงเคล็ดลับที่จะช่วยในการสร้างโปรแกรมทดสอบเพื่อแก้ไขข้อบกพร่องของ Wrapper ดูซอร์สโค้ดแบบเต็มสำหรับตัวอย่างได้ที่ github.com/GoogleChromeLabs/wasm-av1 เพื่อเป็นข้อมูลอ้างอิง
ดาวน์โหลดไฟล์วิดีโอทดสอบ 24fps 2 ไฟล์ แล้วลองเล่นในการสาธิตที่เราสร้าง
การเลือกฐานของโค้ดที่น่าสนใจ
หลายปีมานี้ เราพบว่าการเข้าชมเว็บในสัดส่วนสูงประกอบด้วยข้อมูลวิดีโอ แต่ Cisco ได้คาดการณ์ข้อมูลนี้ไว้ถึง 80% ในความเป็นจริง แน่นอนว่าผู้ให้บริการเบราว์เซอร์และเว็บไซต์วิดีโอทราบดีถึงความปรารถนาที่จะลดการใช้งานเนื้อหาวิดีโอทั้งหมดนี้ แน่นอนว่ากุญแจสำคัญคือการบีบอัดที่ดีกว่า และคุณคงคาดหวังได้ว่าจะมีการวิจัยจำนวนมากเกี่ยวกับการบีบอัดวิดีโอรุ่นถัดไปซึ่งมีจุดมุ่งหมายเพื่อลดภาระด้านข้อมูลในการส่งวิดีโอ ไปทั่วอินเทอร์เน็ต
ในที่สุด Alliance for Open Media ก็ได้พัฒนารูปแบบการบีบอัดวิดีโอรุ่นใหม่ที่เรียกว่า AV1 ซึ่งสัญญาว่าจะลดขนาดข้อมูลวิดีโอลงอย่างมาก ในอนาคต เราคาดว่าเบราว์เซอร์จะส่งการสนับสนุนในเครื่องสำหรับ AV1 แต่โชคดีที่ซอร์สโค้ดสำหรับคอมเพรสเซอร์และการขยายการบีบอัดเป็นโอเพนซอร์ส จึงเป็นตัวเลือกที่เหมาะสำหรับการพยายามคอมไพล์ลงใน WebAssembly เพื่อให้เราทดลองกับโค้ดในเบราว์เซอร์ได้
การปรับตัวสำหรับการใช้งานในเบราว์เซอร์
สิ่งแรกที่เราต้องทำเพื่อให้โค้ดนี้ลงในเบราว์เซอร์ คือการทำความเข้าใจโค้ดที่มีอยู่เพื่อทำความเข้าใจว่า API เป็นอย่างไร เมื่อดูโค้ดนี้ครั้งแรก จะมี 2 สิ่งที่โดดเด่น ได้แก่
- โครงสร้างต้นฉบับสร้างขึ้นโดยใช้เครื่องมือชื่อ
cmake
และ - มีตัวอย่างจำนวนหนึ่งที่ถือว่าทั้งหมดเป็นอินเทอร์เฟซที่ใช้ไฟล์บางประเภท
ตัวอย่างทั้งหมดที่สร้างขึ้นโดยค่าเริ่มต้นจะทำงานในบรรทัดคำสั่งได้ ซึ่งก็น่าจะเป็นจริงในฐานโค้ดอื่นๆ ที่มีอยู่ในชุมชน ดังนั้น อินเทอร์เฟซที่เราจะสร้างเพื่อให้ทำงานในเบราว์เซอร์จึงอาจมีประโยชน์สำหรับเครื่องมือบรรทัดคำสั่งอื่นๆ อีกมากมาย
การใช้ cmake
เพื่อสร้างซอร์สโค้ด
โชคดีที่ผู้เขียน AV1 ได้ทดลองใช้ Emscripten ซึ่งเป็น SDK ที่เราจะนำไปใช้สร้างเวอร์ชัน WebAssembly ในรูทของที่เก็บ AV1 ไฟล์CMakeLists.txt
จะมีกฎบิลด์ต่อไปนี้
if(EMSCRIPTEN)
add_preproc_definition(_POSIX_SOURCE)
append_link_flag_to_target("inspect" "-s TOTAL_MEMORY=402653184")
append_link_flag_to_target("inspect" "-s MODULARIZE=1")
append_link_flag_to_target("inspect"
"-s EXPORT_NAME=\"\'DecoderModule\'\"")
append_link_flag_to_target("inspect" "--memory-init-file 0")
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
# Default to -O3 when no build type is specified.
append_compiler_flag("-O3")
endif()
em_link_post_js(inspect "${AOM_ROOT}/tools/inspect-post.js")
endif()
เชนเครื่องมือ Emscripten สร้างเอาต์พุตได้ 2 รูปแบบคือ asm.js
และรูปแบบ WebAssembly
เราจะกำหนดเป้าหมาย WebAssembly เนื่องจากให้ผลผลิตน้อยลงและทำงานได้เร็วขึ้น กฎบิลด์ที่มีอยู่เหล่านี้มีไว้เพื่อคอมไพล์ไลบรารีเวอร์ชัน asm.js
สำหรับใช้ในแอปพลิเคชันของตัวตรวจสอบที่ใช้ประโยชน์จากการดูเนื้อหาของไฟล์วิดีโอ สำหรับการใช้งาน เราต้องใช้เอาต์พุต WebAssembly จึงจะเพิ่มบรรทัดเหล่านี้ก่อนคำสั่งปิด endif()
ในกฎข้างต้น
# Force generation of Wasm instead of asm.js
append_link_flag_to_target("inspect" "-s WASM=1")
append_compiler_flag("-s WASM=1")
การสร้างด้วย cmake
หมายถึงการสร้าง Makefiles
บางส่วนก่อนโดยการเรียกใช้ cmake
แล้วตามด้วยเรียกใช้คำสั่ง make
ซึ่งจะดำเนินการขั้นตอนการคอมไพล์
โปรดทราบว่าเนื่องจากเราใช้ Emscripten เราจึงต้องใช้เชนเครื่องมือคอมไพเลอร์ Emscripten แทนคอมไพเลอร์ของโฮสต์เริ่มต้น
ซึ่งทำได้ด้วยการใช้ Emscripten.cmake
ซึ่งเป็นส่วนหนึ่งของ Emscripten SDK และส่งผ่านเส้นทางเป็นพารามิเตอร์ไปยัง cmake
บรรทัดคำสั่งด้านล่างนี้เป็นช่องทางที่เราใช้สร้าง Makefile
cmake path/to/aom \
-DENABLE_CCACHE=1 -DAOM_TARGET_CPU=generic -DENABLE_DOCS=0 \
-DCONFIG_ACCOUNTING=1 -DCONFIG_INSPECTION=1 -DCONFIG_MULTITHREAD=0 \
-DCONFIG_RUNTIME_CPU_DETECT=0 -DCONFIG_UNIT_TESTS=0
-DCONFIG_WEBM_IO=0 \
-DCMAKE_TOOLCHAIN_FILE=path/to/emsdk-portable/.../Emscripten.cmake
ควรตั้งค่าพารามิเตอร์ path/to/aom
เป็นเส้นทางแบบเต็มของตำแหน่งไฟล์ต้นทางของไลบรารี AV1 ต้องตั้งค่าพารามิเตอร์ path/to/emsdk-portable/…/Emscripten.cmake
เป็นเส้นทางสำหรับไฟล์คำอธิบายเครื่องมือ Emscripten.cmake
เพื่อความสะดวก เราจะใช้สคริปต์ Shell เพื่อค้นหาไฟล์ดังกล่าว
#!/bin/sh
EMCC_LOC=`which emcc`
EMSDK_LOC=`echo $EMCC_LOC | sed 's?/emscripten/[0-9.]*/emcc??'`
EMCMAKE_LOC=`find $EMSDK_LOC -name Emscripten.cmake -print`
echo $EMCMAKE_LOC
หากดู Makefile
ระดับบนสุดสำหรับโปรเจ็กต์นี้ คุณจะเห็นว่าใช้สคริปต์นั้นในการกำหนดค่าบิลด์อย่างไร
ตอนนี้การตั้งค่าทั้งหมดเสร็จสมบูรณ์แล้ว เพียงเรียกใช้ make
ซึ่งจะสร้างโครงสร้างต้นฉบับทั้งหมดรวมถึงตัวอย่าง แต่ที่สำคัญที่สุดคือสร้าง libaom.a
ซึ่งมีตัวถอดรหัสวิดีโอซึ่งคอมไพล์วิดีโอแล้ว และพร้อมให้เรารวมเข้าในโปรเจ็กต์
การออกแบบ API เพื่ออินเทอร์เฟซกับไลบรารี
เมื่อเราสร้างไลบรารีแล้ว เราต้องหาวิธีเชื่อมต่อกับไลบรารีเพื่อส่งข้อมูลวิดีโอที่บีบอัดไปยังไลบรารี แล้วอ่านเฟรมของวิดีโอที่เราแสดงในเบราว์เซอร์ได้
ลองดูภายในแผนผังโค้ด AV1 จุดเริ่มต้นที่ดีคือตัวอย่างตัวถอดรหัสวิดีโอซึ่งมีอยู่ในไฟล์ [simple_decoder.c](https://aomedia.googlesource.com/aom/+/master/examples/simple_decoder.c)
เครื่องมือถอดรหัสจะอ่านในไฟล์ IVF และถอดรหัสเป็นชุดรูปภาพที่แสดงถึงเฟรมในวิดีโอ
เราใช้อินเทอร์เฟซในไฟล์ต้นฉบับ [decode-av1.c](https://github.com/GoogleChromeLabs/wasm-av1/blob/master/decode-av1.c)
เนื่องจากเบราว์เซอร์ของเราอ่านไฟล์จากระบบไฟล์ไม่ได้ เราจึงต้องออกแบบอินเทอร์เฟซบางรูปแบบให้แยก I/O ออก เพื่อให้สามารถสร้างสิ่งที่คล้ายกับตัวถอดรหัสตัวอย่างเพื่อนำข้อมูลเข้าสู่ไลบรารี AV1 ได้
ในบรรทัดคำสั่ง ไฟล์ I/O คือสิ่งที่เรียกว่าอินเทอร์เฟซสตรีม เราจึงสามารถกำหนดอินเทอร์เฟซของตัวเองให้มีลักษณะเป็น Stream I/O และสร้างอะไรก็ได้ที่เรา ต้องการสำหรับการใช้งานที่เกี่ยวข้อง
ซึ่งเราได้ให้คำจำกัดความของอินเทอร์เฟซไว้ดังนี้
DATA_Source *DS_open(const char *what);
size_t DS_read(DATA_Source *ds,
unsigned char *buf, size_t bytes);
int DS_empty(DATA_Source *ds);
void DS_close(DATA_Source *ds);
// Helper function for blob support
void DS_set_blob(DATA_Source *ds, void *buf, size_t len);
ฟังก์ชัน open/read/empty/close
จะคล้ายกับการดำเนินการ I/O ของไฟล์ปกติมากซึ่งช่วยให้เราแมปกับ I/O ไฟล์สำหรับแอปพลิเคชันบรรทัดคำสั่ง หรือนำไปใช้ในทางอื่นเมื่อเรียกใช้ภายในเบราว์เซอร์ได้ ประเภท DATA_Source
ไม่ชัดเจนจากฝั่ง JavaScript และเพียงแค่ห่อหุ้มอินเทอร์เฟซเท่านั้น โปรดทราบว่าการสร้าง API ที่เป็นไปตามความหมายของไฟล์อย่างใกล้ชิดจะช่วยให้นำกลับมาใช้ซ้ำในฐานของโค้ดอื่นๆ จำนวนมากที่มีไว้สำหรับบรรทัดคำสั่ง (เช่น diff, sed ฯลฯ) ได้อย่างง่ายดาย
นอกจากนี้เรายังต้องกำหนดฟังก์ชันตัวช่วยที่เรียกว่า DS_set_blob
ซึ่งเชื่อมโยงข้อมูลไบนารีดิบกับฟังก์ชัน I/O ของสตรีมด้วย ซึ่งจะทำให้ "อ่าน" บล็อบได้ราวกับว่าเป็นสตรีม (เช่น เป็นไฟล์ที่อ่านตามลำดับ)
การใช้งานตัวอย่างของเราทำให้อ่านค่าที่ส่งใน BLOB ได้ราวกับว่าเป็นแหล่งข้อมูลที่อ่านตามลำดับ ดูโค้ดอ้างอิงได้ในไฟล์
blob-api.c
และการติดตั้งใช้งานทั้งหมดก็มีเพียงแค่นี้
struct DATA_Source {
void *ds_Buf;
size_t ds_Len;
size_t ds_Pos;
};
DATA_Source *
DS_open(const char *what) {
DATA_Source *ds;
ds = malloc(sizeof *ds);
if (ds != NULL) {
memset(ds, 0, sizeof *ds);
}
return ds;
}
size_t
DS_read(DATA_Source *ds, unsigned char *buf, size_t bytes) {
if (DS_empty(ds) || buf == NULL) {
return 0;
}
if (bytes > (ds->ds_Len - ds->ds_Pos)) {
bytes = ds->ds_Len - ds->ds_Pos;
}
memcpy(buf, &ds->ds_Buf[ds->ds_Pos], bytes);
ds->ds_Pos += bytes;
return bytes;
}
int
DS_empty(DATA_Source *ds) {
return ds->ds_Pos >= ds->ds_Len;
}
void
DS_close(DATA_Source *ds) {
free(ds);
}
void
DS_set_blob(DATA_Source *ds, void *buf, size_t len) {
ds->ds_Buf = buf;
ds->ds_Len = len;
ds->ds_Pos = 0;
}
การสร้างโปรแกรมทดสอบอัตโนมัติเพื่อทดสอบนอกเบราว์เซอร์
หนึ่งในแนวทางปฏิบัติแนะนำด้านวิศวกรรมซอฟต์แวร์คือการสร้าง 1 การทดสอบสำหรับโค้ดร่วมกับการทดสอบการผสานรวม
เมื่อสร้างด้วย WebAssembly ในเบราว์เซอร์ คุณควรสร้างการทดสอบหน่วยบางรูปแบบสำหรับอินเทอร์เฟซกับโค้ดที่เรากำลังดำเนินการด้วย เพื่อให้เราแก้ไขข้อบกพร่องนอกเบราว์เซอร์และทดสอบอินเทอร์เฟซที่เราสร้างขึ้นได้ด้วย
ในตัวอย่างนี้ เราได้จำลอง API แบบสตรีมเป็นอินเทอร์เฟซกับไลบรารี AV1 ดังนั้น ตามหลักเหตุผลแล้ว การสร้างโปรแกรมทดสอบที่เรานำไปใช้สร้าง API เวอร์ชันที่ทำงานบนบรรทัดคำสั่งได้จริงและสร้าง I/O ในไฟล์โดยติดตั้ง I/O ไฟล์เองใต้ DATA_Source
API
โค้ด Stream I/O สำหรับเครื่องทดสอบทดสอบของเราตรงไปตรงมา และมีลักษณะดังนี้
DATA_Source *
DS_open(const char *what) {
return (DATA_Source *)fopen(what, "rb");
}
size_t
DS_read(DATA_Source *ds, unsigned char *buf, size_t bytes) {
return fread(buf, 1, bytes, (FILE *)ds);
}
int
DS_empty(DATA_Source *ds) {
return feof((FILE *)ds);
}
void
DS_close(DATA_Source *ds) {
fclose((FILE *)ds);
}
เมื่อพิจารณาอินเทอร์เฟซของสตรีม เราสามารถสร้างโมดูล WebAssembly เพื่อใช้ Blob ข้อมูลไบนารีในเบราว์เซอร์ และอินเทอร์เฟซกับไฟล์จริงเมื่อเราสร้างโค้ดเพื่อทดสอบจากบรรทัดคำสั่ง ดูโค้ดโปรแกรมใช้ประโยชน์จากการทดสอบได้ในไฟล์ต้นฉบับตัวอย่าง test.c
การใช้กลไกการบัฟเฟอร์สำหรับเฟรมวิดีโอหลายเฟรม
เมื่อเล่นวิดีโอ เรื่องทั่วไปคือการเก็บบัฟเฟอร์ 2-3 เฟรมเพื่อให้เล่นได้อย่างราบรื่นมากขึ้น สำหรับวัตถุประสงค์ของเรา เราจะใช้บัฟเฟอร์วิดีโอ 10 เฟรมเท่านั้น ดังนั้นเราจะบัฟเฟอร์ 10 เฟรมก่อนเริ่มเล่น จากนั้นทุกครั้งที่เฟรมแสดงขึ้น เราจะพยายามถอดรหัสอีกเฟรมหนึ่งเพื่อให้บัฟเฟอร์สมบูรณ์ วิธีนี้จะช่วยทำให้เฟรมพร้อมใช้งานล่วงหน้าเพื่อช่วยหยุดวิดีโอกระตุก
ตามตัวอย่างง่ายๆ ของเรา วิดีโอที่บีบอัดมีให้อ่านได้ทั้งหมด ดังนั้นการบัฟเฟอร์จึงไม่จำเป็น อย่างไรก็ตาม หากเราจะขยายอินเทอร์เฟซข้อมูลต้นฉบับให้รองรับอินพุตแบบสตรีมจากเซิร์ฟเวอร์ เราจะต้องมีกลไกการบัฟเฟอร์ด้วย
โค้ดใน decode-av1.c
สำหรับการอ่านเฟรมข้อมูลวิดีโอจากไลบรารี AV1 และจัดเก็บไว้ในบัฟเฟอร์มีลักษณะดังนี้
void
AVX_Decoder_run(AVX_Decoder *ad) {
...
// Try to decode an image from the compressed stream, and buffer
while (ad->ad_NumBuffered < NUM_FRAMES_BUFFERED) {
ad->ad_Image = aom_codec_get_frame(&ad->ad_Codec,
&ad->ad_Iterator);
if (ad->ad_Image == NULL) {
break;
}
else {
buffer_frame(ad);
}
}
เราได้เลือกให้บัฟเฟอร์มี 10 เฟรมของวิดีโอ ซึ่งเป็นการเลือกแบบกำหนดเอง การบัฟเฟอร์เฟรมจำนวนมากทำให้ต้องรอวิดีโอเริ่มเล่นนานขึ้น ขณะที่การบัฟเฟอร์เฟรมน้อยเกินไปอาจทำให้หยุดเล่นได้ ในการใช้งานเบราว์เซอร์แบบเนทีฟ การบัฟเฟอร์เฟรมจะซับซ้อนกว่าการใช้งานนี้มาก
การนำเฟรมวิดีโอมาไว้บนหน้าเว็บด้วย WebGL
เฟรมของวิดีโอที่เราบัฟเฟอร์ไว้ต้องแสดงบนหน้าเว็บของเรา เนื่องจากนี่เป็นเนื้อหาวิดีโอแบบไดนามิก เราจึงต้องการทำเรื่องนั้นให้เร็วที่สุดเท่าที่จะทำได้ เราจึงไปที่ WebGL
WebGL ให้เราถ่ายรูป เช่น เฟรมวิดีโอ แล้วใช้เป็นพื้นผิว ที่มีการวาดลงบนรูปเรขาคณิตบางรูป ในโลกของ WebGL ทุกอย่าง ประกอบด้วยรูปสามเหลี่ยม สำหรับกรณีของเรา เราสามารถใช้ฟีเจอร์ในตัวของ WebGL ที่เรียกว่า gl.TRIANGLE_FAN
แต่มีปัญหาเล็กน้อย พื้นผิว WebGL ควรเป็นภาพ RGB หนึ่งไบต์ต่อช่องสี เอาต์พุตจากตัวถอดรหัส AV1 คือรูปภาพในรูปแบบ YUV ซึ่งเอาต์พุตเริ่มต้นมี 16 บิตต่อช่องสัญญาณ และค่า U หรือ V แต่ละค่าจะสอดคล้องกับ 4 พิกเซลในรูปภาพเอาต์พุตจริง ซึ่งหมายความว่าเราต้องแปลงรูปภาพเป็นสีก่อน แล้วจึงส่งผ่าน WebGL เพื่อแสดงได้
วิธีการคือเราใช้ฟังก์ชัน AVX_YUV_to_RGB()
ซึ่ง
พบได้ในไฟล์ต้นฉบับ
yuv-to-rgb.c
ฟังก์ชันนั้นจะแปลงเอาต์พุตจากตัวถอดรหัส AV1 เป็นสิ่งที่เราสามารถส่งไปยัง WebGL ได้ โปรดทราบว่าเมื่อเราเรียกใช้ฟังก์ชันนี้จาก JavaScript เราจำเป็นต้องตรวจสอบว่าหน่วยความจำที่เราเขียนรูปภาพที่แปลงเข้าไปนั้นได้รับการจัดสรรไว้ในหน่วยความจำของโมดูล WebAssembly มิเช่นนั้นจะไม่สามารถเข้าถึงข้อมูลได้ ฟังก์ชันในการนำรูปภาพออกจากโมดูล WebAssembly แล้วลงสีลงในหน้าจอคือ
function show_frame(af) {
if (rgb_image != 0) {
// Convert The 16-bit YUV to 8-bit RGB
let buf = Module._AVX_Video_Frame_get_buffer(af);
Module._AVX_YUV_to_RGB(rgb_image, buf, WIDTH, HEIGHT);
// Paint the image onto the canvas
drawImageToCanvas(new Uint8Array(Module.HEAPU8.buffer,
rgb_image, 3 * WIDTH * HEIGHT), WIDTH, HEIGHT);
}
}
สามารถดูฟังก์ชัน drawImageToCanvas()
ที่ใช้ภาพวาด WebGL ได้ในไฟล์ต้นฉบับ draw-image.js
เพื่อเป็นข้อมูลอ้างอิง
งานและสิ่งสำคัญที่เรียนรู้ในอนาคต
การลองใช้ไฟล์สาธิตกับไฟล์วิดีโอทดสอบ 2 รายการ (ซึ่งบันทึกเป็นวิดีโอ 24 รายการ) จะให้ความรู้ต่อไปนี้แก่เรา
- เป็นไปได้อย่างยิ่งที่จะสร้างฐานของโค้ดที่ซับซ้อนเพื่อให้ทำงานได้อย่างมีประสิทธิภาพในเบราว์เซอร์โดยใช้ WebAssembly และ
- การทำงานบางอย่างที่ใช้ CPU มากเท่ากับการถอดรหัสวิดีโอขั้นสูงผ่าน WebAssembly
แต่มีข้อจำกัดบางอย่างคือ การติดตั้งใช้งานทั้งหมดจะทำงานบนเทรดหลัก และเราแทรกภาพวาดและการถอดรหัสวิดีโอในเทรดนั้นไว้ การลดการถอดรหัสลงใน Web Worker จะทำให้เราเล่นได้อย่างราบรื่นขึ้น เนื่องจากเวลาที่ใช้ในการถอดรหัสเฟรมนั้นจะขึ้นอยู่กับเนื้อหาของเฟรมนั้นเป็นหลักและบางครั้งอาจใช้เวลามากกว่าที่เราตั้งงบประมาณไว้
การคอมไพล์ใน WebAssembly ใช้การกำหนดค่า AV1 สำหรับประเภท CPU ทั่วไป หากเราคอมไพล์ในบรรทัดคำสั่งสำหรับ CPU ทั่วไป เราก็จะเห็นการโหลดของ CPU ที่คล้ายกันในการถอดรหัสวิดีโอเช่นเดียวกับเวอร์ชัน WebAssembly อย่างไรก็ตาม ไลบรารีตัวถอดรหัส AV1 ยังรวมการใช้งาน SIMD ซึ่งทำงานเร็วกว่าสูงสุด 5 เท่า ขณะนี้กลุ่มชุมชน WebAssembly กําลังพยายามขยายมาตรฐานให้รวมข้อมูลเบื้องต้นของ SIMD ด้วย และเมื่อเป็นเช่นนั้น ก็สัญญาว่าจะเร่งการถอดรหัสได้เร็วขึ้นอย่างมาก เมื่อเป็นเช่นนี้ คุณก็ถอดรหัสวิดีโอ 4K HD ในแบบเรียลไทม์ได้จากตัวถอดรหัสวิดีโอ WebAssembly
ไม่ว่าในกรณีใดก็ตาม โค้ดตัวอย่างจะเป็นประโยชน์ในการช่วยพอร์ตยูทิลิตีบรรทัดคำสั่งที่มีอยู่ให้ทำงานเป็นโมดูล WebAssembly และแสดงสิ่งที่เป็นไปได้บนเว็บในปัจจุบัน
เครดิต
ขอขอบคุณ Jeff Posnick, Eric Bidelman และ Thomas Steiner ที่ร่วมให้ข้อมูลรีวิวและความคิดเห็นที่มีประโยชน์