Merge branch 'cairocanvas' of git.ardour.org:ardour/ardour into cairocanvas
[ardour.git] / gtk2_ardour / utils_videotl.cc
1 /*
2     Copyright (C) 2010-2013 Paul Davis
3     Author: Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #include <cstdio>
21 #include <string>
22 #include <cerrno>
23 #include <gtkmm.h>
24 #include <curl/curl.h>
25
26 #include "pbd/error.h"
27 #include "ardour/ardour.h"
28 #include "ardour/session_directory.h"
29 #include "video_image_frame.h"
30 #include "utils_videotl.h"
31
32 #include "i18n.h"
33
34 using namespace Gtk;
35 using namespace std;
36 using namespace PBD;
37 using namespace ARDOUR;
38
39 bool
40 confirm_video_outfn (std::string outfn, std::string docroot)
41 {
42         /* replace docroot's '/' to G_DIR_SEPARATOR for the comparison */
43         size_t look_here = 0;
44         size_t found_here;
45         const char ds = G_DIR_SEPARATOR;
46         while((found_here = docroot.find('/', look_here)) != string::npos) {
47                 docroot.replace(found_here, 1, std::string(&ds, 1));
48                 look_here = found_here + 1;
49         }
50
51         if (!docroot.empty() && docroot.compare(0, docroot.length(), outfn, 0, docroot.length())) {
52                 ArdourDialog confirm (_("Destination is outside Video Server's docroot. "), true);
53                 Label m (_("The destination file path is outside of the Video Server's docroot. The file will not be readable by the Video Server. Do you still want to continue?"));
54                 confirm.get_vbox()->pack_start (m, true, true);
55                 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
56                 confirm.add_button (_("Continue"), Gtk::RESPONSE_ACCEPT);
57                 confirm.show_all ();
58                 if (confirm.run() == RESPONSE_CANCEL) { return false; }
59         }
60
61         if (Glib::file_test(outfn, Glib::FILE_TEST_EXISTS)) {
62                 ArdourDialog confirm (_("Confirm Overwrite"), true);
63                 Label m (_("A file with the same name already exists.  Do you want to overwrite it?"));
64                 confirm.get_vbox()->pack_start (m, true, true);
65                 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
66                 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
67                 confirm.show_all ();
68                 if (confirm.run() == RESPONSE_CANCEL) { return false; }
69         }
70
71         std::string dir = Glib::path_get_dirname (outfn);
72         if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
73                 error << string_compose(_("Cannot create video folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
74                 return false;
75         }
76         return true;
77 }
78
79 std::string
80 video_dest_dir (const std::string sessiondir, const std::string docroot)
81 {
82         std::string dir = docroot;
83         if (dir.empty() || !dir.compare(0, dir.length(), sessiondir, 0, dir.length())) {
84                 dir=sessiondir;
85         }
86         if ((dir.empty() || dir.at(dir.length()-1) != G_DIR_SEPARATOR)) { dir += G_DIR_SEPARATOR; }
87
88         if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
89                 error << string_compose(_("Cannot create video folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
90         }
91         return dir;
92 }
93
94 std::string
95 video_get_docroot (ARDOUR::RCConfiguration* config)
96 {
97         if (config->get_video_advanced_setup()) {
98                 return config->get_video_server_docroot();
99         }
100         return X_("/");
101 }
102
103 std::string
104 video_get_server_url (ARDOUR::RCConfiguration* config)
105 {
106         if (config->get_video_advanced_setup()) {
107                 return config->get_video_server_url();
108         }
109         return X_("http://localhost:1554");
110 }
111
112
113 std::string
114 strip_file_extension (const std::string infile)
115 {
116         std::string rv;
117         char *ext, *bn = strdup(infile.c_str());
118         if ((ext=strrchr(bn, '.'))) {
119                 if (!strchr(ext, G_DIR_SEPARATOR)) {
120                         *ext = 0;
121                 }
122         }
123         rv = std::string(bn);
124         free(bn);
125         return rv;
126 }
127
128 std::string
129 get_file_extension (const std::string infile)
130 {
131         std::string rv = "";
132         char *ext, *bn = strdup(infile.c_str());
133         if ((ext=strrchr(bn, '.'))) {
134                 if (!strchr(ext, G_DIR_SEPARATOR)) {
135                         rv=std::string(ext+1);
136                 }
137         }
138         free(bn);
139         return rv;
140 }
141
142 std::string
143 video_dest_file (const std::string dir, const std::string infile)
144 {
145         return dir + "a3_" + strip_file_extension(Glib::path_get_basename(infile)) + ".avi";
146 }
147
148 std::string
149 video_map_path (std::string server_docroot, std::string filepath)
150 {
151         std::string rv = filepath;
152
153         /* replace all G_DIR_SEPARATOR with '/' */
154         size_t look_here = 0;
155         size_t found_here;
156         while((found_here = rv.find(G_DIR_SEPARATOR, look_here)) != string::npos) {
157                 rv.replace(found_here, 1, "/");
158                 look_here = found_here + 1;
159         }
160
161         /* strip docroot */
162         if (server_docroot.length() > 0) {
163                 if (rv.compare(0, server_docroot.length(), server_docroot) == 0 ) {
164                         rv = rv.substr(server_docroot.length());
165                 }
166         }
167
168         CURL *curl;
169         char *ue;
170         curl = curl_easy_init();
171         ue = curl_easy_escape(curl, rv.c_str(),rv.length());
172         if (ue) {
173                 rv = std::string(ue);
174                 curl_free(ue);
175         }
176         curl_easy_cleanup(curl);
177
178         return rv;
179 }
180
181 void
182 ParseCSV (const std::string &csv, std::vector<std::vector<std::string> > &lines)
183 {
184         bool inQuote(false);
185         bool newLine(false);
186         std::string field;
187         lines.clear();
188         std::vector<std::string> line;
189
190         std::string::const_iterator aChar = csv.begin();
191         while (aChar != csv.end()) {
192                 switch (*aChar) {
193                 case '"':
194                  newLine = false;
195                  inQuote = !inQuote;
196                  break;
197
198                 case ',':
199                  newLine = false;
200                  if (inQuote == true) {
201                                 field += *aChar;
202                  } else {
203                                 line.push_back(field);
204                                 field.clear();
205                  }
206                  break;
207
208                 case '\n':
209                 case '\r':
210                  if (inQuote == true) {
211                                 field += *aChar;
212                  } else {
213                                 if (newLine == false) {
214                                          line.push_back(field);
215                                          lines.push_back(line);
216                                          field.clear();
217                                          line.clear();
218                                          newLine = true;
219                                 }
220                  }
221                  break;
222
223                 default:
224                          newLine = false;
225                          field.push_back(*aChar);
226                          break;
227                 }
228                 aChar++;
229         }
230
231          if (field.size())
232                 line.push_back(field);
233
234          if (line.size())
235                 lines.push_back(line);
236 }
237
238 bool
239 video_query_info (
240                 std::string video_server_url,
241                 std::string filepath,
242                 double &video_file_fps,
243                 long long int &video_duration,
244                 double &video_start_offset,
245                 double &video_aspect_ratio
246                 )
247 {
248         char url[2048];
249
250         snprintf(url, sizeof(url), "%s%sinfo/?file=%s&format=plain"
251                         , video_server_url.c_str()
252                         , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/"
253                         , filepath.c_str());
254         char *res = curl_http_get(url, NULL);
255         int pid=0;
256         if (res) {
257                 char *pch, *pst;
258                 int version;
259                 pch = strtok_r(res, "\n", &pst);
260                 while (pch) {
261 #if 0 /* DEBUG */
262                         printf("VideoFileInfo [%i] -> '%s'\n", pid, pch);
263 #endif
264                         switch (pid) {
265                                 case 0:
266                                   version = atoi(pch);
267                                         if (version != 1) break;
268                                 case 1:
269                                   video_file_fps = atof(pch);
270                                         break;
271                                 case 2:
272                                         video_duration = atoll(pch);
273                                         break;
274                                 case 3:
275                                         video_start_offset = atof(pch);
276                                         break;
277                                 case 4:
278                                         video_aspect_ratio = atof(pch);
279                                         break;
280                                 default:
281                                         break;
282                         }
283                         pch = strtok_r(NULL,"\n", &pst);
284                         ++pid;
285                 }
286           free(res);
287         }
288         if (pid!=5) {
289                 return false;
290         }
291         return true;
292 }
293
294 void
295 video_draw_cross (Glib::RefPtr<Gdk::Pixbuf> img)
296 {
297
298         int rowstride = img->get_rowstride();
299         int n_channels = img->get_n_channels();
300         guchar *pixels, *p;
301         pixels = img->get_pixels();
302
303         int x,y;
304         int clip_width = img->get_width();
305         int clip_height = img->get_height();
306
307         for (x=0;x<clip_width;x++) {
308                 y = clip_height * x / clip_width;
309                 p = pixels + y * rowstride + x * n_channels;
310                 p[0] = 192; p[1] = 192; p[2] = 192;
311                 if (n_channels>3) p[3] = 255;
312                 p = pixels + y * rowstride + (clip_width-x-1) * n_channels;
313                 p[0] = 192; p[1] = 192; p[2] = 192;
314                 if (n_channels>3) p[3] = 255;
315         }
316 }