New upstream version 26.0.0+dfsg1
This commit is contained in:
parent
8e020cdacb
commit
240080891f
837 changed files with 41275 additions and 9196 deletions
|
|
@ -9,6 +9,8 @@ include_directories(${OBS_JANSSON_INCLUDE_DIRS})
|
|||
set(rtmp-services_SOURCES
|
||||
twitch.c
|
||||
younow.c
|
||||
nimotv.c
|
||||
showroom.c
|
||||
rtmp-common.c
|
||||
rtmp-custom.c
|
||||
rtmp-services-main.c)
|
||||
|
|
@ -23,6 +25,8 @@ endif()
|
|||
set(rtmp-services_HEADERS
|
||||
twitch.h
|
||||
younow.h
|
||||
nimotv.h
|
||||
showroom.h
|
||||
rtmp-format-ver.h)
|
||||
|
||||
set(RTMP_SERVICES_URL
|
||||
|
|
@ -48,6 +52,8 @@ target_link_libraries(rtmp-services
|
|||
${OBS_JANSSON_IMPORT}
|
||||
${LIBCURL_LIBRARIES})
|
||||
|
||||
set_target_properties(rtmp-services PROPERTIES FOLDER "plugins")
|
||||
|
||||
target_include_directories(rtmp-services
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/plugins/rtmp-services>")
|
||||
|
|
|
|||
2
plugins/rtmp-services/data/locale/az-AZ.ini
Normal file
2
plugins/rtmp-services/data/locale/az-AZ.ini
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Server="Server"
|
||||
|
||||
4
plugins/rtmp-services/data/locale/ba-RU.ini
Normal file
4
plugins/rtmp-services/data/locale/ba-RU.ini
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Service="Сервис"
|
||||
Server="Сервер"
|
||||
StreamKey="Стримдың асҡысы"
|
||||
|
||||
11
plugins/rtmp-services/data/locale/en-GB.ini
Normal file
11
plugins/rtmp-services/data/locale/en-GB.ini
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
StreamingServices="Streaming Services"
|
||||
CustomStreamingServer="Custom Streaming Server"
|
||||
Service="Service"
|
||||
Server="Server"
|
||||
Server.Auto="Auto (Recommended)"
|
||||
StreamKey="Stream key"
|
||||
UseAuth="Use authentication"
|
||||
Username="Username"
|
||||
Password="Password"
|
||||
ShowAll="Show all services"
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
StreamingServices="Palvelut"
|
||||
CustomStreamingServer="Valinnainen palvelin"
|
||||
CustomStreamingServer="Mukautettu palvelin"
|
||||
Service="Palvelu"
|
||||
Server="Palvelin"
|
||||
Server.Auto="Automaattinen (suositus)"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ StreamingServices="שרותי הזרמת נתונים"
|
|||
CustomStreamingServer="שרת הזרמת נתונים מותאם אישית"
|
||||
Service="שירות"
|
||||
Server="שרת"
|
||||
Server.Auto="אוטומטי (מומלץ)"
|
||||
StreamKey="מפתח הזרמת נתונים"
|
||||
UseAuth="השתמש באימות"
|
||||
Username="שם משתמש"
|
||||
|
|
|
|||
11
plugins/rtmp-services/data/locale/id-ID.ini
Normal file
11
plugins/rtmp-services/data/locale/id-ID.ini
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
StreamingServices="Layanan Streaming"
|
||||
CustomStreamingServer="Server Streaming Kustom"
|
||||
Service="Layanan"
|
||||
Server="Server"
|
||||
Server.Auto="Otomatis (Direkomendasikan)"
|
||||
StreamKey="Stream key"
|
||||
UseAuth="Gunakan otentikasi"
|
||||
Username="Nama pengguna"
|
||||
Password="Kata sandi"
|
||||
ShowAll="Tampilkan semua layanan"
|
||||
|
||||
8
plugins/rtmp-services/data/locale/ta-IN.ini
Normal file
8
plugins/rtmp-services/data/locale/ta-IN.ini
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
CustomStreamingServer="தனிப்பயன் ஸ்ட்ரீமிங் சேவையகம்"
|
||||
Service="சேவை"
|
||||
Server="சேவையகம்"
|
||||
Server.Auto="தானியங்கு (பரிந்துரைக்கப்படுபவை)"
|
||||
Username="பயனர்பெயர்"
|
||||
Password="கடவுச்சொல்"
|
||||
ShowAll="அனைத்து சேவைகளையும் காண்பி"
|
||||
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
StreamingServices="ใช้บริการสตรีมมิ่ง"
|
||||
CustomStreamingServer="ใช้เซิร์ฟเวอร์สตรีมที่กำหนดเอง"
|
||||
Service="บริการ"
|
||||
Server="เซิร์ฟเวอร์"
|
||||
Server.Auto="อัตโนมัติ (แนะนำ)"
|
||||
StreamKey="รหัสสตรีม"
|
||||
Username="ชื่อผู้ใช้"
|
||||
Password="รหัสผ่าน"
|
||||
ShowAll="แสดงบริการทั้งหมด"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
StreamingServices="Сервіси трансляцій"
|
||||
CustomStreamingServer="Сервер користувача"
|
||||
CustomStreamingServer="Користувацький сервер трансляцій"
|
||||
Service="Сервіс"
|
||||
Server="Сервер"
|
||||
Server.Auto="Автоматично (рекомендується)"
|
||||
StreamKey="Ключ трансляції"
|
||||
UseAuth="Використовувати автентифікацію"
|
||||
Username="Логін"
|
||||
Username="Ім’я користувача"
|
||||
Password="Пароль"
|
||||
ShowAll="Показати всі сервіси"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ StreamingServices="串流服務"
|
|||
CustomStreamingServer="自訂串流伺服器"
|
||||
Service="服務商"
|
||||
Server="伺服器"
|
||||
Server.Auto="自動 (建議)"
|
||||
Server.Auto="自動(建議)"
|
||||
StreamKey="串流金鑰"
|
||||
UseAuth="使用身份驗證"
|
||||
Username="使用者名稱"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"url": "https://obsproject.com/obs2_update/rtmp-services",
|
||||
"version": 131,
|
||||
"version": 147,
|
||||
"files": [
|
||||
{
|
||||
"name": "services.json",
|
||||
"version": 131
|
||||
"version": 147
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,6 +216,25 @@
|
|||
"max audio bitrate": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "VIMM",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Europe: Frankfurt",
|
||||
"url": "rtmp://eu.vimm.tv/live"
|
||||
},
|
||||
{
|
||||
"name": "North America: Montreal",
|
||||
"url": "rtmp://us.vimm.tv/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 8000,
|
||||
"max audio bitrate": 320,
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Smashcast",
|
||||
"servers": [
|
||||
|
|
@ -271,178 +290,6 @@
|
|||
"max audio bitrate": 320
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Mixer.com - FTL",
|
||||
"common": true,
|
||||
"servers": [
|
||||
{
|
||||
"name": "US: Dallas, TX",
|
||||
"url": "ingest-dal.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "US: San Jose, CA",
|
||||
"url": "ingest-sjc.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "US: Seattle, WA",
|
||||
"url": "ingest-sea.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "US: Washington DC",
|
||||
"url": "ingest-wdc.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Canada: Toronto",
|
||||
"url": "ingest-tor.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "EU: London",
|
||||
"url": "ingest-lon.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "EU: Amsterdam",
|
||||
"url": "ingest-ams.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "EU: Milan",
|
||||
"url": "ingest-mil.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "EU: Paris",
|
||||
"url": "ingest-par.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "EU: Frankfurt",
|
||||
"url": "ingest-fra.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Brazil: Sao Paulo",
|
||||
"url": "ingest-sao.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Australia: Melbourne",
|
||||
"url": "ingest-mel.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Australia: Sydney",
|
||||
"url": "ingest-syd.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Mexico: Mexico City",
|
||||
"url": "ingest-mex.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Asia: Hong Kong",
|
||||
"url": "ingest-hkg.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "Asia: Tokyo",
|
||||
"url": "ingest-tok.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "South Korea: Seoul",
|
||||
"url": "ingest-seo.mixer.com"
|
||||
},
|
||||
{
|
||||
"name": "India: Chennai",
|
||||
"url": "ingest-che.mixer.com"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"output": "ftl_output",
|
||||
"max audio bitrate": 160,
|
||||
"max video bitrate": 10000,
|
||||
"profile": "main",
|
||||
"bframes": 0,
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Mixer.com - RTMP",
|
||||
"common": true,
|
||||
"servers": [
|
||||
{
|
||||
"name": "US: Dallas, TX",
|
||||
"url": "rtmp://ingest-dal.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "US: San Jose, CA",
|
||||
"url": "rtmp://ingest-sjc.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "US: Seattle, WA",
|
||||
"url": "rtmp://ingest-sea.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "US: Washington DC",
|
||||
"url": "rtmp://ingest-wdc.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Canada: Toronto",
|
||||
"url": "rtmp://ingest-tor.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "EU: London",
|
||||
"url": "rtmp://ingest-lon.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "EU: Amsterdam",
|
||||
"url": "rtmp://ingest-ams.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "EU: Milan",
|
||||
"url": "rtmp://ingest-mil.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "EU: Paris",
|
||||
"url": "rtmp://ingest-par.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "EU: Frankfurt",
|
||||
"url": "rtmp://ingest-fra.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Brazil: Sao Paulo",
|
||||
"url": "rtmp://ingest-sao.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Australia: Melbourne",
|
||||
"url": "rtmp://ingest-mel.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Australia: Sydney",
|
||||
"url": "rtmp://ingest-syd.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Mexico: Mexico City",
|
||||
"url": "rtmp://ingest-mex.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Asia: Hong Kong",
|
||||
"url": "rtmp://ingest-hkg.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "Asia: Tokyo",
|
||||
"url": "rtmp://ingest-tok.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "South Korea: Seoul",
|
||||
"url": "rtmp://ingest-seo.mixer.com:1935/beam"
|
||||
},
|
||||
{
|
||||
"name": "India: Chennai",
|
||||
"url": "rtmp://ingest-che.mixer.com:1935/beam"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max audio bitrate": 160,
|
||||
"max video bitrate": 10000,
|
||||
"profile": "main",
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Mobcrush",
|
||||
"servers": [
|
||||
|
|
@ -494,14 +341,14 @@
|
|||
{
|
||||
"name": "Vaughn Live / iNSTAGIB",
|
||||
"servers": [
|
||||
{
|
||||
"name": "US: Primary",
|
||||
"url": "rtmp://live.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Chicago, IL",
|
||||
"url": "rtmp://live-ord.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Vint Hill, VA",
|
||||
"url": "rtmp://live-iad.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Denver, CO",
|
||||
"url": "rtmp://live-den.vaughnsoft.net/live"
|
||||
|
|
@ -509,29 +356,41 @@
|
|||
{
|
||||
"name": "US: New York, NY",
|
||||
"url": "rtmp://live-nyc.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Miami, FL",
|
||||
"url": "rtmp://live-mia.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Seattle, WA",
|
||||
"url": "rtmp://live-sea.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "EU: Amsterdam, NL",
|
||||
"url": "rtmp://live-ams.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "EU: London, UK",
|
||||
"url": "rtmp://live-lhr.vaughnsoft.net/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 3500,
|
||||
"max audio bitrate": 160
|
||||
"max video bitrate": 15000,
|
||||
"max audio bitrate": 320
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Breakers.TV",
|
||||
"servers": [
|
||||
{
|
||||
"name": "US: Primary",
|
||||
"url": "rtmp://live.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Chicago, IL",
|
||||
"url": "rtmp://live-ord.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Vint Hill, VA",
|
||||
"url": "rtmp://live-iad.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Denver, CO",
|
||||
"url": "rtmp://live-den.vaughnsoft.net/live"
|
||||
|
|
@ -539,31 +398,30 @@
|
|||
{
|
||||
"name": "US: New York, NY",
|
||||
"url": "rtmp://live-nyc.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Miami, FL",
|
||||
"url": "rtmp://live-mia.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "US: Seattle, WA",
|
||||
"url": "rtmp://live-sea.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "EU: Amsterdam, NL",
|
||||
"url": "rtmp://live-ams.vaughnsoft.net/live"
|
||||
},
|
||||
{
|
||||
"name": "EU: London, UK",
|
||||
"url": "rtmp://live-lhr.vaughnsoft.net/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 3500,
|
||||
"max audio bitrate": 160
|
||||
"max video bitrate": 15000,
|
||||
"max audio bitrate": 320
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CyberGame.TV",
|
||||
"servers": [
|
||||
{
|
||||
"name": "RU Origin",
|
||||
"url": "rtmp://st.cybergame.tv:1953/live"
|
||||
},
|
||||
{
|
||||
"name": "RU Premium",
|
||||
"url": "rtmp://premium.cybergame.tv:1953/premium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Facebook Live",
|
||||
"common": true,
|
||||
|
|
@ -581,9 +439,10 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "Restream.io - RTMP",
|
||||
"name": "Restream.io",
|
||||
"alt_names": [
|
||||
"Restream.io"
|
||||
"Restream.io - RTMP",
|
||||
"Restream.io - FTL"
|
||||
],
|
||||
"common": true,
|
||||
"servers": [
|
||||
|
|
@ -696,124 +555,6 @@
|
|||
"keyint": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Restream.io - FTL",
|
||||
"common": true,
|
||||
"servers": [
|
||||
{
|
||||
"name": "Autodetect",
|
||||
"url": "live.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-West (London, GB)",
|
||||
"url": "london.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-West (Amsterdam, NL)",
|
||||
"url": "amsterdam.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-West (Luxembourg)",
|
||||
"url": "luxembourg.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-West (Paris, FR)",
|
||||
"url": "paris.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-West (Milan, IT)",
|
||||
"url": "milan.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-Central (Frankfurt, DE)",
|
||||
"url": "frankfurt.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-East (Falkenstein, DE)",
|
||||
"url": "falkenstein.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-East (Prague, Czech)",
|
||||
"url": "prague.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "EU-South (Madrid, Spain)",
|
||||
"url": "madrid.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Russia (Moscow)",
|
||||
"url": "moscow.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Turkey (Istanbul)",
|
||||
"url": "istanbul.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Israel (Tel Aviv)",
|
||||
"url": "telaviv.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-West (Seattle, WA)",
|
||||
"url": "seattle.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-West (San Jose, CA)",
|
||||
"url": "sanjose.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-Central (Dallas, TX)",
|
||||
"url": "dallas.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-East (Washington, DC)",
|
||||
"url": "washington.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-East (Miami, FL)",
|
||||
"url": "miami.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "US-East (Chicago, IL)",
|
||||
"url": "chicago.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "NA-East (Toronto, Canada)",
|
||||
"url": "toronto.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "SA (Saint Paul, Brazil)",
|
||||
"url": "saopaulo.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "India (Bangalore)",
|
||||
"url": "bangalore.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Asia (Singapore)",
|
||||
"url": "singapore.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Asia (Seoul, South Korea)",
|
||||
"url": "seoul.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Asia (Tokyo, Japan)",
|
||||
"url": "tokyo.restream.io"
|
||||
},
|
||||
{
|
||||
"name": "Australia (Sydney)",
|
||||
"url": "sydney.restream.io"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"output": "ftl_output",
|
||||
"max audio bitrate": 160,
|
||||
"max video bitrate": 10000,
|
||||
"profile": "main",
|
||||
"bframes": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Nood",
|
||||
"servers": [
|
||||
|
|
@ -972,10 +713,6 @@
|
|||
"name": "EU Central",
|
||||
"url": "rtmp://eu-central.castr.io/static"
|
||||
},
|
||||
{
|
||||
"name": "AU South",
|
||||
"url": "rtmp://au-central.castr.io/static"
|
||||
},
|
||||
{
|
||||
"name": "Singapore",
|
||||
"url": "rtmp://sg-central.castr.io/static"
|
||||
|
|
@ -994,21 +731,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Stream.live",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "rtmp://media.stream.live:1935/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"profile": "main",
|
||||
"max video bitrate": 2500,
|
||||
"max audio bitrate": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Meridix Live Sports Platform",
|
||||
"servers": [
|
||||
|
|
@ -1022,40 +744,30 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "Afreeca.TV",
|
||||
"name": "AfreecaTV",
|
||||
"alt_names": ["아프리카TV", "Afreeca.TV"],
|
||||
"servers": [
|
||||
{
|
||||
"name": "Asia : Korea",
|
||||
"url": "rtmp://rtmpmanager-freecat.afreeca.tv/app"
|
||||
},
|
||||
{
|
||||
"name": "North America : US East",
|
||||
"url": "rtmp://rtmpmanager-aws-en-east.afreeca.tv/live"
|
||||
"url": "rtmp://rtmp-esu.afreecatv.com/app"
|
||||
},
|
||||
{
|
||||
"name": "North America : US West",
|
||||
"url": "rtmp://rtmpmanager-aws-en-west.afreeca.tv/live"
|
||||
"url": "rtmp://rtmp-wsu.afreecatv.com/app"
|
||||
},
|
||||
{
|
||||
"name": "Asia : Singapore",
|
||||
"url": "rtmp://rtmpmanager-aws-sg.afreeca.tv/live"
|
||||
"url": "rtmp://rtmp-sgp.afreecatv.com/app"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 1,
|
||||
"keyint": 2,
|
||||
"profile": "main",
|
||||
"max video bitrate": 5000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "아프리카TV",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Korea",
|
||||
"url": "rtmp://rtmpmanager-freecat.afreeca.tv/app/"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 1,
|
||||
"profile": "main",
|
||||
"max video bitrate": 5000,
|
||||
"max video bitrate": 8000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
|
|
@ -1119,9 +831,14 @@
|
|||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "rtmp://live.uscreen.app/app"
|
||||
"url": "rtmp://global-live.uscreen.app:5222/app"
|
||||
}
|
||||
]
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 8000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stripchat",
|
||||
|
|
@ -1262,33 +979,71 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "Switchboard Live (Joicaster)",
|
||||
"name": "Switchboard Live",
|
||||
"alt_names": ["Switchboard Live (Joicaster)"],
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default - Performance Global",
|
||||
"name": "Global Zone (geo based)",
|
||||
"url": "rtmp://ingest-global-a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "US West",
|
||||
"name": "US Zone (geo based)",
|
||||
"url": "rtmp://ingest-us.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "US West 1 (South)",
|
||||
"url": "rtmp://ingest-us-west.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "US East",
|
||||
"name": "US West 2 (North)",
|
||||
"url": "rtmp://ingest-us-west.b.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "US East 1 (North)",
|
||||
"url": "rtmp://ingest-us-east.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Europe West",
|
||||
"name": "US East 2 (South)",
|
||||
"url": "rtmp://ingest-us-east.b.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "US Central (North)",
|
||||
"url": "rtmp://ingest-us-central.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "South America East (São Paulo, BR)",
|
||||
"url": "rtmp://ingest-sa-east.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Europe West (London, UK)",
|
||||
"url": "rtmp://ingest-eu-west.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Europe Central",
|
||||
"url": "rtmp://ingest-us-east.a.switchboard.zone/live"
|
||||
"name": "Europe North (Hamina, FI)",
|
||||
"url": "rtmp://ingest-eu-north.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Australia East",
|
||||
"url": "rtmp://ingest-au-east.a.switchboard.zone/live"
|
||||
"name": "Australia Southeast (Sydney, AU)",
|
||||
"url": "rtmp://ingest-au-southeast.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Asia East (Changhua County, TW)",
|
||||
"url": "rtmp://ingest-as-east.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Asia Northeast (Tokyo, JP)",
|
||||
"url": "rtmp://ingest-as-northeast.a.switchboard.zone/live"
|
||||
},
|
||||
{
|
||||
"name": "Asia South (Mumbai, IN)",
|
||||
"url": "rtmp://ingest-as-south.a.switchboard.zone/live"
|
||||
}
|
||||
]
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max audio bitrate": 128,
|
||||
"max video bitrate": 10000
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Looch",
|
||||
|
|
@ -1336,8 +1091,8 @@
|
|||
"recommended": {
|
||||
"keyint": 2,
|
||||
"profile": "main",
|
||||
"max video bitrate": 2800,
|
||||
"max audio bitrate": 128
|
||||
"max video bitrate": 4000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1356,13 +1111,35 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "Madcat",
|
||||
"name": "Trovo",
|
||||
"alt_names": ["Madcat"],
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "rtmp://73846.livepush.myqcloud.com/live/"
|
||||
"url": "rtmp://livepush.trovo.live/live/"
|
||||
}
|
||||
]
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 9000,
|
||||
"max audio bitrate": 160,
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Mixcloud",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "rtmp://rtmp.mixcloud.com/broadcast"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 6000,
|
||||
"max audio bitrate": 320,
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SermonAudio Cloud",
|
||||
|
|
@ -1398,6 +1175,27 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GameTips.TV",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Iran - Tehran | AsiaTech",
|
||||
"url": "rtmp://rtmp.s2.gametips.tv:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Netherlands - Amsterdam | Serverius",
|
||||
"url": "rtmp://rtmp.s3.gametips.tv:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Iran - Tehran | ParsOnline",
|
||||
"url": "rtmp://rtmp.s4.gametips.tv:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Iran - Tehran | AfraNet",
|
||||
"url": "rtmp://rtmp.s5.gametips.tv:1935/live"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "KakaoTV",
|
||||
"servers": [
|
||||
|
|
@ -1818,6 +1616,204 @@
|
|||
"url": "rtmp://rtmp.virtwish.com/live"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Nimo TV",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Global:1",
|
||||
"url": "rtmp://wspush.rtmp.nimo.tv/live/"
|
||||
},
|
||||
{
|
||||
"name": "Global:2",
|
||||
"url": "rtmp://txpush.rtmp.nimo.tv/live/"
|
||||
},
|
||||
{
|
||||
"name": "Global:3",
|
||||
"url": "rtmp://alpush.rtmp.nimo.tv/live/"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 6000,
|
||||
"max audio bitrate": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "XLoveCam.com",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Europe(main)",
|
||||
"url": "rtmp://nl.eu.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "Europe(Romania)",
|
||||
"url": "rtmp://ro.eu.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "Europe(Russia)",
|
||||
"url": "rtmp://ru.eu.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "North America(US East)",
|
||||
"url": "rtmp://usec.na.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "North America(US West)",
|
||||
"url": "rtmp://uswc.na.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "North America(Canada)",
|
||||
"url": "rtmp://ca.na.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "South America",
|
||||
"url": "rtmp://co.sa.stream.xlove.com/performer-origin"
|
||||
},
|
||||
{
|
||||
"name": "Asia",
|
||||
"url": "rtmp://sg.as.stream.xlove.com/performer-origin"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"x264opts": "scenecut=0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AngelThump",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Auto",
|
||||
"url": "rtmp://ingest.angelthump.com/live"
|
||||
},
|
||||
{
|
||||
"name": "New York 3",
|
||||
"url": "rtmp://nyc-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "San Francisco 2",
|
||||
"url": "rtmp://sfo-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Singapore 1",
|
||||
"url": "rtmp://sgp-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "London 1",
|
||||
"url": "rtmp://lon-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Frankfurt 1",
|
||||
"url": "rtmp://fra-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Toronto 1",
|
||||
"url": "rtmp://tor-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Bangalore 1",
|
||||
"url": "rtmp://blr-ingest.angelthump.com:1935/live"
|
||||
},
|
||||
{
|
||||
"name": "Amsterdam 3",
|
||||
"url": "rtmp://ams-ingest.angelthump.com:1935/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"profile": "high",
|
||||
"max video bitrate": 3500,
|
||||
"max audio bitrate": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "weabook.live",
|
||||
"servers": [
|
||||
{
|
||||
"name": "N.Virgina, US",
|
||||
"url": "rtmp://us-api.weabook.live/live"
|
||||
},
|
||||
{
|
||||
"name": "Singapore, SG",
|
||||
"url": "rtmp://sg-api.weabook.live/live"
|
||||
},
|
||||
{
|
||||
"name": "Tokyo, JP",
|
||||
"url": "rtmp://jp-api.weabook.live/live"
|
||||
},
|
||||
{
|
||||
"name": "Premium Streaming",
|
||||
"url": "rtmp://premium.rtmp.weabook.live/live"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max audio bitrate": 256,
|
||||
"max video bitrate": 20480
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Taryana - Apachat | تاریانا - آپاچت",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Global: Fastest (Recommended)",
|
||||
"url": "rtmp://cdn.apachat.com:443/multistream"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"profile": "main",
|
||||
"max video bitrate": 4000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "api.video",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "rtmp://broadcast.api.video/s"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 20000,
|
||||
"max audio bitrate": 192
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHOWROOM",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Default",
|
||||
"url": "https://www.showroom-live.com/api/obs/streaming_info?obs_key="
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"profile": "main",
|
||||
"max video bitrate": 1500,
|
||||
"max audio bitrate": 160,
|
||||
"x264opts": "tune=zerolatency"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Mux",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Global (RTMPS)",
|
||||
"url": "rtmps://global-live.mux.com:443/app"
|
||||
},
|
||||
{
|
||||
"name": "Global (RTMP)",
|
||||
"url": "rtmp://global-live.mux.com:5222/app"
|
||||
}
|
||||
],
|
||||
"recommended": {
|
||||
"keyint": 2,
|
||||
"max video bitrate": 5000,
|
||||
"max audio bitrate": 160
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
145
plugins/rtmp-services/nimotv.c
Normal file
145
plugins/rtmp-services/nimotv.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include <util/curl/curl-helper.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <jansson.h>
|
||||
#include <util/dstr.h>
|
||||
#include "util/base.h"
|
||||
#include "nimotv.h"
|
||||
#include <time.h>
|
||||
|
||||
struct nimotv_mem_struct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
static char *current_ingest = NULL;
|
||||
static time_t last_time = -1;
|
||||
|
||||
static size_t nimotv_write_cb(void *contents, size_t size, size_t nmemb,
|
||||
void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
struct nimotv_mem_struct *mem = (struct nimotv_mem_struct *)userp;
|
||||
|
||||
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
|
||||
if (ptr == NULL) {
|
||||
blog(LOG_WARNING, "nimotv_write_cb: realloc returned NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem->memory = ptr;
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
static char *load_ingest(const char *json)
|
||||
{
|
||||
json_t *root = json_loads(json, 0, NULL);
|
||||
char *ingest = NULL;
|
||||
if (!root)
|
||||
return ingest;
|
||||
|
||||
json_t *recommended_ingests = json_object_get(root, "ingests");
|
||||
if (recommended_ingests) {
|
||||
json_t *recommended = json_array_get(recommended_ingests, 0);
|
||||
if (recommended) {
|
||||
json_t *item_url = json_object_get(recommended, "url");
|
||||
if (item_url) {
|
||||
const char *url = json_string_value(item_url);
|
||||
ingest = bstrdup(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
return ingest;
|
||||
}
|
||||
|
||||
const char *nimotv_get_ingest(const char *key)
|
||||
{
|
||||
if (current_ingest != NULL) {
|
||||
time_t now = time(NULL);
|
||||
double diff = difftime(now, last_time);
|
||||
if (diff < 2) {
|
||||
blog(LOG_INFO,
|
||||
"nimotv_get_ingest: returning ingest from cache: %s",
|
||||
current_ingest);
|
||||
return current_ingest;
|
||||
}
|
||||
}
|
||||
|
||||
CURL *curl_handle;
|
||||
CURLcode res;
|
||||
struct nimotv_mem_struct chunk;
|
||||
struct dstr uri;
|
||||
long response_code;
|
||||
|
||||
curl_handle = curl_easy_init();
|
||||
chunk.memory = malloc(1); /* will be grown as needed by realloc */
|
||||
chunk.size = 0; /* no data at this point */
|
||||
|
||||
char *encoded_key = curl_easy_escape(NULL, key, 0);
|
||||
dstr_init(&uri);
|
||||
dstr_copy(&uri, "https://globalcdnweb.nimo.tv/api/ingests/nimo?id=");
|
||||
dstr_ncat(&uri, encoded_key, strlen(encoded_key));
|
||||
curl_free(encoded_key);
|
||||
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 3L);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, nimotv_write_cb);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
curl_obs_set_revoke_setting(curl_handle);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x072400
|
||||
// A lot of servers don't yet support ALPN
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
|
||||
#endif
|
||||
|
||||
res = curl_easy_perform(curl_handle);
|
||||
dstr_free(&uri);
|
||||
|
||||
if (res != CURLE_OK) {
|
||||
blog(LOG_WARNING,
|
||||
"nimotv_get_ingest: curl_easy_perform() failed: %s",
|
||||
curl_easy_strerror(res));
|
||||
curl_easy_cleanup(curl_handle);
|
||||
free(chunk.memory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
if (response_code != 200) {
|
||||
blog(LOG_WARNING,
|
||||
"nimotv_get_ingest: curl_easy_perform() returned code: %ld",
|
||||
response_code);
|
||||
curl_easy_cleanup(curl_handle);
|
||||
free(chunk.memory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl_handle);
|
||||
|
||||
if (chunk.size == 0) {
|
||||
blog(LOG_WARNING,
|
||||
"nimotv_get_ingest: curl_easy_perform() returned empty response");
|
||||
free(chunk.memory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (current_ingest != NULL) {
|
||||
bfree(current_ingest);
|
||||
}
|
||||
|
||||
current_ingest = load_ingest(chunk.memory);
|
||||
last_time = time(NULL);
|
||||
|
||||
free(chunk.memory);
|
||||
blog(LOG_INFO, "nimotv_get_ingest: returning ingest: %s",
|
||||
current_ingest);
|
||||
|
||||
return current_ingest;
|
||||
}
|
||||
3
plugins/rtmp-services/nimotv.h
Normal file
3
plugins/rtmp-services/nimotv.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
extern const char *nimotv_get_ingest(const char *key);
|
||||
|
|
@ -2,10 +2,13 @@
|
|||
#include <util/dstr.h>
|
||||
#include <obs-module.h>
|
||||
#include <jansson.h>
|
||||
#include <obs-config.h>
|
||||
|
||||
#include "rtmp-format-ver.h"
|
||||
#include "twitch.h"
|
||||
#include "younow.h"
|
||||
#include "nimotv.h"
|
||||
#include "showroom.h"
|
||||
|
||||
struct rtmp_common {
|
||||
char *service;
|
||||
|
|
@ -13,6 +16,8 @@ struct rtmp_common {
|
|||
char *key;
|
||||
|
||||
char *output;
|
||||
|
||||
bool supports_additional_audio_track;
|
||||
};
|
||||
|
||||
static const char *rtmp_common_getname(void *unused)
|
||||
|
|
@ -24,6 +29,7 @@ static const char *rtmp_common_getname(void *unused)
|
|||
static json_t *open_services_file(void);
|
||||
static inline json_t *find_service(json_t *root, const char *name,
|
||||
const char **p_new_name);
|
||||
static inline bool get_bool_val(json_t *service, const char *key);
|
||||
static inline const char *get_string_val(json_t *service, const char *key);
|
||||
|
||||
extern void twitch_ingests_refresh(int seconds);
|
||||
|
|
@ -73,6 +79,7 @@ static void rtmp_common_update(void *data, obs_data_t *settings)
|
|||
service->service = bstrdup(obs_data_get_string(settings, "service"));
|
||||
service->server = bstrdup(obs_data_get_string(settings, "server"));
|
||||
service->key = bstrdup(obs_data_get_string(settings, "key"));
|
||||
service->supports_additional_audio_track = false;
|
||||
service->output = NULL;
|
||||
|
||||
json_t *root = open_services_file();
|
||||
|
|
@ -93,6 +100,8 @@ static void rtmp_common_update(void *data, obs_data_t *settings)
|
|||
service->output = bstrdup(out);
|
||||
}
|
||||
|
||||
service->supports_additional_audio_track = get_bool_val(
|
||||
serv, "supports_additional_audio_track");
|
||||
ensure_valid_url(service, serv, settings);
|
||||
}
|
||||
}
|
||||
|
|
@ -340,15 +349,16 @@ static void fill_servers(obs_property_t *servers_prop, json_t *service,
|
|||
return;
|
||||
}
|
||||
|
||||
if (strcmp(name, "Mixer.com - FTL") == 0) {
|
||||
obs_property_list_add_string(
|
||||
servers_prop, obs_module_text("Server.Auto"), "auto");
|
||||
}
|
||||
if (strcmp(name, "Twitch") == 0) {
|
||||
if (fill_twitch_servers(servers_prop))
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(name, "Nimo TV") == 0) {
|
||||
obs_property_list_add_string(
|
||||
servers_prop, obs_module_text("Server.Auto"), "auto");
|
||||
}
|
||||
|
||||
json_array_foreach (servers, index, server) {
|
||||
const char *server_name = get_string_val(server, "name");
|
||||
const char *url = get_string_val(server, "url");
|
||||
|
|
@ -493,6 +503,8 @@ static void apply_video_encoder_settings(obs_data_t *settings,
|
|||
obs_data_set_string(settings, "profile", profile);
|
||||
}
|
||||
|
||||
obs_data_item_release(&enc_item);
|
||||
|
||||
item = json_object_get(recommended, "max video bitrate");
|
||||
if (json_is_integer(item)) {
|
||||
int max_bitrate = (int)json_integer_value(item);
|
||||
|
|
@ -603,15 +615,43 @@ static const char *rtmp_common_url(void *data)
|
|||
}
|
||||
}
|
||||
|
||||
if (service->service && strcmp(service->service, "Nimo TV") == 0) {
|
||||
if (service->server && strcmp(service->server, "auto") == 0) {
|
||||
return nimotv_get_ingest(service->key);
|
||||
}
|
||||
}
|
||||
|
||||
if (service->service && strcmp(service->service, "SHOWROOM") == 0) {
|
||||
if (service->server && service->key) {
|
||||
struct showroom_ingest *ingest;
|
||||
ingest = showroom_get_ingest(service->server,
|
||||
service->key);
|
||||
return ingest->url;
|
||||
}
|
||||
}
|
||||
return service->server;
|
||||
}
|
||||
|
||||
static const char *rtmp_common_key(void *data)
|
||||
{
|
||||
struct rtmp_common *service = data;
|
||||
if (service->service && strcmp(service->service, "SHOWROOM") == 0) {
|
||||
if (service->server && service->key) {
|
||||
struct showroom_ingest *ingest;
|
||||
ingest = showroom_get_ingest(service->server,
|
||||
service->key);
|
||||
return ingest->key;
|
||||
}
|
||||
}
|
||||
return service->key;
|
||||
}
|
||||
|
||||
static bool supports_multitrack(void *data)
|
||||
{
|
||||
struct rtmp_common *service = data;
|
||||
return service->supports_additional_audio_track;
|
||||
}
|
||||
|
||||
struct obs_service_info rtmp_common_service = {
|
||||
.id = "rtmp_common",
|
||||
.get_name = rtmp_common_getname,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "rtmp-format-ver.h"
|
||||
#include "lookup-config.h"
|
||||
#include "showroom.h"
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("rtmp-services", "en-US")
|
||||
|
|
@ -107,5 +108,6 @@ void obs_module_unload(void)
|
|||
{
|
||||
update_info_destroy(update_info);
|
||||
unload_twitch_data();
|
||||
free_showroom_data();
|
||||
dstr_free(&module_name);
|
||||
}
|
||||
|
|
|
|||
163
plugins/rtmp-services/showroom.c
Normal file
163
plugins/rtmp-services/showroom.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include <util/curl/curl-helper.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <jansson.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/darray.h>
|
||||
#include "util/base.h"
|
||||
#include <obs-module.h>
|
||||
#include <util/platform.h>
|
||||
#include "showroom.h"
|
||||
#include <util/threading.h>
|
||||
|
||||
struct showroom_ingest_info {
|
||||
char *access_key;
|
||||
uint64_t last_time;
|
||||
struct showroom_ingest ingest;
|
||||
};
|
||||
|
||||
static DARRAY(struct showroom_ingest_info) cur_ingests = {0};
|
||||
|
||||
struct showroom_ingest invalid_ingest = {"", ""};
|
||||
|
||||
void free_showroom_data(void)
|
||||
{
|
||||
for (size_t i = 0; i < cur_ingests.num; i++) {
|
||||
struct showroom_ingest_info *info = &cur_ingests.array[i];
|
||||
bfree(info->access_key);
|
||||
bfree((void *)info->ingest.key);
|
||||
bfree((void *)info->ingest.url);
|
||||
}
|
||||
|
||||
da_free(cur_ingests);
|
||||
}
|
||||
|
||||
static size_t showroom_write_cb(void *data, size_t size, size_t nmemb,
|
||||
void *user_pointer)
|
||||
{
|
||||
struct dstr *json = user_pointer;
|
||||
size_t realsize = size * nmemb;
|
||||
dstr_ncat(json, data, realsize);
|
||||
return realsize;
|
||||
}
|
||||
|
||||
static struct showroom_ingest_info *find_ingest(const char *access_key)
|
||||
{
|
||||
struct showroom_ingest_info *ret = NULL;
|
||||
for (size_t i = 0; i < cur_ingests.num; i++) {
|
||||
struct showroom_ingest_info *info = &cur_ingests.array[i];
|
||||
if (strcmp(info->access_key, access_key) == 0) {
|
||||
ret = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef SEC_TO_NSEC
|
||||
#define SEC_TO_NSEC 1000000000ULL
|
||||
#endif
|
||||
|
||||
static struct showroom_ingest_info *get_ingest_from_json(char *str,
|
||||
const char *access_key)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
root = json_loads(str, JSON_REJECT_DUPLICATES, &error);
|
||||
if (!root) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *url_str =
|
||||
json_string_value(json_object_get(root, "streaming_url_rtmp"));
|
||||
const char *key_str =
|
||||
json_string_value(json_object_get(root, "streaming_key"));
|
||||
|
||||
struct showroom_ingest_info *info = find_ingest(access_key);
|
||||
if (!info) {
|
||||
info = da_push_back_new(cur_ingests);
|
||||
info->access_key = bstrdup(access_key);
|
||||
}
|
||||
|
||||
bfree((void *)info->ingest.url);
|
||||
bfree((void *)info->ingest.key);
|
||||
info->ingest.url = bstrdup(url_str);
|
||||
info->ingest.key = bstrdup(key_str);
|
||||
info->last_time = os_gettime_ns() / SEC_TO_NSEC;
|
||||
|
||||
json_decref(root);
|
||||
return info;
|
||||
}
|
||||
|
||||
struct showroom_ingest *showroom_get_ingest(const char *server,
|
||||
const char *access_key)
|
||||
{
|
||||
struct showroom_ingest_info *info = find_ingest(access_key);
|
||||
CURL *curl_handle;
|
||||
CURLcode res;
|
||||
struct dstr json = {0};
|
||||
struct dstr uri = {0};
|
||||
long response_code;
|
||||
|
||||
if (info) {
|
||||
/* this function is called a bunch of times for the same data,
|
||||
* so in order to prevent multiple unnecessary queries in a
|
||||
* short period of time, return the same data for 10 seconds */
|
||||
|
||||
uint64_t ts_sec = os_gettime_ns() / SEC_TO_NSEC;
|
||||
if (ts_sec - info->last_time < 10) {
|
||||
return &info->ingest;
|
||||
} else {
|
||||
info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
dstr_copy(&uri, server);
|
||||
dstr_cat(&uri, access_key);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30L);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, showroom_write_cb);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&json);
|
||||
curl_obs_set_revoke_setting(curl_handle);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x072400
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
|
||||
#endif
|
||||
|
||||
res = curl_easy_perform(curl_handle);
|
||||
dstr_free(&uri);
|
||||
if (res != CURLE_OK) {
|
||||
blog(LOG_WARNING,
|
||||
"showroom_get_ingest: curl_easy_perform() failed: %s",
|
||||
curl_easy_strerror(res));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
if (response_code != 200) {
|
||||
blog(LOG_WARNING,
|
||||
"showroom_get_ingest: curl_easy_perform() returned "
|
||||
"code: %ld",
|
||||
response_code);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (json.len == 0) {
|
||||
blog(LOG_WARNING,
|
||||
"showroom_get_ingest: curl_easy_perform() returned "
|
||||
"empty response");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info = get_ingest_from_json(json.array, access_key);
|
||||
|
||||
cleanup:
|
||||
curl_easy_cleanup(curl_handle);
|
||||
dstr_free(&json);
|
||||
return info ? &info->ingest : &invalid_ingest;
|
||||
}
|
||||
11
plugins/rtmp-services/showroom.h
Normal file
11
plugins/rtmp-services/showroom.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
struct showroom_ingest {
|
||||
const char *url;
|
||||
const char *key;
|
||||
};
|
||||
|
||||
extern struct showroom_ingest *showroom_get_ingest(const char *server,
|
||||
const char *access_key);
|
||||
|
||||
extern void free_showroom_data();
|
||||
Loading…
Add table
Add a link
Reference in a new issue