WebAssembly के साथ ब्राउज़र को बढ़ाना

WebAssembly की मदद से, हम ब्राउज़र में नई सुविधाएं जोड़ सकते हैं. इस लेख में, AV1 वीडियो डिकोडर को पोर्ट करने और किसी भी आधुनिक ब्राउज़र में AV1 वीडियो चलाने का तरीका बताया गया है.

Alex Danilo

WebAssembly की सबसे अच्छी बात यह है कि ब्राउज़र में नई सुविधाओं को नेटिव तौर पर उपलब्ध कराने से पहले, उन सुविधाओं के साथ एक्सपेरिमेंट किया जा सकता है और नए आइडिया लागू किए जा सकते हैं. इस तरह, WebAssembly का इस्तेमाल बेहतर परफ़ॉर्मेंस वाले पॉलीफ़िल मशीन के तौर पर किया जा सकता है. इसमें, अपनी सुविधा को JavaScript के बजाय C/C++ या Rust में लिखा जाता है.

पोर्ट करने के लिए मौजूदा कोड की बहुतायत होने की वजह से, ब्राउज़र में वे काम किए जा सकते हैं जो WebAssembly के आने से पहले नहीं किए जा सकते थे.

इस लेख में, मौजूदा AV1 वीडियो कोडेक सोर्स कोड को लेने, उसके लिए रैपर बनाने, और उसे अपने ब्राउज़र में आज़माने का उदाहरण दिया गया है. साथ ही, रैपर को डीबग करने के लिए टेस्ट हार्नेस बनाने में मदद करने के लिए सलाह भी दी गई है. उदाहरण के लिए, यहां दिया गया पूरा सोर्स कोड, रेफ़रंस के लिए github.com/GoogleChromeLabs/wasm-av1 पर उपलब्ध है.

24fps वाले इन दो टेस्ट वीडियो फ़ाइलों में से किसी एक को डाउनलोड करें और उन्हें हमारे बनाए गए डेमो पर आज़माएं.

दिलचस्प कोड-बेस चुनना

पिछले कई सालों से, हमने देखा है कि वेब पर ज़्यादातर ट्रैफ़िक, वीडियो डेटा से मिलता है. Cisco का अनुमान है कि यह 80% तक हो सकता है! बेशक, ब्राउज़र के वेंडर और वीडियो साइटें, इस बात से काफ़ी अच्छी तरह वाकिफ़ हैं कि लोगों को वीडियो कॉन्टेंट के लिए खर्च होने वाले डेटा को कम करना है. इसके लिए, बेहतर कंप्रेशन की ज़रूरत होती है. साथ ही, इंटरनेट पर वीडियो भेजने के लिए ज़रूरी डेटा को कम करने के मकसद से, अगली पीढ़ी के वीडियो कंप्रेशन पर काफ़ी रिसर्च की जा रही है.

Alliance for Open Media, अगली पीढ़ी के वीडियो कंप्रेशन स्कीम पर काम कर रहा है. इसे AV1 कहा जाता है. इससे वीडियो के डेटा का साइज़ काफ़ी कम हो सकता है. आने वाले समय में, हमें उम्मीद है कि ब्राउज़र में AV1 के लिए नेटिव सपोर्ट उपलब्ध होगा. हालांकि, कॉम्प्रेसर और डिकंप्रेसर के लिए सोर्स कोड ओपन सोर्स है. इसलिए, इसे WebAssembly में कंपाइल करने के लिए, यह एक बेहतरीन उम्मीदवार है. इससे हम ब्राउज़र में इसका इस्तेमाल करके एक्सपेरिमेंट कर पाएंगे.

Bunny मूवी की इमेज.

ब्राउज़र में इस्तेमाल करने के लिए अडैप्ट करना

इस कोड को ब्राउज़र में डालने के लिए, सबसे पहले हमें मौजूदा कोड के बारे में जानना होगा, ताकि यह समझा जा सके कि एपीआई कैसा है. इस कोड को पहली बार देखते समय, दो चीज़ें सबसे ज़्यादा ध्यान खींचती हैं:

  1. सोर्स ट्री को cmake नाम के टूल का इस्तेमाल करके बनाया जाता है; और
  2. ऐसे कई उदाहरण हैं जिनमें फ़ाइल-आधारित इंटरफ़ेस का इस्तेमाल किया गया है.

डिफ़ॉल्ट रूप से बने सभी उदाहरणों को कमांड लाइन पर चलाया जा सकता है. साथ ही, कम्यूनिटी में उपलब्ध कई अन्य कोड बेस में भी ऐसा किया जा सकता है. इसलिए, ब्राउज़र में इसे चलाने के लिए, हम जो इंटरफ़ेस बना रहे हैं वह कई अन्य कमांड लाइन टूल के लिए भी काम का हो सकता है.

सोर्स कोड बनाने के लिए cmake का इस्तेमाल करना

सौभाग्य से, AV1 के लेखक Emscripten के साथ प्रयोग कर रहे हैं. हम 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 टूलचेन, आउटपुट को दो फ़ॉर्मैट में जनरेट कर सकता है. पहला फ़ॉर्मैट 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 का इस्तेमाल करके बिल्ड करने का मतलब है कि पहले cmake को चलाकर कुछ Makefiles जनरेट करना, फिर make कमांड चलाना, जो कंपाइल करने का चरण पूरा करेगा. ध्यान दें, हम Emscripten का इस्तेमाल कर रहे हैं. इसलिए, हमें डिफ़ॉल्ट होस्ट कंपाइलर के बजाय, Emscripten कंपाइलर टूलचैन का इस्तेमाल करना होगा. ऐसा Emscripten.cmake का इस्तेमाल करके किया जाता है, जो Emscripten SDK टूल का हिस्सा है. साथ ही, cmake को पैरामीटर के तौर पर उसका पाथ पास किया जाता है. Makefiles जनरेट करने के लिए, हम नीचे दी गई कमांड लाइन का इस्तेमाल करते हैं:

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 जनरेट होगा. इसमें वीडियो डिकोडर को कंपाइल किया गया है और इसे प्रोजेक्ट में शामिल करने के लिए तैयार किया गया है.

लाइब्रेरी के इंटरफ़ेस के लिए एपीआई डिज़ाइन करना

लाइब्रेरी बनाने के बाद, हमें यह तय करना होगा कि कॉम्प्रेस किए गए वीडियो का डेटा इसमें कैसे भेजा जाए. इसके बाद, वीडियो के उन फ़्रेम को पढ़ना होगा जिन्हें ब्राउज़र में दिखाया जा सकता है.

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 के लिए पारदर्शी नहीं होता. इसका इस्तेमाल सिर्फ़ इंटरफ़ेस को कवर करने के लिए किया जाता है. ध्यान दें कि फ़ाइल के सेमेंटेक्स का बारीकी से पालन करने वाला एपीआई बनाने से, कई अन्य कोड-बेस में उसका फिर से इस्तेमाल करना आसान हो जाता है. इन कोड-बेस का इस्तेमाल कमांड-लाइन (उदाहरण के लिए, diff, sed वगैरह) से किया जाता है.

हमें DS_set_blob नाम का एक हेल्पर फ़ंक्शन भी तय करना होगा, जो रॉ बाइनरी डेटा को हमारी स्ट्रीम I/O फ़ंक्शन से जोड़ता है. इससे ब्लॉब को 'रीड' किया जा सकता है, जैसे कि यह कोई स्ट्रीम है (यानी, क्रम से पढ़ी जाने वाली फ़ाइल की तरह दिख रही है).

हमारे उदाहरण में, पास किए गए ब्लॉब को वैसे ही पढ़ा जा सकता है जैसे कि वह क्रम से पढ़ा जाने वाला डेटा सोर्स हो. रेफ़रंस कोड, फ़ाइल में मिल सकता है 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;
}

ब्राउज़र के बाहर टेस्ट करने के लिए, टेस्ट हार्नेस बनाना

सॉफ़्टवेयर इंजीनियरिंग में सबसे सही तरीकों में से एक है, इंटिग्रेशन टेस्ट के साथ कोड के लिए यूनिट टेस्ट बनाना.

ब्राउज़र में WebAssembly का इस्तेमाल करके प्रोग्राम बनाते समय, उस कोड के इंटरफ़ेस के लिए यूनिट टेस्ट का कोई भी तरीका अपनाना सही होता है जिस पर काम किया जा रहा है. इससे, ब्राउज़र के बाहर डीबग करने के साथ-साथ, बनाए गए इंटरफ़ेस की जांच भी की जा सकती है.

इस उदाहरण में, हमने AV1 लाइब्रेरी के इंटरफ़ेस के तौर पर, स्ट्रीम पर आधारित एपीआई को एमुलेट किया है. इसलिए, यह तर्कसंगत है कि हम एक टेस्ट हार्नेस बनाएं, जिसका इस्तेमाल करके अपने एपीआई का ऐसा वर्शन बनाया जा सके जो कमांड लाइन पर चलता हो और DATA_Source एपीआई के नीचे फ़ाइल I/O को लागू करके, अंदरूनी तौर पर असल फ़ाइल I/O करता हो.

हमारे टेस्ट हार्नेस के लिए स्ट्रीम 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 में देखा जा सकता है.

एक से ज़्यादा वीडियो फ़्रेम के लिए, बफ़र करने की सुविधा लागू करना

वीडियो चलाते समय, आम तौर पर कुछ फ़्रेम बफ़र किए जाते हैं, ताकि वीडियो को आसानी से चलाया जा सके. हम अपने काम के लिए, वीडियो के 10 फ़्रेम का बफ़र लागू करेंगे. इसलिए, वीडियो चलाने से पहले हम 10 फ़्रेम बफ़र कर लेंगे. इसके बाद, हर बार जब कोई फ़्रेम दिखेगा, तो हम किसी दूसरे फ़्रेम को डिकोड करने की कोशिश करेंगे, ताकि बफ़र भरा रहे. इस तरीके से, यह पक्का किया जाता है कि फ़्रेम पहले से उपलब्ध हों, ताकि वीडियो में रुकावट आने से रोका जा सके.

हमारे आसान उदाहरण में, कॉम्प्रेस किया गया पूरा वीडियो पढ़ने के लिए उपलब्ध है. इसलिए, वीडियो को बफ़र करने की ज़रूरत नहीं है. हालांकि, अगर हमें किसी सर्वर से स्ट्रीमिंग इनपुट के लिए, सोर्स डेटा इंटरफ़ेस को बढ़ाना है, तो हमें बफ़र करने की सुविधा चालू करनी होगी.

AV1 लाइब्रेरी से वीडियो डेटा के फ़्रेम पढ़ने और बफ़र में सेव करने के लिए, decode-av1.c में मौजूद कोड इस तरह का है:

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 टेक्सचर, आरजीबी इमेज होने चाहिए. हर कलर चैनल के लिए एक बाइट होना चाहिए. हमारे AV1 डिकोडर का आउटपुट, YUV फ़ॉर्मैट में इमेज के तौर पर होता है. इसमें डिफ़ॉल्ट आउटपुट में हर चैनल के लिए 16 बिट होते हैं. साथ ही, असली आउटपुट इमेज में हर U या V वैल्यू, चार पिक्सल के बराबर होती है. इसका मतलब है कि इमेज को डिसप्ले के लिए WebGL में भेजने से पहले, हमें इमेज को कलर में बदलना होगा.

ऐसा करने के लिए, हम एक फ़ंक्शन AVX_YUV_to_RGB() लागू करते हैं. यह फ़ंक्शन, सोर्स फ़ाइल yuv-to-rgb.c में मौजूद होता है. यह फ़ंक्शन, AV1 डिकोडर के आउटपुट को ऐसी चीज़ में बदल देता है जिसे WebGL को पास किया जा सकता है. ध्यान दें कि जब हम JavaScript से इस फ़ंक्शन को कॉल करते हैं, तो हमें यह पक्का करना होता है कि जिस मेमोरी में बदली गई इमेज को लिखा जा रहा है वह वेब असेंबली मॉड्यूल की मेमोरी में असाइन की गई हो. ऐसा न होने पर, उसे ऐक्सेस नहीं किया जा सकता. 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);
   
}
}

WebGL पेंटिंग को लागू करने वाला drawImageToCanvas() फ़ंक्शन, रेफ़रंस के लिए सोर्स फ़ाइल draw-image.js में मिल सकता है.

आने वाले समय में क्या करना है और इससे क्या सीखना है

दो टेस्ट वीडियो फ़ाइलों (24 एफ़पीएस वीडियो के तौर पर रिकॉर्ड की गई) पर, हमारे डेमो को आज़माने से हमें कुछ बातें पता चलती हैं:

  1. WebAssembly का इस्तेमाल करके, ब्राउज़र में बेहतर परफ़ॉर्मेंस के लिए जटिल कोड-बेस बनाया जा सकता है; और
  2. WebAssembly की मदद से, सीपीयू पर ज़्यादा लोड डालने वाली प्रोसेस, जैसे कि बेहतर वीडियो डिकोडिंग की जा सकती है.

हालांकि, इसमें कुछ सीमाएं हैं: लागू करने की प्रोसेस, मुख्य थ्रेड पर चल रही है. साथ ही, हम उस एक ही थ्रेड पर पेंटिंग और वीडियो डिकोडिंग को इंटरलीव करते हैं. डिकोडिंग को वेब वर्कर्स में ऑफ़लोड करने से, वीडियो को आसानी से चलाया जा सकता है. ऐसा इसलिए, क्योंकि फ़्रेम को डिकोड करने में लगने वाला समय, उस फ़्रेम के कॉन्टेंट पर निर्भर करता है. साथ ही, कभी-कभी इसमें तय किए गए बजट से ज़्यादा समय लग सकता है.

WebAssembly में कंपाइल करने के लिए, सामान्य सीपीयू टाइप के लिए AV1 कॉन्फ़िगरेशन का इस्तेमाल किया जाता है. अगर किसी सामान्य सीपीयू के लिए, कमांड-लाइन पर नेटिव तौर पर कॉम्पाइल किया जाता है, तो हमें वीडियो को डिकोड करने के लिए, वेब असेंबली वर्शन जैसा ही सीपीयू लोड दिखता है. हालांकि, AV1 डिकोडर लाइब्रेरी में SIMD लागू करने की सुविधा भी शामिल है, जो पांच गुना तेज़ी से काम करती है. फ़िलहाल, WebAssembly कम्यूनिटी ग्रुप, SIMD प्राइमिटिव को शामिल करने के लिए, स्टैंडर्ड को बढ़ाने पर काम कर रहा है. जब यह काम पूरा हो जाएगा, तो डिकोडिंग की स्पीड काफ़ी बढ़ जाएगी. ऐसा होने पर, WebAssembly वीडियो डीकोडर की मदद से, रीयल-टाइम में 4K एचडी वीडियो को डिकोड करना पूरी तरह से मुमकिन हो जाएगा.

किसी भी मामले में, उदाहरण के तौर पर दिया गया कोड, किसी भी मौजूदा कमांड लाइन की सुविधा को वेबअसेंबली मॉड्यूल के तौर पर चलाने के लिए, गाइड के तौर पर काम आता है. साथ ही, यह दिखाता है कि वेब पर आज क्या-क्या किया जा सकता है.

क्रेडिट

अहम समीक्षा और सुझाव देने के लिए, जेफ़ पॉस्निक, एरिक बिडलमैन, और थॉमस स्टाइनर का धन्यवाद.