r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / filevorbis.C
blob955c2eff7d926499a1ce364394f82c8747968844
1 #include "assets.h"
2 #include "byteorder.h"
3 #include "clip.h"
4 #include "file.h"
5 #include "filevorbis.h"
6 #include "guicast.h"
7 #include "mwindow.inc"
9 #include <errno.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <libintl.h>
14 #define _(String) gettext(String)
15 #define gettext_noop(String) String
16 #define N_(String) gettext_noop (String)
18 FileVorbis::FileVorbis(Asset *asset, File *file)
19  : FileBase(asset, file)
21         reset_parameters();
22         if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
23         asset->byte_order = 0;
26 FileVorbis::~FileVorbis()
28         close_file();
31 void FileVorbis::get_parameters(BC_WindowBase *parent_window, 
32         Asset *asset, 
33         BC_WindowBase* &format_window,
34         int audio_options,
35         int video_options)
37         if(audio_options)
38         {
39                 VorbisConfigAudio *window = new VorbisConfigAudio(parent_window, asset);
40                 format_window = window;
41                 window->create_objects();
42                 window->run_window();
43                 delete window;
44         }
47 int FileVorbis::check_sig(Asset *asset)
49         FILE *fd = fopen(asset->path, "rb");
50         OggVorbis_File vf;
51         if(ov_open(fd, &vf, NULL, 0) < 0)
52         {
53                 ov_clear(&vf);
54                 if(fd) fclose(fd);
55                 return 0;
56         }
57         else
58         {
59                 ov_clear(&vf);
60                 return 1;
61         }
64 int FileVorbis::reset_parameters_derived()
66         fd = 0;
67         bzero(&vf, sizeof(vf));
68         pcm_history = 0;
72 // Just create the Quicktime objects since this routine is also called
73 // for reopening.
74 int FileVorbis::open_file(int rd, int wr)
76         int result = 0;
77         this->rd = rd;
78         this->wr = wr;
80 //printf("FileVorbis::open_file 1\n");
81         if(rd)
82         {
83 //printf("FileVorbis::open_file 1\n");
84                 if(!(fd = fopen(asset->path, "rb")))
85                 {
86                         printf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
87                         result = 1;
88                 }
89                 else
90                 {
91 //printf("FileVorbis::open_file 2 %p %p\n", fd, vf);
92                         if(ov_open(fd, &vf, NULL, 0) < 0)
93                         {
94                                 printf(_("FileVorbis::open_file %s: invalid bitstream.\n"), asset->path);
95                                 result = 1;
96                         }
97                         else
98                         {
99 //printf("FileVorbis::open_file 1\n");
100                                 vorbis_info *vi = ov_info(&vf, -1);
101                                 asset->channels = vi->channels;
102                                 if(!asset->sample_rate)
103                                         asset->sample_rate = vi->rate;
104 //printf("FileVorbis::open_file 1\n");
105                                 asset->audio_length = ov_pcm_total(&vf,-1);
106 //printf("FileVorbis::open_file 1\n");
107                                 asset->audio_data = 1;
108 // printf("FileVorbis::open_file 1 %d %d %d\n", 
109 // asset->channels, 
110 // asset->sample_rate, 
111 // asset->audio_length);
112                         }
113                 }
114         }
116         if(wr)
117         {
118                 if(!(fd = fopen(asset->path, "wb")))
119                 {
120                         printf("FileVorbis::open_file %s: %s\n", asset->path, strerror(errno));
121                         result = 1;
122                 }
123                 else
124                 {
125                         vorbis_info_init(&vi);
126                         if(!asset->vorbis_vbr)
127                                 result = vorbis_encode_init(&vi, 
128                                         asset->channels, 
129                                         asset->sample_rate, 
130                                         asset->vorbis_max_bitrate, 
131                                         asset->vorbis_bitrate, 
132                                         asset->vorbis_min_bitrate);
133                         else
134                         {
135                                 result = vorbis_encode_setup_managed(&vi,
136                                         asset->channels, 
137                                         asset->sample_rate, 
138                                         asset->vorbis_max_bitrate, 
139                                         asset->vorbis_bitrate, 
140                                         asset->vorbis_min_bitrate);
141                                 result |= vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, NULL);
142                                 result |= vorbis_encode_setup_init(&vi);
143                         }
145                         if(!result)
146                         {
147                                 vorbis_analysis_init(&vd, &vi);
148                                 vorbis_block_init(&vd, &vb);
149                                 vorbis_comment_init(&vc);
150                                 srand(time(NULL));
151                                 ogg_stream_init(&os, rand());
153                                 ogg_packet header;
154                                 ogg_packet header_comm;
155                                 ogg_packet header_code;
156                                 vorbis_analysis_headerout(&vd, 
157                                         &vc,
158                                         &header,
159                                         &header_comm,
160                                         &header_code);
161                                 ogg_stream_packetin(&os,
162                                         &header);
163                                 ogg_stream_packetin(&os, 
164                                         &header_comm);
165                                 ogg_stream_packetin(&os,
166                                         &header_code);
168                                 while(1)
169                                 {
170                                         int result = ogg_stream_flush(&os, &og);
171                                         if(result == 0) break;
172                                         fwrite(og.header, 1, og.header_len, fd);
173                                         fwrite(og.body, 1, og.body_len, fd);
174                                 }
175                         }
176                 }
177         }
179 //printf("FileVorbis::open_file 2\n");
180         return result;
183 #define FLUSH_VORBIS \
184 while(vorbis_analysis_blockout(&vd, &vb) == 1) \
185 { \
186         vorbis_analysis(&vb, NULL); \
187         vorbis_bitrate_addblock(&vb); \
188         while(vorbis_bitrate_flushpacket(&vd, &op)) \
189         { \
190                 ogg_stream_packetin(&os, &op); \
191                 int done = 0; \
192                 while(1) \
193                 { \
194                         int result = ogg_stream_pageout(&os, &og); \
195                         if(!result) break; \
196                         fwrite(og.header, 1, og.header_len, fd); \
197                         fwrite(og.body, 1, og.body_len, fd); \
198                         if(ogg_page_eos(&og)) break; \
199                 } \
200         } \
204 int FileVorbis::close_file()
206         if(fd)
207         {
208                 if(wr)
209                 {
210                         vorbis_analysis_wrote(&vd, 0);
211                         FLUSH_VORBIS
213                         ogg_stream_clear(&os);
214                         vorbis_block_clear(&vb);
215                         vorbis_dsp_clear(&vd);
216                         vorbis_comment_clear(&vc);
217                         vorbis_info_clear(&vi);
218                         fclose(fd);
219                 }
220                 
221                 if(rd)
222                 {
223 // This also closes the file handle.
224                         ov_clear(&vf);
225                 }
226                 fd = 0;
227         }
229         if(pcm_history)
230         {
231                 for(int i = 0; i < asset->channels; i++)
232                         delete [] pcm_history[i];
233                 delete [] pcm_history;
234         }
236         reset_parameters();
237         FileBase::close_file();
238         return 0;
242 int FileVorbis::write_samples(double **buffer, int64_t len)
244         if(!fd) return 0;
245         int result = 0;
247         float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
248         for(int i = 0; i < asset->channels; i++)
249         {
250                 float *output = vorbis_buffer[i];
251                 double *input = buffer[i];
252                 for(int j = 0; j < len; j++)
253                 {
254                         output[j] = input[j];
255                 }
256         }
257     vorbis_analysis_wrote(&vd, len);
259         FLUSH_VORBIS
261         return result;
264 int FileVorbis::read_samples(double *buffer, int64_t len)
266         if(!fd) return 0;
268 // printf("FileVorbis::read_samples 1 %d %d %d %d\n", 
269 // history_start, 
270 // history_size,
271 // file->current_sample,
272 // len);
273         float **vorbis_output;
274         int bitstream;
275         int accumulation = 0;
276 //printf("FileVorbis::read_samples 1\n");
277         int decode_start = 0;
278         int decode_len = 0;
280         if(len > 0x100000)
281         {
282                 printf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
283                 return 1;
284         }
286         if(!pcm_history)
287         {
288                 pcm_history = new double*[asset->channels];
289                 for(int i = 0; i < asset->channels; i++)
290                         pcm_history[i] = new double[HISTORY_MAX];
291                 history_start = 0;
292                 history_size = 0;
293         }
295 // Restart history.  Don't bother shifting history back.
296         if(file->current_sample < history_start ||
297                 file->current_sample > history_start + history_size)
298         {
299                 history_size = 0;
300                 history_start = file->current_sample;
301                 decode_start = file->current_sample;
302                 decode_len = len;
303         }
304         else
305 // Shift history forward to make room for new samples
306         if(file->current_sample + len > history_start + history_size)
307         {
308                 if(file->current_sample + len > history_start + HISTORY_MAX)
309                 {
310                         int diff = file->current_sample + len - (history_start + HISTORY_MAX);
311                         for(int i = 0; i < asset->channels; i++)
312                         {
313                                 double *temp = pcm_history[i];
314                                 for(int j = 0; j < HISTORY_MAX - diff; j++)
315                                 {
316                                         temp[j] = temp[j + diff];
317                                 }
318                         }
319                         history_start += diff;
320                         history_size -= diff;
321                 }
323 // Decode more data
324                 decode_start = history_start + history_size;
325                 decode_len = file->current_sample + len - (history_start + history_size);
326         }
329 // Fill history buffer
330         if(history_start + history_size != ov_pcm_tell(&vf))
331         {
332 //printf("FileVorbis::read_samples %d %d\n", history_start + history_size, ov_pcm_tell(&vf));
333                 ov_pcm_seek(&vf, history_start + history_size);
334         }
336         while(accumulation < decode_len)
337         {
338                 int result = ov_read_float(&vf,
339                         &vorbis_output,
340                         decode_len - accumulation,
341                         &bitstream);
342 //printf("FileVorbis::read_samples 1 %d %d %d\n", result, len, accumulation);
343                 if(!result) break;
345                 for(int i = 0; i < asset->channels; i++)
346                 {
347                         double *output = pcm_history[i] + history_size;
348                         float *input = vorbis_output[i];
349                         for(int j = 0; j < result; j++)
350                                 output[j] = input[j];
351                 }
352                 history_size += result;
353                 accumulation += result;
354         }
357 // printf("FileVorbis::read_samples 1 %d %d\n", 
358 // file->current_sample,
359 // history_start);
361         double *input = pcm_history[file->current_channel] + 
362                 file->current_sample - 
363                 history_start;
364         for(int i = 0; i < len; i++)
365                 buffer[i] = input[i];
367 // printf("FileVorbis::read_samples 2 %d %d %d %d\n", 
368 // history_start, 
369 // history_size,
370 // file->current_sample,
371 // len);
373         return 0;
385 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window, 
386         Asset *asset)
387  : BC_Window(PROGRAM_NAME ": Audio Compression",
388         parent_window->get_abs_cursor_x(),
389         parent_window->get_abs_cursor_y(),
390         350,
391         170,
392         -1,
393         -1,
394         0,
395         0,
396         1)
398         this->parent_window = parent_window;
399         this->asset = asset;
402 VorbisConfigAudio::~VorbisConfigAudio()
406 int VorbisConfigAudio::create_objects()
408         int x = 10, y = 10;
409         int x1 = 150;
410         char string[BCTEXTLEN];
412         add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
413         add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
415         y += 30;
416         sprintf(string, "%d", asset->vorbis_min_bitrate);
417         add_tool(new BC_Title(x, y, _("Min bitrate:")));
418         add_tool(new VorbisMinBitrate(x1, y, this, string));
420         y += 30;
421         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
422         sprintf(string, "%d", asset->vorbis_bitrate);
423         add_tool(new VorbisAvgBitrate(x1, y, this, string));
425         y += 30;
426         add_tool(new BC_Title(x, y, _("Max bitrate:")));
427         sprintf(string, "%d", asset->vorbis_max_bitrate);
428         add_tool(new VorbisMaxBitrate(x1, y, this, string));
431         add_subwindow(new BC_OKButton(this));
432         show_window();
433         flush();
434         return 0;
437 int VorbisConfigAudio::close_event()
439         set_done(0);
440         return 1;
447 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
448  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
450         this->gui = gui;
452 int VorbisFixedBitrate::handle_event()
454         gui->asset->vorbis_vbr = 0;
455         gui->variable_bitrate->update(0);
456         return 1;
459 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
460  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
462         this->gui = gui;
464 int VorbisVariableBitrate::handle_event()
466         gui->asset->vorbis_vbr = 1;
467         gui->fixed_bitrate->update(0);
468         return 1;
472 VorbisMinBitrate::VorbisMinBitrate(int x, 
473         int y, 
474         VorbisConfigAudio *gui, 
475         char *text)
476  : BC_TextBox(x, y, 180, 1, text)
478         this->gui = gui;
480 int VorbisMinBitrate::handle_event()
482         gui->asset->vorbis_min_bitrate = atol(get_text());
483         return 1;
488 VorbisMaxBitrate::VorbisMaxBitrate(int x, 
489         int y, 
490         VorbisConfigAudio *gui,
491         char *text)
492  : BC_TextBox(x, y, 180, 1, text)
494         this->gui = gui;
496 int VorbisMaxBitrate::handle_event()
498         gui->asset->vorbis_max_bitrate = atol(get_text());
499         return 1;
504 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
505  : BC_TextBox(x, y, 180, 1, text)
507         this->gui = gui;
509 int VorbisAvgBitrate::handle_event()
511         gui->asset->vorbis_bitrate = atol(get_text());
512         return 1;