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