]> git.decadent.org.uk Git - videolink.git/blobdiff - webdvd.cpp
Separated out dvd_contents and generate_dvd.
[videolink.git] / webdvd.cpp
index eb2a9b2743d28a2a59bdd369af6ab072c25ae16f..8019007deb4fda978bc7533328dbbdcd28bfb169 100644 (file)
@@ -53,6 +53,7 @@
 #include "browser_widget.hpp"
 #include "child_iterator.hpp"
 #include "dvd.hpp"
+#include "generate_dvd.hpp"
 #include "link_iterator.hpp"
 #include "pixbufs.hpp"
 #include "style_sheets.hpp"
@@ -172,60 +173,6 @@ namespace
     }
 
     
-    struct dvd_contents
-    {
-       enum pgc_type { unknown_pgc,  menu_pgc, title_pgc };
-
-       struct pgc_ref
-       {
-           explicit pgc_ref(pgc_type type = unknown_pgc,
-                            int index = -1,
-                            int sub_index = 0)
-                   : type(type), index(index), sub_index(sub_index)
-               {}
-           bool operator==(const pgc_ref & other) const
-               {
-                   return type == other.type && index == other.index;
-               }
-           bool operator!=(const pgc_ref & other) const
-               {
-                   return !(*this == other);
-               }
-           
-           pgc_type type;      // Menu or title reference?
-           unsigned index;     // Menu or title index (within resp. vector)
-           unsigned sub_index; // Button or chapter number (1-based; 0 if
-                               // unspecified; not compared!)
-       };
-
-       struct menu
-       {
-           menu()
-                   : vob_temp(new temp_file("webdvd-vob-"))
-               {
-                   vob_temp->close();
-               }
-
-           boost::shared_ptr<temp_file> vob_temp;
-           std::vector<pgc_ref> entries;
-       };
-
-       struct title
-       {
-           explicit title(const std::string & vob_list)
-                   : vob_list(vob_list)
-               {}
-
-           std::string vob_list;
-       };
-
-       std::vector<menu> menus;
-       std::vector<title> titles;
-    };
-
-    void generate_dvd(const dvd_contents & contents,
-                     const std::string & output_dir);
-
     class webdvd_window : public Gtk::Window
     {
     public:
@@ -837,224 +784,6 @@ namespace
        }
     }
 
-    void generate_dvd(const dvd_contents & contents,
-                     const std::string & output_dir)
-    {
-       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:
-       //
-       // g0:     scratch
-       // g1:     current location
-       // g12:    location that last jumped to a video
-       //
-       // All locations are divided into two bitfields: the least
-       // significant 10 bits are a page/menu number and the most
-       // significant 6 bits are a link/button number, and numbering
-       // starts at 1, not 0.  This is done for compatibility with
-       // the encoding of the s8 (button) register.
-       //
-       static const int button_mult = dvd::reg_s8_button_mult;
-       static const int menu_mask = button_mult - 1;
-       static const int button_mask = (1 << dvd::reg_bits) - button_mult;
-
-       file <<
-           "<dvdauthor>\n"
-           "  <vmgm>\n"
-           "    <menus>\n";
-           
-       for (unsigned menu_num = 0;
-            menu_num != contents.menus.size();
-            ++menu_num)
-       {
-           const dvd_contents::menu & menu = contents.menus[menu_num];
-
-           if (menu_num == 0)
-           {
-               // This is the first (title) menu, displayed when the
-               // disc is first played.
-               file <<
-                   "      <pgc entry='title'>\n"
-                   "        <pre>\n"
-                   // Initialise the current location if it is not set
-                   // (all general registers are initially 0).
-                   "          if (g1 eq 0)\n"
-                   "            g1 = " << 1 + button_mult << ";\n";
-           }
-           else
-           {
-               file <<
-                   "      <pgc>\n"
-                   "        <pre>\n";
-           }
-
-           // When a title finishes or the user presses the menu
-           // button, this always jumps to the titleset's root menu.
-           // We want to return the user to the last menu they used.
-           // So we arrange for each titleset's root menu to return
-           // to the vmgm title menu and then dispatch from there to
-           // whatever the correct menu is.  We determine the correct
-           // menu by looking at the menu part of g1.
-
-           file << "          g0 = g1 &amp; " << menu_mask << ";\n";
-
-           // There is a limit of 128 VM instructions in each PGC.
-           // Therefore in each menu's <pre> section we generate
-           // jumps to menus with numbers greater by 512, 256, 128,
-           // ..., 1 where (a) such a menu exists, (b) this menu
-           // number is divisible by twice that increment and (c) the
-           // correct menu is that or a later menu.  Thus each menu
-           // has at most 10 such conditional jumps and is reachable
-           // by at most 10 jumps from the title menu.  This chain of
-           // jumps might take too long on some players; this has yet
-           // to be investigated.
-           
-           for (std::size_t menu_incr = (menu_mask + 1) / 2;
-                menu_incr != 0;
-                menu_incr /= 2)
-           {
-               if (menu_num + menu_incr < contents.menus.size()
-                   && (menu_num & (menu_incr * 2 - 1)) == 0)
-               {
-                   file <<
-                       "          if (g0 ge " << 1 + menu_num + menu_incr
-                                              << ")\n"
-                       "            jump menu " << 1 + menu_num + menu_incr
-                                              << ";\n";
-               }
-           }
-
-           file <<
-               // Highlight the appropriate button.
-               "          s8 = g1 &amp; " << button_mask << ";\n"
-               "        </pre>\n"
-               "        <vob file='" << menu.vob_temp->get_name() << "'/>\n";
-
-           for (unsigned button_num = 0;
-                button_num != menu.entries.size();
-                ++button_num)
-           {
-               const dvd_contents::pgc_ref & target =
-                   menu.entries[button_num];
-
-               file << "        <button> ";
-
-               if (target.type == dvd_contents::menu_pgc)
-               {
-                   unsigned target_button_num;
-
-                   if (target.sub_index)
-                   {
-                       target_button_num = target.sub_index;
-                   }
-                   else
-                   {
-                       // Look for a button on the new menu that links
-                       // back to this one.  If there is one, set that to
-                       // be the highlighted button; otherwise, use the
-                       // first button.
-                       const std::vector<dvd_contents::pgc_ref> &
-                           target_menu_entries =
-                           contents.menus[target.index].entries;
-                       dvd_contents::pgc_ref this_pgc(dvd_contents::menu_pgc,
-                                                      menu_num);
-                       target_button_num = target_menu_entries.size();
-                       while (target_button_num != 0
-                              && (target_menu_entries[--target_button_num]
-                                  != this_pgc))
-                           ;
-                       target_button_num += 1;
-                   }
-                        
-                   file << "g1 = "
-                        << (1 + target.index
-                            + target_button_num * button_mult)
-                        << "; jump menu " << 1 + target.index << ";";
-               }
-               else
-               {
-                   assert(target.type == dvd_contents::title_pgc);
-
-                   file << "g1 = "
-                        << 1 + menu_num + (1 + button_num) * button_mult
-                        << "; jump title "
-                        << 1 + target.index;
-                   if (target.sub_index)
-                       file << " chapter " << target.sub_index;
-                   file << ";";
-               }
-
-               file <<  " </button>\n";
-           }
-
-           file << "      </pgc>\n";
-       }
-
-       file <<
-           "    </menus>\n"
-           "  </vmgm>\n";
-
-       // Generate a titleset for each title.  This appears to make
-       // jumping to titles a whole lot simpler (but limits us to 99
-       // titles).
-       for (unsigned title_num = 0;
-            title_num != contents.titles.size();
-            ++title_num)
-       {
-           file <<
-               "  <titleset>\n"
-               // Generate a dummy menu so that the menu button on the
-               // remote control will work.
-               "    <menus>\n"
-               "      <pgc entry='root'>\n"
-               "        <pre> jump vmgm menu; </pre>\n"
-               "      </pgc>\n"
-               "    </menus>\n"
-               "    <titles>\n"
-               "      <pgc>\n"
-               // Record calling location.
-               "        <pre> g12 = g1; </pre>\n"
-                << contents.titles[title_num].vob_list <<
-               // If the menu location has not been changed during
-               // the title, set the location to be the following
-               // button in the menu.  In any case, return to some
-               // menu.
-               "        <post> if (g1 eq g12) g1 = g1 + " << button_mult
-                << "; call menu; </post>\n"
-               "      </pgc>\n"
-               "    </titles>\n"
-               "  </titleset>\n";
-       }
-
-       file <<
-           "</dvdauthor>\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<std::string>(
-                                argv, sizeof(argv)/sizeof(argv[0]),
-                                Glib::OWNERSHIP_NONE),
-                            Glib::SPAWN_SEARCH_PATH
-                            | Glib::SPAWN_STDOUT_TO_DEV_NULL,
-                            SigC::Slot0<void>(),
-                            0, 0,
-                            &command_result);
-           if (command_result != 0)
-               throw std::runtime_error("dvdauthor failed");
-       }
-    }
-
     const video::frame_params & lookup_frame_params(const char * str)
     {
        assert(str);