2013-03-12 17:00:09 -04:00
/*
2019-08-02 17:26:43 -04:00
* Copyright ( C ) 2013 - 2017 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2018 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2015 André Nusser < andre . nusser @ googlemail . com >
* Copyright ( C ) 2016 Tim Mayberry < mojofunk @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2013-03-12 17:00:09 -04:00
# include <cstdio>
# include <string>
# include <cerrno>
# include <gtkmm.h>
# include "pbd/error.h"
2016-09-04 19:28:50 -04:00
# include "pbd/string_convert.h"
2016-07-18 10:10:35 -04:00
2013-03-12 17:00:09 -04:00
# include "ardour/ardour.h"
# include "ardour/session_directory.h"
2016-07-18 10:10:35 -04:00
# include "ardour_http.h"
2015-10-12 07:01:05 -04:00
# include "utils.h"
2016-07-18 10:10:35 -04:00
# include "utils_videotl.h"
# include "video_image_frame.h"
2013-03-12 17:00:09 -04:00
2014-09-06 11:59:53 -04:00
# ifdef WAF_BUILD
# include "gtk2ardour-version.h"
# endif
# ifndef ARDOUR_CURL_TIMEOUT
# define ARDOUR_CURL_TIMEOUT (60)
# endif
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2013-03-12 17:00:09 -04:00
using namespace Gtk ;
using namespace std ;
using namespace PBD ;
using namespace ARDOUR ;
2013-08-03 10:54:57 -04:00
using namespace VideoUtils ;
2013-03-12 17:00:09 -04:00
2017-01-10 16:38:43 -05:00
unsigned int VideoUtils : : harvid_version = 0x0 ;
2013-03-12 17:00:09 -04:00
bool
2015-11-01 15:00:05 -05:00
VideoUtils : : confirm_video_outfn ( Gtk : : Window & parent , std : : string outfn , std : : string docroot )
2013-03-12 17:00:09 -04:00
{
/* replace docroot's '/' to G_DIR_SEPARATOR for the comparison */
size_t look_here = 0 ;
size_t found_here ;
const char ds = G_DIR_SEPARATOR ;
while ( ( found_here = docroot . find ( ' / ' , look_here ) ) ! = string : : npos ) {
docroot . replace ( found_here , 1 , std : : string ( & ds , 1 ) ) ;
look_here = found_here + 1 ;
}
if ( ! docroot . empty ( ) & & docroot . compare ( 0 , docroot . length ( ) , outfn , 0 , docroot . length ( ) ) ) {
ArdourDialog confirm ( _ ( " Destination is outside Video Server's docroot. " ) , true ) ;
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? " ) ) ;
confirm . get_vbox ( ) - > pack_start ( m , true , true ) ;
confirm . add_button ( Gtk : : Stock : : CANCEL , Gtk : : RESPONSE_CANCEL ) ;
confirm . add_button ( _ ( " Continue " ) , Gtk : : RESPONSE_ACCEPT ) ;
confirm . show_all ( ) ;
2020-02-27 17:27:42 -05:00
switch ( confirm . run ( ) ) {
case Gtk : : RESPONSE_ACCEPT :
break ;
default :
return false ;
}
2013-03-12 17:00:09 -04:00
}
if ( Glib : : file_test ( outfn , Glib : : FILE_TEST_EXISTS ) ) {
2015-11-01 15:00:05 -05:00
bool overwrite = ARDOUR_UI_UTILS : : overwrite_file_dialog ( parent ,
_ ( " Confirm Overwrite " ) ,
2015-10-12 07:01:05 -04:00
_ ( " A file with the same name already exists. Do you want to overwrite it? " ) ) ;
if ( ! overwrite ) {
return false ;
}
2013-03-12 17:00:09 -04:00
}
std : : string dir = Glib : : path_get_dirname ( outfn ) ;
if ( g_mkdir_with_parents ( dir . c_str ( ) , 0755 ) < 0 ) {
error < < string_compose ( _ ( " Cannot create video folder \" %1 \" (%2) " ) , dir , strerror ( errno ) ) < < endmsg ;
return false ;
}
return true ;
}
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : video_dest_dir ( const std : : string sessiondir , const std : : string docroot )
2013-03-12 17:00:09 -04:00
{
std : : string dir = docroot ;
if ( dir . empty ( ) | | ! dir . compare ( 0 , dir . length ( ) , sessiondir , 0 , dir . length ( ) ) ) {
dir = sessiondir ;
}
if ( ( dir . empty ( ) | | dir . at ( dir . length ( ) - 1 ) ! = G_DIR_SEPARATOR ) ) { dir + = G_DIR_SEPARATOR ; }
if ( g_mkdir_with_parents ( dir . c_str ( ) , 0755 ) < 0 ) {
error < < string_compose ( _ ( " Cannot create video folder \" %1 \" (%2) " ) , dir , strerror ( errno ) ) < < endmsg ;
}
return dir ;
}
2013-03-27 17:27:26 -04:00
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : video_get_docroot ( ARDOUR : : RCConfiguration * config )
2013-03-27 17:27:26 -04:00
{
if ( config - > get_video_advanced_setup ( ) ) {
return config - > get_video_server_docroot ( ) ;
}
2014-12-23 19:36:46 -05:00
# ifndef PLATFORM_WINDOWS
2013-03-27 17:27:26 -04:00
return X_ ( " / " ) ;
2014-12-23 19:36:46 -05:00
# else
2017-01-10 16:38:43 -05:00
if ( harvid_version > = 0x000802 ) { // 0.8.2
return X_ ( " " ) ;
} else {
return X_ ( " C: \\ " ) ;
}
2014-12-23 19:36:46 -05:00
# endif
2013-03-27 17:27:26 -04:00
}
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : video_get_server_url ( ARDOUR : : RCConfiguration * config )
2013-03-27 17:27:26 -04:00
{
if ( config - > get_video_advanced_setup ( ) ) {
return config - > get_video_server_url ( ) ;
}
2015-07-22 06:45:24 -04:00
return X_ ( " http://127.0.0.1:1554 " ) ;
2013-03-27 17:27:26 -04:00
}
2013-03-12 17:00:09 -04:00
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : strip_file_extension ( const std : : string infile )
2013-03-12 17:00:09 -04:00
{
std : : string rv ;
char * ext , * bn = strdup ( infile . c_str ( ) ) ;
if ( ( ext = strrchr ( bn , ' . ' ) ) ) {
if ( ! strchr ( ext , G_DIR_SEPARATOR ) ) {
* ext = 0 ;
}
}
rv = std : : string ( bn ) ;
free ( bn ) ;
return rv ;
}
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : get_file_extension ( const std : : string infile )
2013-03-12 17:00:09 -04:00
{
std : : string rv = " " ;
char * ext , * bn = strdup ( infile . c_str ( ) ) ;
if ( ( ext = strrchr ( bn , ' . ' ) ) ) {
if ( ! strchr ( ext , G_DIR_SEPARATOR ) ) {
rv = std : : string ( ext + 1 ) ;
}
}
free ( bn ) ;
return rv ;
}
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : video_dest_file ( const std : : string dir , const std : : string infile )
2013-03-12 17:00:09 -04:00
{
2015-04-01 11:59:16 -04:00
return Glib : : build_filename ( dir , strip_file_extension ( Glib : : path_get_basename ( infile ) ) + " .avi " ) ;
2013-03-12 17:00:09 -04:00
}
std : : string
2013-08-03 10:54:57 -04:00
VideoUtils : : video_map_path ( std : : string server_docroot , std : : string filepath )
2013-03-12 17:00:09 -04:00
{
std : : string rv = filepath ;
2014-04-18 20:03:43 -04:00
/* strip docroot */
if ( server_docroot . length ( ) > 0 ) {
if ( rv . compare ( 0 , server_docroot . length ( ) , server_docroot ) = = 0 ) {
rv = rv . substr ( server_docroot . length ( ) ) ;
}
}
2013-03-12 17:00:09 -04:00
/* replace all G_DIR_SEPARATOR with '/' */
size_t look_here = 0 ;
size_t found_here ;
while ( ( found_here = rv . find ( G_DIR_SEPARATOR , look_here ) ) ! = string : : npos ) {
rv . replace ( found_here , 1 , " / " ) ;
look_here = found_here + 1 ;
}
CURL * curl ;
char * ue ;
curl = curl_easy_init ( ) ;
ue = curl_easy_escape ( curl , rv . c_str ( ) , rv . length ( ) ) ;
if ( ue ) {
rv = std : : string ( ue ) ;
curl_free ( ue ) ;
}
curl_easy_cleanup ( curl ) ;
return rv ;
}
void
2013-08-03 10:54:57 -04:00
VideoUtils : : ParseCSV ( const std : : string & csv , std : : vector < std : : vector < std : : string > > & lines )
2013-03-12 17:00:09 -04:00
{
bool inQuote ( false ) ;
bool newLine ( false ) ;
std : : string field ;
lines . clear ( ) ;
std : : vector < std : : string > line ;
std : : string : : const_iterator aChar = csv . begin ( ) ;
while ( aChar ! = csv . end ( ) ) {
switch ( * aChar ) {
case ' " ' :
newLine = false ;
inQuote = ! inQuote ;
break ;
case ' , ' :
newLine = false ;
if ( inQuote = = true ) {
field + = * aChar ;
} else {
line . push_back ( field ) ;
field . clear ( ) ;
}
break ;
case ' \n ' :
case ' \r ' :
if ( inQuote = = true ) {
field + = * aChar ;
} else {
if ( newLine = = false ) {
line . push_back ( field ) ;
lines . push_back ( line ) ;
field . clear ( ) ;
line . clear ( ) ;
newLine = true ;
}
}
break ;
default :
newLine = false ;
field . push_back ( * aChar ) ;
break ;
}
aChar + + ;
}
if ( field . size ( ) )
line . push_back ( field ) ;
if ( line . size ( ) )
lines . push_back ( line ) ;
}
bool
2013-08-03 10:54:57 -04:00
VideoUtils : : video_query_info (
2013-03-12 17:00:09 -04:00
std : : string video_server_url ,
std : : string filepath ,
double & video_file_fps ,
long long int & video_duration ,
double & video_start_offset ,
double & video_aspect_ratio
)
{
char url [ 2048 ] ;
2013-08-03 10:41:25 -04:00
snprintf ( url , sizeof ( url ) , " %s%sinfo/?file=%s&format=csv "
2013-03-12 17:00:09 -04:00
, video_server_url . c_str ( )
, ( video_server_url . length ( ) > 0 & & video_server_url . at ( video_server_url . length ( ) - 1 ) = = ' / ' ) ? " " : " / "
, filepath . c_str ( ) ) ;
2018-06-02 13:24:17 -04:00
std : : string res = ArdourCurl : : http_get ( url , false ) ;
2016-07-18 10:10:35 -04:00
if ( res . empty ( ) ) {
2013-08-03 10:41:25 -04:00
return false ;
2013-03-12 17:00:09 -04:00
}
2013-08-03 10:41:25 -04:00
std : : vector < std : : vector < std : : string > > lines ;
2016-07-18 10:10:35 -04:00
ParseCSV ( res , lines ) ;
2013-08-03 10:41:25 -04:00
if ( lines . empty ( ) | | lines . at ( 0 ) . empty ( ) | | lines . at ( 0 ) . size ( ) ! = 6 ) {
2013-03-12 17:00:09 -04:00
return false ;
}
2013-08-03 10:41:25 -04:00
if ( atoi ( lines . at ( 0 ) . at ( 0 ) ) ! = 1 ) return false ; // version
video_start_offset = 0.0 ;
2016-09-04 19:28:50 -04:00
video_aspect_ratio = string_to < double > ( lines . at ( 0 ) . at ( 3 ) ) ;
video_file_fps = string_to < double > ( lines . at ( 0 ) . at ( 4 ) ) ;
video_duration = string_to < int64_t > ( lines . at ( 0 ) . at ( 5 ) ) ;
2016-08-22 08:47:19 -04:00
if ( video_aspect_ratio < 0.01 | | video_file_fps < 0.01 ) {
/* catch errors early, aspect == 0 or fps == 0 will
* wreak havoc down the road */
return false ;
}
2013-03-12 17:00:09 -04:00
return true ;
}
void
2013-08-03 10:54:57 -04:00
VideoUtils : : video_draw_cross ( Glib : : RefPtr < Gdk : : Pixbuf > img )
2013-03-12 17:00:09 -04:00
{
int rowstride = img - > get_rowstride ( ) ;
int n_channels = img - > get_n_channels ( ) ;
guchar * pixels , * p ;
pixels = img - > get_pixels ( ) ;
int x , y ;
int clip_width = img - > get_width ( ) ;
int clip_height = img - > get_height ( ) ;
for ( x = 0 ; x < clip_width ; x + + ) {
y = clip_height * x / clip_width ;
p = pixels + y * rowstride + x * n_channels ;
p [ 0 ] = 192 ; p [ 1 ] = 192 ; p [ 2 ] = 192 ;
if ( n_channels > 3 ) p [ 3 ] = 255 ;
p = pixels + y * rowstride + ( clip_width - x - 1 ) * n_channels ;
p [ 0 ] = 192 ; p [ 1 ] = 192 ; p [ 2 ] = 192 ;
if ( n_channels > 3 ) p [ 3 ] = 255 ;
}
}
2013-06-14 07:51:08 -04:00