From 5930ed6745ac9167ebae2e506671e4ce88c1dfe6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 27 Nov 2005 21:16:05 +0000 Subject: [PATCH] Changed WebDvdWindow to generate temporary files in the proper way, spawn external programs and clean up temporary files when it's done. --- Makefile | 16 ++---- README | 69 ++++++++---------------- TODO | 2 - debian/control | 11 ++-- webdvd.cpp | 143 ++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 141 insertions(+), 100 deletions(-) diff --git a/Makefile b/Makefile index 92f82ae..be6565e 100644 --- a/Makefile +++ b/Makefile @@ -25,14 +25,15 @@ endif cxxsources := \ auto_proc.cpp browserwidget.cpp childiterator.cpp framebuffer.cpp \ - linkiterator.cpp pixbufs.cpp stylesheets.cpp webdvd.cpp xpcom_support.cpp + linkiterator.cpp pixbufs.cpp stylesheets.cpp temp_file.cpp video.cpp \ + webdvd.cpp xpcom_support.cpp csources := jquant2.c webdvd : $(cxxsources:.cpp=.o) $(csources:.c=.o) $(CXX) $(LDFLAGS) -o $@ $^ clean : - rm -f webdvd *.d *.o *~ .\#* *.orig *.rej svn-commit*.tmp *.dvdauthor *.png *.vob *.spumux + rm -f webdvd *.d *.o *~ .\#* *.orig *.rej svn-commit*.tmp distclean : clean rm -rf .svn @@ -48,7 +49,7 @@ browserwidget.% : CPPFLAGS += -DMOZ_LIB_DIR='"$(moz_lib_dir)"' webdvd.% : CPPFLAGS += -DWEBDVD_LIB_DIR='"$(webdvd_lib_dir)"' -browserwidget.% pixbufs.% webdvd.% \ +browserwidget.% pixbufs.% temp_file.% webdvd.% \ : CPPFLAGS += $(shell pkg-config --cflags gtkmm-2.0) browserwidget.% childiterator.o linkiterator.% stylesheets.% webdvd.% \ @@ -69,12 +70,3 @@ linkiterator.% stylesheets.% webdvd.% \ ifneq ($(MAKECMDGOALS),clean) include $(cxxsources:.cpp=.d) $(csources:.c=.d) endif - -# Temporary rule for testing output files. - -%.vob : %_back.png %.spumux %_links.png - pngtopnm $*_back.png \ - | ppmtoy4m -v0 -n 1 -F 25:1 -A 59:54 -I p -S 420_mpeg2 \ - | mpeg2enc -v0 -f 8 -a 2 -o /dev/stdout \ - | mplex -v0 -f 8 -o /dev/stdout /dev/stdin \ - | spumux -v0 -m dvd $*.spumux > $@ diff --git a/README b/README index ec6534a..9e3b82b 100644 --- a/README +++ b/README @@ -5,26 +5,23 @@ WebDVD is intended to provide a simple way of producing DVDs with attractive and usable menus. It converts HTML pages into DVD menus by rendering them in Mozilla and reproducing their link structure. This allows you to design DVDs using familiar HTML editing tools or your -favourite text editor. This very early version produces a set of -files suitable for passing to the "dvdauthor" and "spumux" programs, -but in future it is intended to run the necessary external programs -automatically. +favourite text editor. Requirements ------------ WebDVD depends on the following software: +- dvdauthor - Gtkmm 2.0 +- mjpegtools - Mozilla 1.7.x (later versions may work but are untested) +- netpbm - Xvfb (from XFree86 or X.org) To build a complete DVD image you will also need: -- dvdauthor -- mjpegtools - mkisofs -- netpbm You will also need a program such as ffmpeg or mencoder for producing DVD-suitable MPEG-1 or MPEG-2 video files. @@ -32,47 +29,23 @@ DVD-suitable MPEG-1 or MPEG-2 video files. Usage ----- -Run "webdvd URL" where URL is the URL for the page that is to be the -top menu of the DVD. It will automatically follow links to other -pages and to video files, rendering each page. You must be careful -not to link to pages that you do not want to appear on the disc, such -as normal web sites. - -By default, webdvd uses a frame size of 720x576, which is suitable for -PAL DVDs. If you wish to produce NTSC DVDs you must override this -by adding the option "-geometry 720x480". - -This will create the following files (with NNNNNN replaced with each -successive page number): - -- webdvd.dvdauthor: This is an XML file to be passed to dvdauthor. -- page_NNNNNN.spumux: These are XML files to be passed to spumux. -- page_NNNNNN_back.png: This is a static image of the page, which - becomes the menu background. -- page_NNNNNN_links.png: This is an image of the change in appearance - of each link when the pointer is over it. - -Currently, you must run commands along the following lines to produce -a complete DVD image: - -for spumux in page_??????.spumux; do - page=$(basename $spumux .spumux) - pngtopnm ${page}_back.png \ - | ppmtoy4m -v0 -n 1 -F 25:1 -A 59:54 -I p -S 420_mpeg2 \ - | mpeg2enc -v0 -f 8 -a 2 -o /dev/stdout \ - | mplex -v0 -f 8 -o /dev/stdout /dev/stdin \ - | spumux -v0 -m dvd $spumux > ${page}.vob -done -rm -rf dvd-temp -dvdauthor -o dvd-temp -x webdvd.dvdauthor -mkisofs -dvd-video dvd-temp >dvd.iso -rm -rf dvd-temp - -Adjust the name of the temporary directory (here "dvd-temp") and the -output file ("dvd.iso") as you please. - -If you are using NTSC video, you will need to change the ppmtoy4m -parameters. Use "-F 30000:1001 -A 10:11" instead of "-F 25:1 -A 59:54". +Run "webdvd URL DIR" where URL is the URL for the page that is to be +the top menu of the DVD and DIR is the directory in which to create +the DVD filesystem (which should be missing or empty). It will +automatically follow links to other pages and to video files, +rendering each page. You must be careful not to link to pages that +you do not want to appear on the disc, such as normal web sites. + +By default, webdvd generates PAL/SECAM video. If you wish to produce +NTSC DVDs you can override this by adding the option "--video-std ntsc". + +If webdvd runs successfully you can use mkisofs to create a DVD image: + + mkisofs -dvd-video DIR > IMAGE + rm -rf DIR + +Alternately you can write the filesystem directly to a writable DVD +with growisofs or mkisofs plus a suitable version of cdrecord. Limitations ----------- diff --git a/TODO b/TODO index f57b53d..edce53e 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ -Call spumux. Disable scrollbars (not sure how how to do this). -Call dvdauthor. May need to override default menu navigation actions because dvdauthor seems to cause rather undesirable behaviour when buttons are not arranged in a grid. diff --git a/debian/control b/debian/control index 284ffce..921e18e 100644 --- a/debian/control +++ b/debian/control @@ -2,19 +2,16 @@ Source: webdvd Maintainer: Ben Hutchings Section: graphics Priority: extra -Build-Depends: debhelper (>=4), libgtkmm2.0-dev, mozilla-dev +Build-Depends: debhelper (>=4), libboost-dev, libgtkmm2.0-dev, mozilla-dev Standards-Version: 3.6.2 Package: webdvd Architecture: any -Depends: xvfb, xfonts-base, ${shlibs:Depends}, ${mozilla:Depends} -Recommends: dvdauthor, mjpegtools, mkisofs, netpbm +Depends: xvfb, xfonts-base, dvdauthor, mjpegtools, netpbm, ${shlibs:Depends}, ${mozilla:Depends} +Recommends: mkisofs Description: Converts HTML pages into DVD menus. WebDVD is intended to provide a simple way of producing DVDs with attractive and usable menus. It converts HTML pages into DVD menus by rendering them in Mozilla and reproducing their link structure. This allows you to design DVDs using familiar HTML editing tools or your - favourite text editor. This very early version produces a set of - files suitable for passing to the "dvdauthor" and "spumux" programs, - but in future it is intended to run the necessary external programs - automatically. + favourite text editor. diff --git a/webdvd.cpp b/webdvd.cpp index a6d456a..a6064b2 100644 --- a/webdvd.cpp +++ b/webdvd.cpp @@ -9,12 +9,17 @@ #include #include #include +#include #include #include #include +#include + #include +#include +#include #include #include @@ -48,6 +53,7 @@ #include "linkiterator.hpp" #include "pixbufs.hpp" #include "stylesheets.hpp" +#include "temp_file.hpp" #include "video.hpp" #include "xpcom_support.hpp" @@ -135,7 +141,8 @@ namespace public: WebDvdWindow( const video::frame_params & frame_params, - const std::string & main_page_uri); + const std::string & main_page_uri, + const std::string & output_dir); private: void add_page(const std::string & uri); @@ -146,11 +153,12 @@ namespace void process_links(nsIPresShell * pres_shell, nsIPresContext * pres_context, nsIDOMWindow * dom_window); - void generate_dvdauthor_file(); + void generate_dvd(); enum ResourceType { page_resource, video_resource }; typedef std::pair ResourceEntry; video::frame_params frame_params_; + std::string output_dir_; BrowserWidget browser_widget_; nsCOMPtr stylesheet_; std::queue page_queue_; @@ -159,14 +167,18 @@ namespace std::vector video_paths_; bool loading_; int pending_req_count_; + std::auto_ptr background_temp_; struct link_state; std::auto_ptr link_state_; + std::vector > page_temp_files_; }; WebDvdWindow::WebDvdWindow( const video::frame_params & frame_params, - const std::string & main_page_uri) + const std::string & main_page_uri, + const std::string & output_dir) : frame_params_(frame_params), + output_dir_(output_dir), stylesheet_(load_css("file://" WEBDVD_LIB_DIR "/webdvd.css")), loading_(false), pending_req_count_(0) @@ -282,7 +294,7 @@ namespace page_queue_.pop(); if (page_queue_.empty()) { - generate_dvdauthor_file(); + generate_dvd(); Gtk::Main::quit(); } else @@ -303,25 +315,29 @@ namespace void WebDvdWindow::save_screenshot() { - char filename[25]; - std::sprintf(filename, "page_%06d_back.png", page_links_.size()); Glib::RefPtr window(get_window()); assert(window); window->process_updates(true); - std::cout << "saving " << filename << std::endl; + + background_temp_.reset(new temp_file("webdvd-back-")); + background_temp_->close(); + std::cout << "saving " << background_temp_->get_name() << std::endl; Gdk::Pixbuf::create(Glib::RefPtr(window), window->get_colormap(), 0, 0, 0, 0, frame_params_.width, frame_params_.height) - ->save(filename, "png"); + ->save(background_temp_->get_name(), "png"); } struct WebDvdWindow::link_state { Glib::RefPtr diff_pixbuf; + std::auto_ptr spumux_temp; std::ofstream spumux_file; + std::auto_ptr links_temp; + int link_num; LinkIterator links_it, links_end; @@ -363,20 +379,21 @@ namespace true, 8, // has_alpha, bits_per_sample frame_params_.width, frame_params_.height); - char spumux_filename[20]; - std::sprintf(spumux_filename, - "page_%06d.spumux", page_links_.size()); - state->spumux_file.open(spumux_filename); + state->spumux_temp.reset(new temp_file("webdvd-spumux-")); + state->spumux_temp->close(); + + state->links_temp.reset(new temp_file("webdvd-links-")); + state->links_temp->close(); + + state->spumux_file.open(state->spumux_temp->get_name().c_str()); state->spumux_file << "\n" " \n" " \n"; + " highlight='" << state->links_temp->get_name() + << "'\n" + " select='" << state->links_temp->get_name() + << "'>\n"; state->link_num = 0; state->links_it = LinkIterator(basic_doc); @@ -547,23 +564,65 @@ namespace quantise_rgba_pixbuf(state->diff_pixbuf, dvd::button_n_colours); - char filename[25]; - std::sprintf(filename, "page_%06d_links.png", page_links_.size()); - std::cout << "saving " << filename << std::endl; - state->diff_pixbuf->save(filename, "png"); + std::cout << "saving " << state->links_temp->get_name() + << std::endl; + state->diff_pixbuf->save(state->links_temp->get_name(), "png"); state->spumux_file << " \n" " \n" "\n"; + + state->spumux_file.close(); + + // TODO: if (!state->spumux_file) throw ... + + { + boost::shared_ptr vob_temp( + new temp_file("webdvd-vob-")); + std::ostringstream command_stream; + command_stream << "pngtopnm " + << background_temp_->get_name() + << " | ppmtoy4m -v0 -n1 -F" + << frame_params_.rate_numer + << ":" << frame_params_.rate_denom + << " -A" << frame_params_.pixel_ratio_width + << ":" << frame_params_.pixel_ratio_height + << (" -Ip -S420_mpeg2" + " | mpeg2enc -v0 -f8 -a2 -o/dev/stdout" + " | mplex -v0 -f8 -o/dev/stdout /dev/stdin" + " | spumux -v0 -mdvd ") + << state->spumux_temp->get_name() + << " > " << vob_temp->get_name(); + std::string command(command_stream.str()); + const char * argv[] = { + "/bin/sh", "-c", command.c_str(), 0 + }; + std::cout << "running " << argv[2] << std::endl; + int command_result; + Glib::spawn_sync(".", + Glib::ArrayHandle( + argv, sizeof(argv)/sizeof(argv[0]), + Glib::OWNERSHIP_NONE), + Glib::SPAWN_STDOUT_TO_DEV_NULL, + SigC::Slot0(), + 0, 0, + &command_result); + if (command_result != 0) + throw std::runtime_error("spumux pipeline failed"); + + page_temp_files_.push_back(vob_temp); + } } void generate_page_dispatch(std::ostream &, int indent, int first_page, int last_page); - void WebDvdWindow::generate_dvdauthor_file() + void WebDvdWindow::generate_dvd() { - std::ofstream file("webdvd.dvdauthor"); + temp_file temp("webdvd-dvdauthor-"); + temp.close(); + std::ofstream file(temp.get_name().c_str()); // We generate code that uses registers in the following way: // @@ -657,9 +716,8 @@ namespace // appropriate link/button. " g0 = 0; s8 = g1 & " << link_mask << ";\n" " \n" - " \n"; + " \n"; for (std::size_t link_num = 1; link_num <= page_links.size(); @@ -725,6 +783,29 @@ namespace file << "\n"; + + file.close(); + + { + const char * argv[] = { + "dvdauthor", + "-o", output_dir_.c_str(), + "-x", temp.get_name().c_str(), + 0 + }; + int command_result; + Glib::spawn_sync(".", + Glib::ArrayHandle( + argv, sizeof(argv)/sizeof(argv[0]), + Glib::OWNERSHIP_NONE), + Glib::SPAWN_SEARCH_PATH + | Glib::SPAWN_STDOUT_TO_DEV_NULL, + SigC::Slot0(), + 0, 0, + &command_result); + if (command_result != 0) + throw std::runtime_error("dvdauthor failed"); + } } void generate_page_dispatch(std::ostream & file, int indent, @@ -819,7 +900,7 @@ int main(int argc, char ** argv) // Initialise Gtk Gtk::Main kit(argc, argv); - + // Check we have the right number of arguments. We can't // do this earlier because we need to let Gtk read and remove // any of the many options it understands. @@ -843,18 +924,18 @@ int main(int argc, char ** argv) else break; } - if (argi != argc - 1) + if (argi != argc - 2) { std::cerr << "Usage: " << argv[0] << (" [gtk-options] [--video-std std-name]" - "front-page-url\n"); + "front-page-url output-dir\n"); return EXIT_FAILURE; } // Initialise Mozilla BrowserWidget::init(); - WebDvdWindow window(frame_params, argv[argi]); + WebDvdWindow window(frame_params, argv[argi], argv[argi + 1]); Gtk::Main::run(window); } catch (std::exception & e) -- 2.39.2