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