allow ffmpeg video to resample curr_pos, add bluray format
[goodguy/history.git] / cinelerra-5.0 / quicktime / vorbis.c
1 #include "funcprotos.h"
2 #include "quicktime.h"
3 #include "qtvorbis.h"
4 #include <string.h>
5 #include <time.h>
6 #include "vorbis/vorbisenc.h"
7
8 // Attempts to read more samples than this will crash
9 #define OUTPUT_ALLOCATION 0x100000
10 #define CLAMP(x, y, z) ((x) = ((x) <  (y) ? (y) : ((x) > (z) ? (z) : (x))))
11
12 typedef struct
13 {
14         int max_bitrate;
15         int nominal_bitrate;
16         int min_bitrate;
17         int use_vbr;
18         int encode_initialized;
19         ogg_stream_state enc_os;
20         ogg_page enc_og;
21         ogg_packet enc_op;
22         vorbis_info enc_vi;
23         vorbis_comment enc_vc;
24         vorbis_dsp_state enc_vd;
25         vorbis_block enc_vb;
26 // Number of samples written to disk
27         int encoded_samples;
28 // Number of bytes written to disk
29         int64_t encoded_bytes;
30
31
32 // Number of samples encoded into the chunk
33         int next_chunk_size;
34
35
36
37         ogg_sync_state   dec_oy; /* sync and verify incoming physical bitstream */
38         ogg_stream_state dec_os; /* take physical pages, weld into a logical
39                                 stream of packets */
40         ogg_page         dec_og; /* one Ogg bitstream page.  Vorbis packets are inside */
41         ogg_packet       dec_op; /* one raw packet of data for decode */
42
43         vorbis_info      dec_vi; /* struct that stores all the static vorbis bitstream
44                                 settings */
45         vorbis_comment   dec_vc; /* struct that stores all the bitstream user comments */
46         vorbis_dsp_state dec_vd; /* central working state for the packet->PCM decoder */
47         vorbis_block     dec_vb; /* local working space for packet->PCM decode */
48
49         unsigned int dec_current_serialno;
50         int decode_initialized;
51         float **output;
52
53 // Number of last sample relative to file
54         int64_t output_position;
55 // Number of last sample relative to output buffer
56         long output_end;
57 // Number of samples in output buffer
58         long output_size;
59 // Number of samples allocated in output buffer
60         long output_allocated;
61 // Current reading position in file
62         int64_t chunk;
63 // Number of samples decoded in the current chunk
64         int chunk_samples;
65 } quicktime_vorbis_codec_t;
66
67
68 /* =================================== public for vorbis */
69
70 static void delete_codec(quicktime_audio_map_t *atrack)
71 {
72         quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv;
73         int i;
74
75         if(codec->encode_initialized)
76         {
77                 ogg_stream_clear(&codec->enc_os);
78                 vorbis_block_clear(&codec->enc_vb);
79                 vorbis_dsp_clear(&codec->enc_vd);
80                 vorbis_comment_clear(&codec->enc_vc);
81                 vorbis_info_clear(&codec->enc_vi);
82         }
83
84         if(codec->decode_initialized)
85         {
86                 if(codec->output) 
87                 {
88                         for(i = 0; i < atrack->channels; i++)
89                                 free(codec->output[i]);
90
91                         free(codec->output);
92                 }
93
94                 ogg_stream_clear(&codec->dec_os);
95                 vorbis_block_clear(&codec->dec_vb);
96                 vorbis_dsp_clear(&codec->dec_vd);
97                 vorbis_comment_clear(&codec->dec_vc);
98                 vorbis_info_clear(&codec->dec_vi);
99         }
100
101         free(codec);
102 }
103
104
105
106
107
108 // Buffer fragment should be bigger then largest page header so
109 // all lacing bytes can be decoded.
110 #define BUFFER_FRAGMENT 4096
111
112 // Calculate chunk length from OggS headers.  This is the worst case
113 // but it's better not to assume libogg is going to do anything for us.
114
115 #define SEGMENT_OFFSET 0x1a
116 #define LACE_OFFSET 0x1b
117 static int chunk_len(quicktime_t *file, int64_t offset, int64_t next_chunk)
118 {
119         int result = 0;
120         unsigned char buffer[BUFFER_FRAGMENT];
121         int accum = 0;
122         int segment_count = 0;
123         int page_size = 0;
124         int i;
125
126         while(offset < next_chunk)
127         {
128                 quicktime_set_position(file, offset);
129                 result = !quicktime_read_data(file, (char*)buffer, BUFFER_FRAGMENT);
130                 if(result || memcmp(buffer, "OggS", 4))
131                         return accum;
132
133 // Decode size of OggS page
134                 segment_count = buffer[SEGMENT_OFFSET];
135
136 // Decode one segment at a time
137                 i = LACE_OFFSET;
138                 page_size = 0;
139                 while(segment_count > 0)
140                 {
141                         page_size += buffer[i++];
142                         segment_count--;
143                 }
144                 accum += i + page_size;
145                 offset += i + page_size;
146         }
147
148
149         return accum;
150 }
151
152
153 // Calculates the chunk size based on ogg pages.
154 #define READ_CHUNK(chunk) \
155 { \
156         int64_t offset1 = quicktime_chunk_to_offset(file, trak, (chunk)); \
157         int64_t offset2 = quicktime_chunk_to_offset(file, trak, (chunk) + 1); \
158         int size = 0; \
159         if(offset2 == offset1) \
160                 result = 1; \
161         else \
162         { \
163                 size = chunk_len(file, offset1, \
164                         offset2 > offset1 ? offset2 : offset1 + 0xfffff); \
165  \
166                 buffer = (char*)ogg_sync_buffer(&codec->dec_oy, size); \
167                 quicktime_set_position(file, offset1); \
168                 result = !quicktime_read_data(file, (char*)buffer, size); \
169                 ogg_sync_wrote(&codec->dec_oy, size); \
170         } \
171 /* printf("READ_CHUNK size=%d\n", size); */ \
172 /* printf("%llx %x: ", quicktime_chunk_to_offset(file, trak, (chunk)), size); */ \
173 /* for(i = 0; i < 16; i++) */ \
174 /*      printf("%02x ", buffer[i]); */ \
175 /* printf("result=%d\n", result); */ \
176 }
177
178
179
180
181 static int decode(quicktime_t *file, 
182                                         int16_t *output_i, 
183                                         float *output_f, 
184                                         long samples, 
185                                         int track, 
186                                         int channel)
187 {
188         int result = 0;
189         int i, j;
190         quicktime_audio_map_t *track_map = &(file->atracks[track]);
191         quicktime_trak_t *trak = track_map->track;
192         quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
193         long current_position = track_map->current_position;
194         long end_position = current_position + samples;
195         char *buffer;
196 // End of data in ogg buffer
197         int eos = 0;
198         float *pcm;
199         int have_chunk = 0;
200
201
202         if(samples > OUTPUT_ALLOCATION)
203                 printf("vorbis.c decode: can't read more than %d samples at a time.\n", OUTPUT_ALLOCATION);
204
205
206
207         if(output_i) bzero(output_i, sizeof(int16_t) * samples);
208         if(output_f) bzero(output_f, sizeof(float) * samples);
209
210
211
212
213
214
215
216 // Seeked outside output buffer's range or not initialized: restart
217         if(current_position < codec->output_position - codec->output_size ||
218                 current_position > codec->output_position ||
219                 !codec->decode_initialized)
220         {
221
222                 quicktime_chunk_of_sample(&codec->output_position, 
223                         &codec->chunk, 
224                         trak, 
225                         current_position);
226 // We know the first ogg packet in the chunk has a pcm_offset from the encoding.
227
228                 codec->output_size = 0;
229                 codec->output_end = 0;
230                 codec->chunk_samples = 0;
231
232
233
234         
235 // Initialize and load initial buffer for decoding
236                 if(!codec->decode_initialized)
237                 {
238                         int init_chunk = 1;
239                         codec->decode_initialized = 1;
240
241                         codec->output = malloc(sizeof(float*) * track_map->channels);
242                         for(i = 0; i < track_map->channels; i++)
243                         {
244                                 codec->output[i] = malloc(sizeof(float) * OUTPUT_ALLOCATION);
245                         }
246
247                         codec->output_allocated = OUTPUT_ALLOCATION;
248
249                 ogg_sync_init(&codec->dec_oy); /* Now we can read pages */
250
251
252
253
254                         READ_CHUNK(init_chunk);
255                         init_chunk++;
256
257                         if(ogg_sync_pageout(&codec->dec_oy, &codec->dec_og)!=1)
258                         {
259                                 fprintf(stderr, "decode: ogg_sync_pageout: Must not be Vorbis data\n");
260                                 return 1;
261                         }
262
263
264                 ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og));
265                 vorbis_info_init(&codec->dec_vi);
266                 vorbis_comment_init(&codec->dec_vc);
267
268                 if(ogg_stream_pagein(&codec->dec_os, &codec->dec_og) < 0)
269                         {
270                         fprintf(stderr,"decode: ogg_stream_pagein: stream version mismatch perhaps.\n");
271                         return 1;
272                 }
273
274                         if(ogg_stream_packetout(&codec->dec_os, &codec->dec_op) != 1)
275                         {
276                                 fprintf(stderr, "decode: ogg_stream_packetout: Must not be Vorbis data\n");
277                         return 1;
278                         }
279
280                         if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0)
281                         {
282                                 fprintf(stderr, "decode: vorbis_synthesis_headerin: not a vorbis header\n");
283                                 return 1;
284                         }
285
286
287                         i = 0;
288                         while(i < 2)
289                         {
290                                 while(i < 2)
291                                 {
292                                         result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og);
293                                         if(result == 0) break;
294
295                                         if(result == 1)
296                                         {
297                                                 ogg_stream_pagein(&codec->dec_os, &codec->dec_og);
298
299                                                 while(i < 2)
300                                                 {
301                                                         result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op);
302
303                                                         if(result == 0) break;
304
305                                                         if(result < 0)
306                                                         {
307                                                                 fprintf(stderr, "decode: ogg_stream_packetout: corrupt secondary header\n");
308                                                                 return 1;
309                                                         }
310
311                                                         vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op);
312                                                         i++;
313
314
315
316
317                                                 }
318                                         }
319                                 }
320
321                                 if(i < 2)
322                                 {
323                                         READ_CHUNK(init_chunk);
324                                         init_chunk++;
325                                 }
326
327 // Header should never span more than one chunk so assume it's done here
328                         }
329
330                         vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi);
331                         vorbis_block_init(&codec->dec_vd, &codec->dec_vb);
332
333 // Also the first chunk needed in decoding so don't reread after this.
334                         if(codec->chunk == init_chunk - 1) 
335                         {
336                                 have_chunk = 1;
337                                 codec->chunk++;
338                         }
339                 }
340
341
342
343
344 // Don't already have initial chunk from header
345                 if(!have_chunk)
346                 {
347 // Get initial chunk for decoding at new location
348 // From vorbisfile.c
349 /* clear out decoding machine state */
350                         ogg_stream_clear(&codec->dec_os);
351                         vorbis_dsp_clear(&codec->dec_vd);
352                         vorbis_block_clear(&codec->dec_vb);
353                 ogg_sync_reset(&codec->dec_oy);
354
355                 ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og));
356                 ogg_sync_init(&codec->dec_oy);
357                         vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi);
358                         vorbis_block_init(&codec->dec_vd, &codec->dec_vb);
359
360
361                         READ_CHUNK(codec->chunk);
362                         codec->chunk++;
363                         have_chunk = 1;
364                 }
365         }
366
367 // Assume the chunk exists by now and rely on libogg to say if it's out of
368 // data.
369         have_chunk = 1;
370
371
372
373
374
375
376
377
378
379
380
381 // Read chunks until output buffer is on or after end_position
382         result = 0;
383         while(codec->output_position < end_position)
384         {
385
386
387 // Read chunk to decode if it hasn't been read yet.
388                 if(!have_chunk)
389                 {
390                         codec->chunk_samples = 0;
391
392                         READ_CHUNK(codec->chunk);
393                         if(result) break;
394                         codec->chunk++;
395                 }
396
397                 eos = 0;
398                 while(!eos)
399                 {
400                         result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og);
401
402
403
404
405
406
407
408 // Need more data from chunk
409                         if(result == 0)
410                         {
411 // End of chunk
412                                 eos = 1;
413                         }
414                         else
415 // This stage checks for OggS and a checksum error.
416 // It doesn't tell if it's the end of a chunk.  Need to manually parse OggS
417 // pages to figure out how big the chunk is.
418                         if(result < 0)
419                         {
420 //printf("ogg_sync_pageout=-1\n");
421                                 ;
422                         }
423                         else
424                         {
425                                 ogg_stream_pagein(&codec->dec_os, &codec->dec_og);
426
427
428
429                                 while(!eos)
430                                 {
431 //printf("decode 7\n");
432                                         result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op);
433
434 //printf("decode 8 %d\n", result);
435                                         if(result == 0)
436                                         {
437 //printf("ogg_stream_packetout=0\n");
438 // End of page
439                                                 eos = 1;
440                                         }
441                                         else
442 // This stage doesn't check for OggS.
443                                         if(result < 0)
444                                         {
445 //printf("ogg_stream_packetout=-1\n");
446                                         }
447                                         else
448                                         {
449                                                 float **pcm;
450
451
452
453
454
455
456
457                                                 if(vorbis_synthesis(&codec->dec_vb, &codec->dec_op) == 0)
458                                                 {
459                                                         vorbis_synthesis_blockin(&codec->dec_vd, 
460                                                                 &codec->dec_vb);
461                                                 }
462
463
464                                                 while((result = vorbis_synthesis_pcmout(&codec->dec_vd, &pcm)) > 0)
465                                                 {
466 //printf("vorbis_synthesis_pcmout=%x\n", result);
467                                                         for(i = 0; i < track_map->channels; i++)
468                                                         {
469                                                                 float *output_channel = codec->output[i];
470                                                                 float *input_channel = pcm[i];
471                                                                 int k = codec->output_end;
472
473                                                                 for(j = 0; j < result; j++)
474                                                                 {
475                                                                         output_channel[k++] = input_channel[j];
476                                                                         if(k >= codec->output_allocated)
477                                                                                 k = 0;
478                                                                 }
479                                                                 
480                                                                 if(i == track_map->channels - 1) 
481                                                                         codec->output_end = k;
482                                                         }
483 //printf("codec->output_end = %d\n", codec->output_end);
484
485                                                         codec->output_position += result;
486                                                         codec->output_size += result;
487                                                         codec->chunk_samples += result;
488                                                         if(codec->output_size > codec->output_allocated)
489                                                                 codec->output_size = codec->output_allocated;
490                                                         vorbis_synthesis_read(&codec->dec_vd, result);
491                                                 }
492                                         }
493 //printf("decode 11\n");
494                                 }
495
496 // Reset end of page so it isn't interpreted as an end of chunk
497                                 eos = 0;
498                         }
499                 }
500
501
502 // Next chunk
503                 if(eos)
504                 {
505 //printf("decode 12 got=%x\n", codec->chunk_samples);
506                         have_chunk = 0;
507                 }
508         }
509
510
511 // Fill silence
512         while(codec->output_position < end_position)
513         {
514                 for(i = 0; i < track_map->channels; i++)
515                         codec->output[i][codec->output_end] = 0;
516                 
517                 codec->output_end++;
518                 if(codec->output_end >= codec->output_allocated)
519                         codec->output_end = 0;
520                 codec->output_position++;
521         }
522 //printf("decode 15\n");
523
524
525 //printf("decode 2 codec->output_position=%lld codec->output_end=%d codec->output_size=%d\n", 
526 //      codec->output_position, codec->output_end, codec->output_size);
527
528         current_position = track_map->current_position;
529         i = codec->output_end - (codec->output_position - current_position);
530         j = 0;
531         while(i < 0) i += codec->output_allocated;
532         pcm = codec->output[channel];
533
534         if(output_i)
535         {
536                 for( ; j < samples; j++)
537                 {
538                         int sample = pcm[i] * 32767;
539                         CLAMP(sample, -32768, 32767);
540                         output_i[j] = sample;
541
542                         i++;
543                         if(i >= codec->output_allocated) i = 0;
544                 }
545         }
546         else
547         if(output_f)
548         {
549                 for( ; j < samples; j++)
550                 {
551                         output_f[j] = pcm[i];
552                         i++;
553                         if(i >= codec->output_allocated) i = 0;
554                 }
555         }
556 //printf("decode 16\n");
557
558         return 0;
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 #define FLUSH_OGG1 \
581 while(1) \
582 { \
583         int eos = !ogg_stream_flush(&codec->enc_os, &codec->enc_og); \
584         if(eos) break; \
585  \
586         if(!chunk_started) \
587         { \
588                 chunk_started = 1; \
589                 quicktime_write_chunk_header(file, trak, &chunk_atom); \
590         } \
591  \
592         result = !quicktime_write_data(file,(char*)codec->enc_og.header, codec->enc_og.header_len); \
593         size += codec->enc_og.header_len; \
594  \
595         if(!result) \
596         { \
597                 result = !quicktime_write_data(file,(char*)codec->enc_og.body, codec->enc_og.body_len); \
598                 size += codec->enc_og.body_len; \
599         } \
600  \
601  \
602         if(!result) break; \
603 }
604
605
606
607 #define FLUSH_OGG2 \
608 while(vorbis_analysis_blockout(&codec->enc_vd, &codec->enc_vb) == 1) \
609 { \
610     vorbis_analysis(&codec->enc_vb, &codec->enc_op); \
611     vorbis_bitrate_addblock(&codec->enc_vb); \
612         while(vorbis_bitrate_flushpacket(&codec->enc_vd, &codec->enc_op)) \
613         { \
614         ogg_stream_packetin(&codec->enc_os, &codec->enc_op); \
615  \
616                 while(!result) \
617                 { \
618                         if(!ogg_stream_pageout(&codec->enc_os, &codec->enc_og)) break; \
619          \
620  \
621                         if(!chunk_started) \
622                         { \
623                                 chunk_started = 1; \
624                                 quicktime_write_chunk_header(file, trak, &chunk_atom); \
625                         } \
626                         result = !quicktime_write_data(file, (char*)codec->enc_og.header, codec->enc_og.header_len); \
627                         size += codec->enc_og.header_len; \
628          \
629                         if(!result) \
630                         { \
631                                 result = !quicktime_write_data(file, (char*)codec->enc_og.body, codec->enc_og.body_len); \
632                                 size += codec->enc_og.body_len; \
633                         } \
634          \
635                         if(ogg_page_eos(&codec->enc_og)) break; \
636                 } \
637         } \
638 }
639
640
641 static int encode(quicktime_t *file, 
642                                                         int16_t **input_i, 
643                                                         float **input_f, 
644                                                         int track, 
645                                                         long samples)
646 {
647         int result = 0;
648         int64_t offset = quicktime_position(file);
649         quicktime_audio_map_t *track_map = &(file->atracks[track]);
650         quicktime_trak_t *trak = track_map->track;
651         quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
652         int samplerate = trak->mdia.minf.stbl.stsd.table[0].sample_rate;
653         float **output;
654         int size = 0;
655         int chunk_started = 0;
656         quicktime_atom_t chunk_atom;
657
658
659         if(samplerate < 32000)
660         {
661                 printf("encode: sample rate %d not supported.\n", samplerate);
662                 return 1;
663         }
664
665
666
667
668
669         if(!codec->encode_initialized)
670         {
671         ogg_packet header;
672         ogg_packet header_comm;
673         ogg_packet header_code;
674
675
676                 codec->encode_initialized = 1;
677                 if(file->use_avi)
678                         trak->mdia.minf.stbl.stsd.table[0].sample_size = 0;
679                 vorbis_info_init(&codec->enc_vi);
680
681                 if(codec->use_vbr)
682                 {
683                         result = vorbis_encode_setup_managed(&codec->enc_vi,
684                                 track_map->channels, 
685                                 samplerate, 
686                                 codec->max_bitrate, 
687                                 codec->nominal_bitrate, 
688                                 codec->min_bitrate);
689                         result |= vorbis_encode_ctl(&codec->enc_vi, OV_ECTL_RATEMANAGE_AVG, NULL);
690                         result |= vorbis_encode_setup_init(&codec->enc_vi);
691                 }
692                 else
693                 {
694                         vorbis_encode_init(&codec->enc_vi,
695                                 track_map->channels,
696                                 samplerate, 
697                                 codec->max_bitrate, 
698                                 codec->nominal_bitrate, 
699                                 codec->min_bitrate);
700                 }
701
702
703                 vorbis_comment_init(&codec->enc_vc);
704                 vorbis_analysis_init(&codec->enc_vd, &codec->enc_vi);
705                 vorbis_block_init(&codec->enc_vd, &codec->enc_vb);
706         srand(time(NULL));
707                 ogg_stream_init(&codec->enc_os, rand());
708
709
710         vorbis_analysis_headerout(&codec->enc_vd, 
711                         &codec->enc_vc,
712                         &header,
713                         &header_comm,
714                         &header_code);
715
716         ogg_stream_packetin(&codec->enc_os, &header); 
717         ogg_stream_packetin(&codec->enc_os, &header_comm);
718         ogg_stream_packetin(&codec->enc_os, &header_code);
719
720                 FLUSH_OGG1
721         }
722
723     output = vorbis_analysis_buffer(&codec->enc_vd, samples);
724
725         if(input_i)
726         {
727                 int i, j;
728                 for(i = 0; i < track_map->channels; i++)
729                 {
730                         for(j = 0; j < samples; j++)
731                         {
732                                 output[i][j] = (float)input_i[i][j] / (float)32768;
733                         }
734                 }
735         }
736         else
737         if(input_f)
738         {
739                 int i;
740                 for(i = 0; i < track_map->channels; i++)
741                 {
742                         memcpy(output[i], input_f[i], sizeof(float) * samples);
743                 }
744         }
745
746     vorbis_analysis_wrote(&codec->enc_vd, samples);
747
748         FLUSH_OGG2
749
750         codec->next_chunk_size += samples;
751
752 // Wrote a chunk.
753         if(chunk_started)
754         {
755                 int new_encoded_samples = codec->enc_vd.granulepos;
756 // granulepos is meaningless for fixed bitrate
757                 if(!codec->use_vbr)
758                 {
759                         codec->encoded_bytes += quicktime_position(file) - offset;
760                         new_encoded_samples = codec->encoded_bytes *
761                                 (int64_t)8 *
762                                 (int64_t)samplerate / 
763                                 (int64_t)codec->nominal_bitrate;
764                 }
765                 quicktime_write_chunk_footer(file, 
766                                                 trak,
767                                                 track_map->current_chunk,
768                                                 &chunk_atom, 
769                                                 new_encoded_samples - codec->encoded_samples);
770                 track_map->current_chunk++;
771                 codec->next_chunk_size = 0;
772                 codec->encoded_samples = new_encoded_samples;
773         }
774
775         return result;
776 }
777
778
779
780
781 static int set_parameter(quicktime_t *file, 
782                 int track, 
783                 char *key, 
784                 void *value)
785 {
786         quicktime_audio_map_t *atrack = &(file->atracks[track]);
787         quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv;
788
789
790         if(!strcasecmp(key, "vorbis_vbr"))
791                 codec->use_vbr = *(int*)value;
792         else
793         if(!strcasecmp(key, "vorbis_bitrate"))
794                 codec->nominal_bitrate = *(int*)value;
795         else
796         if(!strcasecmp(key, "vorbis_max_bitrate"))
797                 codec->max_bitrate = *(int*)value;
798         else
799         if(!strcasecmp(key, "vorbis_min_bitrate"))
800                 codec->min_bitrate = *(int*)value;
801         return 0;
802 }
803
804
805 static void flush(quicktime_t *file, int track)
806 {
807         quicktime_audio_map_t *track_map = &(file->atracks[track]);
808         quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
809         if(codec->encode_initialized)
810         {
811                 int result = 0;
812                 int size = 0;
813                 int64_t offset = quicktime_position(file);
814                 //long output_position = codec->enc_vd.granulepos;
815                 int chunk_started = 0;
816                 quicktime_trak_t *trak = track_map->track;
817                 int sample_rate = trak->mdia.minf.stbl.stsd.table[0].sample_rate;
818                 quicktime_atom_t chunk_atom;
819
820                 vorbis_analysis_wrote(&codec->enc_vd,0);
821
822                 FLUSH_OGG2
823         
824                 if(chunk_started)
825                 {
826                         int new_encoded_samples = codec->enc_vd.granulepos;
827                         if(!codec->use_vbr)
828                         {
829                                 codec->encoded_bytes += quicktime_position(file) - offset;
830                                 new_encoded_samples = codec->encoded_bytes *
831                                         (int64_t)8 *
832                                         (int64_t)sample_rate / 
833                                         (int64_t)codec->nominal_bitrate;
834                         }
835                         quicktime_write_chunk_footer(file, 
836                                                         trak,
837                                                         track_map->current_chunk,
838                                                         &chunk_atom, 
839                                                         new_encoded_samples - codec->encoded_samples);
840                         track_map->current_chunk++;
841                         codec->next_chunk_size = 0;
842                 }
843         }
844 }
845
846 void quicktime_init_codec_vorbis(quicktime_audio_map_t *atrack)
847 {
848         quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec;
849         quicktime_vorbis_codec_t *codec;
850
851 /* Init public items */
852         codec_base->priv = calloc(1, sizeof(quicktime_vorbis_codec_t));
853         codec_base->delete_acodec = delete_codec;
854         codec_base->decode_audio = decode;
855         codec_base->encode_audio = encode;
856         codec_base->set_parameter = set_parameter;
857         codec_base->flush = flush;
858         codec_base->fourcc = QUICKTIME_VORBIS;
859         codec_base->title = "OGG Vorbis";
860         codec_base->desc = "OGG Vorbis for video. (Not standardized)";
861
862         codec = codec_base->priv;
863         codec->nominal_bitrate = 128000;
864         codec->max_bitrate = -1;
865         codec->min_bitrate = -1;
866 }