prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filevorbis.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "byteorder.h"
25 #include "clip.h"
26 #include "file.h"
27 #include "filevorbis.h"
28 #include "guicast.h"
29 #include "language.h"
30 #include "mainerror.h"
31 #include "mwindow.inc"
32
33 #include <errno.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 //suppress noref warning
39 void *vorbis1_ov_callbacks[] = {
40  &OV_CALLBACKS_DEFAULT, &OV_CALLBACKS_NOCLOSE,
41  &OV_CALLBACKS_STREAMONLY, &OV_CALLBACKS_STREAMONLY_NOCLOSE,
42 };
43
44 FileVorbis::FileVorbis(Asset *asset, File *file)
45  : FileBase(asset, file)
46 {
47         reset_parameters();
48         if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
49         asset->byte_order = 0;
50 }
51
52 FileVorbis::~FileVorbis()
53 {
54         close_file();
55 }
56
57 void FileVorbis::get_parameters(BC_WindowBase *parent_window, 
58         Asset *asset, 
59         BC_WindowBase* &format_window,
60         int audio_options,
61         int video_options)
62 {
63         if(audio_options)
64         {
65                 VorbisConfigAudio *window = new VorbisConfigAudio(parent_window, asset);
66                 format_window = window;
67                 window->create_objects();
68                 window->run_window();
69                 delete window;
70         }
71 }
72
73 int FileVorbis::check_sig(Asset *asset)
74 {
75         FILE *fd = fopen(asset->path, "rb");
76         OggVorbis_File vf;
77
78 // Test for Quicktime since OGG misinterprets it
79         if(fd)
80         {
81                 fseek(fd, 4, SEEK_SET);
82                 char data[4];
83                 (void)fread(data, 4, 1, fd);
84                 if(data[0] == 'm' &&
85                         data[1] == 'd' &&
86                         data[2] == 'a' &&
87                         data[3] == 't')
88                 {
89                         fclose(fd);
90                         return 0;
91                 }
92
93                 fseek(fd, 0, SEEK_SET);
94
95                 if(ov_open(fd, &vf, NULL, 0) < 0)
96                 {
97         // OGG failed.  Close file handle manually.
98                         ov_clear(&vf);
99                         if(fd) fclose(fd);
100                         return 0;
101                 }
102                 else
103                 {
104                         ov_clear(&vf);
105                         return 1;
106                 }
107         }
108
109         return 0;
110 }
111
112 int FileVorbis::reset_parameters_derived()
113 {
114         fd = 0;
115         bzero(&vf, sizeof(vf));
116         return 0;
117 }
118
119
120 int FileVorbis::open_file(int rd, int wr)
121 {
122
123         int result = 0;
124
125 //printf("FileVorbis::open_file 1\n");
126         if(rd)
127         {
128 //printf("FileVorbis::open_file 1\n");
129                 if(!(fd = fopen(asset->path, "rb")))
130                 {
131                         eprintf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
132                         result = 1;
133                 }
134                 else
135                 {
136 //printf("FileVorbis::open_file 2 %p %p\n", fd, vf);
137                         if(ov_open(fd, &vf, NULL, 0) < 0)
138                         {
139                                 eprintf(_("FileVorbis::open_file %s: invalid bitstream.\n"), asset->path);
140                                 result = 1;
141                         }
142                         else
143                         {
144 //printf("FileVorbis::open_file 1\n");
145                                 vorbis_info *vi = ov_info(&vf, -1);
146                                 asset->channels = vi->channels;
147                                 if(!asset->sample_rate)
148                                         asset->sample_rate = vi->rate;
149 //printf("FileVorbis::open_file 1\n");
150                                 asset->audio_length = ov_pcm_total(&vf,-1);
151 //printf("FileVorbis::open_file 1\n");
152                                 asset->audio_data = 1;
153 // printf("FileVorbis::open_file 1 %d %d %d\n", 
154 // asset->channels, 
155 // asset->sample_rate, 
156 // asset->audio_length);
157                         }
158                 }
159         }
160
161         if(wr)
162         {
163                 if(!(fd = fopen(asset->path, "wb")))
164                 {
165                         eprintf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
166                         result = 1;
167                 }
168                 else
169                 {
170                         vorbis_info_init(&vi);
171                         if(!asset->vorbis_vbr)
172                                 result = vorbis_encode_init(&vi, 
173                                         asset->channels, 
174                                         asset->sample_rate, 
175                                         asset->vorbis_max_bitrate, 
176                                         asset->vorbis_bitrate, 
177                                         asset->vorbis_min_bitrate);
178                         else
179                         {
180                                 result = vorbis_encode_setup_managed(&vi,
181                                         asset->channels, 
182                                         asset->sample_rate, 
183                                         asset->vorbis_max_bitrate, 
184                                         asset->vorbis_bitrate, 
185                                         asset->vorbis_min_bitrate);
186                                 result |= vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, NULL);
187                                 result |= vorbis_encode_setup_init(&vi);
188                         }
189
190                         if(!result)
191                         {
192                                 vorbis_analysis_init(&vd, &vi);
193                                 vorbis_block_init(&vd, &vb);
194                                 vorbis_comment_init(&vc);
195                                 srand(time(NULL));
196                                 ogg_stream_init(&os, rand());
197
198                                 ogg_packet header;
199                                 ogg_packet header_comm;
200                                 ogg_packet header_code;
201                                 vorbis_analysis_headerout(&vd, 
202                                         &vc,
203                                         &header,
204                                         &header_comm,
205                                         &header_code);
206                                 ogg_stream_packetin(&os,
207                                         &header);
208                                 ogg_stream_packetin(&os, 
209                                         &header_comm);
210                                 ogg_stream_packetin(&os,
211                                         &header_code);
212
213                                 while(1)
214                                 {
215                                         int result = ogg_stream_flush(&os, &og);
216                                         if(result == 0) break;
217                                         fwrite(og.header, 1, og.header_len, fd);
218                                         fwrite(og.body, 1, og.body_len, fd);
219                                 }
220                         }
221                 }
222         }
223
224 //printf("FileVorbis::open_file 2\n");
225         return result;
226 }
227
228 #define FLUSH_VORBIS \
229 while(vorbis_analysis_blockout(&vd, &vb) == 1) \
230 { \
231         vorbis_analysis(&vb, NULL); \
232         vorbis_bitrate_addblock(&vb); \
233         while(vorbis_bitrate_flushpacket(&vd, &op)) \
234         { \
235                 ogg_stream_packetin(&os, &op); \
236                 while(1) \
237                 { \
238                         int result = ogg_stream_pageout(&os, &og); \
239                         if(!result) break; \
240                         fwrite(og.header, 1, og.header_len, fd); \
241                         fwrite(og.body, 1, og.body_len, fd); \
242                         if(ogg_page_eos(&og)) break; \
243                 } \
244         } \
245 }
246
247
248 int FileVorbis::close_file_derived()
249 {
250         if(fd)
251         {
252                 if(file->wr)
253                 {
254                         vorbis_analysis_wrote(&vd, 0);
255                         FLUSH_VORBIS
256
257                         ogg_stream_clear(&os);
258                         vorbis_block_clear(&vb);
259                         vorbis_dsp_clear(&vd);
260                         vorbis_comment_clear(&vc);
261                         vorbis_info_clear(&vi);
262                         fclose(fd);
263                 }
264                 
265                 if(file->rd)
266                 {
267 // This also closes the file handle.
268                         ov_clear(&vf);
269                 }
270                 fd = 0;
271         }
272         return 0;
273 }
274
275
276 int FileVorbis::write_samples(double **buffer, int64_t len)
277 {
278         if(!fd) return 0;
279
280         float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
281         for(int i = 0; i < asset->channels; i++)
282         {
283                 float *output = vorbis_buffer[i];
284                 double *input = buffer[i];
285                 for(int j = 0; j < len; j++)
286                 {
287                         output[j] = input[j];
288                 }
289         }
290
291         vorbis_analysis_wrote(&vd, len);
292         FLUSH_VORBIS
293
294         return 0;
295 }
296
297 int FileVorbis::read_samples(double *buffer, int64_t len)
298 {
299         if(!fd) return 0;
300
301 // printf("FileVorbis::read_samples 1 %d %d %d %d\n", 
302 // history_start, 
303 // history_size,
304 // file->current_sample,
305 // len);
306         float **vorbis_output;
307         int bitstream;
308         int accumulation = 0;
309
310
311         update_pcm_history(len);
312
313
314 // Fill history buffer
315         if(decode_start != decode_end)
316         {
317                 ov_pcm_seek(&vf, decode_start);
318                 decode_end = decode_start;
319         }
320
321         while(accumulation < decode_len)
322         {
323                 int result = ov_read_float(&vf,
324                         &vorbis_output,
325                         decode_len - accumulation,
326                         &bitstream);
327 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
328                 if(!result) break;
329
330                 append_history(vorbis_output, result);
331                 accumulation += result;
332         }
333
334
335         read_history(buffer, 
336                 file->current_sample, 
337                 file->current_channel,
338                 len);
339
340 // printf("FileVorbis::read_samples 2 %d %d %d %d\n", 
341 // history_start, 
342 // history_size,
343 // file->current_sample,
344 // len);
345
346         return 0;
347 }
348
349
350
351
352
353
354
355
356
357
358 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window, 
359         Asset *asset)
360  : BC_Window(_(PROGRAM_NAME ": Audio Compression"),
361         parent_window->get_abs_cursor_x(1),
362         parent_window->get_abs_cursor_y(1),
363         350,
364         170,
365         -1,
366         -1,
367         0,
368         0,
369         1)
370 {
371         this->parent_window = parent_window;
372         this->asset = asset;
373 }
374
375 VorbisConfigAudio::~VorbisConfigAudio()
376 {
377 }
378
379 void VorbisConfigAudio::create_objects()
380 {
381         int x = 10, y = 10;
382         int x1 = 150;
383         char string[BCTEXTLEN];
384
385         lock_window("VorbisConfigAudio::create_objects");
386         add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
387         add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
388
389         y += 30;
390         sprintf(string, "%d", asset->vorbis_min_bitrate);
391         add_tool(new BC_Title(x, y, _("Min bitrate:")));
392         add_tool(new VorbisMinBitrate(x1, y, this, string));
393
394         y += 30;
395         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
396         sprintf(string, "%d", asset->vorbis_bitrate);
397         add_tool(new VorbisAvgBitrate(x1, y, this, string));
398
399         y += 30;
400         add_tool(new BC_Title(x, y, _("Max bitrate:")));
401         sprintf(string, "%d", asset->vorbis_max_bitrate);
402         add_tool(new VorbisMaxBitrate(x1, y, this, string));
403
404
405         add_subwindow(new BC_OKButton(this));
406         show_window();
407         flush();
408         unlock_window();
409 }
410
411 int VorbisConfigAudio::close_event()
412 {
413         set_done(0);
414         return 1;
415 }
416
417
418
419
420
421 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
422  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
423 {
424         this->gui = gui;
425 }
426 int VorbisFixedBitrate::handle_event()
427 {
428         gui->asset->vorbis_vbr = 0;
429         gui->variable_bitrate->update(0);
430         return 1;
431 }
432
433 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
434  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
435 {
436         this->gui = gui;
437 }
438 int VorbisVariableBitrate::handle_event()
439 {
440         gui->asset->vorbis_vbr = 1;
441         gui->fixed_bitrate->update(0);
442         return 1;
443 }
444
445
446 VorbisMinBitrate::VorbisMinBitrate(int x, 
447         int y, 
448         VorbisConfigAudio *gui, 
449         char *text)
450  : BC_TextBox(x, y, 180, 1, text)
451 {
452         this->gui = gui;
453 }
454 int VorbisMinBitrate::handle_event()
455 {
456         gui->asset->vorbis_min_bitrate = atol(get_text());
457         return 1;
458 }
459
460
461
462 VorbisMaxBitrate::VorbisMaxBitrate(int x, 
463         int y, 
464         VorbisConfigAudio *gui,
465         char *text)
466  : BC_TextBox(x, y, 180, 1, text)
467 {
468         this->gui = gui;
469 }
470 int VorbisMaxBitrate::handle_event()
471 {
472         gui->asset->vorbis_max_bitrate = atol(get_text());
473         return 1;
474 }
475
476
477
478 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
479  : BC_TextBox(x, y, 180, 1, text)
480 {
481         this->gui = gui;
482 }
483 int VorbisAvgBitrate::handle_event()
484 {
485         gui->asset->vorbis_bitrate = atol(get_text());
486         return 1;
487 }
488
489
490
491