SurfaceTexture

SurfaceTexture ترکیبی از یک سطح و یک بافت OpenGL ES (GLES) است. نمونه‌های SurfaceTexture برای ارائه سطوحی که به بافت‌های GLES خروجی می‌دهند، استفاده می‌شوند.

SurfaceTexture شامل نمونه‌ای از BufferQueue است که برنامه‌ها مصرف‌کننده آن هستند. تابع فراخوانی onFrameAvailable() به برنامه‌ها اطلاع می‌دهد که تولیدکننده چه زمانی یک بافر جدید را در صف قرار می‌دهد. سپس، برنامه‌ها تابع updateTexImage() را فراخوانی می‌کنند که بافر قبلی را آزاد می‌کند، بافر جدید را از صف دریافت می‌کند و فراخوانی‌های EGL را انجام می‌دهد تا بافر را به عنوان یک بافت خارجی در دسترس GLES قرار دهد.

بافت‌های خارجی GLES

بافت‌های خارجی GLES ( GL_TEXTURE_EXTERNAL_OES ) با بافت‌های استاندارد GLES ( GL_TEXTURE_2D ) از جهات زیر متفاوت هستند:

  • بافت‌های خارجی، چندضلعی‌های بافت‌دار را مستقیماً از داده‌های دریافتی از BufferQueue رندر می‌کنند.
  • رندرکننده‌های بافت خارجی متفاوت از رندرکننده‌های بافت استاندارد GLES پیکربندی می‌شوند.
  • بافت‌های خارجی نمی‌توانند تمام فعالیت‌های بافت استاندارد GLES را انجام دهند.

مزیت اصلی بافت‌های خارجی، قابلیت رندر مستقیم آنها از داده‌های BufferQueue است. نمونه‌های SurfaceTexture هنگام ایجاد نمونه‌های BufferQueue برای بافت‌های خارجی، پرچم‌های استفاده از مصرف‌کننده را روی GRALLOC_USAGE_HW_TEXTURE تنظیم می‌کنند تا تأیید کنند که داده‌های موجود در بافر توسط GLES قابل تشخیص هستند.

از آنجا که نمونه‌های SurfaceTexture با یک زمینه EGL تعامل دارند، یک برنامه فقط می‌تواند متدهای خود را فراخوانی کند در حالی که زمینه EGL که مالک بافت است، در نخ فراخوانی کننده موجود باشد. برای اطلاعات بیشتر، به مستندات کلاس SurfaceTexture مراجعه کنید.

مهرهای زمانی و تبدیل‌ها

نمونه‌های SurfaceTexture شامل متد getTimeStamp() هستند که یک مهر زمانی را بازیابی می‌کند و متد getTransformMatrix() که یک ماتریس تبدیل را بازیابی می‌کند. فراخوانی updateTexImage() هم مهر زمانی و هم ماتریس تبدیل را تنظیم می‌کند. هر بافری که BufferQueue ارسال می‌کند شامل پارامترهای تبدیل و یک مهر زمانی است.

پارامترهای تبدیل برای افزایش کارایی مفید هستند. در برخی موارد، داده‌های منبع ممکن است در جهت نادرستی برای مصرف‌کننده باشند. به جای چرخاندن داده‌ها قبل از ارسال به مصرف‌کننده، داده‌ها را در جهت خود به همراه تبدیلی که آن را اصلاح می‌کند، ارسال کنید. ماتریس تبدیل را می‌توان هنگام استفاده از داده‌ها با سایر تبدیل‌ها ادغام کرد و سربار را به حداقل رساند.

برچسب زمانی برای منابع بافر که وابسته به زمان هستند مفید است. برای مثال، وقتی setPreviewTexture() رابط تولیدکننده را به خروجی دوربین متصل می‌کند، می‌توان از فریم‌های دوربین برای ایجاد یک ویدیو استفاده کرد. هر فریم باید یک برچسب زمانی ارائه از زمانی که فریم گرفته شده است داشته باشد، نه از زمانی که برنامه فریم را دریافت کرده است. کد دوربین، برچسب زمانی ارائه شده با بافر را تنظیم می‌کند و در نتیجه مجموعه‌ای از برچسب‌های زمانی سازگارتر ایجاد می‌شود.

مطالعه موردی: ثبت مداوم تصاویر توسط گرافیکا

ضبط مداوم گرافیکا شامل ضبط فریم‌ها از دوربین دستگاه و نمایش آن فریم‌ها روی صفحه است. برای ضبط فریم‌ها، با استفاده از متد createInputSurface() از کلاس MediaCodec یک سطح ایجاد کنید و سطح را به دوربین منتقل کنید. برای نمایش فریم‌ها، یک نمونه از SurfaceView ایجاد کنید و سطح را به setPreviewDisplay() منتقل کنید. توجه داشته باشید که ضبط فریم‌ها و نمایش همزمان آنها فرآیند پیچیده‌تری است.

فعالیت ضبط مداوم، ویدئو را از دوربین همزمان با ضبط نمایش می‌دهد. در این حالت، ویدئوی کدگذاری شده در یک بافر دایره‌ای در حافظه نوشته می‌شود که می‌تواند در هر زمانی روی دیسک ذخیره شود.

این جریان شامل سه صف بافر است:

  • App - این برنامه از یک نمونه SurfaceTexture برای دریافت فریم‌ها از دوربین و تبدیل آنها به یک بافت خارجی GLES استفاده می‌کند.
  • SurfaceFlinger - برنامه یک نمونه SurfaceView را برای نمایش فریم‌ها اعلان می‌کند.
  • MediaServer — یک رمزگذار MediaCodec را با یک سطح ورودی برای ایجاد ویدیو پیکربندی کنید.

در شکل زیر، فلش‌ها نشان‌دهنده‌ی انتشار داده‌ها از دوربین هستند. نمونه‌های BufferQueue با نشانگرهای بصری که تولیدکنندگان (سبز) را از مصرف‌کنندگان (سبز) متمایز می‌کنند، نشان داده شده‌اند.

فعالیت ضبط مداوم گرافیکا

شکل ۱. فعالیت مداوم گرافیکا در ثبت تصاویر

ویدیوی کدگذاری شده H.264 در فرآیند برنامه به یک بافر دایره‌ای در RAM می‌رود. وقتی کاربر دکمه ضبط را فشار می‌دهد، کلاس MediaMuxer ویدیوی کدگذاری شده را در یک فایل MP4 روی دیسک می‌نویسد.

تمام نمونه‌های BufferQueue با یک زمینه EGL واحد در برنامه مدیریت می‌شوند در حالی که عملیات GLES روی نخ UI انجام می‌شود. مدیریت داده‌های رمزگذاری شده (مدیریت بافر دایره‌ای و نوشتن آن روی دیسک) در یک نخ جداگانه انجام می‌شود.

هنگام استفاده از کلاس SurfaceView ، تابع فراخوانی surfaceCreated() نمونه‌های EGLContext و EGLSurface را برای نمایشگر و رمزگذار ویدئو ایجاد می‌کند. وقتی یک فریم جدید می‌رسد، SurfaceTexture چهار فعالیت انجام می‌دهد:

  1. قاب را به دست می‌آورد.
  2. قاب را به عنوان یک بافت GLES در دسترس قرار می‌دهد.
  3. فریم را با دستورات GLES رندر می‌کند.
  4. تبدیل و برچسب زمانی را برای هر نمونه از EGLSurface ارسال می‌کند.

سپس رشته‌ی رمزگذار، خروجی رمزگذاری شده را از MediaCodec دریافت کرده و آن را در حافظه ذخیره می‌کند.

پخش ویدیوی بافت امن

اندروید از پردازش پس از پردازش محتوای ویدیویی محافظت‌شده توسط پردازنده گرافیکی (GPU) پشتیبانی می‌کند. این قابلیت به برنامه‌ها اجازه می‌دهد تا از پردازنده گرافیکی (GPU) برای جلوه‌های ویدیویی پیچیده و غیرخطی (مانند اعوجاج)، نگاشت محتوای ویدیویی محافظت‌شده به بافت‌ها برای استفاده در صحنه‌های گرافیکی عمومی (به عنوان مثال، با استفاده از GLES) و واقعیت مجازی (VR) استفاده کنند.

پخش ویدیوی بافت امن

شکل ۲. پخش ویدیوی بافت امن

پشتیبانی با استفاده از دو افزونه زیر فعال می‌شود:

  • افزونه‌ی EGL — ( EGL_EXT_protected_content ) ایجاد زمینه‌ها و سطوح GL محافظت‌شده را امکان‌پذیر می‌کند، که هر دو می‌توانند روی محتوای محافظت‌شده عمل کنند.
  • افزونه‌ی GLES — ( GL_EXT_protected_textures ) برچسب‌گذاری بافت‌ها به عنوان محافظت‌شده را فعال می‌کند تا بتوان از آن‌ها به عنوان پیوست‌های بافت فریم‌بافر استفاده کرد.

اندروید SurfaceTexture و ACodec ( libstagefright.so ) را قادر می‌سازد تا محتوای محافظت‌شده را ارسال کنند، حتی اگر سطح پنجره در صف SurfaceFlinger قرار نگیرد و یک سطح ویدیویی محافظت‌شده برای استفاده در یک زمینه محافظت‌شده فراهم می‌کند. این کار با تنظیم بیت مصرف‌کننده محافظت‌شده ( GRALLOC_USAGE_PROTECTED ) روی سطوح ایجاد شده در یک زمینه محافظت‌شده (تأیید شده توسط ACodec) انجام می‌شود.

پخش ویدیوی بافت امن، پایه و اساس پیاده‌سازی قوی مدیریت حقوق دیجیتال (DRM) را در محیط OpenGL ES ایجاد می‌کند. بدون پیاده‌سازی قوی DRM، مانند Widevine Level 1، بسیاری از ارائه‌دهندگان محتوا اجازه رندر محتوای ارزشمند خود را در محیط OpenGL ES نمی‌دهند و از موارد مهم استفاده از واقعیت مجازی مانند تماشای محتوای محافظت‌شده با DRM در واقعیت مجازی جلوگیری می‌کنند.

پروژه متن‌باز اندروید (AOSP) شامل کد چارچوب برای پخش ویدیوی بافت امن است. پشتیبانی از درایور به تولیدکنندگان اصلی تجهیزات (OEM) بستگی دارد. پیاده‌سازی‌کنندگان دستگاه باید افزونه‌های EGL_EXT_protected_content و GL_EXT_protected_textures را پیاده‌سازی کنند. هنگام استفاده از کتابخانه کدک خودتان (برای جایگزینی libstagefright )، به تغییرات در /frameworks/av/media/libstagefright/SurfaceUtils.cpp توجه کنید که اجازه می‌دهد بافرهای مشخص شده با GRALLOC_USAGE_PROTECTED به ANativeWindow ارسال شوند (حتی اگر ANativeWindow مستقیماً در صف آهنگساز پنجره قرار نگیرد) تا زمانی که بیت‌های استفاده مصرف‌کننده حاوی GRALLOC_USAGE_PROTECTED باشند. برای مستندات دقیق در مورد پیاده‌سازی افزونه‌ها، به رجیستری‌های Khronos ( EGL_EXT_protected_content ) و ( GL_EXT_protected_textures ) مراجعه کنید.