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