GStreamer 安卓安装辅导四:这个播放器不好吃,塞牙缝,来根 ViewModel 牌牙签,将 GStreamer 剔出来。

0. 辅导四简介:多媒体播放器

🤩:谢谢你们,谢谢我的坚持,都到辅导四了,咱们都是吃饱了撑着的哥们。
路人甲👩‍🎤:谁跟你是哥们?姐手抖进来这。
😃:FreeDesktop 网主说着是个多媒体播放器,准备好网址没有?放电影啦!


🏗️ 1. Common Module 共用仓库

对比了辅导三和辅导四,有些文件是共通的。不要再费时费力,又抄又翻,手指都打疼了。直接来个 common module —— 大家一起分享。

File => New => New Module:
new
Android => Module name: common
lib

✏️, 改 common 的 gradle

打开 common 的 gradle:
gradle

在 dependencies 内:

    api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    api 'androidx.core:core-ktx:1.3.2'
    api 'androidx.appcompat:appcompat:1.2.0'
    
    // test
    api 'junit:junit:4.13.1'
    api 'androidx.test.ext:junit:1.1.2'
    api 'androidx.test.espresso:espresso-core:3.3.0'

将所有的开头改成 api ,sync。😋:看!想都不用想,懒人最爱!

🕵️, 加自己的捷径包

在 Java 加个 helper 的 package 包裹,把 Log,Toast 的私货塞进去。
helper
LogHelper:

const val TAG = "MTAG"
fun lgd(s:String) = Log.d(TAG, s)
fun lgi(s:String) = Log.i(TAG, s)
fun lge(s:String) = Log.e(TAG, s)
fun lgw(s:String) = Log.w(TAG, s)
fun lgv(s:String) = Log.v(TAG, s)

ToastHelper:

// Toast: len: 0-short, 1-long
fun msg(context: Context, s: String, len: Int) =
    if (len > 0) Toast.makeText(context, s, LENGTH_LONG).show()
    else Toast.makeText(context, s, LENGTH_SHORT).show()

📦,GStreamer package 包裹

加 package 包裹:common => java => New => Package
newPkg
main
选 main\java 。
free
继续抄:

copy
assetsGStreamer.java 驻新家。

《✔️》改 辅导一

Gradle: 跳到 dependencies
change
😋:换成一行的,够短了吧? Sync。
Tutorial1.kt:看看私货能用否?

    public override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        try {
   
            GStreamer.init(this)
        } catch (e: Exception) {
   
            msg(this, e.message.toString(), 1)
            finish()
            return
        }
        setContentView(R.layout.main)
        val tv = findViewById<View>(R.id.textview_info) as TextView
        tv.text = nativeGetGStreamerInfo() + " !"
    }

把 Toast() 改成 msg() 。
再将 GStreamer 和 assets 删掉,
del
import 回来,

import
跑一次。😁:一样。
install
Android Studio 自动把 GStreamer 和 assets 装回去了。以后装在新项目,也可以这样操作。

《✔️》改 辅导二的

Gradle:在 dependencies 缩水, sync。
Tutorial2.kt:将 lgd, lgi 的 import 删掉,再 import 一次。
跑步前进…一切正常。

《✔️》改 辅导三

Gradle:在 dependencies 缩水, sync。
Tutorial3.kt:将 lgd, lgi 的 import 删掉,再 import 一次。
🉑 辅导三,辅导四 和 辅导五 共用一个 GStreamerSurfaceView。因此,这个可以搬到 common 里面去:
ui
删掉 辅导三 里面的 GStreamerSurfaceView
在 res/layout/main.xml :

    <你的路径.common.ui.GStreamerSurfaceView
        android:id="@+id/surface_video"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal" />

抬头换成新的地址。象我就是

com.homan.huang.common.ui.GStreamerSurfaceView

跑啊…正常。


♋️ 2. 辅导四转 Kotlin

【✔️】Gradle 和 main.xml

Gradle:在 dependencies 缩水, sync。👌
main.xml: 转 “你的路径.common.ui.GStreamerSurfaceView”

到 Tutorial4 ,跑起来呦,没问题。

【✔️】Tutorial4.Java 转 Kotlin

老样子,Ctrl+Alt+Shift+k,Yes:
有三处爆红:

  1. Date(pos) 改为 Date(pos.toLong())
  2. Date(duration)改为 Date(duration.toLong())
  3. 照旧给 nativeClassInit() 加 @JvmStatic

再跑起来。没事。
film
音响 和 画面 看起来都不错。


3. 分析 Turtorial4

class Tutorial4 : Activity(), SurfaceHolder.Callback, OnSeekBarChangeListener {
   

🤔(一看开头就知道好多仔啊!):你哪来的?下蛋啊?
🐔???🐤🐥🐣

🐾 JNI 参数

    // JNI
    private external fun nativeInit() // Initialize native code, build pipeline, etc
    private external fun nativeFinalize() // Destroy pipeline and shutdown native code
    private external fun nativeSetUri(uri: String?) // Set the URI of the media to play
    private external fun nativePlay() // Set pipeline to PLAYING
    private external fun nativeSetPosition(milliseconds: Int) // Seek to the indicated position, in milliseconds
    private external fun nativePause() // Set pipeline to PAUSED
    private external fun nativeSurfaceInit(surface: Any) // A new surface is available
    private external fun nativeSurfaceFinalize() // Surface about to be destroyed
    private val native_custom_data // Native code will use this to keep private data
            : Long = 0
    private var is_playing_desired // Whether the user asked to go to PLAYING
            = false
    private var position // Current position, reported by native code
            = 0
    private var duration // Current clip duration, reported by native code
            = 0
    private var is_local_media // Whether this clip is stored locally or is being streamed
            = false
    private var desired_position // Position where the users wants to seek to
            = 0
    private var mediaUri // URI of the clip being played
            : String? = null
    private val defaultMediaUri = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv"

  • 有流量当然有 URI
  • 放电影还要有 poistion 位置显示
  • 播过了多长时间 duration
  • 下面还有 资源判断 是 当地的还是网上的 is_local_media
  • 用户选项有一个:跳档,desired_position
  • 下一个 mediaUri,网源
  • 最后一个 defaultMediaUri

📺 UI 触屏参数

    // UI
    val play:ImageButton by lazy {
    findViewById(R.id.button_play) }
    val pause:ImageButton by lazy {
    findViewById(R.id.button_stop) }
    val sb:SeekBar by lazy {
    findViewById(R.id.seek_bar) }
    val msgTV:TextView by lazy {
    findViewById(R.id.textview_message) }
    val timeTV:TextView by lazy {
    findViewById(R.id.textview_time) }
    val gsv:GStreamerSurfaceView by lazy {
    findViewById(R.id.surface_video) }

player

🔨 onCreate()

        // 搜索棍
        sb.setOnSeekBarChangeListener(this)
  • 搜索棍 seek_bar
        // Retrieve our previous state, or initialize it to default values
        if (savedInstanceState != null) {
   
            is_playing_desired = savedInstanceState.getBoolean("playing")
            position = savedInstanceState.getInt("position")
            duration = savedInstanceState.getInt("duration")
            mediaUri = savedInstanceState.getString("mediaUri")
            lgi("GStreamer--Activity created with saved state:")
        } else {
   
            is_playing_desired = false
            duration = 0
            position = duration
            mediaUri = defaultMediaUri
            lgi("GStreamer--Activity created with no saved state:")
        }

检查 onRestart()onStart() 回调的记忆,🙄:防止机器痴呆。onSaveInstanceState() 保持播放器的资料。

    override fun onSaveInstanceState(outState: Bundle) {
        lgd("GStreamer--Saving state, playing:" + is_playing_desired + " position:" + position +
                " duration: " + duration + " uri: " + mediaUri)
        outState.putBoolean("playing", is_playing_desired)
        outState.putInt("position", position)
        outState.putInt("duration", duration)
        outState.putString("mediaUri", mediaUri)
    }

接着,

is_local_media = false

默认使用网络流量。

🛵onGStreamerInitialized()

    private fun onGStreamerInitialized() {
   
        ...
        // Restore previous playing state
        setMediaUri()
        nativeSetPosition(position)
        ...
    }

多了两行。

  • setMediaUri():
    private fun setMediaUri() {
        nativeSetUri(mediaUri)
        is_local_media = mediaUri!!.startsWith("file://")
    }

通知 C 网址。

📥 Implementation 插入的方程。

surfaceChanged(), surfaceCreated(), surfaceDestroyed() 你们都知道了。

📲 onMediaSizeChanged():

    private fun onMediaSizeChanged(width: Int, height: Int) {
   
        lgi("GStreamer--Media size changed to " + width + "x" + height)
        gsv.media_width = width
        gsv.media_height = height
        runOnUiThread {
    gsv.requestLayout() }
    }

平放看看:
hor
锁死了。

        gsv.media_width = height
        gsv.media_height = width

长宽掉转,成了:
long
👨‍🔧:这个播放器没法用,还是改回来吧。还有这些按钮都是非人类的,谁会摆在中间啊?

📏 播放搜索棍

🧙‍♂️:这个不及我的棒棒,只能提放推拉。

    // The Seek Bar thumb has moved, either because the user dragged it or we have called setProgress()
    override fun onProgressChanged(sb: SeekBar, progress: Int, fromUser: Boolean) {
   
        if (fromUser == false) return
        desired_position = progress
        // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
        if (is_local_media) nativeSetPosition(desired_position)
        updateTimeWidget()
    }

    // The user started dragging the Seek Bar thumb
    override fun onStartTrackingTouch(sb: SeekBar) {
   
        nativePause()
    }

    // The user released the Seek Bar thumb
    override fun onStopTrackingTouch(sb: SeekBar) {
   
        // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
        // Therefore, perform only the
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值