summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/command.c22
-rw-r--r--player/core.h8
-rw-r--r--player/loadfile.c93
-rw-r--r--player/playloop.c3
4 files changed, 126 insertions, 0 deletions
diff --git a/player/command.c b/player/command.c
index 6d335e535a..cde67ebe51 100644
--- a/player/command.c
+++ b/player/command.c
@@ -3549,6 +3549,26 @@ static int mp_property_cwd(void *ctx, struct m_property *prop,
return M_PROPERTY_NOT_IMPLEMENTED;
}
+static int mp_property_record_file(void *ctx, struct m_property *prop,
+ int action, void *arg)
+{
+ struct MPContext *mpctx = ctx;
+ struct MPOpts *opts = mpctx->opts;
+ if (action == M_PROPERTY_SET) {
+ char *new = *(char **)arg;
+ if (!bstr_equals(bstr0(new), bstr0(opts->record_file))) {
+ talloc_free(opts->record_file);
+ opts->record_file = talloc_strdup(NULL, new);
+ open_recorder(mpctx, false);
+ // open_recorder() unsets it on failure.
+ if (new && !opts->record_file)
+ return M_PROPERTY_ERROR;
+ }
+ return M_PROPERTY_OK;
+ }
+ return mp_property_generic_option(mpctx, prop, action, arg);
+}
+
static int mp_property_protocols(void *ctx, struct m_property *prop,
int action, void *arg)
{
@@ -4020,6 +4040,8 @@ static const struct m_property mp_properties_base[] = {
{"working-directory", mp_property_cwd},
+ {"record-file", mp_property_record_file},
+
{"protocol-list", mp_property_protocols},
{"decoder-list", mp_property_decoders},
{"encoder-list", mp_property_encoders},
diff --git a/player/core.h b/player/core.h
index 4767830bc9..79120decd3 100644
--- a/player/core.h
+++ b/player/core.h
@@ -153,6 +153,9 @@ struct track {
struct vo_chain *vo_c;
struct ao_chain *ao_c;
struct lavfi_pad *sink;
+
+ // For stream recording (remuxing mode).
+ struct mp_recorder_sink *remux_sink;
};
// Summarizes video filtering and output.
@@ -421,6 +424,8 @@ typedef struct MPContext {
// playback rate. Used to avoid showing it multiple times.
bool drop_message_shown;
+ struct mp_recorder *recorder;
+
char *cached_watch_later_configdir;
struct screenshot_ctx *screenshot_ctx;
@@ -506,6 +511,9 @@ void autoload_external_files(struct MPContext *mpctx);
struct track *select_default_track(struct MPContext *mpctx, int order,
enum stream_type type);
void prefetch_next(struct MPContext *mpctx);
+void close_recorder(struct MPContext *mpctx);
+void close_recorder_and_error(struct MPContext *mpctx);
+void open_recorder(struct MPContext *mpctx, bool on_init);
// main.c
int mp_initialize(struct MPContext *mpctx, char **argv);
diff --git a/player/loadfile.c b/player/loadfile.c
index 524ff8f1b2..dba02ee828 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -40,6 +40,7 @@
#include "options/m_property.h"
#include "common/common.h"
#include "common/encode.h"
+#include "common/recorder.h"
#include "input/input.h"
#include "audio/audio.h"
@@ -469,6 +470,8 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type
uninit_sub(mpctx, current);
if (current) {
+ if (current->remux_sink)
+ close_recorder_and_error(mpctx);
current->selected = false;
reselect_demux_stream(mpctx, current);
}
@@ -1256,6 +1259,8 @@ reopen_file:
if (mpctx->opts->pause)
pause_player(mpctx);
+ open_recorder(mpctx, true);
+
playback_start = mp_time_sec();
mpctx->error_playing = 0;
while (!mpctx->stop_play)
@@ -1278,6 +1283,8 @@ terminate_playback:
mp_abort_playback_async(mpctx);
+ close_recorder(mpctx);
+
// time to uninit all, except global stuff:
uninit_complex_filters(mpctx);
uninit_audio_chain(mpctx);
@@ -1449,3 +1456,89 @@ void mp_set_playlist_entry(struct MPContext *mpctx, struct playlist_entry *e)
mpctx->stop_play = PT_CURRENT_ENTRY;
mp_wakeup_core(mpctx);
}
+
+static void set_track_recorder_sink(struct track *track,
+ struct mp_recorder_sink *sink)
+{
+ if (track->d_sub)
+ sub_set_recorder_sink(track->d_sub, sink);
+ if (track->d_video)
+ track->d_video->recorder_sink = sink;
+ if (track->d_audio)
+ track->d_audio->recorder_sink = sink;
+ track->remux_sink = sink;
+}
+
+void close_recorder(struct MPContext *mpctx)
+{
+ if (!mpctx->recorder)
+ return;
+
+ for (int n = 0; n < mpctx->num_tracks; n++)
+ set_track_recorder_sink(mpctx->tracks[n], NULL);
+
+ mp_recorder_destroy(mpctx->recorder);
+ mpctx->recorder = NULL;
+}
+
+// Like close_recorder(), but also unset the option. Intended for use on errors.
+void close_recorder_and_error(struct MPContext *mpctx)
+{
+ close_recorder(mpctx);
+ talloc_free(mpctx->opts->record_file);
+ mpctx->opts->record_file = NULL;
+ mp_notify_property(mpctx, "record-file");
+ MP_ERR(mpctx, "Disabling stream recording.\n");
+}
+
+void open_recorder(struct MPContext *mpctx, bool on_init)
+{
+ if (!mpctx->playback_initialized)
+ return;
+
+ close_recorder(mpctx);
+
+ char *target = mpctx->opts->record_file;
+ if (!target || !target[0])
+ return;
+
+ struct sh_stream **streams = NULL;
+ int num_streams = 0;
+
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (track->stream && track->selected &&
+ (track->d_sub || track->d_video || track->d_audio))
+ {
+ MP_TARRAY_APPEND(NULL, streams, num_streams, track->stream);
+ }
+ }
+
+ mpctx->recorder = mp_recorder_create(mpctx->global, mpctx->opts->record_file,
+ streams, num_streams);
+
+ if (!mpctx->recorder) {
+ talloc_free(streams);
+ close_recorder_and_error(mpctx);
+ return;
+ }
+
+ if (!on_init)
+ mp_recorder_mark_discontinuity(mpctx->recorder);
+
+ int n_stream = 0;
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (n_stream >= num_streams)
+ break;
+ // (We expect track->stream not to be reused on other tracks.)
+ if (track->stream == streams[n_stream]) {
+ set_track_recorder_sink(track,
+ mp_recorder_get_sink(mpctx->recorder, n_stream));
+ n_stream++;
+ }
+ }
+
+ talloc_free(streams);
+}
+
diff --git a/player/playloop.c b/player/playloop.c
index 232a75f814..e73ad61788 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -28,6 +28,7 @@
#include "options/options.h"
#include "common/common.h"
#include "common/encode.h"
+#include "common/recorder.h"
#include "options/m_config.h"
#include "options/m_property.h"
#include "common/playlist.h"
@@ -330,6 +331,8 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
clear_audio_output_buffers(mpctx);
reset_playback_state(mpctx);
+ if (mpctx->recorder)
+ mp_recorder_mark_discontinuity(mpctx->recorder);
/* Use the target time as "current position" for further relative
* seeks etc until a new video frame has been decoded */