New upstream version 24.0.1+dfsg1

This commit is contained in:
Sebastian Ramacher 2019-09-22 23:19:10 +02:00
parent b14f9eae6d
commit 5a730d6ec3
842 changed files with 42245 additions and 33385 deletions

View file

@ -32,38 +32,38 @@
#include <libavformat/avformat.h>
#define do_log(level, format, ...) \
#define do_log(level, format, ...) \
blog(level, "[ffmpeg muxer: '%s'] " format, \
obs_output_get_name(stream->output), ##__VA_ARGS__)
obs_output_get_name(stream->output), ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
struct ffmpeg_muxer {
obs_output_t *output;
obs_output_t *output;
os_process_pipe_t *pipe;
int64_t stop_ts;
uint64_t total_bytes;
struct dstr path;
bool sent_headers;
volatile bool active;
volatile bool stopping;
volatile bool capturing;
int64_t stop_ts;
uint64_t total_bytes;
struct dstr path;
bool sent_headers;
volatile bool active;
volatile bool stopping;
volatile bool capturing;
/* replay buffer */
struct circlebuf packets;
int64_t cur_size;
int64_t cur_time;
int64_t max_size;
int64_t max_time;
int64_t save_ts;
int keyframes;
obs_hotkey_id hotkey;
struct circlebuf packets;
int64_t cur_size;
int64_t cur_time;
int64_t max_size;
int64_t max_time;
int64_t save_ts;
int keyframes;
obs_hotkey_id hotkey;
DARRAY(struct encoder_packet) mux_packets;
pthread_t mux_thread;
bool mux_thread_joinable;
volatile bool muxing;
pthread_t mux_thread;
bool mux_thread_joinable;
volatile bool muxing;
};
static const char *ffmpeg_mux_getname(void *type)
@ -136,7 +136,7 @@ static inline bool active(struct ffmpeg_muxer *stream)
/* TODO: allow codecs other than h264 whenever we start using them */
static void add_video_encoder_params(struct ffmpeg_muxer *stream,
struct dstr *cmd, obs_encoder_t *vencoder)
struct dstr *cmd, obs_encoder_t *vencoder)
{
obs_data_t *settings = obs_encoder_get_settings(vencoder);
int bitrate = (int)obs_data_get_int(settings, "bitrate");
@ -145,13 +145,10 @@ static void add_video_encoder_params(struct ffmpeg_muxer *stream,
obs_data_release(settings);
dstr_catf(cmd, "%s %d %d %d %d %d ",
obs_encoder_get_codec(vencoder),
bitrate,
obs_output_get_width(stream->output),
obs_output_get_height(stream->output),
(int)info->fps_num,
(int)info->fps_den);
dstr_catf(cmd, "%s %d %d %d %d %d ", obs_encoder_get_codec(vencoder),
bitrate, obs_output_get_width(stream->output),
obs_output_get_height(stream->output), (int)info->fps_num,
(int)info->fps_den);
}
static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)
@ -166,11 +163,9 @@ static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)
dstr_copy(&name, obs_encoder_get_name(aencoder));
dstr_replace(&name, "\"", "\"\"");
dstr_catf(cmd, "\"%s\" %d %d %d ",
name.array,
bitrate,
(int)obs_encoder_get_sample_rate(aencoder),
(int)audio_output_get_channels(audio));
dstr_catf(cmd, "\"%s\" %d %d %d ", name.array, bitrate,
(int)obs_encoder_get_sample_rate(aencoder),
(int)audio_output_get_channels(audio));
dstr_free(&name);
}
@ -181,8 +176,8 @@ static void log_muxer_params(struct ffmpeg_muxer *stream, const char *settings)
AVDictionary *dict = NULL;
if ((ret = av_dict_parse_string(&dict, settings, "=", " ", 0))) {
warn("Failed to parse muxer settings: %s\n%s",
av_err2str(ret), settings);
warn("Failed to parse muxer settings: %s\n%s", av_err2str(ret),
settings);
av_dict_free(&dict);
return;
@ -193,7 +188,7 @@ static void log_muxer_params(struct ffmpeg_muxer *stream, const char *settings)
AVDictionaryEntry *entry = NULL;
while ((entry = av_dict_get(dict, "", entry,
AV_DICT_IGNORE_SUFFIX)))
AV_DICT_IGNORE_SUFFIX)))
dstr_catf(&str, "\n\t%s=%s", entry->key, entry->value);
info("Using muxer settings:%s", str.array);
@ -221,7 +216,7 @@ static void add_muxer_params(struct dstr *cmd, struct ffmpeg_muxer *stream)
}
static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd,
const char *path)
const char *path)
{
obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output);
obs_encoder_t *aencoders[MAX_AUDIO_MIXES];
@ -229,7 +224,7 @@ static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd,
for (;;) {
obs_encoder_t *aencoder = obs_output_get_audio_encoder(
stream->output, num_tracks);
stream->output, num_tracks);
if (!aencoder)
break;
@ -289,7 +284,7 @@ static bool ffmpeg_mux_start(void *data)
if (!test_file) {
struct dstr error_message;
dstr_init_copy(&error_message,
obs_module_text("UnableToWritePath"));
obs_module_text("UnableToWritePath"));
#ifdef _WIN32
// special warning for Windows 10 users about Defender
struct win_version_info ver;
@ -297,12 +292,11 @@ static bool ffmpeg_mux_start(void *data)
if (ver.major >= 10) {
dstr_cat(&error_message, "\n\n");
dstr_cat(&error_message,
obs_module_text("WarnWindowsDefender"));
obs_module_text("WarnWindowsDefender"));
}
#endif
dstr_replace(&error_message, "%1", path);
obs_output_set_last_error(stream->output,
error_message.array);
obs_output_set_last_error(stream->output, error_message.array);
dstr_free(&error_message);
obs_data_release(settings);
return false;
@ -315,8 +309,8 @@ static bool ffmpeg_mux_start(void *data)
obs_data_release(settings);
if (!stream->pipe) {
obs_output_set_last_error(stream->output,
obs_module_text("HelperProcessFailed"));
obs_output_set_last_error(
stream->output, obs_module_text("HelperProcessFailed"));
warn("Failed to create process pipe");
return false;
}
@ -375,19 +369,22 @@ static void signal_failure(struct ffmpeg_muxer *stream)
size_t len;
len = os_process_pipe_read_err(stream->pipe, (uint8_t *)error,
sizeof(error) - 1);
sizeof(error) - 1);
if (len > 0) {
error[len] = 0;
warn ("ffmpeg-mux: %s", error);
obs_output_set_last_error (stream->output, error);
warn("ffmpeg-mux: %s", error);
obs_output_set_last_error(stream->output, error);
}
ret = deactivate(stream, 0);
switch (ret) {
case FFM_UNSUPPORTED: code = OBS_OUTPUT_UNSUPPORTED; break;
default: code = OBS_OUTPUT_ERROR;
case FFM_UNSUPPORTED:
code = OBS_OUTPUT_UNSUPPORTED;
break;
default:
code = OBS_OUTPUT_ERROR;
}
obs_output_signal_stop(stream->output, code);
@ -395,22 +392,21 @@ static void signal_failure(struct ffmpeg_muxer *stream)
}
static bool write_packet(struct ffmpeg_muxer *stream,
struct encoder_packet *packet)
struct encoder_packet *packet)
{
bool is_video = packet->type == OBS_ENCODER_VIDEO;
size_t ret;
struct ffm_packet_info info = {
.pts = packet->pts,
.dts = packet->dts,
.size = (uint32_t)packet->size,
.index = (int)packet->track_idx,
.type = is_video ? FFM_PACKET_VIDEO : FFM_PACKET_AUDIO,
.keyframe = packet->keyframe
};
struct ffm_packet_info info = {.pts = packet->pts,
.dts = packet->dts,
.size = (uint32_t)packet->size,
.index = (int)packet->track_idx,
.type = is_video ? FFM_PACKET_VIDEO
: FFM_PACKET_AUDIO,
.keyframe = packet->keyframe};
ret = os_process_pipe_write(stream->pipe, (const uint8_t*)&info,
sizeof(info));
ret = os_process_pipe_write(stream->pipe, (const uint8_t *)&info,
sizeof(info));
if (ret != sizeof(info)) {
warn("os_process_pipe_write for info structure failed");
signal_failure(stream);
@ -429,13 +425,10 @@ static bool write_packet(struct ffmpeg_muxer *stream,
}
static bool send_audio_headers(struct ffmpeg_muxer *stream,
obs_encoder_t *aencoder, size_t idx)
obs_encoder_t *aencoder, size_t idx)
{
struct encoder_packet packet = {
.type = OBS_ENCODER_AUDIO,
.timebase_den = 1,
.track_idx = idx
};
.type = OBS_ENCODER_AUDIO, .timebase_den = 1, .track_idx = idx};
obs_encoder_get_extra_data(aencoder, &packet.data, &packet.size);
return write_packet(stream, &packet);
@ -445,10 +438,8 @@ static bool send_video_headers(struct ffmpeg_muxer *stream)
{
obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output);
struct encoder_packet packet = {
.type = OBS_ENCODER_VIDEO,
.timebase_den = 1
};
struct encoder_packet packet = {.type = OBS_ENCODER_VIDEO,
.timebase_den = 1};
obs_encoder_get_extra_data(vencoder, &packet.data, &packet.size);
return write_packet(stream, &packet);
@ -511,9 +502,8 @@ static obs_properties_t *ffmpeg_mux_properties(void *unused)
obs_properties_t *props = obs_properties_create();
obs_properties_add_text(props, "path",
obs_module_text("FilePath"),
OBS_TEXT_DEFAULT);
obs_properties_add_text(props, "path", obs_module_text("FilePath"),
OBS_TEXT_DEFAULT);
return props;
}
@ -524,18 +514,17 @@ static uint64_t ffmpeg_mux_total_bytes(void *data)
}
struct obs_output_info ffmpeg_muxer = {
.id = "ffmpeg_muxer",
.flags = OBS_OUTPUT_AV |
OBS_OUTPUT_ENCODED |
OBS_OUTPUT_MULTI_TRACK,
.get_name = ffmpeg_mux_getname,
.create = ffmpeg_mux_create,
.destroy = ffmpeg_mux_destroy,
.start = ffmpeg_mux_start,
.stop = ffmpeg_mux_stop,
.id = "ffmpeg_muxer",
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK |
OBS_OUTPUT_CAN_PAUSE,
.get_name = ffmpeg_mux_getname,
.create = ffmpeg_mux_create,
.destroy = ffmpeg_mux_destroy,
.start = ffmpeg_mux_start,
.stop = ffmpeg_mux_stop,
.encoded_packet = ffmpeg_mux_data,
.get_total_bytes= ffmpeg_mux_total_bytes,
.get_properties = ffmpeg_mux_properties
.get_total_bytes = ffmpeg_mux_total_bytes,
.get_properties = ffmpeg_mux_properties,
};
/* ------------------------------------------------------------------------ */
@ -547,15 +536,27 @@ static const char *replay_buffer_getname(void *type)
}
static void replay_buffer_hotkey(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed)
obs_hotkey_t *hotkey, bool pressed)
{
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(hotkey);
UNUSED_PARAMETER(pressed);
if (!pressed)
return;
struct ffmpeg_muxer *stream = data;
if (os_atomic_load_bool(&stream->active))
if (os_atomic_load_bool(&stream->active)) {
obs_encoder_t *vencoder =
obs_output_get_video_encoder(stream->output);
if (obs_encoder_paused(vencoder)) {
info("Could not save buffer because encoders paused");
return;
}
stream->save_ts = os_gettime_ns() / 1000LL;
}
}
static void save_replay_proc(void *data, calldata_t *cd)
@ -577,15 +578,15 @@ static void *replay_buffer_create(obs_data_t *settings, obs_output_t *output)
struct ffmpeg_muxer *stream = bzalloc(sizeof(*stream));
stream->output = output;
stream->hotkey = obs_hotkey_register_output(output,
"ReplayBuffer.Save",
obs_module_text("ReplayBuffer.Save"),
replay_buffer_hotkey, stream);
stream->hotkey =
obs_hotkey_register_output(output, "ReplayBuffer.Save",
obs_module_text("ReplayBuffer.Save"),
replay_buffer_hotkey, stream);
proc_handler_t *ph = obs_output_get_proc_handler(output);
proc_handler_add(ph, "void save()", save_replay_proc, stream);
proc_handler_add(ph, "void get_last_replay(out string path)",
get_last_replay, stream);
get_last_replay, stream);
return stream;
}
@ -653,7 +654,7 @@ static inline void purge(struct ffmpeg_muxer *stream)
for (;;) {
circlebuf_peek_front(&stream->packets, &pkt,
sizeof(pkt));
sizeof(pkt));
if (pkt.type == OBS_ENCODER_VIDEO && pkt.keyframe)
return;
@ -663,14 +664,14 @@ static inline void purge(struct ffmpeg_muxer *stream)
}
static inline void replay_buffer_purge(struct ffmpeg_muxer *stream,
struct encoder_packet *pkt)
struct encoder_packet *pkt)
{
if (stream->max_size) {
if (!stream->packets.size || stream->keyframes <= 2)
return;
while ((stream->cur_size + (int64_t)pkt->size) >
stream->max_size)
stream->max_size)
purge(stream);
}
@ -682,8 +683,8 @@ static inline void replay_buffer_purge(struct ffmpeg_muxer *stream,
}
static void insert_packet(struct darray *array, struct encoder_packet *packet,
int64_t video_offset, int64_t *audio_offsets,
int64_t video_dts_offset, int64_t *audio_dts_offsets)
int64_t video_offset, int64_t *audio_offsets,
int64_t video_dts_offset, int64_t *audio_dts_offsets)
{
struct encoder_packet pkt;
DARRAY(struct encoder_packet) packets;
@ -725,7 +726,7 @@ static void *replay_buffer_mux_thread(void *data)
if (!send_headers(stream)) {
warn("Could not write headers for file '%s'",
stream->path.array);
stream->path.array);
goto error;
}
@ -780,9 +781,9 @@ static void replay_buffer_save(struct ffmpeg_muxer *stream)
}
}
insert_packet(&stream->mux_packets.da, pkt,
video_offset, audio_offsets,
video_dts_offset, audio_dts_offsets);
insert_packet(&stream->mux_packets.da, pkt, video_offset,
audio_offsets, video_dts_offset,
audio_dts_offsets);
}
/* ---------------------------- */
@ -809,7 +810,8 @@ static void replay_buffer_save(struct ffmpeg_muxer *stream)
os_atomic_set_bool(&stream->muxing, true);
stream->mux_thread_joinable = pthread_create(&stream->mux_thread, NULL,
replay_buffer_mux_thread, stream) == 0;
replay_buffer_mux_thread,
stream) == 0;
}
static void deactivate_replay_buffer(struct ffmpeg_muxer *stream, int code)
@ -883,16 +885,15 @@ static void replay_buffer_defaults(obs_data_t *s)
}
struct obs_output_info replay_buffer = {
.id = "replay_buffer",
.flags = OBS_OUTPUT_AV |
OBS_OUTPUT_ENCODED |
OBS_OUTPUT_MULTI_TRACK,
.get_name = replay_buffer_getname,
.create = replay_buffer_create,
.destroy = replay_buffer_destroy,
.start = replay_buffer_start,
.stop = ffmpeg_mux_stop,
.id = "replay_buffer",
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK |
OBS_OUTPUT_CAN_PAUSE,
.get_name = replay_buffer_getname,
.create = replay_buffer_create,
.destroy = replay_buffer_destroy,
.start = replay_buffer_start,
.stop = ffmpeg_mux_stop,
.encoded_packet = replay_buffer_data,
.get_total_bytes= ffmpeg_mux_total_bytes,
.get_defaults = replay_buffer_defaults
.get_total_bytes = ffmpeg_mux_total_bytes,
.get_defaults = replay_buffer_defaults,
};