New upstream version 0.15.4+dfsg1
This commit is contained in:
parent
55d5047af0
commit
67704ac59c
359 changed files with 8423 additions and 1050 deletions
|
|
@ -2,11 +2,11 @@ FFmpegOutput="FFmpeg ulostulo"
|
|||
FFmpegAAC="FFmpeg oletus AAC-enkooderi"
|
||||
Bitrate="Bitrate"
|
||||
Preset="Esiasetus"
|
||||
RateControl="Nopeudensäädin"
|
||||
KeyframeIntervalSec="Keyframe-väli (sec, 0=auto)"
|
||||
RateControl="Rate Control -tila"
|
||||
KeyframeIntervalSec="Keyframe-väli (sekunteina, 0=automaattinen)"
|
||||
Lossless="Häviötön"
|
||||
|
||||
NVENC.Use2Pass="Käytä kaksivaiheista enkoodausta"
|
||||
NVENC.Use2Pass="Käytä Two-Pass enkoodausta"
|
||||
NVENC.Preset.default="Oletusarvo"
|
||||
NVENC.Preset.hq="Korkea laatu"
|
||||
NVENC.Preset.hp="Korkea suorituskyky"
|
||||
|
|
@ -22,7 +22,7 @@ Looping="Toista jatkuvasti"
|
|||
Input="Sisääntulo"
|
||||
InputFormat="Sisääntulon muoto"
|
||||
ForceFormat="Pakota muodon muuntaminen"
|
||||
HardwareDecode="Käytä laitteistoa purkamiseen, kun mahdollista"
|
||||
HardwareDecode="Käytä laitteistotason purkua, kun mahdollista"
|
||||
ClearOnMediaEnd="Piilota lähde kun toisto päättyy"
|
||||
Advanced="Lisäasetukset"
|
||||
AudioBufferSize="Äänipuskurin koko (ruutua)"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
FFmpegOutput="פלט FFmpeg"
|
||||
FFmpegAAC="FFmpeg מקודד AAC ברירת מחדל"
|
||||
Bitrate="קצב ביטים"
|
||||
Preset="קבוע מראש"
|
||||
RateControl="בקרת קצב"
|
||||
KeyframeIntervalSec="מרווח ערך ה keyframe בשניות (0=אוטומטי)"
|
||||
Lossless="ללא אובדן נתונים"
|
||||
|
||||
NVENC.Use2Pass="השתמש בקידוד שני מעברים"
|
||||
NVENC.Preset.default="ברירת מחדל"
|
||||
NVENC.Preset.hq="איכות גבוהה"
|
||||
NVENC.Preset.hp="ביצועים גבוהים"
|
||||
NVENC.Preset.bd="בלוריי"
|
||||
NVENC.Preset.ll="השהיה נמוכה"
|
||||
NVENC.Preset.llhq="השהיה נמוכה איכות גבוהה"
|
||||
NVENC.Preset.llhp="השהיה נמוכה ביצועים גבוהים"
|
||||
NVENC.Level="רמה"
|
||||
|
||||
FFmpegSource="מקור מדיה"
|
||||
LocalFile="קובץ מקומי"
|
||||
|
|
@ -23,6 +36,10 @@ DiscardNonIntra="פריימים לא ביינים"
|
|||
DiscardNonKey="מסגרות שאינן מפתח"
|
||||
DiscardAll="כל הפריימים (זהירות!)"
|
||||
RestartWhenActivated="הפעל מחדש השמעה כאשר מקור הופך לפעיל"
|
||||
ColorRange="טווח צבעים YUV"
|
||||
ColorRange.Auto="אוטומטי"
|
||||
ColorRange.Partial="חלקי"
|
||||
ColorRange.Full="מלא"
|
||||
|
||||
|
||||
MediaFileFilter.AllMediaFiles="כל קבצי המדיה"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ FFmpegOutput="FFmpeg izlaz"
|
|||
FFmpegAAC="FFmpeg podrazumevani AAC enkoder"
|
||||
Bitrate="Protok"
|
||||
Preset="Šablon"
|
||||
RateControl="Kontrola protoka"
|
||||
KeyframeIntervalSec="Interval ključnih frejmova (sekunde, 0=automatski)"
|
||||
Lossless="Bez gubitka"
|
||||
|
||||
NVENC.Use2Pass="Koristi enkoding duplog prolaza"
|
||||
NVENC.Preset.default="Podrazumevani"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
FFmpegOutput="Uscita FFmpeg"
|
||||
FFmpegAAC="Codificatore FFmpeg predefinito AAC"
|
||||
Bitrate="Bitrate"
|
||||
Preset="Preset"
|
||||
RateControl="Controllo frequenza"
|
||||
KeyframeIntervalSec="Intervallo Keyframe (secondi, 0=automatico)"
|
||||
Lossless="Lossless"
|
||||
|
||||
NVENC.Use2Pass="Usa codifica in due passaggi"
|
||||
NVENC.Preset.default="Predefinito"
|
||||
NVENC.Preset.hq="Alta Qualità"
|
||||
NVENC.Preset.hp="Alte Prestazioni"
|
||||
NVENC.Preset.bd="Bluray"
|
||||
NVENC.Preset.ll="Bassa latenza"
|
||||
NVENC.Preset.llhq="Bassa latenza Alta Qualità"
|
||||
NVENC.Preset.llhp="Bassa latenza ad Alte Prestazioni"
|
||||
NVENC.Level="Livello"
|
||||
|
||||
FFmpegSource="Origine multimediale"
|
||||
LocalFile="File locale"
|
||||
|
|
@ -23,6 +36,14 @@ DiscardNonIntra="Frame non interposti"
|
|||
DiscardNonKey="Frame non di chiave"
|
||||
DiscardAll="Tutti i Frame (opzione per utenti più esperti)"
|
||||
RestartWhenActivated="Riattiva playback quando la fonte torna attiva"
|
||||
ColorRange="Gamma di colore YUV"
|
||||
ColorRange.Auto="Autom."
|
||||
ColorRange.Partial="Parziale"
|
||||
ColorRange.Full="Intero"
|
||||
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Tutti i file media"
|
||||
MediaFileFilter.VideoFiles="File video"
|
||||
MediaFileFilter.AudioFiles="File audio"
|
||||
MediaFileFilter.AllFiles="Tutti i file"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,26 @@
|
|||
FFmpegOutput="FFmpeg utdata"
|
||||
FFmpegAAC="Standard FFmpeg AAC-koder"
|
||||
Bitrate="Bitrate"
|
||||
Preset="Forhåndsinnstilling"
|
||||
RateControl="Hastighetskontroll"
|
||||
KeyframeIntervalSec="Nøkkelbildeintervall (sekunder, 0 = automatisk)"
|
||||
Lossless="Tapsfri"
|
||||
|
||||
NVENC.Use2Pass="Bruk tostegskoding"
|
||||
NVENC.Preset.default="Standard"
|
||||
NVENC.Preset.hq="Høy kvalitet"
|
||||
NVENC.Preset.hp="Høy ytelse"
|
||||
NVENC.Preset.bd="Bluray"
|
||||
NVENC.Preset.ll="Lav latens"
|
||||
NVENC.Preset.llhq="Lav latens, høy kvalitet"
|
||||
NVENC.Preset.llhp="Lav latens, høy ytelse"
|
||||
NVENC.Level="Nivå"
|
||||
|
||||
FFmpegSource="Mediekilde"
|
||||
LocalFile="Lokal fil"
|
||||
Looping="Repeter"
|
||||
Input="Inndata"
|
||||
InputFormat="Inndataformat"
|
||||
Input="Inngang"
|
||||
InputFormat="Inngangsformat"
|
||||
ForceFormat="Tving formatkonvertering"
|
||||
HardwareDecode="Bruk maskinvaredekoding når tilgjengelig"
|
||||
ClearOnMediaEnd="Skjul kilde når avspilling ender"
|
||||
|
|
@ -22,6 +35,15 @@ DiscardBiDir="Toveisbilder"
|
|||
DiscardNonIntra="Non-intra bilder"
|
||||
DiscardNonKey="Ikkenøkkelbilder"
|
||||
DiscardAll="Alle bilder (forsiktig!)"
|
||||
RestartWhenActivated="Start avspilling omigjen når kilde blir aktiv"
|
||||
ColorRange="YUV fargerom"
|
||||
ColorRange.Auto="Automatisk"
|
||||
ColorRange.Partial="Delvis"
|
||||
ColorRange.Full="Hel"
|
||||
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Alle mediefiler"
|
||||
MediaFileFilter.VideoFiles="Videofiler"
|
||||
MediaFileFilter.AudioFiles="Lydfiler"
|
||||
MediaFileFilter.AllFiles="Alle filer"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ FFmpegOutput="Wyjście FFmpeg"
|
|||
FFmpegAAC="Domyślny enkoder AAC w FFmpeg"
|
||||
Bitrate="Przepływność bitowa"
|
||||
Preset="Profil ustawień"
|
||||
RateControl="Typ przepływności"
|
||||
KeyframeIntervalSec="Odstęp między klatkami kluczowymi (sekundy, 0=automatyczny)"
|
||||
Lossless="Bezstratny"
|
||||
|
||||
NVENC.Use2Pass="Użyj enkodowania dwuprzebiegowego"
|
||||
NVENC.Preset.default="Domyślny"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
FFmpegOutput="Saída do FFmpeg"
|
||||
FFmpegAAC="Codificador AAC Padrão do FFmpeg"
|
||||
Bitrate="Taxa de Bits"
|
||||
Preset="Predefinição"
|
||||
RateControl="Controle de Taxa"
|
||||
KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)"
|
||||
Lossless="Sem perdas"
|
||||
|
||||
NVENC.Preset.default="Predefinido"
|
||||
NVENC.Preset.hq="Alta Qualidade"
|
||||
NVENC.Preset.hp="Alto Desempenho"
|
||||
NVENC.Preset.bd="Bluray"
|
||||
NVENC.Preset.ll="Baixa latência"
|
||||
NVENC.Preset.llhq="Baixa latência Alta Qualidade"
|
||||
NVENC.Preset.llhp="Baixa latência Alto Desempenho"
|
||||
NVENC.Level="Nível"
|
||||
|
||||
FFmpegSource="Fonte de mídia"
|
||||
LocalFile="Arquivo Local"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
FFmpegOutput="Saída de FFmpeg"
|
||||
FFmpegAAC="Codificador AAC padrão do FFmpeg"
|
||||
Bitrate="Bitrate"
|
||||
Preset="Predefinição"
|
||||
RateControl="Controle de Taxa"
|
||||
KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)"
|
||||
Lossless="Sem perdas"
|
||||
|
||||
NVENC.Preset.default="Predefinido"
|
||||
NVENC.Preset.hq="Alta Qualidade"
|
||||
NVENC.Preset.hp="Alto Desempenho"
|
||||
NVENC.Preset.bd="Bluray"
|
||||
NVENC.Preset.ll="Baixa latência"
|
||||
NVENC.Preset.llhq="Baixa latência Alta Qualidade"
|
||||
NVENC.Preset.llhp="Baixa latência Alto Desempenho"
|
||||
NVENC.Level="Nível"
|
||||
|
||||
FFmpegSource="Fonte de multimédia"
|
||||
LocalFile="Ficheiro local"
|
||||
|
|
@ -22,6 +34,15 @@ DiscardBiDir="Fotogramas bidirecionais"
|
|||
DiscardNonIntra="Fotogramas não internos"
|
||||
DiscardNonKey="Fotogramas não registados"
|
||||
DiscardAll="Todos os fotogramas (cuidado!)"
|
||||
RestartWhenActivated="Reiniciar reprodução quando a fonte se torna ativo"
|
||||
ColorRange="Gama de cor YUV"
|
||||
ColorRange.Auto="Auto"
|
||||
ColorRange.Partial="Parcial"
|
||||
ColorRange.Full="Completo"
|
||||
|
||||
|
||||
MediaFileFilter.AllMediaFiles="Todos os Arquivos de Media"
|
||||
MediaFileFilter.VideoFiles="Arquivos de Vídeo"
|
||||
MediaFileFilter.AudioFiles="Arquivos de Áudio"
|
||||
MediaFileFilter.AllFiles="Todos os ficheiros"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ FFmpegOutput="Вывод FFmpeg"
|
|||
FFmpegAAC="Стандартный AAC-кодер FFmpeg"
|
||||
Bitrate="Битрейт"
|
||||
Preset="Пресет"
|
||||
RateControl="Управление битрейтом"
|
||||
KeyframeIntervalSec="Интервал ключевых кадров (сек, 0=авто)"
|
||||
Lossless="Без потерь"
|
||||
|
||||
NVENC.Use2Pass="Использовать двухпроходное кодирование"
|
||||
NVENC.Preset.default="По умолчанию"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ FFmpegOutput="FFmpeg izlaz"
|
|||
FFmpegAAC="FFmpeg podrazumevani AAC enkoder"
|
||||
Bitrate="Protok"
|
||||
Preset="Šablon"
|
||||
RateControl="Kontrola protoka"
|
||||
KeyframeIntervalSec="Interval ključnih frejmova (sekunde, 0=automatski)"
|
||||
Lossless="Bez gubitka"
|
||||
|
||||
NVENC.Use2Pass="Koristi enkoding duplog prolaza"
|
||||
NVENC.Preset.default="Podrazumevani"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ FFmpegOutput="FFmpeg излаз"
|
|||
FFmpegAAC="FFmpeg подразумевани AAC енкодер"
|
||||
Bitrate="Проток"
|
||||
Preset="Шаблон"
|
||||
RateControl="Контрола протока"
|
||||
KeyframeIntervalSec="Интервал кључних фрејмова (секунде, 0=аутоматски)"
|
||||
Lossless="Без губитка"
|
||||
|
||||
NVENC.Use2Pass="Користи енкодинг дуплог пролаза"
|
||||
NVENC.Preset.default="Подразумевани"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ FFmpegOutput="FFmpeg-utmatning"
|
|||
FFmpegAAC="AAC-kodare (FFmpeg standard)"
|
||||
Bitrate="Bithastighet"
|
||||
Preset="Förinställning"
|
||||
RateControl="Hastighetskontroll"
|
||||
Lossless="Förlustfri"
|
||||
|
||||
NVENC.Use2Pass="Använd tvåpassavkodning"
|
||||
NVENC.Preset.default="Standard"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
FFmpegOutput="FFmpeg 輸出"
|
||||
FFmpegAAC="FFmpeg 預設 AAC 編碼器"
|
||||
Bitrate="流量"
|
||||
Bitrate="位元率"
|
||||
Preset="預置"
|
||||
RateControl="位元率控制"
|
||||
KeyframeIntervalSec="關鍵訊框間隔 (秒,0 = 自動)"
|
||||
Lossless="無損"
|
||||
|
||||
NVENC.Use2Pass="使用 Two-Pass 編碼"
|
||||
NVENC.Preset.default="預設"
|
||||
NVENC.Preset.hq="高品質"
|
||||
NVENC.Preset.hp="高性能"
|
||||
NVENC.Preset.bd="藍光"
|
||||
NVENC.Preset.ll="低延遲"
|
||||
NVENC.Preset.llhq="低延遲高品質"
|
||||
NVENC.Preset.llhp="低延遲高性能"
|
||||
NVENC.Level="级别"
|
||||
|
||||
FFmpegSource="媒體來源"
|
||||
LocalFile="本機檔案"
|
||||
|
|
@ -12,15 +25,21 @@ ForceFormat="強制格式轉換"
|
|||
HardwareDecode="盡可能使用硬體解碼"
|
||||
ClearOnMediaEnd="當播放結束時隱藏來源"
|
||||
Advanced="進階"
|
||||
AudioBufferSize="音訊緩衝區大小 (幀)"
|
||||
VideoBufferSize="影像緩衝區大小 (幀)"
|
||||
FrameDropping="掉幀程度"
|
||||
AudioBufferSize="音訊緩衝區大小 (訊框)"
|
||||
VideoBufferSize="影像緩衝區大小 (訊框)"
|
||||
FrameDropping="丟棄訊框级别"
|
||||
DiscardNone="無"
|
||||
DiscardDefault="預設 (無效封包)"
|
||||
DiscardNonRef="非參考幀"
|
||||
DiscardNonIntra="非內部框架"
|
||||
DiscardNonKey="非關鍵幀"
|
||||
DiscardAll="所有幀(小心!)"
|
||||
DiscardNonRef="非參考訊框"
|
||||
DiscardBiDir="雙向訊框"
|
||||
DiscardNonIntra="非內部訊框"
|
||||
DiscardNonKey="非關鍵訊框"
|
||||
DiscardAll="所有訊框(小心!)"
|
||||
RestartWhenActivated="當來源可使用時重新播放"
|
||||
ColorRange="YUV 色彩空間"
|
||||
ColorRange.Auto="自動"
|
||||
ColorRange.Partial="部分"
|
||||
ColorRange.Full="全部"
|
||||
|
||||
|
||||
MediaFileFilter.AllMediaFiles="所有媒體檔案"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <obs-avc.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/pipe.h>
|
||||
#include <util/threading.h>
|
||||
#include "ffmpeg-mux/ffmpeg-mux.h"
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
|
|
@ -33,10 +34,12 @@
|
|||
struct ffmpeg_muxer {
|
||||
obs_output_t *output;
|
||||
os_process_pipe_t *pipe;
|
||||
int64_t stop_ts;
|
||||
struct dstr path;
|
||||
bool sent_headers;
|
||||
bool active;
|
||||
bool capturing;
|
||||
volatile bool active;
|
||||
volatile bool stopping;
|
||||
volatile bool capturing;
|
||||
};
|
||||
|
||||
static const char *ffmpeg_mux_getname(void *unused)
|
||||
|
|
@ -72,6 +75,21 @@ static void *ffmpeg_mux_create(obs_data_t *settings, obs_output_t *output)
|
|||
#define FFMPEG_MUX "ffmpeg-mux"
|
||||
#endif
|
||||
|
||||
static inline bool capturing(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->capturing);
|
||||
}
|
||||
|
||||
static inline bool stopping(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->stopping);
|
||||
}
|
||||
|
||||
static inline bool active(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->active);
|
||||
}
|
||||
|
||||
/* TODO: allow codecs other than h264 whenever we start using them */
|
||||
|
||||
static void add_video_encoder_params(struct ffmpeg_muxer *stream,
|
||||
|
|
@ -223,8 +241,8 @@ static bool ffmpeg_mux_start(void *data)
|
|||
}
|
||||
|
||||
/* write headers and start capture */
|
||||
stream->active = true;
|
||||
stream->capturing = true;
|
||||
os_atomic_set_bool(&stream->active, true);
|
||||
os_atomic_set_bool(&stream->capturing, true);
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
|
||||
info("Writing file '%s'...", stream->path.array);
|
||||
|
|
@ -235,29 +253,32 @@ static int deactivate(struct ffmpeg_muxer *stream)
|
|||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stream->active) {
|
||||
if (active(stream)) {
|
||||
ret = os_process_pipe_destroy(stream->pipe);
|
||||
stream->pipe = NULL;
|
||||
|
||||
stream->active = false;
|
||||
stream->sent_headers = false;
|
||||
os_atomic_set_bool(&stream->active, false);
|
||||
os_atomic_set_bool(&stream->sent_headers, false);
|
||||
|
||||
info("Output of file '%s' stopped", stream->path.array);
|
||||
}
|
||||
|
||||
if (stopping(stream))
|
||||
obs_output_end_data_capture(stream->output);
|
||||
|
||||
os_atomic_set_bool(&stream->stopping, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ffmpeg_mux_stop(void *data)
|
||||
static void ffmpeg_mux_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
if (stream->capturing) {
|
||||
obs_output_end_data_capture(stream->output);
|
||||
stream->capturing = false;
|
||||
if (capturing(stream)) {
|
||||
stream->stop_ts = (int64_t)ts / 1000LL;
|
||||
os_atomic_set_bool(&stream->stopping, true);
|
||||
os_atomic_set_bool(&stream->capturing, false);
|
||||
}
|
||||
|
||||
deactivate(stream);
|
||||
}
|
||||
|
||||
static void signal_failure(struct ffmpeg_muxer *stream)
|
||||
|
|
@ -271,7 +292,7 @@ static void signal_failure(struct ffmpeg_muxer *stream)
|
|||
}
|
||||
|
||||
obs_output_signal_stop(stream->output, code);
|
||||
stream->capturing = false;
|
||||
os_atomic_set_bool(&stream->capturing, false);
|
||||
}
|
||||
|
||||
static bool write_packet(struct ffmpeg_muxer *stream,
|
||||
|
|
@ -358,7 +379,7 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
|
|||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
if (!stream->active)
|
||||
if (!active(stream))
|
||||
return;
|
||||
|
||||
if (!stream->sent_headers) {
|
||||
|
|
@ -368,6 +389,13 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
|
|||
stream->sent_headers = true;
|
||||
}
|
||||
|
||||
if (stopping(stream)) {
|
||||
if (packet->sys_dts_usec >= stream->stop_ts) {
|
||||
deactivate(stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
write_packet(stream, packet);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@ static bool nvenc_update(void *data, obs_data_t *settings)
|
|||
nvenc_video_info(enc, &info);
|
||||
av_opt_set_int(enc->context->priv_data, "cbr", false, 0);
|
||||
|
||||
av_opt_set(enc->context->priv_data, "preset", preset, 0);
|
||||
|
||||
if (astrcmpi(rc, "cqp") == 0) {
|
||||
bitrate = 0;
|
||||
enc->context->global_quality = cqp;
|
||||
|
|
@ -171,7 +173,7 @@ static bool nvenc_update(void *data, obs_data_t *settings)
|
|||
bool hp = (astrcmpi(preset, "hp") == 0 ||
|
||||
astrcmpi(preset, "llhp") == 0);
|
||||
|
||||
av_opt_set(enc->context->priv_data, "profile",
|
||||
av_opt_set(enc->context->priv_data, "preset",
|
||||
hp ? "losslesshp" : "lossless", 0);
|
||||
|
||||
} else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
|
||||
|
|
@ -182,7 +184,6 @@ static bool nvenc_update(void *data, obs_data_t *settings)
|
|||
}
|
||||
|
||||
|
||||
av_opt_set(enc->context->priv_data, "preset", preset, 0);
|
||||
av_opt_set(enc->context->priv_data, "level", level, 0);
|
||||
av_opt_set_int(enc->context->priv_data, "2pass", twopass, 0);
|
||||
av_opt_set_int(enc->context->priv_data, "gpu", gpu, 0);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,11 @@ struct ffmpeg_output {
|
|||
bool connecting;
|
||||
pthread_t start_thread;
|
||||
|
||||
uint64_t audio_start_ts;
|
||||
uint64_t video_start_ts;
|
||||
uint64_t stop_ts;
|
||||
volatile bool stopping;
|
||||
|
||||
bool write_thread_active;
|
||||
pthread_mutex_t write_mutex;
|
||||
pthread_t write_thread;
|
||||
|
|
@ -237,6 +242,7 @@ static bool create_video_stream(struct ffmpeg_data *data)
|
|||
context->pix_fmt = closest_format;
|
||||
context->colorspace = data->config.color_space;
|
||||
context->color_range = data->config.color_range;
|
||||
context->thread_count = 0;
|
||||
|
||||
data->video->time_base = context->time_base;
|
||||
|
||||
|
|
@ -548,6 +554,11 @@ fail:
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline bool stopping(struct ffmpeg_output *output)
|
||||
{
|
||||
return os_atomic_load_bool(&output->stopping);
|
||||
}
|
||||
|
||||
static const char *ffmpeg_output_getname(void *unused)
|
||||
{
|
||||
UNUSED_PARAMETER(unused);
|
||||
|
|
@ -588,7 +599,7 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void ffmpeg_output_stop(void *data);
|
||||
static void ffmpeg_output_full_stop(void *data);
|
||||
static void ffmpeg_deactivate(struct ffmpeg_output *output);
|
||||
|
||||
static void ffmpeg_output_destroy(void *data)
|
||||
|
|
@ -599,7 +610,7 @@ static void ffmpeg_output_destroy(void *data)
|
|||
if (output->connecting)
|
||||
pthread_join(output->start_thread, NULL);
|
||||
|
||||
ffmpeg_output_stop(output);
|
||||
ffmpeg_output_full_stop(output);
|
||||
|
||||
pthread_mutex_destroy(&output->write_mutex);
|
||||
os_sem_destroy(output->write_sem);
|
||||
|
|
@ -647,6 +658,8 @@ static void receive_video(void *param, struct video_data *frame)
|
|||
|
||||
av_init_packet(&packet);
|
||||
|
||||
if (!output->video_start_ts)
|
||||
output->video_start_ts = frame->timestamp;
|
||||
if (!data->start_timestamp)
|
||||
data->start_timestamp = frame->timestamp;
|
||||
|
||||
|
|
@ -768,6 +781,8 @@ static bool prepare_audio(struct ffmpeg_data *data,
|
|||
return false;
|
||||
|
||||
cutoff = data->start_timestamp - frame->timestamp;
|
||||
output->timestamp += cutoff;
|
||||
|
||||
cutoff = cutoff * (uint64_t)data->audio_samplerate /
|
||||
1000000000;
|
||||
|
||||
|
|
@ -797,6 +812,9 @@ static void receive_audio(void *param, struct audio_data *frame)
|
|||
if (!prepare_audio(data, frame, &in))
|
||||
return;
|
||||
|
||||
if (!output->audio_start_ts)
|
||||
output->audio_start_ts = in.timestamp;
|
||||
|
||||
frame_size_bytes = (size_t)data->frame_size * data->audio_size;
|
||||
|
||||
for (size_t i = 0; i < data->audio_planes; i++)
|
||||
|
|
@ -812,6 +830,26 @@ static void receive_audio(void *param, struct audio_data *frame)
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t get_packet_sys_dts(struct ffmpeg_output *output,
|
||||
AVPacket *packet)
|
||||
{
|
||||
struct ffmpeg_data *data = &output->ff_data;
|
||||
uint64_t start_ts;
|
||||
|
||||
AVRational time_base;
|
||||
|
||||
if (data->video && data->video->index == packet->stream_index) {
|
||||
time_base = data->video->time_base;
|
||||
start_ts = output->video_start_ts;
|
||||
} else {
|
||||
time_base = data->audio->time_base;
|
||||
start_ts = output->audio_start_ts;
|
||||
}
|
||||
|
||||
return start_ts + (uint64_t)av_rescale_q(packet->dts,
|
||||
time_base, (AVRational){1, 1000000000});
|
||||
}
|
||||
|
||||
static int process_packet(struct ffmpeg_output *output)
|
||||
{
|
||||
AVPacket packet;
|
||||
|
|
@ -834,6 +872,14 @@ static int process_packet(struct ffmpeg_output *output)
|
|||
packet.size, packet.flags,
|
||||
packet.stream_index, output->packets.num);*/
|
||||
|
||||
if (stopping(output)) {
|
||||
uint64_t sys_ts = get_packet_sys_dts(output, &packet);
|
||||
if (sys_ts >= output->stop_ts) {
|
||||
ffmpeg_output_full_stop(output);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = av_interleaved_write_frame(output->ff_data.output, &packet);
|
||||
if (ret < 0) {
|
||||
av_free_packet(&packet);
|
||||
|
|
@ -954,7 +1000,7 @@ static bool try_connect(struct ffmpeg_output *output)
|
|||
if (ret != 0) {
|
||||
blog(LOG_WARNING, "ffmpeg_output_start: failed to create write "
|
||||
"thread.");
|
||||
ffmpeg_output_stop(output);
|
||||
ffmpeg_output_full_stop(output);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -985,11 +1031,15 @@ static bool ffmpeg_output_start(void *data)
|
|||
if (output->connecting)
|
||||
return false;
|
||||
|
||||
os_atomic_set_bool(&output->stopping, false);
|
||||
output->audio_start_ts = 0;
|
||||
output->video_start_ts = 0;
|
||||
|
||||
ret = pthread_create(&output->start_thread, NULL, start_thread, output);
|
||||
return (output->connecting = (ret == 0));
|
||||
}
|
||||
|
||||
static void ffmpeg_output_stop(void *data)
|
||||
static void ffmpeg_output_full_stop(void *data)
|
||||
{
|
||||
struct ffmpeg_output *output = data;
|
||||
|
||||
|
|
@ -999,6 +1049,20 @@ static void ffmpeg_output_stop(void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void ffmpeg_output_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct ffmpeg_output *output = data;
|
||||
|
||||
if (output->active) {
|
||||
if (ts == 0) {
|
||||
ffmpeg_output_full_stop(output);
|
||||
} else {
|
||||
os_atomic_set_bool(&output->stopping, true);
|
||||
output->stop_ts = ts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ffmpeg_deactivate(struct ffmpeg_output *output)
|
||||
{
|
||||
if (output->write_thread_active) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue