]> git.decadent.org.uk Git - videolink.git/blobdiff - webdvd.cpp
Use ffmpeg by default since it seems to work if we use pause correctly.
[videolink.git] / webdvd.cpp
index 9c26c8fb20ef13df89ffc2ab9c6ea34a57c46282..f8e44005f204f24bcd80a7196e126dad7ff97c6b 100644 (file)
@@ -68,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
@@ -152,7 +160,8 @@ 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;
 
@@ -173,6 +182,7 @@ namespace
 
        video::frame_params frame_params_;
        std::string output_dir_;
+       mpeg_encoder encoder_;
        browser_widget browser_widget_;
        nsCOMPtr<nsIStyleSheet> stylesheet_;
 
@@ -194,9 +204,11 @@ namespace
     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),
@@ -735,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
@@ -771,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()
@@ -843,10 +880,11 @@ 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
@@ -923,6 +961,35 @@ int main(int argc, char ** argv)
                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";
@@ -965,7 +1032,7 @@ int main(int argc, char ** argv)
            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())