New upstream version 21.0.2+dfsg1
This commit is contained in:
parent
1f1bbb3518
commit
baafb6325b
706 changed files with 49633 additions and 5044 deletions
|
|
@ -19,6 +19,63 @@ else()
|
|||
add_definitions(-DNO_CRYPTO)
|
||||
endif()
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ftl-sdk/CMakeLists.txt")
|
||||
find_package(Libcurl REQUIRED)
|
||||
|
||||
include_directories(${LIBCURL_INCLUDE_DIRS})
|
||||
|
||||
set(ftl_SOURCES
|
||||
ftl-stream.c
|
||||
ftl-sdk/libftl/hmac/hmac.c
|
||||
ftl-sdk/libftl/hmac/sha2.c
|
||||
ftl-sdk/libftl/ftl-sdk.c
|
||||
ftl-sdk/libftl/handshake.c
|
||||
ftl-sdk/libftl/ingest.c
|
||||
ftl-sdk/libftl/ftl_helpers.c
|
||||
ftl-sdk/libftl/media.c
|
||||
ftl-sdk/libftl/gettimeofday/gettimeofday.c
|
||||
ftl-sdk/libftl/logging.c)
|
||||
set(ftl_HEADERS
|
||||
ftl-sdk/libftl/hmac/hmac.h
|
||||
ftl-sdk/libftl/hmac/sha2.h
|
||||
ftl-sdk/libftl/ftl.h
|
||||
ftl-sdk/libftl/ftl_private.h)
|
||||
set(ftl_IMPORTS
|
||||
${OBS_JANSSON_IMPORT}
|
||||
${LIBCURL_LIBRARIES})
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND ftl_SOURCES
|
||||
ftl-sdk/libftl/win32/socket.c
|
||||
ftl-sdk/libftl/gettimeofday/gettimeofday.c
|
||||
ftl-sdk/libftl/win32/threads.c)
|
||||
list(APPEND ftl_HEADERS
|
||||
ftl-sdk/libftl/gettimeofday/gettimeofday.h
|
||||
ftl-sdk/libftl/win32/threads.h)
|
||||
|
||||
include_directories(ftl-sdk/libftl/win32)
|
||||
else()
|
||||
list(APPEND ftl_SOURCES
|
||||
ftl-sdk/libftl/posix/socket.c
|
||||
ftl-sdk/libftl/posix/threads.c)
|
||||
list(APPEND ftl_HEADERS
|
||||
ftl-sdk/libftl/posix/threads.h)
|
||||
|
||||
include_directories(ftl-sdk/libftl/posix)
|
||||
endif()
|
||||
|
||||
include_directories(ftl-sdk/libftl)
|
||||
|
||||
set(COMPILE_FTL TRUE)
|
||||
else()
|
||||
set(COMPILE_FTL FALSE)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/obs-outputs-config.h.in"
|
||||
"${CMAKE_BINARY_DIR}/plugins/obs-outputs/config/obs-outputs-config.h")
|
||||
|
||||
include_directories("${CMAKE_BINARY_DIR}/plugins/obs-outputs/config")
|
||||
|
||||
if(WIN32)
|
||||
set(obs-outputs_PLATFORM_DEPS
|
||||
|
|
@ -60,13 +117,12 @@ if(NOT WIN32)
|
|||
endif()
|
||||
|
||||
set(obs-outputs_HEADERS
|
||||
"${CMAKE_BINARY_DIR}/plugins/obs-outputs/config/obs-outputs-config.h"
|
||||
obs-output-ver.h
|
||||
rtmp-helpers.h
|
||||
rtmp-stream.h
|
||||
net-if.h
|
||||
flv-mux.h
|
||||
flv-output.h
|
||||
librtmp)
|
||||
flv-mux.h)
|
||||
set(obs-outputs_SOURCES
|
||||
obs-outputs.c
|
||||
null-output.c
|
||||
|
|
@ -77,14 +133,17 @@ set(obs-outputs_SOURCES
|
|||
net-if.c)
|
||||
|
||||
add_library(obs-outputs MODULE
|
||||
${ftl_SOURCES}
|
||||
${ftl_HEADERS}
|
||||
${obs-outputs_SOURCES}
|
||||
${obs-outputs_HEADER}
|
||||
${obs-outputs_HEADERS}
|
||||
${obs-outputs_librtmp_SOURCES}
|
||||
${obs-outputs_librtmp_HEADERS})
|
||||
target_link_libraries(obs-outputs
|
||||
libobs
|
||||
${SSL_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${ftl_IMPORTS}
|
||||
${obs-outputs_PLATFORM_DEPS})
|
||||
|
||||
install_obs_plugin_with_data(obs-outputs data)
|
||||
|
|
|
|||
|
|
@ -4,4 +4,11 @@ FLVOutput="Sortida del fitxer FLV"
|
|||
FLVOutput.FilePath="Camí del fitxer"
|
||||
Default="Per defecte"
|
||||
|
||||
ConnectionTimedOut="S'ha esgotat el temps de la connexió. Assegureu-vos que ha configurat un servei de transmissió vàlid i cap tallafocs està bloquejant la connexió."
|
||||
PermissionDenied="La connexió ha estat bloquejada. Comproveu la configuració del tallafocs o antivirus per assegurar-se que OBS disposa de llibertat absoluta a Internet."
|
||||
ConnectionAborted="La connexió ha estat avortada. Normalment això indica que hi ha problemes de connexió entre el vostre equip i el servei de transmissió."
|
||||
ConnectionReset="La connexió s'ha acabat. Normalment això indica que hi ha problemes de connexió entre el vostre equip i el servei de transmissió."
|
||||
HostNotFound="Nom d'amfitrió no trobat. Assegureu-vos que hi hagi configurat un servidor de transmissió vàlid i que la seva connexió a Internet / DNS estiguin funcionant correctament."
|
||||
NoData="Nom d'amfitrió trobat, però no hi ha dades del tipus sol·licitat. Això pot passar si heu enllaçat a una adreça IPv6 i el seu servei de transmissió només té adreces IPv4 (veure configuració / avançada)."
|
||||
AddressNotAvailable="Direcció no disponible. Potser heu intentat enllaçar amb una adreça IP no vàlida (veure configuració / avançada)."
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
RTMPStream="RTMP Strøm"
|
||||
RTMPStream.DropThreshold="Drop Tærskel (millisekunder)"
|
||||
RTMPStream.DropThreshold="Tabstærskel (millisekunder)"
|
||||
FLVOutput="FLV File Output"
|
||||
FLVOutput.FilePath="Filsti"
|
||||
Default="Standard"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ FLVOutput="Archivo de salida FLV"
|
|||
FLVOutput.FilePath="Ruta de archivo"
|
||||
Default="Por defecto"
|
||||
|
||||
ConnectionTimedOut="Agotado el tiempo de la conexión. Asegúrese de que ha configurado un servicio de streaming válido y ningún firewall está bloqueando la conexión."
|
||||
PermissionDenied="La conexión ha sido bloqueada. Compruebe su configuración del cortafuegos o anti-virus para asegurarse de que OBS tiene acceso completo a Internet."
|
||||
ConnectionAborted="La conexión ha sido abortada. Normalmente esto indica que hay problemas de conexión entre tu equipo y el servicio de transmisión."
|
||||
ConnectionReset="La conexión se ha terminado. Normalmente esto indica que hay problemas de conexión entre tu equipo y el servicio de transmisión."
|
||||
HostNotFound="Nombre de host no encontrado. Asegúrese que haya configurado un servidor de transmisión valido y que su conexión a Internet / DNS estén funcionando correctamente."
|
||||
NoData="Nombre de host encontrado, pero no hay datos del tipo solicitado. Esto puede ocurrir si has enlazado a una dirección IPv6 y su servicio de streaming sólo tiene direcciones IPv4 (ver Configuración / Avanzada)."
|
||||
AddressNotAvailable="Dirección no disponible. Puede que hayas intentado enlazar con una dirección IP no valida (vea Configuración / Avanzado)."
|
||||
|
||||
|
|
|
|||
|
|
@ -7,4 +7,8 @@ Default="Interface par défaut"
|
|||
ConnectionTimedOut="La connexion à expiré. Assurez-vous que vous avez configuré un service de streaming valide et qu'aucun pare-feu ne bloque la connexion."
|
||||
PermissionDenied="La connexion a été bloquée. Vérifiez vos paramètres de pare-feu / antivirus pour vous assurer OBS est autorisé à avoir l'accès complet d'internet."
|
||||
ConnectionAborted="La connexion à été interrompue. Cela indique généralement des problèmes de connexion internet entre vous et le service de streaming."
|
||||
ConnectionReset="La connexion à été interrompue. Cela indique généralement des problèmes de connexion internet entre vous et le service de diffusion."
|
||||
HostNotFound="Nom d’hôte non trouvé. Assurez-vous que vous avez spécifié un serveur de diffusion valide et que votre connexion internet / DNS fonctionnent correctement."
|
||||
NoData="Nom d’hôte trouvé, mais aucune donnée du type requis. Cela peut se produire si vous avez lié à une adresse IPv6 et votre service de diffusion ne possède que des adresses IPv4 (voir Paramètres / Avancé)."
|
||||
AddressNotAvailable="Adresse non disponible. Vous avez peut-être essayé de la lier à une adresse IP non valide (voir Paramètres / Avancé)."
|
||||
|
||||
|
|
|
|||
|
|
@ -4,4 +4,11 @@ FLVOutput="Uscita file FLV"
|
|||
FLVOutput.FilePath="Destinazione file"
|
||||
Default="Predefinito"
|
||||
|
||||
ConnectionTimedOut="Timeout della connessione. Assicurarsi di aver configurato un valido servizio di streaming e nessun firewall sta bloccando la connessione."
|
||||
PermissionDenied="La connessione è stata bloccata. Controlla il tuo firewall / impostazioni di anti-virus per assicurarsi che per OBS sia consentito accesso completo a internet."
|
||||
ConnectionAborted="La connessione è stata interrotta. In genere indica problemi di connessione tra l'utente e il servizio di streaming."
|
||||
ConnectionReset="La connessione è stata ripristinata dal peer. In genere indica problemi di connessione tra l'utente e il servizio di streaming."
|
||||
HostNotFound="Nome host non trovato. Assicurarsi di aver inserito un valido server per lo streaming e che la connessione a internet / DNS funzioni correttamente."
|
||||
NoData="Nome host trovato, ma nessun dato del tipo richiesto. Ciò può verificarsi se è stato associato a un indirizzo IPv6 e il servizio di streaming ha solo indirizzi IPv4 (vedere Impostazioni / avanzate)."
|
||||
AddressNotAvailable="Indirizzo non disponibile. Si è cercato di associare un indirizzo IP non valido (vedere Impostazioni / avanzate)."
|
||||
|
||||
|
|
|
|||
|
|
@ -4,4 +4,11 @@ FLVOutput="FLV-filutgang"
|
|||
FLVOutput.FilePath="Filbane"
|
||||
Default="Standard"
|
||||
|
||||
ConnectionTimedOut="Forbindelsen ble tidsavbrutt. Sørg for at du har konfigurert en strømmingstjeneste og at den ikke blir blokkert av en brannmur."
|
||||
PermissionDenied="Tilkoblingen ble blokkert. Sjekk at OBS har full internettilgang i brannmur/antivirusinnstillingene dine."
|
||||
ConnectionAborted="Tilkoblingen ble avbrutt. Dette betyr vanligvis at det er problemer med nettverkskoblingen mellom deg og strømmetjenesten."
|
||||
ConnectionReset="Tilkoblingen ble avbrutt. Dette betyr vanligvis at det er problemer med nettverkskoblingen mellom deg og strømmetjenesten."
|
||||
HostNotFound="Tjeneren ble ikke funnet. Kontroller at du har angitt en gyldig streaming server og at tilkoblingen / DNS fungerer."
|
||||
NoData="Tjeneren funnet, men ingen data for den forespurte typen. Dette kan skje hvis du har bundet til en IPv6-adresse og streaming tjeneste har bare IPv4-adresser (se Snnstillinger / Avansert)."
|
||||
AddressNotAvailable="Adresse ikke tilgjengelig. Du prøvde å binde til en ugyldig IP-adresse (se Innstillinger / Avansert)."
|
||||
|
||||
|
|
|
|||
|
|
@ -4,4 +4,11 @@ FLVOutput="Выходной файл FLV"
|
|||
FLVOutput.FilePath="Путь к файлу"
|
||||
Default="По умолчанию"
|
||||
|
||||
ConnectionTimedOut="Истекло время ожидания соединения. Убедитесь, что вы настроили действительный сервис вещания и брандмауэр не блокирует подключение."
|
||||
PermissionDenied="Соединение было заблокировано. Проверьте параметры вашего брандмауэра/антивируса, чтобы убедиться, что OBS разрешен полный доступ к интернету."
|
||||
ConnectionAborted="Соединение было прервано. Обычно это указывает на проблемы с интернет-соединением между вами и службой вещания."
|
||||
ConnectionReset="Соединение было сброшено одноранговым узлом. Обычно это указывает на проблемы с интернет-соединением между вами и службой вещания."
|
||||
HostNotFound="Имя узла не найдено. Убедитесь, что вы ввели действительный сервер вещания и ваше подключение к интернету/DNS работают правильно."
|
||||
NoData="Имя узла найдено, но нет данных запрошенного типа. Такое может случиться, если вы привязаны к IPv6-адресу, а ваш сервис вещания имеет только IPv4-адреса (смотрите Настройки - Расширенные)."
|
||||
AddressNotAvailable="Адрес недоступен. Возможно вы пытались привязаться к недействительному IP-адресу (смотрите Настройки - Расширенные)."
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
RTMPStream="RTMP stream"
|
||||
RTMPStream.DropThreshold="Prah strát (milisekundy)"
|
||||
FLVOutput="Výstup do súboru FLV"
|
||||
FLVOutput.FilePath="Cesta k súboru"
|
||||
Default="Základné"
|
||||
Default="Predvolené"
|
||||
|
||||
ConnectionReset="Pripojenie bolo resetované druhou stranou. Toto obvykle znamená, že nastali problémy s pripojením medzi vami a streaming službou."
|
||||
AddressNotAvailable="Adresa nie je k dispozícii. Môžno ste sa snažili naviazať na neplatnú IP adresu (pozrite si Nastavenia / Rozšírené)."
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Default="Standard"
|
|||
ConnectionTimedOut="Anslutningen förlorades. Se till att du har konfigurerat en giltig strömningstjänst och att inga brandväggar blockerar anslutningen."
|
||||
PermissionDenied="Anslutningen blockerades. Kontrollera inställningarna för din brandvägg/antivirusprogram för att se till att OBS har fullständig åtkomst till Internet."
|
||||
ConnectionAborted="Anslutningen avbröts. Detta kan indikera problem med Internetanslutningen mellan dig och strömningstjänsten."
|
||||
ConnectionReset="Anslutningen återställdes av en peer. Detta kan indikera problem med Internetanslutningen mellan dig och strömningstjänsten."
|
||||
HostNotFound="Värdnamnet hittades inte. Se till att du har angivit en giltigt strömningstjänst och att din Internetanslutning / DNS fungerar på rätt sätt."
|
||||
NoData="Värdnamnet hittades, men ingen data av den begärda typen. Detta kan hända om du ansluter till en IPv6-adress och din strömningstjänst endast har IPv4-adresser (gå till Inställningar / Avancerat)."
|
||||
AddressNotAvailable="Adressen är inte tillgänglig. Du kanske försökte ansluta till en ogiltig IP-adress (gå till Inställningar / Avancerat)."
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ FLVOutput="FLV tập tin đầu ra"
|
|||
FLVOutput.FilePath="Đường dẫn tệp"
|
||||
Default="Mặc định"
|
||||
|
||||
ConnectionTimedOut="Kết nối đã hết thời. Đảm bảo bạn đã định cấu hình dịch vụ phát trực tuyến hợp lệ và không có tường lửa nào đang chặn kết nối."
|
||||
PermissionDenied="Kết nối đã bị chặn. Hãy kiểm tra tường lửa / cài đặt chống virus để đảm bảo rằng OBS được cho phép truy cập internet đầy đủ."
|
||||
ConnectionAborted="Kết nối đã bị hủy bỏ. Điều này thường chỉ ra kết nối internet giữa bạn và dịch vụ trực tuyến có vấn đề."
|
||||
ConnectionReset="Kết nối đã được đặt lại bởi peer. Điều này thường chỉ ra các sự cố kết nối Internet giữa bạn và dịch vụ truyền trực tuyến."
|
||||
HostNotFound="Tên máy chủ không tìm thấy. Đảm bảo rằng bạn đã nhập vào một máy chủ stream hợp lệ và kết nối internet của bạn / DNS đang hoạt động tốt."
|
||||
NoData="Tên máy chủ được tìm thấy nhưng không có dữ liệu được yêu cầu. Điều này có thể xảy ra nếu bạn sử dụng địa chỉ IPv6 và dịch vụ stream của bạn chỉ có địa chỉ IPv4 (xem Cài đặt / Nâng cao)."
|
||||
AddressNotAvailable="Địa chỉ không có sẵn. Bạn có thể đã cố gắng liên kết với một địa chỉ IP không hợp lệ (xem Cài đặt / Nâng cao)."
|
||||
|
|
|
|||
|
|
@ -102,6 +102,18 @@ static bool build_flv_meta_data(obs_output_t *context,
|
|||
|
||||
enc_bool_val(&enc, end, "stereo",
|
||||
audio_output_get_channels(audio) == 2);
|
||||
enc_bool_val(&enc, end, "2.1",
|
||||
audio_output_get_channels(audio) == 3);
|
||||
enc_bool_val(&enc, end, "3.1",
|
||||
audio_output_get_channels(audio) == 4);
|
||||
enc_bool_val(&enc, end, "4.0",
|
||||
audio_output_get_channels(audio) == 4);
|
||||
enc_bool_val(&enc, end, "4.1",
|
||||
audio_output_get_channels(audio) == 5);
|
||||
enc_bool_val(&enc, end, "5.1",
|
||||
audio_output_get_channels(audio) == 6);
|
||||
enc_bool_val(&enc, end, "7.1",
|
||||
audio_output_get_channels(audio) == 8);
|
||||
|
||||
dstr_printf(&encoder_name, "%s (libobs version ",
|
||||
MODULE_NAME);
|
||||
|
|
@ -164,7 +176,7 @@ bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
|||
|
||||
s_write(&s, meta_data, meta_data_size);
|
||||
|
||||
s_wb32(&s, (uint32_t)serializer_get_pos(&s) - start_pos + 4 - 1);
|
||||
s_wb32(&s, (uint32_t)serializer_get_pos(&s) - start_pos - 1);
|
||||
|
||||
*output = data.bytes.array;
|
||||
*size = data.bytes.num;
|
||||
|
|
@ -177,11 +189,11 @@ bool flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
|||
static int32_t last_time = 0;
|
||||
#endif
|
||||
|
||||
static void flv_video(struct serializer *s, struct encoder_packet *packet,
|
||||
bool is_header)
|
||||
static void flv_video(struct serializer *s, int32_t dts_offset,
|
||||
struct encoder_packet *packet, bool is_header)
|
||||
{
|
||||
int64_t offset = packet->pts - packet->dts;
|
||||
int32_t time_ms = get_ms_time(packet, packet->dts);
|
||||
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
||||
|
||||
if (!packet->data || !packet->size)
|
||||
return;
|
||||
|
|
@ -209,13 +221,13 @@ static void flv_video(struct serializer *s, struct encoder_packet *packet,
|
|||
s_write(s, packet->data, packet->size);
|
||||
|
||||
/* write tag size (starting byte doesn't count) */
|
||||
s_wb32(s, (uint32_t)serializer_get_pos(s) + 4 - 1);
|
||||
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
||||
}
|
||||
|
||||
static void flv_audio(struct serializer *s, struct encoder_packet *packet,
|
||||
bool is_header)
|
||||
static void flv_audio(struct serializer *s, int32_t dts_offset,
|
||||
struct encoder_packet *packet, bool is_header)
|
||||
{
|
||||
int32_t time_ms = get_ms_time(packet, packet->dts);
|
||||
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
||||
|
||||
if (!packet->data || !packet->size)
|
||||
return;
|
||||
|
|
@ -242,10 +254,10 @@ static void flv_audio(struct serializer *s, struct encoder_packet *packet,
|
|||
s_write(s, packet->data, packet->size);
|
||||
|
||||
/* write tag size (starting byte doesn't count) */
|
||||
s_wb32(s, (uint32_t)serializer_get_pos(s) + 4 - 1);
|
||||
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
||||
}
|
||||
|
||||
void flv_packet_mux(struct encoder_packet *packet,
|
||||
void flv_packet_mux(struct encoder_packet *packet, int32_t dts_offset,
|
||||
uint8_t **output, size_t *size, bool is_header)
|
||||
{
|
||||
struct array_output_data data;
|
||||
|
|
@ -254,9 +266,9 @@ void flv_packet_mux(struct encoder_packet *packet,
|
|||
array_output_serializer_init(&s, &data);
|
||||
|
||||
if (packet->type == OBS_ENCODER_VIDEO)
|
||||
flv_video(&s, packet, is_header);
|
||||
flv_video(&s, dts_offset, packet, is_header);
|
||||
else
|
||||
flv_audio(&s, packet, is_header);
|
||||
flv_audio(&s, dts_offset, packet, is_header);
|
||||
|
||||
*output = data.bytes.array;
|
||||
*size = data.bytes.num;
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@
|
|||
|
||||
#define MILLISECOND_DEN 1000
|
||||
|
||||
static uint32_t get_ms_time(struct encoder_packet *packet, int64_t val)
|
||||
static int32_t get_ms_time(struct encoder_packet *packet, int64_t val)
|
||||
{
|
||||
return (uint32_t)(val * MILLISECOND_DEN / packet->timebase_den);
|
||||
return (int32_t)(val * MILLISECOND_DEN / packet->timebase_den);
|
||||
}
|
||||
|
||||
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_packet_mux(struct encoder_packet *packet,
|
||||
extern void flv_packet_mux(struct encoder_packet *packet, int32_t dts_offset,
|
||||
uint8_t **output, size_t *size, bool is_header);
|
||||
|
|
|
|||
|
|
@ -32,14 +32,31 @@
|
|||
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
|
||||
|
||||
struct flv_output {
|
||||
obs_output_t *output;
|
||||
struct dstr path;
|
||||
FILE *file;
|
||||
bool active;
|
||||
bool sent_headers;
|
||||
int64_t last_packet_ts;
|
||||
obs_output_t *output;
|
||||
struct dstr path;
|
||||
FILE *file;
|
||||
volatile bool active;
|
||||
volatile bool stopping;
|
||||
uint64_t stop_ts;
|
||||
bool sent_headers;
|
||||
int64_t last_packet_ts;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
bool got_first_video;
|
||||
int32_t start_dts_offset;
|
||||
};
|
||||
|
||||
static inline bool stopping(struct flv_output *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->stopping);
|
||||
}
|
||||
|
||||
static inline bool active(struct flv_output *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->active);
|
||||
}
|
||||
|
||||
static const char *flv_output_getname(void *unused)
|
||||
{
|
||||
UNUSED_PARAMETER(unused);
|
||||
|
|
@ -52,9 +69,7 @@ static void flv_output_destroy(void *data)
|
|||
{
|
||||
struct flv_output *stream = data;
|
||||
|
||||
if (stream->active)
|
||||
flv_output_stop(data, 0);
|
||||
|
||||
pthread_mutex_destroy(&stream->mutex);
|
||||
dstr_free(&stream->path);
|
||||
bfree(stream);
|
||||
}
|
||||
|
|
@ -63,32 +78,12 @@ static void *flv_output_create(obs_data_t *settings, obs_output_t *output)
|
|||
{
|
||||
struct flv_output *stream = bzalloc(sizeof(struct flv_output));
|
||||
stream->output = output;
|
||||
pthread_mutex_init(&stream->mutex, NULL);
|
||||
|
||||
UNUSED_PARAMETER(settings);
|
||||
return stream;
|
||||
}
|
||||
|
||||
static void flv_output_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct flv_output *stream = data;
|
||||
|
||||
if (stream->active) {
|
||||
if (stream->file) {
|
||||
write_file_info(stream->file, stream->last_packet_ts,
|
||||
os_ftelli64(stream->file));
|
||||
|
||||
fclose(stream->file);
|
||||
}
|
||||
obs_output_end_data_capture(stream->output);
|
||||
stream->active = false;
|
||||
stream->sent_headers = false;
|
||||
|
||||
info("FLV file output complete");
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(ts);
|
||||
}
|
||||
|
||||
static int write_packet(struct flv_output *stream,
|
||||
struct encoder_packet *packet, bool is_header)
|
||||
{
|
||||
|
|
@ -98,10 +93,10 @@ static int write_packet(struct flv_output *stream,
|
|||
|
||||
stream->last_packet_ts = get_ms_time(packet, packet->dts);
|
||||
|
||||
flv_packet_mux(packet, &data, &size, is_header);
|
||||
flv_packet_mux(packet, is_header ? 0 : stream->start_dts_offset,
|
||||
&data, &size, is_header);
|
||||
fwrite(data, 1, size, stream->file);
|
||||
bfree(data);
|
||||
obs_encoder_packet_release(packet);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -120,15 +115,13 @@ static void write_audio_header(struct flv_output *stream)
|
|||
{
|
||||
obs_output_t *context = stream->output;
|
||||
obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, 0);
|
||||
uint8_t *header;
|
||||
|
||||
struct encoder_packet packet = {
|
||||
.type = OBS_ENCODER_AUDIO,
|
||||
.timebase_den = 1
|
||||
};
|
||||
|
||||
obs_encoder_get_extra_data(aencoder, &header, &packet.size);
|
||||
packet.data = bmemdup(header, packet.size);
|
||||
obs_encoder_get_extra_data(aencoder, &packet.data, &packet.size);
|
||||
write_packet(stream, &packet, true);
|
||||
}
|
||||
|
||||
|
|
@ -148,13 +141,14 @@ static void write_video_header(struct flv_output *stream)
|
|||
obs_encoder_get_extra_data(vencoder, &header, &size);
|
||||
packet.size = obs_parse_avc_header(&packet.data, header, size);
|
||||
write_packet(stream, &packet, true);
|
||||
bfree(packet.data);
|
||||
}
|
||||
|
||||
static void write_headers(struct flv_output *stream)
|
||||
{
|
||||
write_meta_data(stream);
|
||||
write_audio_header(stream);
|
||||
write_video_header(stream);
|
||||
write_audio_header(stream);
|
||||
}
|
||||
|
||||
static bool flv_output_start(void *data)
|
||||
|
|
@ -168,6 +162,10 @@ static bool flv_output_start(void *data)
|
|||
if (!obs_output_initialize_encoders(stream->output, 0))
|
||||
return false;
|
||||
|
||||
stream->got_first_video = false;
|
||||
stream->sent_headers = false;
|
||||
os_atomic_set_bool(&stream->stopping, false);
|
||||
|
||||
/* get path */
|
||||
settings = obs_output_get_settings(stream->output);
|
||||
path = obs_data_get_string(settings, "path");
|
||||
|
|
@ -181,30 +179,73 @@ static bool flv_output_start(void *data)
|
|||
}
|
||||
|
||||
/* write headers and start capture */
|
||||
stream->active = true;
|
||||
os_atomic_set_bool(&stream->active, true);
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
|
||||
info("Writing FLV file '%s'...", stream->path.array);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void flv_output_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct flv_output *stream = data;
|
||||
stream->stop_ts = ts / 1000;
|
||||
os_atomic_set_bool(&stream->stopping, true);
|
||||
}
|
||||
|
||||
static void flv_output_actual_stop(struct flv_output *stream)
|
||||
{
|
||||
os_atomic_set_bool(&stream->active, false);
|
||||
|
||||
if (stream->file) {
|
||||
write_file_info(stream->file, stream->last_packet_ts,
|
||||
os_ftelli64(stream->file));
|
||||
|
||||
fclose(stream->file);
|
||||
}
|
||||
obs_output_end_data_capture(stream->output);
|
||||
|
||||
info("FLV file output complete");
|
||||
}
|
||||
|
||||
static void flv_output_data(void *data, struct encoder_packet *packet)
|
||||
{
|
||||
struct flv_output *stream = data;
|
||||
struct encoder_packet parsed_packet;
|
||||
|
||||
pthread_mutex_lock(&stream->mutex);
|
||||
|
||||
if (!active(stream))
|
||||
goto unlock;
|
||||
|
||||
if (stopping(stream)) {
|
||||
if (packet->sys_dts_usec >= (int64_t)stream->stop_ts) {
|
||||
flv_output_actual_stop(stream);
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stream->sent_headers) {
|
||||
write_headers(stream);
|
||||
stream->sent_headers = true;
|
||||
}
|
||||
|
||||
if (packet->type == OBS_ENCODER_VIDEO) {
|
||||
if (!stream->got_first_video) {
|
||||
stream->start_dts_offset =
|
||||
get_ms_time(packet, packet->dts);
|
||||
stream->got_first_video = true;
|
||||
}
|
||||
|
||||
obs_parse_avc_packet(&parsed_packet, packet);
|
||||
write_packet(stream, &parsed_packet, false);
|
||||
obs_encoder_packet_release(&parsed_packet);
|
||||
} else {
|
||||
write_packet(stream, packet, false);
|
||||
}
|
||||
|
||||
unlock:
|
||||
pthread_mutex_unlock(&stream->mutex);
|
||||
}
|
||||
|
||||
static obs_properties_t *flv_output_properties(void *unused)
|
||||
|
|
@ -220,13 +261,15 @@ static obs_properties_t *flv_output_properties(void *unused)
|
|||
}
|
||||
|
||||
struct obs_output_info flv_output_info = {
|
||||
.id = "flv_output",
|
||||
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED,
|
||||
.get_name = flv_output_getname,
|
||||
.create = flv_output_create,
|
||||
.destroy = flv_output_destroy,
|
||||
.start = flv_output_start,
|
||||
.stop = flv_output_stop,
|
||||
.encoded_packet = flv_output_data,
|
||||
.get_properties = flv_output_properties
|
||||
.id = "flv_output",
|
||||
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED,
|
||||
.encoded_video_codecs = "h264",
|
||||
.encoded_audio_codecs = "aac",
|
||||
.get_name = flv_output_getname,
|
||||
.create = flv_output_create,
|
||||
.destroy = flv_output_destroy,
|
||||
.start = flv_output_start,
|
||||
.stop = flv_output_stop,
|
||||
.encoded_packet = flv_output_data,
|
||||
.get_properties = flv_output_properties
|
||||
};
|
||||
|
|
|
|||
1166
plugins/obs-outputs/ftl-stream.c
Normal file
1166
plugins/obs-outputs/ftl-stream.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,8 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
|
||||
#include "net-if.h"
|
||||
#include <util/platform.h>
|
||||
#include <util/dstr.h>
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static void null_output_stop(void *data, uint64_t ts)
|
|||
|
||||
static void null_output_data(void *data, struct encoder_packet *packet)
|
||||
{
|
||||
struct null_output *context = data;
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(packet);
|
||||
}
|
||||
|
||||
|
|
|
|||
15
plugins/obs-outputs/obs-outputs-config.h.in
Normal file
15
plugins/obs-outputs/obs-outputs-config.h.in
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef ON
|
||||
#define ON 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define COMPILE_FTL @COMPILE_FTL@
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include <obs-module.h>
|
||||
|
||||
#include "obs-outputs-config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
|
|
@ -11,6 +13,9 @@ OBS_MODULE_USE_DEFAULT_LOCALE("obs-outputs", "en-US")
|
|||
extern struct obs_output_info rtmp_output_info;
|
||||
extern struct obs_output_info null_output_info;
|
||||
extern struct obs_output_info flv_output_info;
|
||||
#if COMPILE_FTL
|
||||
extern struct obs_output_info ftl_output_info;
|
||||
#endif
|
||||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
|
|
@ -22,6 +27,9 @@ bool obs_module_load(void)
|
|||
obs_register_output(&rtmp_output_info);
|
||||
obs_register_output(&null_output_info);
|
||||
obs_register_output(&flv_output_info);
|
||||
#if COMPILE_FTL
|
||||
obs_register_output(&ftl_output_info);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -178,15 +178,17 @@ static void rtmp_stream_stop(void *data, uint64_t ts)
|
|||
pthread_join(stream->connect_thread, NULL);
|
||||
|
||||
stream->stop_ts = ts / 1000ULL;
|
||||
os_event_signal(stream->stop_event);
|
||||
|
||||
if (ts)
|
||||
stream->shutdown_timeout_ts = ts +
|
||||
(uint64_t)stream->max_shutdown_time_sec * 1000000000ULL;
|
||||
|
||||
if (active(stream)) {
|
||||
os_event_signal(stream->stop_event);
|
||||
if (stream->stop_ts == 0)
|
||||
os_sem_post(stream->send_sem);
|
||||
} else {
|
||||
obs_output_signal_stop(stream->output, OBS_OUTPUT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,6 +295,8 @@ static void droptest_cap_data_rate(struct rtmp_stream *stream, size_t size)
|
|||
|
||||
static int socket_queue_data(RTMPSockBuf *sb, const char *data, int len, void *arg)
|
||||
{
|
||||
UNUSED_PARAMETER(sb);
|
||||
|
||||
struct rtmp_stream *stream = arg;
|
||||
|
||||
retry_send:
|
||||
|
|
@ -345,7 +349,8 @@ static int send_packet(struct rtmp_stream *stream,
|
|||
}
|
||||
}
|
||||
|
||||
flv_packet_mux(packet, &data, &size, is_header);
|
||||
flv_packet_mux(packet, is_header ? 0 : stream->start_dts_offset,
|
||||
&data, &size, is_header);
|
||||
|
||||
#ifdef TEST_FRAMEDROPS
|
||||
droptest_cap_data_rate(stream, size);
|
||||
|
|
@ -656,6 +661,14 @@ static int init_send(struct rtmp_stream *stream)
|
|||
obs_data_t *params = obs_encoder_get_settings(vencoder);
|
||||
if (params) {
|
||||
int bitrate = obs_data_get_int(params, "bitrate");
|
||||
if (!bitrate) {
|
||||
warn ("Video encoder didn't return a "
|
||||
"valid bitrate, new network "
|
||||
"code may function poorly. "
|
||||
"Low latency mode disabled.");
|
||||
stream->low_latency_mode = false;
|
||||
bitrate = 10000;
|
||||
}
|
||||
total_bitrate += bitrate;
|
||||
obs_data_release(params);
|
||||
}
|
||||
|
|
@ -666,6 +679,8 @@ static int init_send(struct rtmp_stream *stream)
|
|||
obs_data_t *params = obs_encoder_get_settings(aencoder);
|
||||
if (params) {
|
||||
int bitrate = obs_data_get_int(params, "bitrate");
|
||||
if (!bitrate)
|
||||
bitrate = 160;
|
||||
total_bitrate += bitrate;
|
||||
obs_data_release(params);
|
||||
}
|
||||
|
|
@ -864,6 +879,7 @@ static bool init_connect(struct rtmp_stream *stream)
|
|||
stream->total_bytes_sent = 0;
|
||||
stream->dropped_frames = 0;
|
||||
stream->min_priority = 0;
|
||||
stream->got_first_video = false;
|
||||
|
||||
settings = obs_output_get_settings(stream->output);
|
||||
dstr_copy(&stream->path, obs_service_get_url(service));
|
||||
|
|
@ -951,8 +967,9 @@ static inline size_t num_buffered_packets(struct rtmp_stream *stream)
|
|||
static void drop_frames(struct rtmp_stream *stream, const char *name,
|
||||
int highest_priority, bool pframes)
|
||||
{
|
||||
UNUSED_PARAMETER(pframes);
|
||||
|
||||
struct circlebuf new_buf = {0};
|
||||
uint64_t last_drop_dts_usec = 0;
|
||||
int num_frames_dropped = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
@ -967,8 +984,6 @@ static void drop_frames(struct rtmp_stream *stream, const char *name,
|
|||
struct encoder_packet packet;
|
||||
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
|
||||
|
||||
last_drop_dts_usec = packet.dts_usec;
|
||||
|
||||
/* do not drop audio data or video keyframes */
|
||||
if (packet.type == OBS_ENCODER_AUDIO ||
|
||||
packet.drop_priority >= highest_priority) {
|
||||
|
|
@ -1078,10 +1093,17 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet)
|
|||
if (disconnected(stream) || !active(stream))
|
||||
return;
|
||||
|
||||
if (packet->type == OBS_ENCODER_VIDEO)
|
||||
if (packet->type == OBS_ENCODER_VIDEO) {
|
||||
if (!stream->got_first_video) {
|
||||
stream->start_dts_offset =
|
||||
get_ms_time(packet, packet->dts);
|
||||
stream->got_first_video = true;
|
||||
}
|
||||
|
||||
obs_parse_avc_packet(&new_packet, packet);
|
||||
else
|
||||
} else {
|
||||
obs_encoder_packet_ref(&new_packet, packet);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&stream->packets_mutex);
|
||||
|
||||
|
|
@ -1172,21 +1194,23 @@ static int rtmp_stream_connect_time(void *data)
|
|||
}
|
||||
|
||||
struct obs_output_info rtmp_output_info = {
|
||||
.id = "rtmp_output",
|
||||
.flags = OBS_OUTPUT_AV |
|
||||
OBS_OUTPUT_ENCODED |
|
||||
OBS_OUTPUT_SERVICE |
|
||||
OBS_OUTPUT_MULTI_TRACK,
|
||||
.get_name = rtmp_stream_getname,
|
||||
.create = rtmp_stream_create,
|
||||
.destroy = rtmp_stream_destroy,
|
||||
.start = rtmp_stream_start,
|
||||
.stop = rtmp_stream_stop,
|
||||
.encoded_packet = rtmp_stream_data,
|
||||
.get_defaults = rtmp_stream_defaults,
|
||||
.get_properties = rtmp_stream_properties,
|
||||
.get_total_bytes = rtmp_stream_total_bytes_sent,
|
||||
.get_congestion = rtmp_stream_congestion,
|
||||
.get_connect_time_ms= rtmp_stream_connect_time,
|
||||
.get_dropped_frames = rtmp_stream_dropped_frames
|
||||
.id = "rtmp_output",
|
||||
.flags = OBS_OUTPUT_AV |
|
||||
OBS_OUTPUT_ENCODED |
|
||||
OBS_OUTPUT_SERVICE |
|
||||
OBS_OUTPUT_MULTI_TRACK,
|
||||
.encoded_video_codecs = "h264",
|
||||
.encoded_audio_codecs = "aac",
|
||||
.get_name = rtmp_stream_getname,
|
||||
.create = rtmp_stream_create,
|
||||
.destroy = rtmp_stream_destroy,
|
||||
.start = rtmp_stream_start,
|
||||
.stop = rtmp_stream_stop,
|
||||
.encoded_packet = rtmp_stream_data,
|
||||
.get_defaults = rtmp_stream_defaults,
|
||||
.get_properties = rtmp_stream_properties,
|
||||
.get_total_bytes = rtmp_stream_total_bytes_sent,
|
||||
.get_congestion = rtmp_stream_congestion,
|
||||
.get_connect_time_ms = rtmp_stream_connect_time,
|
||||
.get_dropped_frames = rtmp_stream_dropped_frames
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ struct rtmp_stream {
|
|||
struct circlebuf packets;
|
||||
bool sent_headers;
|
||||
|
||||
bool got_first_video;
|
||||
int64_t start_dts_offset;
|
||||
|
||||
volatile bool connecting;
|
||||
pthread_t connect_thread;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue