Video import/export overhaul and ffmpeg-5.0 compat

* Update commandline parameters for ffmpeg 5.0
* Simplify video-export, allow only standard settings
* Check ffmpeg exit code and parse errors
* Fix SessionhandleRef on audio-import (clear import status)
* Cleanup and reformat sourcecode
This commit is contained in:
Robin Gareus 2022-02-07 22:46:23 +01:00
parent 391c3e96b3
commit 0b5e502546
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
7 changed files with 1126 additions and 1630 deletions

View File

@ -99,7 +99,8 @@ Editor::embed_audio_from_video (std::string path, samplepos_t n, bool lock_posit
std::string const& gid = ARDOUR::Playlist::generate_pgroup_id (); std::string const& gid = ARDOUR::Playlist::generate_pgroup_id ();
Temporal::timepos_t pos (n); Temporal::timepos_t pos (n);
bool ok = (import_sndfiles (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, pos, 1, 1, track, gid, false) == 0); bool ok = import_sndfiles (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, pos, 1, 1, track, gid, false) == 0;
import_status.clear();
if (ok && track) { if (ok && track) {
if (lock_position_to_video) { if (lock_position_to_video) {

File diff suppressed because it is too large Load Diff

View File

@ -22,16 +22,16 @@
#include <gtkmm/box.h> #include <gtkmm/box.h>
#include <gtkmm/button.h> #include <gtkmm/button.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/checkbutton.h> #include <gtkmm/checkbutton.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/entry.h> #include <gtkmm/entry.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <gtkmm/progressbar.h> #include <gtkmm/progressbar.h>
#include "ardour/export_status.h"
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/template_utils.h"
#include "ardour_dialog.h"
#include "ardour_dialog.h"
#include "time_selection.h" #include "time_selection.h"
#include "transcode_ffmpeg.h" #include "transcode_ffmpeg.h"
@ -48,58 +48,41 @@ public:
ExportVideoDialog (); ExportVideoDialog ();
~ExportVideoDialog (); ~ExportVideoDialog ();
std::string get_exported_filename () { return outfn_path_entry.get_text(); } std::string get_exported_filename ()
{
return outfn_path_entry.get_text ();
}
void apply_state (TimeSelection& tme, bool range); void apply_state (TimeSelection& tme, bool range);
XMLNode& get_state (); XMLNode& get_state ();
void set_state (const XMLNode&); void set_state (const XMLNode&);
void on_response (int response_id) {
Gtk::Dialog::on_response (response_id);
}
private: private:
TimeSelection export_range;
void on_show ();
void abort_clicked (); void abort_clicked ();
void launch_export (); void launch_export ();
void encode_pass (int); void encode_video ();
void change_file_extension (std::string); void finished (int);
void width_value_changed ();
void height_value_changed ();
void set_original_file_information (); void set_original_file_information ();
void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t);
gint audio_progress_display ();
void open_outfn_dialog (); void open_outfn_dialog ();
void open_invid_dialog (); void open_invid_dialog ();
void scale_checkbox_toggled ();
void preset_combo_changed ();
void video_codec_combo_changed ();
void aspect_checkbox_toggled ();
void fps_checkbox_toggled ();
bool _aborted; bool _aborted;
bool _twopass;
bool _firstpass;
bool _normalize; bool _normalize;
void finished ();
void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t);
boost::shared_ptr<ARDOUR::ExportStatus> status; boost::shared_ptr<ARDOUR::ExportStatus> status;
sigc::connection audio_progress_connection;
gint audio_progress_display ();
float _previous_progress;
TimeSelection _export_range;
sigc::connection _audio_progress_connection;
float _previous_progress;
TranscodeFfmpeg* _transcoder; TranscodeFfmpeg* _transcoder;
std::string _insnd; std::string _insnd;
float _video_source_aspect_ratio;
bool _suspend_signals;
bool _suspend_dirty;
Gtk::Label outfn_path_label; Gtk::Label outfn_path_label;
Gtk::Entry outfn_path_entry; Gtk::Entry outfn_path_entry;
Gtk::Button outfn_browse_button; Gtk::Button outfn_browse_button;
@ -116,33 +99,9 @@ private:
Gtk::VBox* progress_box; Gtk::VBox* progress_box;
Gtk::ProgressBar pbar; Gtk::ProgressBar pbar;
Gtk::ComboBoxText audio_codec_combo;
Gtk::ComboBoxText video_codec_combo;
Gtk::ComboBoxText video_bitrate_combo;
Gtk::ComboBoxText audio_bitrate_combo;
Gtk::ComboBoxText audio_samplerate_combo;
Gtk::ComboBoxText preset_combo;
Gtk::CheckButton scale_checkbox;
Gtk::CheckButton scale_aspect;
Gtk::Adjustment width_adjustment;
Gtk::SpinButton width_spinner;
Gtk::Adjustment height_adjustment;
Gtk::SpinButton height_spinner;
Gtk::CheckButton aspect_checkbox;
Gtk::ComboBoxText aspect_combo;
Gtk::CheckButton normalize_checkbox; Gtk::CheckButton normalize_checkbox;
Gtk::CheckButton twopass_checkbox;
Gtk::CheckButton optimizations_checkbox;
Gtk::Label optimizations_label;
Gtk::CheckButton deinterlace_checkbox;
Gtk::CheckButton bframes_checkbox;
Gtk::CheckButton fps_checkbox;
Gtk::ComboBoxText fps_combo;
Gtk::CheckButton meta_checkbox; Gtk::CheckButton meta_checkbox;
#if 1 /* tentative debug mode */
Gtk::CheckButton debug_checkbox; Gtk::CheckButton debug_checkbox;
#endif
}; };
#endif /* __gtk_ardour_export_video_dialog_h__ */ #endif /* __gtk_ardour_export_video_dialog_h__ */

View File

@ -18,15 +18,15 @@
* with this program; if not, write to the Free Software Foundation, Inc., * with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <sstream>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sstream>
#include <sys/types.h> #include <sys/types.h>
#include "pbd/error.h"
#include "pbd/convert.h"
#include "pbd/file_utils.h"
#include "gui_thread.h" #include "gui_thread.h"
#include "pbd/convert.h"
#include "pbd/error.h"
#include "pbd/file_utils.h"
#include "ardour/filesystem_paths.h" #include "ardour/filesystem_paths.h"
@ -48,14 +48,10 @@ TranscodeFfmpeg::TranscodeFfmpeg (std::string f)
m_width = m_height = 0; m_width = m_height = 0;
m_aspect = m_fps = 0; m_aspect = m_fps = 0;
m_sar = ""; m_sar = "";
#if 1 /* tentative debug mode */
debug_enable = false; debug_enable = false;
#endif
if (!ARDOUR::ArdourVideoToolPaths::transcoder_exe (ffmpeg_exe, ffprobe_exe)) { if (!ARDOUR::ArdourVideoToolPaths::transcoder_exe (ffmpeg_exe, ffprobe_exe)) {
warning << string_compose( warning << string_compose (_("ffmpeg installation was not found on this system.\n"
_(
"ffmpeg installation was not found on this system.\n"
"%1 requires ffmpeg and ffprobe from ffmpeg.org - version 1.1 or newer.\n" "%1 requires ffmpeg and ffprobe from ffmpeg.org - version 1.1 or newer.\n"
"Video import and export is not possible until you install tools.\n" "Video import and export is not possible until you install tools.\n"
"\n" "\n"
@ -66,8 +62,9 @@ TranscodeFfmpeg::TranscodeFfmpeg (std::string f)
"If you already have a suitable ffmpeg installation on your system, we recommend creating " "If you already have a suitable ffmpeg installation on your system, we recommend creating "
"symbolic links from ffmpeg to ffmpeg_harvid and from ffprobe to ffprobe_harvid.\n" "symbolic links from ffmpeg to ffmpeg_harvid and from ffprobe to ffprobe_harvid.\n"
"\n" "\n"
"see also http://manual.ardour.org/video-timeline/setup/" "see also http://manual.ardour.org/video-timeline/setup/"),
), PROGRAM_NAME) << endmsg; PROGRAM_NAME)
<< endmsg;
return; return;
} }
ffexecok = true; ffexecok = true;
@ -78,11 +75,6 @@ TranscodeFfmpeg::TranscodeFfmpeg (std::string f)
probeok = true; probeok = true;
} }
TranscodeFfmpeg::~TranscodeFfmpeg ()
{
;
}
bool bool
TranscodeFfmpeg::probe () TranscodeFfmpeg::probe ()
{ {
@ -130,6 +122,7 @@ TranscodeFfmpeg::probe ()
m_codec.clear (); m_codec.clear ();
m_audio.clear (); m_audio.clear ();
/* clang-format off */
#define PARSE_FRACTIONAL_FPS(VAR) \ #define PARSE_FRACTIONAL_FPS(VAR) \
{ \ { \
std::string::size_type pos; \ std::string::size_type pos; \
@ -139,6 +132,7 @@ TranscodeFfmpeg::probe ()
VAR = atof (value.substr (0, pos)) / atof (value.substr (pos + 1)); \ VAR = atof (value.substr (0, pos)) / atof (value.substr (pos + 1)); \
} \ } \
} }
/* clang-format on */
std::string duration_from_format; std::string duration_from_format;
@ -147,20 +141,21 @@ TranscodeFfmpeg::probe ()
/* format,filename,#streams,format-name,format-long-name,start-time,duration,size,bitrate */ /* format,filename,#streams,format-name,format-long-name,start-time,duration,size,bitrate */
for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) { for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) {
const size_t kvsep = kv->find ('='); const size_t kvsep = kv->find ('=');
if(kvsep == std::string::npos) continue; if (kvsep == std::string::npos) {
continue;
}
std::string key = kv->substr (0, kvsep); std::string key = kv->substr (0, kvsep);
std::string value = kv->substr (kvsep + 1); std::string value = kv->substr (kvsep + 1);
if (key == X_("duration")) { if (key == X_("duration")) {
duration_from_format = value; duration_from_format = value;
} }
} }
} else } else if (i->at (0) == X_("stream")) {
if (i->at(0) == X_("stream")) {
if (i->at (5) == X_("codec_type=video") && m_width == 0) { if (i->at (5) == X_("codec_type=video") && m_width == 0) {
for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) { for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) {
const size_t kvsep = kv->find ('='); const size_t kvsep = kv->find ('=');
if(kvsep == std::string::npos) continue; if (kvsep == std::string::npos)
continue;
std::string key = kv->substr (0, kvsep); std::string key = kv->substr (0, kvsep);
std::string value = kv->substr (kvsep + 1); std::string value = kv->substr (kvsep + 1);
@ -171,13 +166,19 @@ TranscodeFfmpeg::probe ()
} else if (key == X_("height")) { } else if (key == X_("height")) {
m_height = atoi (value); m_height = atoi (value);
} else if (key == X_("codec_name")) { } else if (key == X_("codec_name")) {
if (!m_codec.empty()) m_codec += " "; if (!m_codec.empty ()) {
m_codec += " ";
}
m_codec += value; m_codec += value;
} else if (key == X_("codec_long_name")) { } else if (key == X_("codec_long_name")) {
if (!m_codec.empty()) m_codec += " "; if (!m_codec.empty ()) {
m_codec += " ";
}
m_codec += "[" + value + "]"; m_codec += "[" + value + "]";
} else if (key == X_("codec_tag_string")) { } else if (key == X_("codec_tag_string")) {
if (!m_codec.empty()) m_codec += " "; if (!m_codec.empty ()) {
m_codec += " ";
}
m_codec += "(" + value + ")"; m_codec += "(" + value + ")";
} else if (key == X_("r_frame_rate")) { } else if (key == X_("r_frame_rate")) {
PARSE_FRACTIONAL_FPS (m_fps) PARSE_FRACTIONAL_FPS (m_fps)
@ -186,14 +187,10 @@ TranscodeFfmpeg::probe ()
} else if (key == X_("time_base")) { } else if (key == X_("time_base")) {
PARSE_FRACTIONAL_FPS (timebase) PARSE_FRACTIONAL_FPS (timebase)
} else if (key == X_("timecode") && m_duration == 0 && m_fps > 0) { } else if (key == X_("timecode") && m_duration == 0 && m_fps > 0) {
int h,m,s; char f[32]; int h, m, s;
char f[32];
if (sscanf (i->at (16).c_str (), "%d:%d:%d:%32s", &h, &m, &s, f) == 4) { if (sscanf (i->at (16).c_str (), "%d:%d:%d:%32s", &h, &m, &s, f) == 4) {
m_duration = (ARDOUR::samplecnt_t) floor(m_fps * ( m_duration = (ARDOUR::samplecnt_t)floor (m_fps * (h * 3600.0 + m * 60.0 + s * 1.0 + atoi (f) / pow ((double)10, (int)strlen (f))));
h * 3600.0
+ m * 60.0
+ s * 1.0
+ atoi(f) / pow((double)10, (int)strlen(f))
));
} }
} else if (key == X_("duration_ts") && m_fps == 0 && timebase != 0) { } else if (key == X_("duration_ts") && m_fps == 0 && timebase != 0) {
m_duration = atof (value) * m_fps * timebase; m_duration = atof (value) * m_fps * timebase;
@ -223,7 +220,9 @@ TranscodeFfmpeg::probe ()
FFAudioStream as; FFAudioStream as;
for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) { for (std::vector<std::string>::iterator kv = i->begin (); kv != i->end (); ++kv) {
const size_t kvsep = kv->find ('='); const size_t kvsep = kv->find ('=');
if(kvsep == std::string::npos) continue; if (kvsep == std::string::npos) {
continue;
}
std::string key = kv->substr (0, kvsep); std::string key = kv->substr (0, kvsep);
std::string value = kv->substr (kvsep + 1); std::string value = kv->substr (kvsep + 1);
@ -232,19 +231,26 @@ TranscodeFfmpeg::probe ()
} else if (key == X_("index")) { } else if (key == X_("index")) {
as.stream_id = value; as.stream_id = value;
} else if (key == X_("codec_long_name")) { } else if (key == X_("codec_long_name")) {
if (!as.name.empty()) as.name += " "; if (!as.name.empty ()) {
as.name += " ";
}
as.name += value; as.name += value;
} else if (key == X_("codec_name")) { } else if (key == X_("codec_name")) {
if (!as.name.empty()) as.name += " "; if (!as.name.empty ()) {
as.name += " ";
}
as.name += value; as.name += value;
} else if (key == X_("sample_fmt")) { } else if (key == X_("sample_fmt")) {
if (!as.name.empty()) as.name += " "; if (!as.name.empty ()) {
as.name += " ";
}
as.name += "FMT:" + value; as.name += "FMT:" + value;
} else if (key == X_("sample_rate")) { } else if (key == X_("sample_rate")) {
if (!as.name.empty()) as.name += " "; if (!as.name.empty ()) {
as.name += " ";
}
as.name += "SR:" + value; as.name += "SR:" + value;
} }
} }
m_audio.push_back (as); m_audio.push_back (as);
} }
@ -296,21 +302,25 @@ TranscodeFfmpeg::default_meta_data ()
return ffm; return ffm;
} }
bool bool
TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf_v, TranscodeFfmpeg::FFSettings ffs, TranscodeFfmpeg::FFSettings meta, bool map) TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf_v, TranscodeFfmpeg::FFSettings ffs, TranscodeFfmpeg::FFSettings meta, bool map)
{ {
#define MAX_FFMPEG_ENCODER_ARGS (100) #define MAX_FFMPEG_ENCODER_ARGS (100)
char **argp;
int a = 0; int a = 0;
argp=(char**) calloc(MAX_FFMPEG_ENCODER_ARGS,sizeof(char*)); char** argp = (char**)calloc (MAX_FFMPEG_ENCODER_ARGS, sizeof (char*));
argp[a++] = strdup (ffmpeg_exe.c_str ()); argp[a++] = strdup (ffmpeg_exe.c_str ());
if (m_avoffset < 0 || m_avoffset > 0) { if (m_avoffset < 0 || m_avoffset > 0) {
std::ostringstream osstream; osstream << m_avoffset; argp[a++] = strdup ("-accurate_seek");
std::ostringstream osstream;
osstream << m_avoffset;
argp[a++] = strdup ("-itsoffset"); argp[a++] = strdup ("-itsoffset");
argp[a++] = strdup (osstream.str ().c_str ()); argp[a++] = strdup (osstream.str ().c_str ());
argp[a++] = strdup ("-ss");
argp[a++] = strdup ("0");
} }
argp[a++] = strdup ("-i"); argp[a++] = strdup ("-i");
argp[a++] = strdup (inf_v.c_str ()); argp[a++] = strdup (inf_v.c_str ());
@ -335,10 +345,14 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
std::ostringstream osstream; std::ostringstream osstream;
argp[a++] = strdup ("-vf"); argp[a++] = strdup ("-vf");
osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in;
if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; if (!m_sar.empty ()) {
osstream << X_(":sar=") << m_sar;
}
osstream << X_(" [pre]; "); osstream << X_(" [pre]; ");
osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out;
if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; if (!m_sar.empty ()) {
osstream << X_(":sar=") << m_sar;
}
osstream << X_(" [post]; "); osstream << X_(" [post]; ");
osstream << X_("[pre] [in] [post] concat=n=3"); osstream << X_("[pre] [in] [post] concat=n=3");
argp[a++] = strdup (osstream.str ().c_str ()); argp[a++] = strdup (osstream.str ().c_str ());
@ -346,7 +360,9 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
std::ostringstream osstream; std::ostringstream osstream;
argp[a++] = strdup ("-vf"); argp[a++] = strdup ("-vf");
osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in;
if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; if (!m_sar.empty ()) {
osstream << X_(":sar=") << m_sar;
}
osstream << X_(" [pre]; "); osstream << X_(" [pre]; ");
osstream << X_("[pre] [in] concat=n=2"); osstream << X_("[pre] [in] concat=n=2");
argp[a++] = strdup (osstream.str ().c_str ()); argp[a++] = strdup (osstream.str ().c_str ());
@ -354,7 +370,9 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
std::ostringstream osstream; std::ostringstream osstream;
argp[a++] = strdup ("-vf"); argp[a++] = strdup ("-vf");
osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out;
if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; if (!m_sar.empty ()) {
osstream << X_(":sar=") << m_sar;
}
osstream << X_(" [post]; "); osstream << X_(" [post]; ");
osstream << X_("[in] [post] concat=n=2"); osstream << X_("[in] [post] concat=n=2");
argp[a++] = strdup (osstream.str ().c_str ()); argp[a++] = strdup (osstream.str ().c_str ());
@ -374,19 +392,19 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
argp[a] = (char*)0; argp[a] = (char*)0;
assert (a < MAX_FFMPEG_ENCODER_ARGS); assert (a < MAX_FFMPEG_ENCODER_ARGS);
/* Note: these are free()d in ~SystemExec */ /* Note: these are free()d in ~SystemExec */
#if 1 /* DEBUG */
if (debug_enable) { /* tentative debug mode */ if (debug_enable) {
printf ("EXPORT ENCODE:\n"); printf ("EXPORT ENCODE:\n");
for (int i = 0; i < a; ++i) { for (int i = 0; i < a; ++i) {
printf ("%s ", argp[i]); printf ("%s ", argp[i]);
} }
printf ("\n"); printf ("\n");
} }
#endif
ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp);
ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2)); ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2));
ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ());
if (ffcmd->start (SystemExec::MergeWithStdin)) { if (ffcmd->start (SystemExec::MergeWithStdin)) {
ffexit (); ffexit ();
return false; return false;
@ -397,8 +415,9 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
bool bool
TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*samplerate*/, unsigned int stream) TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*samplerate*/, unsigned int stream)
{ {
if (!probeok) return false; if (!probeok || stream >= m_audio.size ()) {
if (stream >= m_audio.size()) return false; return false;
}
char** argp; char** argp;
int i = 0; int i = 0;
@ -412,9 +431,11 @@ TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*sampl
argp[i] = (char*) calloc(7,sizeof(char)); snprintf(argp[i++], 7, "%"PRId64, samplerate); argp[i] = (char*) calloc(7,sizeof(char)); snprintf(argp[i++], 7, "%"PRId64, samplerate);
#endif #endif
argp[i++] = strdup ("-ac"); argp[i++] = strdup ("-ac");
argp[i] = (char*) calloc(3,sizeof(char)); snprintf(argp[i++], 3, "%i", m_audio.at(stream).channels); argp[i] = (char*)calloc (3, sizeof (char));
snprintf (argp[i++], 3, "%i", m_audio.at (stream).channels);
argp[i++] = strdup ("-map"); argp[i++] = strdup ("-map");
argp[i] = (char*) calloc(8,sizeof(char)); snprintf(argp[i++], 8, "0:%s", m_audio.at(stream).stream_id.c_str()); argp[i] = (char*)calloc (8, sizeof (char));
snprintf (argp[i++], 8, "0:%s", m_audio.at (stream).stream_id.c_str ());
argp[i++] = strdup ("-vn"); argp[i++] = strdup ("-vn");
argp[i++] = strdup ("-acodec"); argp[i++] = strdup ("-acodec");
argp[i++] = strdup ("pcm_f32le"); argp[i++] = strdup ("pcm_f32le");
@ -422,19 +443,19 @@ TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*sampl
argp[i++] = strdup (outfile.c_str ()); argp[i++] = strdup (outfile.c_str ());
argp[i++] = (char*)0; argp[i++] = (char*)0;
/* Note: argp is free()d in ~SystemExec */ /* Note: argp is free()d in ~SystemExec */
#if 1 /* DEBUG */
if (debug_enable) { /* tentative debug mode */ if (debug_enable) {
printf ("EXTRACT AUDIO:\n"); printf ("EXTRACT AUDIO:\n");
for (int i = 0; i < 14; ++i) { for (int i = 0; i < 14; ++i) {
printf ("%s ", argp[i]); printf ("%s ", argp[i]);
} }
printf ("\n"); printf ("\n");
} }
#endif
ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp);
ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_a, this, _1, _2)); ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_a, this, _1, _2));
ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ());
if (ffcmd->start (SystemExec::MergeWithStdin)) { if (ffcmd->start (SystemExec::MergeWithStdin)) {
ffexit (); ffexit ();
return false; return false;
@ -442,19 +463,25 @@ TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*sampl
return true; return true;
} }
bool bool
TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh, const int kbitps) TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh, const int kbitps)
{ {
if (!probeok) return false; if (!probeok) {
return false;
}
char** argp; char** argp;
int bitrate = kbitps; int bitrate = kbitps;
int width = outw; int width = outw;
int height = outh; int height = outh;
if (width < 1 || width > m_width) { width = m_width; } /* don't allow upscaling */ if (width < 1 || width > m_width) {
if (height < 1 || height > m_height) { height = floor(width / m_aspect); } width = m_width;
}
/* don't allow upscaling */
if (height < 1 || height > m_height) {
height = floor (width / m_aspect);
}
if (bitrate == 0) { if (bitrate == 0) {
const double bitperpixel = .7; /* avg quality */ const double bitperpixel = .7; /* avg quality */
@ -462,36 +489,41 @@ TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh,
} else { } else {
bitrate = bitrate / 10; bitrate = bitrate / 10;
} }
if (bitrate < 10) bitrate = 10; if (bitrate < 10) {
if (bitrate > 1000) bitrate = 1000; bitrate = 10;
}
if (bitrate > 1000) {
bitrate = 1000;
}
argp=(char**) calloc(16,sizeof(char*)); argp = (char**)calloc (15, sizeof (char*));
argp[0] = strdup (ffmpeg_exe.c_str ()); argp[0] = strdup (ffmpeg_exe.c_str ());
argp[1] = strdup ("-i"); argp[1] = strdup ("-i");
argp[2] = strdup (infile.c_str ()); argp[2] = strdup (infile.c_str ());
argp[3] = strdup ("-b:v"); argp[3] = strdup ("-b:v");
argp[4] = (char*) calloc(7,sizeof(char)); snprintf(argp[4], 7, "%i0k", bitrate); argp[4] = (char*)calloc (7, sizeof (char));
snprintf (argp[4], 7, "%i0k", bitrate);
argp[5] = strdup ("-s"); argp[5] = strdup ("-s");
argp[6] = (char*) calloc(10,sizeof(char)); snprintf(argp[6], 10, "%ix%i", width, height); argp[6] = (char*)calloc (10, sizeof (char));
snprintf (argp[6], 10, "%ix%i", width, height);
argp[7] = strdup ("-y"); argp[7] = strdup ("-y");
argp[8] = strdup ("-vcodec"); argp[8] = strdup ("-vcodec");
argp[9] = strdup ("mjpeg"); argp[9] = strdup ("mjpeg");
argp[10] = strdup ("-an"); argp[10] = strdup ("-an");
argp[11] = strdup("-intra"); argp[11] = strdup ("-g");
argp[12] = strdup("-g"); argp[12] = strdup ("0");
argp[13] = strdup("1"); argp[13] = strdup (outfile.c_str ());
argp[14] = strdup(outfile.c_str()); argp[14] = (char*)0;
argp[15] = (char *)0;
/* Note: these are free()d in ~SystemExec */ /* Note: these are free()d in ~SystemExec */
#if 1 /* DEBUG */
if (debug_enable) { /* tentative debug mode */ if (debug_enable) {
printf ("TRANSCODE VIDEO:\n"); printf ("TRANSCODE VIDEO:\n");
for (int i = 0; i < 15; ++i) { for (int i = 0; i < 15; ++i) {
printf ("%s ", argp[i]); printf ("%s ", argp[i]);
} }
printf ("\n"); printf ("\n");
} }
#endif
ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp);
ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2)); ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2));
ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ());
@ -505,13 +537,11 @@ TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh,
void void
TranscodeFfmpeg::cancel () TranscodeFfmpeg::cancel ()
{ {
if (!ffcmd || !ffcmd->is_running()) { return;} if (!ffcmd || !ffcmd->is_running ()) {
return;
}
ffcmd->write_to_stdin ("q"); ffcmd->write_to_stdin ("q");
#ifdef PLATFORM_WINDOWS Glib::usleep (1000000); /* 1 sec */
Sleep(1000);
#else
sleep (1);
#endif
if (ffcmd) { if (ffcmd) {
ffcmd->terminate (); ffcmd->terminate ();
} }
@ -520,9 +550,10 @@ TranscodeFfmpeg::cancel ()
void void
TranscodeFfmpeg::ffexit () TranscodeFfmpeg::ffexit ()
{ {
int rv = ffcmd->wait ();
delete ffcmd; delete ffcmd;
ffcmd = 0; ffcmd = 0;
Finished(); /* EMIT SIGNAL */ Finished (rv); /* EMIT SIGNAL */
} }
void void
@ -535,20 +566,21 @@ void
TranscodeFfmpeg::ffmpegparse_a (std::string d, size_t /* s */) TranscodeFfmpeg::ffmpegparse_a (std::string d, size_t /* s */)
{ {
const char* t; const char* t;
int h,m,s; char f[7]; int h, m, s;
ARDOUR::samplecnt_t p = -1; char f[7];
if (!(t=strstr(d.c_str(), "time="))) { return; } if (!(t = strstr (d.c_str (), "time="))) {
Progress (0, 0); /* EMIT SIGNAL */
return;
}
if (sscanf (t + 5, "%d:%d:%d.%s", &h, &m, &s, f) == 4) { if (sscanf (t + 5, "%d:%d:%d.%s", &h, &m, &s, f) == 4) {
p = (ARDOUR::samplecnt_t) floor( 100.0 * ( ARDOUR::samplecnt_t p;
h * 3600.0 p = (ARDOUR::samplecnt_t)floor (100.0 * (h * 3600.0 + m * 60.0 + s * 1.0 + atoi (f) / pow (10.0, (int)strlen (f))));
+ m * 60.0
+ s * 1.0
+ atoi(f) / pow((double)10, (int)strlen(f))
));
p = p * m_fps / 100.0; p = p * m_fps / 100.0;
if (p > m_duration ) { p = m_duration; } if (p > m_duration) {
p = m_duration;
}
Progress (p, m_duration); /* EMIT SIGNAL */ Progress (p, m_duration); /* EMIT SIGNAL */
} else { } else {
Progress (0, 0); /* EMIT SIGNAL */ Progress (0, 0); /* EMIT SIGNAL */
@ -558,18 +590,33 @@ TranscodeFfmpeg::ffmpegparse_a (std::string d, size_t /* s */)
void void
TranscodeFfmpeg::ffmpegparse_v (std::string d, size_t /* s */) TranscodeFfmpeg::ffmpegparse_v (std::string d, size_t /* s */)
{ {
if (strstr(d.c_str(), "ERROR") || strstr(d.c_str(), "Error") || strstr(d.c_str(), "error")) { /* see ffmpeg-src/doc/errno.txt
warning << "ffmpeg-error: " << d << endmsg; * Not all error messages are forwarded to ardour's log,
* but exit-code other than 0 shows a popup window.
*/
if (strstr (d.c_str (), "No space left on device") || strstr (d.c_str (), "File too large")) {
error << "ffmpeg-error: " << d << endmsg;
return;
} }
if (strstr (d.c_str (), "ERROR") || strstr (d.c_str (), "Error") || strstr (d.c_str (), "error")) {
error << "ffmpeg-error: " << d << endmsg;
return;
}
if (strstr (d.c_str (), "Unrecognized option") || strstr (d.c_str (), "Missing argument") || strstr (d.c_str (), "Invalid argument")) {
error << "ffmpeg-error: " << d << endmsg;
return;
}
if (strncmp (d.c_str (), "frame=", 6)) { if (strncmp (d.c_str (), "frame=", 6)) {
#if 1 /* DEBUG */
if (debug_enable) { if (debug_enable) {
d.erase (d.find_last_not_of (" \t\r\n") + 1); d.erase (d.find_last_not_of (" \t\r\n") + 1);
printf ("ffmpeg: '%s'\n", d.c_str ()); printf ("ffmpeg: '%s'\n", d.c_str ());
} }
#endif Progress (0, 0); /* EMIT SIGNAL */
return; return;
} }
ARDOUR::samplecnt_t f = atol (d.substr (6)); ARDOUR::samplecnt_t f = atol (d.substr (6));
if (f == 0) { if (f == 0) {
Progress (0, 0); /* EMIT SIGNAL */ Progress (0, 0); /* EMIT SIGNAL */

View File

@ -19,10 +19,10 @@
#define __ardour_transcode_ffmpeg_h__ #define __ardour_transcode_ffmpeg_h__
#include <string> #include <string>
#include "ardour/system_exec.h" #include "ardour/system_exec.h"
#include "ardour/types.h" #include "ardour/types.h"
/** @class TranscodeFfmpeg /** @class TranscodeFfmpeg
* @brief wrapper around ffmpeg and ffprobe command-line utils * @brief wrapper around ffmpeg and ffprobe command-line utils
* *
@ -31,27 +31,24 @@
* transcode video-files and extract aufio tracks and query * transcode video-files and extract aufio tracks and query
* file information. * file information.
*/ */
class TranscodeFfmpeg : public sigc::trackable class TranscodeFfmpeg : public sigc::trackable, public PBD::ScopedConnectionList
, public PBD::ScopedConnectionList
{ {
public: public:
struct FFAudioStream { struct FFAudioStream {
std::string name; std::string name;
std::string stream_id; std::string stream_id;
uint32_t channels; uint32_t channels;
}; };
typedef std::vector<FFAudioStream> FFAudioStreams; typedef std::vector<FFAudioStream> FFAudioStreams;
typedef std::map<std::string, std::string> FFSettings; typedef std::map<std::string, std::string> FFSettings;
/** instantiate a new transcoder. If a file-name is given, the file's /** instantiate a new transcoder. If a file-name is given, the file's
* attributes (fps, duration, geometry etc) are read. * attributes (fps, duration, geometry etc) are read.
* *
* @param f path to the video-file to probe or use as input for \ref extract_audio and \ref transcode . * @param f path to the video-file to probe or use as input for \ref extract_audio and \ref transcode .
*/ */
TranscodeFfmpeg (std::string f); TranscodeFfmpeg (std::string f);
virtual ~TranscodeFfmpeg ();
/** transcode to (import a video-file) /** transcode to (import a video-file)
* *
@ -86,55 +83,105 @@ class TranscodeFfmpeg : public sigc::trackable
*/ */
bool encode (std::string outfile, std::string inf_a, std::string inf_v, FFSettings ffs, FFSettings meta, bool map = true); bool encode (std::string outfile, std::string inf_a, std::string inf_v, FFSettings ffs, FFSettings meta, bool map = true);
/** @return array with default encoder settings */
FFSettings default_encoder_settings ();
/** @return array with default meta data */
FFSettings default_meta_data ();
/** abort any running transcoding process */ /** abort any running transcoding process */
void cancel (); void cancel ();
/**
* @return \c true if the input file was parsed correctly on class creation. */ /** @return array with default encoder settings */
bool probe_ok () { return probeok; } FFSettings default_encoder_settings ();
/** @return array with default meta data */
FFSettings default_meta_data ();
/** @return \c true if the input file was parsed correctly on class creation. */
bool probe_ok ()
{
return probeok;
}
/** @return \c true if the ffmpeg/ffparse executables are avail on this system */ /** @return \c true if the ffmpeg/ffparse executables are avail on this system */
bool ffexec_ok () { return ffexecok; } bool ffexec_ok ()
{
return ffexecok;
}
double get_fps ()
{
return m_fps;
}
double get_aspect ()
{
return m_aspect;
}
int get_width ()
{
return m_width;
}
int get_height ()
{
return m_height;
}
ARDOUR::samplecnt_t get_duration ()
{
return m_duration;
}
std::string get_codec ()
{
return m_codec;
}
FFAudioStreams get_audio ()
{
return m_audio;
}
/** override file duration used with the \ref Progress signal.
* @param d duration in video-frames = length_in_seconds * get_fps()
*/
void set_duration (ARDOUR::samplecnt_t d)
{
m_duration = d;
}
/* offset, lead-in/out are in seconds */
void set_avoffset (double av_offset)
{
m_avoffset = av_offset;
}
void set_leadinout (double lead_in, double lead_out)
{
m_lead_in = lead_in;
m_lead_out = lead_out;
}
void set_debug (bool onoff)
{
debug_enable = onoff;
}
/** signal emitted when ffmpeg reports progress updates /** signal emitted when ffmpeg reports progress updates
* during \ref encode \ref transcode and \ref extract_audio * during \ref encode \ref transcode and \ref extract_audio
* The parameters are current and last video-frame. * The parameters are current and last video-frame.
*/ */
PBD::Signal2<void, ARDOUR::samplecnt_t, ARDOUR::samplecnt_t> Progress; PBD::Signal2<void, ARDOUR::samplecnt_t, ARDOUR::samplecnt_t> Progress;
/** signal emitted when the transcoder process terminates. */ /** signal emitted when the transcoder process terminates. */
PBD::Signal0<void> Finished; PBD::Signal1<void, int> Finished;
double get_fps () { return m_fps; }
double get_aspect () { return m_aspect; }
int get_width() { return m_width; }
int get_height() { return m_height; }
ARDOUR::samplecnt_t get_duration() { return m_duration; }
std::string get_codec() { return m_codec; }
FFAudioStreams get_audio() { return m_audio; }
/** override file duration used with the \ref Progress signal.
* @param d duration in video-frames = length_in_seconds * get_fps()
*/
void set_duration(ARDOUR::samplecnt_t d) { m_duration = d; }
/* offset, lead-in/out are in seconds */
void set_avoffset(double av_offset) { m_avoffset = av_offset; }
void set_leadinout(double lead_in, double lead_out) { m_lead_in = lead_in; m_lead_out = lead_out; }
void set_fps(double fps) { m_fps = fps; } // on export, used for rounding only.
#if 1 /* tentative debug mode */
void set_debug (bool onoff) { debug_enable = onoff; }
#endif
protected: protected:
bool probe ();
void ffmpegparse_v (std::string d, size_t s);
void ffmpegparse_a (std::string d, size_t s);
void ffprobeparse (std::string d, size_t s);
void ffexit ();
std::string infile; std::string infile;
ARDOUR::SystemExec* ffcmd; ARDOUR::SystemExec* ffcmd;
bool probe ();
double m_fps; double m_fps;
double m_aspect; double m_aspect;
std::string m_sar; std::string m_sar;
@ -142,27 +189,17 @@ class TranscodeFfmpeg : public sigc::trackable
int m_width; int m_width;
int m_height; int m_height;
std::string m_codec; std::string m_codec;
int m_videoidx; int m_videoidx;
double m_avoffset; double m_avoffset;
double m_lead_in; double m_lead_in;
double m_lead_out; double m_lead_out;
bool ffexecok; bool ffexecok;
bool probeok; bool probeok;
FFAudioStreams m_audio; FFAudioStreams m_audio;
void ffmpegparse_v (std::string d, size_t s);
void ffmpegparse_a (std::string d, size_t s);
void ffprobeparse (std::string d, size_t s);
void ffexit ();
std::string ffoutput; std::string ffoutput;
std::string ffmpeg_exe; std::string ffmpeg_exe;
std::string ffprobe_exe; std::string ffprobe_exe;
#if 1 /* tentative debug mode */
bool debug_enable; bool debug_enable;
#endif
}; };
#endif /* __ardour_transcode_ffmpeg_h__ */ #endif /* __ardour_transcode_ffmpeg_h__ */

View File

@ -18,14 +18,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <cstdio> #include <cstdio>
#include <string>
#include <sstream>
#include <iomanip> #include <iomanip>
#include <sstream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sigc++/bind.h> #include <sigc++/bind.h>
@ -34,19 +34,20 @@
#include "pbd/gstdio_compat.h" #include "pbd/gstdio_compat.h"
#include "pbd/error.h"
#include "pbd/convert.h"
#include "gtkmm2ext/utils.h"
#include "ardour/session_directory.h"
#include "ardour/profile.h" #include "ardour/profile.h"
#include "ardour/template_utils.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/template_utils.h"
#include "ardour_ui.h" #include "ardour_ui.h"
#include "gtkmm2ext/utils.h"
#include "gui_thread.h" #include "gui_thread.h"
#include "pbd/convert.h"
#include "pbd/error.h"
#include "opts.h" #include "opts.h"
#include "transcode_video_dialog.h" #include "transcode_video_dialog.h"
#include "utils_videotl.h" #include "utils_videotl.h"
#include "pbd/i18n.h" #include "pbd/i18n.h"
using namespace Gtk; using namespace Gtk;
@ -70,9 +71,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
, bitrate_checkbox (_("Manual Override")) , bitrate_checkbox (_("Manual Override"))
, bitrate_adjustment (2000, 500, 10000, 10, 100, 0) , bitrate_adjustment (2000, 500, 10000, 10, 100, 0)
, bitrate_spinner (bitrate_adjustment) , bitrate_spinner (bitrate_adjustment)
#if 1 /* tentative debug mode */
, debug_checkbox (_("Debug Mode: Print ffmpeg command and output to stdout.")) , debug_checkbox (_("Debug Mode: Print ffmpeg command and output to stdout."))
#endif
{ {
set_session (s); set_session (s);
@ -92,19 +91,21 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
HBox* path_hbox = manage (new HBox); HBox* path_hbox = manage (new HBox);
int w = 0, h = 0; int w = 0, h = 0;
m_aspect = 4.0/3.0; m_aspect = 16.0 / 9.0;
TranscodeFfmpeg::FFAudioStreams as; as.clear();
TranscodeFfmpeg::FFAudioStreams as;
path_hbox->pack_start (path_label, false, false, 3); path_hbox->pack_start (path_label, false, false, 3);
path_hbox->pack_start (path_entry, true, true, 3); path_hbox->pack_start (path_entry, true, true, 3);
path_hbox->pack_start (browse_button, false, false, 3); path_hbox->pack_start (browse_button, false, false, 3);
path_entry.set_width_chars(38);
height_spinner.set_sensitive (false); height_spinner.set_sensitive (false);
bitrate_spinner.set_sensitive (false); bitrate_spinner.set_sensitive (false);
std::string dstdir = video_dest_dir (_session->session_directory ().video_path (), video_get_docroot (Config)); std::string dstdir = video_dest_dir (_session->session_directory ().video_path (), video_get_docroot (Config));
std::string dstfn = video_dest_file (dstdir, infile); std::string dstfn = video_dest_file (dstdir, infile);
path_entry.set_width_chars (38);
path_entry.set_text (dstfn); path_entry.set_text (dstfn);
l = manage (new Label (_("<b>File Information</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); l = manage (new Label (_("<b>File Information</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
@ -118,8 +119,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
options_box->pack_start (*l, false, true, 4); options_box->pack_start (*l, false, true, 4);
aspect_checkbox.set_sensitive (false); aspect_checkbox.set_sensitive (false);
bitrate_checkbox.set_sensitive (false); bitrate_checkbox.set_sensitive (false);
} } else if (!transcoder->probe_ok ()) {
else if (!transcoder->probe_ok()) {
l = manage (new Label (string_compose (_("File-info can not be read. Most likely '%1' is not a valid video-file or an unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); l = manage (new Label (string_compose (_("File-info can not be read. Most likely '%1' is not a valid video-file or an unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
options_box->pack_start (*l, false, true, 4); options_box->pack_start (*l, false, true, 4);
aspect_checkbox.set_sensitive (false); aspect_checkbox.set_sensitive (false);
@ -231,17 +231,39 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
t->attach (height_spinner, 3, 4, 0, 1); t->attach (height_spinner, 3, 4, 0, 1);
scale_combo.append_text (_("Original Width")); scale_combo.append_text (_("Original Width"));
if (w > 1920) { scale_combo.append_text("1920 (hd1080)"); } if (w > 1920) {
if (w > 1408) { scale_combo.append_text("1408 (16cif)"); } scale_combo.append_text ("1920 (hd1080)");
if (w > 1280) { scale_combo.append_text("1280 (sxga, hd720)"); } }
if (w > 1024) { scale_combo.append_text("1024 (xga)"); } if (w > 1408) {
if (w > 852) { scale_combo.append_text(" 852 (hd480)"); } scale_combo.append_text ("1408 (16cif)");
if (w > 768) { scale_combo.append_text(" 768 (PAL)"); } }
if (w > 720) { scale_combo.append_text(" 720 (PAL)"); } if (w > 1280) {
if (w > 640) { scale_combo.append_text(" 640 (vga, ega)"); } scale_combo.append_text ("1280 (sxga, hd720)");
if (w > 352) { scale_combo.append_text(" 352 (cif)"); } }
if (w > 320) { scale_combo.append_text(" 320 (cga, qvga)"); } if (w > 1024) {
if (w > 176) { scale_combo.append_text(" 176 (qcif)"); } scale_combo.append_text ("1024 (xga)");
}
if (w > 852) {
scale_combo.append_text (" 852 (hd480)");
}
if (w > 768) {
scale_combo.append_text (" 768 (PAL)");
}
if (w > 720) {
scale_combo.append_text (" 720 (PAL)");
}
if (w > 640) {
scale_combo.append_text (" 640 (vga, ega)");
}
if (w > 352) {
scale_combo.append_text (" 352 (cif)");
}
if (w > 320) {
scale_combo.append_text (" 320 (cga, qvga)");
}
if (w > 176) {
scale_combo.append_text (" 176 (qcif)");
}
scale_combo.set_active (0); scale_combo.set_active (0);
height_spinner.set_value (h); height_spinner.set_value (h);
@ -254,6 +276,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
t->attach (*l, 0, 1, 2, 3); t->attach (*l, 0, 1, 2, 3);
t->attach (audio_combo, 1, 4, 2, 3); t->attach (audio_combo, 1, 4, 2, 3);
t->attach (ltc_detect, 1, 4, 3, 4); t->attach (ltc_detect, 1, 4, 3, 4);
if (as.size () == 0) { if (as.size () == 0) {
audio_combo.append_text (_("No Audio Track Present")); audio_combo.append_text (_("No Audio Track Present"));
audio_combo.set_sensitive (false); audio_combo.set_sensitive (false);
@ -266,9 +289,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
audio_combo.set_active (0); audio_combo.set_active (0);
ltc_detect.set_sensitive (false); ltc_detect.set_sensitive (false);
#if 1 /* tentative debug mode */
options_box->pack_start (debug_checkbox, false, true, 4); options_box->pack_start (debug_checkbox, false, true, 4);
#endif
vbox->pack_start (*path_hbox, false, false); vbox->pack_start (*path_hbox, false, false);
vbox->pack_start (*options_box, false, true); vbox->pack_start (*options_box, false, true);
@ -298,6 +319,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL); cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
get_action_area ()->pack_start (transcode_button, false, false); get_action_area ()->pack_start (transcode_button, false, false);
show_all_children (); show_all_children ();
progress_box->hide (); progress_box->hide ();
} }
@ -332,9 +354,12 @@ TranscodeVideoDialog::update_progress (samplecnt_t c, samplecnt_t a)
} }
void void
TranscodeVideoDialog::finished () TranscodeVideoDialog::finished (int status)
{ {
if (aborted) { if (aborted || status != 0) {
if (!aborted) {
ARDOUR_UI::instance ()->popup_error (_("Video transcoding failed."));
}
::g_unlink (path_entry.get_text ().c_str ()); ::g_unlink (path_entry.get_text ().c_str ());
if (!audiofile.empty ()) { if (!audiofile.empty ()) {
::g_unlink (audiofile.c_str ()); ::g_unlink (audiofile.c_str ());
@ -342,7 +367,7 @@ TranscodeVideoDialog::finished ()
Gtk::Dialog::response (RESPONSE_CANCEL); Gtk::Dialog::response (RESPONSE_CANCEL);
} else { } else {
if (pending_audio_extract) { if (pending_audio_extract) {
StartNextStage(); StartNextStage (); /* EMIT SIGNAL */
} else { } else {
Gtk::Dialog::response (RESPONSE_ACCEPT); Gtk::Dialog::response (RESPONSE_ACCEPT);
} }
@ -353,17 +378,15 @@ void
TranscodeVideoDialog::launch_audioonly () TranscodeVideoDialog::launch_audioonly ()
{ {
if (audio_combo.get_active_row_number () == 0) { if (audio_combo.get_active_row_number () == 0) {
finished(); finished (0);
return; return;
} }
dialog_progress_mode (); dialog_progress_mode ();
#if 1 /* tentative debug mode */
if (debug_checkbox.get_active ()) { if (debug_checkbox.get_active ()) {
transcoder->set_debug (true); transcoder->set_debug (true);
} }
#endif
transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ()); transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ());
transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context()); transcoder->Finished.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this, _1), gui_context ());
launch_extract (); launch_extract ();
} }
@ -371,10 +394,10 @@ void
TranscodeVideoDialog::launch_extract () TranscodeVideoDialog::launch_extract ()
{ {
audiofile = path_entry.get_text () + ".wav"; /* TODO: mktemp */ audiofile = path_entry.get_text () + ".wav"; /* TODO: mktemp */
int audio_stream;
pending_audio_extract = false; pending_audio_extract = false;
aborted = false; aborted = false;
audio_stream = audio_combo.get_active_row_number() -1; int audio_stream = audio_combo.get_active_row_number () - 1;
progress_label.set_text (_("Extracting Audio..")); progress_label.set_text (_("Extracting Audio.."));
if (!transcoder->extract_audio (audiofile, _session->nominal_sample_rate (), audio_stream)) { if (!transcoder->extract_audio (audiofile, _session->nominal_sample_rate (), audio_stream)) {
@ -403,14 +426,13 @@ TranscodeVideoDialog::launch_transcode ()
return; return;
} }
std::string outfn = path_entry.get_text (); std::string outfn = path_entry.get_text ();
if (!confirm_video_outfn(*this, outfn, video_get_docroot(Config))) return; if (!confirm_video_outfn (*this, outfn, video_get_docroot (Config)))
return;
progress_label.set_text (_("Transcoding Video..")); progress_label.set_text (_("Transcoding Video.."));
dialog_progress_mode (); dialog_progress_mode ();
#if 1 /* tentative debug mode */
if (debug_checkbox.get_active ()) { if (debug_checkbox.get_active ()) {
transcoder->set_debug (true); transcoder->set_debug (true);
} }
#endif
aborted = false; aborted = false;
if (audio_combo.get_active_row_number () != 0) { if (audio_combo.get_active_row_number () != 0) {
@ -436,7 +458,7 @@ TranscodeVideoDialog::launch_transcode ()
} }
transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ()); transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ());
transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context()); transcoder->Finished.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this, _1), gui_context ());
if (!transcoder->transcode (outfn, scale_width, scale_height, bitrate)) { if (!transcoder->transcode (outfn, scale_width, scale_height, bitrate)) {
ARDOUR_UI::instance ()->popup_error (_("Transcoding Failed.")); ARDOUR_UI::instance ()->popup_error (_("Transcoding Failed."));
Gtk::Dialog::response (RESPONSE_CANCEL); Gtk::Dialog::response (RESPONSE_CANCEL);
@ -472,17 +494,13 @@ TranscodeVideoDialog::video_combo_changed ()
void void
TranscodeVideoDialog::audio_combo_changed () TranscodeVideoDialog::audio_combo_changed ()
{ {
if (video_combo.get_active_row_number() == 2 if (video_combo.get_active_row_number () == 2 && audio_combo.get_active_row_number () == 0) {
&& audio_combo.get_active_row_number() == 0)
{
audio_combo.set_active (1); audio_combo.set_active (1);
ltc_detect.set_sensitive (false); ltc_detect.set_sensitive (false);
ltc_detect.set_active (false); ltc_detect.set_active (false);
} }
if (video_combo.get_active_row_number() != 2 if (video_combo.get_active_row_number () != 2 && audio_combo.get_active_row_number () > 0) {
&& audio_combo.get_active_row_number() > 0)
{
ltc_detect.set_sensitive (true); ltc_detect.set_sensitive (true);
} else { } else {
ltc_detect.set_sensitive (false); ltc_detect.set_sensitive (false);
@ -525,7 +543,9 @@ void
TranscodeVideoDialog::update_bitrate () TranscodeVideoDialog::update_bitrate ()
{ {
double br = .7; /* avg quality - bits per pixel */ double br = .7; /* avg quality - bits per pixel */
if (bitrate_checkbox.get_active() || !transcoder->probe_ok()) { return; } if (bitrate_checkbox.get_active () || !transcoder->probe_ok ()) {
return;
}
br *= transcoder->get_fps (); br *= transcoder->get_fps ();
br *= height_spinner.get_value (); br *= height_spinner.get_value ();
@ -561,7 +581,8 @@ TranscodeVideoDialog::open_browse_dialog ()
} }
enum VtlTranscodeOption enum VtlTranscodeOption
TranscodeVideoDialog::import_option() { TranscodeVideoDialog::import_option ()
{
int i = video_combo.get_active_row_number (); int i = video_combo.get_active_row_number ();
return static_cast<VtlTranscodeOption> (i); return static_cast<VtlTranscodeOption> (i);
} }

View File

@ -25,13 +25,13 @@
#include <gtkmm/button.h> #include <gtkmm/button.h>
#include <gtkmm/checkbutton.h> #include <gtkmm/checkbutton.h>
#include <gtkmm/comboboxtext.h> #include <gtkmm/comboboxtext.h>
#include <gtkmm/label.h>
#include <gtkmm/entry.h> #include <gtkmm/entry.h>
#include <gtkmm/label.h>
#include <gtkmm/progressbar.h> #include <gtkmm/progressbar.h>
#include <gtkmm/spinbutton.h> #include <gtkmm/spinbutton.h>
#include "ardour/types.h"
#include "ardour/template_utils.h" #include "ardour/template_utils.h"
#include "ardour/types.h"
#include "ardour_dialog.h" #include "ardour_dialog.h"
#include "transcode_ffmpeg.h" #include "transcode_ffmpeg.h"
@ -51,12 +51,25 @@ public:
TranscodeVideoDialog (ARDOUR::Session*, std::string); TranscodeVideoDialog (ARDOUR::Session*, std::string);
~TranscodeVideoDialog (); ~TranscodeVideoDialog ();
std::string get_filename () { return path_entry.get_text(); }
std::string get_audiofile () { return audiofile; }
VtlTranscodeOption import_option (); VtlTranscodeOption import_option ();
bool detect_ltc () { return ltc_detect.get_active (); }
void on_response (int response_id) { std::string get_filename ()
{
return path_entry.get_text ();
}
std::string get_audiofile ()
{
return audiofile;
}
bool detect_ltc ()
{
return ltc_detect.get_active ();
}
void on_response (int response_id)
{
Gtk::Dialog::on_response (response_id); Gtk::Dialog::on_response (response_id);
} }
@ -74,6 +87,9 @@ private:
void launch_transcode (); void launch_transcode ();
void launch_extract (); void launch_extract ();
void dialog_progress_mode (); void dialog_progress_mode ();
void finished (int);
void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t);
bool aborted; bool aborted;
bool pending_audio_extract; bool pending_audio_extract;
std::string audiofile; std::string audiofile;
@ -81,8 +97,6 @@ private:
double m_aspect; double m_aspect;
PBD::Signal0<void> StartNextStage; PBD::Signal0<void> StartNextStage;
void finished ();
void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t);
TranscodeFfmpeg* transcoder; TranscodeFfmpeg* transcoder;
@ -109,10 +123,7 @@ private:
Gtk::CheckButton bitrate_checkbox; Gtk::CheckButton bitrate_checkbox;
Gtk::Adjustment bitrate_adjustment; Gtk::Adjustment bitrate_adjustment;
Gtk::SpinButton bitrate_spinner; Gtk::SpinButton bitrate_spinner;
#if 1 /* tentative debug mode */
Gtk::CheckButton debug_checkbox; Gtk::CheckButton debug_checkbox;
#endif
}; };
#endif /* __gtk_ardour_transcode_video_dialog_h__ */ #endif /* __gtk_ardour_transcode_video_dialog_h__ */