WebAssembly দিয়ে ব্রাউজার প্রসারিত করা হচ্ছে

WebAssembly আমাদের নতুন বৈশিষ্ট্য সহ ব্রাউজার প্রসারিত করতে দেয়। এই নিবন্ধটি দেখায় কিভাবে AV1 ভিডিও ডিকোডার পোর্ট করতে হয় এবং যেকোনো আধুনিক ব্রাউজারে AV1 ভিডিও চালাতে হয়।

Alex Danilo

WebAssembly সম্পর্কে সেরা জিনিসগুলির মধ্যে একটি হল নতুন ক্ষমতার সাথে সক্ষমতা পরীক্ষা করা এবং ব্রাউজারটি সেই বৈশিষ্ট্যগুলি স্থানীয়ভাবে পাঠানোর আগে নতুন ধারণাগুলি বাস্তবায়ন করা (যদি থাকে)। আপনি এইভাবে WebAssembly ব্যবহার করার কথা ভাবতে পারেন একটি উচ্চ-পারফরম্যান্স পলিফিল মেকানিজম হিসেবে, যেখানে আপনি JavaScript-এর পরিবর্তে C/C++ বা Rust-এ আপনার বৈশিষ্ট্য লেখেন।

পোর্টিংয়ের জন্য উপলব্ধ বিদ্যমান কোডের আধিক্যের সাথে, ব্রাউজারে এমন কিছু করা সম্ভব যা WebAssembly না আসা পর্যন্ত কার্যকর ছিল না।

এই নিবন্ধটি কীভাবে বিদ্যমান AV1 ভিডিও কোডেক সোর্স কোড নিতে হয়, এটির জন্য একটি র‍্যাপার তৈরি করতে হয় এবং এটি আপনার ব্রাউজারের ভিতরে ব্যবহার করে দেখুন এবং র‍্যাপার ডিবাগ করার জন্য একটি পরীক্ষামূলক জোতা তৈরিতে সহায়তা করার জন্য টিপসগুলির একটি উদাহরণ দিয়ে হেঁটে যাবে৷ উদাহরণের জন্য সম্পূর্ণ সোর্স কোড এখানে রেফারেন্সের জন্য github.com/GoogleChromeLabs/wasm-av1 এ উপলব্ধ।

এই দুটি 24fps টেস্ট ভিডিও ফাইলগুলির একটি ডাউনলোড করুন এবং আমাদের তৈরি ডেমোতে চেষ্টা করুন৷

একটি আকর্ষণীয় কোড-বেস নির্বাচন করা

এখন বেশ কয়েক বছর ধরে, আমরা দেখেছি যে ওয়েবে ট্র্যাফিকের একটি বড় শতাংশ ভিডিও ডেটা নিয়ে গঠিত, সিসকো এটিকে প্রকৃতপক্ষে 80% হিসাবে অনুমান করে ! অবশ্যই, ব্রাউজার বিক্রেতা এবং ভিডিও সাইটগুলি এই সমস্ত ভিডিও সামগ্রীর দ্বারা ব্যবহৃত ডেটা হ্রাস করার ইচ্ছা সম্পর্কে ব্যাপকভাবে সচেতন। এর মূল চাবিকাঠি, অবশ্যই, আরও ভাল কম্প্রেশন, এবং আপনি যেমন আশা করছেন ইন্টারনেট জুড়ে ভিডিও শিপিংয়ের ডেটা বোঝা হ্রাস করার লক্ষ্যে পরবর্তী প্রজন্মের ভিডিও কম্প্রেশনে প্রচুর গবেষণা রয়েছে।

যেমনটি ঘটে, অ্যালায়েন্স ফর ওপেন মিডিয়া AV1 নামক একটি পরবর্তী প্রজন্মের ভিডিও কম্প্রেশন স্কিম নিয়ে কাজ করছে যা ভিডিও ডেটার আকারকে উল্লেখযোগ্যভাবে সঙ্কুচিত করার প্রতিশ্রুতি দেয়। ভবিষ্যতে, আমরা আশা করব ব্রাউজারগুলি AV1-এর জন্য নেটিভ সাপোর্ট পাঠাবে, কিন্তু সৌভাগ্যবশত কম্প্রেসার এবং ডিকম্প্রেসারের জন্য সোর্স কোড ওপেন সোর্স , যা এটিকে WebAssembly-এ কম্পাইল করার চেষ্টা করার জন্য একটি আদর্শ প্রার্থী করে তোলে যাতে আমরা এটির সাথে পরীক্ষা করতে পারি ব্রাউজার

খরগোশ সিনেমার ছবি।

ব্রাউজারে ব্যবহারের জন্য মানিয়ে নেওয়া

এই কোডটি ব্রাউজারে পাওয়ার জন্য আমাদের প্রথমে যা করতে হবে তা হল এপিআই কেমন তা বোঝার জন্য বিদ্যমান কোডটি জানা। এই কোডটি প্রথম দেখার সময়, দুটি জিনিস আলাদা হয়:

  1. উৎস গাছটি cmake নামক একটি টুল ব্যবহার করে নির্মিত হয়; এবং
  2. এমন অনেকগুলি উদাহরণ রয়েছে যেগুলি সকলেই কিছু ধরণের ফাইল-ভিত্তিক ইন্টারফেস ধরে নেয়।

ডিফল্টরূপে তৈরি করা সমস্ত উদাহরণ কমান্ড লাইনে চালানো যেতে পারে এবং সম্প্রদায়ে উপলব্ধ অন্যান্য কোড বেসগুলিতে এটি সত্য হতে পারে। সুতরাং, আমরা ব্রাউজারে চালানোর জন্য যে ইন্টারফেসটি তৈরি করতে যাচ্ছি তা অন্য অনেক কমান্ড লাইন টুলের জন্য উপযোগী হতে পারে।

সোর্স কোড তৈরি করতে 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 টুলচেইন দুটি ফরম্যাটে আউটপুট তৈরি করতে পারে, একটিকে বলা হয় 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 জন্য পাস করে। নীচের কমান্ড লাইনটি আমরা মেকফাইলস তৈরি করতে ব্যবহার করি:

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

AV1 লাইব্রেরি সোর্স ফাইলের অবস্থানের সম্পূর্ণ পাথে প্যারামিটার path/to/aom সেট করা উচিত। 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) ফাইলে পাওয়া যাবে [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 প্রকারটি জাভাস্ক্রিপ্টের দিক থেকে অস্বচ্ছ, এবং শুধুমাত্র ইন্টারফেসকে এনক্যাপসুলেট করতে কাজ করে। দ্রষ্টব্য, যে একটি API তৈরি করা যা ফাইলের শব্দার্থবিদ্যাকে ঘনিষ্ঠভাবে অনুসরণ করে তা অন্য অনেক কোড-বেসগুলিতে পুনঃব্যবহার করা সহজ করে যা একটি কমান্ড লাইন (যেমন 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 লাইব্রেরির ইন্টারফেস হিসাবে একটি স্ট্রিম ভিত্তিক API অনুকরণ করছি। সুতরাং, যৌক্তিকভাবে এটি একটি টেস্ট হার্নেস তৈরি করা বোধগম্য হয় যা আমরা আমাদের API-এর একটি সংস্করণ তৈরি করতে ব্যবহার করতে পারি যা কমান্ড লাইনে চলে এবং প্রকৃত ফাইল I/O কে আমাদের DATA_Source API-এর নীচে 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 টেক্সচার RGB ছবি, প্রতি রঙ চ্যানেলে এক বাইট। আমাদের AV1 ডিকোডার থেকে আউটপুট হল একটি তথাকথিত YUV ফর্ম্যাটে ছবি, যেখানে ডিফল্ট আউটপুট প্রতি চ্যানেলে 16 বিট থাকে, এবং প্রতিটি U বা V মান প্রকৃত আউটপুট চিত্রের 4 পিক্সেলের সাথে মিলে যায়। এর অর্থ হল আমরা ওয়েবজিএল-এ প্রদর্শনের জন্য পাস করার আগে ছবিটিকে রঙিন রূপান্তর করতে হবে।

এটি করার জন্য, আমরা একটি ফাংশন AVX_YUV_to_RGB() প্রয়োগ করি যা আপনি yuv-to-rgb.c সোর্স ফাইলে খুঁজে পেতে পারেন। এই ফাংশনটি AV1 ডিকোডার থেকে আউটপুটকে এমন কিছুতে রূপান্তর করে যা আমরা WebGL-এ পাস করতে পারি। দ্রষ্টব্য, যখন আমরা জাভাস্ক্রিপ্ট থেকে এই ফাংশনটিকে কল করি তখন আমাদের নিশ্চিত করতে হবে যে আমরা যে মেমরিতে রূপান্তরিত চিত্রটি লিখছি সেটি 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 এ পাওয়া যাবে।

ভবিষ্যত কাজ এবং takeaways

দুটি পরীক্ষামূলক ভিডিও ফাইলে (24 fps ভিডিও হিসাবে রেকর্ড করা) আমাদের ডেমো চেষ্টা করা আমাদের কয়েকটি জিনিস শেখায়:

  1. WebAssembly ব্যবহার করে ব্রাউজারে কার্যকরীভাবে চালানোর জন্য একটি জটিল কোড-বেস তৈরি করা সম্পূর্ণরূপে সম্ভব; এবং
  2. WebAssembly-এর মাধ্যমে উন্নত ভিডিও ডিকোডিংয়ের মতো CPU-এর মতো নিবিড় কিছু করা সম্ভব।

যদিও কিছু সীমাবদ্ধতা আছে: বাস্তবায়ন সবই প্রধান থ্রেডে চলছে এবং আমরা সেই একক থ্রেডে পেইন্টিং এবং ভিডিও ডিকোডিং আন্তঃলিভ করি। একটি ওয়েব কর্মীতে ডিকোডিং অফলোড করা আমাদের মসৃণ প্লেব্যাক প্রদান করতে পারে, কারণ ফ্রেমগুলি ডিকোড করার সময়টি সেই ফ্রেমের বিষয়বস্তুর উপর অত্যন্ত নির্ভরশীল এবং কখনও কখনও আমাদের বাজেটের চেয়ে বেশি সময় নিতে পারে৷

WebAssembly-এ সংকলন একটি জেনেরিক CPU প্রকারের জন্য AV1 কনফিগারেশন ব্যবহার করে। যদি আমরা একটি জেনেরিক সিপিইউ-এর জন্য কমান্ড লাইনে স্থানীয়ভাবে কম্পাইল করি আমরা WebAssembly সংস্করণের মতো ভিডিও ডিকোড করার জন্য একই রকম CPU লোড দেখতে পাই, তবে AV1 ডিকোডার লাইব্রেরিতে SIMD বাস্তবায়ন অন্তর্ভুক্ত রয়েছে যা 5 গুণ দ্রুত চলে। WebAssembly কমিউনিটি গ্রুপ বর্তমানে SIMD প্রিমিটিভস অন্তর্ভুক্ত করার জন্য স্ট্যান্ডার্ড প্রসারিত করার জন্য কাজ করছে, এবং যখন এটি আসে তখন এটি যথেষ্ট পরিমাণে ডিকোডিং গতি বাড়ানোর প্রতিশ্রুতি দেয়। যখন এটি ঘটবে, তখন একটি WebAssembly ভিডিও ডিকোডার থেকে রিয়েল-টাইমে 4k HD ভিডিও ডিকোড করা সম্পূর্ণরূপে সম্ভব হবে৷

যাই হোক না কেন, উদাহরণ কোডটি একটি নির্দেশিকা হিসাবে কার্যকর যেকোন বিদ্যমান কমান্ড লাইন ইউটিলিটিকে একটি WebAssembly মডিউল হিসাবে চালানোর জন্য পোর্ট করতে সাহায্য করে এবং দেখায় যে আজকে ওয়েবে কী সম্ভব।

ক্রেডিট

মূল্যবান পর্যালোচনা এবং প্রতিক্রিয়া প্রদানের জন্য জেফ পসনিক, এরিক বিডেলম্যান এবং টমাস স্টেইনারকে ধন্যবাদ।