diff --git a/webrtc_player/android/app/build.gradle b/webrtc_player/android/app/build.gradle
index cfd25638..ba13d606 100644
--- a/webrtc_player/android/app/build.gradle
+++ b/webrtc_player/android/app/build.gradle
@@ -41,6 +41,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation project(':zlm')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
diff --git a/webrtc_player/android/app/src/main/AndroidManifest.xml b/webrtc_player/android/app/src/main/AndroidManifest.xml
index 81281350..f80d6143 100644
--- a/webrtc_player/android/app/src/main/AndroidManifest.xml
+++ b/webrtc_player/android/app/src/main/AndroidManifest.xml
@@ -41,6 +41,9 @@
+
+
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt
index 15a8efc8..14f55008 100644
--- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt
+++ b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt
@@ -1,79 +1,26 @@
package com.zlmediakit.webrtc
-import android.annotation.SuppressLint
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
+import android.content.Intent
import android.os.Bundle
-import android.widget.Toast
+import android.view.View
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.android.synthetic.main.activity_main.view.*
-
class MainActivity : AppCompatActivity() {
- private var isSpeaker = true
-
- @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ }
- lifecycle.addObserver(web_rtc_sv)
+ fun toPlayActivity(view: View) {
+ startActivity(Intent(this, PlayDemoActivity::class.java))
+ }
- //http://124.223.98.45/index/api/webrtc?app=live&stream=test&type=play
- url.setText("http://124.223.98.45/index/api/webrtc?app=live&stream=test&type=play")
-
- //http://192.168.1.17/index/api/webrtc?app=live&stream=test&type=play
- btn_play.setOnClickListener {
- web_rtc_sv?.setVideoPath(url.text.toString())
- web_rtc_sv.start()
- }
-
- web_rtc_sv.setOnErrorListener { errorCode, errorMsg ->
- runOnUiThread {
- Toast.makeText(this, "errorCode:$errorCode,errorMsg:$errorMsg", Toast.LENGTH_SHORT)
- .show()
- }
- }
-
-
- btn_pause.setOnClickListener {
- web_rtc_sv?.pause()
- }
-
- btn_resume.setOnClickListener {
- web_rtc_sv?.resume()
- }
-
- btn_screenshot.setOnClickListener {
- web_rtc_sv?.screenshot {
- runOnUiThread {
- iv_screen.setImageDrawable(BitmapDrawable(it))
- }
- }
- }
-
- btn_mute.setOnClickListener {
- web_rtc_sv.mute(true)
- }
-
-
- selectAudio()
- btn_speaker.setOnClickListener {
- selectAudio()
- }
+ fun toPushActivity(view: View) {
}
- fun selectAudio(){
- if (isSpeaker){
- btn_speaker.setText("扬声器")
- web_rtc_sv.setSpeakerphoneOn(isSpeaker)
- }else{
- btn_speaker.setText("话筒")
- web_rtc_sv.setSpeakerphoneOn(isSpeaker)
- }
- isSpeaker=!isSpeaker
+ fun toDataChannelActivity(view: View) {
+
}
}
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt
new file mode 100644
index 00000000..fb950b32
--- /dev/null
+++ b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt
@@ -0,0 +1,84 @@
+package com.zlmediakit.webrtc
+
+import android.annotation.SuppressLint
+import android.graphics.drawable.BitmapDrawable
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.zlm.rtc.ZLMRTCPlayer
+import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.activity_main.view.*
+import kotlinx.android.synthetic.main.activity_play.*
+
+
+class PlayDemoActivity : AppCompatActivity() {
+
+ private var isSpeaker = true
+
+ @SuppressLint("SetTextI18n")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_play)
+
+ lifecycle.addObserver(web_rtc_sv)
+
+
+
+
+
+ //http://124.223.98.45/index/api/webrtc?app=live&stream=test&type=play
+ url.setText("https://zlmediakit.com/index/api/webrtc?app=live&stream=test&type=play")
+
+ //http://192.168.1.17/index/api/webrtc?app=live&stream=test&type=play
+ btn_play.setOnClickListener {
+ web_rtc_sv?.setVideoPath(url.text.toString())
+ web_rtc_sv.start()
+ }
+
+ web_rtc_sv.setOnErrorListener { errorCode, errorMsg ->
+ runOnUiThread {
+ Toast.makeText(this, "errorCode:$errorCode,errorMsg:$errorMsg", Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+
+
+ btn_pause.setOnClickListener {
+ web_rtc_sv?.pause()
+ }
+
+ btn_resume.setOnClickListener {
+ web_rtc_sv?.resume()
+ }
+
+ btn_screenshot.setOnClickListener {
+ web_rtc_sv?.screenshot {
+ runOnUiThread {
+ iv_screen.setImageDrawable(BitmapDrawable(it))
+ }
+ }
+ }
+
+ btn_mute.setOnClickListener {
+ web_rtc_sv.mute(true)
+ }
+
+
+ selectAudio()
+ btn_speaker.setOnClickListener {
+ selectAudio()
+ }
+
+ }
+
+ fun selectAudio(){
+ if (isSpeaker){
+ btn_speaker.setText("扬声器")
+ web_rtc_sv.setSpeakerphoneOn(isSpeaker)
+ }else{
+ btn_speaker.setText("话筒")
+ web_rtc_sv.setSpeakerphoneOn(isSpeaker)
+ }
+ isSpeaker=!isSpeaker
+ }
+}
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt
new file mode 100644
index 00000000..26ed3462
--- /dev/null
+++ b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt
@@ -0,0 +1,19 @@
+package com.zlmediakit.webrtc
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.zlm.rtc.ZLMRTCPlayer
+import kotlinx.android.synthetic.main.activity_player.surface_view_renderer
+
+class PlayerDemoActivity:AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_play)
+
+ ZLMRTCPlayer.shareInstance().bind(this,surface_view_renderer,true)
+
+
+ }
+}
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PushDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PushDemoActivity.kt
new file mode 100644
index 00000000..4ec9002a
--- /dev/null
+++ b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PushDemoActivity.kt
@@ -0,0 +1,12 @@
+package com.zlmediakit.webrtc
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+class PushDemoActivity: AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ }
+}
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/res/layout/activity_main.xml b/webrtc_player/android/app/src/main/res/layout/activity_main.xml
index fdefb4e5..6cb0ffaa 100644
--- a/webrtc_player/android/app/src/main/res/layout/activity_main.xml
+++ b/webrtc_player/android/app/src/main/res/layout/activity_main.xml
@@ -1,93 +1,27 @@
-
+ android:orientation="vertical">
-
-
-
-
-
+
+
+ android:onClick="toPushActivity"
+ android:text="推流" />
-
-
-
-
-
-
-
-
-
-
-
-
+ android:onClick="toDataChannelActivity"
+ android:text="DataChannel"
+ android:textAllCaps="false" />
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/res/layout/activity_play.xml b/webrtc_player/android/app/src/main/res/layout/activity_play.xml
new file mode 100644
index 00000000..c84e17e0
--- /dev/null
+++ b/webrtc_player/android/app/src/main/res/layout/activity_play.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/res/layout/activity_player.xml b/webrtc_player/android/app/src/main/res/layout/activity_player.xml
new file mode 100644
index 00000000..88e8f09b
--- /dev/null
+++ b/webrtc_player/android/app/src/main/res/layout/activity_player.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/webrtc_player/android/app/src/main/res/values/strings.xml b/webrtc_player/android/app/src/main/res/values/strings.xml
index a7484826..7a3df89f 100644
--- a/webrtc_player/android/app/src/main/res/values/strings.xml
+++ b/webrtc_player/android/app/src/main/res/values/strings.xml
@@ -1,3 +1,3 @@
- AndroidWebRTC
+ ZLMediakit WebRTC
\ No newline at end of file
diff --git a/webrtc_player/android/settings.gradle b/webrtc_player/android/settings.gradle
index 4a669b32..60b70506 100644
--- a/webrtc_player/android/settings.gradle
+++ b/webrtc_player/android/settings.gradle
@@ -22,3 +22,4 @@ dependencyResolutionManagement {
}
rootProject.name = "android"
include ':app'
+include ':zlm'
diff --git a/webrtc_player/android/zlm/.gitignore b/webrtc_player/android/zlm/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/webrtc_player/android/zlm/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/build.gradle b/webrtc_player/android/zlm/build.gradle
new file mode 100644
index 00000000..cbefd241
--- /dev/null
+++ b/webrtc_player/android/zlm/build.gradle
@@ -0,0 +1,54 @@
+plugins {
+ id 'com.android.library'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ namespace 'com.zlm.rtc'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 24
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ externalNativeBuild {
+ cmake {
+ cppFlags ""
+ }
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "src/main/cpp/CMakeLists.txt"
+ version "3.22.1"
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.core:core-ktx:1.13.1'
+ implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.12.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+
+ implementation 'org.webrtc:google-webrtc:1.0.32006'
+}
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/consumer-rules.pro b/webrtc_player/android/zlm/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.a b/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.a
new file mode 100644
index 00000000..2d478107
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.a differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.so b/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.so
new file mode 100644
index 00000000..060457de
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libcrypto.so differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.a b/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.a
new file mode 100644
index 00000000..8a3ea083
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.a differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.so b/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.so
new file mode 100644
index 00000000..a57f1916
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libcurl.so differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libssl.a b/webrtc_player/android/zlm/libs/arm64-v8a/libssl.a
new file mode 100644
index 00000000..98ec2d04
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libssl.a differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libssl.so b/webrtc_player/android/zlm/libs/arm64-v8a/libssl.so
new file mode 100644
index 00000000..210c7814
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libssl.so differ
diff --git a/webrtc_player/android/zlm/libs/arm64-v8a/libz.a b/webrtc_player/android/zlm/libs/arm64-v8a/libz.a
new file mode 100644
index 00000000..654aa523
Binary files /dev/null and b/webrtc_player/android/zlm/libs/arm64-v8a/libz.a differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.a b/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.a
new file mode 100644
index 00000000..e1e23590
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.a differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.so b/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.so
new file mode 100644
index 00000000..3027104f
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libcrypto.so differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.a b/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.a
new file mode 100644
index 00000000..f0ed7b9b
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.a differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.so b/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.so
new file mode 100644
index 00000000..83836f13
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libcurl.so differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.a b/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.a
new file mode 100644
index 00000000..c49e3f48
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.a differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.so b/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.so
new file mode 100644
index 00000000..b4fb776a
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libssl.so differ
diff --git a/webrtc_player/android/zlm/libs/armeabi-v7a/libz.a b/webrtc_player/android/zlm/libs/armeabi-v7a/libz.a
new file mode 100644
index 00000000..89cccb33
Binary files /dev/null and b/webrtc_player/android/zlm/libs/armeabi-v7a/libz.a differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libcrypto.a b/webrtc_player/android/zlm/libs/x86-64/libcrypto.a
new file mode 100644
index 00000000..ea216f54
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libcrypto.a differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libcrypto.so b/webrtc_player/android/zlm/libs/x86-64/libcrypto.so
new file mode 100644
index 00000000..b5b2325e
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libcrypto.so differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libcurl.a b/webrtc_player/android/zlm/libs/x86-64/libcurl.a
new file mode 100644
index 00000000..1dedc2c9
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libcurl.a differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libcurl.so b/webrtc_player/android/zlm/libs/x86-64/libcurl.so
new file mode 100644
index 00000000..8dbdf906
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libcurl.so differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libssl.a b/webrtc_player/android/zlm/libs/x86-64/libssl.a
new file mode 100644
index 00000000..fc62e1fb
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libssl.a differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libssl.so b/webrtc_player/android/zlm/libs/x86-64/libssl.so
new file mode 100644
index 00000000..64e114a9
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libssl.so differ
diff --git a/webrtc_player/android/zlm/libs/x86-64/libz.a b/webrtc_player/android/zlm/libs/x86-64/libz.a
new file mode 100644
index 00000000..e8ad9dd3
Binary files /dev/null and b/webrtc_player/android/zlm/libs/x86-64/libz.a differ
diff --git a/webrtc_player/android/zlm/proguard-rules.pro b/webrtc_player/android/zlm/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/webrtc_player/android/zlm/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/src/androidTest/java/com/zlm/rtc/ExampleInstrumentedTest.kt b/webrtc_player/android/zlm/src/androidTest/java/com/zlm/rtc/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..bb55c2f0
--- /dev/null
+++ b/webrtc_player/android/zlm/src/androidTest/java/com/zlm/rtc/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.zlm.rtc
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.zlm.rtc.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/src/main/AndroidManifest.xml b/webrtc_player/android/zlm/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/src/main/cpp/CMakeLists.txt b/webrtc_player/android/zlm/src/main/cpp/CMakeLists.txt
new file mode 100644
index 00000000..7b804cd9
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,46 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html.
+# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
+
+# Sets the minimum CMake version required for this project.
+cmake_minimum_required(VERSION 3.22.1)
+
+# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
+# Since this is the top level CMakeLists.txt, the project name is also accessible
+# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
+# build script scope).
+project("rtc")
+
+
+
+add_library(ZLToolKit IMPORTED STATIC)
+set_target_properties(tools PROPERTIES
+ IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libZLToolKit.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include"
+ )
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+#
+# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
+# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
+# is preferred for the same purpose.
+#
+# In order to load a library into your app from Java/Kotlin, you must call
+# System.loadLibrary() and pass the name of the library defined here;
+# for GameActivity/NativeActivity derived applications, the same library name must be
+# used in the AndroidManifest.xml file.
+add_library(${CMAKE_PROJECT_NAME} SHARED
+ # List C/C++ source files with relative paths to this CMakeLists.txt.
+ rtc.cpp)
+
+# Specifies libraries CMake should link to your target library. You
+# can link libraries from various origins, such as libraries defined in this
+# build script, prebuilt third-party libraries, or Android system libraries.
+target_link_libraries(${CMAKE_PROJECT_NAME}
+ # List libraries link to the target library
+ android
+ log
+ ZLToolKit)
\ No newline at end of file
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Codec/AACEncoder.h b/webrtc_player/android/zlm/src/main/cpp/include/Codec/AACEncoder.h
new file mode 100644
index 00000000..657a43b9
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Codec/AACEncoder.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef CODEC_AACENCODER_H_
+#define CODEC_AACENCODER_H_
+
+namespace mediakit {
+
+class AACEncoder {
+public:
+ AACEncoder(void);
+ virtual ~AACEncoder(void);
+ bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit);
+ int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer);
+
+private:
+ unsigned char *_pucPcmBuf = nullptr;
+ unsigned int _uiPcmLen = 0;
+
+ unsigned char *_pucAacBuf = nullptr;
+ void *_hEncoder = nullptr;
+
+ unsigned long _ulInputSamples = 0;
+ unsigned long _ulMaxInputBytes = 0;
+ unsigned long _ulMaxOutputBytes = 0;
+
+};
+
+} /* namespace mediakit */
+
+#endif /* CODEC_AACENCODER_H_ */
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Codec/H264Encoder.h b/webrtc_player/android/zlm/src/main/cpp/include/Codec/H264Encoder.h
new file mode 100644
index 00000000..46c86150
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Codec/H264Encoder.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef CODEC_H264ENCODER_H_
+#define CODEC_H264ENCODER_H_
+
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif //__cplusplus
+#include
+#ifdef __cplusplus
+}
+#endif //__cplusplus
+
+namespace mediakit {
+
+class H264Encoder {
+public:
+ typedef struct {
+ int iType;
+ int iLength;
+ uint8_t *pucData;
+ } H264Frame;
+
+ H264Encoder();
+ ~H264Encoder();
+
+ bool init(int iWidth, int iHeight, int iFps, int iBitRate);
+ int inputData(char *yuv[3], int linesize[3], int64_t cts, H264Frame **out_frame);
+
+private:
+ x264_t *_pX264Handle = nullptr;
+ x264_picture_t *_pPicIn = nullptr;
+ x264_picture_t *_pPicOut = nullptr;
+ H264Frame _aFrames[10];
+};
+
+} /* namespace mediakit */
+
+#endif /* CODEC_H264ENCODER_H_ */
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Codec/Transcode.h b/webrtc_player/android/zlm/src/main/cpp/include/Codec/Transcode.h
new file mode 100644
index 00000000..4cfaee62
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Codec/Transcode.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLMEDIAKIT_TRANSCODE_H
+#define ZLMEDIAKIT_TRANSCODE_H
+
+#if defined(ENABLE_FFMPEG)
+
+#include "Util/TimeTicker.h"
+#include "Common/MediaSink.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "libswscale/swscale.h"
+#include "libavutil/avutil.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/avcodec.h"
+#include "libswresample/swresample.h"
+#include "libavutil/audio_fifo.h"
+#include "libavutil/imgutils.h"
+#ifdef __cplusplus
+}
+#endif
+
+namespace mediakit {
+
+class FFmpegFrame {
+public:
+ using Ptr = std::shared_ptr;
+
+ FFmpegFrame(std::shared_ptr frame = nullptr);
+ ~FFmpegFrame();
+
+ AVFrame *get() const;
+ void fillPicture(AVPixelFormat target_format, int target_width, int target_height);
+
+private:
+ char *_data = nullptr;
+ std::shared_ptr _frame;
+};
+
+class FFmpegSwr {
+public:
+ using Ptr = std::shared_ptr;
+
+ FFmpegSwr(AVSampleFormat output, int channel, int channel_layout, int samplerate);
+ ~FFmpegSwr();
+ FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame);
+
+private:
+ int _target_channels;
+ int _target_channel_layout;
+ int _target_samplerate;
+ AVSampleFormat _target_format;
+ SwrContext *_ctx = nullptr;
+};
+
+class TaskManager {
+public:
+ virtual ~TaskManager();
+
+ void setMaxTaskSize(size_t size);
+ void stopThread(bool drop_task);
+
+protected:
+ void startThread(const std::string &name);
+ bool addEncodeTask(std::function task);
+ bool addDecodeTask(bool key_frame, std::function task);
+ bool isEnabled() const;
+
+private:
+ void onThreadRun(const std::string &name);
+
+private:
+ class ThreadExitException : public std::runtime_error {
+ public:
+ ThreadExitException() : std::runtime_error("exit") {}
+ };
+
+private:
+ bool _decode_drop_start = false;
+ bool _exit = false;
+ size_t _max_task = 30;
+ std::mutex _task_mtx;
+ toolkit::semaphore _sem;
+ toolkit::List > _task;
+ std::shared_ptr _thread;
+};
+
+class FFmpegDecoder : public TaskManager {
+public:
+ using Ptr = std::shared_ptr;
+ using onDec = std::function;
+
+ FFmpegDecoder(const Track::Ptr &track, int thread_num = 2, const std::vector &codec_name = {});
+ ~FFmpegDecoder() override;
+
+ bool inputFrame(const Frame::Ptr &frame, bool live, bool async, bool enable_merge = true);
+ void setOnDecode(onDec cb);
+ void flush();
+ const AVCodecContext *getContext() const;
+
+private:
+ void onDecode(const FFmpegFrame::Ptr &frame);
+ bool inputFrame_l(const Frame::Ptr &frame, bool live, bool enable_merge);
+ bool decodeFrame(const char *data, size_t size, uint64_t dts, uint64_t pts, bool live, bool key_frame);
+
+private:
+ bool _do_merger = false;
+ toolkit::Ticker _ticker;
+ onDec _cb;
+ std::shared_ptr _context;
+ FrameMerger _merger{FrameMerger::h264_prefix};
+};
+
+class FFmpegSws {
+public:
+ using Ptr = std::shared_ptr;
+
+ FFmpegSws(AVPixelFormat output, int width, int height);
+ ~FFmpegSws();
+ FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame);
+ int inputFrame(const FFmpegFrame::Ptr &frame, uint8_t *data);
+
+private:
+ FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame, int &ret, uint8_t *data);
+
+private:
+ int _target_width = 0;
+ int _target_height = 0;
+ int _src_width = 0;
+ int _src_height = 0;
+ SwsContext *_ctx = nullptr;
+ AVPixelFormat _src_format = AV_PIX_FMT_NONE;
+ AVPixelFormat _target_format = AV_PIX_FMT_NONE;
+};
+
+}//namespace mediakit
+#endif// ENABLE_FFMPEG
+#endif //ZLMEDIAKIT_TRANSCODE_H
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/Device.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/Device.h
new file mode 100644
index 00000000..6af52626
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/Device.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef DEVICE_DEVICE_H_
+#define DEVICE_DEVICE_H_
+
+#include
+#include
+#include
+#include "Util/TimeTicker.h"
+#include "Common/MultiMediaSourceMuxer.h"
+
+namespace mediakit {
+
+class H264Encoder;
+class AACEncoder;
+
+class VideoInfo {
+public:
+ CodecId codecId = CodecH264;
+ int iWidth;
+ int iHeight;
+ float iFrameRate;
+ int iBitRate = 2 * 1024 * 1024;
+};
+
+class AudioInfo {
+public:
+ CodecId codecId = CodecAAC;
+ int iChannel;
+ int iSampleBit;
+ int iSampleRate;
+};
+
+/**
+ * MultiMediaSourceMuxer类的包装,方便初学者使用
+ */
+class DevChannel : public MultiMediaSourceMuxer{
+public:
+ using Ptr = std::shared_ptr;
+
+ //fDuration<=0为直播,否则为点播
+ DevChannel(const MediaTuple& tuple, float duration = 0, const ProtocolOption &option = ProtocolOption())
+ : MultiMediaSourceMuxer(tuple, duration, option) {}
+
+ /**
+ * 初始化视频Track
+ * 相当于MultiMediaSourceMuxer::addTrack(VideoTrack::Ptr );
+ * @param info 视频相关信息
+ */
+ bool initVideo(const VideoInfo &info);
+
+ /**
+ * 初始化音频Track
+ * 相当于MultiMediaSourceMuxer::addTrack(AudioTrack::Ptr );
+ * @param info 音频相关信息
+ */
+ bool initAudio(const AudioInfo &info);
+
+ /**
+ * 输入264帧
+ * @param data 264单帧数据指针
+ * @param len 数据指针长度
+ * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
+ * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
+ */
+ bool inputH264(const char *data, int len, uint64_t dts, uint64_t pts = 0);
+
+ /**
+ * 输入265帧
+ * @param data 265单帧数据指针
+ * @param len 数据指针长度
+ * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
+ * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
+ */
+ bool inputH265(const char *data, int len, uint64_t dts, uint64_t pts = 0);
+
+ /**
+ * 输入aac帧
+ * @param data_without_adts 不带adts头的aac帧
+ * @param len 帧数据长度
+ * @param dts 时间戳,单位毫秒
+ * @param adts_header adts头
+ */
+ bool inputAAC(const char *data_without_adts, int len, uint64_t dts, const char *adts_header);
+
+ /**
+ * 输入OPUS/G711音频帧
+ * @param data 音频帧
+ * @param len 帧数据长度
+ * @param dts 时间戳,单位毫秒
+ */
+ bool inputAudio(const char *data, int len, uint64_t dts);
+
+ /**
+ * 输入yuv420p视频帧,内部会完成编码并调用inputH264方法
+ * @param yuv yuv420p数据指针
+ * @param linesize yuv420p数据linesize
+ * @param cts 采集时间戳,单位毫秒
+ */
+ bool inputYUV(char *yuv[3], int linesize[3], uint64_t cts);
+
+ /**
+ * 输入pcm数据,内部会完成编码并调用inputAAC方法
+ * @param data pcm数据指针,int16整形
+ * @param len pcm数据长度
+ * @param cts 采集时间戳,单位毫秒
+ */
+ bool inputPCM(char *data, int len, uint64_t cts);
+
+ //// 重载基类方法,确保线程安全 ////
+ bool inputFrame(const Frame::Ptr &frame) override;
+ bool addTrack(const Track::Ptr & track) override;
+ void addTrackCompleted() override;
+
+private:
+ MediaOriginType getOriginType(MediaSource &sender) const override;
+
+private:
+ std::shared_ptr _pH264Enc;
+ std::shared_ptr _pAacEnc;
+ std::shared_ptr _video;
+ std::shared_ptr _audio;
+ toolkit::SmoothTicker _aTicker[2];
+};
+
+} /* namespace mediakit */
+
+#endif /* DEVICE_DEVICE_H_ */
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/JemallocUtil.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/JemallocUtil.h
new file mode 100644
index 00000000..b1c1472a
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/JemallocUtil.h
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+*
+* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+*
+* Use of this source code is governed by MIT-like license that can be found in the
+* LICENSE file in the root of the source tree. All contributing project authors
+* may be found in the AUTHORS file in the root of the source tree.
+*/
+
+#ifndef ZLMEDIAKIT_JEMALLOCUTIL_H
+#define ZLMEDIAKIT_JEMALLOCUTIL_H
+#include
+#include
+#include
+namespace mediakit {
+class JemallocUtil {
+public:
+ static void enable_profiling();
+
+ static void disable_profiling();
+
+ static void dump(const std::string &file_name);
+ static std::string get_malloc_stats();
+ static void some_malloc_stats(const std::function &fn);
+};
+} // namespace mediakit
+#endif // ZLMEDIAKIT_JEMALLOCUTIL_H
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSink.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSink.h
new file mode 100644
index 00000000..683878e3
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSink.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLMEDIAKIT_MEDIASINK_H
+#define ZLMEDIAKIT_MEDIASINK_H
+
+#include
+#include
+#include "Util/TimeTicker.h"
+#include "Extension/Frame.h"
+#include "Extension/Track.h"
+
+namespace mediakit{
+
+class TrackListener {
+public:
+ virtual ~TrackListener() = default;
+
+ /**
+ * 添加track,内部会调用Track的clone方法
+ * 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系
+ * @param track
+ */
+ virtual bool addTrack(const Track::Ptr & track) = 0;
+
+ /**
+ * 添加track完毕
+ */
+ virtual void addTrackCompleted() {};
+
+ /**
+ * 重置track
+ */
+ virtual void resetTracks() {};
+};
+
+class MediaSinkInterface : public FrameWriterInterface, public TrackListener {
+public:
+ using Ptr = std::shared_ptr;
+};
+
+/**
+ * aac静音音频添加器
+ */
+class MuteAudioMaker : public FrameDispatcher {
+public:
+ using Ptr = std::shared_ptr;
+ bool inputFrame(const Frame::Ptr &frame) override;
+
+private:
+ int _track_index = -1;
+ uint64_t _audio_idx = 0;
+};
+
+/**
+ * 该类的作用是等待Track ready()返回true也就是就绪后再通知派生类进行下一步的操作
+ * 目的是输入Frame前由Track截取处理下,以便获取有效的信息(譬如sps pps aa_cfg)
+ */
+class MediaSink : public MediaSinkInterface, public TrackSource{
+public:
+ using Ptr = std::shared_ptr;
+ /**
+ * 输入frame
+ * @param frame
+ */
+ bool inputFrame(const Frame::Ptr &frame) override;
+
+ /**
+ * 添加track,内部会调用Track的clone方法
+ * 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系
+ * @param track
+ */
+ bool addTrack(const Track::Ptr & track) override;
+
+ /**
+ * 添加Track完毕,如果是单Track,会最多等待3秒才会触发onAllTrackReady
+ * 这样会增加生成流的延时,如果添加了音视频双Track,那么可以不调用此方法
+ * 否则为了降低流注册延时,请手动调用此方法
+ */
+ void addTrackCompleted() override;
+
+ /**
+ * 设置最大track数,取值范围>=1;该方法与addTrackCompleted类型;
+ * 在设置单track时,可以加快媒体注册速度
+ */
+ void setMaxTrackCount(size_t i);
+
+ /**
+ * 重置track
+ */
+ void resetTracks() override;
+
+ /**
+ * 获取所有Track
+ * @param trackReady 是否获取已经准备好的Track
+ */
+ std::vector getTracks(bool trackReady = true) const override;
+
+ /**
+ * 判断是否已经触发onAllTrackReady事件
+ */
+ bool isAllTrackReady() const;
+
+ /**
+ * 设置是否开启音频
+ */
+ void enableAudio(bool flag);
+
+ /**
+ * 设置单音频
+ */
+ void setOnlyAudio();
+
+ /**
+ * 设置是否开启添加静音音频
+ */
+ void enableMuteAudio(bool flag);
+
+ /**
+ * 是否有视频track
+ */
+ bool haveVideo() const;
+
+protected:
+ /**
+ * 某track已经准备好,其ready()状态返回true,
+ * 此时代表可以获取其例如sps pps等相关信息了
+ * @param track
+ */
+ virtual bool onTrackReady(const Track::Ptr & track) { return false; };
+
+ /**
+ * 所有Track已经准备好,
+ */
+ virtual void onAllTrackReady() {};
+
+ /**
+ * 某Track输出frame,在onAllTrackReady触发后才会调用此方法
+ * @param frame
+ */
+ virtual bool onTrackFrame(const Frame::Ptr &frame) { return false; };
+
+private:
+ /**
+ * 触发onAllTrackReady事件
+ */
+ void emitAllTrackReady();
+
+ /**
+ * 检查track是否准备完毕
+ */
+ void checkTrackIfReady();
+ void onAllTrackReady_l();
+ /**
+ * 添加aac静音轨道
+ */
+ bool addMuteAudioTrack();
+
+private:
+ bool _audio_add = false;
+ bool _have_video = false;
+ bool _enable_audio = true;
+ bool _only_audio = false;
+ bool _add_mute_audio = true;
+ bool _all_track_ready = false;
+ size_t _max_track_size = 2;
+
+ toolkit::Ticker _ticker;
+ MuteAudioMaker::Ptr _mute_audio_maker;
+
+ std::unordered_map > _frame_unread;
+ std::unordered_map > _track_ready_callback;
+ std::unordered_map > _track_map;
+};
+
+
+class MediaSinkDelegate : public MediaSink {
+public:
+ /**
+ * 设置track监听器
+ */
+ void setTrackListener(TrackListener *listener);
+
+protected:
+ void resetTracks() override;
+ bool onTrackReady(const Track::Ptr & track) override;
+ void onAllTrackReady() override;
+
+private:
+ TrackListener *_listener = nullptr;
+};
+
+class Demuxer : protected TrackListener, public TrackSource {
+public:
+ void setTrackListener(TrackListener *listener, bool wait_track_ready = false);
+ std::vector getTracks(bool trackReady = true) const override;
+
+protected:
+ bool addTrack(const Track::Ptr &track) override;
+ void addTrackCompleted() override;
+ void resetTracks() override;
+
+private:
+ MediaSink::Ptr _sink;
+ TrackListener *_listener = nullptr;
+ std::vector _origin_track;
+};
+
+}//namespace mediakit
+
+#endif //ZLMEDIAKIT_MEDIASINK_H
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSource.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSource.h
new file mode 100644
index 00000000..49f16dd4
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/MediaSource.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLMEDIAKIT_MEDIASOURCE_H
+#define ZLMEDIAKIT_MEDIASOURCE_H
+
+#include
+#include
+#include
+#include
+#include "Network/Socket.h"
+#include "Extension/Track.h"
+#include "Record/Recorder.h"
+
+namespace toolkit {
+class Session;
+} // namespace toolkit
+
+namespace mediakit {
+
+enum class MediaOriginType : uint8_t {
+ unknown = 0,
+ rtmp_push ,
+ rtsp_push,
+ rtp_push,
+ pull,
+ ffmpeg_pull,
+ mp4_vod,
+ device_chn,
+ rtc_push,
+ srt_push
+};
+
+std::string getOriginTypeString(MediaOriginType type);
+
+class MediaSource;
+class MultiMediaSourceMuxer;
+class MediaSourceEvent {
+public:
+ friend class MediaSource;
+
+ class NotImplemented : public std::runtime_error {
+ public:
+ template
+ NotImplemented(T && ...args) : std::runtime_error(std::forward(args)...) {}
+ };
+
+ virtual ~MediaSourceEvent() = default;
+
+ // 获取媒体源类型
+ virtual MediaOriginType getOriginType(MediaSource &sender) const { return MediaOriginType::unknown; }
+ // 获取媒体源url或者文件路径
+ virtual std::string getOriginUrl(MediaSource &sender) const;
+ // 获取媒体源客户端相关信息
+ virtual std::shared_ptr getOriginSock(MediaSource &sender) const { return nullptr; }
+
+ // 通知拖动进度条
+ virtual bool seekTo(MediaSource &sender, uint32_t stamp) { return false; }
+ // 通知暂停或恢复
+ virtual bool pause(MediaSource &sender, bool pause) { return false; }
+ // 通知倍数
+ virtual bool speed(MediaSource &sender, float speed) { return false; }
+ // 通知其停止产生流
+ virtual bool close(MediaSource &sender) { return false; }
+ // 获取观看总人数,此函数一般强制重载
+ virtual int totalReaderCount(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::totalReaderCount not implemented"); }
+ // 通知观看人数变化
+ virtual void onReaderChanged(MediaSource &sender, int size);
+ //流注册或注销事件
+ virtual void onRegist(MediaSource &sender, bool regist) {}
+ // 获取丢包率
+ virtual float getLossRate(MediaSource &sender, TrackType type) { return -1; }
+ // 获取所在线程, 此函数一般强制重载
+ virtual toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::getOwnerPoller not implemented"); }
+
+ ////////////////////////仅供MultiMediaSourceMuxer对象继承////////////////////////
+ // 开启或关闭录制
+ virtual bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) { return false; };
+ // 获取录制状态
+ virtual bool isRecording(MediaSource &sender, Recorder::type type) { return false; }
+ // 获取所有track相关信息
+ virtual std::vector getMediaTracks(MediaSource &sender, bool trackReady = true) const { return std::vector(); };
+ // 获取MultiMediaSourceMuxer对象
+ virtual std::shared_ptr getMuxer(MediaSource &sender) { return nullptr; }
+
+ class SendRtpArgs {
+ public:
+ enum Type { kRtpRAW = 0, kRtpPS = 1, kRtpTS = 2 };
+ // 是否采用udp方式发送rtp
+ bool is_udp = true;
+ // rtp类型
+ Type type = kRtpPS;
+ //发送es流时指定是否只发送纯音频流
+ bool only_audio = false;
+ //tcp被动方式
+ bool passive = false;
+ // rtp payload type
+ uint8_t pt = 96;
+ //是否支持同ssrc多服务器发送
+ bool ssrc_multi_send = false;
+ // 指定rtp ssrc
+ std::string ssrc;
+ // 指定本地发送端口
+ uint16_t src_port = 0;
+ // 发送目标端口
+ uint16_t dst_port;
+ // 发送目标主机地址,可以是ip或域名
+ std::string dst_url;
+
+ //udp发送时,是否开启rr rtcp接收超时判断
+ bool udp_rtcp_timeout = false;
+ //tcp被动发送服务器延时关闭事件,单位毫秒;设置为0时,则使用默认值5000ms
+ uint32_t tcp_passive_close_delay_ms = 0;
+ //udp 发送时,rr rtcp包接收超时时间,单位毫秒
+ uint32_t rtcp_timeout_ms = 30 * 1000;
+ //udp 发送时,发送sr rtcp包间隔,单位毫秒
+ uint32_t rtcp_send_interval_ms = 5 * 1000;
+
+ //发送rtp同时接收,一般用于双向语言对讲, 如果不为空,说明开启接收
+ std::string recv_stream_id;
+ };
+
+ // 开始发送ps-rtp
+ virtual void startSendRtp(MediaSource &sender, const SendRtpArgs &args, const std::function cb) { cb(0, toolkit::SockException(toolkit::Err_other, "not implemented"));};
+ // 停止发送ps-rtp
+ virtual bool stopSendRtp(MediaSource &sender, const std::string &ssrc) {return false; }
+
+private:
+ toolkit::Timer::Ptr _async_close_timer;
+};
+
+
+template
+static void getArgsValue(const MAP &allArgs, const KEY &key, TYPE &value) {
+ auto val = ((MAP &)allArgs)[key];
+ if (!val.empty()) {
+ value = (TYPE)val;
+ }
+}
+
+class ProtocolOption {
+public:
+ ProtocolOption();
+
+ enum {
+ kModifyStampOff = 0, // 采用源视频流绝对时间戳,不做任何改变
+ kModifyStampSystem = 1, // 采用zlmediakit接收数据时的系统时间戳(有平滑处理)
+ kModifyStampRelative = 2 // 采用源视频流时间戳相对时间戳(增长量),有做时间戳跳跃和回退矫正
+ };
+ // 时间戳类型
+ int modify_stamp;
+
+ //转协议是否开启音频
+ bool enable_audio;
+ //添加静音音频,在关闭音频时,此开关无效
+ bool add_mute_audio;
+ // 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close)
+ // 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调,
+ // 而是将直接关闭流
+ bool auto_close;
+
+ //断连续推延时,单位毫秒,默认采用配置文件
+ uint32_t continue_push_ms;
+
+ // 平滑发送定时器间隔,单位毫秒,置0则关闭;开启后影响cpu性能同时增加内存
+ // 该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题
+ uint32_t paced_sender_ms;
+
+ //是否开启转换为hls(mpegts)
+ bool enable_hls;
+ //是否开启转换为hls(fmp4)
+ bool enable_hls_fmp4;
+ //是否开启MP4录制
+ bool enable_mp4;
+ //是否开启转换为rtsp/webrtc
+ bool enable_rtsp;
+ //是否开启转换为rtmp/flv
+ bool enable_rtmp;
+ //是否开启转换为http-ts/ws-ts
+ bool enable_ts;
+ //是否开启转换为http-fmp4/ws-fmp4
+ bool enable_fmp4;
+
+ // hls协议是否按需生成,如果hls.segNum配置为0(意味着hls录制),那么hls将一直生成(不管此开关)
+ bool hls_demand;
+ // rtsp[s]协议是否按需生成
+ bool rtsp_demand;
+ // rtmp[s]、http[s]-flv、ws[s]-flv协议是否按需生成
+ bool rtmp_demand;
+ // http[s]-ts协议是否按需生成
+ bool ts_demand;
+ // http[s]-fmp4、ws[s]-fmp4协议是否按需生成
+ bool fmp4_demand;
+
+ //是否将mp4录制当做观看者
+ bool mp4_as_player;
+ //mp4切片大小,单位秒
+ size_t mp4_max_second;
+ //mp4录制保存路径
+ std::string mp4_save_path;
+
+ //hls录制保存路径
+ std::string hls_save_path;
+
+ // 支持通过on_publish返回值替换stream_id
+ std::string stream_replace;
+
+ // 最大track数
+ size_t max_track = 2;
+
+ template
+ ProtocolOption(const MAP &allArgs) : ProtocolOption() {
+ load(allArgs);
+ }
+
+ template
+ void load(const MAP &allArgs) {
+#define GET_OPT_VALUE(key) getArgsValue(allArgs, #key, key)
+ GET_OPT_VALUE(modify_stamp);
+ GET_OPT_VALUE(enable_audio);
+ GET_OPT_VALUE(add_mute_audio);
+ GET_OPT_VALUE(auto_close);
+ GET_OPT_VALUE(continue_push_ms);
+ GET_OPT_VALUE(paced_sender_ms);
+
+ GET_OPT_VALUE(enable_hls);
+ GET_OPT_VALUE(enable_hls_fmp4);
+ GET_OPT_VALUE(enable_mp4);
+ GET_OPT_VALUE(enable_rtsp);
+ GET_OPT_VALUE(enable_rtmp);
+ GET_OPT_VALUE(enable_ts);
+ GET_OPT_VALUE(enable_fmp4);
+
+ GET_OPT_VALUE(hls_demand);
+ GET_OPT_VALUE(rtsp_demand);
+ GET_OPT_VALUE(rtmp_demand);
+ GET_OPT_VALUE(ts_demand);
+ GET_OPT_VALUE(fmp4_demand);
+
+ GET_OPT_VALUE(mp4_max_second);
+ GET_OPT_VALUE(mp4_as_player);
+ GET_OPT_VALUE(mp4_save_path);
+
+ GET_OPT_VALUE(hls_save_path);
+ GET_OPT_VALUE(stream_replace);
+ GET_OPT_VALUE(max_track);
+ }
+};
+
+//该对象用于拦截感兴趣的MediaSourceEvent事件
+class MediaSourceEventInterceptor : public MediaSourceEvent {
+public:
+ void setDelegate(const std::weak_ptr &listener);
+ std::shared_ptr getDelegate() const;
+
+ MediaOriginType getOriginType(MediaSource &sender) const override;
+ std::string getOriginUrl(MediaSource &sender) const override;
+ std::shared_ptr getOriginSock(MediaSource &sender) const override;
+
+ bool seekTo(MediaSource &sender, uint32_t stamp) override;
+ bool pause(MediaSource &sender, bool pause) override;
+ bool speed(MediaSource &sender, float speed) override;
+ bool close(MediaSource &sender) override;
+ int totalReaderCount(MediaSource &sender) override;
+ void onReaderChanged(MediaSource &sender, int size) override;
+ void onRegist(MediaSource &sender, bool regist) override;
+ bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) override;
+ bool isRecording(MediaSource &sender, Recorder::type type) override;
+ std::vector getMediaTracks(MediaSource &sender, bool trackReady = true) const override;
+ void startSendRtp(MediaSource &sender, const SendRtpArgs &args, const std::function cb) override;
+ bool stopSendRtp(MediaSource &sender, const std::string &ssrc) override;
+ float getLossRate(MediaSource &sender, TrackType type) override;
+ toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) override;
+ std::shared_ptr getMuxer(MediaSource &sender) override;
+
+private:
+ std::weak_ptr _listener;
+};
+
+/**
+ * 解析url获取媒体相关信息
+ */
+class MediaInfo: public MediaTuple {
+public:
+ MediaInfo() = default;
+ MediaInfo(const std::string &url) { parse(url); }
+ void parse(const std::string &url);
+ std::string getUrl() const { return schema + "://" + shortUrl(); }
+
+public:
+ uint16_t port = 0;
+ std::string full_url;
+ std::string schema;
+ std::string host;
+};
+
+bool equalMediaTuple(const MediaTuple& a, const MediaTuple& b);
+
+/**
+ * 媒体源,任何rtsp/rtmp的直播流都源自该对象
+ */
+class MediaSource: public TrackSource, public std::enable_shared_from_this {
+public:
+ static MediaSource& NullMediaSource();
+ using Ptr = std::shared_ptr;
+
+ MediaSource(const std::string &schema, const MediaTuple& tuple);
+ virtual ~MediaSource();
+
+ ////////////////获取MediaSource相关信息////////////////
+
+ // 获取协议类型
+ const std::string& getSchema() const {
+ return _schema;
+ }
+
+ const MediaTuple& getMediaTuple() const {
+ return _tuple;
+ }
+
+ std::string getUrl() const { return _schema + "://" + _tuple.shortUrl(); }
+
+ //获取对象所有权
+ std::shared_ptr getOwnership();
+
+ // 获取所有Track
+ std::vector getTracks(bool ready = true) const override;
+
+ // 获取流当前时间戳
+ virtual uint32_t getTimeStamp(TrackType type) { return 0; };
+ // 设置时间戳
+ virtual void setTimeStamp(uint32_t stamp) {};
+
+ // 获取数据速率,单位bytes/s
+ int getBytesSpeed(TrackType type = TrackInvalid);
+ // 获取流创建GMT unix时间戳,单位秒
+ uint64_t getCreateStamp() const { return _create_stamp; }
+ // 获取流上线时间,单位秒
+ uint64_t getAliveSecond() const;
+
+ ////////////////MediaSourceEvent相关接口实现////////////////
+
+ // 设置监听者
+ virtual void setListener(const std::weak_ptr &listener);
+ // 获取监听者
+ std::weak_ptr getListener() const;
+
+ // 本协议获取观看者个数,可能返回本协议的观看人数,也可能返回总人数
+ virtual int readerCount() = 0;
+ // 观看者个数,包括(hls/rtsp/rtmp)
+ virtual int totalReaderCount();
+ // 获取播放器列表
+ virtual void getPlayerList(const std::function &info_list)> &cb,
+ const std::function &on_change) {
+ assert(cb);
+ cb(std::list());
+ }
+
+ virtual bool broadcastMessage(const toolkit::Any &data) { return false; }
+
+ // 获取媒体源类型
+ MediaOriginType getOriginType() const;
+ // 获取媒体源url或者文件路径
+ std::string getOriginUrl() const;
+ // 获取媒体源客户端相关信息
+ std::shared_ptr getOriginSock() const;
+
+ // 拖动进度条
+ bool seekTo(uint32_t stamp);
+ // 暂停
+ bool pause(bool pause);
+ // 倍数播放
+ bool speed(float speed);
+ // 关闭该流
+ bool close(bool force);
+ // 该流观看人数变化
+ void onReaderChanged(int size);
+ // 开启或关闭录制
+ bool setupRecord(Recorder::type type, bool start, const std::string &custom_path, size_t max_second);
+ // 获取录制状态
+ bool isRecording(Recorder::type type);
+ // 开始发送ps-rtp
+ void startSendRtp(const MediaSourceEvent::SendRtpArgs &args, const std::function cb);
+ // 停止发送ps-rtp
+ bool stopSendRtp(const std::string &ssrc);
+ // 获取丢包率
+ float getLossRate(mediakit::TrackType type);
+ // 获取所在线程
+ toolkit::EventPoller::Ptr getOwnerPoller();
+ // 获取MultiMediaSourceMuxer对象
+ std::shared_ptr getMuxer();
+
+ ////////////////static方法,查找或生成MediaSource////////////////
+
+ // 同步查找流
+ static Ptr find(const std::string &schema, const std::string &vhost, const std::string &app, const std::string &id, bool from_mp4 = false);
+ static Ptr find(const MediaInfo &info, bool from_mp4 = false) {
+ return find(info.schema, info.vhost, info.app, info.stream, from_mp4);
+ }
+
+ // 忽略schema,同步查找流,可能返回rtmp/rtsp/hls类型
+ static Ptr find(const std::string &vhost, const std::string &app, const std::string &stream_id, bool from_mp4 = false);
+
+ // 异步查找流
+ static void findAsync(const MediaInfo &info, const std::shared_ptr &session, const std::function &cb);
+ // 遍历所有流
+ static void for_each_media(const std::function &cb, const std::string &schema = "", const std::string &vhost = "", const std::string &app = "", const std::string &stream = "");
+ // 从mp4文件生成MediaSource
+ static MediaSource::Ptr createFromMP4(const std::string &schema, const std::string &vhost, const std::string &app, const std::string &stream, const std::string &file_path = "", bool check_app = true);
+
+protected:
+ //媒体注册
+ void regist();
+
+private:
+ // 媒体注销
+ bool unregist();
+ // 触发媒体事件
+ void emitEvent(bool regist);
+
+protected:
+ toolkit::BytesSpeed _speed[TrackMax];
+ MediaTuple _tuple;
+
+private:
+ std::atomic_flag _owned { false };
+ time_t _create_stamp;
+ toolkit::Ticker _ticker;
+ std::string _schema;
+ std::weak_ptr _listener;
+ // 对象个数统计
+ toolkit::ObjectStatistic _statistic;
+};
+
+} /* namespace mediakit */
+#endif //ZLMEDIAKIT_MEDIASOURCE_H
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/MultiMediaSourceMuxer.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/MultiMediaSourceMuxer.h
new file mode 100644
index 00000000..9ca34370
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/MultiMediaSourceMuxer.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H
+#define ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H
+
+#include "Common/Stamp.h"
+#include "Common/MediaSource.h"
+#include "Common/MediaSink.h"
+#include "Record/Recorder.h"
+#include "Rtp/RtpSender.h"
+#include "Record/HlsRecorder.h"
+#include "Record/HlsMediaSource.h"
+#include "Rtsp/RtspMediaSourceMuxer.h"
+#include "Rtmp/RtmpMediaSourceMuxer.h"
+#include "TS/TSMediaSourceMuxer.h"
+#include "FMP4/FMP4MediaSourceMuxer.h"
+
+namespace mediakit {
+
+class MultiMediaSourceMuxer : public MediaSourceEventInterceptor, public MediaSink, public std::enable_shared_from_this{
+public:
+ using Ptr = std::shared_ptr;
+ using RingType = toolkit::RingBuffer;
+
+ class Listener {
+ public:
+ virtual ~Listener() = default;
+ virtual void onAllTrackReady() = 0;
+ };
+
+ MultiMediaSourceMuxer(const MediaTuple& tuple, float dur_sec = 0.0,const ProtocolOption &option = ProtocolOption());
+
+ /**
+ * 设置事件监听器
+ * @param listener 监听器
+ */
+ void setMediaListener(const std::weak_ptr &listener);
+
+ /**
+ * 设置Track就绪事件监听器
+ * @param listener 事件监听器
+ */
+ void setTrackListener(const std::weak_ptr &listener);
+
+ /**
+ * 返回总的消费者个数
+ */
+ int totalReaderCount() const;
+
+ /**
+ * 判断是否生效(是否正在转其他协议)
+ */
+ bool isEnabled();
+
+ /**
+ * 设置MediaSource时间戳
+ * @param stamp 时间戳
+ */
+ void setTimeStamp(uint32_t stamp);
+
+ /**
+ * 重置track
+ */
+ void resetTracks() override;
+
+ /////////////////////////////////MediaSourceEvent override/////////////////////////////////
+
+ /**
+ * 观看总人数
+ * @param sender 事件发送者
+ * @return 观看总人数
+ */
+ int totalReaderCount(MediaSource &sender) override;
+
+ /**
+ * 设置录制状态
+ * @param type 录制类型
+ * @param start 开始或停止
+ * @param custom_path 开启录制时,指定自定义路径
+ * @return 是否设置成功
+ */
+ bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) override;
+
+ /**
+ * 获取录制状态
+ * @param type 录制类型
+ * @return 录制状态
+ */
+ bool isRecording(MediaSource &sender, Recorder::type type) override;
+
+ /**
+ * 开始发送ps-rtp流
+ * @param dst_url 目标ip或域名
+ * @param dst_port 目标端口
+ * @param ssrc rtp的ssrc
+ * @param is_udp 是否为udp
+ * @param cb 启动成功或失败回调
+ */
+ void startSendRtp(MediaSource &sender, const MediaSourceEvent::SendRtpArgs &args, const std::function cb) override;
+
+ /**
+ * 停止ps-rtp发送
+ * @return 是否成功
+ */
+ bool stopSendRtp(MediaSource &sender, const std::string &ssrc) override;
+
+ /**
+ * 获取所有Track
+ * @param trackReady 是否筛选过滤未就绪的track
+ * @return 所有Track
+ */
+ std::vector getMediaTracks(MediaSource &sender, bool trackReady = true) const override;
+
+ /**
+ * 获取所属线程
+ */
+ toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) override;
+
+ /**
+ * 获取本对象
+ */
+ std::shared_ptr getMuxer(MediaSource &sender) override;
+
+ const ProtocolOption &getOption() const;
+ const MediaTuple &getMediaTuple() const;
+ std::string shortUrl() const;
+
+protected:
+ /////////////////////////////////MediaSink override/////////////////////////////////
+
+ /**
+ * 某track已经准备好,其ready()状态返回true,
+ * 此时代表可以获取其例如sps pps等相关信息了
+ * @param track
+ */
+ bool onTrackReady(const Track::Ptr & track) override;
+
+ /**
+ * 所有Track已经准备好,
+ */
+ void onAllTrackReady() override;
+
+ /**
+ * 某Track输出frame,在onAllTrackReady触发后才会调用此方法
+ * @param frame
+ */
+ bool onTrackFrame(const Frame::Ptr &frame) override;
+ bool onTrackFrame_l(const Frame::Ptr &frame);
+
+private:
+ void createGopCacheIfNeed();
+
+private:
+ bool _is_enable = false;
+ bool _create_in_poller = false;
+ bool _video_key_pos = false;
+ float _dur_sec;
+ std::shared_ptr _paced_sender;
+ MediaTuple _tuple;
+ ProtocolOption _option;
+ toolkit::Ticker _last_check;
+ std::unordered_map _stamps;
+ std::weak_ptr _track_listener;
+ std::unordered_multimap _rtp_sender;
+ FMP4MediaSourceMuxer::Ptr _fmp4;
+ RtmpMediaSourceMuxer::Ptr _rtmp;
+ RtspMediaSourceMuxer::Ptr _rtsp;
+ TSMediaSourceMuxer::Ptr _ts;
+ MediaSinkInterface::Ptr _mp4;
+ HlsRecorder::Ptr _hls;
+ HlsFMP4Recorder::Ptr _hls_fmp4;
+ toolkit::EventPoller::Ptr _poller;
+ RingType::Ptr _ring;
+
+ //对象个数统计
+ toolkit::ObjectStatistic _statistic;
+};
+
+}//namespace mediakit
+#endif //ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/PacketCache.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/PacketCache.h
new file mode 100644
index 00000000..5e930a5f
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/PacketCache.h
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+*
+* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+*
+* Use of this source code is governed by MIT-like license that can be found in the
+* LICENSE file in the root of the source tree. All contributing project authors
+* may be found in the AUTHORS file in the root of the source tree.
+*/
+
+#ifndef ZLMEDIAKIT_PACKET_CACHE_H_
+#define ZLMEDIAKIT_PACKET_CACHE_H_
+
+#include "Common/config.h"
+#include "Util/List.h"
+
+namespace mediakit {
+/// 缓存刷新策略类
+class FlushPolicy {
+public:
+ bool isFlushAble(bool is_video, bool is_key, uint64_t new_stamp, size_t cache_size);
+
+private:
+ // 音视频的最后时间戳
+ uint64_t _last_stamp[2] = { 0, 0 };
+};
+
+/// 合并写缓存模板
+/// \tparam packet 包类型
+/// \tparam policy 刷新缓存策略
+/// \tparam packet_list 包缓存类型
+template > >
+class PacketCache {
+public:
+ PacketCache() { _cache = std::make_shared(); }
+
+ virtual ~PacketCache() = default;
+
+ void inputPacket(uint64_t stamp, bool is_video, std::shared_ptr pkt, bool key_pos) {
+ bool flag = flushImmediatelyWhenCloseMerge();
+ if (!flag && _policy.isFlushAble(is_video, key_pos, stamp, _cache->size())) {
+ flush();
+ }
+
+ //追加数据到最后
+ _cache->emplace_back(std::move(pkt));
+ if (key_pos) {
+ _key_pos = key_pos;
+ }
+
+ if (flag) {
+ flush();
+ }
+ }
+
+ void flush() {
+ if (_cache->empty()) {
+ return;
+ }
+ onFlush(std::move(_cache), _key_pos);
+ _cache = std::make_shared();
+ _key_pos = false;
+ }
+
+ virtual void clearCache() {
+ _cache->clear();
+ }
+
+ virtual void onFlush(std::shared_ptr, bool key_pos) = 0;
+
+private:
+ bool flushImmediatelyWhenCloseMerge() {
+ // 一般的协议关闭合并写时,立即刷新缓存,这样可以减少一帧的延时,但是rtp例外
+ // 因为rtp的包很小,一个RtpPacket包中也不是完整的一帧图像,所以在关闭合并写时,
+ // 还是有必要缓冲一帧的rtp(也就是时间戳相同的rtp)再输出,这样虽然会增加一帧的延时
+ // 但是却对性能提升很大,这样做还是比较划算的
+
+ GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
+ GET_CONFIG(int, rtspLowLatency, Rtsp::kLowLatency);
+ return std::is_same::value ? rtspLowLatency : (mergeWriteMS <= 0);
+ }
+
+private:
+ bool _key_pos = false;
+ policy _policy;
+ std::shared_ptr _cache;
+};
+}
+
+#endif //ZLMEDIAKIT_PACKET_CACHE_H_
diff --git a/webrtc_player/android/zlm/src/main/cpp/include/Common/Parser.h b/webrtc_player/android/zlm/src/main/cpp/include/Common/Parser.h
new file mode 100644
index 00000000..324658ba
--- /dev/null
+++ b/webrtc_player/android/zlm/src/main/cpp/include/Common/Parser.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLMEDIAKIT_PARSER_H
+#define ZLMEDIAKIT_PARSER_H
+
+#include