add Autosave continuous backups by Andras Reuss and Andrew-R
[goodguy/cinelerra.git] / cinelerra-5.1 / 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 #ifdef HAVE_OGG
22
23 #include "asset.h"
24 #include "bcsignals.h"
25 #include "byteorder.h"
26 #include "clip.h"
27 #include "file.h"
28 #include "filevorbis.h"
29 #include "guicast.h"
30 #include "language.h"
31 #include "mainerror.h"
32 #include "mwindow.inc"
33 #include "mainerror.h"
34
35 #include <errno.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 //suppress noref warning
41 void *vorbis1_ov_callbacks[] = {
42  &OV_CALLBACKS_DEFAULT, &OV_CALLBACKS_NOCLOSE,
43  &OV_CALLBACKS_STREAMONLY, &OV_CALLBACKS_STREAMONLY_NOCLOSE,
44 };
45
46 FileVorbis::FileVorbis(Asset *asset, File *file)
47  : FileBase(asset, file)
48 {
49         reset_parameters();
50         if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
51         asset->byte_order = 0;
52 }
53
54 FileVorbis::~FileVorbis()
55 {
56         close_file();
57 }
58
59 void FileVorbis::get_parameters(BC_WindowBase *parent_window,
60         Asset *asset, BC_WindowBase* &format_window,
61         int audio_options, int video_options, EDL *edl)
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("Error while opening \"%s\" for reading. \n%m\n", asset->path);
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(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
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
273         return 0;
274 }
275
276
277 int FileVorbis::write_samples(double **buffer, int64_t len)
278 {
279         if(!fd) return 0;
280
281         float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
282         for(int i = 0; i < asset->channels; i++)
283         {
284                 float *output = vorbis_buffer[i];
285                 double *input = buffer[i];
286                 for(int j = 0; j < len; j++)
287                 {
288                         output[j] = input[j];
289                 }
290         }
291
292         vorbis_analysis_wrote(&vd, len);
293         FLUSH_VORBIS
294
295         return 0;
296 }
297
298 int FileVorbis::read_samples(double *buffer, int64_t len)
299 {
300         if(!fd) return 0;
301
302 // printf("FileVorbis::read_samples 1 %d %d %d %d\n",
303 // history_start,
304 // history_size,
305 // file->current_sample,
306 // len);
307         float **vorbis_output;
308         int bitstream;
309         int accumulation = 0;
310
311
312         update_pcm_history(len);
313
314
315 // Fill history buffer
316         if(decode_start != decode_end)
317         {
318                 ov_pcm_seek(&vf, decode_start);
319                 decode_end = decode_start;
320         }
321
322         while(accumulation < decode_len)
323         {
324                 int result = ov_read_float(&vf,
325                         &vorbis_output,
326                         decode_len - accumulation,
327                         &bitstream);
328 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
329                 if(!result) break;
330
331                 append_history(vorbis_output, result);
332                 accumulation += result;
333         }
334
335
336         read_history(buffer,
337                 file->current_sample,
338                 file->current_channel,
339                 len);
340
341 // printf("FileVorbis::read_samples 2 %d %d %d %d\n",
342 // history_start,
343 // history_size,
344 // file->current_sample,
345 // len);
346
347         return 0;
348 }
349
350
351
352
353
354
355
356
357
358
359 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window,
360         Asset *asset)
361  : BC_Window(_(PROGRAM_NAME ": Audio Compression"),
362         parent_window->get_abs_cursor_x(1),
363         parent_window->get_abs_cursor_y(1),
364         350,
365         170,
366         -1,
367         -1,
368         0,
369         0,
370         1)
371 {
372         this->parent_window = parent_window;
373         this->asset = asset;
374 }
375
376 VorbisConfigAudio::~VorbisConfigAudio()
377 {
378 }
379
380 void VorbisConfigAudio::create_objects()
381 {
382         int x = 10, y = 10;
383         int x1 = 150;
384         char string[BCTEXTLEN];
385
386         lock_window("VorbisConfigAudio::create_objects");
387         add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
388         add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
389
390         y += 30;
391         sprintf(string, "%d", asset->vorbis_min_bitrate);
392         add_tool(new BC_Title(x, y, _("Min bitrate:")));
393         add_tool(new VorbisMinBitrate(x1, y, this, string));
394
395         y += 30;
396         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
397         sprintf(string, "%d", asset->vorbis_bitrate);
398         add_tool(new VorbisAvgBitrate(x1, y, this, string));
399
400         y += 30;
401         add_tool(new BC_Title(x, y, _("Max bitrate:")));
402         sprintf(string, "%d", asset->vorbis_max_bitrate);
403         add_tool(new VorbisMaxBitrate(x1, y, this, string));
404
405
406         add_subwindow(new BC_OKButton(this));
407         show_window();
408         flush();
409         unlock_window();
410 }
411
412 int VorbisConfigAudio::close_event()
413 {
414         set_done(0);
415         return 1;
416 }
417
418
419
420
421
422 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
423  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
424 {
425         this->gui = gui;
426 }
427 int VorbisFixedBitrate::handle_event()
428 {
429         gui->asset->vorbis_vbr = 0;
430         gui->variable_bitrate->update(0);
431         return 1;
432 }
433
434 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
435  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
436 {
437         this->gui = gui;
438 }
439 int VorbisVariableBitrate::handle_event()
440 {
441         gui->asset->vorbis_vbr = 1;
442         gui->fixed_bitrate->update(0);
443         return 1;
444 }
445
446
447 VorbisMinBitrate::VorbisMinBitrate(int x,
448         int y,
449         VorbisConfigAudio *gui,
450         char *text)
451  : BC_TextBox(x, y, 180, 1, text)
452 {
453         this->gui = gui;
454 }
455 int VorbisMinBitrate::handle_event()
456 {
457         gui->asset->vorbis_min_bitrate = atol(get_text());
458         return 1;
459 }
460
461
462
463 VorbisMaxBitrate::VorbisMaxBitrate(int x,
464         int y,
465         VorbisConfigAudio *gui,
466         char *text)
467  : BC_TextBox(x, y, 180, 1, text)
468 {
469         this->gui = gui;
470 }
471 int VorbisMaxBitrate::handle_event()
472 {
473         gui->asset->vorbis_max_bitrate = atol(get_text());
474         return 1;
475 }
476
477
478
479 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
480  : BC_TextBox(x, y, 180, 1, text)
481 {
482         this->gui = gui;
483 }
484 int VorbisAvgBitrate::handle_event()
485 {
486         gui->asset->vorbis_bitrate = atol(get_text());
487         return 1;
488 }
489
490 #endif