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

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

Alex Danilo

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

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

इस लेख में, मौजूदा AV1 वीडियो कोडेक सोर्स कोड को लेने, उसके लिए रैपर बनाने, और उसे अपने ब्राउज़र में आज़माने का उदाहरण दिया गया है. साथ ही, रैपर को डीबग करने के लिए टेस्ट हार्नेस बनाने से जुड़ी सलाह भी दी गई है. यहां दिए गए उदाहरण का पूरा सोर्स कोड, रेफ़रंस के लिए github.com/GoogleChromeLabs/vasm-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) फ़ाइल में मौजूद है. वह डिकोडर एक आईवीएफ़ फ़ाइल में पढ़ता है और उसे इमेज की ऐसी सीरीज़ में डिकोड करता है जो वीडियो में मौजूद फ़्रेम को दिखाती है.

हम अपने इंटरफ़ेस को सोर्स फ़ाइल [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 पर आसानी से मैप किया जा सकता है. इसके अलावा, ब्राउज़र में चलाने पर, इन्हें किसी दूसरे तरीके से लागू किया जा सकता है. JavaScript की तरफ़ से DATA_Source टाइप ओपेक नहीं है और सिर्फ़ इंटरफ़ेस को एनकैप्सुलेट करने का काम करता है. ध्यान दें कि फ़ाइल सिमेंटिक्स के मुताबिक एपीआई बनाने से, कई ऐसे कोड-बेस में आसानी से दोबारा इस्तेमाल किया जा सकता है जिन्हें कमांड लाइन (उदाहरण के लिए, डिफ़रेंस, 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;
}

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

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

ब्राउज़र में 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 की वैल्यू भी असल आउटपुट इमेज में 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);
    }
}

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

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

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

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

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

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

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

क्रेडिट

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