#include "vframe.h"
#include "filexml.h"
+#ifdef FFMPEG3
+#define av_filter_iterate(p) ((*(const AVFilter**)(p))=avfilter_next(*(const AVFilter **)(p)))
+#endif
static void ff_err(int ret, const char *fmt, ...)
{
}
}
-void PluginFClientConfig::interpolate(PluginFClientConfig &prev, PluginFClientConfig &next,
+void PluginFClientConfig::interpolate(PluginFClientConfig &prev, PluginFClientConfig &next,
int64_t prev_frame, int64_t next_frame, int64_t current_frame)
{
copy_from(prev);
void PluginFClientConfig::initialize(const char *name)
{
+ delete ffilt;
ffilt = PluginFFilter::new_ffilter(name);
const AVOption *opt = 0;
void *obj = ffilt->filter_config();
append(fopt);
}
}
+ if( (ffilt->filter->flags & AVFILTER_FLAG_SLICE_THREADS) != 0 ) {
+ opt = av_opt_find(ffilt->fctx, "threads", NULL, 0, 0);
+ if( opt ) {
+ PluginFClient_Opt *fopt = new PluginFClient_Opt(this, opt);
+ append(fopt);
+ }
+ }
}
int PluginFClientConfig::update()
int PluginFClientReset::handle_event()
{
- av_opt_set_defaults(fwin->ffmpeg->config.filter_config());
+ fwin->ffmpeg->config.initialize(fwin->ffmpeg->name);
if( fwin->ffmpeg->config.update() > 0 )
fwin->draw();
fwin->ffmpeg->plugin->send_configure_change();
int PluginFClientApply::handle_event()
{
- const char *text = fwin->text->get_text();
- if( text && fwin->selected ) {
- fwin->selected->set(text);
- fwin->selected->item_value->update();
- fwin->draw();
- fwin->ffmpeg->plugin->send_configure_change();
+ return fwin->update();
+}
+
+PluginFClientPot::PluginFClientPot(PluginFClientWindow *fwin, int x, int y)
+ : BC_FPot(x, y, 0.f, 0.f, 0.f)
+{
+ this->fwin = fwin;
+}
+
+int PluginFClient_Opt::get_range(float &fmn, float &fmx)
+{
+ switch( opt->type ) {
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_INT64:
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_FLOAT: break;
+ default: return 1;
+ }
+ const AVClass *filt_class = filter_class();
+ if( !filt_class || !filt_class->option ) return 1;
+ AVOptionRanges *r = 0;
+ void *obj = &filt_class;
+ if( av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) < 0 ) return 1;
+ int ret = 1;
+ if( r->nb_ranges == 1 ) {
+ fmn = r->range[0]->value_min;
+ fmx = r->range[0]->value_max;
+ ret = 0;
+ }
+ av_opt_freep_ranges(&r);
+ return ret;
+}
+
+float PluginFClient_Opt::get_float()
+{
+ char val[BCTEXTLEN]; val[0] = 0;
+ get(val, sizeof(val));
+ return atof(val);
+}
+
+void PluginFClient_Opt::set_float(float v)
+{
+ char val[BCTEXTLEN]; val[0] = 0;
+ sprintf(val, "%f", v);
+ set(val);
+}
+
+int PluginFClientPot::handle_event()
+{
+ if( fwin->selected ) {
+ fwin->selected->set_float(get_value());
+ fwin->update_selected();
+ return fwin->update();
+ }
+ return 1;
+}
+
+PluginFClientSlider::PluginFClientSlider(PluginFClientWindow *fwin, int x, int y)
+ : BC_FSlider(x, y, 0, fwin->get_w()-x-20, fwin->get_w()-x-20, 0.f, 0.f, 0.f)
+{
+ this->fwin = fwin;
+}
+
+int PluginFClientSlider::handle_event()
+{
+ if( fwin->selected ) {
+ fwin->selected->set_float(get_value());
+ fwin->update_selected();
+ return fwin->update();
}
return 1;
}
*(sp=str) = 0;
if( opt ) opt->ranges(sp);
range->update(str);
- while( units->total_items() ) units->remove_item(0);
+ while( units->total_items() ) units->del_item(0);
ArrayList<const AVOption *> opts;
int n = !opt ? 0 : opt->units(opts);
for( int i=0; i<n; ++i )
if( opt ) opt->get(val, sizeof(val));
text->update(val);
+ float v = 0, fmn = 0, fmx = 0;
+ if( opt && !opt->get_range(fmn, fmx) ) v = atof(val);
+ float p = (fmx-fmn) / slider->get_w();
+ slider->set_precision(p);
+ slider->update(slider->get_w(), v, fmn, fmx);
+ pot->set_precision(p);
+ pot->update(v, fmn, fmx);
panel->update();
}
+int PluginFClientWindow::update()
+{
+ const char *txt = text->get_text();
+ if( txt && selected ) {
+ selected->set(txt);
+ selected->item_value->update();
+ draw();
+ ffmpeg->plugin->send_configure_change();
+ }
+ return 1;
+}
+
+void PluginFClientWindow::update_selected()
+{
+ update(selected);
+}
+
int PluginFClient_OptPanel::selection_changed()
{
PluginFClient_Opt *opt = 0;
if( strlen(opts[i]->name) < strlen(opt->name) ) opts[i] = opt;
break;
}
- if( i < 0 )
+ if( i < 0 )
opts.append(opt);
}
return opts.size();
add_subwindow(apply = new PluginFClientApply(this, x1, y));
add_subwindow(text = new PluginFClientText(this, x0, y, x1-x0 - 8));
y += title->get_h() + 10;
+ add_subwindow(pot = new PluginFClientPot(this, x, y));
+ x1 = x + pot->get_w() + 10;
+ add_subwindow(slider = new PluginFClientSlider(this, x1, y+10));
+ y += pot->get_h() + 10;
panel_x = x; panel_y = y;
panel_w = get_w()-10 - panel_x;
int x0 = units->get_x() + units->get_w() + 8;
int y0 = units->get_y();
text->reposition_window(x0,y0, x1-x0-8);
+ x1 = pot->get_x() + pot->get_w() + 10;
+ int w1 = w - slider->get_x() - 20;
+ slider->set_pointer_motion_range(w1);
+ slider->reposition_window(x1, slider->get_y(), w1, slider->get_h());
panel_w = get_w()-10 - panel_x;
panel_h = get_h()-10 - panel_y;
panel->reposition_window(panel_x,panel_y, panel_w, panel_h);
return 1;
}
+
PluginFClient::PluginFClient(PluginClient *plugin, const char *name)
{
this->plugin = plugin;
PluginFClient::~PluginFClient()
{
+ delete ffilt;
}
-bool PluginFClient::is_audio(AVFilter *fp)
+bool PluginFClient::is_audio(const AVFilter *fp)
{
if( !fp->outputs ) return 0;
if( avfilter_pad_count(fp->outputs) > 1 ) return 0;
if( avfilter_pad_get_type(fp->inputs, 0) != AVMEDIA_TYPE_AUDIO ) return 0;
return 1;
}
-bool PluginFClient::is_video(AVFilter *fp)
+bool PluginFClient::is_video(const AVFilter *fp)
{
if( !fp->outputs ) return 0;
if( avfilter_pad_count(fp->outputs) > 1 ) return 0;
av_freep(&buf);
}
}
+ if( (config.ffilt->filter->flags & AVFILTER_FLAG_SLICE_THREADS) != 0 ) {
+ uint8_t *buf = 0;
+ if( av_opt_get(config.ffilt->fctx, "threads", 0, &buf) >= 0 && buf ) {
+ output.tag.set_property("threads", (const char *)buf);
+ av_freep(&buf);
+ }
+ }
output.append_tag();
output.terminate_string();
void PluginFClient::read_data(KeyFrame *keyframe)
{
FileXML input;
- char string[BCTEXTLEN], value[BCTEXTLEN];
+ char string[BCTEXTLEN];
input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
while( !input.read_tag() ) {
void *obj = config.filter_config();
const AVOption *opt = NULL;
while( (opt=av_opt_next(obj, opt)) != 0 ) {
- to_upper(string, opt->name);
- if( !input.tag.get_property(string, value) ) continue;
- av_opt_set(obj, opt->name, value, 0);
+ const char *v = input.tag.get_property(opt->name);
+ if( v ) av_opt_set(obj, opt->name, v, 0);
+ }
+ if( (config.ffilt->filter->flags & AVFILTER_FLAG_SLICE_THREADS) != 0 ) {
+ const char *v = input.tag.get_property("threads");
+ if( v ) av_opt_set(config.ffilt->fctx, "threads", v, 0);
}
}
}
{
AVFilterContext *fctx = ffilt->fctx;
AVFilterLink **links = !fctx->nb_inputs ? 0 : fctx->inputs;
- return !links ? 0 : avfilter_link_get_channels(links[0]);
+ return !links ? 0 : links[0]->channels;
}
int PluginFAClient::get_outchannels()
{
AVFilterContext *fctx = ffilt->fctx;
AVFilterLink **links = !fctx->nb_outputs ? 0 : fctx->outputs;
- return !links ? 0 : avfilter_link_get_channels(links[0]);
+ return !links ? 0 : links[0]->channels;
}
int PluginFAClient::process_buffer(int64_t size, Samples **buffer, int64_t start_position, int sample_rate)
if( ret >= 0 ) {
in_channels = get_inchannels();
out_channels = get_outchannels();
+ frame->nb_samples = size;
+ frame->format = AV_SAMPLE_FMT_FLTP;
+ frame->channel_layout = (1<<in_channels)-1;
+ frame->sample_rate = sample_rate;
+ frame->pts = local_to_edl(filter_position);
}
int retry = 10;
for( int i=0; i<total_in; ++i )
read_samples(buffer[i], i, sample_rate, filter_position, size);
filter_position += size;
- frame->nb_samples = size;
- frame->format = AV_SAMPLE_FMT_FLTP;
- frame->channel_layout = (1<<in_channels)-1;
- frame->sample_rate = sample_rate;
- frame->pts = local_to_edl(filter_position);
ret = av_frame_get_buffer(frame, 0);
if( ret < 0 ) break;
float **in_buffers = (float **)&frame->extended_data[0];
color_model_to_pix_fmt(colormodel);
if( pix_fmt <= AV_PIX_FMT_NONE || pix_fmt >= AV_PIX_FMT_NB )
pix_fmt = AV_PIX_FMT_RGBA;
-
+
AVFrame *frame = 0;
if( ret >= 0 && !(frame = av_frame_alloc()) ) {
fprintf(stderr, "PluginFVClient::process_buffer: av_frame_alloc failed\n");
ret = av_buffersink_get_frame(fsink, frame);
if( ret >= 0 || ret != AVERROR(EAGAIN) ) break;
if( !fsrc ) { ret = AVERROR(EIO); break; }
- read_frame(vframe, 0, filter_position++, frame_rate, get_use_opengl());
+ read_frame(vframe, 0, filter_position++, frame_rate, 0);
frame->format = pix_fmt;
frame->width = width;
frame->height = height;
frame->pts = local_to_edl(position);
ret = av_frame_get_buffer(frame, 32);
if( ret < 0 ) break;
- ret = transfer_pixfmt(vframe, frame, pix_fmt, width, height);
+ ret = transfer_pixfmt(vframe, frame);
if( ret < 0 ) break;
ret = av_buffersrc_add_frame_flags(fsrc, frame, 0);
}
if( ret >= 0 ) {
pix_fmt = (AVPixelFormat) frame->format;
- ret = transfer_cmodel(vframe, frame, pix_fmt, width, height);
+ ret = transfer_cmodel(vframe, frame);
}
if( ret < 0 ) {
ff_err(ret, "PluginFVClient::process_buffer() %s\n", plugin_title());
delete item_value;
}
-char *PluginFClient_Opt::get(char *vp, int sz)
+const char *PluginFClientConfig::get(const char *name)
{
- char *ret = 0;
- void *obj = filter_config();
uint8_t *bp = 0;
- if( av_opt_get(obj, opt->name, 0, &bp) >= 0 && bp != 0 ) {
- const char *val = (const char *)bp;
- ret = sz >= 0 ? strncpy(vp,val,sz) : strcpy(vp, val);
- if( sz > 0 ) vp[sz-1] = 0;
- av_freep(&bp);
+ if( av_opt_get(filter_config(), name, 0, &bp) >= 0 ||
+ av_opt_get(ffilt->fctx, name, 0, &bp) >= 0 )
+ return (const char *)bp;
+ return 0;
+}
+char *PluginFClient_Opt::get(char *vp, int sz)
+{
+ const char *val = conf->get(opt->name);
+ if( val ) {
+ strncpy(vp, val, sz);
+ vp[sz-1] = 0;
}
- return ret;
+ else
+ vp = 0;
+ av_freep(&val);
+ return vp;
+}
+
+void PluginFClientConfig::set(const char *name, const char *val)
+{
+ if( av_opt_set(filter_config(), name, val, 0) < 0 )
+ av_opt_set(ffilt->fctx, name, val, 0);
}
void PluginFClient_Opt::set(const char *val)
{
- void *obj = filter_config();
- av_opt_set(obj , opt->name, val, 0);
+ conf->set(opt->name, val);
}
void PluginFFilter::uninit()
FILE *fp = fopen(defaults_path,"r");
if( !fp ) return 0;
char ff_plugin[BCSTRLEN], ff_args[BCTEXTLEN], *ap = 0;
- while( !ap && fgets(ff_args, sizeof(ff_args), fp) ) {
- if( *(ap=ff_args) == ';' ) continue;
- if( *(ap=ff_args) == '#' ) ++ap;
+ while( fgets(ff_args, sizeof(ff_args), fp) ) {
+ char *cp = ff_args;
+ if( *cp == ';' ) continue;
+ if( *cp == '#' ) ++cp;
char *bp = ff_plugin, *ep = bp + sizeof(ff_plugin)-1;
- while( bp < ep && *ap && *ap != '\n' && *ap != ' ' ) *bp++ = *ap++;
+ while( bp < ep && *cp && *cp != '\n' && *cp != ' ' ) *bp++ = *cp++;
*bp = 0;
- if( strcmp(ff_plugin, name) ) ap = 0;
+ if( !strcmp(ff_plugin, name) ) { ap = cp; break; }
}
fclose(fp);
if( !ap ) return 0;
static int inst = 0;
char inst_name[BCSTRLEN];
sprintf(inst_name,"%s_%d", name, ++inst);
- graph->thread_type = 0;
- graph->nb_threads = 1;
+ if( conf && (filter->flags & AVFILTER_FLAG_SLICE_THREADS) != 0 ) {
+ graph->thread_type = AVFILTER_THREAD_SLICE;
+ graph->nb_threads = atoi(conf->get("threads"));
+ }
+ else {
+ graph->thread_type = 0;
+ graph->nb_threads = 0;
+ }
fctx = avfilter_graph_alloc_filter(graph, filter, inst_name);
if( !fctx ) return AVERROR(ENOMEM);
+ fctx->thread_type = graph->thread_type; // bug in avfilter
if( conf ) {
AVDictionary *opts = 0;
for( int i=0; i<conf->size(); ++i ) {
PluginFClient_Opt *op = conf->get(i);
const char *name = op->opt->name;
char val[BCTEXTLEN], *vp = op->get(val, sizeof(val));
- if( vp ) av_dict_set(&opts, name, vp, 0);
+ if( !vp ) continue;
+ uint8_t *bp = 0;
+// unspecified opts cause a special behavior in some filters (lut3d)
+// so... if opt value is the default, skip it or no special behavior
+ if( av_opt_get(filter_config(), name, 0, &bp) >= 0 ) {
+ int result = strcmp((const char *)bp, vp);
+ av_freep(&bp);
+ if( !result ) continue;
+ }
+ av_dict_set(&opts, name, vp, 0);
}
ret = avfilter_init_dict(fctx, &opts);
av_dict_free(&opts);
PluginClient *PluginServer::new_ffmpeg_plugin()
{
- AVFilter *filter = avfilter_get_by_name(ff_name);
+ const AVFilter *filter = avfilter_get_by_name(ff_name);
if( !filter ) return 0;
PluginFClient *ffmpeg =
PluginFClient::is_audio(filter) ?
PluginFFilter *ffilt = PluginFFilter::new_ffilter(name);
if( !ffilt ) return 0;
delete ffilt;
- return new PluginServer(mwindow, (char*)name, PLUGIN_TYPE_FFMPEG);
+ return new PluginServer(mwindow, name, PLUGIN_TYPE_FFMPEG);
}
void MWindow::init_ffmpeg_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
{
PluginFLogLevel errs(AV_LOG_ERROR);
- const AVFilter *filter = 0;
- while( (filter=avfilter_next(filter)) != 0 ) {
+ const AVFilter *filter = 0; void *idx = 0;
+ while( (filter=av_filter_iterate(&idx)) != 0 ) {
+//printf("%s\n",filter->name);
PluginServer *server = new_ffmpeg_server(mwindow, filter->name);
if( server ) {
int result = server->open_plugin(1, preferences, 0, 0);
void MWindow::init_ffmpeg()
{
- av_register_all();
- avfilter_register_all();
}