From a3a59f63fdfbcf94c561595f515951fdfd4bea30 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Sat, 31 Oct 2015 17:33:44 -0600 Subject: [PATCH] add ffmpeg filters as plugins --- cinelerra-5.0/cinelerra/Makefile | 8 +- cinelerra-5.0/cinelerra/aattachmentpoint.C | 53 +- cinelerra-5.0/cinelerra/awindow.C | 9 + cinelerra-5.0/cinelerra/awindow.h | 3 + cinelerra-5.0/cinelerra/awindowgui.C | 75 +- cinelerra-5.0/cinelerra/awindowgui.h | 7 +- cinelerra-5.0/cinelerra/data/ff_audio.png | Bin 0 -> 2634 bytes cinelerra-5.0/cinelerra/data/ff_audio_png.h | 174 +++ cinelerra-5.0/cinelerra/data/ff_video.png | Bin 0 -> 2717 bytes cinelerra-5.0/cinelerra/data/ff_video_png.h | 179 +++ cinelerra-5.0/cinelerra/ffmpeg.C | 72 +- cinelerra-5.0/cinelerra/ffmpeg.h | 40 +- cinelerra-5.0/cinelerra/fileac3.C | 6 +- cinelerra-5.0/cinelerra/mwindow.C | 67 +- cinelerra-5.0/cinelerra/mwindow.h | 6 +- cinelerra-5.0/cinelerra/mwindow.inc | 2 +- cinelerra-5.0/cinelerra/pluginfclient.C | 1152 +++++++++++++++++++ cinelerra-5.0/cinelerra/pluginfclient.h | 285 +++++ cinelerra-5.0/cinelerra/pluginfclient.inc | 39 + cinelerra-5.0/cinelerra/pluginserver.C | 213 ++-- cinelerra-5.0/cinelerra/pluginserver.h | 52 +- cinelerra-5.0/cinelerra/pluginserver.inc | 13 +- cinelerra-5.0/cinelerra/vattachmentpoint.C | 80 +- cinelerra-5.0/ffmpeg/plugin.opts | 168 +++ cinelerra-5.0/guicast/bchash.C | 24 +- cinelerra-5.0/guicast/bchash.h | 1 + cinelerra-5.0/guicast/vframe.C | 5 +- cinelerra-5.0/mpeg2enc/Makefile | 5 +- cinelerra-5.0/msg.txt | 9 + 29 files changed, 2431 insertions(+), 316 deletions(-) create mode 100644 cinelerra-5.0/cinelerra/data/ff_audio.png create mode 100644 cinelerra-5.0/cinelerra/data/ff_audio_png.h create mode 100644 cinelerra-5.0/cinelerra/data/ff_video.png create mode 100644 cinelerra-5.0/cinelerra/data/ff_video_png.h create mode 100644 cinelerra-5.0/cinelerra/pluginfclient.C create mode 100644 cinelerra-5.0/cinelerra/pluginfclient.h create mode 100644 cinelerra-5.0/cinelerra/pluginfclient.inc create mode 100644 cinelerra-5.0/ffmpeg/plugin.opts diff --git a/cinelerra-5.0/cinelerra/Makefile b/cinelerra-5.0/cinelerra/Makefile index 065346f5..6b0d1bd1 100644 --- a/cinelerra-5.0/cinelerra/Makefile +++ b/cinelerra-5.0/cinelerra/Makefile @@ -326,6 +326,7 @@ OBJS = \ $(OBJDIR)/vdevicempeg.o \ $(OBJDIR)/vdevicev4l2mpeg.o \ $(OBJDIR)/wwindow.o \ + $(OBJDIR)/pluginfclient.o \ # $(OBJDIR)/renderfarmfsclient.o \ # $(OBJDIR)/renderfarmfsserver.o \ @@ -344,9 +345,6 @@ LIBRARIES := \ $(THEME_DATA) \ LIBS = $(LIBRARIES) -LIBS += $(thirdparty_libraries) -LIBS += $(thirdparty_libraries) -LIBS += $(thirdparty_libraries) LIBS += \ -lX11 \ -lXext \ @@ -361,7 +359,9 @@ LIBS += \ -llzma \ -lfontconfig \ -lfreetype \ - $(EXTRA_LIBS) + +LIBS += -Wl,--start-group $(thirdparty_libraries) -Wl,--end-group +LIBS += $(EXTRA_LIBS) CUTADS = $(OBJDIR)/cutads CUTOBJ = $(OBJDIR)/cutads.o diff --git a/cinelerra-5.0/cinelerra/aattachmentpoint.C b/cinelerra-5.0/cinelerra/aattachmentpoint.C index 00d8ae0d..edeba467 100644 --- a/cinelerra-5.0/cinelerra/aattachmentpoint.C +++ b/cinelerra-5.0/cinelerra/aattachmentpoint.C @@ -96,48 +96,27 @@ void AAttachmentPoint::render(Samples *output, if(plugin_server->multichannel) { // Test against previous parameters for reuse of previous data - if(is_processed && - this->start_position == start_position && - this->len == len && - this->sample_rate == sample_rate) - { - memcpy(output->get_data(), - buffer_vector[buffer_number]->get_data(), - sizeof(double) * len); - return; - } - + if( !is_processed || this->start_position != start_position || + this->len != len || this->sample_rate != sample_rate ) { // Update status - this->start_position = start_position; - this->len = len; - this->sample_rate = sample_rate; - is_processed = 1; + this->start_position = start_position; + this->len = len; + this->sample_rate = sample_rate; + is_processed = 1; // Allocate buffer vector - new_buffer_vector(virtual_plugins.total, len); - -// Create temporary buffer vector with output argument substituted in - Samples **output_temp = new Samples*[virtual_plugins.total]; - for(int i = 0; i < virtual_plugins.total; i++) - { - if(i == buffer_number) - output_temp[i] = output; - else - output_temp[i] = buffer_vector[i]; - } + new_buffer_vector(virtual_plugins.total, len); // Process plugin - plugin_servers.values[0]->process_buffer(output_temp, - start_position, - len, - sample_rate, - plugin->length * - sample_rate / - renderengine->get_edl()->session->sample_rate, - renderengine->command->get_direction()); - -// Delete temporary buffer vector - delete [] output_temp; + plugin_servers.values[0]->process_buffer( + buffer_vector, start_position, len, sample_rate, + plugin->length * sample_rate / + renderengine->get_edl()->session->sample_rate, + renderengine->command->get_direction()); + } + memcpy(output->get_data(), + buffer_vector[buffer_number]->get_data(), + sizeof(double) * len); } else { diff --git a/cinelerra-5.0/cinelerra/awindow.C b/cinelerra-5.0/cinelerra/awindow.C index 4dcfc4a3..f338f0e7 100644 --- a/cinelerra-5.0/cinelerra/awindow.C +++ b/cinelerra-5.0/cinelerra/awindow.C @@ -62,6 +62,15 @@ void AWindow::create_objects() clip_edit = new ClipEdit(mwindow, this, 0); } +int AWindow::save_defaults(BC_Hash *defaults) +{ + return gui->save_defaults(defaults); +} +int AWindow::load_defaults(BC_Hash *defaults) +{ + return gui->load_defaults(defaults); +} + void AWindow::run() { diff --git a/cinelerra-5.0/cinelerra/awindow.h b/cinelerra-5.0/cinelerra/awindow.h index a19f8abf..65e34085 100644 --- a/cinelerra-5.0/cinelerra/awindow.h +++ b/cinelerra-5.0/cinelerra/awindow.h @@ -25,6 +25,7 @@ #include "assetedit.inc" #include "assetremove.inc" #include "awindowgui.inc" +#include "bchash.inc" #include "bcwindowbase.inc" #include "clipedit.inc" #include "mwindow.inc" @@ -38,6 +39,8 @@ public: void run(); void create_objects(); + int load_defaults(BC_Hash *defaults); + int save_defaults(BC_Hash *defaults); char current_folder[BCTEXTLEN]; diff --git a/cinelerra-5.0/cinelerra/awindowgui.C b/cinelerra-5.0/cinelerra/awindowgui.C index 70df0cce..81e8760b 100644 --- a/cinelerra-5.0/cinelerra/awindowgui.C +++ b/cinelerra-5.0/cinelerra/awindowgui.C @@ -28,6 +28,7 @@ #include "awindow.h" #include "awindowmenu.h" #include "bcsignals.h" +#include "bchash.h" #include "cache.h" #include "bccmodels.h" #include "cursors.h" @@ -54,6 +55,8 @@ #include "vwindow.h" #include "data/lad_picon_png.h" +#include "data/ff_audio_png.h" +#include "data/ff_video_png.h" #include #include @@ -257,20 +260,28 @@ void AssetPicon::create_objects() icon = gui->atransition_icon; icon_vframe = gui->atransition_vframe; } - else if( !plugin->is_ladspa() ) { - icon = gui->aeffect_icon; - icon_vframe = gui->aeffect_vframe; + else if( plugin->is_ffmpeg() ) { + icon = gui->ff_aud_icon; + icon_vframe = gui->ff_aud_vframe; } - else { + else if( plugin->is_ladspa() ) { icon = gui->ladspa_icon; icon_vframe = gui->ladspa_vframe; } + else { + icon = gui->aeffect_icon; + icon_vframe = gui->aeffect_vframe; + } } else if( plugin->video ) { if( plugin->transition ) { icon = gui->vtransition_icon; icon_vframe = gui->vtransition_vframe; } + else if( plugin->is_ffmpeg() ) { + icon = gui->ff_vid_icon; + icon_vframe = gui->ff_vid_vframe; + } else { icon = gui->veffect_icon; icon_vframe = gui->veffect_vframe; @@ -321,13 +332,15 @@ AWindowGUI::AWindowGUI(MWindow *mwindow, AWindow *awindow) aeffect_icon = 0; aeffect_vframe = 0; ladspa_icon = 0; ladspa_vframe = 0; veffect_icon = 0; veffect_vframe = 0; + ff_aud_icon = 0; ff_aud_vframe = 0; + ff_vid_icon = 0; ff_vid_vframe = 0; + plugin_visibility = ((uint64_t)1<<(8*sizeof(uint64_t)-1))-1; newfolder_thread = 0; asset_menu = 0; assetlist_menu = 0; folderlist_menu = 0; temp_picon = 0; remove_plugin = 0; - plugin_visibility = ~0; } AWindowGUI::~AWindowGUI() @@ -339,6 +352,7 @@ AWindowGUI::~AWindowGUI() atransitions.remove_all_objects(); vtransitions.remove_all_objects(); displayed_assets[1].remove_all_objects(); + delete file_icon; delete audio_icon; delete video_icon; @@ -349,6 +363,10 @@ AWindowGUI::~AWindowGUI() delete aeffect_icon; delete ladspa_icon; delete ladspa_vframe; + delete ff_aud_icon; + delete ff_aud_vframe; + delete ff_vid_icon; + delete ff_vid_vframe; delete veffect_icon; delete newfolder_thread; delete asset_menu; @@ -361,15 +379,17 @@ AWindowGUI::~AWindowGUI() bool AWindowGUI::protected_pixmap(BC_Pixmap *icon) { return icon == file_icon || - icon == audio_icon || icon == folder_icon || - icon == clip_icon || + icon == audio_icon || icon == video_icon || - icon == veffect_icon || + icon == clip_icon || icon == vtransition_icon || + icon == atransition_icon || + icon == veffect_icon || icon == aeffect_icon || icon == ladspa_icon || - icon == atransition_icon; + icon == ff_aud_icon || + icon == ff_vid_icon; } void AWindowGUI::create_objects() @@ -413,6 +433,10 @@ SET_TRACE aeffect_icon = new BC_Pixmap(this, aeffect_vframe, PIXMAP_ALPHA); ladspa_vframe = new VFrame(lad_picon_png); ladspa_icon = new BC_Pixmap(this, ladspa_vframe, PIXMAP_ALPHA); + ff_aud_vframe = new VFrame(ff_audio_png); + ff_aud_icon = new BC_Pixmap(this, ff_aud_vframe, PIXMAP_ALPHA); + ff_vid_vframe = new VFrame(ff_video_png); + ff_vid_icon = new BC_Pixmap(this, ff_vid_vframe, PIXMAP_ALPHA); veffect_vframe = mwindow->theme->get_image("veffect_icon"); veffect_icon = new BC_Pixmap(this, veffect_vframe, PIXMAP_ALPHA); @@ -438,6 +462,7 @@ SET_TRACE SET_TRACE mwindow->theme->get_awindow_sizes(this); + load_defaults(mwindow->defaults); SET_TRACE add_subwindow(asset_list = new AWindowAssets(mwindow, @@ -574,6 +599,19 @@ void AWindowGUI::reposition_objects() flush(); } +int AWindowGUI::save_defaults(BC_Hash *defaults) +{ + defaults->update("PLUGIN_VISIBILTY", plugin_visibility); + return 0; +} + +int AWindowGUI::load_defaults(BC_Hash *defaults) +{ + plugin_visibility = defaults->get("PLUGIN_VISIBILTY", plugin_visibility); + return 0; +} + + int AWindowGUI::close_event() { hide_window(); @@ -585,6 +623,7 @@ int AWindowGUI::close_event() mwindow->gui->unlock_window(); lock_window("AWindowGUI::close_event"); + save_defaults(mwindow->defaults); mwindow->save_defaults(); return 1; } @@ -1733,7 +1772,11 @@ AddPluginsMenu::AddPluginsMenu(MWindow *mwindow, AWindowGUI *gui) void AddPluginsMenu::create_objects() { - uint32_t vis = 0; + uint64_t vis = 0; + add_item(new AddPluginItem(this, "ladspa", PLUGIN_LADSPA_ID)); + vis |= 1 << PLUGIN_LADSPA_ID; + add_item(new AddPluginItem(this, "ffmpeg", PLUGIN_FFMPEG_ID)); + vis |= 1 << PLUGIN_FFMPEG_ID; for( int i=0; isize(); ++i ) { PluginServer *plugin = MWindow::plugindb->get(i); if( !plugin->audio && !plugin->video ) continue; @@ -1743,16 +1786,11 @@ void AddPluginsMenu::create_objects() vis |= msk; char parent[BCTEXTLEN]; strcpy(parent, plugin->path); - char *cp = strrchr(parent, '/'); - if( !cp ) continue; - *cp = 0; char *bp = strrchr(parent, '/'); + if( bp ) { *bp = 0; bp = strrchr(parent, '/'); } if( !bp ) bp = parent; else ++bp; - if( !strcmp(bp, "ladspa") ) - gui->plugin_visibility &= ~(1 << idx); add_item(new AddPluginItem(this, bp, idx)); } - } AddPluginItem::AddPluginItem(AddPluginsMenu *menu, char const *text, int idx) @@ -1760,7 +1798,7 @@ AddPluginItem::AddPluginItem(AddPluginsMenu *menu, char const *text, int idx) { this->menu = menu; this->idx = idx; - uint32_t msk = 1 << idx, vis = menu->gui->plugin_visibility; + uint64_t msk = (uint64_t)1 << idx, vis = menu->gui->plugin_visibility; int chk = (msk & vis) ? 1 : 0; set_checked(chk); } @@ -1769,10 +1807,11 @@ int AddPluginItem::handle_event() { int chk = get_checked() ^ 1; set_checked(chk); - uint32_t msk = 1 << idx, vis = menu->gui->plugin_visibility; + uint64_t msk = (uint64_t)1 << idx, vis = menu->gui->plugin_visibility; menu->gui->plugin_visibility = chk ? vis | msk : vis & ~msk; menu->gui->update_effects(); menu->gui->update_assets(); + menu->gui->save_defaults(menu->mwindow->defaults); return 1; } diff --git a/cinelerra-5.0/cinelerra/awindowgui.h b/cinelerra-5.0/cinelerra/awindowgui.h index d925572a..8958fbf7 100644 --- a/cinelerra-5.0/cinelerra/awindowgui.h +++ b/cinelerra-5.0/cinelerra/awindowgui.h @@ -154,6 +154,8 @@ public: PluginServer* selected_plugin(); AssetPicon* selected_folder(); bool protected_pixmap(BC_Pixmap *pixmap); + int save_defaults(BC_Hash *defaults); + int load_defaults(BC_Hash *defaults); MWindow *mwindow; AWindow *awindow; @@ -161,7 +163,6 @@ public: AWindowAssets *asset_list; AWindowFolders *folder_list; AWindowDivider *divider; - uint32_t plugin_visibility; // Store data to speed up responses // Persistant data for listboxes @@ -179,6 +180,7 @@ public: const char *asset_titles[ASSET_COLUMNS]; + BC_Hash *defaults; // Persistent icons BC_Pixmap *folder_icon; BC_Pixmap *file_icon; @@ -189,6 +191,8 @@ public: BC_Pixmap *vtransition_icon; VFrame *vtransition_vframe; BC_Pixmap *aeffect_icon; VFrame *aeffect_vframe; BC_Pixmap *ladspa_icon; VFrame *ladspa_vframe; + BC_Pixmap *ff_aud_icon; VFrame *ff_aud_vframe; + BC_Pixmap *ff_vid_icon; VFrame *ff_vid_vframe; BC_Pixmap *veffect_icon; VFrame *veffect_vframe; NewFolderThread *newfolder_thread; @@ -200,6 +204,7 @@ public: // Temporary for reading picons from files VFrame *temp_picon; + int64_t plugin_visibility; AWindowRemovePlugin *remove_plugin; private: void update_folder_list(); diff --git a/cinelerra-5.0/cinelerra/data/ff_audio.png b/cinelerra-5.0/cinelerra/data/ff_audio.png new file mode 100644 index 0000000000000000000000000000000000000000..c62e40735006bdff4d47615a32a9b3c1200975e3 GIT binary patch literal 2634 zcmV-Q3bpl#P)j)edK02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{012{5L_t(&-qo5xY+P3rhQD*) zn;Cm1wnLIOP247JlQwCZs7fqVEV?NR1RGkZo2)@yvH^)jVZ|0i8wrre28w7UR8<00 zgo;22C{#k7q6%Usg{o=PI(6bWwiCzp%)EP8+e7q$Q-ARblJIUl#KL_1t9`-R(bzYk3XIp=iQI@U?d^UESx$p&letFIb-^yftySnKNI|Ob_c77>&S~}ihOTYV?!Nnq|Lg)bLCj|uX;@ToWUv-A zTZcp;*~Dlm-RQpwr0TcAcblQv8dltiG+&h=o`?+=n4O2or?+R*$G?KTyS4$O%7Lc; zoatMX3J@i5?ep6Mv48hAKn!!N4rWAJq>KT{`q9gvSK9Ax&z4h1HgM8bBLZLqB#D89 zHaP;KAie6;;*&*W%RqEUhUDjKAR~E5B91gYh+Z{WLuy?Zyl4Bz-q25z>{5{teH3Uo zn+Ji^U8pwj+U!-he69anJ%!_khIm`}^j=c>A~gqQ5J=4dsmjX@h<@S_)NB94@|(X> zXLCOgpL1~&spuC~X*Ko8=9TUf1F0;(2~Y!i5fB?9VupJ`sv~mt7w)~09oK&c6Jxj0 zWR(s1S)3P;)X^aaB7llRXH0ct3=!Ez#X59v1Y(0~ICM=azzd!RNj`G85LnzvF{O*c z+b}zC28ez;uc@QK0Evtdug5o7lc3qX!SOW`>`il!4oK!B5`f5Hf^4^cOg$105;Da5 zGCWEWnqTRUBmu3th)B+nPzB788)cP1o_!k5ezQV3hMQ`f>{>dmlGLT|qQSU|v@_1WZss2X3&%$B6d)Ul#bPJVHl ziuiTdyZbgva2W_`e;?5-q?YgO#`sKdxjB0kF36W`EF+@ z;;V_2QYNlyVXb_fTRZ=Lm+!oIi=V!Bi?5z;@x5=10d-W9{O3{$GkX9c0Z5cuGu;Xx zEs#31S9)BYw}XoKp;pm5)JA>8Mvc$&VuQ8cys^remzH_`%~b%dECgMcqH55<5pi?8 z4^GXKK6McZWdHr)Qe`aiw>`5ysE8kGP_NgcOtBFUO6en7$q`k{4}ZSMnU@#&*QLmj z5-MyBEptROaTP#nJ}R|HMwp^F7o@^55ZItImXipDD1A_TA`?@O3^V%%R0U^@HoZUK6hh#iulp7J|G?Mi;;%u z8(N2^77mEZBntIwZIC0T7+8?JYW2?!MMSC^<+IP+!`W{?Tv6q!HgetZ%~kD}=bH&H zN%8{G2c(EdAbMH?A^z6dXU|*bDmwn7<3NHUh-k%#rvqxx-8(jNv(!p_iHl>3L>+ue09R!~?UgLaO9zt!6!nRekf+k~(OLTAPc3 z6d=i7>(l(jnQb-$gDvz z{`w3ML{dK_`D0Ap0Pow^>RK8wcFuHF@=hh`$*1_#HU)(5R=p(p|6ng_VjWE zKX!to7-NuJcBB;~4Qj!q@Ry%?fG<6{*C&AR*pYGGxv;!xA3-%APmJJZ6U}dwMnhJb z?_wC^fv78gZ=YML0J7UvbYn0kXtl^Ov1-8NYpu~52k#x{!2U5%;rZtt8-l~+ z4pAlQBVp*$h$Eq^Q%s4G6ml~C++qdMcl(=^x6-3>D;jOGMfEef?#a*YmbQ4Bf_=edDR3vQ-%yUo0hKWyo4|{NR1#JpbHD4o>di zg`ZsD!@1S|6fI4Trmt`1qA`g!#>^J`w%*3(_3iC$CyC+fUpdMP-#Wz;Q+ohtjYd2x zYb{rg1(Kc6@N(E@uAFHGdMh9D3$IB3lU6ZBngpdBujK&4Zl(^d^<5WIU3up72e^N7 z2fzNqEGLgmKstfi7TTN3N#e9tufyua8Mx2d5Q(>A8E!4Z{Ebm=bZW?ml43J1 ztl!11`I}f-V$Zr#pLaLG(?DZSs|R2U3Rx}IH1q3Pii#h($07*qoM6N<$f~g+~W&i*H literal 0 HcmV?d00001 diff --git a/cinelerra-5.0/cinelerra/data/ff_audio_png.h b/cinelerra-5.0/cinelerra/data/ff_audio_png.h new file mode 100644 index 00000000..92b0801c --- /dev/null +++ b/cinelerra-5.0/cinelerra/data/ff_audio_png.h @@ -0,0 +1,174 @@ +#ifndef FF_AUDIO_PNG_H +#define FF_AUDIO_PNG_H + +static unsigned char ff_audio_png[] = +{ + 0x00, 0x00, 0x0a, 0x4a, + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x3f, 0x88, + 0xb1, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, + 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, + 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xdf, 0x0a, 0x1a, 0x00, 0x24, 0x35, 0xfd, 0xf3, 0x8e, 0x85, 0x00, 0x00, 0x00, 0x19, 0x74, + 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0x0e, 0x17, + 0x00, 0x00, 0x09, 0xb2, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xd5, 0x9a, 0x41, 0x6c, 0x5c, 0x57, + 0x15, 0x86, 0xbf, 0x73, 0xdf, 0x9b, 0x19, 0x7b, 0x26, 0xb6, 0x43, 0x92, 0x36, 0x4d, 0xdc, 0x26, + 0x6d, 0x93, 0x36, 0x69, 0x9a, 0xa8, 0x4a, 0x2c, 0x55, 0x2c, 0xba, 0x29, 0x0b, 0x04, 0x1b, 0x5a, + 0xa9, 0x9b, 0xac, 0x41, 0x5d, 0xb2, 0x01, 0x89, 0x45, 0x61, 0xc5, 0x16, 0x44, 0x1b, 0x09, 0x90, + 0xc8, 0x06, 0x8a, 0x68, 0x25, 0x54, 0x55, 0x02, 0x54, 0x84, 0x8a, 0x40, 0x08, 0x28, 0x54, 0x42, + 0x9d, 0xa2, 0x0a, 0x62, 0x27, 0x85, 0xaa, 0x69, 0xd4, 0x3a, 0x75, 0xe2, 0x38, 0xb6, 0x13, 0xc7, + 0xf6, 0xcc, 0xbc, 0x7b, 0x58, 0xdc, 0x7b, 0xdf, 0xbb, 0xf3, 0xe6, 0x8d, 0x1d, 0xbb, 0x05, 0x85, + 0x91, 0x46, 0xf3, 0xe6, 0xdd, 0xe7, 0x79, 0xe7, 0x3f, 0xe7, 0xfc, 0xe7, 0xfc, 0xe7, 0x3e, 0xcb, + 0xe9, 0xd3, 0xa7, 0x75, 0x7d, 0x7d, 0x1d, 0x91, 0x04, 0x05, 0x94, 0xff, 0x83, 0x97, 0x82, 0x08, + 0x18, 0x51, 0xac, 0xb5, 0x34, 0x1a, 0x0d, 0xd2, 0xd5, 0xd5, 0x55, 0x3a, 0xdd, 0x0c, 0xe8, 0x50, + 0x4f, 0x7a, 0xa4, 0x26, 0x03, 0xd5, 0x3b, 0x1c, 0x87, 0xa1, 0x9b, 0xa5, 0x74, 0x6d, 0x82, 0x31, + 0x0e, 0x4c, 0x2a, 0x62, 0x68, 0xd6, 0x56, 0x79, 0xe2, 0xc8, 0x1c, 0xa7, 0x8e, 0x74, 0xd9, 0xb9, + 0x6b, 0x94, 0x8c, 0xf4, 0x8e, 0x05, 0x21, 0x02, 0x74, 0x56, 0x79, 0xff, 0x52, 0x8f, 0x3f, 0x9e, + 0x1b, 0xe7, 0xdd, 0x8f, 0xf7, 0x60, 0x24, 0x21, 0xcd, 0x2c, 0x9c, 0x3a, 0x30, 0xcf, 0x17, 0x1e, + 0x5f, 0xe4, 0xe8, 0xe1, 0x04, 0x46, 0x0d, 0x90, 0xdd, 0xd9, 0x49, 0x66, 0x3b, 0x3c, 0xbc, 0x6f, + 0x95, 0x7a, 0xda, 0x65, 0xe1, 0xc6, 0x28, 0x8b, 0xdd, 0x06, 0xa9, 0xb5, 0x70, 0xe2, 0xe0, 0x02, + 0xf7, 0x4f, 0xae, 0x83, 0x18, 0xb8, 0xbe, 0x76, 0x07, 0x27, 0x95, 0x80, 0x5a, 0x48, 0x0d, 0xcd, + 0x31, 0xcb, 0xf1, 0x07, 0x7b, 0xfc, 0xe9, 0x9f, 0x37, 0xb8, 0x36, 0xb7, 0x9b, 0xd4, 0xaa, 0xd0, + 0x6c, 0x75, 0xc1, 0x2e, 0xc3, 0xad, 0x55, 0xe8, 0x28, 0x48, 0x41, 0xaa, 0xf0, 0xf7, 0x31, 0xd1, + 0xfa, 0xce, 0x69, 0xf5, 0xfd, 0x86, 0xae, 0x6d, 0xd1, 0xee, 0xbe, 0xfb, 0x8a, 0xff, 0xec, 0x02, + 0x36, 0x41, 0xcc, 0x67, 0x18, 0x69, 0x58, 0x54, 0x71, 0x64, 0xb0, 0x16, 0x34, 0x5b, 0x87, 0x44, + 0x21, 0xd9, 0xc4, 0x68, 0x29, 0xdd, 0xe8, 0xbf, 0x09, 0xa4, 0xea, 0xb7, 0xc2, 0x77, 0x9b, 0xa1, + 0xd9, 0x1a, 0x56, 0xdc, 0x89, 0x34, 0x5f, 0x95, 0x21, 0x9e, 0x88, 0x0d, 0x16, 0x98, 0x9d, 0x87, + 0xc9, 0xa7, 0xb7, 0x67, 0xd3, 0xc7, 0xbf, 0x82, 0xbd, 0xbb, 0xb6, 0x01, 0xa4, 0xca, 0x81, 0xa6, + 0xff, 0x9c, 0xe9, 0x5b, 0x94, 0x0a, 0x10, 0x25, 0x70, 0xed, 0xf3, 0xdb, 0x03, 0xb1, 0x7f, 0xf7, + 0x36, 0x40, 0x0c, 0x73, 0xac, 0x0e, 0x66, 0x44, 0x5a, 0xa4, 0x8c, 0x01, 0xc9, 0xfa, 0xd1, 0xcb, + 0xa0, 0x57, 0xda, 0xef, 0x6e, 0xcf, 0x96, 0x53, 0x47, 0x36, 0x70, 0xd2, 0x56, 0x23, 0x02, 0x60, + 0x04, 0x24, 0x89, 0x81, 0x84, 0x36, 0x39, 0x02, 0xa2, 0x20, 0xbd, 0xea, 0xd4, 0xe2, 0x93, 0x45, + 0x64, 0xcb, 0x40, 0x74, 0x48, 0x86, 0xe4, 0xe7, 0x6b, 0x20, 0x23, 0x79, 0x48, 0x22, 0x8e, 0x34, + 0x3d, 0x88, 0x5e, 0x35, 0x59, 0x43, 0x6a, 0x5d, 0x18, 0xbc, 0x67, 0xfb, 0xc7, 0xde, 0xd0, 0x4f, + 0x93, 0xec, 0x52, 0x91, 0x11, 0x7d, 0x14, 0x68, 0x38, 0x9b, 0x07, 0x81, 0xd4, 0x5d, 0xa8, 0x36, + 0xf0, 0xda, 0xec, 0x55, 0xb8, 0x7c, 0xad, 0xff, 0x5c, 0x3d, 0x85, 0xe3, 0x87, 0x86, 0x78, 0x5b, + 0xf8, 0xf4, 0x5e, 0x52, 0xfa, 0x22, 0x35, 0x07, 0x66, 0x10, 0x48, 0xcd, 0x01, 0xa9, 0xca, 0xcb, + 0x0d, 0x88, 0x7e, 0xe2, 0x10, 0xd4, 0x6b, 0xff, 0xc3, 0xf2, 0x9b, 0xbf, 0x52, 0x67, 0x73, 0x3f, + 0x10, 0x9f, 0x73, 0x71, 0x13, 0xa9, 0xe8, 0x17, 0x55, 0x69, 0x35, 0xf5, 0xc8, 0xe6, 0x95, 0xee, + 0x13, 0x03, 0xa9, 0x2c, 0xbf, 0x09, 0x50, 0x03, 0x7a, 0x11, 0x10, 0x1b, 0x22, 0x62, 0x86, 0x7b, + 0x41, 0xaa, 0x23, 0x72, 0xf6, 0x17, 0xee, 0xbd, 0x91, 0x1d, 0xd7, 0x7f, 0x07, 0x13, 0x63, 0xb7, + 0xd1, 0x64, 0x95, 0x0d, 0xf9, 0x59, 0x9c, 0x17, 0x90, 0xd4, 0xd1, 0x21, 0x07, 0x22, 0x80, 0x8a, + 0x43, 0x67, 0x4c, 0x75, 0x63, 0x0c, 0x11, 0xd9, 0x46, 0xc5, 0x3a, 0x74, 0x6f, 0x04, 0x62, 0x83, + 0x6a, 0x38, 0x74, 0x4d, 0x2a, 0xc0, 0x0b, 0x9e, 0x06, 0x49, 0x3e, 0x72, 0xb8, 0x10, 0x58, 0xdc, + 0x49, 0x31, 0xa5, 0x8b, 0xc3, 0xdb, 0x30, 0x3b, 0x6f, 0x06, 0x88, 0x7e, 0x3b, 0xaf, 0xa9, 0xa3, + 0xc1, 0x00, 0x89, 0x8c, 0x11, 0xaf, 0xc7, 0x37, 0x58, 0x93, 0xa0, 0xd9, 0xbd, 0xc1, 0xf1, 0x35, + 0x12, 0xec, 0x4d, 0x73, 0x90, 0x0e, 0x48, 0xe6, 0x23, 0x12, 0x80, 0xc8, 0x60, 0x82, 0x6c, 0xb7, + 0x7f, 0x4c, 0x3d, 0x12, 0x0f, 0x12, 0x32, 0xc4, 0xfb, 0x32, 0x3c, 0x4a, 0x12, 0x9a, 0x5f, 0xe9, + 0x8f, 0x24, 0x01, 0xad, 0xb9, 0x88, 0x48, 0xce, 0x91, 0x50, 0x05, 0xcc, 0x90, 0x1b, 0x65, 0x95, + 0x40, 0x9e, 0x7d, 0x1a, 0xce, 0x7e, 0xb3, 0x42, 0x39, 0x86, 0x9b, 0x6a, 0x9c, 0xec, 0x5a, 0x3a, + 0xae, 0x92, 0xd4, 0xa5, 0xef, 0xa2, 0xc1, 0xb8, 0x8a, 0xb4, 0x33, 0x2e, 0x2a, 0x36, 0xae, 0x5a, + 0xd6, 0x2f, 0x94, 0x23, 0x12, 0x75, 0xd7, 0xf6, 0xcc, 0xb0, 0x8a, 0xa5, 0x43, 0xda, 0x72, 0xd9, + 0x21, 0x43, 0x8c, 0xdd, 0xf0, 0xd8, 0xff, 0x7e, 0x55, 0xd5, 0x92, 0x04, 0x34, 0xf5, 0xd9, 0xe4, + 0x81, 0xa8, 0x1a, 0x5f, 0xca, 0xcc, 0x96, 0xa4, 0xc9, 0xd4, 0xb1, 0xa2, 0x51, 0x4e, 0x7e, 0x71, + 0x9b, 0x8a, 0xf8, 0x75, 0xd8, 0xbb, 0xfb, 0x36, 0x4b, 0x70, 0x19, 0x08, 0x69, 0x7f, 0x1f, 0xd1, + 0x2c, 0xa4, 0x96, 0xef, 0xec, 0xc6, 0xf8, 0x4c, 0x70, 0xb9, 0x39, 0x7b, 0x15, 0x2e, 0xcf, 0xf7, + 0xfa, 0x7e, 0xbb, 0x96, 0xc2, 0x89, 0xc3, 0x29, 0x18, 0xa1, 0x7d, 0xde, 0xfa, 0xf1, 0x78, 0x8b, + 0x8a, 0xf8, 0x2e, 0xd8, 0xbb, 0x27, 0x8d, 0x52, 0x51, 0x8b, 0xd4, 0xec, 0x3b, 0x8e, 0x7c, 0xac, + 0xd6, 0x7f, 0x49, 0x41, 0xe3, 0xd4, 0x12, 0xb0, 0x19, 0xa8, 0xfa, 0x96, 0x2f, 0xa9, 0x27, 0xbe, + 0x78, 0xce, 0x08, 0xed, 0xf3, 0xbd, 0xbc, 0x5e, 0x87, 0xd7, 0xf1, 0x43, 0x86, 0x46, 0xa3, 0xe9, + 0xa2, 0x35, 0xb3, 0xb6, 0x2d, 0x20, 0xa7, 0x8e, 0xa6, 0x5e, 0xf8, 0x05, 0x6e, 0xda, 0x22, 0x97, + 0xc5, 0x73, 0x4a, 0xca, 0x59, 0x62, 0x3d, 0x05, 0xea, 0xbe, 0xfc, 0x46, 0x32, 0xde, 0x5a, 0xbc, + 0xf1, 0x23, 0xfe, 0x5d, 0xf3, 0xf3, 0xb1, 0x01, 0x11, 0xda, 0x33, 0x2b, 0x15, 0x69, 0x55, 0xf7, + 0x46, 0x04, 0x20, 0xdb, 0x50, 0xc4, 0x8f, 0xd4, 0xfb, 0x81, 0x54, 0x0d, 0x1a, 0x3e, 0x5a, 0xcb, + 0x37, 0x2d, 0x7f, 0x7e, 0xbb, 0xcb, 0x03, 0x93, 0x29, 0xc7, 0x0e, 0xd7, 0x41, 0x1a, 0xa8, 0x26, + 0x58, 0xab, 0x48, 0x9e, 0x5a, 0x56, 0x50, 0x42, 0xa7, 0xac, 0x47, 0x7c, 0x71, 0xde, 0x69, 0x4f, + 0xdf, 0xa8, 0x20, 0x7a, 0xc3, 0x5f, 0x0b, 0xed, 0x99, 0xde, 0xa0, 0x22, 0x7e, 0xf9, 0x6e, 0x67, + 0x28, 0xe2, 0xab, 0x89, 0x94, 0x52, 0x26, 0xae, 0x6a, 0x61, 0xad, 0x7c, 0x9d, 0x5b, 0x3b, 0xff, + 0x7e, 0x97, 0xef, 0xbc, 0x78, 0x8b, 0x9f, 0xbe, 0x76, 0x8b, 0xaf, 0x9e, 0x6e, 0xf1, 0xbd, 0x6f, + 0x8c, 0x01, 0x75, 0x54, 0x93, 0xfc, 0xe7, 0x52, 0x09, 0x33, 0x7b, 0x00, 0x22, 0x01, 0x48, 0x94, + 0x5a, 0x33, 0xdd, 0x0a, 0x20, 0x2d, 0x90, 0x3a, 0xb3, 0x57, 0x7a, 0x5c, 0x9e, 0xb7, 0x83, 0x8a, + 0xf8, 0xa1, 0x56, 0xd1, 0x3b, 0xd4, 0x46, 0x7d, 0xc4, 0x46, 0x8d, 0xcf, 0xf3, 0x62, 0x83, 0xb5, + 0xdf, 0xbc, 0xb1, 0xca, 0x99, 0x97, 0x96, 0x79, 0xfd, 0xcd, 0x55, 0x00, 0xae, 0x2c, 0x04, 0x5d, + 0x98, 0xa2, 0x6a, 0xd0, 0xc0, 0x11, 0x71, 0x73, 0xbc, 0x0f, 0x4e, 0xcd, 0x93, 0x3e, 0x75, 0x11, + 0x09, 0x64, 0xff, 0xfd, 0xe1, 0x52, 0x65, 0x2c, 0xf2, 0xb7, 0x3d, 0xb3, 0x3e, 0xa8, 0x88, 0x1f, + 0x6a, 0x50, 0xaf, 0xd7, 0xa3, 0x4c, 0xb1, 0x11, 0x0f, 0x4a, 0xe9, 0x23, 0x5a, 0xc9, 0x11, 0x55, + 0xcb, 0x0f, 0x7f, 0xbe, 0xc8, 0x99, 0x97, 0x17, 0xf9, 0xd7, 0xa5, 0xc8, 0x91, 0x12, 0x2a, 0x6c, + 0x0d, 0x2d, 0x73, 0x44, 0x33, 0x71, 0x15, 0x40, 0x6a, 0x3e, 0x2a, 0xb5, 0x48, 0x46, 0x98, 0xa2, + 0x72, 0x48, 0x09, 0x08, 0x86, 0xf6, 0x4c, 0xa7, 0x82, 0x3f, 0x4d, 0xcf, 0xb9, 0x7c, 0x47, 0x6d, + 0x08, 0x0f, 0xca, 0x6b, 0x0e, 0xc8, 0x87, 0x73, 0x3d, 0xce, 0xbc, 0xb4, 0xc0, 0x99, 0x97, 0xae, + 0xd1, 0xed, 0x55, 0xd4, 0x62, 0x71, 0x40, 0xac, 0x4d, 0x3c, 0xbf, 0x21, 0x45, 0x43, 0x6a, 0x19, + 0x5f, 0x7e, 0x93, 0x28, 0x22, 0x9e, 0x6c, 0x12, 0xe7, 0x6d, 0x94, 0xe7, 0x46, 0x68, 0x4f, 0x0f, + 0x46, 0xe4, 0xec, 0xab, 0xd7, 0x39, 0xfb, 0xea, 0xf5, 0x8d, 0x15, 0xf1, 0x5f, 0x4e, 0x30, 0x31, + 0x66, 0xf2, 0x82, 0xb2, 0x7c, 0xd3, 0x82, 0x1a, 0xc6, 0x77, 0x24, 0x7c, 0xed, 0xbb, 0x1f, 0xf1, + 0xca, 0x6f, 0x17, 0x87, 0xfc, 0xb5, 0x71, 0x40, 0x4c, 0x0a, 0x48, 0x04, 0x24, 0x70, 0x44, 0x83, + 0x34, 0xae, 0x79, 0x31, 0x66, 0xfa, 0xc5, 0x5b, 0xdf, 0xa0, 0x55, 0x78, 0xb5, 0x3d, 0xbd, 0xba, + 0x75, 0x45, 0x7c, 0x5f, 0x83, 0x89, 0xf1, 0x7a, 0xfe, 0x5b, 0x2f, 0xfe, 0x72, 0x81, 0x1f, 0xbd, + 0x72, 0x95, 0x5d, 0x13, 0x09, 0xaf, 0xfd, 0xe0, 0xf0, 0x06, 0x20, 0x22, 0x09, 0xaf, 0xa6, 0xa8, + 0x07, 0x05, 0x10, 0x8d, 0x34, 0x7e, 0x2d, 0xd2, 0x5d, 0x25, 0xa1, 0xa7, 0xfd, 0x12, 0x63, 0xf6, + 0x6a, 0x97, 0xcb, 0xf3, 0xdd, 0xad, 0x0b, 0xc9, 0x63, 0xad, 0x68, 0xa6, 0x53, 0xa6, 0xdf, 0x5b, + 0xe7, 0xcd, 0x77, 0x56, 0xd8, 0x31, 0x1a, 0xf2, 0x7f, 0x93, 0x5d, 0x6c, 0x9f, 0x31, 0x6a, 0xb5, + 0xa8, 0x5a, 0xa1, 0xa8, 0xa8, 0x4a, 0xd1, 0x31, 0x49, 0xcb, 0x3a, 0xbe, 0x34, 0xf0, 0x38, 0xc5, + 0xd9, 0x3e, 0x77, 0x63, 0x7b, 0x8a, 0xf8, 0xd1, 0xb1, 0x3e, 0x20, 0x1d, 0xef, 0x8b, 0x91, 0x86, + 0xe9, 0x1b, 0x5a, 0x87, 0xa6, 0x16, 0x0e, 0x88, 0xcb, 0x24, 0x0a, 0xf5, 0x6b, 0x6d, 0x90, 0x23, + 0xa6, 0x18, 0x58, 0x90, 0xbc, 0x6a, 0xf5, 0xcf, 0x0e, 0x45, 0x44, 0xaa, 0x1a, 0xe5, 0xb3, 0xcf, + 0xdc, 0xc3, 0xd9, 0x6f, 0x3f, 0x5c, 0x51, 0xe5, 0xaa, 0x36, 0x72, 0xdd, 0xf1, 0xcd, 0x55, 0xed, + 0x97, 0xe7, 0x9b, 0x09, 0x2f, 0x49, 0xf2, 0x02, 0xd1, 0x07, 0xa4, 0x88, 0x48, 0x20, 0x7a, 0x5a, + 0x02, 0x21, 0xfe, 0xd6, 0xda, 0x67, 0xcf, 0x5b, 0xe7, 0x2a, 0x3a, 0xfe, 0xa3, 0xe3, 0x40, 0x82, + 0x22, 0x88, 0x68, 0xc5, 0x88, 0xa7, 0x03, 0x6a, 0xd0, 0xdd, 0x3b, 0x36, 0x72, 0xb3, 0xd4, 0x4a, + 0x7c, 0x89, 0x8e, 0x38, 0xa2, 0xa1, 0x8f, 0xa8, 0x14, 0xbd, 0x44, 0xd2, 0x88, 0xe0, 0x5e, 0xda, + 0x07, 0x72, 0xa1, 0x88, 0xaf, 0xf7, 0xed, 0x73, 0x37, 0x07, 0x81, 0x1c, 0xdf, 0xe9, 0x79, 0x66, + 0x7c, 0xaf, 0xb3, 0xde, 0xd8, 0xc4, 0x03, 0xb3, 0xae, 0x42, 0xaa, 0xe4, 0x6b, 0xad, 0x66, 0x3d, + 0x8a, 0x55, 0x7d, 0xf3, 0xd4, 0x92, 0x3a, 0x68, 0x8a, 0x5a, 0x9b, 0x8b, 0x81, 0x14, 0x20, 0xd3, + 0x30, 0xd3, 0xfb, 0x99, 0x04, 0x53, 0xf4, 0x0f, 0x1f, 0x82, 0xcc, 0x0a, 0x62, 0x52, 0x12, 0xb1, + 0xa0, 0x3d, 0x3e, 0x9a, 0x5b, 0xe7, 0xe3, 0xf9, 0xf5, 0x92, 0x22, 0x16, 0x4e, 0x3c, 0xbc, 0x13, + 0xab, 0x09, 0x56, 0x13, 0x92, 0xd4, 0x80, 0xed, 0x3a, 0xb7, 0x25, 0x75, 0xb0, 0xbd, 0xc2, 0xeb, + 0x62, 0x40, 0xbb, 0x80, 0xd0, 0x68, 0x38, 0x82, 0xaf, 0x75, 0x2c, 0x98, 0xfa, 0xe6, 0xa9, 0x45, + 0xe2, 0x1d, 0xa5, 0x79, 0x92, 0x3a, 0x66, 0x85, 0x88, 0x48, 0x12, 0x6d, 0x0b, 0x49, 0xe4, 0x01, + 0x97, 0x7a, 0x22, 0x89, 0x07, 0xa7, 0xbc, 0x35, 0x3d, 0x18, 0x8d, 0xe3, 0x0f, 0x8d, 0xd1, 0x68, + 0xd4, 0xc8, 0xac, 0x41, 0x31, 0xfe, 0xfa, 0x0c, 0x10, 0x44, 0x52, 0x3f, 0x24, 0xf9, 0x63, 0x4c, + 0xde, 0x00, 0xef, 0xdb, 0xd7, 0xe4, 0xfe, 0xfd, 0xa3, 0xec, 0x1c, 0xaf, 0xf9, 0xb5, 0xdb, 0xe1, + 0x48, 0x31, 0x85, 0x8a, 0x94, 0xfb, 0x48, 0xce, 0x91, 0xc4, 0xa7, 0x5a, 0xd1, 0x10, 0x93, 0xd4, + 0x20, 0xa1, 0xaf, 0x90, 0xf2, 0xf6, 0xf4, 0x72, 0x05, 0x3f, 0x76, 0x82, 0xa4, 0x18, 0x63, 0x90, + 0x5c, 0x76, 0xa4, 0x15, 0x24, 0x0d, 0x6a, 0xc1, 0xa5, 0xf0, 0x97, 0x9f, 0x79, 0x80, 0x2f, 0x3d, + 0xb9, 0xd7, 0x27, 0x80, 0xf0, 0xd8, 0x91, 0x71, 0xde, 0xb9, 0xb0, 0xbc, 0x69, 0x1f, 0x41, 0x35, + 0x1f, 0x4f, 0x8c, 0xe0, 0x66, 0x13, 0xcd, 0x6f, 0x94, 0x46, 0x43, 0x56, 0x9a, 0xef, 0x62, 0x18, + 0xe3, 0x81, 0xa8, 0x2b, 0x7f, 0x6f, 0x9f, 0x5b, 0xaa, 0x00, 0xb2, 0xdb, 0x55, 0x74, 0x63, 0x30, + 0x26, 0x68, 0xb5, 0xc8, 0x31, 0xb1, 0x6a, 0xc0, 0xe4, 0x6b, 0xad, 0xd1, 0x1a, 0x07, 0xef, 0x1d, + 0xe7, 0xc0, 0xfe, 0x31, 0x50, 0xe1, 0xf9, 0xe7, 0x1e, 0xe3, 0xa9, 0xcf, 0xed, 0x1b, 0x82, 0xc3, + 0xe4, 0x0e, 0x51, 0x25, 0xea, 0x23, 0x61, 0xe8, 0xd2, 0x88, 0x23, 0xa1, 0xab, 0x53, 0x4c, 0x89, + 0x91, 0x14, 0x72, 0x32, 0xfd, 0xdc, 0x62, 0x05, 0xd1, 0x77, 0xfb, 0x9b, 0x94, 0xb7, 0xd2, 0xa3, + 0x72, 0x2b, 0x1a, 0x6d, 0xb2, 0x45, 0xf5, 0x33, 0xba, 0xee, 0xc9, 0xcf, 0xee, 0xe3, 0xe0, 0xe4, + 0x18, 0x07, 0xf6, 0xb7, 0xf8, 0xfe, 0xcf, 0xfe, 0x5d, 0x9a, 0xe2, 0x8b, 0xa7, 0x3c, 0xaa, 0x45, + 0x0d, 0x8c, 0x80, 0xf8, 0x2a, 0x15, 0x6f, 0x42, 0xa8, 0x0c, 0xdd, 0xc6, 0x99, 0x7d, 0xe3, 0xa9, + 0xa2, 0xb2, 0x55, 0x19, 0x1b, 0x5f, 0x2c, 0x25, 0x63, 0x65, 0xc8, 0x5a, 0x74, 0xfc, 0xe0, 0x7d, + 0xe3, 0x3c, 0xff, 0xdc, 0x49, 0x0e, 0x4e, 0xee, 0xe0, 0x85, 0x9f, 0x5c, 0xe0, 0xc3, 0xb9, 0xd5, + 0xfe, 0x14, 0x2d, 0x4d, 0x8e, 0xa6, 0xaf, 0x6f, 0xe5, 0xa2, 0x31, 0x89, 0x36, 0xc6, 0xcc, 0x16, + 0xfb, 0xb6, 0xde, 0xc6, 0xe6, 0xf5, 0xed, 0xed, 0x6e, 0x27, 0x89, 0xe1, 0xeb, 0x5f, 0x39, 0xca, + 0x0b, 0xdf, 0x3a, 0xc5, 0x13, 0x53, 0x7b, 0x00, 0x68, 0x8d, 0x46, 0x3c, 0x2b, 0x6b, 0x2d, 0x57, + 0x8f, 0x05, 0x92, 0x9d, 0xd0, 0xf0, 0x72, 0xd8, 0x66, 0xae, 0x9c, 0x69, 0x06, 0x7a, 0x2b, 0x1f, + 0xf2, 0x0b, 0xaf, 0x48, 0xff, 0x93, 0x56, 0x31, 0x45, 0x9a, 0x04, 0xa5, 0x1c, 0xaf, 0xe5, 0x00, + 0xc3, 0x6e, 0xa6, 0x0e, 0xae, 0xf5, 0x5d, 0x17, 0x52, 0x5d, 0x79, 0xe6, 0xf3, 0x07, 0xb8, 0x7f, + 0x72, 0x07, 0xbf, 0xfe, 0xc3, 0x2c, 0x27, 0x8f, 0x4d, 0x40, 0x3a, 0x81, 0xda, 0x16, 0xda, 0x9b, + 0xcb, 0x49, 0xe2, 0xb4, 0x56, 0xaf, 0xc3, 0xea, 0xc5, 0x19, 0xb8, 0xe7, 0x71, 0x98, 0x78, 0xc0, + 0x1b, 0x9f, 0xf9, 0x96, 0x9f, 0xb9, 0x8d, 0x87, 0xdc, 0x30, 0x8b, 0xa2, 0x88, 0xda, 0x68, 0x1c, + 0xd5, 0xbc, 0x59, 0x86, 0xb7, 0x0c, 0xf1, 0xba, 0xc6, 0xe7, 0x75, 0x70, 0xa3, 0x71, 0xd8, 0x76, + 0xd4, 0xd4, 0xc9, 0x7d, 0x4c, 0x9d, 0x3c, 0xe6, 0x25, 0xfc, 0x18, 0xbd, 0x6b, 0x1f, 0xd0, 0xf9, + 0xe8, 0x1f, 0x50, 0x6b, 0x04, 0x20, 0x82, 0x66, 0x19, 0x4b, 0xef, 0xfe, 0x9d, 0xf1, 0xc6, 0x12, + 0xcd, 0x7b, 0xef, 0xa1, 0xd6, 0xc4, 0x3d, 0xaa, 0x56, 0x5f, 0xd2, 0xac, 0xfb, 0x54, 0x75, 0x4a, + 0x59, 0xad, 0xc3, 0xe8, 0xca, 0xb6, 0xbb, 0xce, 0x06, 0x25, 0x6a, 0x35, 0xd7, 0x95, 0x5a, 0xb9, + 0x01, 0xa9, 0x39, 0xed, 0xe2, 0x51, 0x47, 0x4c, 0xf1, 0x58, 0x30, 0x7c, 0x0f, 0x02, 0x3c, 0xee, + 0xd1, 0xd8, 0x84, 0xde, 0x4a, 0x97, 0x95, 0x8b, 0x17, 0x59, 0x9b, 0xbf, 0x82, 0x24, 0x87, 0x8b, + 0xe7, 0xec, 0xa2, 0x4a, 0x77, 0x69, 0x9e, 0xb5, 0x4b, 0x8b, 0xd4, 0x6d, 0x93, 0xda, 0x2e, 0x81, + 0x11, 0x75, 0xbb, 0x78, 0xbd, 0x22, 0xc3, 0x6c, 0x4f, 0xc8, 0x32, 0xd7, 0xa0, 0xb3, 0x0c, 0x7f, + 0x2c, 0x79, 0x26, 0x66, 0x99, 0x07, 0x67, 0x8b, 0xcf, 0x58, 0x66, 0x05, 0xa3, 0x4d, 0xe2, 0xdf, + 0xc6, 0x7d, 0x26, 0x49, 0x71, 0x2e, 0x49, 0xa3, 0x73, 0xfe, 0x98, 0xa8, 0x2b, 0xd0, 0x05, 0xbb, + 0xd0, 0xa1, 0x77, 0x75, 0x05, 0xbb, 0x3e, 0x82, 0x5a, 0xe3, 0x1a, 0xa2, 0xa8, 0xb2, 0xd0, 0x19, + 0xe1, 0xe6, 0x5a, 0x8d, 0x6c, 0xa5, 0x0b, 0x4b, 0xcb, 0xee, 0x0f, 0x3a, 0xe4, 0x20, 0xf0, 0xdb, + 0x5a, 0x9a, 0x81, 0xf6, 0x1c, 0x10, 0xdb, 0x73, 0xc6, 0x07, 0x50, 0xb6, 0x07, 0x99, 0x2d, 0x8e, + 0x03, 0x38, 0xb5, 0x11, 0x10, 0x53, 0x18, 0x9d, 0x78, 0xa3, 0x35, 0x29, 0xfa, 0x5b, 0xd8, 0x2e, + 0x08, 0xbb, 0xa1, 0xa4, 0x25, 0x10, 0x89, 0xb7, 0x63, 0x19, 0x6e, 0x2d, 0xc3, 0xfc, 0x8d, 0x51, + 0x6e, 0x74, 0x6a, 0xc8, 0x88, 0x92, 0x62, 0x33, 0x2e, 0xac, 0xdf, 0xc5, 0xae, 0xf9, 0x9b, 0x58, + 0x59, 0x62, 0xcf, 0xba, 0x52, 0x9f, 0x77, 0x37, 0xc1, 0xd3, 0x40, 0x63, 0x4f, 0xab, 0x07, 0x60, + 0x0b, 0x0a, 0x59, 0x2d, 0xd6, 0x34, 0xf3, 0xeb, 0x5a, 0x8a, 0x8a, 0x29, 0x80, 0x88, 0xf8, 0x68, + 0xf8, 0xb7, 0xc4, 0x9f, 0x51, 0x6a, 0x25, 0x3e, 0x6a, 0xf9, 0x5e, 0x61, 0xe2, 0x1c, 0x7b, 0x6b, + 0x05, 0xde, 0xbb, 0x3c, 0xc2, 0xdf, 0xe6, 0xee, 0xe2, 0x4a, 0xd6, 0x22, 0xb5, 0x3d, 0xd2, 0x56, + 0x6b, 0x94, 0x25, 0xee, 0xe6, 0xaf, 0x9d, 0x51, 0xa6, 0x3f, 0x58, 0xa6, 0x71, 0xa9, 0x8b, 0x88, + 0xf4, 0x17, 0x5d, 0x19, 0xfe, 0x4c, 0xb2, 0xf2, 0x41, 0xac, 0x6c, 0xb2, 0x77, 0xab, 0x54, 0xff, + 0x93, 0x9b, 0x6e, 0x50, 0xa0, 0xa3, 0x13, 0x3d, 0x15, 0x96, 0xa5, 0xc9, 0x42, 0x3a, 0x41, 0xd2, + 0x18, 0xa1, 0xd5, 0x1c, 0xe1, 0x3f, 0x89, 0x98, 0x18, 0xac, 0xd2, 0xd3, 0xb2, 0x95, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +#endif diff --git a/cinelerra-5.0/cinelerra/data/ff_video.png b/cinelerra-5.0/cinelerra/data/ff_video.png new file mode 100644 index 0000000000000000000000000000000000000000..73c231ba104945a601b8cb672ae3b262b2570886 GIT binary patch literal 2717 zcmV;O3S#w%P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{015?3L_t(&-qo7lZyZ+@$3N%J z?5@3*f5dTqG(Spcel@LwP(mZ9iV8H)rmEBws0a^;7y2LY#sd<6L?80P3j$s$A%qY} zAXHR9RB-_n$7xX1G^NfjH;Lmows&{#;o;spb7yweY21RsNTZ#dnf09SJ?DGQ_nfhu zI(16d*47Y7P(b-V*c3#-h+?g!)oPKhtgO)KWVKUMO7K8}US>fGFJzk$3~oAvLr|Ez^(m_~Sp9`0(mx zQmaCHqzm>o++Bf=f)u0*zmJJlI;Zu|8+h$L?Jhl6{AU-i31T)e)Uv4J$Y3pKwg!np zau1`W@}U1Fkh;GWzS|7VRn{J5IZ(+0K}k$)&7V`i;yuOSsA_bugc8%joEVK;5v(Rza9ZF0+Pf)LYW)_ zQIKAJXz}qpa^FC7K!oJy8z4iuOCpZ6J&0aCSwm>O)BntwAA3VTNwP~#M3gAdayIt^ zX*yS}vug9#;qr&&bIlZ{_YPQX;gj2>@k$3$UT8M{hv_%pQfG4+ zh>y9rh}6`Jy0AKW=-!#`V*{y8zX{L)dJzyCJYoi~g4BED^e^1Lo*g%T2jin3p~x!h z^0PQEAgQB64nzPIht8P#!WcZVfsD0xR|I06Y&h_m)PNT}4U)X&a4xX8lVU12hutv0 zVETyuQMRLx1_LBAM!X(h=b8k~?hTIbkzj9{gLFVL?~wpR`U7O6_2cNFxRHmK{RUzfEc0Zn~0c_6CBr!sS2(&Xr4MWNhzVuOnK zx3F#VM@+$0Af)9wqFD$nU)hcEk>Fx;{yJP<=#~Cyvwy@pn+?YuR&x*;G(9!5T|LHlT$p}+q4ygdaFf-Sw;ZNIhE}y6k-~se{8UHxn z;nq^dXZAOl+LR(U7~rVM1Fq9k=H6Z9!uxBy ze&!A@KRd}w&rI^j?iP~UVe^Plt3}od-cpsKVv<&Me5K)WigRXmX=94`@zJO`P5V@8 zr>C5mUFMyOtNh{3JAC{3DZX-Sob6Lhj0rXxA4wGI*V-UQOwq6)dDbfT4uwbR3gs)` z*v{!69jM82b%R{`D|eu@!s4Bb-@I{?zn@#?%f}`-bz%!oKQYGWSdu4?5|F|pf#_)k zg!o5m$(}Q_H5LEyF(5$^M6{;GtEfLo)@|;s!u<6PKl}AH{`&S3Uq3#@cTVnL`hb)< zqM?qc6tzUsh~Qq@2Xdi^&-XL4clv=$Pk5dgU+XNOs3snmbs18{T@wfTp07j{E?ipS z)t}GPY&DrakfPS+Vju;`^6X}!f@4ZuU1kL_DT!Fn9v@s?R1 z8n9irY)KPrukeBx&~7b925o67?0dM)fjy&sp)?Ot$GG4TNusfk6mxEIp(m1faLSpp z{oa_~KT50BAhQO=`1>?!iUJ)npPIAe@;C)-sG7lw{q(FT|9Mk z6H^lnNE=`csOIg7(^`s))4c0S%F_)5W5NnJL*ANQtO2swWpslBqUwv679KAVT}nMg zT=_@Z3C9jk^78Y$c;QPs*tLDwEx&5MAgV-lBs5(baU@iAiY_siOksRFd#i@%oBczo zqx3l4Msh>&x~kZQTM38uj`Gr1cX9Ig4h}vtMk9@@yXGy1YOw|p5TB*uA%x1nG0yxO zFBX}t&e-^7sf-XKQlt$-ni`D2!#mo%_{=U|er`8MrzaU|nVK<>7RjPK365+DqA{NV zZ)6&+^)F^>Uvj{nog;krr9E7lzsvC_xADc#ZDrGVbDigE!LzE?a`{*wnShp;!!~p2 zOf%5Cd6Qp?@3`KHi5elv2WR=U01#7zh{E{TFyH^)V};U2%e{wa5z-+f({a>}puMX( zNu1W|by&GL2iuRq_@}+`nJ@X78$9HOSrkRoM(wEP#WL(Nz>6B6uW8HIpXRG84`!6! zhwst(;B9EM0uVv7jK%YRW307Ed)IavZQQGB^(oD|PgSRs)jEtWZM*wyP@-0IU8%JL zNX=;%w>n~q*Mi}D5a4l*#wPTZyDVS4$m+s1B-vNIXBSnviwmq?x<%8rX-oujRAC#4YUIWw>y8h&Qip;aWCAYI~$3Bf~7R zl|OfeIs4viT9>+rNO=k@gWpNkzKE53%x;zXe{$2oBk%Y`Plemk=0-YB(i&oget_w(), frame->get_h(), ofmt, SWS_BICUBIC, NULL, NULL, NULL); if( !convert_ctx ) { - fprintf(stderr, "FFVideoStream::convert_picture_frame:" + fprintf(stderr, "FFVideoConvert::convert_picture_frame:" " sws_getCachedContext() failed\n"); - return 1; + return -1; } int ret = sws_scale(convert_ctx, ip->data, ip->linesize, 0, ih, opic.data, opic.linesize); if( ret < 0 ) { - ff_err(ret, "FFVideoStream::convert_picture_frame: sws_scale() failed\n"); - return 1; + ff_err(ret, "FFVideoConvert::convert_picture_frame: sws_scale() failed\n"); + return -1; } return 0; } -int FFVideoStream::convert_cmodel(VFrame *frame, +int FFVideoConvert::convert_cmodel(VFrame *frame, AVPicture *ip, PixelFormat ifmt, int iw, int ih) { // try direct transfer @@ -922,7 +921,22 @@ int FFVideoStream::convert_cmodel(VFrame *frame, return 1; } -int FFVideoStream::convert_vframe_picture(VFrame *frame, +int FFVideoConvert::transfer_cmodel(VFrame *frame, + AVFrame *ifp, PixelFormat ifmt, int iw, int ih) +{ + int ret = convert_cmodel(frame, (AVPicture *)ifp, ifmt, iw, ih); + if( ret > 0 ) { + const AVDictionary *src = av_frame_get_metadata(ifp); + AVDictionaryEntry *t = NULL; + BC_Hash *hp = frame->get_params(); + //hp->clear(); + while( (t=av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX)) ) + hp->update(t->key, t->value); + } + return ret; +} + +int FFVideoConvert::convert_vframe_picture(VFrame *frame, AVPicture *op, PixelFormat ofmt, int ow, int oh) { AVPicture opic; @@ -949,24 +963,24 @@ int FFVideoStream::convert_vframe_picture(VFrame *frame, convert_ctx = sws_getCachedContext(convert_ctx, frame->get_w(), frame->get_h(), ifmt, ow, oh, ofmt, SWS_BICUBIC, NULL, NULL, NULL); if( !convert_ctx ) { - fprintf(stderr, "FFVideoStream::convert_frame_picture:" + fprintf(stderr, "FFVideoConvert::convert_frame_picture:" " sws_getCachedContext() failed\n"); - return 1; + return -1; } int ret = sws_scale(convert_ctx, opic.data, opic.linesize, 0, frame->get_h(), op->data, op->linesize); if( ret < 0 ) { - ff_err(ret, "FFVideoStream::convert_frame_picture: sws_scale() failed\n"); - return 1; + ff_err(ret, "FFVideoConvert::convert_frame_picture: sws_scale() failed\n"); + return -1; } return 0; } -int FFVideoStream::convert_pixfmt(VFrame *frame, +int FFVideoConvert::convert_pixfmt(VFrame *frame, AVPicture *op, PixelFormat ofmt, int ow, int oh) { // try direct transfer - if( !convert_vframe_picture(frame, op, ofmt, ow, oh) ) return 0; + if( !convert_vframe_picture(frame, op, ofmt, ow, oh) ) return 1; // use indirect transfer int colormodel = frame->get_color_model(); int bits = BC_CModels::calculate_pixelsize(colormodel) * 8; @@ -976,8 +990,24 @@ int FFVideoStream::convert_pixfmt(VFrame *frame, (bits > 8 ? BC_RGB161616: BC_RGB888) ; VFrame vframe(frame->get_w(), frame->get_h(), icolor_model); vframe.transfer_from(frame); - if( convert_vframe_picture(&vframe, op, ofmt, ow, oh) ) return 1; - return 0; + if( !convert_vframe_picture(&vframe, op, ofmt, ow, oh) ) return 1; + return -1; +} + +int FFVideoConvert::transfer_pixfmt(VFrame *frame, + AVFrame *ofp, PixelFormat ofmt, int ow, int oh) +{ + int ret = convert_pixfmt(frame, (AVPicture *)ofp, ofmt, ow, oh); + if( ret > 0 ) { + BC_Hash *hp = frame->get_params(); + AVDictionary **dict = avpriv_frame_get_metadatap(ofp); + //av_dict_free(dict); + for( int i=0; isize(); ++i ) { + char *key = hp->get_key(i), *val = hp->get_value(i); + av_dict_set(dict, key, val, 0); + } + } + return ret; } void FFVideoStream::load_markers() @@ -2214,7 +2244,7 @@ int FFVideoStream::create_filter(const char *filter_spec, snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", src_ctx->width, src_ctx->height, src_ctx->pix_fmt, - st->time_base.num, st->time_base.den, + src_ctx->time_base.num, src_ctx->time_base.den, src_ctx->sample_aspect_ratio.num, src_ctx->sample_aspect_ratio.den); if( ret >= 0 ) ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", @@ -2248,7 +2278,7 @@ int FFAudioStream::create_filter(const char *filter_spec, int ret = 0; char args[BCTEXTLEN]; snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%jx", - st->time_base.num, st->time_base.den, src_ctx->sample_rate, + src_ctx->time_base.num, src_ctx->time_base.den, src_ctx->sample_rate, av_get_sample_fmt_name(src_ctx->sample_fmt), src_ctx->channel_layout); if( ret >= 0 ) ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", diff --git a/cinelerra-5.0/cinelerra/ffmpeg.h b/cinelerra-5.0/cinelerra/ffmpeg.h index 92fabfcd..68649d16 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.h +++ b/cinelerra-5.0/cinelerra/ffmpeg.h @@ -194,7 +194,32 @@ public: float *aud_bfr; }; -class FFVideoStream : public FFStream { + +class FFVideoConvert { +public: + struct SwsContext *convert_ctx; + + FFVideoConvert() { convert_ctx = 0; } + ~FFVideoConvert() { if( convert_ctx ) sws_freeContext(convert_ctx); } + + static PixelFormat color_model_to_pix_fmt(int color_model); + static int pix_fmt_to_color_model(PixelFormat pix_fmt); + + int convert_picture_vframe(VFrame *frame, + AVPicture *ip, PixelFormat ifmt, int iw, int ih); + int convert_cmodel(VFrame *frame_out, + AVPicture *ip, PixelFormat ifmt, int iw, int ih); + int transfer_cmodel(VFrame *frame_in, //defaults->metadata + AVFrame *ifp, PixelFormat ifmt, int iw, int ih); + int convert_vframe_picture(VFrame *frame, + AVPicture *op, PixelFormat ofmt, int ow, int oh); + int convert_pixfmt(VFrame *frame_in, + AVPicture *op, PixelFormat ofmt, int ow, int oh); + int transfer_pixfmt(VFrame *frame_in, //metadata->defaults + AVFrame *ofp, PixelFormat ofmt, int ow, int oh); +}; + +class FFVideoStream : public FFStream, public FFVideoConvert { public: FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx); virtual ~FFVideoStream(); @@ -217,22 +242,9 @@ public: int64_t length; float aspect_ratio; - struct SwsContext *convert_ctx; uint8_t *pkt_bfr; int pkt_bfr_sz; int64_t start_pts; - - static PixelFormat color_model_to_pix_fmt(int color_model); - static int pix_fmt_to_color_model(PixelFormat pix_fmt); - - int convert_picture_vframe(VFrame *frame, - AVPicture *ip, PixelFormat ifmt, int iw, int ih); - int convert_cmodel(VFrame *frame_out, - AVPicture *ip, PixelFormat ifmt, int iw, int ih); - int convert_vframe_picture(VFrame *frame, - AVPicture *op, PixelFormat ofmt, int ow, int oh); - int convert_pixfmt(VFrame *frame_in, - AVPicture *op, PixelFormat ofmt, int ow, int oh); }; class FFMPEG : public Thread { diff --git a/cinelerra-5.0/cinelerra/fileac3.C b/cinelerra-5.0/cinelerra/fileac3.C index a072e9c0..99ba4e5c 100644 --- a/cinelerra-5.0/cinelerra/fileac3.C +++ b/cinelerra-5.0/cinelerra/fileac3.C @@ -296,8 +296,10 @@ int FileAC3::write_samples(double **buffer, int64_t len) file->get_audio_position() : AV_NOPTS_VALUE ; int got_packet = 0; ret = avcodec_encode_audio2(avctx, &avpkt, frame, &got_packet); - if( !ret ) { - fprintf(stderr, "avcodec_encode_audio2 failed. \n%m\n"); + if( ret < 0 ) { + char errmsg[BCSTRLEN]; + av_strerror(ret, errmsg, sizeof(errmsg)); + fprintf(stderr, "avcodec_encode_audio2 failed. \n%s\n", errmsg); } } av_packet_free_side_data(&avpkt); diff --git a/cinelerra-5.0/cinelerra/mwindow.C b/cinelerra-5.0/cinelerra/mwindow.C index 4be07df6..b1216332 100644 --- a/cinelerra-5.0/cinelerra/mwindow.C +++ b/cinelerra-5.0/cinelerra/mwindow.C @@ -392,23 +392,30 @@ int MWindow::load_plugin_index(MWindow *mwindow, char *path) index_version != PLUGIN_FILE_VERSION ) ret = 1; while( !ret && !feof(fp)) { - char *sp = index_line, *plugin_path = 0, *plugin_title = 0; - if( fgets(sp, BCTEXTLEN, fp) ) { - plugin_path = PluginServer::table_quoted_field(sp); - if( plugin_exists(plugin_path) ) continue; - plugin_title = PluginServer::table_quoted_field(sp); + if( !fgets(index_line, BCTEXTLEN, fp) ) break; + if( index_line[0] == ';' ) continue; + if( index_line[0] == '#' ) continue; + int type = PLUGIN_TYPE_UNKNOWN; + char path[BCTEXTLEN], title[BCTEXTLEN]; + if( PluginServer::scan_table(index_line, type, path, title) ) continue; + PluginServer *server = 0; + switch( type ) { + case PLUGIN_TYPE_BUILTIN: + case PLUGIN_TYPE_LADSPA: + server = new PluginServer(mwindow, path, type); + break; + case PLUGIN_TYPE_FFMPEG: // skip "ff_..." + server = new_ffmpeg_server(mwindow, path+3); + break; } - if( plugin_path && plugin_title ) { + if( !server ) continue; // Create plugin server from index entry - PluginServer *new_plugin = new PluginServer(path, mwindow); - new_plugin->set_path(plugin_path); - new_plugin->set_title(plugin_title); - if( new_plugin->read_table(sp) ) { - delete new_plugin; - ret = 1; break; - } - plugindb->append(new_plugin); + server->set_title(title); + if( server->read_table(index_line) ) { + delete server; + ret = 1; break; } + plugindb->append(server); } fclose(fp); @@ -427,7 +434,7 @@ void MWindow::init_plugin_index(MWindow *mwindow, Preferences *preferences, FILE fs.set_filter( "[*.plugin][*.so]" ); int result = fs.update(plugin_path); if( result || !fs.dir_list.total ) return; - int vis_id = ++idx; + int vis_id = idx++; for( int i=0; ipath; @@ -441,30 +448,31 @@ void MWindow::init_plugin_index(MWindow *mwindow, Preferences *preferences, FILE continue; } if( plugin_exists(plugin_path) ) continue; - PluginServer *new_plugin = new PluginServer(plugin_path, mwindow); - result = new_plugin->open_plugin(1, preferences, 0, 0); + PluginServer *server = new PluginServer(mwindow, plugin_path, PLUGIN_TYPE_UNKNOWN); + result = server->open_plugin(1, preferences, 0, 0); if( !result ) { - new_plugin->write_table(fp,vis_id); - new_plugin->close_plugin(); - new_plugin->delete_this(); + server->write_table(fp,vis_id); + server->close_plugin(); + server->delete_this(); continue; } if( result != PLUGINSERVER_IS_LAD ) continue; int lad_index = 0; for(;;) { - PluginServer *new_plugin = new PluginServer(plugin_path, mwindow); - new_plugin->set_lad_index(lad_index++); - result = new_plugin->open_plugin(1, preferences, 0, 0); + PluginServer *server = new PluginServer(mwindow, plugin_path, PLUGIN_TYPE_LADSPA); + server->set_lad_index(lad_index++); + result = server->open_plugin(1, preferences, 0, 0); if( result ) break; - new_plugin->write_table(fp,vis_id); - new_plugin->close_plugin(); - new_plugin->delete_this(); + server->write_table(fp, PLUGIN_LADSPA_ID); + server->close_plugin(); + server->delete_this(); } } } int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences) { + init_ffmpeg(); if( !plugindb ) plugindb = new ArrayList; char index_path[BCTEXTLEN]; sprintf(index_path, "%s/%s", preferences->plugin_dir, PLUGIN_FILE); @@ -477,8 +485,9 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences) } fprintf(fp, "%d\n", PLUGIN_FILE_VERSION); char *plug_path = FileSystem::basepath(preferences->plugin_dir); - int dir_id = 0; + int dir_id = PLUGIN_IDS; init_plugin_index(mwindow, preferences, fp, plug_path, ".", dir_id); + init_ffmpeg_index(mwindow, preferences, fp); fclose(fp); delete [] plug_path; return load_plugin_index(mwindow, index_path); @@ -2829,8 +2838,9 @@ void MWindow::dump_plugins(FILE *fp) if( !plugindb ) return; for(int i = 0; i < plugindb->total; i++) { - fprintf(fp, "audio=%d video=%d rt=%d multi=%d" + fprintf(fp, "type=%d audio=%d video=%d rt=%d multi=%d" " synth=%d transition=%d theme=%d %s\n", + plugindb->values[i]->plugin_type, plugindb->values[i]->audio, plugindb->values[i]->video, plugindb->values[i]->realtime, @@ -2908,6 +2918,7 @@ int MWindow::save_defaults() // Pointer comparison plugin_guis->values[i]->save_defaults(); } + awindow->save_defaults(defaults); defaults->save(); return 0; diff --git a/cinelerra-5.0/cinelerra/mwindow.h b/cinelerra-5.0/cinelerra/mwindow.h index 79ef49da..88613de8 100644 --- a/cinelerra-5.0/cinelerra/mwindow.h +++ b/cinelerra-5.0/cinelerra/mwindow.h @@ -67,6 +67,7 @@ #include "playback3d.inc" #include "playbackengine.inc" #include "plugin.inc" +#include "pluginfclient.inc" #include "pluginserver.inc" #include "pluginset.inc" #include "preferences.inc" @@ -526,13 +527,13 @@ public: // Contains file descriptors for all the dlopens static ArrayList *plugindb; // Currently visible plugins + int64_t plugin_visibility; ArrayList *plugin_guis; // GUI Plugins to delete ArrayList *dead_plugins; // Keyframe editors ArrayList *keyframe_threads; - // Adjust sample position to line up with frames. int fix_timing(int64_t &samples_out, int64_t &frames_out, @@ -606,7 +607,10 @@ public: static int init_plugins(MWindow *mwindow, Preferences *preferences); static void init_plugin_index(MWindow *mwindow, Preferences *preferences, FILE *fp, const char *plug_dir, const char *plug_path, int &dir_id); + static void init_ffmpeg(); + static void init_ffmpeg_index(MWindow *mwindow, Preferences *preferences, FILE *fp); static int load_plugin_index(MWindow *mwindow, char *path); + static PluginServer* new_ffmpeg_server(MWindow *mwindow, const char *name); void init_preferences(); void init_signals(); void init_theme(); diff --git a/cinelerra-5.0/cinelerra/mwindow.inc b/cinelerra-5.0/cinelerra/mwindow.inc index 1dd39320..b1ec4d5e 100644 --- a/cinelerra-5.0/cinelerra/mwindow.inc +++ b/cinelerra-5.0/cinelerra/mwindow.inc @@ -30,7 +30,7 @@ #define PRESETS_FILE "Cinelerra_presets" #define PICTURE_FILE "Cinelerra_picture" #define PLUGIN_FILE "Cinelerra_plugins" -#define PLUGIN_FILE_VERSION 1 +#define PLUGIN_FILE_VERSION 2 // Behavior of region selections #define SELECTION_SAMPLES 0 diff --git a/cinelerra-5.0/cinelerra/pluginfclient.C b/cinelerra-5.0/cinelerra/pluginfclient.C new file mode 100644 index 00000000..4efbe2d5 --- /dev/null +++ b/cinelerra-5.0/cinelerra/pluginfclient.C @@ -0,0 +1,1152 @@ +#include +#include +#include +#include +#include +#include + +#include "bcwindowbase.h" +#include "bctitle.h" +#include "cstrdup.h" +#include "language.h" +#include "mwindow.h" +#include "pluginfclient.h" +#include "pluginserver.h" +#include "samples.h" +#include "vframe.h" +#include "filexml.h" + + +static void ff_err(int ret, const char *fmt, ...) +{ + char msg[BCTEXTLEN]; + va_list ap; + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + char errmsg[BCSTRLEN]; + av_strerror(ret, errmsg, sizeof(errmsg)); + fprintf(stderr,_("%s err: %s\n"),msg, errmsg); +} + +PluginFClientConfig::PluginFClientConfig() +{ + ffilt = 0; +} + +PluginFClientConfig::~PluginFClientConfig() +{ + delete ffilt; + remove_all_objects(); +} + +int PluginFClientConfig::equivalent(PluginFClientConfig &that) +{ + PluginFClientConfig &conf = *this; + for( int i=0; iget(tval, sizeof(tval)); + char vval[BCTEXTLEN], *vp = vopt->get(vval, sizeof(vval)); + int ret = tp && vp ? strcmp(tp, vp) : tp || vp ? 1 : 0; + if( ret ) return 0; + } + return 1; +} + +void PluginFClientConfig::copy_from(PluginFClientConfig &that) +{ + PluginFClientConfig &conf = *this; + for( int i=0; iopt->name; + int k = size(); + while( --k >= 0 && strcmp(nm, conf[k]->opt->name) ); + if( k < 0 ) continue; + PluginFClient_Opt *fopt = conf[k]; + char str[BCTEXTLEN], *sp = vp->get(str, sizeof(str)); + if( sp ) fopt->set(sp); + } +} + +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) +{ + ffilt = PluginFFilter::new_ffilter(name); + const AVOption *opt = 0; + void *obj = ffilt->filter_config(); + + const AVClass *filt_class = ffilt->filter_class(); + if( filt_class && filt_class->option ) { + PluginFClientConfig &conf = *this; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( opt->type == AV_OPT_TYPE_CONST ) continue; + int dupl = 0; + for( int i=0; !dupl && iopt; + if( op->offset != opt->offset ) continue; + if( op->type != opt->type ) continue; + dupl = 1; + if( strlen(op->name) < strlen(opt->name) ) + fp->opt = opt; + } + if( dupl ) continue; + PluginFClient_Opt *fopt = new PluginFClient_Opt(this, opt); + append(fopt); + } + } +} + +int PluginFClientConfig::update() +{ + int ret = 0; + PluginFClientConfig &conf = *this; + + for( int i=0; iget(val, sizeof(val)); + if( !vp || !strcmp(val, fopt->item_value->get_text()) ) continue; + fopt->item_value->update(); + ++ret; + } + return ret; +} + +void PluginFClientConfig::dump(FILE *fp) +{ + const AVOption *opt = 0; + const AVClass *obj = filter_class(); + PluginFClientConfig &conf = *this; + + while( (opt=av_opt_next(&obj, opt)) != 0 ) { + if( opt->type == AV_OPT_TYPE_CONST ) continue; + int k = size(); + while( --k >= 0 && strcmp(opt->name, conf[k]->opt->name) ); + if( k < 0 ) continue; + PluginFClient_Opt *fopt = conf[k]; + char val[BCTEXTLEN], *vp = fopt->get(val,sizeof(val)); + fprintf(fp, " %s:=%s", opt->name, vp); + if( opt->unit ) { + char unt[BCTEXTLEN], *up = unt; + fopt->units(up); + fprintf(fp, "%s", unt); + } + fprintf(fp, "\n"); + } +} + +PluginFClientReset:: +PluginFClientReset(PluginFClientWindow *fwin, int x, int y) + : BC_GenericButton(x, y, _("Reset")) +{ + this->fwin = fwin; +} + +PluginFClientReset:: +~PluginFClientReset() +{ +} + +int PluginFClientReset::handle_event() +{ + av_opt_set_defaults(fwin->ffmpeg->config.filter_config()); + if( fwin->ffmpeg->config.update() > 0 ) + fwin->draw(); + fwin->ffmpeg->plugin->send_configure_change(); + return 1; +} + +PluginFClientText:: +PluginFClientText(PluginFClientWindow *fwin, int x, int y, int w) + : BC_TextBox(x, y, w, 1, (char *)"") +{ + this->fwin = fwin; +} + +PluginFClientText:: +~PluginFClientText() +{ +} + +int PluginFClientText::handle_event() +{ + return 0; +} + +PluginFClientUnits:: +PluginFClientUnits(PluginFClientWindow *fwin, int x, int y, int w) + : BC_PopupMenu(x, y, w, "") +{ + this->fwin = fwin; +} + +PluginFClientUnits:: +~PluginFClientUnits() +{ +} + +int PluginFClientUnits::handle_event() +{ + const char *text = get_text(); + if( text && fwin->selected ) { + if( text ) fwin->selected->set(text); + fwin->selected->item_value->update(); + fwin->draw(); + fwin->ffmpeg->plugin->send_configure_change(); + } + return 1; +} + +PluginFClientApply:: +PluginFClientApply(PluginFClientWindow *fwin, int x, int y) + : BC_GenericButton(x, y, _("Apply")) +{ + this->fwin = fwin; +} + +PluginFClientApply:: +~PluginFClientApply() +{ +} + +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 1; +} + + +PluginFClient_OptPanel:: +PluginFClient_OptPanel(PluginFClientWindow *fwin, int x, int y, int w, int h) + : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1]) +{ + this->fwin = fwin; + update(); // init col/wid/columns +} + +PluginFClient_OptPanel:: +~PluginFClient_OptPanel() +{ +} + +void PluginFClient_OptPanel::create_objects() +{ + PluginFClientConfig &fconfig = fwin->ffmpeg->config; + for( int i=0; iitem_name); + vals.append(opt->item_value); + } +} + +int PluginFClient_OptPanel::cursor_leave_event() +{ + hide_tooltip(); + return 0; +} + +void PluginFClientWindow::update(PluginFClient_Opt *opt) +{ + if( selected != opt ) { + if( selected ) selected->item_name->set_selected(0); + selected = opt; + if( selected ) selected->item_name->set_selected(1); + } + clear_box(0,0, 0,panel->get_y()); + char str[BCTEXTLEN], *sp; + *(sp=str) = 0; + if( opt ) opt->types(sp); + type->update(str); + *(sp=str) = 0; + if( opt ) opt->ranges(sp); + range->update(str); + while( units->total_items() ) units->remove_item(0); + ArrayList opts; + int n = !opt ? 0 : opt->units(opts); + for( int i=0; iadd_item(new BC_MenuItem(opts[i]->name, 0)); + char unit[BCSTRLEN]; strcpy(unit, "()"); + if( units->total_items() && opt && opt->opt->unit ) + strcpy(unit, opt->opt->unit); + units->set_text(unit); + char val[BCTEXTLEN]; val[0] = 0; + if( opt ) opt->get(val, sizeof(val)); + text->update(val); + + panel->update(); +} + +int PluginFClient_OptPanel::selection_changed() +{ + PluginFClient_Opt *opt = 0; + BC_ListBoxItem *item = get_selection(0, 0); + if( item ) { + PluginFClient_OptName *opt_name = (PluginFClient_OptName *)item; + opt = opt_name->opt; + } + fwin->update(opt); + fwin->panel->set_tooltip(!opt ? 0 : opt->tip()); + fwin->panel->show_tooltip(); + return 1; +} + +void *PluginFClient_Opt::filter_config() +{ + return conf->filter_config(); +} +const AVClass *PluginFClient_Opt::filter_class() +{ + return conf->filter_class(); +} + +int PluginFClient_Opt::types(char *rp) +{ + const char *cp; + switch (opt->type) { + case AV_OPT_TYPE_FLAGS: cp = ""; break; + case AV_OPT_TYPE_INT: cp = ""; break; + case AV_OPT_TYPE_INT64: cp = ""; break; + case AV_OPT_TYPE_DOUBLE: cp = ""; break; + case AV_OPT_TYPE_FLOAT: cp = ""; break; + case AV_OPT_TYPE_STRING: cp = ""; break; + case AV_OPT_TYPE_RATIONAL: cp = ""; break; + case AV_OPT_TYPE_BINARY: cp = ""; break; + case AV_OPT_TYPE_IMAGE_SIZE: cp = ""; break; + case AV_OPT_TYPE_VIDEO_RATE: cp = ""; break; + case AV_OPT_TYPE_PIXEL_FMT: cp = ""; break; + case AV_OPT_TYPE_SAMPLE_FMT: cp = ""; break; + case AV_OPT_TYPE_DURATION: cp = ""; break; + case AV_OPT_TYPE_COLOR: cp = ""; break; + case AV_OPT_TYPE_CHANNEL_LAYOUT: cp = ""; break; + default: cp = ""; break; + } + return sprintf(rp, "%s", cp); +} +int PluginFClient_Opt::scalar(double d, char *rp) +{ + const char *cp = 0; + if( d == INT_MAX ) cp = "INT_MAX"; + else if( d == INT_MIN ) cp = "INT_MIN"; + else if( d == UINT32_MAX ) cp = "UINT32_MAX"; + else if( d == (double)INT64_MAX ) cp = "I64_MAX"; + else if( d == INT64_MIN ) cp = "I64_MIN"; + else if( d == FLT_MAX ) cp = "FLT_MAX"; + else if( d == FLT_MIN ) cp = "FLT_MIN"; + else if( d == -FLT_MAX ) cp = "-FLT_MAX"; + else if( d == -FLT_MIN ) cp = "-FLT_MIN"; + else if( d == DBL_MAX ) cp = "DBL_MAX"; + else if( d == DBL_MIN ) cp = "DBL_MIN"; + else if( d == -DBL_MAX ) cp = "-DBL_MAX"; + else if( d == -DBL_MIN ) cp = "-DBL_MIN"; + else if( d == 0 ) cp = signbit(d) ? "-0" : "0"; + else if( isnan(d) ) cp = signbit(d) ? "-NAN" : "NAN"; + else if( isinf(d) ) cp = signbit(d) ? "-INF" : "INF"; + else return sprintf(rp, "%g", d); + return sprintf(rp, "%s", cp); +} + +int PluginFClient_Opt::ranges(char *rp) +{ + const AVClass *filt_class = filter_class(); + if( !filt_class || !filt_class->option ) return 0; + 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 0;; + } + AVOptionRanges *r = 0; + void *obj = &filt_class; + char *cp = rp; + if( av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) < 0 ) return 0; + for( int i=0; inb_ranges; ++i ) { + cp += sprintf(cp, " ("); cp += scalar(r->range[i]->value_min, cp); + cp += sprintf(cp, ".."); cp += scalar(r->range[i]->value_max, cp); + cp += sprintf(cp, ")"); + } + av_opt_freep_ranges(&r); + return cp - rp; +} + +int PluginFClient_Opt::units(ArrayList &opts) +{ + if( !this->opt->unit ) return 0; + const AVClass *filt_class = filter_class(); + if( !filt_class || !filt_class->option ) return 0; + void *obj = &filt_class; + const AVOption *opt = NULL; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( !opt->unit ) continue; + if( opt->type != AV_OPT_TYPE_CONST ) continue; + if( strcmp(this->opt->unit, opt->unit) ) continue; + int i = opts.size(); + while( --i >= 0 ) { + if( opts[i]->default_val.i64 != opt->default_val.i64 ) continue; + if( strlen(opts[i]->name) < strlen(opt->name) ) opts[i] = opt; + break; + } + if( i < 0 ) + opts.append(opt); + } + return opts.size(); +} + +int PluginFClient_Opt::units(char *rp) +{ + ArrayList opts; + int n = units(opts); + if( !n ) return 0; + char *cp = rp; + cp += sprintf(cp, " [%s:", this->opt->unit); + for( int i=0; iname); + cp += sprintf(cp, "]:"); + return cp - rp; +} + +const char *PluginFClient_Opt::tip() +{ + return opt->help; +} + +int PluginFClient_OptPanel::update() +{ + const char *cols[] = { "option", "value", }; + const int col1_w = 150; + int wids[] = { col1_w, get_w()-col1_w }; + BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0])); + return 0; +} + + +PluginFClientWindow::PluginFClientWindow(PluginFClient *ffmpeg) + : PluginClientWindow(ffmpeg->plugin, 600, 300, 600, 300, 1) +{ + this->ffmpeg = ffmpeg; + this->selected = 0; +} + +PluginFClientWindow::~PluginFClientWindow() +{ +} + +void PluginFClientWindow::create_objects() +{ + char string[BCTEXTLEN]; + BC_Title *title; + int x = 10, y = 10; + const char *descr = ffmpeg->config.ffilt->description(); + if( !descr ) descr = ffmpeg->config.ffilt->filter_name(); + add_subwindow(title = new BC_Title(x, y, descr)); + y += title->get_h() + 10; + int x0 = x; + sprintf(string, _("Type: ")); + add_subwindow(title = new BC_Title(x0, y, string)); + x0 += title->get_w() + 8; + add_subwindow(type = new BC_Title(x0, y, (char *)"")); + x0 = x + 150; + sprintf(string, _("Range: ")); + add_subwindow(title = new BC_Title(x0, y, string)); + x0 += title->get_w() + 8; + add_subwindow(range = new BC_Title(x0, y, (char *)"")); + int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8; + add_subwindow(reset = new PluginFClientReset(this, x1, y)); + y += title->get_h() + 10; + x0 = x; + add_subwindow(units = new PluginFClientUnits(this, x0, y, 120)); + x0 += units->get_w() + 8; + x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8; + add_subwindow(apply = new PluginFClientApply(this, x1, y)); + add_subwindow(text = new PluginFClientText(this, x0, y, x1-x0 - 8)); + y += title->get_h() + 10; + + panel_x = x; panel_y = y; + panel_w = get_w()-10 - panel_x; + panel_h = get_h()-10 - panel_y; + panel = new PluginFClient_OptPanel(this, panel_x, panel_y, panel_w, panel_h); + add_subwindow(panel); + panel->create_objects(); + ffmpeg->config.update(); + draw(); + show_window(1); +} + +void PluginFClientWindow::draw() +{ + update(selected); +} + +int PluginFClientWindow::resize_event(int w, int h) +{ + int x = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8; + int y = reset->get_y(); + reset->reposition_window(x, y); + int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8; + int y1 = units->get_y(); + apply->reposition_window(x1, y1); + int x0 = units->get_x() + units->get_w() + 8; + int y0 = units->get_y(); + text->reposition_window(x0,y0, x1-x0-8); + 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; + this->name = name; + ffilt = 0; + fsrc = fsink = 0; + plugin_position = -1; + filter_position = -1; + activated = 0; + sprintf(title, "F_%s", name); + config.initialize(name); + curr_config.initialize(name); +} + +PluginFClient::~PluginFClient() +{ +} + +bool PluginFClient::is_audio(AVFilter *fp) +{ + if( !fp->outputs ) return 0; + if( avfilter_pad_count(fp->outputs) > 1 ) return 0; + if( !avfilter_pad_get_name(fp->outputs, 0) ) return 0; + if( avfilter_pad_get_type(fp->outputs, 0) != AVMEDIA_TYPE_AUDIO ) return 0; + if( !fp->inputs ) return 1; + if( avfilter_pad_count(fp->inputs) > 1 ) return 0; + if( !avfilter_pad_get_name(fp->inputs, 0) ) return 0; + if( avfilter_pad_get_type(fp->inputs, 0) != AVMEDIA_TYPE_AUDIO ) return 0; + return 1; +} +bool PluginFClient::is_video(AVFilter *fp) +{ + if( !fp->outputs ) return 0; + if( avfilter_pad_count(fp->outputs) > 1 ) return 0; + if( !avfilter_pad_get_name(fp->outputs, 0) ) return 0; + if( avfilter_pad_get_type(fp->outputs, 0) != AVMEDIA_TYPE_VIDEO ) return 0; + if( !fp->inputs ) return 1; + if( avfilter_pad_count(fp->inputs) > 1 ) return 0; + if( !avfilter_pad_get_name(fp->inputs, 0) ) return 0; + if( avfilter_pad_get_type(fp->inputs, 0) != AVMEDIA_TYPE_VIDEO ) return 0; + return 1; +} + +NEW_WINDOW_MACRO(PluginFClient, PluginFClientWindow) + +int PluginFClient::load_configuration() +{ + int64_t src_position = get_source_position(); + KeyFrame *prev_keyframe = get_prev_keyframe(src_position); + config.copy_from(curr_config); + read_data(prev_keyframe); + int ret = !config.equivalent(curr_config) ? 1 : 0; + return ret; +} + + +void PluginFClient::render_gui(void *data, int size) +{ + PluginFClientConfig *conf = (PluginFClientConfig *)data; + config.copy_from(*conf); + KeyFrame *keyframe = plugin->server->get_keyframe(); + save_data(keyframe); + update_gui(); +} + +void PluginFClient::update_gui() +{ + PluginClientThread *thread = plugin->get_thread(); + if( !thread ) return; + PluginFClientWindow *window = (PluginFClientWindow*)thread->get_window(); + window->lock_window("PluginFClient::update_gui"); + load_configuration(); + if( config.update() > 0 ) + window->draw(); + window->unlock_window(); +} + +const char *PluginFClient::plugin_title() +{ + return title; +} + +char *PluginFClient::to_upper(char *cp, const char *sp) +{ + char *bp = cp; + while( *sp != 0 ) *bp++ = toupper(*sp++); + *bp = 0; + return cp; +} + +void PluginFClient::save_data(KeyFrame *keyframe) +{ + FileXML output; + char string[BCTEXTLEN]; + +// cause data to be stored directly in text + output.set_shared_output(keyframe->get_data(), MESSAGESIZE); + output.tag.set_title(to_upper(string, plugin_title())); + const AVClass *filt_class = config.filter_class(); + if( filt_class && filt_class->option ) { + void *obj = config.filter_config(); + const AVOption *opt = NULL; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + uint8_t *buf = 0; + if( av_opt_get(obj, opt->name, 0, &buf) < 0 ) continue; + output.tag.set_property(opt->name, (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]; + input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); + + while( !input.read_tag() ) { + to_upper(string, plugin_title()); + if( !input.tag.title_is(string) ) continue; + const AVClass *filt_class = config.filter_class(); + if( filt_class && filt_class->option ) { + 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); + } + } + } +} + +int PluginFClient::activate() +{ + if( fsrc ) + avfilter_link(fsrc, 0, ffilt->fctx, 0); + avfilter_link(ffilt->fctx, 0, fsink, 0); + int ret = avfilter_graph_config(ffilt->graph, NULL); + if( ret >= 0 ) { + curr_config.copy_from(config); + activated = 1; + } + return ret; +} + +void PluginFClient::reactivate() +{ + delete ffilt; ffilt = 0; + activated = 0; +} + +PluginFAClient::PluginFAClient(PluginServer *server, const char *name) + : PluginAClient(server), PluginFClient(this, name) +{ +} + +PluginFAClient::~PluginFAClient() +{ +} + +int PluginFAClient::activate() +{ + if( activated ) return activated; + ffilt = PluginFFilter::new_ffilter(name, &config); + if( !ffilt ) { + config.copy_from(curr_config); + send_configure_change(); + send_render_gui(&config, sizeof(config)); + ffilt = PluginFFilter::new_ffilter(name, &config); + } + AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP; + int channels = PluginClient::total_in_buffers; + uint64_t layout = (((uint64_t)1)<graph; + int ret = !graph ? -1 : 0; + if( ret >= 0 && ffilt->filter->inputs ) { + char args[BCTEXTLEN]; + snprintf(args, sizeof(args), + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%jx", + 1, sample_rate, sample_rate, av_get_sample_fmt_name(sample_fmt), layout); + ret = avfilter_graph_create_filter(&fsrc, avfilter_get_by_name("abuffer"), + "in", args, NULL, graph); + } + if( ret >= 0 ) + ret = avfilter_graph_create_filter(&fsink, avfilter_get_by_name("abuffersink"), + "out", NULL, NULL, graph); + if( ret >= 0 ) + ret = av_opt_set_bin(fsink, "sample_fmts", + (uint8_t*)&sample_fmt, sizeof(sample_fmt), AV_OPT_SEARCH_CHILDREN); + if( ret >= 0 ) + ret = av_opt_set_bin(fsink, "channel_layouts", + (uint8_t*)&layout, sizeof(layout), AV_OPT_SEARCH_CHILDREN); + if( ret >= 0 ) + ret = av_opt_set_bin(fsink, "sample_rates", + (uint8_t*)&sample_rate, sizeof(sample_rate), AV_OPT_SEARCH_CHILDREN); + if( ret >= 0 ) + ret = PluginFClient::activate(); + if( ret < 0 && activated >= 0 ) { + ff_err(ret, "PluginFAClient::activate: %s failed\n", plugin_title()); + activated = -1; + } + return activated; +} + + +static AVRational best_frame_rate(double frame_rate) +{ + static const int m1 = 1001*12, m2 = 1000*12; + static const int freqs[] = { + 40*m1, 48*m1, 50*m1, 60*m1, 80*m1,120*m1, 240*m1, + 24*m2, 30*m2, 60*m2, 12*m2, 15*m2, 48*m2, 0, + }; + double max_err = 1.; + int freq, best_freq = 0; + for( int i=0; (freq = i<30*12 ? (i+1)*1001 : freqs[i-30*12]); ++i ) { + double framerate = (double)freq / m1; + double err = fabs(frame_rate/framerate - 1.); + if( err >= max_err ) continue; + max_err = err; + best_freq = freq; + } + return max_err < 0.0001 ? + (AVRational) { best_freq, m1 } : + (AVRational) { 0, 0 }; +} + +int PluginFVClient::activate(int width, int height, int color_model) +{ + if( activated ) return activated; + ffilt = PluginFFilter::new_ffilter(name, &config); + if( !ffilt ) { + config.copy_from(curr_config); + send_configure_change(); + send_render_gui(&config, sizeof(config)); + ffilt = PluginFFilter::new_ffilter(name, &config); + } + AVPixelFormat pix_fmt = color_model_to_pix_fmt(color_model); + AVFilterGraph *graph = !ffilt ? 0 : ffilt->graph; + int ret = !graph ? -1 : 0; + if( ret >= 0 && ffilt->filter->inputs ) { + curr_config.copy_from(config); + if( pix_fmt == AV_PIX_FMT_NB ) { + int bpp = BC_CModels::calculate_pixelsize(color_model) * 8; + int bits_per_comp = bpp / BC_CModels::components(color_model); + int alpha = BC_CModels::has_alpha(color_model); + pix_fmt = bits_per_comp > 8 ? + !alpha ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGBA64LE : + !alpha ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_RGBA ; + } + int aspect_w = 1, aspect_h = 1; // XXX + AVRational best_rate = best_frame_rate(frame_rate); + char args[BCTEXTLEN]; + snprintf(args, sizeof(args), + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", + width, height, pix_fmt, best_rate.num, best_rate.den, aspect_w, aspect_h); + ret = avfilter_graph_create_filter(&fsrc, avfilter_get_by_name("buffer"), + "in", args, NULL, graph); + } + if( ret >= 0 ) + ret = avfilter_graph_create_filter(&fsink, avfilter_get_by_name("buffersink"), + "out", NULL, NULL, graph); + if( ret >= 0 ) + ret = av_opt_set_bin(fsink, "pix_fmts", + (uint8_t*)&pix_fmt, sizeof(pix_fmt), AV_OPT_SEARCH_CHILDREN); + if( ret >= 0 ) + ret = PluginFClient::activate(); + if( ret < 0 && activated >= 0 ) { + ff_err(ret, "PluginFVClient::activate() %s\n", plugin_title()); + activated = -1; + } + return activated; +} + +int PluginFAClient::get_inchannels() +{ + AVFilterContext *fctx = ffilt->fctx; + AVFilterLink **links = !fctx->nb_inputs ? 0 : fctx->inputs; + return !links ? 0 : avfilter_link_get_channels(links[0]); +} + +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]); +} + +int PluginFAClient::process_buffer(int64_t size, Samples **buffer, int64_t start_position, int sample_rate) +{ + int total_in = PluginClient::total_in_buffers; + int total_out = PluginClient::total_out_buffers; + int in_channels = 0, out_channels = 0; + + if( load_configuration() ) + plugin_position = -1; + if( plugin_position != start_position ) { + filter_position = plugin_position = start_position; + reactivate(); + } + + AVFrame *frame = 0; + int ret = activate(); + if( ret >= 0 && !(frame = av_frame_alloc()) ) { + fprintf(stderr, "PluginFAClient::process_buffer: av_frame_alloc failed\n"); + ret = AVERROR(ENOMEM); + } + if( ret >= 0 ) { + in_channels = get_inchannels(); + out_channels = get_outchannels(); + } + + int retry = 10; + while( ret >= 0 && --retry >= 0 ) { + ret = av_buffersink_get_frame(fsink, frame); + if( ret >= 0 || ret != AVERROR(EAGAIN) ) break; + if( !fsrc ) { ret = AVERROR(EIO); break; } + for( int i=0; inb_samples = size; + frame->format = AV_SAMPLE_FMT_FLTP; + frame->channel_layout = (1<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]; + for(int i = 0; i < in_channels; i++) { + float *in_buffer = in_buffers[i]; + int k = i < total_in ? i : 0; + double *in_ptr = buffer[k]->get_data(); + for(int j = 0; j < size; j++) in_buffer[j] = in_ptr[j]; + } + ret = av_buffersrc_add_frame_flags(fsrc, frame, 0); + } + if( ret >= 0 && retry < 0 ) + ret = AVERROR(EAGAIN); + + if( ret >= 0 ) { + int nbfrs = total_out; + if( out_channels < nbfrs ) nbfrs = out_channels; + float **out_buffers = (float **)&frame->extended_data[0]; + int i = 0; + while( i < nbfrs ) { + float *out_buffer = out_buffers[i]; + double *out_ptr = buffer[i++]->get_data(); + for(int j = 0; j < size; j++) out_ptr[j] = out_buffer[j]; + } + while( i < total_out ) { + double *out_ptr = buffer[i++]->get_data(); + bzero(out_ptr, sizeof(double) * size); + } + } + if( ret < 0 ) { + int64_t position = PluginFClient::get_source_position(); + double t0 = (double)position/sample_rate, dt = 1./sample_rate; + for( int i=0; iget_data(); + for( int k=size; --k>=0; t+=dt ) { + double w = int(2*t) & 1 ? 2*M_PI*440 : 2*M_PI*697; + *out++ = sin(t * w); + } + } + ff_err(ret, "PluginFAClient::process_buffer() %s\n", plugin_title()); + } + + av_frame_free(&frame); + plugin_position += size; + return size; +} + + +PluginFVClient::PluginFVClient(PluginServer *server, const char *name) + : PluginVClient(server), PluginFClient(this, name) +{ +} + +PluginFVClient::~PluginFVClient() +{ +} + +int PluginFVClient::process_buffer(VFrame **frames, int64_t position, double frame_rate) +{ + VFrame *vframe = *frames; + int width = vframe->get_w(); + int height = vframe->get_h(); + + if( load_configuration() ) + plugin_position = -1; + if( plugin_position != position ) { + filter_position = plugin_position = position; + reactivate(); + } + + int colormodel = vframe->get_color_model(); + int ret = activate(width, height, colormodel); + AVPixelFormat pix_fmt = fsrc ? + (AVPixelFormat) fsrc->outputs[0]->format : + 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 = AVERROR(ENOMEM); + } + + int retry = 10; + while( ret >= 0 && --retry >= 0 ) { + 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()); + 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); + if( ret < 0 ) break; + ret = av_buffersrc_add_frame_flags(fsrc, frame, 0); + } + if( ret >= 0 && retry < 0 ) + ret = AVERROR(EAGAIN); + + if( ret >= 0 ) { + pix_fmt = (AVPixelFormat) frame->format; + ret = transfer_cmodel(vframe, frame, pix_fmt, width, height); + } + if( ret < 0 ) { + ff_err(ret, "PluginFVClient::process_buffer() %s\n", plugin_title()); + if( position & 1 ) vframe->clear_frame(); + } + + ++plugin_position; + av_frame_free(&frame); + return ret >= 0 ? 0 : 1; +} + + +PluginFClient_OptName:: PluginFClient_OptName(PluginFClient_Opt *opt) +{ + this->opt = opt; + set_text(opt->opt->name); +} + +PluginFClient_OptValue::PluginFClient_OptValue(PluginFClient_Opt *opt) +{ + this->opt = opt; + update(); +} + +void PluginFClient_OptValue::update() +{ + char val[BCTEXTLEN]; val[0] = 0; + opt->get(val, sizeof(val)); + set_text(val); +} + + +PluginFClient_Opt::PluginFClient_Opt(PluginFClientConfig *conf, const AVOption *opt) +{ + this->conf = conf; + this->opt = opt; + item_name = new PluginFClient_OptName(this); + item_value = new PluginFClient_OptValue(this); +} + +PluginFClient_Opt::~PluginFClient_Opt() +{ + delete item_name; + delete item_value; +} + +char *PluginFClient_Opt::get(char *vp, int sz) +{ + 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); + } + return ret; +} +void PluginFClient_Opt::set(const char *val) +{ + void *obj = filter_config(); + av_opt_set(obj , opt->name, val, 0); +} + +void PluginFFilter::uninit() +{ +} + +static int get_defaults(const char *name, char *args) +{ + *args = 0; + char defaults_path[BCTEXTLEN]; + FFMPEG::set_option_path(defaults_path, "plugin.opts"); + 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; + char *bp = ff_plugin, *ep = bp + sizeof(ff_plugin)-1; + while( bp < ep && *ap && *ap != '\n' && *ap != ' ' ) *bp++ = *ap++; + *bp = 0; + if( strcmp(ff_plugin, name) ) ap = 0; + } + fclose(fp); + if( !ap ) return 0; + if( ff_args[0] == '#' ) return -1; + while( *ap == ' ' ) ++ap; + while( *ap && *ap != '\n' ) *args++ = *ap++; + *args = 0; + return 1; +} + +bool PluginFFilter::is_audio() +{ + return PluginFClient::is_audio(filter); +} + +bool PluginFFilter::is_video() +{ + return PluginFClient::is_video(filter); +} + +int PluginFFilter::init(const char *name, PluginFClientConfig *conf) +{ + char args[BCTEXTLEN]; + int ret = get_defaults(name, args); + if( ret < 0 ) return 0; + PluginFLogLevel errs(AV_LOG_ERROR); + this->filter = avfilter_get_by_name(name); + if( !this->filter ) return AVERROR(ENOENT); + int flag_mask = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS; + if( filter->flags & flag_mask ) return AVERROR(EPERM); + if( !this->is_audio() && !this->is_video() ) return AVERROR(EIO); + this->graph = avfilter_graph_alloc(); + if( !this->graph ) return AVERROR(ENOMEM); + static int inst = 0; + char inst_name[BCSTRLEN]; + sprintf(inst_name,"%s_%d", name, ++inst); + graph->thread_type = 0; + graph->nb_threads = 1; + fctx = avfilter_graph_alloc_filter(graph, filter, inst_name); + if( !fctx ) return AVERROR(ENOMEM); + if( conf ) { + AVDictionary *opts = 0; + for( int i=0; isize(); ++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); + } + ret = avfilter_init_dict(fctx, &opts); + av_dict_free(&opts); + } + else + ret = avfilter_init_str(fctx, args); + return ret < 0 ? ret : 1; +} + + +PluginFFilter::PluginFFilter() +{ + filter = 0; + graph = 0; + fctx = 0; +} + +PluginFFilter::~PluginFFilter() +{ + PluginFLogLevel errs(AV_LOG_ERROR); + avfilter_graph_free(&graph); + filter = 0; fctx = 0; +} + +PluginFFilter *PluginFFilter::new_ffilter(const char *name, PluginFClientConfig *conf) +{ + PluginFFilter *ffilt = new PluginFFilter; + int ret = ffilt->init(name, conf); + if( ret < 0 ) ff_err(ret, "PluginFFilter::new_ffilter(%s)\n", name); + if( ret <= 0 ) { delete ffilt; ffilt = 0; } + return ffilt; +} + +PluginClient *PluginServer::new_ffmpeg_plugin() +{ + AVFilter *filter = avfilter_get_by_name(ff_name); + if( !filter ) return 0; + PluginFClient *ffmpeg = + PluginFClient::is_audio(filter) ? + (PluginFClient *)new PluginFAClient(this, ff_name) : + PluginFClient::is_video(filter) ? + (PluginFClient *)new PluginFVClient(this, ff_name) : + 0; + if( !ffmpeg ) return 0; + return ffmpeg->plugin; +} + + +PluginServer* MWindow::new_ffmpeg_server(MWindow *mwindow, const char *name) +{ + PluginFFilter *ffilt = PluginFFilter::new_ffilter(name); + if( !ffilt ) return 0; + delete ffilt; + return new PluginServer(mwindow, (char*)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 ) { + PluginServer *server = new_ffmpeg_server(mwindow, filter->name); + if( server ) { + int result = server->open_plugin(1, preferences, 0, 0); + if( !result ) { + server->write_table(fp, PLUGIN_FFMPEG_ID); + server->close_plugin(); + } + server->delete_this(); + if( result ) fprintf(fp, "#%s\n", filter->name); + } + } +} + +void MWindow::init_ffmpeg() +{ + av_register_all(); + avfilter_register_all(); +} + diff --git a/cinelerra-5.0/cinelerra/pluginfclient.h b/cinelerra-5.0/cinelerra/pluginfclient.h new file mode 100644 index 00000000..781e2523 --- /dev/null +++ b/cinelerra-5.0/cinelerra/pluginfclient.h @@ -0,0 +1,285 @@ +#ifndef __PLUGINFCLIENT_H__ +#define __PLUGINFCLIENT_H__ + +#include "arraylist.h" +#include "bclistbox.h" +#include "bclistboxitem.h" +#include "bcbutton.h" +#include "bcpopupmenu.h" +#include "bcmenuitem.h" +#include "bctextbox.h" +#include "ffmpeg.h" +#include "pluginclient.h" +#include "pluginaclient.h" +#include "pluginvclient.h" +#include "pluginserver.h" +#include "pluginfclient.inc" +#include "preferences.inc" + +extern "C" { +#include "libavfilter/buffersrc.h" +#include "libavfilter/buffersink.h" +#include "libavformat/avformat.h" +#include "libavformat/avio.h" +#include "libavcodec/avcodec.h" +#include "libavfilter/avfilter.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libswresample/swresample.h" +#include "libswscale/swscale.h" +} + +class PluginFClient_OptName : public BC_ListBoxItem { +public: + PluginFClient_Opt *opt; + + PluginFClient_OptName(PluginFClient_Opt *opt); +}; + +class PluginFClient_OptValue : public BC_ListBoxItem { +public: + PluginFClient_Opt *opt; + + void update(); + PluginFClient_OptValue(PluginFClient_Opt *opt); +}; + +class PluginFClient_Opt { +public: + PluginFClientConfig *conf; + const AVOption *opt; + PluginFClient_OptName *item_name; + PluginFClient_OptValue *item_value; + + char *get(char *vp, int sz=-1); + void set(const char *val); + int types(char *rp); + int scalar(double d, char *rp); + int ranges(char *rp); + int units(ArrayList &opts); + int units(char *rp); + const char *tip(); + void *filter_config(); + const AVClass *filter_class(); + + PluginFClient_Opt(PluginFClientConfig *conf, const AVOption *opt); + ~PluginFClient_Opt(); +}; + +class PluginFFilter { + PluginFFilter(PluginFFilter &that) {} //disable assign/copy +public: + AVFilter *filter; + AVFilterGraph *graph; + AVFilterContext *fctx; + + void *filter_config() { return fctx->priv; } + const AVClass *filter_class() { return filter->priv_class; } + const char *description() { return filter->description; } + + int init(const char *name, PluginFClientConfig *conf); + void uninit(); + static PluginFFilter *new_ffilter(const char *name, PluginFClientConfig *conf=0); + + PluginClient* new_plugin(PluginServer*); + const char *filter_name() { return filter->name; } + bool is_audio(); + bool is_video(); + + PluginFFilter(); + ~PluginFFilter(); +}; + +class PluginFClientConfig : public ArrayList +{ +public: + PluginFFilter *ffilt; + void *filter_config() { return ffilt->filter_config(); } + const AVClass *filter_class() { return ffilt->filter_class(); } + + void copy_from(PluginFClientConfig &that); + int equivalent(PluginFClientConfig &that); + void interpolate(PluginFClientConfig &prev, PluginFClientConfig &next, + int64_t prev_frame, int64_t next_frame, int64_t current_frame); + void initialize(const char *name); + int update(); + void dump(FILE *fp=stdout); + + PluginFClientConfig(); + ~PluginFClientConfig(); +}; + + +class PluginFClient_OptPanel : public BC_ListBox { +public: + PluginFClient_OptPanel(PluginFClientWindow *fwin, int x, int y, int w, int h); + ~PluginFClient_OptPanel(); + void create_objects(); + int cursor_leave_event(); + + PluginFClientWindow *fwin; + ArrayList items[2]; + ArrayList &opts; + ArrayList &vals; + + int selection_changed(); + int update(); +}; + +class PluginFClientReset : public BC_GenericButton { +public: + PluginFClientWindow *fwin; + + PluginFClientReset(PluginFClientWindow *fwin, int x, int y); + ~PluginFClientReset(); + int handle_event(); +}; + +class PluginFClientUnits : public BC_PopupMenu { +public: + PluginFClientWindow *fwin; + + PluginFClientUnits(PluginFClientWindow *fwin, int x, int y, int w); + ~PluginFClientUnits(); + int handle_event(); +}; + +class PluginFClientText : public BC_TextBox { +public: + PluginFClientWindow *fwin; + + PluginFClientText(PluginFClientWindow *fwin, int x, int y, int w); + ~PluginFClientText(); + int handle_event(); +}; + +class PluginFClientApply : public BC_GenericButton { +public: + PluginFClientWindow *fwin; + + PluginFClientApply(PluginFClientWindow *fwin, int x, int y); + ~PluginFClientApply(); + int handle_event(); +}; + +class PluginFClientWindow : public PluginClientWindow +{ +public: + PluginFClientWindow(PluginFClient *ffmpeg); + ~PluginFClientWindow(); + + void create_objects(); + void update(PluginFClient_Opt *oip); + void draw(); + int resize_event(int w, int h); + + PluginFClient *ffmpeg; + PluginFClient_OptPanel *panel; + int panel_x, panel_y, panel_w, panel_h; + BC_Title *type, *range; + PluginFClient_Opt *selected; + + PluginFClientReset *reset; + PluginFClientUnits *units; + PluginFClientText *text; + PluginFClientApply *apply; +}; + +class PluginFLogLevel { + int level; +public: + PluginFLogLevel(int lvl) { + level = av_log_get_level(); + if( level > lvl ) av_log_set_level(lvl); + } + ~PluginFLogLevel() { av_log_set_level(level); } +}; + +class PluginFClient { +public: + const char *name; + PluginClient *plugin; + PluginFFilter *ffilt; + AVFilterContext *fsrc, *fsink; + int64_t plugin_position, filter_position; + int activated; + char title[BCSTRLEN]; + + PluginFClient(PluginClient *plugin, const char *name); + ~PluginFClient(); + static bool is_audio(AVFilter *fp); + static bool is_video(AVFilter *fp); + + int64_t get_source_position() { + return plugin->get_source_position(); + } + KeyFrame* get_prev_keyframe(int64_t position, int is_local=1) { + return plugin->get_prev_keyframe(position, is_local); + } + KeyFrame* get_next_keyframe(int64_t position, int is_local=1) { + return plugin->get_next_keyframe(position, is_local); + } + int64_t edl_to_local(int64_t position) { + return plugin->edl_to_local(position); + } + + void update_gui(); + char *to_upper(char *bp, const char *sp); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + void render_gui(void *data, int size); + int activate(); + void reactivate(); + + PluginFClientConfig curr_config, av_config; + PLUGIN_CLASS_MEMBERS(PluginFClientConfig) +}; + +class PluginFAClient : public PluginAClient, public PluginFClient +{ +public: + PluginFAClient(PluginServer *server, const char *name); + ~PluginFAClient(); + const char *plugin_title() { return PluginFClient::plugin_title(); } + PluginClientWindow *new_window() { return PluginFClient::new_window(); } + int activate(); + + int load_configuration() { return PluginFClient::load_configuration(); } + void save_data(KeyFrame *keyframe) { PluginFClient::save_data(keyframe); } + void read_data(KeyFrame *keyframe) { PluginFClient::read_data(keyframe); } + void update_gui() { PluginFClient::update_gui(); } + void render_gui(void *data, int size) { PluginFClient::render_gui(data, size); } + + int is_realtime() { return 1; } + int is_multichannel() { return 1; } + int uses_gui() { return 1; } + int is_synthesis() { return 1; } + int get_inchannels(); + int get_outchannels(); + int process_buffer(int64_t size, Samples **buffer, int64_t start_position, int sample_rate); +}; + +class PluginFVClient : public PluginVClient, public PluginFClient, public FFVideoConvert +{ +public: + PluginFVClient(PluginServer *server, const char *name); + ~PluginFVClient(); + const char *plugin_title() { return PluginFClient::plugin_title(); } + PluginClientWindow *new_window() { return PluginFClient::new_window(); } + int activate(int width, int height, int color_model); + + int load_configuration() { return PluginFClient::load_configuration(); } + void save_data(KeyFrame *keyframe) { PluginFClient::save_data(keyframe); } + void read_data(KeyFrame *keyframe) { PluginFClient::read_data(keyframe); } + void update_gui() { PluginFClient::update_gui(); } + void render_gui(void *data, int size) { PluginFClient::render_gui(data, size); } + + int is_realtime() { return 1; } + int is_multichannel() { return 1; } + int uses_gui() { return 1; } + int is_synthesis() { return 1; } + int process_buffer(VFrame **frames, int64_t start_position, double frame_rate); +}; + +#endif diff --git a/cinelerra-5.0/cinelerra/pluginfclient.inc b/cinelerra-5.0/cinelerra/pluginfclient.inc new file mode 100644 index 00000000..5c3f8f0c --- /dev/null +++ b/cinelerra-5.0/cinelerra/pluginfclient.inc @@ -0,0 +1,39 @@ +#ifndef __PLUGINFCLIENT_INC__ +#define __PLUGINFCLIENT_INC__ + +struct AVFilter; +typedef struct AVFilter AVFilter; +struct AVFilterGraph; +typedef struct AVFilterGraph AVFilterGraph; + +class PluginFClient_Opt; +class PluginFFilter; +class PluginFClientConfig; +class PluginFClient_OptName; +class PluginFClient_OptValue; +class PluginFClient_OptPanel; +class PluginFClientUnits; +class PluginFClientText; +class PluginFClientApply; +class PluginFClientWindow; +class PluginFClient; +class PluginFAClient; +class PluginFVClient; + +#ifndef FLT_MAX +#define FLT_MAX 3.40282346638528859812e+38F +#endif + +#ifndef FLT_MIN +#define FLT_MIN 1.17549435082228750797e-38F +#endif + +#ifndef DBL_MAX +#define DBL_MAX ((double)1.79769313486231570815e+308L) +#endif + +#ifndef DBL_MIN +#define DBL_MIN ((double)2.22507385850720138309e-308L) +#endif + +#endif diff --git a/cinelerra-5.0/cinelerra/pluginserver.C b/cinelerra-5.0/cinelerra/pluginserver.C index a57da865..66abd3bd 100644 --- a/cinelerra-5.0/cinelerra/pluginserver.C +++ b/cinelerra-5.0/cinelerra/pluginserver.C @@ -25,6 +25,7 @@ #include "autoconf.h" #include "bcsignals.h" #include "cplayback.h" +#include "cstrdup.h" #include "cwindow.h" #include "edl.h" #include "edlsession.h" @@ -40,6 +41,7 @@ #include "plugin.h" #include "pluginaclient.h" #include "pluginaclientlad.h" +#include "pluginfclient.h" #include "pluginclient.h" #include "plugincommands.h" #include "pluginserver.h" @@ -68,38 +70,40 @@ #include -PluginServer::PluginServer() +void PluginServer::init() { reset_parameters(); + this->plugin_type = PLUGIN_TYPE_UNKNOWN; modules = new ArrayList; nodes = new ArrayList; } -PluginServer::PluginServer(char *path, MWindow *mwindow) +PluginServer::PluginServer() { - reset_parameters(); - set_path(path); - modules = new ArrayList; - nodes = new ArrayList; - this->mwindow = mwindow; + init(); } -PluginServer::PluginServer(PluginServer &that) +PluginServer::PluginServer(MWindow *mwindow, char *path, int type) { - reset_parameters(); - - if(that.title) - { - title = new char[strlen(that.title) + 1]; - strcpy(title, that.title); - } - - if(that.path) - { - path = new char[strlen(that.path) + 1]; - strcpy(path, that.path); + char fpath[BCTEXTLEN]; + init(); + this->plugin_type = type; + this->mwindow = mwindow; + if( type == PLUGIN_TYPE_FFMPEG ) { + ff_name = cstrdup(path); + sprintf(fpath, "ff_%s", path); + path = fpath; } + set_path(path); +} +PluginServer::PluginServer(PluginServer &that) +{ + reset_parameters(); + plugin_type = that.plugin_type; + title = !that.title ? 0 : cstrdup(that.title); + path = !that.path ? 0 : cstrdup(that.path); + ff_name = !that.ff_name ? 0 : cstrdup(that.ff_name); modules = new ArrayList; nodes = new ArrayList; @@ -117,7 +121,6 @@ PluginServer::PluginServer(PluginServer &that) keyframe = that.keyframe; new_plugin = that.new_plugin; - is_lad = that.is_lad; lad_descriptor = that.lad_descriptor; lad_descriptor_function = that.lad_descriptor_function; lad_index = that.lad_index; @@ -126,11 +129,12 @@ PluginServer::PluginServer(PluginServer &that) PluginServer::~PluginServer() { close_plugin(); - if(path) delete [] path; - if(title) delete [] title; - if(modules) delete modules; - if(nodes) delete nodes; - if(picon) delete picon; + delete [] path; + delete [] ff_name; + delete [] title; + delete modules; + delete nodes; + delete picon; } // Done only once at creation @@ -141,11 +145,12 @@ int PluginServer::reset_parameters() prompt = 0; cleanup_plugin(); autos = 0; - plugin = 0; edl = 0; + dlobj = 0; preferences = 0; title = 0; path = 0; + ff_name = 0; audio = video = theme = 0; fileio = 0; uses_gui = 0; @@ -161,14 +166,12 @@ int PluginServer::reset_parameters() nodes = 0; picon = 0; - is_lad = 0; lad_index = -1; lad_descriptor_function = 0; lad_descriptor = 0; return 0; } - // Done every time the plugin is opened or closed int PluginServer::cleanup_plugin() { @@ -217,15 +220,18 @@ int PluginServer::get_lad_index() int PluginServer::is_ladspa() { - return is_lad; + return plugin_type == PLUGIN_TYPE_LADSPA ? 1 : 0; } -int PluginServer::set_path(char *path) +int PluginServer::is_ffmpeg() { - if(this->path) delete [] this->path; - this->path = new char[strlen(path) + 1]; - strcpy(this->path, path); - return 0; + return plugin_type == PLUGIN_TYPE_FFMPEG ? 1 : 0; +} + +void PluginServer::set_path(const char *path) +{ + delete [] this->path; + this->path = cstrdup(path); } char* PluginServer::get_path() @@ -242,8 +248,7 @@ int PluginServer::get_synthesis() void PluginServer::set_title(const char *string) { if(title) delete [] title; - title = new char[strlen(string) + 1]; - strcpy(title, string); + title = cstrdup(string); } void PluginServer::generate_display_title(char *string) @@ -260,11 +265,34 @@ void PluginServer::generate_display_title(char *string) strcpy(string, ltitle); } +void *PluginServer::load_obj() +{ + if( !dlobj ) { + char dlpath[BCTEXTLEN], *dp = dlpath; + char *cp = path; + if( *cp != '/' ) { + char *bp = preferences->plugin_dir; + while( *bp ) *dp++ = *bp++; + *dp++ = '/'; + } + while( *cp ) *dp++ = *cp++; + *dp = 0; + dlobj = load(dlpath); + } + return dlobj; +} + +void PluginServer::unload_obj() +{ + if( !dlobj ) return; + unload(dlobj); dlobj = 0; +} + void PluginServer::delete_this() { - void *dlp = load_obj(); + void *obj = dlobj; delete this; - unload_obj(dlp); + if( obj ) unload(obj); } // Open plugin for signal processing @@ -278,57 +306,61 @@ int PluginServer::open_plugin(int master, this->preferences = preferences; this->plugin = plugin; this->edl = edl; - if( !load_obj() ) { - // add base path if not absolute path - char dl_path[BCTEXTLEN], *dp = dl_path; - char *cp = path; - if( *cp != '/' ) { - char *bp = preferences->plugin_dir; - while( *bp ) *dp++ = *bp++; - *dp++ = '/'; - } - while( *cp ) *dp++ = *cp++; - *dp = 0; - if( !load_obj(dl_path) ) { + if( plugin_type != PLUGIN_TYPE_FFMPEG && plugin_type != PLUGIN_TYPE_EXECUTABLE && !load_obj() ) { // If the load failed it may still be an executable tool for a specific // file format, in which case we just store the path. - set_title(path); - char string[BCTEXTLEN]; - strcpy(string, load_error()); - if(!strstr(string, "executable")) - eprintf("PluginServer::open_plugin: load_obj failure = %s\n", string); + set_title(path); + char string[BCTEXTLEN]; + strcpy(string, load_error()); + if( !strstr(string, "executable") ) { + eprintf("PluginServer::open_plugin: load_obj failure = %s\n", string); return PLUGINSERVER_NOT_RECOGNIZED; } + plugin_type = PLUGIN_TYPE_EXECUTABLE; } - if( !new_plugin && !lad_descriptor ) { + if( plugin_type == PLUGIN_TYPE_UNKNOWN || plugin_type == PLUGIN_TYPE_BUILTIN ) { new_plugin = (PluginClient* (*)(PluginServer*)) load_sym("new_plugin"); - if( !new_plugin ) { - lad_descriptor_function = - (LADSPA_Descriptor_Function) load_sym("ladspa_descriptor"); - if(!lad_descriptor_function) { - fprintf(stderr, "PluginServer::open_plugin " - " %d: new_plugin undefined in %s\n", __LINE__, path); - unload_obj(); - return PLUGINSERVER_NOT_RECOGNIZED; - } + if( new_plugin ) + plugin_type = PLUGIN_TYPE_BUILTIN; + } + if( plugin_type == PLUGIN_TYPE_UNKNOWN || plugin_type == PLUGIN_TYPE_LADSPA ) { + lad_descriptor_function = + (LADSPA_Descriptor_Function) load_sym("ladspa_descriptor"); + if( lad_descriptor_function ) { if( lad_index < 0 ) { unload_obj(); return PLUGINSERVER_IS_LAD; } lad_descriptor = lad_descriptor_function(lad_index); - if(!lad_descriptor) { - unload_obj(); + if( !lad_descriptor ) return PLUGINSERVER_NOT_RECOGNIZED; - } - is_lad = 1; + plugin_type = PLUGIN_TYPE_LADSPA; } } - - client = is_lad ? - (PluginClient *) new PluginAClientLAD(this) : - new_plugin(this); - + if( plugin_type == PLUGIN_TYPE_UNKNOWN ) { + fprintf(stderr, "PluginServer::open_plugin " + " %d: plugin undefined in %s\n", __LINE__, path); + unload_obj(); + return PLUGINSERVER_NOT_RECOGNIZED; + } + switch( plugin_type ) { + case PLUGIN_TYPE_BUILTIN: + client = new_plugin(this); + break; + case PLUGIN_TYPE_LADSPA: + client = new PluginAClientLAD(this); + break; + case PLUGIN_TYPE_FFMPEG: + client = new_ffmpeg_plugin(); + break; + default: + client = 0; + break; + } + if( !client ) + return PLUGINSERVER_NOT_RECOGNIZED; + // Run initialization functions realtime = client->is_realtime(); // Don't load defaults when probing the directory. @@ -393,30 +425,27 @@ void PluginServer::render_stop() void PluginServer::write_table(FILE *fp, int idx) { if(!fp) return; - fprintf(fp, "\"%s\" \"%s\" %d %d %d %d %d %d %d %d %d %d %d %d\n", - path, title, idx, audio, video, theme, realtime, fileio, - uses_gui, multichannel, synthesis, transition, is_lad, lad_index); + fprintf(fp, "%d \"%s\" \"%s\" %d %d %d %d %d %d %d %d %d %d %d\n", + plugin_type, path, title, idx, audio, video, theme, realtime, + fileio, uses_gui, multichannel, synthesis, transition, lad_index); } -char *PluginServer::table_quoted_field(char *&sp) +int PluginServer::scan_table(char *text, int &type, char *path, char *title) { - char *cp = sp; - while( *cp && (*cp == ' ' || *cp == '\t') ) ++cp; - if( *cp++ != '"' ) return 0; - char *bp = cp; - while( *cp && *cp != '"' ) ++cp; - if( *cp != '"' ) return 0; - *cp++ = 0; sp = cp; - return bp; + int n = sscanf(text, "%d \"%[^\"]\" \"%[^\"]\"", &type, path, title); + return n < 3 ? 1 : 0; } int PluginServer::read_table(char *text) { - int n = sscanf(text, "%d %d %d %d %d %d %d %d %d %d %d %d", - &dir_idx, &audio, &video, &theme, &realtime, &fileio, &uses_gui, - &multichannel, &synthesis, &transition, &is_lad, &lad_index); - - return n == 12 ? 0 : 1; + char path[BCTEXTLEN], title[BCTEXTLEN]; + int n = sscanf(text, "%d \"%[^\"]\" \"%[^\"]\" %d %d %d %d %d %d %d %d %d %d %d", + &plugin_type, path, title, &dir_idx, &audio, &video, &theme, &realtime, + &fileio, &uses_gui, &multichannel, &synthesis, &transition, &lad_index); + if( n != 14 ) return 1; + this->path = cstrdup(path); + this->title = cstrdup(title); + return 0; } int PluginServer::init_realtime(int realtime_sched, diff --git a/cinelerra-5.0/cinelerra/pluginserver.h b/cinelerra-5.0/cinelerra/pluginserver.h index 659f64ea..e174ebaa 100644 --- a/cinelerra-5.0/cinelerra/pluginserver.h +++ b/cinelerra-5.0/cinelerra/pluginserver.h @@ -44,6 +44,7 @@ #include "mwindow.inc" #include "plugin.inc" #include "pluginaclientlad.inc" +#include "pluginfclient.inc" #include "pluginclient.inc" #include "pluginserver.inc" #include "preferences.inc" @@ -57,28 +58,19 @@ #include - - -class PluginObj +class PluginServer { + int reset_parameters(); + void init(); + int cleanup_plugin(); + void *dlobj; -public: - PluginObj() { dlobj = 0; } - ~PluginObj() {} - PluginObj(PluginObj &that) { dlobj = 0; } -// dl interface - void *load_obj() { return dlobj; } - void *load_obj(const char *path) { return dlobj = dlopen(path, RTLD_NOW); } - static void unload_obj(void *dlp) { if( dlp ) dlclose(dlp); } - void unload_obj() { unload_obj(dlobj); } + void *load(const char *dlp) { return dlobj = dlopen(dlp, RTLD_NOW); } + void unload(void *obj) { dlclose(obj); } void *load_sym(const char *sym) { return dlsym(dlobj, sym); } const char *load_error() { return dlerror(); } -}; - -class PluginServer : public PluginObj -{ - int reset_parameters(); - int cleanup_plugin(); + void *load_obj(); + void unload_obj(); // Base class created by client PluginClient *client; @@ -87,24 +79,30 @@ class PluginServer : public PluginObj PluginClient* (*new_plugin)(PluginServer*); // LAD support - int is_lad; int lad_index; LADSPA_Descriptor_Function lad_descriptor_function; const LADSPA_Descriptor *lad_descriptor; int use_opengl; +// FFMPEG support + const char *ff_name; // Driver for opengl calls. VideoDevice *vdevice; public: PluginServer(); - PluginServer(char *path, MWindow *mwindow=0); + PluginServer(MWindow *mwindow, char *path, int type); PluginServer(PluginServer &); virtual ~PluginServer(); - friend class PluginAClientLAD; friend class PluginAClientConfig; friend class PluginAClientWindow; + friend class PluginFClient; + friend class PluginFAClient; + friend class PluginFVClient; + friend class PluginFClientConfig; + friend class PluginFClientWindow; + // open a plugin and wait for commands // Get information for plugindb if master. #define PLUGINSERVER_IS_LAD 2 @@ -121,7 +119,7 @@ public: void render_stop(); // Write entry into plugin table void write_table(FILE *fp, int idx); - static char *table_quoted_field(char *&sp); + static int scan_table(char *text, int &type, char *path, char *title); int read_table(char *text); // queries void set_title(const char *string); @@ -151,10 +149,14 @@ public: // Get picon png vframe image VFrame *get_picon(); VFrame *get_plugin_images(); + // ladspa void set_lad_index(int i); int get_lad_index(); int is_ladspa(); +// ffmpeg + int is_ffmpeg(); + PluginClient *new_ffmpeg_plugin(); // =============================== for realtime plugins // save configuration of plugin void save_data(KeyFrame *keyframe); @@ -292,8 +294,8 @@ public: double get_framerate(); // get framerate produced by plugin int get_project_samplerate(); // get samplerate of project data before processing double get_project_framerate(); // get framerate of project data before processing - int set_path(char *path); // required first - char* get_path(); + void set_path(const char *path); // required first + char *get_path(); int get_synthesis(); void get_defaults_path(char *path); void save_defaults(); @@ -321,6 +323,8 @@ public: int64_t get_written_samples(); // after samples are written, get the number written int64_t get_written_frames(); // after frames are written, get the number written +// client origin + int plugin_type; // buffers int64_t out_buffer_size; // size of a send buffer to the plugin diff --git a/cinelerra-5.0/cinelerra/pluginserver.inc b/cinelerra-5.0/cinelerra/pluginserver.inc index 20f3cc2f..505af55c 100644 --- a/cinelerra-5.0/cinelerra/pluginserver.inc +++ b/cinelerra-5.0/cinelerra/pluginserver.inc @@ -22,7 +22,18 @@ #ifndef PLUGINSERVER_INC #define PLUGINSERVER_INC +class PluginObj; class PluginServer; -class PluginGUIServer; + +#define PLUGIN_LADSPA_ID 0 +#define PLUGIN_FFMPEG_ID 1 +#define PLUGIN_IDS 2 + +#define PLUGIN_TYPE_UNKNOWN -1 +#define PLUGIN_TYPE_EXECUTABLE 0 +#define PLUGIN_TYPE_BUILTIN 1 +#define PLUGIN_TYPE_LADSPA 2 +#define PLUGIN_TYPE_FFMPEG 3 +#define PLUGIN_TYPES 4 #endif diff --git a/cinelerra-5.0/cinelerra/vattachmentpoint.C b/cinelerra-5.0/cinelerra/vattachmentpoint.C index fd1bec75..062db5bb 100644 --- a/cinelerra-5.0/cinelerra/vattachmentpoint.C +++ b/cinelerra-5.0/cinelerra/vattachmentpoint.C @@ -106,64 +106,40 @@ void VAttachmentPoint::render(VFrame *output, if(plugin_server->multichannel) { // Test against previous parameters for reuse of previous data - if(is_processed && - this->start_position == start_position && - EQUIV(this->frame_rate, frame_rate)) - { + if( !is_processed || this->start_position != start_position || + !EQUIV(this->frame_rate, frame_rate)) { + is_processed = 1; + this->start_position = start_position; + this->frame_rate = frame_rate; + +// Allocate buffer vector for subsequent render calls + new_buffer_vector(output->get_w(), output->get_h(), + output->get_color_model()); +// Process plugin +//printf("VAttachmentPoint::render 1 %d\n", buffer_number); + if(renderengine) + plugin_servers.values[0]->set_use_opengl(use_opengl, + renderengine->video); + plugin_servers.values[0]->process_buffer(buffer_vector, + start_position, frame_rate, + (int64_t)Units::round(plugin->length * frame_rate / + renderengine->get_edl()->session->frame_rate), + renderengine->command->get_direction()); + } +//printf("VAttachmentPoint::render 3\n"); // Need to copy PBuffer if OpenGL, regardless of use_opengl - if(buffer_vector[buffer_number]->get_opengl_state() == VFrame::RAM) - { - output->copy_from(buffer_vector[buffer_number]); - output->set_opengl_state(VFrame::RAM); - } - else - if(renderengine && renderengine->video) - { + if( buffer_vector[buffer_number]->get_opengl_state() == VFrame::RAM ) { + output->copy_from(buffer_vector[buffer_number]); + output->set_opengl_state(VFrame::RAM); + } + else if(renderengine && renderengine->video) { // Need to copy PBuffer to texture // printf("VAttachmentPoint::render temp=%p output=%p\n", // buffer_vector[buffer_number], // output); - VDeviceX11 *x11_device = (VDeviceX11*)renderengine->video->get_output_base(); - x11_device->copy_frame(output, buffer_vector[buffer_number]); - } - return; - } - - is_processed = 1; - this->start_position = start_position; - this->frame_rate = frame_rate; - -// Allocate buffer vector for subsequent render calls - new_buffer_vector(output->get_w(), - output->get_h(), - output->get_color_model()); - -// Create temporary vector with output argument substituted in - VFrame **output_temp = new VFrame*[virtual_plugins.total]; - for(int i = 0; i < virtual_plugins.total; i++) - { - if(i == buffer_number) - output_temp[i] = output; - else - output_temp[i] = buffer_vector[i]; + VDeviceX11 *x11_device = (VDeviceX11*)renderengine->video->get_output_base(); + x11_device->copy_frame(output, buffer_vector[buffer_number]); } - -// Process plugin -//printf("VAttachmentPoint::render 1 %d\n", buffer_number); - if(renderengine) - plugin_servers.values[0]->set_use_opengl(use_opengl, - renderengine->video); - plugin_servers.values[0]->process_buffer(output_temp, - start_position, - frame_rate, - (int64_t)Units::round(plugin->length * - frame_rate / - renderengine->get_edl()->session->frame_rate), - renderengine->command->get_direction()); -//printf("VAttachmentPoint::render 2\n"); - - delete [] output_temp; -//printf("VAttachmentPoint::render 3\n"); } else // process single track diff --git a/cinelerra-5.0/ffmpeg/plugin.opts b/cinelerra-5.0/ffmpeg/plugin.opts new file mode 100644 index 00000000..e47f86f6 --- /dev/null +++ b/cinelerra-5.0/ffmpeg/plugin.opts @@ -0,0 +1,168 @@ +#abuffer +#abuffersink +#acrossfade +adelay delays=1 +#adrawgraph +aeval exprs=(sin(2*PI*t*440)+sin(2*PI*t*350))/2*mod(floor(2*t),2):channel_layout=1c +#aevalsrc +#afifo +#aformat +#ainterleave +#allrgb +#allyuv +#alphaextract +#alphamerge +#amerge +#amix +#amovie +#anull +#anullsink +#anullsrc +#apad +#aperms +#aphasemeter +aresample sample_rate=48000 +#areverse +#aselect +#asendcmd +#asetnsamples +#asetpts +#asetrate +#asettb +#ashowinfo +#asilencedetect +#asilenceremove +#asplit +#astats +#astreamsync +#atadenoise +#atempo +#atrim +#avectorscope +#bbox +#blackdetect +#blackframe +#blend +#buffer +#buffersink +#cellauto +#channelmap +#channelsplit +chorus in_gain=0.400000:out_gain=0.400000:delays=1|1:decays=1|1:speeds=1|1:depths=1|1 +#codecview +#color +colormatrix src=bt601:dst=smpte240m +#concat +#copy +#cover_rect +#cropdetect +#curves +#dctdnoiz +#decimate +delogo x=1:y=1:w=1:h=1:band=1:show=0 +#detelecine +#drawgraph +#dynaudnorm +#ebur128 +#elbg +equalizer frequency=1000.000000:width_type=1:width=200.000000:gain=-10.000000 +#extractplanes +#ffabuffersink +#ffbuffersink +#fftfilt +#field +#fieldmatch +#fieldorder +#fifo +#find_rect +#fliporder +#format +#fps +#framepack +#framerate +#framestep +#geq +#haldclut +#haldclutsrc +hflip +#hstack +#hue +#idet +#interlace +#interleave +#isdesctest +#join +#life +#lut +#lut3d +#lutrgb +#lutyuv +#mandelbrot +#mergeplanes +#movie +#mpdecimate +#mptestsrc +#noformat +#null +#nullsink +#nullsrc +#overlay +#pad +#palettegen +#paletteuse +#pan +#perms +#pixdesctest +#psnr +#pullup +#qp +#random +#removelogo +#repeatfields +#replaygain +#reverse +#rgbtestsrc +#scale +#scale2ref +#select +#sendcmd +#separatefields +#setdar +#setfield +#setpts +#setsar +#settb +#showcqt +#showfreqs +#showinfo +#showpalette +#showspectrum +#showvolume +#showwaves +#showwavespic +#shuffleplanes +#sidechaincompress +#signalstats +#silencedetect +#silenceremove +#sine +#smptebars +#smptehdbars +#split +#ssim +swapuv +#tblend +#telecine +#testsrc +#thumbnail +#tile +#tinterlace +#trim +#vectorscope +vflip +#volume +#volumedetect +#vstack +#w3fdif +#waveform +#zoompan diff --git a/cinelerra-5.0/guicast/bchash.C b/cinelerra-5.0/guicast/bchash.C index 573c0044..180c70de 100644 --- a/cinelerra-5.0/guicast/bchash.C +++ b/cinelerra-5.0/guicast/bchash.C @@ -48,16 +48,21 @@ BC_Hash::BC_Hash(const char *filename) FileSystem directory; directory.parse_tildas(this->filename); - total = 0; } -BC_Hash::~BC_Hash() +void BC_Hash::clear() { for(int i = 0; i < total; i++) { delete [] names[i]; delete [] values[i]; } + total = 0; +} + +BC_Hash::~BC_Hash() +{ + clear(); delete [] names; delete [] values; } @@ -317,19 +322,8 @@ varFn(int,update,const char *) varFn(char *,get,char *) void BC_Hash::copy_from(BC_Hash *src) { // Can't delete because this is used by file decoders after plugins -// request data. -// for(int i = 0; i < total; i++) -// { -// delete [] names[i]; -// delete [] values[i]; -// } -// delete [] names; -// delete [] values; -// -// allocated = 0; -// names = 0; -// values = 0; -// total = 0; +// request data. use explicit destructor to clear/clean +// this->~BC_Hash(); SET_TRACE reallocate_table(src->total); diff --git a/cinelerra-5.0/guicast/bchash.h b/cinelerra-5.0/guicast/bchash.h index a694f424..36c4a4a3 100644 --- a/cinelerra-5.0/guicast/bchash.h +++ b/cinelerra-5.0/guicast/bchash.h @@ -81,6 +81,7 @@ public: int size(); char* get_key(int number); char* get_value(int number); + void clear(); private: // Reallocate table so at least total entries exist diff --git a/cinelerra-5.0/guicast/vframe.C b/cinelerra-5.0/guicast/vframe.C index e3f5bf0a..99746eb8 100644 --- a/cinelerra-5.0/guicast/vframe.C +++ b/cinelerra-5.0/guicast/vframe.C @@ -1215,8 +1215,7 @@ void VFrame::clear_stacks() { next_effects.remove_all_objects(); prev_effects.remove_all_objects(); - delete params; - params = new BC_Hash; + params->clear(); } void VFrame::copy_params(VFrame *src) @@ -1241,7 +1240,7 @@ void VFrame::copy_stacks(VFrame *src) strcpy(ptr, src->prev_effects.values[i]); } - params->copy_from(src->params); + copy_params(src); } int VFrame::equal_stacks(VFrame *src) diff --git a/cinelerra-5.0/mpeg2enc/Makefile b/cinelerra-5.0/mpeg2enc/Makefile index 1d210846..53578de5 100644 --- a/cinelerra-5.0/mpeg2enc/Makefile +++ b/cinelerra-5.0/mpeg2enc/Makefile @@ -53,7 +53,6 @@ OBJ = \ LIBS = \ ../libzmpeg3/$(OBJDIR)/libzmpeg3.a \ - $(thirdparty_libraries) $(static_libraries) \ -lasound \ -lpthread \ -lpng \ @@ -64,7 +63,9 @@ LIBS = \ -lbz2 \ -lm \ -ldl \ - $(EXTRA_LIBS) + +LIBS += -Wl,--start-group $(thirdparty_libraries) -Wl,--end-group +LIBS += $(EXTRA_LIBS) HVEG2LIB = $(OBJDIR)/hveg2enc.a HVEG2ENC = $(OBJDIR)/hveg2enc diff --git a/cinelerra-5.0/msg.txt b/cinelerra-5.0/msg.txt index 0d785e5e..aea63960 100644 --- a/cinelerra-5.0/msg.txt +++ b/cinelerra-5.0/msg.txt @@ -1,3 +1,12 @@ +add ffmpeg filters as plugins +fix nvidia gl lock problem, update active vwindow tests +fix segv in formattools for record format ffmpeg +add ffmpeg indexing +upgrade to ffmpeg-2.8 +move aspect ratio fixex, better get_info, fixes for ffmpeg asset detection +aspect ratio fixes for dvd/bd create, TZ fix +remove old quicktime, replaced with current ffmpeg +bunch of small fixes, add msg.txt to about prefs sync to last commit on google_code fixups for plugins interpolate, c41 so long, Michael Niedermayer... and thanks for all the fish!!! -- 2.26.2