4 * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "assetedit.h"
25 #include "awindowgui.h"
26 #include "bcprogressbox.h"
27 #include "bcsignals.h"
28 #include "bitspopup.h"
31 #include "cplayback.h"
34 #include "edlsession.h"
37 #include "fileffmpeg.h"
38 #include "filesystem.h"
39 #include "indexable.h"
40 #include "indexfile.h"
41 #include "indexstate.h"
43 #include "mainindexes.h"
45 #include "mwindowgui.h"
48 #include "preferences.h"
49 #include "resizetrackthread.h"
50 #include "removefile.h"
52 #include "transportque.h"
53 #include "interlacemodes.h"
55 #include "edlsession.h"
61 AssetEdit::AssetEdit(MWindow *mwindow)
64 this->mwindow = mwindow;
67 changed_params = new Asset;
72 AssetEdit::~AssetEdit()
75 changed_params->remove_user();
79 void AssetEdit::edit_asset(Indexable *indexable, int x, int y)
82 this->indexable = indexable;
83 this->indexable->add_user();
84 this->x = x; this->y = y;
86 // Copy asset parameters into temporary storage for editing.
87 if( indexable->is_asset ) {
88 changed_params->copy_from((Asset*)indexable, 0);
91 EDL *nested_edl = (EDL*)indexable;
92 strcpy(changed_params->path, nested_edl->path);
93 changed_params->sample_rate = nested_edl->session->sample_rate;
94 changed_params->channels = nested_edl->session->audio_channels;
96 //printf("AssetEdit::edit_asset %d %f\n", __LINE__, nested_edl->session->frame_rate);
97 changed_params->frame_rate = nested_edl->session->frame_rate;
98 changed_params->width = nested_edl->session->output_w;
99 changed_params->height = nested_edl->session->output_h;
102 BC_DialogThread::start();
105 void AssetEdit::handle_done_event(int result)
107 if( !result && changed_params->timecode >= 0 ) {
108 double rate = indexable->get_frame_rate();
109 changed_params->timecode =
110 atoi(window->tc_hrs->get_text()) * 3600 +
111 atoi(window->tc_mins->get_text()) * 60 +
112 atoi(window->tc_secs->get_text()) +
113 atoi(window->tc_rest->get_text()) / rate;
117 void AssetEdit::handle_close_event(int result)
124 if( indexable->is_asset ) {
125 asset = (Asset*)indexable;
126 if( !changed_params->equivalent(*asset, 1, 1, mwindow->edl) )
130 nested_edl = (EDL*)indexable;
131 if( strcmp(changed_params->path, nested_edl->path)
132 // || changed_params->sample_rate != nested_edl->session->sample_rate
133 // || !EQUIV(changed_params->frame_rate, nested_edl->session->frame_rate
138 mwindow->gui->lock_window();
139 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
141 // Omit index status from copy since an index rebuild may have been
142 // happening when new_asset was created but not be happening anymore.
144 mwindow->remove_from_caches(asset);
145 //printf("AssetEdit::handle_close_event %d %f\n", __LINE__, asset->get_frame_rate());
146 asset->copy_from(changed_params, 0);
147 //printf("AssetEdit::handle_close_event %d %d %d\n", __LINE__, changed_params->bits, asset->bits);
150 strcpy(nested_edl->path, changed_params->path);
151 // Other parameters can't be changed because they're defined in the other EDL
152 // nested_edl->session->frame_rate = changed_params->frame_rate;
153 // nested_edl->session->sample_rate = changed_params->sample_rate;
155 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
157 mwindow->gui->update(0, FORCE_REDRAW, 0, 0, 0, 0, 0);
158 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
160 // Start index rebuilding
161 if( (asset && asset->audio_data) || nested_edl) {
162 char source_filename[BCTEXTLEN];
163 char index_filename[BCTEXTLEN];
164 IndexFile::get_index_filename(source_filename,
165 mwindow->preferences->index_directory,
168 remove_file(index_filename);
169 indexable->index_state->index_status = INDEX_NOTTESTED;
170 mwindow->mainindexes->add_indexable(indexable);
171 mwindow->mainindexes->start_build();
173 mwindow->gui->unlock_window();
174 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
175 mwindow->awindow->gui->update_picon(indexable);
176 mwindow->awindow->gui->async_update_assets();
178 mwindow->restart_brender();
179 mwindow->sync_parameters(CHANGE_ALL);
180 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
184 this->indexable->remove_user();
186 //printf("AssetEdit::handle_close_event %d\n", __LINE__);
189 BC_Window* AssetEdit::new_gui()
191 window = new AssetEditWindow(mwindow, this);
192 window->create_objects();
196 int AssetEdit::window_height()
198 int h = yS(128 + 64);
199 if( indexable->have_audio() ) h += yS(200);
200 if( indexable->have_video() ) {
202 if( indexable->is_asset ) {
203 Asset *asset = (Asset *)indexable;
204 if( File::can_scale_input(asset) )
206 if( asset->timecode >= 0 )
213 #define AEW_W xS(450)
215 AssetEditWindow::AssetEditWindow(MWindow *mwindow, AssetEdit *asset_edit)
216 : BC_Window(_(PROGRAM_NAME ": Asset Info"),
217 asset_edit->x - AEW_W/2, asset_edit->y - asset_edit->window_height()/2,
218 AEW_W, asset_edit->window_height(), 0, 0, 1)
220 this->mwindow = mwindow;
221 this->asset_edit = asset_edit;
231 // *** CONTEXT_HELP ***
232 context_help_set_keyword("Info Asset Details");
239 AssetEditWindow::~AssetEditWindow()
241 lock_window("AssetEditWindow::~AssetEditWindow");
243 delete detail_dialog;
250 void AssetEditWindow::create_objects()
253 int ypad5 = yS(5), ypad10 = yS(10), ypad20 = yS(20), ypad30 = yS(30);
254 int y = ypad10, x = xpad10, x1 = xpad10, x2 = xS(190);
255 char string[BCTEXTLEN];
261 if( asset_edit->indexable->is_asset )
262 asset = (Asset*)asset_edit->indexable;
264 nested_edl = (EDL*)asset_edit->indexable;
266 allow_edits = asset && asset->format == FILE_PCM ? 1 : 0;
267 int vmargin = yS(allow_edits ? 30 : 20);
268 lock_window("AssetEditWindow::create_objects");
270 add_subwindow(path_text = new AssetEditPathText(this, y));
271 add_subwindow(path_button = new AssetEditPath(mwindow, this,
272 path_text, y, asset_edit->indexable->path,
273 _(PROGRAM_NAME ": Asset path"),
274 _("Select a file for this asset:")));
278 add_subwindow(new BC_Title(x, y, _("File format:")));
280 add_subwindow(new BC_Title(x, y, File::formattostr(asset->format),
282 mwindow->theme->assetedit_color));
286 int64_t bytes = fs.get_size(asset->path);
287 add_subwindow(new BC_Title(x, y, _("Bytes:")));
288 sprintf(string, "%jd", bytes);
289 Units::punctuate(string);
292 add_subwindow(new BC_Title(x2, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
293 if( asset->format == FILE_MPEG || asset->format == FILE_FFMPEG ) {
294 detail_dialog = new DetailAssetDialog(mwindow);
295 BC_GenericButton *detail = new DetailAssetButton(this, x2+xS(120), y);
296 add_subwindow(detail);
306 if( asset->audio_length > 0 )
307 length = (double)asset->audio_length / asset->sample_rate;
308 if( asset->video_length > 0 )
309 length = MAX(length, (double)asset->video_length / asset->frame_rate);
311 if( !EQUIV(length, 0) )
312 bitrate = (int64_t)(bytes * 8 / length);
315 add_subwindow(new BC_Title(x, y, _("Bitrate (bits/sec):")));
316 sprintf(string, "%jd", bitrate);
318 Units::punctuate(string);
319 add_subwindow(new BC_Title(x2, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
325 if( (asset && asset->audio_data) || nested_edl ) {
326 add_subwindow(new BC_Bar(x, y, get_w() - x * 2));
329 add_subwindow(new BC_Title(x, y, _("Audio:"), LARGEFONT, RED));
334 if( asset->get_compression_text(1, 0) ) {
335 add_subwindow(new BC_Title(x, y, _("Compression:")));
337 add_subwindow(new BC_Title(x,
339 asset->get_compression_text(1, 0),
341 mwindow->theme->assetedit_color));
347 add_subwindow(new BC_Title(x, y, _("Channels:")));
348 sprintf(string, "%d", asset_edit->changed_params->channels);
352 BC_TumbleTextBox *textbox = new AssetEditChannels(this,
356 textbox->create_objects();
360 add_subwindow(new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
365 add_subwindow(new BC_Title(x, y, _("Sample rate:")));
366 sprintf(string, "%d", asset_edit->changed_params->sample_rate);
371 add_subwindow(textbox = new AssetEditRate(this, string, x, y));
372 x += textbox->get_w();
373 add_subwindow(new SampleRatePulldown(mwindow, textbox, x, y));
376 add_subwindow(new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
383 add_subwindow(new BC_Title(x, y, _("Bits:")));
386 bitspopup = new BitsPopup(this, x, y,
387 &asset_edit->changed_params->bits,
389 bitspopup->create_objects();
392 add_subwindow(new BC_Title(x, y, File::bitstostr(asset->bits), MEDIUMFONT, mwindow->theme->assetedit_color));
397 add_subwindow(new BC_Title(x, y, _("Header length:")));
398 sprintf(string, "%d", asset->header);
402 add_subwindow(new AssetEditHeader(this, string, x, y));
404 add_subwindow(new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
409 add_subwindow(new BC_Title(x, y, _("Byte order:")));
415 add_subwindow(lohi = new AssetEditByteOrderLOHI(this,
416 asset->byte_order, x, y));
418 add_subwindow(hilo = new AssetEditByteOrderHILO(this,
419 !asset->byte_order, x, y));
424 if( asset->byte_order )
425 add_subwindow(new BC_Title(x, y, _("Lo-Hi"), MEDIUMFONT, mwindow->theme->assetedit_color));
427 add_subwindow(new BC_Title(x, y, _("Hi-Lo"), MEDIUMFONT, mwindow->theme->assetedit_color));
434 // add_subwindow(new BC_Title(x, y, _("Values are signed:")));
435 add_subwindow(new AssetEditSigned(this, asset->signed_, x, y));
438 if( !asset->signed_ && asset->bits == 8 )
439 add_subwindow(new BC_Title(x, y, _("Values are unsigned")));
441 add_subwindow(new BC_Title(x, y, _("Values are signed")));
449 if( (asset && asset->video_data) || nested_edl ) {
450 add_subwindow(new BC_Bar(x, y, get_w() - x * 2));
453 add_subwindow(new BC_Title(x, y, _("Video:"), LARGEFONT, RED));
458 if( asset && asset->get_compression_text(0,1) ) {
459 add_subwindow(new BC_Title(x, y, _("Compression:")));
461 add_subwindow(new BC_Title(x,
463 asset->get_compression_text(0,1),
465 mwindow->theme->assetedit_color));
470 add_subwindow(new BC_Title(x, y, _("Frame rate:")));
472 sprintf(string, "%.4f", asset_edit->changed_params->frame_rate);
474 //printf("AssetEditWindow::create_objects %d %f\n", __LINE__, asset_edit->changed_params->frame_rate);
476 BC_TextBox *framerate;
477 add_subwindow(framerate = new AssetEditFRate(this, string, x, y));
478 x += framerate->get_w();
479 add_subwindow(new FrameRatePulldown(mwindow, framerate, x, y));
482 add_subwindow(new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
487 add_subwindow(new BC_Title(x, y, _("Width:")));
489 sprintf(string, "%d", asset_edit->changed_params->width);
490 win_width = new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color);
491 add_subwindow(win_width);
495 add_subwindow(new BC_Title(x, y, _("Height:")));
497 sprintf(string, "%d", asset_edit->changed_params->height);
498 win_height = new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color);
499 add_subwindow(win_height);
500 y += win_height->get_h() + ypad5;
502 if( asset && File::can_scale_input(asset) ) {
505 add_subwindow(new BC_Title(x, y, _("Actual width:")));
507 sprintf(string, "%d", asset->actual_width);
508 add_subwindow(new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color));
510 BC_GenericButton *resize = new ResizeAssetButton(this, x+xS(64), y);
511 add_subwindow(resize);
515 add_subwindow(new BC_Title(x, y, _("Actual height:")));
517 sprintf(string, "%d", asset->actual_height);
518 title = new BC_Title(x, y, string, MEDIUMFONT, mwindow->theme->assetedit_color);
519 add_subwindow(title);
520 y += title->get_h() + ypad5;
523 add_subwindow(title = new BC_Title(x1, y, _("Asset's interlacing:")));
524 ilacemode_to_text(string, asset->interlace_mode);
525 AssetEditILacemode *edit_ilace_mode;
526 add_subwindow(edit_ilace_mode = new AssetEditILacemode(this, string, x2, y, xS(160)));
527 add_subwindow(new AssetEditInterlacemodePulldown(mwindow, edit_ilace_mode,
528 &asset_edit->changed_params->interlace_mode,
529 (ArrayList<BC_ListBoxItem*>*)&mwindow->interlace_asset_modes,
530 x2 + edit_ilace_mode->get_w(), y));
531 y += title->get_h() + yS(15);
534 if( asset && asset->timecode >= 0 ) {
535 char text[BCSTRLEN], *tc = text;
536 Units::totext(tc, asset->timecode, TIME_HMSF,
537 asset->sample_rate, asset->frame_rate);
538 const char *hrs = tc; tc = strchr(tc, ':'); *tc++ = 0;
539 const char *mins = tc; tc = strchr(tc, ':'); *tc++ = 0;
540 const char *secs = tc; tc = strchr(tc, ':'); *tc++ = 0;
541 const char *rest = tc;
542 int padw = BC_Title::calculate_w(this, ":", MEDIUMFONT);
543 int fldw = BC_Title::calculate_w(this, "00", MEDIUMFONT) + 5;
544 int hdrw = fldw + padw; x = x2;
545 add_subwindow(title = new BC_Title(x, y, _("hour"), SMALLFONT)); x += hdrw;
546 add_subwindow(title = new BC_Title(x, y, _("min"), SMALLFONT)); x += hdrw;
547 add_subwindow(title = new BC_Title(x, y, _("sec"), SMALLFONT)); x += hdrw;
548 add_subwindow(title = new BC_Title(x, y, _("frms"), SMALLFONT));
549 y += title->get_h() + xS(3);
550 add_subwindow(title = new BC_Title(x1, y, _("Time Code Start:")));
551 add_subwindow(tc_hrs = new BC_TextBox(x=x2, y, fldw, 1, hrs));
552 add_subwindow(new BC_Title(x += tc_hrs->get_w(), y, ":"));
553 add_subwindow(tc_mins = new BC_TextBox(x += padw, y, fldw, 1, mins));
554 add_subwindow(new BC_Title(x += tc_mins->get_w(), y, ":"));
555 add_subwindow(tc_secs = new BC_TextBox(x += padw, y , fldw, 1, secs));
556 add_subwindow(new BC_Title(x += tc_secs->get_w(), y, ":"));
557 add_subwindow(tc_rest = new BC_TextBox(x += 10, y, fldw, 1, rest));
558 y += title->get_h() + ypad5;
561 add_subwindow(new BC_OKButton(this));
562 add_subwindow(new BC_CancelButton(this));
567 void AssetEditWindow::show_info_detail()
570 get_abs_cursor(cur_x, cur_y, 0);
571 detail_dialog->start((Asset*)asset_edit->indexable, cur_x, cur_y);
575 AssetEditChannels::AssetEditChannels(AssetEditWindow *fwindow,
579 : BC_TumbleTextBox(fwindow, (int)atol(text), (int)1,
580 (int)MAXCHANNELS, x, y, xS(50))
582 this->fwindow = fwindow;
585 int AssetEditChannels::handle_event()
587 Asset *asset = fwindow->asset_edit->changed_params;
588 asset->channels = atol(get_text());
592 AssetEditRate::AssetEditRate(AssetEditWindow *fwindow, char *text, int x, int y)
593 : BC_TextBox(x, y, xS(100), 1, text)
595 this->fwindow = fwindow;
598 int AssetEditRate::handle_event()
600 Asset *asset = fwindow->asset_edit->changed_params;
601 asset->sample_rate = atol(get_text());
605 AssetEditFRate::AssetEditFRate(AssetEditWindow *fwindow, char *text, int x, int y)
606 : BC_TextBox(x, y, xS(100), 1, text)
608 this->fwindow = fwindow;
611 int AssetEditFRate::handle_event()
613 Asset *asset = fwindow->asset_edit->changed_params;
614 asset->frame_rate = atof(get_text());
619 AssetEditILacemode::AssetEditILacemode(AssetEditWindow *fwindow, const char *text, int x, int y, int w)
620 : BC_TextBox(x, y, w, 1, text)
622 this->fwindow = fwindow;
625 int AssetEditILacemode::handle_event()
627 Asset *asset = fwindow->asset_edit->changed_params;
628 asset->interlace_mode = ilacemode_from_text(get_text(), ILACE_ASSET_MODEDEFAULT);
632 AssetEditInterlacemodePulldown::AssetEditInterlacemodePulldown(MWindow *mwindow,
633 BC_TextBox *output_text, int *output_value,
634 ArrayList<BC_ListBoxItem*> *data, int x, int y)
635 : BC_ListBox(x, y, xS(160), yS(80), LISTBOX_TEXT, data, 0, 0, 1, 0, 1)
637 this->mwindow = mwindow;
638 this->output_text = output_text;
639 this->output_value = output_value;
640 output_text->update(interlacemode_to_text());
643 int AssetEditInterlacemodePulldown::handle_event()
645 output_text->update(get_selection(0, 0)->get_text());
646 *output_value = ((InterlacemodeItem*)get_selection(0, 0))->value;
650 char* AssetEditInterlacemodePulldown::interlacemode_to_text()
652 ilacemode_to_text(this->string,*output_value);
653 return (this->string);
656 AssetEditHeader::AssetEditHeader(AssetEditWindow *fwindow, char *text, int x, int y)
657 : BC_TextBox(x, y, xS(100), 1, text)
659 this->fwindow = fwindow;
662 int AssetEditHeader::handle_event()
664 Asset *asset = fwindow->asset_edit->changed_params;
665 asset->header = atol(get_text());
669 AssetEditByteOrderLOHI::AssetEditByteOrderLOHI(AssetEditWindow *fwindow,
673 : BC_Radial(x, y, value, _("Lo-Hi"))
675 this->fwindow = fwindow;
678 int AssetEditByteOrderLOHI::handle_event()
680 Asset *asset = fwindow->asset_edit->changed_params;
681 asset->byte_order = 1;
682 fwindow->hilo->update(0);
687 AssetEditByteOrderHILO::AssetEditByteOrderHILO(AssetEditWindow *fwindow,
691 : BC_Radial(x, y, value, _("Hi-Lo"))
693 this->fwindow = fwindow;
696 int AssetEditByteOrderHILO::handle_event()
698 Asset *asset = fwindow->asset_edit->changed_params;
699 asset->byte_order = 0;
700 fwindow->lohi->update(0);
705 AssetEditSigned::AssetEditSigned(AssetEditWindow *fwindow,
709 : BC_CheckBox(x, y, value, _("Values are signed"))
711 this->fwindow = fwindow;
714 int AssetEditSigned::handle_event()
716 Asset *asset = fwindow->asset_edit->changed_params;
717 asset->signed_ = get_value();
727 AssetEditPathText::AssetEditPathText(AssetEditWindow *fwindow, int y)
728 : BC_TextBox(5, y, xS(300), 1, fwindow->asset_edit->changed_params->path)
730 this->fwindow = fwindow;
732 AssetEditPathText::~AssetEditPathText()
735 int AssetEditPathText::handle_event()
737 strcpy(fwindow->asset_edit->changed_params->path, get_text());
741 AssetEditPath::AssetEditPath(MWindow *mwindow, AssetEditWindow *fwindow,
742 BC_TextBox *textbox, int y, const char *text,
743 const char *window_title, const char *window_caption)
744 : BrowseButton(mwindow->theme, fwindow, textbox, yS(310), y, text,
745 window_title, window_caption, 0)
747 this->fwindow = fwindow;
750 AssetEditPath::~AssetEditPath() {}
755 DetailAssetButton::DetailAssetButton(AssetEditWindow *fwindow, int x, int y)
756 : BC_GenericButton(x, y, _("Detail"))
758 this->fwindow = fwindow;
761 DetailAssetButton::~DetailAssetButton()
765 int DetailAssetButton::handle_event()
767 fwindow->show_info_detail();
771 #define DTL_W xS(600)
772 #define DTL_H yS(500)
774 DetailAssetWindow::DetailAssetWindow(MWindow *mwindow,
775 DetailAssetDialog *detail_dialog, Asset *asset)
776 : BC_Window(_("Asset Detail"),
777 detail_dialog->x - DTL_W/2, detail_dialog->y - DTL_H/2, DTL_W, DTL_H)
779 this->mwindow = mwindow;
780 this->detail_dialog = detail_dialog;
785 // *** CONTEXT_HELP ***
786 context_help_set_keyword("Info Asset Details");
789 DetailAssetWindow::~DetailAssetWindow()
791 asset->remove_user();
795 DetailAssetDialog::DetailAssetDialog(MWindow *mwindow)
798 this->mwindow = mwindow;
802 DetailAssetDialog::~DetailAssetDialog()
807 void DetailAssetWindow::create_objects()
809 int y = yS(10), x = xS(10);
810 char file_name[BCTEXTLEN];
811 int len = sizeof(info);
812 strncpy(info,_("no info available"),len);
813 if( !mwindow->preferences->get_asset_file_path(asset, file_name) ) {
814 switch( asset->format ) {
817 FileMPEG::get_info(asset->path, file_name, &info[0],len);
821 FileFFMPEG::get_info(asset->path, &info[0],len);
825 lock_window("DetailAssetWindow::create_objects");
826 int text_h = get_h()-y - BC_OKButton::calculate_h() - yS(15);
827 int lines = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
828 text = new BC_ScrollTextBox(this, x, y, get_w()-xS(32), lines, info, -len);
829 text->create_objects(); text->set_text_row(0);
830 add_subwindow(new BC_OKButton(this));
835 void DetailAssetDialog::start(Asset *asset, int x, int y)
839 this->x = x; this->y = y;
840 BC_DialogThread::start();
843 BC_Window *DetailAssetDialog::new_gui()
845 dwindow = new DetailAssetWindow(mwindow, this, asset);
846 dwindow->create_objects();