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
|
|
@ -5,22 +5,21 @@ set_property(CACHE WITH_RTMPS PROPERTY STRINGS AUTO ON OFF)
|
|||
|
||||
option(STATIC_MBEDTLS "Statically link mbedTLS into binary" OFF)
|
||||
|
||||
if (WITH_RTMPS OR (WITH_RTMPS STREQUAL "AUTO"))
|
||||
find_package(MbedTLS QUIET)
|
||||
find_package(ZLIB QUIET)
|
||||
if (WITH_RTMPS STREQUAL "AUTO")
|
||||
find_package(MbedTLS)
|
||||
find_package(ZLIB)
|
||||
if (NOT MBEDTLS_FOUND OR NOT ZLIB_FOUND)
|
||||
set(WITH_RTMPS "OFF")
|
||||
message(WARNING "mbedTLS or zlib was not found, RTMPS will be auto-disabled")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LIBMBEDTLS_FOUND AND ZLIB_FOUND)
|
||||
if (WITH_RTMPS)
|
||||
find_package(MbedTLS REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
add_definitions(-DCRYPTO -DUSE_MBEDTLS)
|
||||
include_directories(${LIBMBEDTLS_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
|
||||
include_directories(${MBEDTLS_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
|
||||
else()
|
||||
if(WITH_RTMPS STREQUAL "AUTO")
|
||||
message(WARNING "mbedTLS was not found, RTMPS will be auto-disabled")
|
||||
elseif (WITH_RTMPS)
|
||||
message(FATAL_ERROR "RTMPS enabled by user, but mbedTLS was not found")
|
||||
endif()
|
||||
unset(LIBMBEDTLS_LIBRARIES)
|
||||
unset(ZLIB_LIBRARIES)
|
||||
add_definitions(-DNO_CRYPTO)
|
||||
endif()
|
||||
|
||||
|
|
@ -172,9 +171,10 @@ add_library(obs-outputs MODULE
|
|||
${obs-outputs_librtmp_HEADERS})
|
||||
target_link_libraries(obs-outputs
|
||||
libobs
|
||||
${LIBMBEDTLS_LIBRARIES}
|
||||
${MBEDTLS_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${ftl_IMPORTS}
|
||||
${obs-outputs_PLATFORM_DEPS})
|
||||
set_target_properties(obs-outputs PROPERTIES FOLDER "plugins")
|
||||
|
||||
install_obs_plugin_with_data(obs-outputs data)
|
||||
|
|
|
|||
4
plugins/obs-outputs/data/locale/ba-RU.ini
Normal file
4
plugins/obs-outputs/data/locale/ba-RU.ini
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
FLVOutput.FilePath="Файл юлы"
|
||||
Default="Ғәҙәти"
|
||||
|
||||
|
||||
|
|
@ -8,8 +8,8 @@ ConnectionTimedOut="Zeitüberschreitung bei der Verbindung. Stellen Sie sicher,
|
|||
PermissionDenied="Die Verbindung wurde blockiert. Überprüfen Sie Ihre Firewall‐/Anti‐Virus‐Einstellungen, um sicherzustellen, dass OBS vollen Internetzugang hat."
|
||||
ConnectionAborted="Die Verbindung wurde abgebrochen. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und dem Streamingdienst."
|
||||
ConnectionReset="Die Verbindung wurde durch den Kommunikationspartner zurückgesetzt. Dies bedeutet in der Regel Probleme mit der Internetverbindung zwischen Ihnen und dem Streamingdienst."
|
||||
HostNotFound="Hostname nicht gefunden. Stellen Sie sicher, dass Sie einen gültigen Streamingserver eingegeben haben und Ihre Internetverbindung/DNS korrekt arbeiten."
|
||||
NoData="Hostname gefunden, aber keine Daten des angeforderten Typs vorhanden. Dies kann auftreten, wenn Sie eine IPv6‐Adresse verwenden, aber Ihr Streamingdienst nur über IPv4‐Adressen verfügt. (siehe „Einstellungen“ → „Erweitert“)"
|
||||
AddressNotAvailable="Adresse nicht verfügbar. Sie haben möglicherweise eine ungültige IP‐Adresse versucht zu verwenden. (siehe „Einstellungen“ → „Erweitert“)"
|
||||
HostNotFound="Hostname nicht gefunden. Stellen Sie sicher, dass Sie einen gültigen Streamingserver eingegeben haben und Ihr(e) Internetverbindung/DNS korrekt arbeiten."
|
||||
NoData="Hostname gefunden, aber keine Daten des angeforderten Typs vorhanden. Dies kann auftreten, wenn Sie eine IPv6‐Adresse verwenden, aber Ihr Streamingdienst nur über IPv4‐Adressen verfügt. (siehe „Einstellungen“ → „Erweitert“)"
|
||||
AddressNotAvailable="Adresse nicht verfügbar. Sie haben möglicherweise eine ungültige IP‐Adresse versucht zu verwenden. (siehe „Einstellungen“ → „Erweitert“)"
|
||||
SSLCertVerifyFailed="Der RTMP‐Server hat ein ungültiges SSL‐Zertifikat gesendet."
|
||||
|
||||
|
|
|
|||
15
plugins/obs-outputs/data/locale/en-GB.ini
Normal file
15
plugins/obs-outputs/data/locale/en-GB.ini
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
RTMPStream="RTMP Stream"
|
||||
RTMPStream.DropThreshold="Drop Threshold (milliseconds)"
|
||||
FLVOutput="FLV File Output"
|
||||
FLVOutput.FilePath="File Path"
|
||||
Default="Default"
|
||||
|
||||
ConnectionTimedOut="The connection timed out. Make sure you've configured a valid streaming service and no firewall is blocking the connection."
|
||||
PermissionDenied="The connection was blocked. Check your firewall / anti-virus settings to make sure OBS is allowed full Internet access."
|
||||
ConnectionAborted="The connection was aborted. This usually indicates Internet connection problems between you and the streaming service."
|
||||
ConnectionReset="The connection was reset by the peer. This usually indicates Internet connection problems between you and the streaming service."
|
||||
HostNotFound="Hostname not found. Make sure you entered a valid streaming server and your Internet connection / DNS are working correctly."
|
||||
NoData="Hostname found, but no data of the requested type. This can occur if you have bound to an IPv6 address and your streaming service only has IPv4 addresses (see Settings → Advanced)."
|
||||
AddressNotAvailable="Address not available. You may have tried to bind to an invalid IP address (see Settings → Advanced)."
|
||||
SSLCertVerifyFailed="The RTMP server sent an invalid SSL certificate."
|
||||
|
||||
|
|
@ -2,6 +2,6 @@ RTMPStream="זרם RTMP"
|
|||
RTMPStream.DropThreshold="הורד סף (אלפיות שניה)"
|
||||
FLVOutput="קובץ פלט FLV"
|
||||
FLVOutput.FilePath="נתיב קובץ"
|
||||
Default="ברירת מחדל"
|
||||
Default="ברירת־מחדל"
|
||||
|
||||
|
||||
|
|
|
|||
15
plugins/obs-outputs/data/locale/id-ID.ini
Normal file
15
plugins/obs-outputs/data/locale/id-ID.ini
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
RTMPStream="Stream RTMP"
|
||||
RTMPStream.DropThreshold="Ambang Batas Drop (milidetik)"
|
||||
FLVOutput="Output File FLV"
|
||||
FLVOutput.FilePath="Lokasi File"
|
||||
Default="Default"
|
||||
|
||||
ConnectionTimedOut="Waktu koneksi habis. Pastikan Anda telah mengkonfigurasi layanan streaming dengan valid dan tidak ada firewall yang memblokir koneksi."
|
||||
PermissionDenied="Koneksi diblokir. Periksa pengaturan firewall/anti-virus Anda untuk memastikan OBS diizinkan akses internet penuh."
|
||||
ConnectionAborted="Koneksi dibatalkan. Biasanya mengindikasi masalah koneksi internet antara Anda dan layanan streaming."
|
||||
ConnectionReset="Koneksi diatur ulang oleh peer. Biasanya mengindikasi masalah koneksi internet antara Anda dan layanan streaming."
|
||||
HostNotFound="Hostname tidak ditemukan. Pastikan Anda memasukkan server streaming dengan valid dan koneksi internet / DNS Anda berfungsi dengan benar."
|
||||
NoData="Hostname ditemukan, tetapi tidak ada data dari tipe yang diminta. Ini dapat terjadi jika Anda telah terikat ke alamat IPv6 dan layanan streaming Anda hanya memiliki alamat IPv4 (lihat Pengaturan → Tingkat Lanjut)."
|
||||
AddressNotAvailable="Alamat tidak tersedia. Anda mungkin mencoba untuk mengikat ke alamat IP yang tidak benar (lihat Pengaturan → Tingkat Lanjut)."
|
||||
SSLCertVerifyFailed="Server RTMP mengirim sertifikat SSL yang tidak valid."
|
||||
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
RTMPStream="Flux RTMP"
|
||||
RTMPStream.DropThreshold="Prag de pierderi (milisecunde)"
|
||||
FLVOutput="Ieșire fișier FLV"
|
||||
FLVOutput="Output fișier FLV"
|
||||
FLVOutput.FilePath="Calea fișierului"
|
||||
Default="Implicit"
|
||||
|
||||
ConnectionTimedOut="Conexiunea a expirat. Asigură-te că ai configurat un serviciu de streaming valid și că nici un firewall nu blochează conexiunea."
|
||||
PermissionDenied="Conexiunea a fost blocată. Verificați setările firewall-ului / anti-virus pentru a vă asigura că OBS are acces complet la internet."
|
||||
ConnectionAborted="Conexiunea a fost întreruptă. Acest lucru indică de obicei probleme de conexiune la internet între dvs. și serviciul de streaming."
|
||||
ConnectionReset="Conexiunea a fost întreruptă. Acest lucru indică de obicei probleme de conexiune la internet între dvs. și serviciul de streaming."
|
||||
HostNotFound="Hostname nu a fost găsit. Asigură-te că ai introdus un server valid de streaming și că conexiunea la internet/DNS funcționează corect."
|
||||
NoData="A fost găsit numele gazdei, dar nu există date de tipul solicitat. Acest lucru poate apărea dacă aveți o adresă IPv6 și serviciul dvs. de streaming are doar adrese IPv4 (vezi Setări → Avansat)."
|
||||
AddressNotAvailable="Adresa nu este disponibilă. Este posibil să fi încercat conectarea la o adresă IP invalidă (vezi Setări → Avansat)."
|
||||
SSLCertVerifyFailed="Serverul RTMP a trimis un certificat SSL nevalid."
|
||||
|
||||
|
|
|
|||
6
plugins/obs-outputs/data/locale/ta-IN.ini
Normal file
6
plugins/obs-outputs/data/locale/ta-IN.ini
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
RTMPStream="RTMP ஸ்ட்ரீம்"
|
||||
FLVOutput="FLV கோப்பு வெளியீட்டு"
|
||||
FLVOutput.FilePath="கோப்புப் பாதை"
|
||||
Default="இயல்புநிலை"
|
||||
|
||||
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
RTMPStream="RTMP потік"
|
||||
RTMPStream.DropThreshold="Поріг втрат (мілісекунд)"
|
||||
RTMPStream.DropThreshold="Поріг втрат (мілісекунди)"
|
||||
FLVOutput="Вивід FLV файлу"
|
||||
FLVOutput.FilePath="Шлях до файлу"
|
||||
Default="За замовчанням"
|
||||
Default="За замовчуванням"
|
||||
|
||||
ConnectionTimedOut="Вичерпано час підключення. Переконайтеся, що ви вказали правильний сервіс трансляцій і брандмауер не блокує з'єднання."
|
||||
PermissionDenied="З'єднання було заблоковано. Перевірте налаштування вашого брандмауеру / антивірусу, щоб переконатися, що OBS має повний доступ до Інтернету."
|
||||
ConnectionAborted="З'єднання було перервано. Зазвичай свідчить про проблеми з Інтернет підключенням між вами і постачальником з сервісу трансляцій."
|
||||
ConnectionReset="З'єднання було скинуте рівноправним вузлом (reset by peer). Зазвичай свідчить про проблеми з Інтернет підключенням між вами і постачальником з сервісу трансляцій."
|
||||
HostNotFound="Ім'я хоста, не знайдено. Переконайтеся, що ви ввели дійсний сервер трансляцій і підключення до Інтернету / DNS працює правильно."
|
||||
NoData="Ім'я хоста знайдено, але нема жодних даних вказаного типу. Це може статися, якщо ви вказали прив'язку до IPv6-адресу, але ваш сервіс трансляцій підтримує лише адреси IPv4 (див. Налаштування → Розширені)."
|
||||
AddressNotAvailable="Адреса недоступна. Напевно ви спробували прив'язатись до адаптера з неіснуючою IP-адресою (див. Налаштування → Розширені)."
|
||||
SSLCertVerifyFailed="RTMP сервер надіслав неприпустимий сертифікат SSL."
|
||||
ConnectionTimedOut="Час очікування підключення вичерпано. Переконайтеся, що ви вказали коректний сервіс трансляцій і брандмауер не блокує з'єднання."
|
||||
PermissionDenied="З'єднання було заблоковано. Перевірте налаштування вашого брандмауера / антивірусу, щоб переконатися чи має OBS повний доступ до Інтернету."
|
||||
ConnectionAborted="З'єднання було перервано. Зазвичай, це свідчить про проблеми з Інтернет підключенням між вами та сервісом трансляцій."
|
||||
ConnectionReset="З'єднання було скинуте рівноправним вузлом (reset by peer). Зазвичай свідчить про проблеми з Інтернет підключенням між вами та сервісом трансляцій."
|
||||
HostNotFound="Назву хоста не знайдено. Переконайтеся, що ви ввели дійсний сервер трансляцій і підключення до Інтернету / DNS працює правильно."
|
||||
NoData="Ім'я хоста знайдено, але нема жодних даних вказаного типу. Це трапляється, якщо ви вказали прив'язку до IPv6-адресу, а ваш сервіс трансляцій підтримує лише адреси IPv4 (див. Налаштування → Розширені)."
|
||||
AddressNotAvailable="Адреса недоступна. Напевно ви спробували прив'язатись до недійсної IP-адреси (див. Налаштування → Розширені)."
|
||||
SSLCertVerifyFailed="RTMP сервер надіслав недійсний SSL сертифікат."
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
//#define WRITE_FLV_HEADER
|
||||
|
||||
#define VIDEO_HEADER_SIZE 5
|
||||
#define VIDEODATA_AVCVIDEOPACKET 7.0
|
||||
#define AUDIODATA_AAC 10.0
|
||||
|
||||
static inline double encoder_bitrate(obs_encoder_t *encoder)
|
||||
{
|
||||
|
|
@ -56,11 +58,11 @@ void write_file_info(FILE *file, int64_t duration_ms, int64_t size)
|
|||
fwrite(buf, 1, enc - buf, file);
|
||||
}
|
||||
|
||||
static bool build_flv_meta_data(obs_output_t *context, uint8_t **output,
|
||||
size_t *size, size_t a_idx)
|
||||
static void build_flv_meta_data(obs_output_t *context, uint8_t **output,
|
||||
size_t *size)
|
||||
{
|
||||
obs_encoder_t *vencoder = obs_output_get_video_encoder(context);
|
||||
obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, a_idx);
|
||||
obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, 0);
|
||||
video_t *video = obs_encoder_video(vencoder);
|
||||
audio_t *audio = obs_encoder_audio(aencoder);
|
||||
char buf[4096];
|
||||
|
|
@ -68,31 +70,25 @@ static bool build_flv_meta_data(obs_output_t *context, uint8_t **output,
|
|||
char *end = enc + sizeof(buf);
|
||||
struct dstr encoder_name = {0};
|
||||
|
||||
if (a_idx > 0 && !aencoder)
|
||||
return false;
|
||||
|
||||
enc_str(&enc, end, "@setDataFrame");
|
||||
enc_str(&enc, end, "onMetaData");
|
||||
|
||||
*enc++ = AMF_ECMA_ARRAY;
|
||||
enc = AMF_EncodeInt32(enc, end, a_idx == 0 ? 20 : 15);
|
||||
enc = AMF_EncodeInt32(enc, end, 20);
|
||||
|
||||
enc_num_val(&enc, end, "duration", 0.0);
|
||||
enc_num_val(&enc, end, "fileSize", 0.0);
|
||||
|
||||
if (a_idx == 0) {
|
||||
enc_num_val(&enc, end, "width",
|
||||
(double)obs_encoder_get_width(vencoder));
|
||||
enc_num_val(&enc, end, "height",
|
||||
(double)obs_encoder_get_height(vencoder));
|
||||
enc_num_val(&enc, end, "width",
|
||||
(double)obs_encoder_get_width(vencoder));
|
||||
enc_num_val(&enc, end, "height",
|
||||
(double)obs_encoder_get_height(vencoder));
|
||||
|
||||
enc_str_val(&enc, end, "videocodecid", "avc1");
|
||||
enc_num_val(&enc, end, "videodatarate",
|
||||
encoder_bitrate(vencoder));
|
||||
enc_num_val(&enc, end, "framerate",
|
||||
video_output_get_frame_rate(video));
|
||||
}
|
||||
enc_num_val(&enc, end, "videocodecid", VIDEODATA_AVCVIDEOPACKET);
|
||||
enc_num_val(&enc, end, "videodatarate", encoder_bitrate(vencoder));
|
||||
enc_num_val(&enc, end, "framerate", video_output_get_frame_rate(video));
|
||||
|
||||
enc_str_val(&enc, end, "audiocodecid", "mp4a");
|
||||
enc_num_val(&enc, end, "audiocodecid", AUDIODATA_AAC);
|
||||
enc_num_val(&enc, end, "audiodatarate", encoder_bitrate(aencoder));
|
||||
enc_num_val(&enc, end, "audiosamplerate",
|
||||
(double)obs_encoder_get_sample_rate(aencoder));
|
||||
|
|
@ -129,11 +125,10 @@ static bool build_flv_meta_data(obs_output_t *context, uint8_t **output,
|
|||
|
||||
*size = enc - buf;
|
||||
*output = bmemdup(buf, *size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
||||
bool write_header, size_t audio_idx)
|
||||
void flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
||||
bool write_header)
|
||||
{
|
||||
struct array_output_data data;
|
||||
struct serializer s;
|
||||
|
|
@ -142,12 +137,7 @@ bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
|||
uint32_t start_pos;
|
||||
|
||||
array_output_serializer_init(&s, &data);
|
||||
|
||||
if (!build_flv_meta_data(context, &meta_data, &meta_data_size,
|
||||
audio_idx)) {
|
||||
bfree(meta_data);
|
||||
return false;
|
||||
}
|
||||
build_flv_meta_data(context, &meta_data, &meta_data_size);
|
||||
|
||||
if (write_header) {
|
||||
s_write(&s, "FLV", 3);
|
||||
|
|
@ -173,7 +163,6 @@ bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
|||
*size = data.bytes.num;
|
||||
|
||||
bfree(meta_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIMESTAMPS
|
||||
|
|
@ -264,3 +253,251 @@ void flv_packet_mux(struct encoder_packet *packet, int32_t dts_offset,
|
|||
*output = data.bytes.array;
|
||||
*size = data.bytes.num;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* stuff for additional media streams */
|
||||
|
||||
#define s_amf_conststring(s, str) \
|
||||
do { \
|
||||
const size_t len = sizeof(str) - 1; \
|
||||
s_wb16(s, (uint16_t)len); \
|
||||
serialize(s, str, len); \
|
||||
} while (false)
|
||||
|
||||
#define s_amf_double(s, d) \
|
||||
do { \
|
||||
double d_val = d; \
|
||||
uint64_t u_val = *(uint64_t *)&d_val; \
|
||||
s_wb64(s, u_val); \
|
||||
} while (false)
|
||||
|
||||
static void flv_build_additional_meta_data(uint8_t **data, size_t *size)
|
||||
{
|
||||
struct array_output_data out;
|
||||
struct serializer s;
|
||||
|
||||
array_output_serializer_init(&s, &out);
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "@setDataFrame");
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "onExpectAdditionalMedia");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "processingIntents");
|
||||
|
||||
s_w8(&s, AMF_STRICT_ARRAY);
|
||||
s_wb32(&s, 1);
|
||||
{
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "ArchiveProgramNarrationAudio");
|
||||
}
|
||||
|
||||
/* ---- */
|
||||
|
||||
s_amf_conststring(&s, "additionalMedia");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "stream0");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "type");
|
||||
|
||||
s_w8(&s, AMF_NUMBER);
|
||||
s_amf_double(&s, RTMP_PACKET_TYPE_AUDIO);
|
||||
|
||||
/* ---- */
|
||||
|
||||
s_amf_conststring(&s, "mediaLabels");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "contentType");
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "PNAR");
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
|
||||
/* ---- */
|
||||
|
||||
s_amf_conststring(&s, "defaultMedia");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "audio");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "mediaLabels");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "contentType");
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "PRM");
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
|
||||
*data = out.bytes.array;
|
||||
*size = out.bytes.num;
|
||||
}
|
||||
|
||||
void flv_additional_meta_data(obs_output_t *context, uint8_t **data,
|
||||
size_t *size)
|
||||
{
|
||||
UNUSED_PARAMETER(context);
|
||||
struct array_output_data out;
|
||||
struct serializer s;
|
||||
uint8_t *meta_data = NULL;
|
||||
size_t meta_data_size;
|
||||
|
||||
flv_build_additional_meta_data(&meta_data, &meta_data_size);
|
||||
|
||||
array_output_serializer_init(&s, &out);
|
||||
|
||||
s_w8(&s, RTMP_PACKET_TYPE_INFO); //18
|
||||
|
||||
s_wb24(&s, (uint32_t)meta_data_size);
|
||||
s_wb32(&s, 0);
|
||||
s_wb24(&s, 0);
|
||||
|
||||
s_write(&s, meta_data, meta_data_size);
|
||||
bfree(meta_data);
|
||||
|
||||
s_wb32(&s, (uint32_t)serializer_get_pos(&s) - 1);
|
||||
|
||||
*data = out.bytes.array;
|
||||
*size = out.bytes.num;
|
||||
}
|
||||
|
||||
static inline void s_u29(struct serializer *s, uint32_t val)
|
||||
{
|
||||
if (val <= 0x7F) {
|
||||
s_w8(s, val);
|
||||
} else if (val <= 0x3FFF) {
|
||||
s_w8(s, 0x80 | (val >> 7));
|
||||
s_w8(s, val & 0x7F);
|
||||
} else if (val <= 0x1FFFFF) {
|
||||
s_w8(s, 0x80 | (val >> 14));
|
||||
s_w8(s, 0x80 | ((val >> 7) & 0x7F));
|
||||
s_w8(s, val & 0x7F);
|
||||
} else {
|
||||
s_w8(s, 0x80 | (val >> 22));
|
||||
s_w8(s, 0x80 | ((val >> 15) & 0x7F));
|
||||
s_w8(s, 0x80 | ((val >> 8) & 0x7F));
|
||||
s_w8(s, val & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void s_u29b_value(struct serializer *s, uint32_t val)
|
||||
{
|
||||
s_u29(s, 1 | ((val & 0xFFFFFFF) << 1));
|
||||
}
|
||||
|
||||
static void flv_build_additional_audio(uint8_t **data, size_t *size,
|
||||
struct encoder_packet *packet,
|
||||
bool is_header, size_t index)
|
||||
{
|
||||
UNUSED_PARAMETER(index);
|
||||
struct array_output_data out;
|
||||
struct serializer s;
|
||||
|
||||
array_output_serializer_init(&s, &out);
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "additionalMedia");
|
||||
|
||||
s_w8(&s, AMF_OBJECT);
|
||||
{
|
||||
s_amf_conststring(&s, "id");
|
||||
|
||||
s_w8(&s, AMF_STRING);
|
||||
s_amf_conststring(&s, "stream0");
|
||||
|
||||
/* ----- */
|
||||
|
||||
s_amf_conststring(&s, "media");
|
||||
|
||||
s_w8(&s, AMF_AVMPLUS);
|
||||
s_w8(&s, AMF3_BYTE_ARRAY);
|
||||
s_u29b_value(&s, (uint32_t)packet->size + 2);
|
||||
s_w8(&s, 0xaf);
|
||||
s_w8(&s, is_header ? 0 : 1);
|
||||
s_write(&s, packet->data, packet->size);
|
||||
}
|
||||
s_wb24(&s, AMF_OBJECT_END);
|
||||
|
||||
*data = out.bytes.array;
|
||||
*size = out.bytes.num;
|
||||
}
|
||||
|
||||
static void flv_additional_audio(struct serializer *s, int32_t dts_offset,
|
||||
struct encoder_packet *packet, bool is_header,
|
||||
size_t index)
|
||||
{
|
||||
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
|
||||
if (!packet->data || !packet->size)
|
||||
return;
|
||||
|
||||
flv_build_additional_audio(&data, &size, packet, is_header, index);
|
||||
|
||||
s_w8(s, RTMP_PACKET_TYPE_INFO); //18
|
||||
|
||||
#ifdef DEBUG_TIMESTAMPS
|
||||
blog(LOG_DEBUG, "Audio2: %lu", time_ms);
|
||||
|
||||
if (last_time > time_ms)
|
||||
blog(LOG_DEBUG, "Non-monotonic");
|
||||
|
||||
last_time = time_ms;
|
||||
#endif
|
||||
|
||||
s_wb24(s, (uint32_t)size);
|
||||
s_wb24(s, time_ms);
|
||||
s_w8(s, (time_ms >> 24) & 0x7F);
|
||||
s_wb24(s, 0);
|
||||
|
||||
serialize(s, data, size);
|
||||
bfree(data);
|
||||
|
||||
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
||||
}
|
||||
|
||||
void flv_additional_packet_mux(struct encoder_packet *packet,
|
||||
int32_t dts_offset, uint8_t **data, size_t *size,
|
||||
bool is_header, size_t index)
|
||||
{
|
||||
struct array_output_data out;
|
||||
struct serializer s;
|
||||
|
||||
array_output_serializer_init(&s, &out);
|
||||
|
||||
if (packet->type == OBS_ENCODER_VIDEO) {
|
||||
//currently unsupported
|
||||
bcrash("who said you could output an additional video packet?");
|
||||
} else {
|
||||
flv_additional_audio(&s, dts_offset, packet, is_header, index);
|
||||
}
|
||||
|
||||
*data = out.bytes.array;
|
||||
*size = out.bytes.num;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,13 @@ static int32_t get_ms_time(struct encoder_packet *packet, int64_t val)
|
|||
|
||||
extern void write_file_info(FILE *file, int64_t duration_ms, int64_t size);
|
||||
|
||||
extern bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
||||
bool write_header, size_t audio_idx);
|
||||
extern void flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
||||
bool write_header);
|
||||
extern void flv_additional_meta_data(obs_output_t *context, uint8_t **output,
|
||||
size_t *size);
|
||||
extern void flv_packet_mux(struct encoder_packet *packet, int32_t dts_offset,
|
||||
uint8_t **output, size_t *size, bool is_header);
|
||||
extern void flv_additional_packet_mux(struct encoder_packet *packet,
|
||||
int32_t dts_offset, uint8_t **output,
|
||||
size_t *size, bool is_header,
|
||||
size_t index);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static void write_meta_data(struct flv_output *stream)
|
|||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
|
||||
flv_meta_data(stream->output, &meta_data, &meta_data_size, true, 0);
|
||||
flv_meta_data(stream->output, &meta_data, &meta_data_size, true);
|
||||
fwrite(meta_data, 1, meta_data_size, stream->file);
|
||||
bfree(meta_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,6 +370,7 @@ DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
|
|||
|
||||
MP_gethex(q1, Q1024, len);
|
||||
assert(len);
|
||||
UNUSED_PARAMETER(len); // Make GCC happy len is used in release.
|
||||
|
||||
if (isValidPublicKey(pubkeyBn, dh->p, q1))
|
||||
res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ HMACsha256(const uint8_t *message, size_t messageLen, const uint8_t *key,
|
|||
#endif
|
||||
|
||||
assert(digestLen == 32);
|
||||
UNUSED_PARAMETER(digestLen); // Make GCC happy digestLen is used in release.
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -3064,6 +3064,8 @@ static const AVal av_NetStream_Play_UnpublishNotify =
|
|||
static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
|
||||
static const AVal av_NetStream_Publish_Rejected = AVC("NetStream.Publish.Rejected");
|
||||
static const AVal av_NetStream_Publish_Denied = AVC("NetStream.Publish.Denied");
|
||||
static const AVal av_NetStream_Publish_BadName = AVC("NetStream.Publish.BadName");
|
||||
|
||||
|
||||
/* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
|
||||
static int
|
||||
|
|
@ -3314,7 +3316,8 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
|
|||
|| AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
|
||||
|| AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)
|
||||
|| AVMATCH(&code, &av_NetStream_Publish_Rejected)
|
||||
|| AVMATCH(&code, &av_NetStream_Publish_Denied))
|
||||
|| AVMATCH(&code, &av_NetStream_Publish_Denied)
|
||||
|| AVMATCH(&code, &av_NetStream_Publish_BadName))
|
||||
{
|
||||
r->m_stream_id = -1;
|
||||
RTMP_Close(r);
|
||||
|
|
@ -3376,6 +3379,14 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
|
|||
r->m_pausing = 3;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (description.av_len)
|
||||
RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s (%s)", r->Link.tcUrl.av_val, code.av_val, description.av_val);
|
||||
else
|
||||
RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s", r->Link.tcUrl.av_val, code.av_val);
|
||||
}
|
||||
}
|
||||
else if (AVMATCH(&method, &av_playlist_ready))
|
||||
{
|
||||
|
|
@ -5266,13 +5277,11 @@ fail:
|
|||
return total;
|
||||
}
|
||||
|
||||
static const AVal av_setDataFrame = AVC("@setDataFrame");
|
||||
|
||||
int
|
||||
RTMP_Write(RTMP *r, const char *buf, int size, int streamIdx)
|
||||
{
|
||||
RTMPPacket *pkt = &r->m_write;
|
||||
char *pend, *enc;
|
||||
char *enc;
|
||||
int s2 = size, ret, num;
|
||||
|
||||
pkt->m_nChannel = 0x04; /* source channel */
|
||||
|
|
@ -5308,8 +5317,6 @@ RTMP_Write(RTMP *r, const char *buf, int size, int streamIdx)
|
|||
!pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
|
||||
{
|
||||
pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
|
||||
if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
|
||||
pkt->m_nBodySize += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -5322,12 +5329,6 @@ RTMP_Write(RTMP *r, const char *buf, int size, int streamIdx)
|
|||
return FALSE;
|
||||
}
|
||||
enc = pkt->m_body;
|
||||
pend = enc + pkt->m_nBodySize;
|
||||
if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
|
||||
{
|
||||
enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
|
||||
pkt->m_nBytesRead = enc - pkt->m_body;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <mbedtls/threading.h>
|
||||
#endif
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
|
|
@ -21,6 +22,37 @@ extern struct obs_output_info flv_output_info;
|
|||
extern struct obs_output_info ftl_output_info;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(MBEDTLS_THREADING_ALT)
|
||||
void mbed_mutex_init(mbedtls_threading_mutex_t *m)
|
||||
{
|
||||
CRITICAL_SECTION *c = bzalloc(sizeof(CRITICAL_SECTION));
|
||||
*m = c;
|
||||
InitializeCriticalSection(c);
|
||||
}
|
||||
|
||||
void mbed_mutex_free(mbedtls_threading_mutex_t *m)
|
||||
{
|
||||
CRITICAL_SECTION *c = *m;
|
||||
DeleteCriticalSection(c);
|
||||
bfree(*m);
|
||||
*m = NULL;
|
||||
}
|
||||
|
||||
int mbed_mutex_lock(mbedtls_threading_mutex_t *m)
|
||||
{
|
||||
CRITICAL_SECTION *c = *m;
|
||||
EnterCriticalSection(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mbed_mutex_unlock(mbedtls_threading_mutex_t *m)
|
||||
{
|
||||
CRITICAL_SECTION *c = *m;
|
||||
LeaveCriticalSection(c);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
|
@ -28,6 +60,11 @@ bool obs_module_load(void)
|
|||
WSAStartup(MAKEWORD(2, 2), &wsad);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(MBEDTLS_THREADING_ALT)
|
||||
mbedtls_threading_set_alt(mbed_mutex_init, mbed_mutex_free,
|
||||
mbed_mutex_lock, mbed_mutex_unlock);
|
||||
#endif
|
||||
|
||||
obs_register_output(&rtmp_output_info);
|
||||
obs_register_output(&null_output_info);
|
||||
obs_register_output(&flv_output_info);
|
||||
|
|
@ -40,6 +77,9 @@ bool obs_module_load(void)
|
|||
void obs_module_unload(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef MBEDTLS_THREADING_ALT
|
||||
mbedtls_threading_free_alt();
|
||||
#endif
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -423,14 +423,20 @@ static int send_packet(struct rtmp_stream *stream,
|
|||
}
|
||||
}
|
||||
|
||||
flv_packet_mux(packet, is_header ? 0 : stream->start_dts_offset, &data,
|
||||
&size, is_header);
|
||||
if (idx > 0) {
|
||||
flv_additional_packet_mux(
|
||||
packet, is_header ? 0 : stream->start_dts_offset, &data,
|
||||
&size, is_header, idx);
|
||||
} else {
|
||||
flv_packet_mux(packet, is_header ? 0 : stream->start_dts_offset,
|
||||
&data, &size, is_header);
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEDROPS
|
||||
droptest_cap_data_rate(stream, size);
|
||||
#endif
|
||||
|
||||
ret = RTMP_Write(&stream->rtmp, (char *)data, (int)size, (int)idx);
|
||||
ret = RTMP_Write(&stream->rtmp, (char *)data, (int)size, 0);
|
||||
bfree(data);
|
||||
|
||||
if (is_header)
|
||||
|
|
@ -659,20 +665,30 @@ static void *send_thread(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool send_meta_data(struct rtmp_stream *stream, size_t idx, bool *next)
|
||||
static bool send_additional_meta_data(struct rtmp_stream *stream)
|
||||
{
|
||||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
bool success = true;
|
||||
|
||||
*next = flv_meta_data(stream->output, &meta_data, &meta_data_size,
|
||||
false, idx);
|
||||
flv_additional_meta_data(stream->output, &meta_data, &meta_data_size);
|
||||
success = RTMP_Write(&stream->rtmp, (char *)meta_data,
|
||||
(int)meta_data_size, 0) >= 0;
|
||||
bfree(meta_data);
|
||||
|
||||
if (*next) {
|
||||
success = RTMP_Write(&stream->rtmp, (char *)meta_data,
|
||||
(int)meta_data_size, (int)idx) >= 0;
|
||||
bfree(meta_data);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool send_meta_data(struct rtmp_stream *stream)
|
||||
{
|
||||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
bool success = true;
|
||||
|
||||
flv_meta_data(stream->output, &meta_data, &meta_data_size, false);
|
||||
success = RTMP_Write(&stream->rtmp, (char *)meta_data,
|
||||
(int)meta_data_size, 0) >= 0;
|
||||
bfree(meta_data);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
@ -761,8 +777,7 @@ static void adjust_sndbuf_size(struct rtmp_stream *stream, int new_size)
|
|||
static int init_send(struct rtmp_stream *stream)
|
||||
{
|
||||
int ret;
|
||||
size_t idx = 0;
|
||||
bool next = true;
|
||||
obs_output_t *context = stream->output;
|
||||
|
||||
#if defined(_WIN32)
|
||||
adjust_sndbuf_size(stream, MIN_SENDBUF_SIZE);
|
||||
|
|
@ -800,7 +815,6 @@ static int init_send(struct rtmp_stream *stream)
|
|||
bfree(stream->write_buf);
|
||||
|
||||
int total_bitrate = 0;
|
||||
obs_output_t *context = stream->output;
|
||||
|
||||
obs_encoder_t *vencoder = obs_output_get_video_encoder(context);
|
||||
if (vencoder) {
|
||||
|
|
@ -865,14 +879,25 @@ static int init_send(struct rtmp_stream *stream)
|
|||
}
|
||||
|
||||
os_atomic_set_bool(&stream->active, true);
|
||||
while (next) {
|
||||
if (!send_meta_data(stream, idx++, &next)) {
|
||||
warn("Disconnected while attempting to connect to "
|
||||
"server.");
|
||||
set_output_error(stream);
|
||||
return OBS_OUTPUT_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (!send_meta_data(stream)) {
|
||||
warn("Disconnected while attempting to send metadata");
|
||||
set_output_error(stream);
|
||||
return OBS_OUTPUT_DISCONNECTED;
|
||||
}
|
||||
|
||||
obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, 1);
|
||||
if (aencoder && !send_additional_meta_data(stream)) {
|
||||
warn("Disconnected while attempting to send additional "
|
||||
"metadata");
|
||||
return OBS_OUTPUT_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (obs_output_get_audio_encoder(context, 2) != NULL) {
|
||||
warn("Additional audio streams not supported");
|
||||
return OBS_OUTPUT_DISCONNECTED;
|
||||
}
|
||||
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
|
||||
return OBS_OUTPUT_SUCCESS;
|
||||
|
|
@ -982,18 +1007,6 @@ static int try_connect(struct rtmp_stream *stream)
|
|||
|
||||
RTMP_AddStream(&stream->rtmp, stream->key.array);
|
||||
|
||||
for (size_t idx = 1;; idx++) {
|
||||
obs_encoder_t *encoder =
|
||||
obs_output_get_audio_encoder(stream->output, idx);
|
||||
const char *encoder_name;
|
||||
|
||||
if (!encoder)
|
||||
break;
|
||||
|
||||
encoder_name = obs_encoder_get_name(encoder);
|
||||
RTMP_AddStream(&stream->rtmp, encoder_name);
|
||||
}
|
||||
|
||||
stream->rtmp.m_outChunkSize = 4096;
|
||||
stream->rtmp.m_bSendChunkSizeInfo = true;
|
||||
stream->rtmp.m_bUseNagle = true;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#define OPT_BIND_IP "bind_ip"
|
||||
#define OPT_NEWSOCKETLOOP_ENABLED "new_socket_loop_enabled"
|
||||
#define OPT_LOWLATENCY_ENABLED "low_latency_mode_enabled"
|
||||
#define OPT_METADATA_MULTITRACK "metadata_multitrack"
|
||||
|
||||
//#define TEST_FRAMEDROPS
|
||||
//#define TEST_FRAMEDROPS_WITH_BITRATE_SHORTCUTS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue