Something went wrong. Try again.
🎥 Command line media player
Something went wrong. Try again.
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312#include "audio/aframe.h"#include "video/mp_image.h"
#include "f_utils.h"#include "filter_internal.h"
struct frame_duration_priv { struct mp_image *buffered;};
static void frame_duration_process(struct mp_filter *f){ struct frame_duration_priv *p = f->priv;
if (!mp_pin_can_transfer_data(f->ppins[1], f->ppins[0])) return;
struct mp_frame frame = mp_pin_out_read(f->ppins[0]);
if (frame.type == MP_FRAME_EOF && p->buffered) { mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_VIDEO, p->buffered)); p->buffered = NULL; // Pass through the actual EOF in the next iteration. mp_pin_out_repeat_eof(f->ppins[0]); } else if (frame.type == MP_FRAME_VIDEO) { struct mp_image *next = frame.data; if (p->buffered) { if (p->buffered->pts != MP_NOPTS_VALUE && next->pts != MP_NOPTS_VALUE && next->pts >= p->buffered->pts) { p->buffered->pkt_duration = next->pts - p->buffered->pts; } mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_VIDEO, p->buffered)); } else { mp_pin_out_request_data(f->ppins[0]); } p->buffered = next; } else { mp_pin_in_write(f->ppins[1], frame); }}
static void frame_duration_reset(struct mp_filter *f){ struct frame_duration_priv *p = f->priv;
mp_image_unrefp(&p->buffered);}
static const struct mp_filter_info frame_duration_filter = { .name = "frame_duration", .priv_size = sizeof(struct frame_duration_priv), .process = frame_duration_process, .reset = frame_duration_reset, .destroy = frame_duration_reset,};
struct mp_filter *mp_compute_frame_duration_create(struct mp_filter *parent){ struct mp_filter *f = mp_filter_create(parent, &frame_duration_filter); if (!f) return NULL;
mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out");
return f;}
void mp_chain_filters(struct mp_pin *in, struct mp_pin *out, struct mp_filter **filters, int num_filters){ for (int n = 0; n < num_filters; n++) { if (!filters[n]) continue; assert(filters[n]->num_pins == 2); mp_pin_connect(filters[n]->pins[0], in); in = filters[n]->pins[1]; } mp_pin_connect(out, in);}
// Make it repeat process().static void mark_progress(struct mp_subfilter *sub){ // f == NULL is not really allowed, but at least don't crash. struct mp_filter *f = mp_pin_get_manual_connection(sub->in); if (f) mp_filter_internal_mark_progress(f);}
bool mp_subfilter_read(struct mp_subfilter *sub){ if (sub->filter) { if (mp_pin_can_transfer_data(sub->out, sub->filter->pins[1])) { struct mp_frame frame = mp_pin_out_read(sub->filter->pins[1]); if (sub->draining && frame.type == MP_FRAME_EOF) { sub->draining = false; TA_FREEP(&sub->filter); mark_progress(sub); return false; } mp_pin_in_write(sub->out, frame); return false; } if (sub->draining) return false; }
struct mp_pin *out = sub->filter ? sub->filter->pins[0] : sub->out;
if (sub->frame.type) return mp_pin_in_needs_data(out);
if (!mp_pin_can_transfer_data(out, sub->in)) return false;
sub->frame = mp_pin_out_read(sub->in); return true;}
void mp_subfilter_reset(struct mp_subfilter *sub){ if (sub->filter && sub->draining) TA_FREEP(&sub->filter); sub->draining = false; mp_frame_unref(&sub->frame);}
void mp_subfilter_continue(struct mp_subfilter *sub){ struct mp_pin *out = sub->filter ? sub->filter->pins[0] : sub->out; // It was made sure earlier that the pin is writable, unless the filter // was newly created, or a previously existing filter (which was going to // accept input) was destroyed. In those cases, essentially restart // data flow. if (!mp_pin_in_needs_data(out)) { mark_progress(sub); return; } mp_pin_in_write(out, sub->frame); sub->frame = MP_NO_FRAME;}
void mp_subfilter_destroy(struct mp_subfilter *sub){ TA_FREEP(&sub->filter); sub->draining = false;}
bool mp_subfilter_drain_destroy(struct mp_subfilter *sub){ if (!sub->draining && sub->filter) { // We know the filter is writable (unless the user created a new filter // and immediately called this function, which is invalid). mp_pin_in_write(sub->filter->pins[0], MP_EOF_FRAME); sub->draining = true; } return !sub->filter;}
static const struct mp_filter_info bidir_nop_filter = { .name = "nop",};
struct mp_filter *mp_bidir_nop_filter_create(struct mp_filter *parent){ struct mp_filter *f = mp_filter_create(parent, &bidir_nop_filter); if (!f) return NULL;
mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out");
mp_pin_connect(f->ppins[1], f->ppins[0]);
return f;}
static const struct mp_filter_info bidir_dummy_filter = { .name = "dummy",};
struct mp_filter *mp_bidir_dummy_filter_create(struct mp_filter *parent){ struct mp_filter *f = mp_filter_create(parent, &bidir_dummy_filter); if (!f) return NULL;
mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out");
return f;}
struct fixed_aframe_size_priv { int samples; bool pad_silence; struct mp_aframe *in; struct mp_aframe *out; int out_written; // valid samples in out struct mp_aframe_pool *pool;};
static void fixed_aframe_size_process(struct mp_filter *f){ struct fixed_aframe_size_priv *p = f->priv;
if (!mp_pin_in_needs_data(f->ppins[1])) return;
if (p->in && !mp_aframe_get_size(p->in)) TA_FREEP(&p->in);
if (!p->in) { struct mp_frame frame = mp_pin_out_read(f->ppins[0]); if (frame.type == MP_FRAME_EOF) { if (!p->out) { mp_pin_in_write(f->ppins[1], frame); return; } mp_pin_out_repeat_eof(f->ppins[0]); } else if (frame.type == MP_FRAME_AUDIO) { p->in = frame.data; if (p->out && !mp_aframe_config_equals(p->out, p->in)) { mp_pin_out_unread(f->ppins[0], frame); p->in = NULL; } } else if (frame.type) { MP_ERR(f, "unsupported frame type\n"); mp_filter_internal_mark_failed(f); return; } else { return; // no new data yet } }
if (p->in) { if (!p->out) { p->out = mp_aframe_create(); mp_aframe_config_copy(p->out, p->in); mp_aframe_copy_attributes(p->out, p->in); if (mp_aframe_pool_allocate(p->pool, p->out, p->samples) < 0) { mp_filter_internal_mark_failed(f); return; } p->out_written = 0; } int in_samples = mp_aframe_get_size(p->in); int copy = MPMIN(in_samples, p->samples - p->out_written); if (!mp_aframe_copy_samples(p->out, p->out_written, p->in, 0, copy)) MP_ASSERT_UNREACHABLE(); mp_aframe_skip_samples(p->in, copy); p->out_written += copy; }
// p->in not set means draining for EOF or format change if ((!p->in && p->out_written) || p->out_written == p->samples) { int missing = p->samples - p->out_written; assert(missing >= 0); if (missing) { mp_aframe_set_silence(p->out, p->out_written, missing); if (!p->pad_silence) mp_aframe_set_size(p->out, p->out_written); } mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, p->out)); p->out = NULL; p->out_written = 0; } else { mp_pin_out_request_data_next(f->ppins[0]); }}
static void fixed_aframe_size_reset(struct mp_filter *f){ struct fixed_aframe_size_priv *p = f->priv;
TA_FREEP(&p->in); TA_FREEP(&p->out); p->out_written = 0;}
static const struct mp_filter_info fixed_aframe_size_filter = { .name = "fixed_aframe_size", .priv_size = sizeof(struct fixed_aframe_size_priv), .process = fixed_aframe_size_process, .reset = fixed_aframe_size_reset, .destroy = fixed_aframe_size_reset,};
struct mp_filter *mp_fixed_aframe_size_create(struct mp_filter *parent, int samples, bool pad_silence){ if (samples < 1) return NULL;
struct mp_filter *f = mp_filter_create(parent, &fixed_aframe_size_filter); if (!f) return NULL;
mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out");
struct fixed_aframe_size_priv *p = f->priv; p->samples = samples; p->pad_silence = pad_silence; p->pool = mp_aframe_pool_create(p);
return f;}