r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / filevorbis.C
blob5b3459ae6c675022d2ed854e1a5278f5a33e3ab5
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"
10 #include <errno.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
15 FileVorbis::FileVorbis(Asset *asset, File *file)
16  : FileBase(asset, file)
18         reset_parameters();
19         if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
20         asset->byte_order = 0;
23 FileVorbis::~FileVorbis()
25         close_file();
28 void FileVorbis::get_parameters(BC_WindowBase *parent_window, 
29         Asset *asset, 
30         BC_WindowBase* &format_window,
31         int audio_options,
32         int video_options)
34         if(audio_options)
35         {
36                 VorbisConfigAudio *window = new VorbisConfigAudio(parent_window, asset);
37                 format_window = window;
38                 window->create_objects();
39                 window->run_window();
40                 delete window;
41         }
44 int FileVorbis::check_sig(Asset *asset)
46         FILE *fd = fopen(asset->path, "rb");
47         OggVorbis_File vf;
49 // Test for Quicktime since OGG misinterprets it
50         fseek(fd, 4, SEEK_SET);
51         char data[4];
52         fread(data, 4, 1, fd);
53         if(data[0] == 'm' &&
54                 data[1] == 'd' &&
55                 data[2] == 'a' &&
56                 data[3] == 't')
57         {
58                 fclose(fd);
59                 return 0;
60         }
61         
62         fseek(fd, 0, SEEK_SET);
64         if(ov_open(fd, &vf, NULL, 0) < 0)
65         {
66 // OGG failed.  Close file handle manually.
67                 ov_clear(&vf);
68                 if(fd) fclose(fd);
69                 return 0;
70         }
71         else
72         {
73                 ov_clear(&vf);
74                 return 1;
75         }
78 int FileVorbis::reset_parameters_derived()
80         fd = 0;
81         bzero(&vf, sizeof(vf));
82         pcm_history = 0;
86 // Just create the Quicktime objects since this routine is also called
87 // for reopening.
88 int FileVorbis::open_file(int rd, int wr)
90         int result = 0;
91         this->rd = rd;
92         this->wr = wr;
94 //printf("FileVorbis::open_file 1\n");
95         if(rd)
96         {
97 //printf("FileVorbis::open_file 1\n");
98                 if(!(fd = fopen(asset->path, "rb")))
99                 {
100                         printf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
101                         result = 1;
102                 }
103                 else
104                 {
105 //printf("FileVorbis::open_file 2 %p %p\n", fd, vf);
106                         if(ov_open(fd, &vf, NULL, 0) < 0)
107                         {
108                                 printf(_("FileVorbis::open_file %s: invalid bitstream.\n"), asset->path);
109                                 result = 1;
110                         }
111                         else
112                         {
113 //printf("FileVorbis::open_file 1\n");
114                                 vorbis_info *vi = ov_info(&vf, -1);
115                                 asset->channels = vi->channels;
116                                 if(!asset->sample_rate)
117                                         asset->sample_rate = vi->rate;
118 //printf("FileVorbis::open_file 1\n");
119                                 asset->audio_length = ov_pcm_total(&vf,-1);
120 //printf("FileVorbis::open_file 1\n");
121                                 asset->audio_data = 1;
122 // printf("FileVorbis::open_file 1 %d %d %d\n", 
123 // asset->channels, 
124 // asset->sample_rate, 
125 // asset->audio_length);
126                         }
127                 }
128         }
130         if(wr)
131         {
132                 if(!(fd = fopen(asset->path, "wb")))
133                 {
134                         printf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
135                         result = 1;
136                 }
137                 else
138                 {
139                         vorbis_info_init(&vi);
140                         if(!asset->vorbis_vbr)
141                                 result = vorbis_encode_init(&vi, 
142                                         asset->channels, 
143                                         asset->sample_rate, 
144                                         asset->vorbis_max_bitrate, 
145                                         asset->vorbis_bitrate, 
146                                         asset->vorbis_min_bitrate);
147                         else
148                         {
149                                 result = vorbis_encode_setup_managed(&vi,
150                                         asset->channels, 
151                                         asset->sample_rate, 
152                                         asset->vorbis_max_bitrate, 
153                                         asset->vorbis_bitrate, 
154                                         asset->vorbis_min_bitrate);
155                                 result |= vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, NULL);
156                                 result |= vorbis_encode_setup_init(&vi);
157                         }
159                         if(!result)
160                         {
161                                 vorbis_analysis_init(&vd, &vi);
162                                 vorbis_block_init(&vd, &vb);
163                                 vorbis_comment_init(&vc);
164                                 srand(time(NULL));
165                                 ogg_stream_init(&os, rand());
167                                 ogg_packet header;
168                                 ogg_packet header_comm;
169                                 ogg_packet header_code;
170                                 vorbis_analysis_headerout(&vd, 
171                                         &vc,
172                                         &header,
173                                         &header_comm,
174                                         &header_code);
175                                 ogg_stream_packetin(&os,
176                                         &header);
177                                 ogg_stream_packetin(&os, 
178                                         &header_comm);
179                                 ogg_stream_packetin(&os,
180                                         &header_code);
182                                 while(1)
183                                 {
184                                         int result = ogg_stream_flush(&os, &og);
185                                         if(result == 0) break;
186                                         fwrite(og.header, 1, og.header_len, fd);
187                                         fwrite(og.body, 1, og.body_len, fd);
188                                 }
189                         }
190                 }
191         }
193 //printf("FileVorbis::open_file 2\n");
194         return result;
197 #define FLUSH_VORBIS \
198 while(vorbis_analysis_blockout(&vd, &vb) == 1) \
199 { \
200         vorbis_analysis(&vb, NULL); \
201         vorbis_bitrate_addblock(&vb); \
202         while(vorbis_bitrate_flushpacket(&vd, &op)) \
203         { \
204                 ogg_stream_packetin(&os, &op); \
205                 int done = 0; \
206                 while(1) \
207                 { \
208                         int result = ogg_stream_pageout(&os, &og); \
209                         if(!result) break; \
210                         fwrite(og.header, 1, og.header_len, fd); \
211                         fwrite(og.body, 1, og.body_len, fd); \
212                         if(ogg_page_eos(&og)) break; \
213                 } \
214         } \
218 int FileVorbis::close_file()
220         if(fd)
221         {
222                 if(wr)
223                 {
224                         vorbis_analysis_wrote(&vd, 0);
225                         FLUSH_VORBIS
227                         ogg_stream_clear(&os);
228                         vorbis_block_clear(&vb);
229                         vorbis_dsp_clear(&vd);
230                         vorbis_comment_clear(&vc);
231                         vorbis_info_clear(&vi);
232                         fclose(fd);
233                 }
234                 
235                 if(rd)
236                 {
237 // This also closes the file handle.
238                         ov_clear(&vf);
239                 }
240                 fd = 0;
241         }
243         if(pcm_history)
244         {
245                 for(int i = 0; i < asset->channels; i++)
246                         delete [] pcm_history[i];
247                 delete [] pcm_history;
248         }
250         reset_parameters();
251         FileBase::close_file();
252         return 0;
256 int FileVorbis::write_samples(double **buffer, int64_t len)
258         if(!fd) return 0;
259         int result = 0;
261         float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
262         for(int i = 0; i < asset->channels; i++)
263         {
264                 float *output = vorbis_buffer[i];
265                 double *input = buffer[i];
266                 for(int j = 0; j < len; j++)
267                 {
268                         output[j] = input[j];
269                 }
270         }
271     vorbis_analysis_wrote(&vd, len);
273         FLUSH_VORBIS
275         return result;
278 int FileVorbis::read_samples(double *buffer, int64_t len)
280         if(!fd) return 0;
282 // printf("FileVorbis::read_samples 1 %d %d %d %d\n", 
283 // history_start, 
284 // history_size,
285 // file->current_sample,
286 // len);
287         float **vorbis_output;
288         int bitstream;
289         int accumulation = 0;
290 //printf("FileVorbis::read_samples 1\n");
291         int decode_start = 0;
292         int decode_len = 0;
294         if(len > 0x100000)
295         {
296                 printf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
297                 return 1;
298         }
300         if(!pcm_history)
301         {
302                 pcm_history = new double*[asset->channels];
303                 for(int i = 0; i < asset->channels; i++)
304                         pcm_history[i] = new double[HISTORY_MAX];
305                 history_start = 0;
306                 history_size = 0;
307         }
309 // Restart history.  Don't bother shifting history back.
310         if(file->current_sample < history_start ||
311                 file->current_sample > history_start + history_size)
312         {
313                 history_size = 0;
314                 history_start = file->current_sample;
315                 decode_start = file->current_sample;
316                 decode_len = len;
317         }
318         else
319 // Shift history forward to make room for new samples
320         if(file->current_sample + len > history_start + history_size)
321         {
322                 if(file->current_sample + len > history_start + HISTORY_MAX)
323                 {
324                         int diff = file->current_sample + len - (history_start + HISTORY_MAX);
325                         for(int i = 0; i < asset->channels; i++)
326                         {
327                                 double *temp = pcm_history[i];
328                                 for(int j = 0; j < HISTORY_MAX - diff; j++)
329                                 {
330                                         temp[j] = temp[j + diff];
331                                 }
332                         }
333                         history_start += diff;
334                         history_size -= diff;
335                 }
337 // Decode more data
338                 decode_start = history_start + history_size;
339                 decode_len = file->current_sample + len - (history_start + history_size);
340         }
343 // Fill history buffer
344         if(history_start + history_size != ov_pcm_tell(&vf))
345         {
346 //printf("FileVorbis::read_samples %d %d\n", history_start + history_size, ov_pcm_tell(&vf));
347                 ov_pcm_seek(&vf, history_start + history_size);
348         }
350         while(accumulation < decode_len)
351         {
352                 int result = ov_read_float(&vf,
353                         &vorbis_output,
354                         decode_len - accumulation,
355                         &bitstream);
356 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
357                 if(!result) break;
359                 for(int i = 0; i < asset->channels; i++)
360                 {
361                         double *output = pcm_history[i] + history_size;
362                         float *input = vorbis_output[i];
363                         for(int j = 0; j < result; j++)
364                                 output[j] = input[j];
365                 }
366                 history_size += result;
367                 accumulation += result;
368         }
371 // printf("FileVorbis::read_samples 1 %d %d\n", 
372 // file->current_sample,
373 // history_start);
375         double *input = pcm_history[file->current_channel] + 
376                 file->current_sample - 
377                 history_start;
378         for(int i = 0; i < len; i++)
379                 buffer[i] = input[i];
381 // printf("FileVorbis::read_samples 2 %d %d %d %d\n", 
382 // history_start, 
383 // history_size,
384 // file->current_sample,
385 // len);
387         return 0;
399 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window, 
400         Asset *asset)
401  : BC_Window(PROGRAM_NAME ": Audio Compression",
402         parent_window->get_abs_cursor_x(1),
403         parent_window->get_abs_cursor_y(1),
404         350,
405         170,
406         -1,
407         -1,
408         0,
409         0,
410         1)
412         this->parent_window = parent_window;
413         this->asset = asset;
416 VorbisConfigAudio::~VorbisConfigAudio()
420 int VorbisConfigAudio::create_objects()
422         int x = 10, y = 10;
423         int x1 = 150;
424         char string[BCTEXTLEN];
426         add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
427         add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
429         y += 30;
430         sprintf(string, "%d", asset->vorbis_min_bitrate);
431         add_tool(new BC_Title(x, y, _("Min bitrate:")));
432         add_tool(new VorbisMinBitrate(x1, y, this, string));
434         y += 30;
435         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
436         sprintf(string, "%d", asset->vorbis_bitrate);
437         add_tool(new VorbisAvgBitrate(x1, y, this, string));
439         y += 30;
440         add_tool(new BC_Title(x, y, _("Max bitrate:")));
441         sprintf(string, "%d", asset->vorbis_max_bitrate);
442         add_tool(new VorbisMaxBitrate(x1, y, this, string));
445         add_subwindow(new BC_OKButton(this));
446         show_window();
447         flush();
448         return 0;
451 int VorbisConfigAudio::close_event()
453         set_done(0);
454         return 1;
461 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
462  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
464         this->gui = gui;
466 int VorbisFixedBitrate::handle_event()
468         gui->asset->vorbis_vbr = 0;
469         gui->variable_bitrate->update(0);
470         return 1;
473 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
474  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
476         this->gui = gui;
478 int VorbisVariableBitrate::handle_event()
480         gui->asset->vorbis_vbr = 1;
481         gui->fixed_bitrate->update(0);
482         return 1;
486 VorbisMinBitrate::VorbisMinBitrate(int x, 
487         int y, 
488         VorbisConfigAudio *gui, 
489         char *text)
490  : BC_TextBox(x, y, 180, 1, text)
492         this->gui = gui;
494 int VorbisMinBitrate::handle_event()
496         gui->asset->vorbis_min_bitrate = atol(get_text());
497         return 1;
502 VorbisMaxBitrate::VorbisMaxBitrate(int x, 
503         int y, 
504         VorbisConfigAudio *gui,
505         char *text)
506  : BC_TextBox(x, y, 180, 1, text)
508         this->gui = gui;
510 int VorbisMaxBitrate::handle_event()
512         gui->asset->vorbis_max_bitrate = atol(get_text());
513         return 1;
518 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
519  : BC_TextBox(x, y, 180, 1, text)
521         this->gui = gui;
523 int VorbisAvgBitrate::handle_event()
525         gui->asset->vorbis_bitrate = atol(get_text());
526         return 1;