WebAssembly ช่วยให้เราขยายความสามารถของเบราว์เซอร์ด้วยฟีเจอร์ใหม่ๆ บทความนี้แสดงวิธีพอร์ตโปรแกรมถอดรหัสวิดีโอ AV1 และเล่นวิดีโอ AV1 ในเบราว์เซอร์สมัยใหม่
สิ่งที่ดีที่สุดอย่างหนึ่งเกี่ยวกับ WebAssembly คือความสามารถในการทดลองใช้ความสามารถใหม่ๆ และนำแนวคิดใหม่ๆ ไปใช้ก่อนที่เบราว์เซอร์จะเปิดตัวฟีเจอร์เหล่านั้นโดยค่าเริ่มต้น (หากมี) คุณอาจมองว่าการใช้ WebAssembly ในลักษณะนี้เป็นกลไกการทดแทนประสิทธิภาพสูง ซึ่งคุณเขียนฟีเจอร์เป็น C/C++ หรือ Rust แทน JavaScript
การมีโค้ดที่มีอยู่มากมายสำหรับการพอร์ตช่วยให้คุณทําสิ่งต่างๆ ในเบราว์เซอร์ได้ ซึ่งก่อนหน้านี้ไม่สามารถทำได้จนกว่าจะมี WebAssembly
บทความนี้จะอธิบายตัวอย่างวิธีใช้ซอร์สโค้ดตัวแปลงรหัสวิดีโอ AV1 ที่มีอยู่ สร้างตัวแฝงสำหรับโค้ดดังกล่าว และลองใช้ภายในเบราว์เซอร์ รวมถึงเคล็ดลับที่จะช่วยสร้างชุดทดสอบเพื่อแก้ไขข้อบกพร่องของตัวแฝง ดูซอร์สโค้ดแบบเต็มของตัวอย่างได้ที่นี่ github.com/GoogleChromeLabs/wasm-av1
ดาวน์โหลดไฟล์วิดีโอทดสอบ 24 fps รายการใดรายการหนึ่งต่อไปนี้ แล้วลองใช้กับเดโมที่สร้างไว้
การเลือกฐานโค้ดที่น่าสนใจ
ในช่วงหลายปีที่ผ่านมา เราพบว่าการเข้าชมส่วนใหญ่บนเว็บประกอบด้วยข้อมูลวิดีโอ โดย 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
เราใช้เชลล์สคริปต์เพื่อค้นหาไฟล์ดังกล่าวเพื่อความสะดวก
#!/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 ของไฟล์เรียกว่าอินเทอร์เฟซสตรีม เราจึงกำหนดอินเทอร์เฟซของเราเองที่ดูเหมือน 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 ที่ส่งมาราวกับว่าเป็นแหล่งข้อมูลที่อ่านตามลําดับ รหัสอ้างอิงอยู่ในไฟล์ 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
โค้ด 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 เพื่อใช้กลุ่มข้อมูลไบนารีเมื่ออยู่ในเบราว์เซอร์ และอินเทอร์เฟซกับไฟล์จริงเมื่อเราสร้างโค้ดเพื่อทดสอบจากบรรทัดคำสั่ง โค้ดการทดสอบของเราจะอยู่
ในไฟล์ซอร์สตัวอย่าง
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 1 ไบต์ต่อช่องสี เอาต์พุตจากโปรแกรมถอดรหัส 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 f.p.s.) ทำให้เราทราบข้อมูลบางอย่างดังนี้
- คุณสามารถสร้างฐานโค้ดที่ซับซ้อนให้ทำงานได้อย่างมีประสิทธิภาพในเบราว์เซอร์โดยใช้ 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 ที่ให้รีวิวและความคิดเห็นที่มีคุณค่า