obs-ffmpeg, UI: Reset timestamps at splitting file
This commit adds a setting to reset timestamps when splitting files. Some NLEs cannot handle video files whose starting timestamp is not zero. Default is enabed.
This commit is contained in:
parent
0e81c66f6e
commit
550b1331ac
@ -946,6 +946,7 @@ Basic.Settings.Output.SplitFile.TypeTime="Split by Time"
|
||||
Basic.Settings.Output.SplitFile.TypeSize="Split by Size"
|
||||
Basic.Settings.Output.SplitFile.Time="Split Time"
|
||||
Basic.Settings.Output.SplitFile.Size="Split Size"
|
||||
Basic.Settings.Output.SplitFile.ResetTimestamps="Reset timestamps at the beginning of each split file"
|
||||
|
||||
# Screenshot
|
||||
Screenshot="Screenshot Output"
|
||||
|
@ -2487,6 +2487,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="advOutSplitFileRstTS">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Output.SplitFile.ResetTimestamps</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QStackedWidget" name="advRecTrackWidget">
|
||||
<property name="sizePolicy">
|
||||
@ -5758,6 +5768,7 @@
|
||||
<tabstop>advOutSplitFileType</tabstop>
|
||||
<tabstop>advOutSplitFileTime</tabstop>
|
||||
<tabstop>advOutSplitFileSize</tabstop>
|
||||
<tabstop>advOutSplitFileRstTS</tabstop>
|
||||
<tabstop>advOutFFType</tabstop>
|
||||
<tabstop>advOutFFRecPath</tabstop>
|
||||
<tabstop>advOutFFPathBrowse</tabstop>
|
||||
|
@ -1854,6 +1854,7 @@ bool AdvancedOutput::StartRecording()
|
||||
const char *splitFileType;
|
||||
int splitFileTime;
|
||||
int splitFileSize;
|
||||
bool splitFileResetTimestamps;
|
||||
|
||||
if (!useStreamEncoder) {
|
||||
if (!ffmpegOutput) {
|
||||
@ -1910,6 +1911,9 @@ bool AdvancedOutput::StartRecording()
|
||||
"AdvOut",
|
||||
"RecSplitFileSize")
|
||||
: 0;
|
||||
splitFileResetTimestamps =
|
||||
config_get_bool(main->Config(), "AdvOut",
|
||||
"RecSplitFileResetTimestamps");
|
||||
obs_data_set_string(settings, "directory", path);
|
||||
obs_data_set_string(settings, "format", filenameFormat);
|
||||
obs_data_set_string(settings, "extension", recFormat);
|
||||
@ -1920,6 +1924,8 @@ bool AdvancedOutput::StartRecording()
|
||||
splitFileTime);
|
||||
obs_data_set_int(settings, "max_size_mb",
|
||||
splitFileSize);
|
||||
obs_data_set_bool(settings, "reset_timestamps",
|
||||
splitFileResetTimestamps);
|
||||
}
|
||||
|
||||
obs_output_update(fileOutput, settings);
|
||||
|
@ -1417,6 +1417,8 @@ bool OBSBasic::InitBasicConfigDefaults()
|
||||
config_set_default_uint(basicConfig, "AdvOut", "RecSplitFileTime", 900);
|
||||
config_set_default_uint(basicConfig, "AdvOut", "RecSplitFileSize",
|
||||
2048);
|
||||
config_set_default_bool(basicConfig, "AdvOut",
|
||||
"RecSplitFileResetTimestamps", true);
|
||||
|
||||
config_set_default_bool(basicConfig, "AdvOut", "RecRB", false);
|
||||
config_set_default_uint(basicConfig, "AdvOut", "RecRBTime", 20);
|
||||
|
@ -461,6 +461,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
||||
HookWidget(ui->advOutSplitFileType, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutSplitFileTime, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutSplitFileSize, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutSplitFileRstTS, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutRecTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutRecTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutRecTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
@ -1918,6 +1919,8 @@ void OBSBasicSettings::LoadAdvOutputRecordingSettings()
|
||||
config_get_int(main->Config(), "AdvOut", "RecSplitFileTime");
|
||||
int splitFileSize =
|
||||
config_get_int(main->Config(), "AdvOut", "RecSplitFileSize");
|
||||
bool splitFileResetTimestamps = config_get_bool(
|
||||
main->Config(), "AdvOut", "RecSplitFileResetTimestamps");
|
||||
|
||||
int typeIndex = (astrcmpi(type, "FFmpeg") == 0) ? 1 : 0;
|
||||
ui->advOutRecType->setCurrentIndex(typeIndex);
|
||||
@ -1942,6 +1945,7 @@ void OBSBasicSettings::LoadAdvOutputRecordingSettings()
|
||||
ui->advOutSplitFileType->setCurrentIndex(idx);
|
||||
ui->advOutSplitFileTime->setValue(splitFileTime);
|
||||
ui->advOutSplitFileSize->setValue(splitFileSize);
|
||||
ui->advOutSplitFileRstTS->setChecked(splitFileResetTimestamps);
|
||||
|
||||
switch (flvTrack) {
|
||||
case 1:
|
||||
@ -3550,6 +3554,8 @@ void OBSBasicSettings::SaveOutputSettings()
|
||||
SplitFileTypeFromIdx(ui->advOutSplitFileType->currentIndex()));
|
||||
SaveSpinBox(ui->advOutSplitFileTime, "AdvOut", "RecSplitFileTime");
|
||||
SaveSpinBox(ui->advOutSplitFileSize, "AdvOut", "RecSplitFileSize");
|
||||
SaveCheckBox(ui->advOutSplitFileRstTS, "AdvOut",
|
||||
"RecSplitFileResetTimestamps");
|
||||
|
||||
config_set_int(
|
||||
main->Config(), "AdvOut", "RecTracks",
|
||||
@ -4462,6 +4468,7 @@ void OBSBasicSettings::AdvOutSplitFileChanged()
|
||||
ui->advOutSplitFileTime->setVisible(splitFileType == 0);
|
||||
ui->advOutSplitFileSizeLabel->setVisible(splitFileType == 1);
|
||||
ui->advOutSplitFileSize->setVisible(splitFileType == 1);
|
||||
ui->advOutSplitFileRstTS->setVisible(splitFile);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::AdvOutRecCheckWarnings()
|
||||
|
@ -309,6 +309,35 @@ static void set_file_not_readable_error(struct ffmpeg_muxer *stream,
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
inline static void ts_offset_clear(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
stream->found_video = false;
|
||||
stream->video_pts_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
stream->found_audio[i] = false;
|
||||
stream->audio_dts_offsets[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ts_offset_update(struct ffmpeg_muxer *stream,
|
||||
struct encoder_packet *packet)
|
||||
{
|
||||
if (packet->type == OBS_ENCODER_VIDEO) {
|
||||
if (!stream->found_video) {
|
||||
stream->video_pts_offset = packet->pts;
|
||||
stream->found_video = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->found_audio[packet->track_idx])
|
||||
return;
|
||||
|
||||
stream->audio_dts_offsets[packet->track_idx] = packet->dts;
|
||||
stream->found_audio[packet->track_idx] = true;
|
||||
}
|
||||
|
||||
static bool ffmpeg_mux_start(void *data)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
@ -328,6 +357,7 @@ static bool ffmpeg_mux_start(void *data)
|
||||
return false;
|
||||
path = obs_service_get_url(service);
|
||||
stream->split_file = false;
|
||||
stream->reset_timestamps = false;
|
||||
} else {
|
||||
path = obs_data_get_string(settings, "path");
|
||||
|
||||
@ -337,12 +367,16 @@ static bool ffmpeg_mux_start(void *data)
|
||||
(1024 * 1024);
|
||||
stream->split_file = stream->max_time > 0 ||
|
||||
stream->max_size > 0;
|
||||
stream->reset_timestamps =
|
||||
obs_data_get_bool(settings, "reset_timestamps");
|
||||
stream->allow_overwrite =
|
||||
obs_data_get_bool(settings, "allow_overwrite");
|
||||
stream->cur_size = 0;
|
||||
stream->sent_headers = false;
|
||||
}
|
||||
|
||||
ts_offset_clear(stream);
|
||||
|
||||
if (!stream->is_network) {
|
||||
/* ensure output path is writable to avoid generic error
|
||||
* message.
|
||||
@ -545,6 +579,16 @@ bool write_packet(struct ffmpeg_muxer *stream, struct encoder_packet *packet)
|
||||
: FFM_PACKET_AUDIO,
|
||||
.keyframe = packet->keyframe};
|
||||
|
||||
if (stream->split_file && stream->reset_timestamps) {
|
||||
if (is_video) {
|
||||
info.dts -= stream->video_pts_offset;
|
||||
info.pts -= stream->video_pts_offset;
|
||||
} else {
|
||||
info.dts -= stream->audio_dts_offsets[info.index];
|
||||
info.pts -= stream->audio_dts_offsets[info.index];
|
||||
}
|
||||
}
|
||||
|
||||
ret = os_process_pipe_write(stream->pipe, (const uint8_t *)&info,
|
||||
sizeof(info));
|
||||
if (ret != sizeof(info)) {
|
||||
@ -682,6 +726,7 @@ static bool prepare_split_file(struct ffmpeg_muxer *stream,
|
||||
|
||||
stream->cur_size = 0;
|
||||
stream->cur_time = packet->dts_usec;
|
||||
ts_offset_clear(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -721,6 +766,9 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->split_file && stream->reset_timestamps)
|
||||
ts_offset_update(stream, packet);
|
||||
|
||||
write_packet(stream, packet);
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,12 @@ struct ffmpeg_muxer {
|
||||
volatile bool muxing;
|
||||
DARRAY(struct encoder_packet) mux_packets;
|
||||
|
||||
/* split file */
|
||||
bool found_video;
|
||||
bool found_audio[MAX_AUDIO_MIXES];
|
||||
int64_t video_pts_offset;
|
||||
int64_t audio_dts_offsets[MAX_AUDIO_MIXES];
|
||||
|
||||
/* these are accessed both by replay buffer and by HLS */
|
||||
pthread_t mux_thread;
|
||||
bool mux_thread_joinable;
|
||||
@ -54,6 +60,7 @@ struct ffmpeg_muxer {
|
||||
|
||||
bool is_network;
|
||||
bool split_file;
|
||||
bool reset_timestamps;
|
||||
bool allow_overwrite;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user