initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / fileffmpeg.C
1
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 // work around for __STDC_CONSTANT_MACROS
8 #include <lzma.h>
9
10 #include "asset.h"
11 #include "bcwindowbase.h"
12 #include "bitspopup.h"
13 #include "ffmpeg.h"
14 #include "filebase.h"
15 #include "file.h"
16 #include "fileffmpeg.h"
17 #include "filesystem.h"
18 #include "mutex.h"
19 #include "videodevice.inc"
20
21 FileFFMPEG::FileFFMPEG(Asset *asset, File *file)
22   : FileBase(asset, file)
23 {
24         ff = 0;
25         if(asset->format == FILE_UNKNOWN)
26                 asset->format = FILE_FFMPEG;
27 }
28
29 FileFFMPEG::~FileFFMPEG()
30 {
31         delete ff;
32 }
33
34
35 void FileFFMPEG::get_parameters(BC_WindowBase *parent_window,
36                 Asset *asset, BC_WindowBase *&format_window,
37                 int audio_options, int video_options)
38 {
39         if(audio_options) {
40                 FFMPEGConfigAudio *window = new FFMPEGConfigAudio(parent_window, asset);
41                 format_window = window;
42                 window->create_objects();
43                 window->run_window();
44                 delete window;
45         }
46         else if(video_options) {
47                 FFMPEGConfigVideo *window = new FFMPEGConfigVideo(parent_window, asset);
48                 format_window = window;
49                 window->create_objects();
50                 window->run_window();
51                 delete window;
52         }
53 }
54
55 int FileFFMPEG::check_sig(Asset *asset)
56 {
57         char *ptr = strstr(asset->path, ".pcm");
58         if( ptr ) return 0;
59         ptr = strstr(asset->path, ".raw");
60         if( ptr ) return 0;
61
62         FFMPEG ffmpeg(0);
63         int ret = !ffmpeg.init_decoder(asset->path) &&
64                 !ffmpeg.open_decoder() ? 1 : 0;
65         return ret;
66 }
67
68 void FileFFMPEG::get_info(char *path, char *text)
69 {
70         char *cp = text;
71         FFMPEG ffmpeg(0);
72         cp += sprintf(cp, "file path: %s\n", path);
73         struct stat st;
74         int ret = 0;
75         if( stat(path, &st) < 0 ) {
76                 cp += sprintf(cp, " err: %s\n", strerror(errno));
77                 ret = 1;
78         }
79         else {
80                 cp += sprintf(cp, "  %jd bytes\n", st.st_size);
81         }
82         if( !ret ) ret = ffmpeg.init_decoder(path);
83         if( !ret ) ret = ffmpeg.open_decoder();
84         if( !ret ) {
85                 cp += sprintf(cp, "info:\n");
86                 ffmpeg.info(cp, BCTEXTLEN-(cp-text));
87         }
88         else
89                 sprintf(cp, "== open failed\n");
90 }
91
92 int FileFFMPEG::get_video_info(int track, int &pid, double &framerate,
93                 int &width, int &height, char *title)
94 {
95         if( !ff ) return -1;
96         pid = ff->ff_video_pid(track);
97         framerate = ff->ff_frame_rate(track);
98         width = ff->ff_video_width(track);
99         height = ff->ff_video_height(track);
100         if( title ) *title = 0;
101         return 0;
102 }
103
104 int FileFFMPEG::get_audio_for_video(int vstream, int astream, int64_t &channel_mask)
105 {
106         if( !ff ) return 1;
107         return ff->ff_audio_for_video(vstream, astream, channel_mask);
108 }
109
110 int FileFFMPEG::select_video_stream(Asset *asset, int vstream)
111 {
112         if( !ff || !asset->video_data ) return 1;
113         asset->width = ff->ff_video_width(vstream);
114         asset->height = ff->ff_video_height(vstream);
115         asset->video_length = ff->ff_video_frames(vstream);
116         asset->frame_rate = ff->ff_frame_rate(vstream);
117         return 0;
118 }
119
120 int FileFFMPEG::select_audio_stream(Asset *asset, int astream)
121 {
122         if( !ff || !asset->audio_data ) return 1;
123         asset->channels = ff->ff_audio_channels(astream);
124         asset->sample_rate = ff->ff_sample_rate(astream);
125         asset->audio_length = ff->ff_audio_samples(astream);
126         return 0;
127 }
128
129 int FileFFMPEG::open_file(int rd, int wr)
130 {
131         int result = 0;
132         if( ff ) return 1;
133         ff = new FFMPEG(this);
134
135         if( rd ) {
136                 result = ff->init_decoder(asset->path);
137                 if( !result ) result = ff->open_decoder();
138                 if( !result ) {
139                         int audio_channels = ff->ff_total_audio_channels();
140                         if( audio_channels > 0 ) {
141                                 asset->audio_data = 1;
142                                 asset->channels = audio_channels;
143                                 asset->sample_rate = ff->ff_sample_rate(0);
144                                 asset->audio_length = ff->ff_audio_samples(0);
145                         }
146                         int video_layers = ff->ff_total_video_layers();
147                         if( video_layers > 0 ) {
148                                 asset->video_data = 1;
149                                 if( !asset->layers ) asset->layers = video_layers;
150                                 asset->actual_width = ff->ff_video_width(0);
151                                 asset->actual_height = ff->ff_video_height(0);
152                                 if( !asset->width ) asset->width = asset->actual_width;
153                                 if( !asset->height ) asset->height = asset->actual_height;
154                                 if( !asset->video_length ) asset->video_length = ff->ff_video_frames(0);
155                                 if( !asset->frame_rate ) asset->frame_rate = ff->ff_frame_rate(0);
156                         }
157                 }
158         }
159         else if( wr ) {
160                 result = ff->init_encoder(asset->path);
161                 // must be in this order or dvdauthor will fail
162                 if( !result && asset->video_data )
163                         result = ff->open_encoder("video", asset->vcodec);
164                 if( !result && asset->audio_data )
165                         result = ff->open_encoder("audio", asset->acodec);
166         }
167         return result;
168 }
169
170 int FileFFMPEG::close_file()
171 {
172         delete ff;
173         ff = 0;
174         return 0;
175 }
176
177
178 int FileFFMPEG::set_video_position(int64_t pos)
179 {
180         if( !ff || pos < 0 || pos >= asset->video_length )
181                 return 1;
182         return 0;
183 }
184
185
186 int FileFFMPEG::set_audio_position(int64_t pos)
187 {
188         if( !ff || pos < 0 || pos >= asset->audio_length )
189                 return 1;
190         return 0;
191 }
192
193
194 int FileFFMPEG::write_samples(double **buffer, int64_t len)
195 {
196         if( !ff || len < 0 ) return -1;
197         int stream = 0;
198         int ret = ff->encode(stream, buffer, len);
199         return ret;
200 }
201
202 int FileFFMPEG::write_frames(VFrame ***frames, int len)
203 {
204         if( !ff ) return -1;
205         int ret = 0, layer = 0;
206         for(int i = 0; i < 1; i++) {
207                 for(int j = 0; j < len && !ret; j++) {
208                         VFrame *frame = frames[i][j];
209                         ret = ff->encode(layer, frame);
210                 }
211         }
212         return ret;
213 }
214
215
216 int FileFFMPEG::read_samples(double *buffer, int64_t len)
217 {
218         if( !ff || len < 0 ) return -1;
219         int ch = file->current_channel;
220         int64_t pos = file->current_sample;
221         ff->decode(ch, pos, buffer, len);
222         return 0;
223 }
224
225 int FileFFMPEG::read_frame(VFrame *frame)
226 {
227         if( !ff ) return -1;
228         int layer = file->current_layer;
229         int64_t pos = file->current_frame;
230         ff->decode(layer, pos, frame);
231         return 0;
232 }
233
234
235 int64_t FileFFMPEG::get_memory_usage()
236 {
237         return 0;
238 }
239
240 int FileFFMPEG::colormodel_supported(int colormodel)
241 {
242         return colormodel;
243 }
244
245 int FileFFMPEG::get_best_colormodel(Asset *asset, int driver)
246 {
247         switch(driver) {
248         case PLAYBACK_X11:      return BC_RGB888;
249         case PLAYBACK_X11_GL:   return BC_YUV888;
250         }
251         return BC_YUV420P;
252 }
253
254
255 //======
256 extern void get_exe_path(char *result); // from main.C
257
258 FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
259  : BC_Window(PROGRAM_NAME ": Audio Preset",
260         parent_window->get_abs_cursor_x(1),
261         parent_window->get_abs_cursor_y(1),
262         420, 420)
263 {
264         this->parent_window = parent_window;
265         this->asset = asset;
266         preset_popup = 0;
267 }
268
269 FFMPEGConfigAudio::~FFMPEGConfigAudio()
270 {
271         lock_window("FFMPEGConfigAudio::~FFMPEGConfigAudio");
272         if(preset_popup) delete preset_popup;
273         presets.remove_all_objects();
274         unlock_window();
275 }
276
277 void FFMPEGConfigAudio::create_objects()
278 {
279         int x = 10, y = 10;
280         lock_window("FFMPEGConfigAudio::create_objects");
281
282         FileSystem fs;
283         char option_path[BCTEXTLEN];
284         FFMPEG::set_option_path(option_path, "/audio");
285         fs.update(option_path);
286         int total_files = fs.total_files();
287         for(int i = 0; i < total_files; i++) {
288                 const char *name = fs.get_entry(i)->get_name();
289                 presets.append(new BC_ListBoxItem(name));
290         }
291
292         add_tool(new BC_Title(x, y, _("Preset:")));
293         y += 25;
294         preset_popup = new FFMPEGConfigAudioPopup(this, x, y);
295         preset_popup->create_objects();
296
297         add_subwindow(new BC_OKButton(this));
298         show_window(1);
299         unlock_window();
300 }
301
302 int FFMPEGConfigAudio::close_event()
303 {
304         set_done(0);
305         return 1;
306 }
307
308
309 FFMPEGConfigAudioPopup::FFMPEGConfigAudioPopup(FFMPEGConfigAudio *popup, int x, int y)
310  : BC_PopupTextBox(popup, &popup->presets, popup->asset->acodec, x, y, 300, 300)
311 {
312         this->popup = popup;
313 }
314
315 int FFMPEGConfigAudioPopup::handle_event()
316 {
317         strcpy(popup->asset->acodec, get_text());
318         return 1;
319 }
320
321
322 FFMPEGConfigAudioToggle::FFMPEGConfigAudioToggle(FFMPEGConfigAudio *popup,
323         char *title_text, int x, int y, int *output)
324  : BC_CheckBox(x, y, *output, title_text)
325 {
326         this->popup = popup;
327         this->output = output;
328 }
329 int FFMPEGConfigAudioToggle::handle_event()
330 {
331         *output = get_value();
332         return 1;
333 }
334
335
336 //======
337
338 FFMPEGConfigVideo::FFMPEGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
339  : BC_Window(PROGRAM_NAME ": Video Preset",
340         parent_window->get_abs_cursor_x(1),
341         parent_window->get_abs_cursor_y(1),
342         420, 420)
343 {
344         this->parent_window = parent_window;
345         this->asset = asset;
346         preset_popup = 0;
347 }
348
349 FFMPEGConfigVideo::~FFMPEGConfigVideo()
350 {
351         lock_window("FFMPEGConfigVideo::~FFMPEGConfigVideo");
352         if(preset_popup) delete preset_popup;
353         presets.remove_all_objects();
354         unlock_window();
355 }
356
357 void FFMPEGConfigVideo::create_objects()
358 {
359         int x = 10, y = 10;
360         lock_window("FFMPEGConfigVideo::create_objects");
361
362         add_subwindow(new BC_Title(x, y, _("Compression:")));
363         y += 25;
364
365         FileSystem fs;
366         char option_path[BCTEXTLEN];
367         FFMPEG::set_option_path(option_path, "video");
368         fs.update(option_path);
369         int total_files = fs.total_files();
370         for(int i = 0; i < total_files; i++) {
371                 const char *name = fs.get_entry(i)->get_name();
372                 presets.append(new BC_ListBoxItem(name));
373         }
374
375         preset_popup = new FFMPEGConfigVideoPopup(this, x, y);
376         preset_popup->create_objects();
377
378         add_subwindow(new BC_OKButton(this));
379         show_window(1);
380         unlock_window();
381 }
382
383 int FFMPEGConfigVideo::close_event()
384 {
385         set_done(0);
386         return 1;
387 }
388
389
390 FFMPEGConfigVideoPopup::FFMPEGConfigVideoPopup(FFMPEGConfigVideo *popup, int x, int y)
391  : BC_PopupTextBox(popup, &popup->presets, popup->asset->vcodec, x, y, 300, 300)
392 {
393         this->popup = popup;
394 }
395
396 int FFMPEGConfigVideoPopup::handle_event()
397 {
398         strcpy(popup->asset->vcodec, get_text());
399         return 1;
400 }
401
402
403 FFMPEGConfigVideoToggle::FFMPEGConfigVideoToggle(FFMPEGConfigVideo *popup,
404         char *title_text, int x, int y, int *output)
405  : BC_CheckBox(x, y, *output, title_text)
406 {
407         this->popup = popup;
408         this->output = output;
409 }
410 int FFMPEGConfigVideoToggle::handle_event()
411 {
412         *output = get_value();
413         return 1;
414 }
415
416