7 // work around for __STDC_CONSTANT_MACROS
11 #include "bcwindowbase.h"
12 #include "bitspopup.h"
16 #include "fileffmpeg.h"
17 #include "filesystem.h"
19 #include "videodevice.inc"
21 FileFFMPEG::FileFFMPEG(Asset *asset, File *file)
22 : FileBase(asset, file)
25 if(asset->format == FILE_UNKNOWN)
26 asset->format = FILE_FFMPEG;
29 FileFFMPEG::~FileFFMPEG()
35 FFMpegConfigNum::FFMpegConfigNum(BC_Window *window,
36 int x, int y, char *title_text, int *output)
37 : BC_TumbleTextBox(window, (int64_t)*output,
38 (int64_t)-1, (int64_t)25000000, 100, y, 100)
40 this->window = window;
41 this->x = x; this->y = y;
42 this->title_text = title_text;
43 this->output = output;
46 FFMpegConfigNum::~FFMpegConfigNum()
50 void FFMpegConfigNum::create_objects()
52 window->add_subwindow(title = new BC_Title(x, y, title_text));
53 BC_TumbleTextBox::create_objects();
56 int FFMpegConfigNum::handle_event()
58 *output = atol(get_text());
62 FFMpegAudioNum::FFMpegAudioNum(BC_Window *window,
63 int x, int y, char *title_text, int *output)
64 : FFMpegConfigNum(window, x, y, title_text, output)
68 int FFMpegAudioBitrate::handle_event()
70 int ret = FFMpegAudioNum::handle_event();
74 FFMpegVideoNum::FFMpegVideoNum(BC_Window *window,
75 int x, int y, char *title_text, int *output)
76 : FFMpegConfigNum(window, x, y, title_text, output)
80 int FFMpegVideoBitrate::handle_event()
82 int ret = FFMpegVideoNum::handle_event();
83 Asset *asset = window()->asset;
84 if( asset->ff_video_bitrate )
85 window()->quality->disable();
87 window()->quality->enable();
91 int FFMpegVideoQuality::handle_event()
93 int ret = FFMpegVideoNum::handle_event();
94 Asset *asset = window()->asset;
95 if( asset->ff_video_quality )
96 window()->bitrate->disable();
98 window()->bitrate->enable();
102 void FileFFMPEG::get_parameters(BC_WindowBase *parent_window,
103 Asset *asset, BC_WindowBase *&format_window,
104 int audio_options, int video_options)
107 FFMPEGConfigAudio *window = new FFMPEGConfigAudio(parent_window, asset);
108 format_window = window;
109 window->create_objects();
110 window->run_window();
113 else if(video_options) {
114 FFMPEGConfigVideo *window = new FFMPEGConfigVideo(parent_window, asset);
115 format_window = window;
116 window->create_objects();
117 window->run_window();
122 int FileFFMPEG::check_sig(Asset *asset)
124 char *ptr = strstr(asset->path, ".pcm");
126 ptr = strstr(asset->path, ".raw");
130 int ret = !ffmpeg.init_decoder(asset->path) &&
131 !ffmpeg.open_decoder() ? 1 : 0;
135 void FileFFMPEG::get_info(char *path, char *text)
139 cp += sprintf(cp, "file path: %s\n", path);
142 if( stat(path, &st) < 0 ) {
143 cp += sprintf(cp, " err: %s\n", strerror(errno));
147 cp += sprintf(cp, " %jd bytes\n", st.st_size);
149 if( !ret ) ret = ffmpeg.init_decoder(path);
150 if( !ret ) ret = ffmpeg.open_decoder();
152 cp += sprintf(cp, "info:\n");
153 ffmpeg.info(cp, BCTEXTLEN-(cp-text));
156 sprintf(cp, "== open failed\n");
159 int FileFFMPEG::get_video_info(int track, int &pid, double &framerate,
160 int &width, int &height, char *title)
163 pid = ff->ff_video_pid(track);
164 framerate = ff->ff_frame_rate(track);
165 width = ff->ff_video_width(track);
166 height = ff->ff_video_height(track);
167 if( title ) *title = 0;
171 int FileFFMPEG::get_audio_for_video(int vstream, int astream, int64_t &channel_mask)
174 return ff->ff_audio_for_video(vstream, astream, channel_mask);
177 int FileFFMPEG::select_video_stream(Asset *asset, int vstream)
179 if( !ff || !asset->video_data ) return 1;
180 asset->width = ff->ff_video_width(vstream);
181 asset->height = ff->ff_video_height(vstream);
182 asset->video_length = ff->ff_video_frames(vstream);
183 asset->frame_rate = ff->ff_frame_rate(vstream);
187 int FileFFMPEG::select_audio_stream(Asset *asset, int astream)
189 if( !ff || !asset->audio_data ) return 1;
190 asset->channels = ff->ff_audio_channels(astream);
191 asset->sample_rate = ff->ff_sample_rate(astream);
192 asset->audio_length = ff->ff_audio_samples(astream);
196 int FileFFMPEG::open_file(int rd, int wr)
200 ff = new FFMPEG(this);
203 result = ff->init_decoder(asset->path);
204 if( !result ) result = ff->open_decoder();
206 int audio_channels = ff->ff_total_audio_channels();
207 if( audio_channels > 0 ) {
208 asset->audio_data = 1;
209 asset->channels = audio_channels;
210 asset->sample_rate = ff->ff_sample_rate(0);
211 asset->audio_length = ff->ff_audio_samples(0);
213 int video_layers = ff->ff_total_video_layers();
214 if( video_layers > 0 ) {
215 asset->video_data = 1;
216 if( !asset->layers ) asset->layers = video_layers;
217 asset->actual_width = ff->ff_video_width(0);
218 asset->actual_height = ff->ff_video_height(0);
219 if( !asset->width ) asset->width = asset->actual_width;
220 if( !asset->height ) asset->height = asset->actual_height;
221 if( !asset->video_length ) asset->video_length = ff->ff_video_frames(0);
222 if( !asset->frame_rate ) asset->frame_rate = ff->ff_frame_rate(0);
227 result = ff->init_encoder(asset->path);
228 // must be in this order or dvdauthor will fail
229 if( !result && asset->video_data )
230 result = ff->open_encoder("video", asset->vcodec);
231 if( !result && asset->audio_data )
232 result = ff->open_encoder("audio", asset->acodec);
237 int FileFFMPEG::close_file()
245 int FileFFMPEG::set_video_position(int64_t pos)
247 if( !ff || pos < 0 || pos >= asset->video_length )
253 int FileFFMPEG::set_audio_position(int64_t pos)
255 if( !ff || pos < 0 || pos >= asset->audio_length )
261 int FileFFMPEG::write_samples(double **buffer, int64_t len)
263 if( !ff || len < 0 ) return -1;
265 int ret = ff->encode(stream, buffer, len);
269 int FileFFMPEG::write_frames(VFrame ***frames, int len)
272 int ret = 0, layer = 0;
273 for(int i = 0; i < 1; i++) {
274 for(int j = 0; j < len && !ret; j++) {
275 VFrame *frame = frames[i][j];
276 ret = ff->encode(layer, frame);
283 int FileFFMPEG::read_samples(double *buffer, int64_t len)
285 if( !ff || len < 0 ) return -1;
286 int ch = file->current_channel;
287 int64_t pos = file->current_sample;
288 ff->decode(ch, pos, buffer, len);
292 int FileFFMPEG::read_frame(VFrame *frame)
295 int layer = file->current_layer;
296 int64_t pos = file->current_frame;
297 ff->decode(layer, pos, frame);
302 int64_t FileFFMPEG::get_memory_usage()
307 int FileFFMPEG::colormodel_supported(int colormodel)
312 int FileFFMPEG::get_best_colormodel(Asset *asset, int driver)
315 case PLAYBACK_X11: return BC_RGB888;
316 case PLAYBACK_X11_GL: return BC_YUV888;
322 extern void get_exe_path(char *result); // from main.C
324 FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
325 : BC_Window(PROGRAM_NAME ": Audio Preset",
326 parent_window->get_abs_cursor_x(1),
327 parent_window->get_abs_cursor_y(1),
330 this->parent_window = parent_window;
338 FFMPEGConfigAudio::~FFMPEGConfigAudio()
340 lock_window("FFMPEGConfigAudio::~FFMPEGConfigAudio");
341 if(preset_popup) delete preset_popup;
342 presets.remove_all_objects();
346 void FFMPEGConfigAudio::create_objects()
349 lock_window("FFMPEGConfigAudio::create_objects");
352 char option_path[BCTEXTLEN];
353 FFMPEG::set_option_path(option_path, "/audio");
354 fs.update(option_path);
355 int total_files = fs.total_files();
356 for(int i = 0; i < total_files; i++) {
357 const char *name = fs.get_entry(i)->get_name();
358 if( asset->fformat[0] != 0 ) {
359 const char *ext = strrchr(name,'.');
360 if( !ext ) ext = name;
361 else if( !strcmp("opts", ++ext) ) continue;
362 if( strcmp(asset->fformat, ext) ) continue;
364 presets.append(new BC_ListBoxItem(name));
367 if( asset->acodec[0] ) {
368 int k = presets.size();
369 while( --k >= 0 && strcmp(asset->acodec, presets[k]->get_text()) );
370 if( k < 0 ) asset->acodec[0] = 0;
373 if( !asset->acodec[0] && presets.size() > 0 )
374 strcpy(asset->acodec, presets[0]->get_text());
376 add_tool(new BC_Title(x, y, _("Preset:")));
378 preset_popup = new FFMPEGConfigAudioPopup(this, x, y);
379 preset_popup->create_objects();
382 bitrate = new FFMpegAudioBitrate(this, x, y, _("Bitrate:"), &asset->ff_audio_bitrate);
383 bitrate->create_objects();
384 bitrate->set_increment(1000);
386 y += bitrate->get_h() + 10;
387 add_subwindow(new BC_Title(x, y, _("Audio Options:")));
389 if( !asset->ff_audio_options[0] && asset->acodec[0] ) {
390 FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
391 FFMPEG::load_options(option_path, asset->ff_audio_options,
392 sizeof(asset->ff_audio_options));
394 add_subwindow(audio_options = new FFAudioOptions(this, x, y, get_w()-x-20, 10,
395 sizeof(asset->ff_audio_options)-1, asset->ff_audio_options));
396 add_subwindow(new BC_OKButton(this));
398 bitrate->handle_event();
402 int FFMPEGConfigAudio::close_event()
409 FFAudioOptions::FFAudioOptions(FFMPEGConfigAudio *audio_popup,
410 int x, int y, int w, int rows, int size, char *text)
411 : BC_TextBox(x, y, w, rows, size, text)
413 this->audio_popup = audio_popup;
416 int FFAudioOptions::handle_event()
418 strcpy(audio_popup->asset->ff_audio_options, get_text());
423 FFMPEGConfigAudioPopup::FFMPEGConfigAudioPopup(FFMPEGConfigAudio *popup, int x, int y)
424 : BC_PopupTextBox(popup, &popup->presets, popup->asset->acodec, x, y, 300, 300)
429 int FFMPEGConfigAudioPopup::handle_event()
431 strcpy(popup->asset->acodec, get_text());
432 Asset *asset = popup->asset;
433 char option_path[BCTEXTLEN];
434 FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
435 FFMPEG::load_options(option_path, asset->ff_audio_options,
436 sizeof(asset->ff_audio_options));
437 popup->audio_options->update(asset->ff_audio_options);
442 FFMPEGConfigAudioToggle::FFMPEGConfigAudioToggle(FFMPEGConfigAudio *popup,
443 char *title_text, int x, int y, int *output)
444 : BC_CheckBox(x, y, *output, title_text)
447 this->output = output;
449 int FFMPEGConfigAudioToggle::handle_event()
451 *output = get_value();
458 FFMPEGConfigVideo::FFMPEGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
459 : BC_Window(PROGRAM_NAME ": Video Preset",
460 parent_window->get_abs_cursor_x(1),
461 parent_window->get_abs_cursor_y(1),
464 this->parent_window = parent_window;
472 FFMPEGConfigVideo::~FFMPEGConfigVideo()
474 lock_window("FFMPEGConfigVideo::~FFMPEGConfigVideo");
475 if(preset_popup) delete preset_popup;
476 presets.remove_all_objects();
480 void FFMPEGConfigVideo::create_objects()
483 lock_window("FFMPEGConfigVideo::create_objects");
485 add_subwindow(new BC_Title(x, y, _("Compression:")));
489 char option_path[BCTEXTLEN];
490 FFMPEG::set_option_path(option_path, "video");
491 fs.update(option_path);
492 int total_files = fs.total_files();
493 for(int i = 0; i < total_files; i++) {
494 const char *name = fs.get_entry(i)->get_name();
495 if( asset->fformat[0] != 0 ) {
496 const char *ext = strrchr(name,'.');
497 if( !ext ) ext = name;
498 else if( !strcmp("opts", ++ext) ) continue;
499 if( strcmp(asset->fformat, ext) ) continue;
501 presets.append(new BC_ListBoxItem(name));
504 if( asset->vcodec[0] ) {
505 int k = presets.size();
506 while( --k >= 0 && strcmp(asset->vcodec, presets[k]->get_text()) );
507 if( k < 0 ) asset->vcodec[0] = 0;
510 if( !asset->vcodec[0] && presets.size() > 0 )
511 strcpy(asset->vcodec, presets[0]->get_text());
513 preset_popup = new FFMPEGConfigVideoPopup(this, x, y);
514 preset_popup->create_objects();
516 if( asset->ff_video_bitrate && asset->ff_video_quality ) {
517 asset->ff_video_bitrate = 0;
518 asset->ff_video_quality = 0;
522 bitrate = new FFMpegVideoBitrate(this, x, y, _("Bitrate:"), &asset->ff_video_bitrate);
523 bitrate->create_objects();
524 bitrate->set_increment(100000);
525 y += bitrate->get_h() + 5;
526 quality = new FFMpegVideoQuality(this, x, y, _("Quality:"), &asset->ff_video_quality);
527 quality->create_objects();
528 quality->set_increment(1);
529 quality->set_boundaries((int64_t)0, (int64_t)31);
531 y += quality->get_h() + 10;
532 add_subwindow(new BC_Title(x, y, _("Video Options:")));
534 if( !asset->ff_video_options[0] && asset->vcodec[0] ) {
535 FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
536 FFMPEG::load_options(option_path, asset->ff_video_options,
537 sizeof(asset->ff_video_options));
539 add_subwindow(video_options = new FFVideoOptions(this, x, y, get_w()-x-20, 10,
540 sizeof(asset->ff_video_options)-1, asset->ff_video_options));
542 add_subwindow(new BC_OKButton(this));
544 if( asset->ff_video_bitrate )
546 if( asset->ff_video_quality )
551 int FFMPEGConfigVideo::close_event()
558 FFVideoOptions::FFVideoOptions(FFMPEGConfigVideo *video_popup,
559 int x, int y, int w, int rows, int size, char *text)
560 : BC_TextBox(x, y, w, rows, size, text)
562 this->video_popup = video_popup;
565 int FFVideoOptions::handle_event()
567 strcpy(video_popup->asset->ff_video_options, get_text());
572 FFMPEGConfigVideoPopup::FFMPEGConfigVideoPopup(FFMPEGConfigVideo *popup, int x, int y)
573 : BC_PopupTextBox(popup, &popup->presets, popup->asset->vcodec, x, y, 300, 300)
578 int FFMPEGConfigVideoPopup::handle_event()
580 strcpy(popup->asset->vcodec, get_text());
581 Asset *asset = popup->asset;
582 char option_path[BCTEXTLEN];
583 FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
584 FFMPEG::load_options(option_path, asset->ff_video_options,
585 sizeof(asset->ff_video_options));
586 popup->video_options->update(asset->ff_video_options);
591 FFMPEGConfigVideoToggle::FFMPEGConfigVideoToggle(FFMPEGConfigVideo *popup,
592 char *title_text, int x, int y, int *output)
593 : BC_CheckBox(x, y, *output, title_text)
596 this->output = output;
598 int FFMPEGConfigVideoToggle::handle_event()
600 *output = get_value();