TextureView

کلاس TextureView یک شی view است که یک view را با یک SurfaceTexture ترکیب می کند.

رندر با OpenGL ES

یک شی TextureView یک SurfaceTexture را می‌پیچد، به تماس‌ها پاسخ می‌دهد و بافرهای جدیدی را به دست می‌آورد. هنگامی که یک TextureView بافرهای جدیدی را به دست می آورد، یک TextureView یک درخواست بی اعتباری نما صادر می کند و با استفاده از محتویات جدیدترین بافر به عنوان منبع داده، ترسیم می کند، هر کجا و هر طور که وضعیت view نشان می دهد که باید ارائه شود.

OpenGL ES (GLES) می‌تواند با ارسال SurfaceTexture به فراخوانی ایجاد EGL در یک TextureView رندر شود، اما این مشکل ایجاد می‌کند. وقتی GLES در یک TextureView رندر می‌شود، تولیدکنندگان و مصرف‌کنندگان BufferQueue در یک رشته قرار می‌گیرند، که می‌تواند باعث توقف یا شکست فراخوانی تعویض بافر شود. به عنوان مثال، اگر یک تولیدکننده چندین بافر را پشت سر هم از رشته UI ارسال کند، فراخوانی تعویض بافر EGL باید یک بافر را از BufferQueue حذف کند. با این حال، از آنجایی که مصرف‌کننده و تولیدکننده در یک رشته هستند، هیچ بافری در دسترس نخواهد بود و تماس مبادله قطع می‌شود یا با شکست مواجه می‌شود.

برای اطمینان از اینکه تعویض بافر متوقف نمی شود، BufferQueue همیشه به یک بافر در دسترس نیاز دارد تا در صف قرار گیرد. برای اجرای این، BufferQueue محتویات بافری را که قبلاً به دست آورده بود، هنگامی که یک بافر جدید در صف قرار می‌گیرد دور می‌اندازد و محدودیت‌هایی را روی حداقل و حداکثر تعداد بافرها اعمال می‌کند تا از مصرف یکباره همه بافرها توسط مصرف‌کننده جلوگیری شود.

انتخاب SurfaceView یا TextureView

SurfaceView و TextureView نقش های مشابهی را پر می کنند و هر دو شهروند سلسله مراتب view هستند. با این حال، SurfaceView و TextureView پیاده سازی های متفاوتی دارند. یک SurfaceView پارامترهای مشابه سایر نماها را می گیرد، اما محتویات SurfaceView هنگام رندر شفاف هستند.

یک TextureView کنترل آلفا و چرخش بهتری نسبت به SurfaceView دارد، اما SurfaceView هنگام ترکیب عناصر UI لایه‌بندی شده روی ویدیوها، مزایای عملکردی دارد. هنگامی که یک کلاینت با SurfaceView رندر می کند، SurfaceView یک لایه ترکیب جداگانه را در اختیار مشتری قرار می دهد. SurfaceFlinger لایه جداگانه را به عنوان یک پوشش سخت افزاری در صورت پشتیبانی توسط دستگاه می سازد. هنگامی که یک کلاینت با یک TextureView رندر می کند، جعبه ابزار UI محتوای TextureView را در سلسله مراتب view با GPU ترکیب می کند. به‌روزرسانی‌های محتوا ممکن است باعث ترسیم دیگر عناصر نمای شود، برای مثال، اگر نماهای دیگر در بالای یک TextureView قرار گیرند. پس از تکمیل رندر نمایش، SurfaceFlinger لایه رابط کاربری برنامه و تمام لایه‌های دیگر را ترکیب می‌کند، به طوری که هر پیکسل قابل مشاهده دو بار ترکیب می‌شود.

مطالعه موردی: ویدیوی Play Grafika

Play Video Grafika شامل یک جفت پخش کننده ویدیو است که یکی با TextureView و دیگری با SurfaceView پیاده سازی شده است. بخش رمزگشایی ویدیو از فعالیت، فریم‌هایی را از MediaCodec به سطحی برای TextureView و SurfaceView ارسال می‌کند. بزرگترین تفاوت بین پیاده سازی ها مراحل مورد نیاز برای ارائه نسبت تصویر صحیح است.

مقیاس گذاری SurfaceView به پیاده سازی سفارشی FrameLayout نیاز دارد. WindowManager باید موقعیت پنجره جدید و مقادیر اندازه جدید را به SurfaceFlinger ارسال کند. مقیاس بندی SurfaceTexture یک TextureView نیاز به پیکربندی یک ماتریس تبدیل با TextureView#setTransform() دارد.

پس از ارائه نسبت تصویر صحیح، هر دو پیاده سازی از یک الگو پیروی می کنند. وقتی SurfaceView/TextureView سطح را ایجاد می کند، کد برنامه پخش را فعال می کند. هنگامی که کاربر روی پخش ضربه می زند، یک رشته رمزگشایی ویدیو را شروع می کند که سطح آن به عنوان هدف خروجی است. پس از آن، کد برنامه کاری انجام نمی دهد - ترکیب و نمایش توسط SurfaceFlinger (برای SurfaceView) یا توسط TextureView مدیریت می شود.

مطالعه موردی: رمزگشایی دوگانه Grafika

رمزگشایی دوگانه Grafika دستکاری SurfaceTexture را در داخل یک TextureView نشان می دهد.

رمزگشایی دوبل Grafika از یک جفت آبجکت TextureView برای نمایش دو ویدیو در حال پخش در کنار هم استفاده می‌کند و یک برنامه کنفرانس ویدیویی را شبیه‌سازی می‌کند. هنگامی که جهت صفحه تغییر می کند و فعالیت مجدداً راه اندازی می شود، رمزگشاهای MediaCodec متوقف نمی شوند و پخش یک جریان ویدیویی بلادرنگ را شبیه سازی می کنند. برای بهبود کارایی، مشتری باید سطح را زنده نگه دارد. سطح یک دسته برای رابط سازنده در BufferQueue SurfaceTexture است. از آنجایی که TextureView SurfaceTexture را مدیریت می کند، مشتری باید SurfaceTexture را زنده نگه دارد تا سطح را زنده نگه دارد.

برای زنده نگه داشتن SurfaceTexture، Double Decode Grafika ارجاع به SurfaceTextures را از اشیاء TextureView دریافت می کند و آنها را در یک فیلد ثابت ذخیره می کند. سپس، Double Decode Grafika، false از TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed() برمی گرداند تا از تخریب SurfaceTexture جلوگیری کند. سپس TextureView یک SurfaceTexture را به onSurfaceTextureDestroyed() می‌فرستد که می‌تواند در تغییرات پیکربندی فعالیت حفظ شود، که مشتری از طریق setSurfaceTexture() به TextureView جدید منتقل می‌کند.

رشته‌های جداگانه هر رمزگشای ویدیویی را هدایت می‌کنند. Mediaserver بافرهایی را با خروجی رمزگشایی شده به SurfaceTextures، مصرف کنندگان BufferQueue می فرستد. اشیاء TextureView رندر و اجرا را روی رشته UI انجام می دهند.

پیاده‌سازی دو رمزگشایی Grafika با SurfaceView سخت‌تر از پیاده‌سازی با TextureView است زیرا اشیاء SurfaceView سطوح را در طول تغییر جهت‌گیری از بین می‌برند. علاوه بر این، استفاده از اشیاء SurfaceView دو لایه اضافه می کند که به دلیل محدودیت در تعداد پوشش های موجود بر روی سخت افزار، ایده آل نیست.