From 4b6ce3edff3fdffce323835371e1aa27fdefb3be Mon Sep 17 00:00:00 2001 From: edubinskaya Date: Tue, 13 Jun 2023 11:42:50 +0300 Subject: [PATCH] supported preview in DivVideo --- .../java/com/yandex/div/video/ExoDivPlayer.kt | 2 +- .../com/yandex/div/core/player/DivPlayer.kt | 5 +++ .../div/core/view2/divs/DivVideoBinder.kt | 31 +++++++++++++++++++ .../core/view2/divs/widgets/DivVideoView.kt | 4 +-- .../video/video_with_controls.json | 1 + 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/client/android/div-video/src/main/java/com/yandex/div/video/ExoDivPlayer.kt b/client/android/div-video/src/main/java/com/yandex/div/video/ExoDivPlayer.kt index a9f54ba04..56cfb9775 100644 --- a/client/android/div-video/src/main/java/com/yandex/div/video/ExoDivPlayer.kt +++ b/client/android/div-video/src/main/java/com/yandex/div/video/ExoDivPlayer.kt @@ -48,13 +48,13 @@ class ExoDivPlayer( } override fun onPlaybackStateChanged(state: Int) { - if (state != Player.STATE_BUFFERING && state != Player.STATE_ENDED) return if (state == Player.STATE_ENDED) needToRenderFrameExplicitly = true observers.forEach { when (state) { Player.STATE_BUFFERING -> it.onBuffering() Player.STATE_ENDED -> it.onEnd() + Player.STATE_READY -> it.onReady() else -> Unit } } diff --git a/client/android/div/src/main/java/com/yandex/div/core/player/DivPlayer.kt b/client/android/div/src/main/java/com/yandex/div/core/player/DivPlayer.kt index dbf2e1393..827e9adb0 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/player/DivPlayer.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/player/DivPlayer.kt @@ -10,6 +10,11 @@ interface DivPlayer { */ fun onPlay() = Unit + /** + * Called when player video is ready to show. + */ + fun onReady() = Unit + /** * Called when playback has been paused by an action. */ diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivVideoBinder.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivVideoBinder.kt index d39fbf892..7e73f0843 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivVideoBinder.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/DivVideoBinder.kt @@ -1,5 +1,13 @@ package com.yandex.div.core.view2.divs +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.util.Base64 +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView import com.yandex.div.core.DivActionHandler import com.yandex.div.core.dagger.DivScope import com.yandex.div.core.expression.variables.TwoWayIntegerVariableBinder @@ -45,7 +53,20 @@ internal class DivVideoBinder @Inject constructor( ) val playerView = divView.div2Component.divVideoFactory.makePlayerView(view.context) + val preview = div.createPreview(resolver) + val previewImageView: ImageView = ImageView(view.context).apply { + layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + scaleType = ImageView.ScaleType.FIT_CENTER + if (preview != null) { + visibility = View.VISIBLE + setImageBitmap(preview) + } else { + visibility = View.INVISIBLE + } + setBackgroundColor(Color.TRANSPARENT) + } view.addView(playerView) + view.addView(previewImageView) playerView.attach(player) @@ -70,6 +91,10 @@ internal class DivVideoBinder @Inject constructor( divView.let { divActionHandler.handleAction(divAction, it) } } } + + override fun onReady() { + previewImageView.visibility = View.INVISIBLE + } } player.addObserver(playerListener) @@ -120,3 +145,9 @@ fun DivVideo.createSource(resolver: ExpressionResolver): List { ) } } + +fun DivVideo.createPreview(resolver: ExpressionResolver): Bitmap? { + val base64String = preview?.evaluate(resolver) ?: return null + val imageBytes = Base64.decode(base64String, Base64.DEFAULT) + return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) +} diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivVideoView.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivVideoView.kt index 026e98b2c..ed1e47053 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivVideoView.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivVideoView.kt @@ -97,8 +97,8 @@ internal class DivVideoView @JvmOverloads constructor( } fun getPlayerView(): DivPlayerView? { - if (this.childCount > 1) { - KAssert.fail { "More than one player view inside DivVideo" } + if (this.childCount > 2) { + KAssert.fail { "Too many children in DivVideo" } } this.getChildAt(0)?.let { if (it !is DivPlayerView) { diff --git a/test_data/regression_test_data/video/video_with_controls.json b/test_data/regression_test_data/video/video_with_controls.json index 9419822b0..3c869f0fb 100644 --- a/test_data/regression_test_data/video/video_with_controls.json +++ b/test_data/regression_test_data/video/video_with_controls.json @@ -31,6 +31,7 @@ { "type": "video", "id": "bears_video", + "preview": "iVBORw0KGgoAAAANSUhEUgAAAFUAAAAtCAIAAABQ5rChAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGYktHRAD/AP8A/6C9p5MAAAAHdElNRQfnBgYLFBxbRE8dAAAZKklEQVRo3l16aY8kOZKdHTz8iIw86+ienunV7CUBq///WyQBi9GOpqe6qyoz43J3knboAyNzG+tAAIlIwoNGM3v27BnxD4+PM5GDn9wRABHdHRHNPSDMzITo7sXcwBkxITKRA5ybVDNAdDMAAERCBABzJ8T+Hnh73l/r7g5wQ/Tz7U11/3K+iDojAjogJqIhcAohMAIgiLp5NXuprZoBgjlEwj1zEiN1AHQEAgB3AHBEcFB0BjgTnsDRPQIyeEAkh74muSckjeSE4SkwGRzACcChfwAAEMAdxJ0cFNwB3EHBK0Dy62IHIIAc4xDjfsoP87SW+tvx9LqWt5egQzcZELF/6e5k/vp8WhEaef8GAYmQiQygiGwCYwiRUM0RwNwVHB3NHR3dAR0IwBAQHB0MEQGo/xBgt4MQEAANCMAdHBwAzQ0AgREcwSCMzGR6dkDsi+Btn2AAmzmBOwABEoIBiIObEYCDP+2mp5vdfsx385hTioFP58uPD/t///X5ry+HbuzvLQd3d59juE8pILioiAJDBDJwBRA3U3BAAB+YofsMuzeQEfvbCAAdAAB7zAKg+/u+CUAIjRwN0BHhGogGAAiEyAYIAOiEFGoVdjAC62/E91BCdzd3u3rS9zkD4W/LCo5T5B/2u3/4+JiYSynrspRtM/et1Nv9zb/88FRa+/V0gbcdu/tbOuAuxTzlpsqIA0JkBoBDaUUNETJT6KcLAG5EiPoWOG9BxdBd7IQIgA6O7/9HNMQFvbl7jwh3QOw2EfR0uKYkEYYLOCIUd3hz0ru7ENHNezzNiBPAAjDHOMfwOI9300CIv768MkBKUc1UTUQv2/dpSI9jflnWrSkR+hVZru9+Wcultl1ODrCKBvciemqCb9ZNITEiIyIimL773AG6qYSAcLUKEcDBHQgxjBGZlirF1AAc3m3q8AIMEK7p4ITIhKH19MLrovdTvEYNIQKYOROKGiD/8W4XkcyhqrV1q1VSDGtpTcQdRBUAl60x48M42AhmZuZ38xiYSmmltXOTn+73//D5Y1M9XBY1X0q51GbmOYY5xSmlwARuZrau5XBZzRzAyAmQmIgBERD6Hq97dwycdqObaW194+pv9jggAoEzIAN0RGEHRAzsyAgKvpn/54G5A0AgBHcCeJqHj/t5ZG6q7n7e6iYytshXR0ATVTVzFzNGcvStyR8/PHx+ethKU9WbeULE1tpW2lrq3X7e3+wQ8ePjfWsiIk1UVZgZEQGQiZqKme53M8XjBtDURLWKqkgzZDUEIGbojkKEyIuIrFXMFNwcCIAAEcEBDYAdEEEIo11RA9xDA1cAQtwFToEJ0MHVnBDvhoREU06PN7sQiIhO5+X5eLrUlpgDkwNupapZE6uigcncDTQwRaLdON7f7psouFPgN2R2N+9J5WaASIFBLQTMOZm5qHZ/DcOgog7+U84/ff4EiKU1EW0iy/HsVaS1y3ExgBaImFIMW2soggCESAAGLuDoAOTooAgFAdAjwT4FInSHsBsSI0Tm/ZhSYAAEdyJCwsiUUxrH0cy+Pr/e7W+GIbeXgzswkbmbWSQSsU2EkNw9B56HDIjLujmAOSCiqPEbrJj1Y3BVr7XGGMBdVR2ciBB7OkNrLcbw+dOHX78/T+PwdH+/blut1dyPp9M5sYqK6G6/++3v36vrBmCtqRkBOkIiRIBFdYMrfr19nBzmEDB2DPVwM6QpMACkEGIgZgYAJmIiNXN3ESEiMXs5XX76+Hi/38nL0dxqcyZkxuaQQ8iBhxTmMQ8pxRi/vhzc/Xw+m3ltbZ6mGIM7qCoiEpGqbqX0goyEBFRrBXQzN7Oc0rptX19exiHP03haluPp3GrbSnk+HNZSCTFGZuY10aUIubGguK9gqaMDQEBEBPUeT73kORFOgRixZ3sAcEJqqlXEnRNiZHazqgqIZqZmgdncn1+Pl3WLhCmw2ns5wyFwU2Oi+5u5o0cMYb+bv728rutamzCTm5m7qakZEqUYz8vi7nc3oCop58P5/PX5kCL/05/+OAzZ3Y/n0+F4AoDn18N+t5vH4f+9viLAkPPxslbRSaN5PYoA4gMzIi6qm4ICiGqvt9fPGxtFgCmGKYQ3pMeg5uZqbtKgiZWmSNAdlWPMkUWNmBLRFOPpvMwpjmMuor2E9KLmBjGGnJKaVZHX88XMmMN52bbaphy/Pr+ae2Qqqr++XoigNp2HBIhfX47M/Hy+1Cb/8scfpjEjYqmiqmqmos+vh9P5HJi3UpmpNXV3UbtsJTLvUqhNnJCAiPwhhpxCUb1snTJ7s85jwADmFP/p01Ni+v7tAOZIGKpYIVuaNFV1t3dsRIhcpxjMITLNOXKgEHi3m2Lgy3YGRGJQczUvqr6Vm63uxlxq+/p6QgQmBoBxSKp2vKxM5DmoelPVZuKuW/3b15eXZXV3Mfvx4faHp4fD6XQ4nsdheLi//ctf/7as2zjkIedlWQGhNjXVaUhMuBZpqlMIEamoqokC3BDthvwYg5iVJu4QU9ya/OX769rkfsq3u4mZ17WslxXMQ1M5Fvu2FkQwBwbMjAHRzY9Vj6UBwC6GHPluHh73cxWtpVbTc2mR2cGr2Kpqqz+v5dPt7nbIKYYvh5Op3Y5DjzpGUFXdPBBGIjcLiKXJs0jHocx8M+R1XVtrL8fTUtplXc/Lysy7eXbwy1YIEYmaaI5hylnNmygiBuYiIt3LBPOYp3HiwCISiKd5AvOc0v/626/oYGY5508fn55fXl8Pp1BEc+h9WyfrDoDqHokSuCOMgechDynGEABxXde1NkZiIjEDRA40Mjb141YOW4lEmWg35pgQEZbSdjmFQKVJRBxS+hCjuqu5uosoE6YYppyfbneism7baS0UIjXvMHw8X5pqaQpu5h4Dq9lbrYDzVqtZZ3A58MN+t7/ZDcN45RFMRESEf/r0dDiexxyHnJk5p3xrVkWCAbh7JKx2JYEBkRB3OX3McUhxTCGlGDgg4raVKtJU1PxuGjJTimFIqdRWTcXxdV1V9HbIH+9uROT1vALC2traAAF2Y/704WG/24XIiOgGTQQRUorgcL4s58ulNHV3dMsxi8iylSYCgEiAgClwDEHUtFmtYgiB6fPj7a8vx1LaD/d3Hx8fck4xRUIk6p2xmRkz//TxYczDOIwduIeUPj49BEJ0xMy8aSPEx2m4H3JgjIFTCEOK9oagTOSAZjblHGNgBOrUyo0IJ47jOMwptFpjCIfzMqQwDenbZV3MphBuhnS/v7m7vR2noTvWOz1ANLfWWgxR1UptN2N217VWQgxMosQEiKjmTQ1cRLUWQYTqvqmetmpq//Tjxx8/fyCmwNyNZyZEbM1VlYg+Pj4gonunrJhyzEMKvTQMgcUtM//hbnczjQDXQg1I1LtWd6KrRMBEBNBE1BwRRTTFEAMv20YAIfBpK6UpIY459RqxH/PPP3y8v92nFBgpcuhcpLuCkSgl3tPL8ZhTmHKqTUqphBCYcmAxc3MTRcR1a2ZmiATAiFOMTfTnnz7/8x9/5MDXttGusoKquTszgRpxb6ChKzHX/g/c1V0APs/TbsxjiteMIYLrOnL3EAIimTsRqmp/czfSwa02IhJXEXW7FhFCrCLUOzmAnNJuNwXmyByYVVXcGAkRmRncc4ifPzyCm4h0irxtrUnrDD8Q5RAA/FRFAYgwxvA4j0NO0zQ+PT5M42DmTOTg19qpKqIdKTqx7BkBQFeBwzzcTUMkMrN5SPOQ6G15ilFV348Kr5zqXR1CBGfC7r2mdlq3HFjUHIAJzdDMWtO+7LTVv375bX8z39/edkFNTFU1RiYiRgQiQgzMiKhqtbaytdYEEGMKQ07mpuqtNkdEwtvd9PnDQynF3c3sfLkMOfVUujIbRCJC1O5wZkbs2YbuvQlxMw+30/B4M6uaqsLvnn4Q718SESG6g5orqBoy4RCDA4gaEYiaKgUidxfzHIMDVLHeBQD48bL+8uXrbprHIXda+S5pmDkiXMr62/fvy7q+nJZtrZFwyDHlmHMCgONlNfOQwuOYeyit63Y4XQLT8XRJp8s0jvM0ibS39goRsZNuMyMiZna3/ltEZGYAEJg5hq6IXDuQ38uV7+HQTzEwEWFpCgBjDIGp6w/u5AidPhFiDuwAS2kAbg5qpoSI+O3l9en19Q+fP9lbZ9HJcseX76+H0/liqk21ugdiM1ezlGIMsbMpNQX33pi0JmupgNhEeS3zb9/+9NMPPRyIqB8AM3es6DltBlezw7UjCz2xAbSfEP5XuQrecgauiPoWIEXUwHMKXZxhQgMIRAhw2uqlNiacY2jmxdzVRu8NvDg4IeaYCAmhbwjdfFtXADDAp/0uxugAKYacUopxK6VntaiJ6FLq9+MlELmDqAAiER2Op9Npf3+3b6L4+1T9nRfNoCNiPwUACO+2vaf6u1T5bjwiElIIIafMxO4SA5t5ExU1BLQ3jbGqNJFFVMwn5KomXbtxB0dzPy+LqkUO5BaHAd+2eLosotqaAPjNbufuTFxbfT0ciHldN1FDQgQsTfrvKhESOCABuvvreTmcL3d3+9+b/S49vzvVvet0DoAhcDD339UD+i8QQEgG7mZdAB6GnFPcamUiBDMHUdtExb3b2WuSuatbs56FMBDdDilHVlG76jZk1rW1/1QczZ2IcooAIKqn86X3QB0pcozN9LKWHEMMQayJGTm+KSoEAMu61tpC4K44ujsgEJKbd1xkppRirdLrAgCE3hz1VLlqvma/29M1WhAwMOcUpyEfLwsiTjltTUQtMbF7JJQuboC7A/VpiEME2A/5w34CxPNlzTEBgIpgj6y3s44xBOaUYs6plKqqbzqdqxkTcQjSukmYAjc1dwuE2FVQAEQopYrIkFMT0Y4CDubWreX+EAcO1wbZPTzc3T7upuN56TzxfUojIv6WCTGGlFOMIaU4TcNwSuMQ3X0tDbq8hhAQGTEwdS1gP+QU6HUpj7e72zGnEETakNM4ZEdUd/Y+iAB6K7e7adpKqbX16t0jwswRyR1ej+cuSVzWwkxVdYwx8jVtTU0NlrVclnWeJhFV1RgCvS0IIbwnNSAwk5m7e/if//0f/+Hzh//7t1//8tdfDsdjX9HrU0+KwMwcYgjMHEK42c3j4dhhEglQwa5hhoBISDkgE+1yGlJ4uLv9/OGplhJjOJ4vW33d7+Y5ZxFFvE6Q1B1VCXHIuedO36j5Gwqji5qYIaKZO4CKRuabaVi2UqpQDzaEJvpyON7d7gNz382VtnNXisGgj6PcereHEFIKD/c3w5DGnP/3v//ll19/sy4qI8YQAnPOOaf0hh+23+1207gsq5ojIAIEJgIgIlEV1S4NLrUhwv5mdz6fETEEnoY8j7lvCCKAg3Xlz90BAlIfOor2xzoAxQitQ8ubKt3HfDFQFWlypTdNrQ8YTuel1HK336vqW3pd6Y6ImjmiM7ObqZm5h9ZkWTYz+/HTo5mvWzmcTr0sdc7PzCFwjH0oiTmlp8eHL/LbupUU2N2rKCIyoTuZqrn3NruK/vr9ZRozAqxryjkR4ZevX0st8zTP49DPt2ONmpVWu6akAIhgBu88+kpX3R1AzSOzqgnqkOLrZdU3JoMAa6nn8yVwEBEzcwdz73+buYhstTY1uvIuC6oqTWuTri79tz/99B9/++VwOr8PcBG60E4xhEAsqrc3N7WUL1+/kRozsRkRvRMDdycgQlxr676dh2Su27aZ6rZtX0UPx3POaR7HEEOKaUixtHZZ1g66MYTamrv2DajZe+aag4OrGRGnwD0vzJ2vra6b+7fn179/fQ5EzHRaSmRU89pkSKGJnLc6j8PT3b7z5aDqambmh9OybGUep88fPriDiDJzSjF21zO7u4EjEjM+PT5WkV++fL3GCOFbjAIT9l71msmAaq5b6TmKSKJipk2llELMIYQQGB2lCTO31moTU3OHGLmJdQkbEdwQ3BhJzdNV5AQmQvdIBODNPIKfl3UtMg2p8+umAA4pxZjiPE9PD/xwtx+HTMSIGDo32mo7r5uINBEHmKZR1VOKqdM7oh6Ebs5Mqo6IHx4fEPDb8+tl6+M2IERCJCQAZyY0yjF8enogxMPpdFpWEU3Mw5DGFEm1qAJiYE4dX94GnOYmZp2n1SZECEgGBuYEyEzNJDCBQ2BCADVn7LNrT8x/+PwpBM4xMjMFUlFCIia+tgBObygL4GHZyq/fXp8Px9JaIC6t1loRMSXma/HoUhMauLqZGDiIippN0wQvR9HOF4DwmoREiIBMuDX5P//xCyKKKoKruxvEteyGNOSYAgNACCGl5O8DWMRukrvrdcILAJACuxkSbqLqRoSM1KvQmzyBzLibhk9PD8OQzZyI1HoL228igLnbtam9gml4eT1pKVtt4zCMOZdam+iQEvZDQ1Sz1loTKVtZS9lKvWyltiai4H7eylolME0xIGIMBA4dAx2gqSJAIN7N436eEHFZtypSRdbz6tCV5XS737fWrkCoWpqIaAjERBiwiUrTwExMjMhoQwiRudc8JsxvwzVG3M3zMGRmjoHM7Y2OQW+6wYxjGnPKKa5bKbWGZVsTgYg2as/tcDxfAMDVq7QmWmo7L+tl3bZaRRTBU2DigIiMsDUBdyI0hxADAObI8ziogamGwESYY3S3GEIIAQE+Pt5/e3l9OZwj6fOylQoIWEVyjKXWa09OpNx5e692mGOoauCAhIEoMgF4FasiCMCI4u7u97c3nz88xRDNjAgBiLhPsQwcmHg3Trt5yCkz0WVd17WE2qTWBoDPr6/H83lICRG/vZ5ezkttTc0CUR/4EOI8jj//+Onf/vXPnWP+8uv3X75+M3VVfXq4TSECQgjBulxlOg5DFTkcjp1vXtYVEOZx2M3j95fj87J2saRWuZlGc2+tMaExJQAzE/UUmMnUoKeVA5gZBi5Vl9rMPRAF5ohOSJ8/PDze33VarW9cFtwRMMSwn6fbmzlGbqK1qhsE5jDmhIBrqV+/vzAj5nQ8nV9OJ3fsclAM4f5m54DjkP7tX/78r//4p908hsAO/j/++edv3w9fvr6elwWJ0MHcL+u6rluKoTNwEb27vd227bws0zBM4+gOpZaH252Yb7XthkQIKaXaRESYmYmq6FZrjjEGWrfChILIiISozCmymo/giMj9bgcAITZREekErA+X3wnvbhzvb3cxcEcZRIwxunvoHctluTSRGPK2lSKyG8en+9t5GkMI0zCMQ44hfP7w8Oeff4yRRbU2M3cVHYZ0v9+ZWhVBBBUppdRaa63jkLdSmrTdNI1Drk0AfBrH2pq739/dPdzdN2nuXlvbSumET81qa4Q45cQhtNZCYBVDhJxivyaVYnBzhI5wftnqmGIKtK5ra8JD7sZ36iemCMhMKTIi6JVVQBPZagl///r1cZ4QYTcNpTZM6ePjwzRND7c3zKGXbHPPKT3e74lRVK8NUhNp0tr1fkqfW3fJsdSaYoohquo0DFvZYoiPd7fndTkcT1vZ5nkmJGAHjNIkxqhqOSVTK7WqelFhpgTY+YWhTzntdjMiLMuac57H8bwsL4fTulUCSIEBHOldpsR+ccnAu3gbQp8+WxNTNTOrtZbawtfvB6wyzwMR7W92N/M8TcM8TYGDmuFbaIW37tjNm7R+20NFbWtlK+u2IZGIrKW427puh9P59XRWlc8fnm5vdk3FzHbTdDPP58siasu6mHlKcX+zE9X9PKvZL7/9VlvLKdqma6m1yZAjuhNBTjEyT+P44eHxZp6GnJvI8+vh28vhsiyqwoR3+xsDryJEfVxyvR44pGhma2kA+K7/dDoX5mmIkc/n5VwaMOWXY2C+3c0/ff6wm6f/7NDdpUltIk2kNjfXKqfL9uX59cvzM4D/8eNHJwKAYRiQiIgD0ethLe1LDCHGMKY4jWNOsdTm7k0FAddtDcxmVlstrW1bLbUgQgicwRF74wa7ef784cMw5N005RR775RT2o3j5w9Pl3Vd1o0Qp2kQtdpqCCEQE+A4pCbaNc7j6cLMncJ3JW5Z1rCfRzD7flocQM0uCE3tl28vX19e//j5w0+fP8WUuuR4WbchRyttPa+tCoge16UcTz/E9DAMT8hHJpjnIsJE57KW2ppquYiIBqYYY+h6OVMMobff5vbbt5fe2ARmcG96nYgyUgzURGqTP/3hDz//9KOqdYLQVWkz603qzTzP0+TuagqoIoKAQ0rmvtV6d7Nbt7psmztobcXrWgoArKW8Ho7h2+tpLbU0icyB3rgX2PPh9HpeXk+XDw93Q84fHu6PpwWr1K1AqfcU8sPNzPTnec7NyAwcglsj/sUqIJRaWy9B7szkAKXWhqjmKQZ3aH3I4aCm7oDUaSaWpn0S31mnmw8pphgJqZm8a1Pvsk9v7AlAzMDhw/2dqBzPSwgBEc6vyxEvVeRwEmKex7G2elk3cDgcjy+HI48xiioCFFV37y8KiInDpbVvp8vfvn7/+/eXmzHPOcuy+Vo+cbxNMeaUqiYH7OkE4O4DsZh+ORyWsl1vJV55DPZhYaezHVnwTWy36/1XQsQqYn06bNZPKHJ4vLuZxqED0HXy64BvCne/YshEMYZpHKZxuJnGIcfD6bxsa2vSq8bL4bRsm6gRUY7xt+/PX769/H+lLAByVXnMqQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMy0wNi0wNlQxMToyMDoyOCswMDowMJKWYW0AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjMtMDYtMDZUMTE6MjA6MjgrMDA6MDDjy9nRAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDIzLTA2LTA2VDExOjIwOjI4KzAwOjAwtN74DgAAAABJRU5ErkJggg==", "video_sources": [ { "type": "video_source",