r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / filevorbis.C
blob7ed3f1a407139823966b7e3d24e81b6ae66cea70
1 #include "asset.h"
2 #include "byteorder.h"
3 #include "clip.h"
4 #include "file.h"
5 #include "filevorbis.h"
6 #include "guicast.h"
7 #include "language.h"
8 #include "mwindow.inc"
9 #include "mainerror.h"
11 #include <errno.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
16 FileVorbis::FileVorbis(Asset *asset, File *file)
17  : FileBase(asset, file)
19         reset_parameters();
20         if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
21         asset->byte_order = 0;
24 FileVorbis::~FileVorbis()
26         close_file();
29 void FileVorbis::get_parameters(BC_WindowBase *parent_window, 
30         Asset *asset, 
31         BC_WindowBase* &format_window,
32         int audio_options,
33         int video_options)
35         if(audio_options)
36         {
37                 VorbisConfigAudio *window = new VorbisConfigAudio(parent_window, asset);
38                 format_window = window;
39                 window->create_objects();
40                 window->run_window();
41                 delete window;
42         }
45 int FileVorbis::check_sig(Asset *asset)
47 // FILEVORBIS DECODING IS DISABLED
48         return 0;
49         FILE *fd = fopen(asset->path, "rb");
50         OggVorbis_File vf;
52 // Test for Quicktime since OGG misinterprets it
53         fseek(fd, 4, SEEK_SET);
54         char data[4];
55         fread(data, 4, 1, fd);
56         if(data[0] == 'm' &&
57                 data[1] == 'd' &&
58                 data[2] == 'a' &&
59                 data[3] == 't')
60         {
61                 fclose(fd);
62                 return 0;
63         }
64         
65         fseek(fd, 0, SEEK_SET);
67         if(ov_open(fd, &vf, NULL, 0) < 0)
68         {
69 // OGG failed.  Close file handle manually.
70                 ov_clear(&vf);
71                 if(fd) fclose(fd);
72                 return 0;
73         }
74         else
75         {
76                 ov_clear(&vf);
77                 return 1;
78         }
81 int FileVorbis::reset_parameters_derived()
83         fd = 0;
84         bzero(&vf, sizeof(vf));
85         pcm_history = 0;
86         pcm_history_float = 0;
90 // Just create the Quicktime objects since this routine is also called
91 // for reopening.
92 int FileVorbis::open_file(int rd, int wr)
94         int result = 0;
95         this->rd = rd;
96         this->wr = wr;
98 //printf("FileVorbis::open_file 1\n");
99         if(rd)
100         {
101 //printf("FileVorbis::open_file 1\n");
102                 if(!(fd = fopen(asset->path, "rb")))
103                 {
104                         eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
105                         result = 1;
106                 }
107                 else
108                 {
109 //printf("FileVorbis::open_file 2 %p %p\n", fd, vf);
110                         if(ov_open(fd, &vf, NULL, 0) < 0)
111                         {
112                                 eprintf("Invalid bitstream in %s\n", asset->path);
113                                 result = 1;
114                         }
115                         else
116                         {
117 //printf("FileVorbis::open_file 1\n");
118                                 vorbis_info *vi = ov_info(&vf, -1);
119                                 asset->channels = vi->channels;
120                                 if(!asset->sample_rate)
121                                         asset->sample_rate = vi->rate;
122 //printf("FileVorbis::open_file 1\n");
123                                 asset->audio_length = ov_pcm_total(&vf,-1);
124 //printf("FileVorbis::open_file 1\n");
125                                 asset->audio_data = 1;
126 // printf("FileVorbis::open_file 1 %d %d %d\n", 
127 // asset->channels, 
128 // asset->sample_rate, 
129 // asset->audio_length);
130                         }
131                 }
132         }
134         if(wr)
135         {
136                 if(!(fd = fopen(asset->path, "wb")))
137                 {
138                         eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
139                         result = 1;
140                 }
141                 else
142                 {
143                         vorbis_info_init(&vi);
144                         if(!asset->vorbis_vbr)
145                                 result = vorbis_encode_init(&vi, 
146                                         asset->channels, 
147                                         asset->sample_rate, 
148                                         asset->vorbis_max_bitrate, 
149                                         asset->vorbis_bitrate, 
150                                         asset->vorbis_min_bitrate);
151                         else
152                         {
153                                 result = vorbis_encode_setup_managed(&vi,
154                                         asset->channels, 
155                                         asset->sample_rate, 
156                                         asset->vorbis_max_bitrate, 
157                                         asset->vorbis_bitrate, 
158                                         asset->vorbis_min_bitrate);
159                                 result |= vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, NULL);
160                                 result |= vorbis_encode_setup_init(&vi);
161                         }
163                         if(!result)
164                         {
165                                 vorbis_analysis_init(&vd, &vi);
166                                 vorbis_block_init(&vd, &vb);
167                                 vorbis_comment_init(&vc);
168                                 srand(time(NULL));
169                                 ogg_stream_init(&os, rand());
171                                 ogg_packet header;
172                                 ogg_packet header_comm;
173                                 ogg_packet header_code;
174                                 vorbis_analysis_headerout(&vd, 
175                                         &vc,
176                                         &header,
177                                         &header_comm,
178                                         &header_code);
179                                 ogg_stream_packetin(&os,
180                                         &header);
181                                 ogg_stream_packetin(&os, 
182                                         &header_comm);
183                                 ogg_stream_packetin(&os,
184                                         &header_code);
186                                 while(1)
187                                 {
188                                         int result = ogg_stream_flush(&os, &og);
189                                         if(result == 0) break;
190                                         fwrite(og.header, 1, og.header_len, fd);
191                                         fwrite(og.body, 1, og.body_len, fd);
192                                 }
193                         }
194                 }
195         }
197 //printf("FileVorbis::open_file 2\n");
198         return result;
201 #define FLUSH_VORBIS \
202 while(vorbis_analysis_blockout(&vd, &vb) == 1) \
203 { \
204         vorbis_analysis(&vb, NULL); \
205         vorbis_bitrate_addblock(&vb); \
206         while(vorbis_bitrate_flushpacket(&vd, &op)) \
207         { \
208                 ogg_stream_packetin(&os, &op); \
209                 int done = 0; \
210                 while(1) \
211                 { \
212                         int result = ogg_stream_pageout(&os, &og); \
213                         if(!result) break; \
214                         fwrite(og.header, 1, og.header_len, fd); \
215                         fwrite(og.body, 1, og.body_len, fd); \
216                         if(ogg_page_eos(&og)) break; \
217                 } \
218         } \
222 int FileVorbis::close_file()
224         if(fd)
225         {
226                 if(wr)
227                 {
228                         vorbis_analysis_wrote(&vd, 0);
229                         FLUSH_VORBIS
231                         ogg_stream_clear(&os);
232                         vorbis_block_clear(&vb);
233                         vorbis_dsp_clear(&vd);
234                         vorbis_comment_clear(&vc);
235                         vorbis_info_clear(&vi);
236                         fclose(fd);
237                 }
238                 
239                 if(rd)
240                 {
241 // This also closes the file handle.
242                         ov_clear(&vf);
243                 }
244                 fd = 0;
245         }
247         if(pcm_history)
248         {
249                 for(int i = 0; i < asset->channels; i++)
250                         delete [] pcm_history[i];
251                 delete [] pcm_history;
252         }
253         if(pcm_history_float)
254         {
255                 for(int i = 0; i < asset->channels; i++)
256                         delete [] pcm_history_float[i];
257                 delete [] pcm_history_float;
258         }
260         reset_parameters();
261         FileBase::close_file();
262         return 0;
266 int FileVorbis::write_samples(double **buffer, int64_t len)
268         if(!fd) return 0;
269         int result = 0;
271         float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
272         for(int i = 0; i < asset->channels; i++)
273         {
274                 float *output = vorbis_buffer[i];
275                 double *input = buffer[i];
276                 for(int j = 0; j < len; j++)
277                 {
278                         output[j] = input[j];
279                 }
280         }
281     vorbis_analysis_wrote(&vd, len);
283         FLUSH_VORBIS
285         return result;
288 int FileVorbis::read_samples(double *buffer, int64_t len)
290         if(!fd) return 0;
292 // printf("FileVorbis::read_samples 1 %d %d %d %d\n", 
293 // history_start, 
294 // history_size,
295 // file->current_sample,
296 // len);
297         float **vorbis_output;
298         int bitstream;
299         int accumulation = 0;
300 //printf("FileVorbis::read_samples 1\n");
301         int decode_start = 0;
302         int decode_len = 0;
304         if(len > 0x100000)
305         {
306                 eprintf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
307                 return 1;
308         }
310         if(!pcm_history)
311         {
312                 pcm_history = new double*[asset->channels];
313                 for(int i = 0; i < asset->channels; i++)
314                         pcm_history[i] = new double[HISTORY_MAX];
315                 history_start = 0;
316                 history_size = 0;
317         }
319 // Restart history.  Don't bother shifting history back.
320         if(file->current_sample < history_start ||
321                 file->current_sample > history_start + history_size)
322         {
323                 history_size = 0;
324                 history_start = file->current_sample;
325                 decode_start = file->current_sample;
326                 decode_len = len;
327         }
328         else
329 // Shift history forward to make room for new samples
330         if(file->current_sample + len > history_start + history_size)
331         {
332                 if(file->current_sample + len > history_start + HISTORY_MAX)
333                 {
334                         int diff = file->current_sample + len - (history_start + HISTORY_MAX);
335                         for(int i = 0; i < asset->channels; i++)
336                         {
337                                 double *temp = pcm_history[i];
338                                 for(int j = 0; j < HISTORY_MAX - diff; j++)
339                                 {
340                                         temp[j] = temp[j + diff];
341                                 }
342                         }
343                         history_start += diff;
344                         history_size -= diff;
345                 }
347 // Decode more data
348                 decode_start = history_start + history_size;
349                 decode_len = file->current_sample + len - (history_start + history_size);
350         }
353 // Fill history buffer
354         if(history_start + history_size != ov_pcm_tell(&vf))
355         {
356 //printf("FileVorbis::read_samples %d %d\n", history_start + history_size, ov_pcm_tell(&vf));
357                 ov_pcm_seek(&vf, history_start + history_size);
358         }
360         while(accumulation < decode_len)
361         {
362                 int result = ov_read_float(&vf,
363                         &vorbis_output,
364                         decode_len - accumulation,
365                         &bitstream);
366 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
367                 if(!result) break;
369                 for(int i = 0; i < asset->channels; i++)
370                 {
371                         double *output = pcm_history[i] + history_size;
372                         float *input = vorbis_output[i];
373                         for(int j = 0; j < result; j++)
374                                 output[j] = input[j];
375                 }
376                 history_size += result;
377                 accumulation += result;
378         }
381 // printf("FileVorbis::read_samples 1 %d %d\n", 
382 // file->current_sample,
383 // history_start);
385         double *input = pcm_history[file->current_channel] + 
386                 file->current_sample - 
387                 history_start;
388         for(int i = 0; i < len; i++)
389                 buffer[i] = input[i];
391 // printf("FileVorbis::read_samples 2 %d %d %d %d\n", 
392 // history_start, 
393 // history_size,
394 // file->current_sample,
395 // len);
397         return 0;
400 int FileVorbis::prefer_samples_float() 
402         return 1;
405 int FileVorbis::read_samples_float(float *buffer, int64_t len)
407         if(!fd) return 0;
409 // printf("FileVorbis::read_samples 1 %d %d %d %d\n", 
410 // history_start, 
411 // history_size,
412 // file->current_sample,
413 // len);
414         float **vorbis_output;
415         int bitstream;
416         int accumulation = 0;
417 //printf("FileVorbis::read_samples 1\n");
418         int decode_start = 0;
419         int decode_len = 0;
421         if(len > 0x100000)
422         {
423                 eprintf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
424                 return 1;
425         }
427         if(!pcm_history_float)
428         {
429                 pcm_history_float = new float*[asset->channels];
430                 for(int i = 0; i < asset->channels; i++)
431                         pcm_history_float[i] = new float[HISTORY_MAX];
432                 history_start = 0;
433                 history_size = 0;
434         }
436 // Restart history.  Don't bother shifting history back.
437         if(file->current_sample < history_start ||
438                 file->current_sample > history_start + history_size)
439         {
440                 history_size = 0;
441                 history_start = file->current_sample;
442                 decode_start = file->current_sample;
443                 decode_len = len;
444         }
445         else
446 // Shift history forward to make room for new samples
447         if(file->current_sample + len > history_start + history_size)
448         {
449                 if(file->current_sample + len > history_start + HISTORY_MAX)
450                 {
451                         int diff = file->current_sample + len - (history_start + HISTORY_MAX);
452                         for(int i = 0; i < asset->channels; i++)
453                         {
454                                 float *temp = pcm_history_float[i];
455 //                              for(int j = 0; j < HISTORY_MAX - diff; j++)
456 //                              {
457 //                                      temp[j] = temp[j + diff];
458 //                              }
459                                 bcopy(temp, temp + diff, (HISTORY_MAX - diff) * sizeof(float));
460                         }
461                         history_start += diff;
462                         history_size -= diff;
463                 }
465 // Decode more data
466                 decode_start = history_start + history_size;
467                 decode_len = file->current_sample + len - (history_start + history_size);
468         }
471 // Fill history buffer
472         if(history_start + history_size != ov_pcm_tell(&vf))
473         {
474 //printf("FileVorbis::read_samples %d %d\n", history_start + history_size, ov_pcm_tell(&vf));
475                 ov_pcm_seek(&vf, history_start + history_size);
476         }
478         while(accumulation < decode_len)
479         {
480                 int result = ov_read_float(&vf,
481                         &vorbis_output,
482                         decode_len - accumulation,
483                         &bitstream);
484 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
485                 if(!result) break;
487                 for(int i = 0; i < asset->channels; i++)
488                 {
489                         float *output = pcm_history_float[i] + history_size;
490                         float *input = vorbis_output[i];
491 //                      for(int j = 0; j < result; j++)
492 //                              output[j] = input[j];
493                         bcopy(input, output, result * sizeof(float));
494                 }
495                 history_size += result;
496                 accumulation += result;
497         }
500 // printf("FileVorbis::read_samples 1 %d %d\n", 
501 // file->current_sample,
502 // history_start);
504         float *input = pcm_history_float[file->current_channel] + 
505                 file->current_sample - 
506                 history_start;
507 //      for(int i = 0; i < len; i++)
508 //              buffer[i] = input[i];
509         bcopy(input, buffer, len * sizeof(float));
511 // printf("FileVorbis::read_samples 2 %d %d %d %d\n", 
512 // history_start, 
513 // history_size,
514 // file->current_sample,
515 // len);
517         return 0;
529 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window, 
530         Asset *asset)
531  : BC_Window(PROGRAM_NAME ": Audio Compression",
532         parent_window->get_abs_cursor_x(1),
533         parent_window->get_abs_cursor_y(1),
534         350,
535         170,
536         -1,
537         -1,
538         0,
539         0,
540         1)
542         this->parent_window = parent_window;
543         this->asset = asset;
546 VorbisConfigAudio::~VorbisConfigAudio()
550 int VorbisConfigAudio::create_objects()
552         int x = 10, y = 10;
553         int x1 = 150;
554         char string[BCTEXTLEN];
556         add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
557         add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
559         y += 30;
560         sprintf(string, "%d", asset->vorbis_min_bitrate);
561         add_tool(new BC_Title(x, y, _("Min bitrate:")));
562         add_tool(new VorbisMinBitrate(x1, y, this, string));
564         y += 30;
565         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
566         sprintf(string, "%d", asset->vorbis_bitrate);
567         add_tool(new VorbisAvgBitrate(x1, y, this, string));
569         y += 30;
570         add_tool(new BC_Title(x, y, _("Max bitrate:")));
571         sprintf(string, "%d", asset->vorbis_max_bitrate);
572         add_tool(new VorbisMaxBitrate(x1, y, this, string));
575         add_subwindow(new BC_OKButton(this));
576         show_window();
577         flush();
578         return 0;
581 int VorbisConfigAudio::close_event()
583         set_done(0);
584         return 1;
591 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
592  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
594         this->gui = gui;
596 int VorbisFixedBitrate::handle_event()
598         gui->asset->vorbis_vbr = 0;
599         gui->variable_bitrate->update(0);
600         return 1;
603 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
604  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
606         this->gui = gui;
608 int VorbisVariableBitrate::handle_event()
610         gui->asset->vorbis_vbr = 1;
611         gui->fixed_bitrate->update(0);
612         return 1;
616 VorbisMinBitrate::VorbisMinBitrate(int x, 
617         int y, 
618         VorbisConfigAudio *gui, 
619         char *text)
620  : BC_TextBox(x, y, 180, 1, text)
622         this->gui = gui;
624 int VorbisMinBitrate::handle_event()
626         gui->asset->vorbis_min_bitrate = atol(get_text());
627         return 1;
632 VorbisMaxBitrate::VorbisMaxBitrate(int x, 
633         int y, 
634         VorbisConfigAudio *gui,
635         char *text)
636  : BC_TextBox(x, y, 180, 1, text)
638         this->gui = gui;
640 int VorbisMaxBitrate::handle_event()
642         gui->asset->vorbis_max_bitrate = atol(get_text());
643         return 1;
648 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
649  : BC_TextBox(x, y, 180, 1, text)
651         this->gui = gui;
653 int VorbisAvgBitrate::handle_event()
655         gui->asset->vorbis_bitrate = atol(get_text());
656         return 1;