X-Git-Url: https://git.decadent.org.uk/gitweb/?p=videolink.git;a=blobdiff_plain;f=webdvd.cpp;h=f8e44005f204f24bcd80a7196e126dad7ff97c6b;hp=43f54c7021a703b8be936cb8280548239dfee6f0;hb=388aa3e7fbf7d7586c998833ab53712a88c8d46a;hpb=c13714f6498df33e02635421354f5fb88a60eb3d diff --git a/webdvd.cpp b/webdvd.cpp index 43f54c7..f8e4400 100644 --- a/webdvd.cpp +++ b/webdvd.cpp @@ -55,6 +55,7 @@ #include "dvd.hpp" #include "generate_dvd.hpp" #include "link_iterator.hpp" +#include "null_prompt_service.hpp" #include "pixbufs.hpp" #include "style_sheets.hpp" #include "temp_file.hpp" @@ -67,6 +68,14 @@ using xpcom_support::check; namespace { + // We can try using any of these encoders to convert PNG to MPEG. + enum mpeg_encoder + { + mpeg_encoder_ffmpeg, // ffmpeg + mpeg_encoder_mjpegtools_old, // mjpegtools before version 1.8 + mpeg_encoder_mjpegtools_new // mjpegtools from version 1.8 + }; + struct rectangle { int left, top; // inclusive @@ -151,7 +160,10 @@ namespace webdvd_window( const video::frame_params & frame_params, const std::string & main_page_uri, - const std::string & output_dir); + const std::string & output_dir, + mpeg_encoder encoder); + + bool is_finished() const; private: dvd_contents::pgc_ref add_menu(const std::string & uri); @@ -170,6 +182,7 @@ namespace video::frame_params frame_params_; std::string output_dir_; + mpeg_encoder encoder_; browser_widget browser_widget_; nsCOMPtr stylesheet_; @@ -184,18 +197,23 @@ namespace std::auto_ptr background_temp_; struct page_state; std::auto_ptr page_state_; + + bool finished_; }; webdvd_window::webdvd_window( const video::frame_params & frame_params, const std::string & main_page_uri, - const std::string & output_dir) + const std::string & output_dir, + mpeg_encoder encoder) : frame_params_(frame_params), output_dir_(output_dir), + encoder_(encoder), stylesheet_(load_css("file://" WEBDVD_LIB_DIR "/webdvd.css")), pending_window_update_(false), pending_req_count_(0), - have_tweaked_page_(false) + have_tweaked_page_(false), + finished_(false) { set_size_request(frame_params_.width, frame_params_.height); set_resizable(false); @@ -209,6 +227,11 @@ namespace load_next_page(); } + bool webdvd_window::is_finished() const + { + return finished_; + } + dvd_contents::pgc_ref webdvd_window::add_menu(const std::string & uri) { dvd_contents::pgc_ref next_menu(dvd_contents::menu_pgc, @@ -356,7 +379,10 @@ namespace try { if (!process_page()) + { + finished_ = true; Gtk::Main::quit(); + } } catch (std::exception & e) { @@ -721,20 +747,45 @@ namespace { 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() - << " > " - << contents_.menus[menu_num].vob_temp->get_name(); + if (encoder_ == mpeg_encoder_ffmpeg) + { + command_stream + << "ffmpeg" + << " -f image2 -vcodec png -i " + << background_temp_->get_name() + << " -target " << frame_params_.ffmpeg_name << "-dvd" + << " -vcodec mpeg2video -an -y /dev/stdout" + << " | spumux -v0 -mdvd " << state->spumux_temp.get_name() + << " > " << contents_.menus[menu_num].vob_temp->get_name(); + } + else + { + assert(encoder_ == mpeg_encoder_mjpegtools_old + || encoder_ == mpeg_encoder_mjpegtools_new); + 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 "; + // The chroma subsampling keywords changed between + // versions 1.6.2 and 1.8 of mjpegtools. There is no + // keyword that works with both. + if (encoder_ == mpeg_encoder_mjpegtools_old) + command_stream << "-S420_mpeg2"; + else + command_stream << "-S420mpeg2"; + command_stream + << (" | mpeg2enc -v0 -f8 -a2 -o/dev/stdout" + " | mplex -v0 -f8 -o/dev/stdout /dev/stdin" + " | spumux -v0 -mdvd ") + << state->spumux_temp.get_name() + << " > " + << contents_.menus[menu_num].vob_temp->get_name(); + } std::string command(command_stream.str()); const char * argv[] = { "/bin/sh", "-c", command.c_str(), 0 @@ -757,31 +808,31 @@ namespace const video::frame_params & lookup_frame_params(const char * str) { assert(str); - static const struct { const char * str; bool is_ntsc; } - known_strings[] = { - { "NTSC", true }, - { "ntsc", true }, - { "PAL", false }, - { "pal", false }, - // For DVD purposes, SECAM can be treated identically to PAL. - { "SECAM", false }, - { "secam", false } + static const char * const known_strings[] = { + "525", "625", + "525/60", "625/50", + "NTSC", "PAL", + "ntsc", "pal" }; for (std::size_t i = 0; i != sizeof(known_strings)/sizeof(known_strings[0]); ++i) - if (std::strcmp(str, known_strings[i].str) == 0) - return known_strings[i].is_ntsc ? - video::ntsc_params : video::pal_params; + if (std::strcmp(str, known_strings[i]) == 0) + return (i & 1) + ? video::frame_params_625 + : video::frame_params_525; throw std::runtime_error( std::string("Invalid video standard: ").append(str)); } void print_usage(std::ostream & stream, const char * command_name) { - stream << "Usage: " << command_name - << (" [gtk-options] [--video-std std-name]" - " [--preview] menu-url [output-dir]\n"); + stream << + "Usage: " << command_name << " [gtk-options] [--preview]\n" + " [--video-std {525|525/60|NTSC|ntsc" + " | 625|625/50|PAL|pal}]\n" + " [--encoder {mjpegtools|mjpegtools-old}]\n" + " menu-url [output-dir]\n"; } void set_browser_preferences() @@ -819,14 +870,21 @@ namespace } // namespace +void fatal_error(const std::string & message) +{ + std::cerr << "Fatal error: " << message << "\n"; + Gtk::Main::quit(); +} + int main(int argc, char ** argv) { try { - video::frame_params frame_params = video::pal_params; + video::frame_params frame_params = video::frame_params_625; bool preview_mode = false; std::string menu_url; std::string output_dir; + mpeg_encoder encoder = mpeg_encoder_ffmpeg; // Do initial option parsing. We have to do this before // letting Gtk parse the arguments since we may need to spawn @@ -898,6 +956,40 @@ int main(int argc, char ** argv) { argi += 2; } + else if (std::strcmp(argv[argi], "--save-temps") == 0) + { + temp_file::keep_all(true); + argi += 1; + } + else if (std::strcmp(argv[argi], "--encoder") == 0) + { + if (argi + 1 == argc) + { + std::cerr << "Missing argument to --encoder\n"; + print_usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + if (std::strcmp(argv[argi + 1], "ffmpeg") == 0) + { + encoder = mpeg_encoder_ffmpeg; + } + else if (std::strcmp(argv[argi + 1], "mjpegtools-old") == 0) + { + encoder = mpeg_encoder_mjpegtools_old; + } + else if (std::strcmp(argv[argi + 1], "mjpegtools") == 0 + || std::strcmp(argv[argi + 1], "mjpegtools-new") == 0) + { + encoder = mpeg_encoder_mjpegtools_new; + } + else + { + std::cerr << "Invalid argument to --encoder\n"; + print_usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + argi += 2; + } else if (argv[argi][0] == '-') { std::cerr << "Invalid option: " << argv[argi] << "\n"; @@ -936,16 +1028,20 @@ int main(int argc, char ** argv) // Initialise Mozilla browser_widget::initialiser browser_init; set_browser_preferences(); + if (!preview_mode) + null_prompt_service::install(); // Run the browser/converter - webdvd_window window(frame_params, menu_url, output_dir); + webdvd_window window(frame_params, menu_url, output_dir, encoder); Gtk::Main::run(window); + + return ((preview_mode || window.is_finished()) + ? EXIT_SUCCESS + : EXIT_FAILURE); } catch (std::exception & e) { std::cerr << "Fatal error: " << e.what() << "\n"; return EXIT_FAILURE; } - - return EXIT_SUCCESS; }