1 #include "funcprotos.h"
4 #include "vorbis/vorbisenc.h"
6 // Attempts to read more samples than this will crash
7 #define OUTPUT_ALLOCATION 0x100000
8 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
16 int encode_initialized
;
17 ogg_stream_state enc_os
;
21 vorbis_comment enc_vc
;
22 vorbis_dsp_state enc_vd
;
24 // Number of samples written to disk
29 // Number of samples encoded into the chunk
34 ogg_sync_state dec_oy
; /* sync and verify incoming physical bitstream */
35 ogg_stream_state dec_os
; /* take physical pages, weld into a logical
37 ogg_page dec_og
; /* one Ogg bitstream page. Vorbis packets are inside */
38 ogg_packet dec_op
; /* one raw packet of data for decode */
40 vorbis_info dec_vi
; /* struct that stores all the static vorbis bitstream
42 vorbis_comment dec_vc
; /* struct that stores all the bitstream user comments */
43 vorbis_dsp_state dec_vd
; /* central working state for the packet->PCM decoder */
44 vorbis_block dec_vb
; /* local working space for packet->PCM decode */
46 unsigned int dec_current_serialno
;
47 int decode_initialized
;
50 // Number of last sample relative to file
51 int64_t output_position
;
52 // Number of last sample relative to output buffer
54 // Number of samples in output buffer
56 // Number of samples allocated in output buffer
57 long output_allocated
;
58 // Current reading position in file
60 // Number of samples decoded in the current chunk
62 } quicktime_vorbis_codec_t
;
65 /* =================================== public for vorbis */
67 static int delete_codec(quicktime_audio_map_t
*atrack
)
69 quicktime_vorbis_codec_t
*codec
= ((quicktime_codec_t
*)atrack
->codec
)->priv
;
72 if(codec
->encode_initialized
)
74 ogg_stream_clear(&codec
->enc_os
);
75 vorbis_block_clear(&codec
->enc_vb
);
76 vorbis_dsp_clear(&codec
->enc_vd
);
77 vorbis_comment_clear(&codec
->enc_vc
);
78 vorbis_info_clear(&codec
->enc_vi
);
81 if(codec
->decode_initialized
)
85 for(i
= 0; i
< atrack
->channels
; i
++)
86 free(codec
->output
[i
]);
91 ogg_stream_clear(&codec
->dec_os
);
92 vorbis_block_clear(&codec
->dec_vb
);
93 vorbis_dsp_clear(&codec
->dec_vd
);
94 vorbis_comment_clear(&codec
->dec_vc
);
95 vorbis_info_clear(&codec
->dec_vi
);
106 // Buffer fragment should be bigger then largest page header so
107 // all lacing bytes can be decoded.
108 #define BUFFER_FRAGMENT 4096
110 // Calculate chunk length from OggS headers. This is the worst case
111 // but it's better not to assume libogg is going to do anything for us.
113 #define SEGMENT_OFFSET 0x1a
114 #define LACE_OFFSET 0x1b
115 static int chunk_len(quicktime_t
*file
, int64_t offset
, int64_t next_chunk
)
118 unsigned char buffer
[BUFFER_FRAGMENT
];
120 int segment_count
= 0;
121 int segment_size
= 0;
126 while(offset
< next_chunk
)
128 quicktime_set_position(file
, offset
);
129 result
= !quicktime_read_data(file
, buffer
, BUFFER_FRAGMENT
);
136 if(memcmp(buffer
, "OggS", 4))
144 // Decode size of OggS page
145 segment_count
= buffer
[SEGMENT_OFFSET
];
147 // Decode one segment at a time
150 while(segment_count
> 0)
152 page_size
+= buffer
[i
++];
155 accum
+= i
+ page_size
;
156 offset
+= i
+ page_size
;
164 // Calculates the chunk size based on ogg pages.
165 #define READ_CHUNK(chunk) \
167 int64_t offset1 = quicktime_chunk_to_offset(file, trak, (chunk)); \
168 int64_t offset2 = quicktime_chunk_to_offset(file, trak, (chunk) + 1); \
170 if(offset2 == offset1) \
174 size = chunk_len(file, offset1, \
175 offset2 > offset1 ? offset2 : offset1 + 0xfffff); \
177 buffer = ogg_sync_buffer(&codec->dec_oy, size); \
178 quicktime_set_position(file, offset1); \
179 result = !quicktime_read_data(file, buffer, size); \
180 ogg_sync_wrote(&codec->dec_oy, size); \
182 /* printf("READ_CHUNK size=%d\n", size); */ \
183 /* printf("%llx %x: ", quicktime_chunk_to_offset(file, trak, (chunk)), size); */ \
184 /* for(i = 0; i < 16; i++) */ \
185 /* printf("%02x ", buffer[i]); */ \
186 /* printf("result=%d\n", result); */ \
192 static int decode(quicktime_t
*file
,
202 quicktime_audio_map_t
*track_map
= &(file
->atracks
[track
]);
203 quicktime_trak_t
*trak
= track_map
->track
;
204 quicktime_vorbis_codec_t
*codec
= ((quicktime_codec_t
*)track_map
->codec
)->priv
;
205 long current_position
= track_map
->current_position
;
206 long end_position
= current_position
+ samples
;
207 unsigned char *buffer
;
208 // End of data in ogg buffer
216 if(samples
> OUTPUT_ALLOCATION
)
217 printf("vorbis.c decode: can't read more than %p samples at a time.\n", OUTPUT_ALLOCATION
);
221 if(output_i
) bzero(output_i
, sizeof(int16_t) * samples
);
222 if(output_f
) bzero(output_f
, sizeof(float) * samples
);
230 // Seeked outside output buffer's range or not initialized: restart
231 if(current_position
< codec
->output_position
- codec
->output_size
||
232 current_position
> codec
->output_position
||
233 !codec
->decode_initialized
)
236 quicktime_chunk_of_sample(&codec
->output_position
,
240 // We know the first ogg packet in the chunk has a pcm_offset from the encoding.
242 codec
->output_size
= 0;
243 codec
->output_end
= 0;
244 codec
->chunk_samples
= 0;
249 // Initialize and load initial buffer for decoding
250 if(!codec
->decode_initialized
)
253 codec
->decode_initialized
= 1;
255 codec
->output
= malloc(sizeof(float*) * track_map
->channels
);
256 for(i
= 0; i
< track_map
->channels
; i
++)
258 codec
->output
[i
] = malloc(sizeof(float) * OUTPUT_ALLOCATION
);
261 codec
->output_allocated
= OUTPUT_ALLOCATION
;
263 ogg_sync_init(&codec
->dec_oy
); /* Now we can read pages */
268 READ_CHUNK(init_chunk
);
271 if(ogg_sync_pageout(&codec
->dec_oy
, &codec
->dec_og
)!=1)
273 fprintf(stderr
, "decode: ogg_sync_pageout: Must not be Vorbis data\n");
278 ogg_stream_init(&codec
->dec_os
, ogg_page_serialno(&codec
->dec_og
));
279 vorbis_info_init(&codec
->dec_vi
);
280 vorbis_comment_init(&codec
->dec_vc
);
282 if(ogg_stream_pagein(&codec
->dec_os
, &codec
->dec_og
) < 0)
284 fprintf(stderr
,"decode: ogg_stream_pagein: stream version mismatch perhaps.\n");
288 if(ogg_stream_packetout(&codec
->dec_os
, &codec
->dec_op
) != 1)
290 fprintf(stderr
, "decode: ogg_stream_packetout: Must not be Vorbis data\n");
294 if(vorbis_synthesis_headerin(&codec
->dec_vi
, &codec
->dec_vc
, &codec
->dec_op
) < 0)
296 fprintf(stderr
, "decode: vorbis_synthesis_headerin: not a vorbis header\n");
306 result
= ogg_sync_pageout(&codec
->dec_oy
, &codec
->dec_og
);
307 if(result
== 0) break;
311 ogg_stream_pagein(&codec
->dec_os
, &codec
->dec_og
);
315 result
= ogg_stream_packetout(&codec
->dec_os
, &codec
->dec_op
);
317 if(result
== 0) break;
321 fprintf(stderr
, "decode: ogg_stream_packetout: corrupt secondary header\n");
325 vorbis_synthesis_headerin(&codec
->dec_vi
, &codec
->dec_vc
, &codec
->dec_op
);
337 READ_CHUNK(init_chunk
);
341 // Header should never span more than one chunk so assume it's done here
344 vorbis_synthesis_init(&codec
->dec_vd
, &codec
->dec_vi
);
345 vorbis_block_init(&codec
->dec_vd
, &codec
->dec_vb
);
347 // Also the first chunk needed in decoding so don't reread after this.
348 if(codec
->chunk
== init_chunk
- 1)
358 // Don't already have initial chunk from header
361 // Get initial chunk for decoding at new location
363 /* clear out decoding machine state */
364 ogg_stream_clear(&codec
->dec_os
);
365 vorbis_dsp_clear(&codec
->dec_vd
);
366 vorbis_block_clear(&codec
->dec_vb
);
367 ogg_sync_reset(&codec
->dec_oy
);
369 ogg_stream_init(&codec
->dec_os
, ogg_page_serialno(&codec
->dec_og
));
370 ogg_sync_init(&codec
->dec_oy
);
371 vorbis_synthesis_init(&codec
->dec_vd
, &codec
->dec_vi
);
372 vorbis_block_init(&codec
->dec_vd
, &codec
->dec_vb
);
375 READ_CHUNK(codec
->chunk
);
381 // Assume the chunk exists by now and rely on libogg to say if it's out of
395 // Read chunks until output buffer is on or after end_position
397 while(codec
->output_position
< end_position
)
401 // Read chunk to decode if it hasn't been read yet.
404 codec
->chunk_samples
= 0;
406 READ_CHUNK(codec
->chunk
);
414 result
= ogg_sync_pageout(&codec
->dec_oy
, &codec
->dec_og
);
422 // Need more data from chunk
429 // This stage checks for OggS and a checksum error.
430 // It doesn't tell if it's the end of a chunk. Need to manually parse OggS
431 // pages to figure out how big the chunk is.
434 //printf("ogg_sync_pageout=-1\n");
439 ogg_stream_pagein(&codec
->dec_os
, &codec
->dec_og
);
445 //printf("decode 7\n");
446 result
= ogg_stream_packetout(&codec
->dec_os
, &codec
->dec_op
);
448 //printf("decode 8 %d\n", result);
451 //printf("ogg_stream_packetout=0\n");
456 // This stage doesn't check for OggS.
459 //printf("ogg_stream_packetout=-1\n");
471 if(vorbis_synthesis(&codec
->dec_vb
, &codec
->dec_op
) == 0)
473 vorbis_synthesis_blockin(&codec
->dec_vd
,
478 while((result
= vorbis_synthesis_pcmout(&codec
->dec_vd
, &pcm
)) > 0)
480 //printf("vorbis_synthesis_pcmout=%x\n", result);
481 for(i
= 0; i
< track_map
->channels
; i
++)
483 float *output_channel
= codec
->output
[i
];
484 float *input_channel
= pcm
[i
];
485 int k
= codec
->output_end
;
487 for(j
= 0; j
< result
; j
++)
489 output_channel
[k
++] = input_channel
[j
];
490 if(k
>= codec
->output_allocated
)
494 if(i
== track_map
->channels
- 1)
495 codec
->output_end
= k
;
497 //printf("codec->output_end = %d\n", codec->output_end);
499 codec
->output_position
+= result
;
500 codec
->output_size
+= result
;
501 codec
->chunk_samples
+= result
;
502 if(codec
->output_size
> codec
->output_allocated
)
503 codec
->output_size
= codec
->output_allocated
;
504 vorbis_synthesis_read(&codec
->dec_vd
, result
);
507 //printf("decode 11\n");
510 // Reset end of page so it isn't interpreted as an end of chunk
519 //printf("decode 12 got=%x\n", codec->chunk_samples);
526 while(codec
->output_position
< end_position
)
528 for(i
= 0; i
< track_map
->channels
; i
++)
529 codec
->output
[i
][codec
->output_end
] = 0;
532 if(codec
->output_end
>= codec
->output_allocated
)
533 codec
->output_end
= 0;
534 codec
->output_position
++;
536 //printf("decode 15\n");
539 //printf("decode 2 codec->output_position=%lld codec->output_end=%d codec->output_size=%d\n",
540 // codec->output_position, codec->output_end, codec->output_size);
542 current_position
= track_map
->current_position
;
543 i
= codec
->output_end
- (codec
->output_position
- current_position
);
545 while(i
< 0) i
+= codec
->output_allocated
;
546 pcm
= codec
->output
[channel
];
550 for( ; j
< samples
; j
++)
552 int sample
= pcm
[i
] * 32767;
553 CLAMP(sample
, -32768, 32767);
554 output_i
[j
] = sample
;
557 if(i
>= codec
->output_allocated
) i
= 0;
563 for( ; j
< samples
; j
++)
565 output_f
[j
] = pcm
[i
];
567 if(i
>= codec
->output_allocated
) i
= 0;
570 //printf("decode 16\n");
597 int eos = !ogg_stream_flush(&codec->enc_os, &codec->enc_og); \
603 quicktime_write_chunk_header(file, trak, &chunk_atom); \
606 result = !quicktime_write_data(file, codec->enc_og.header, codec->enc_og.header_len); \
607 size += codec->enc_og.header_len; \
611 result = !quicktime_write_data(file, codec->enc_og.body, codec->enc_og.body_len); \
612 size += codec->enc_og.body_len; \
622 while(vorbis_analysis_blockout(&codec->enc_vd, &codec->enc_vb) == 1) \
624 vorbis_analysis(&codec->enc_vb, &codec->enc_op); \
625 vorbis_bitrate_addblock(&codec->enc_vb); \
626 while(vorbis_bitrate_flushpacket(&codec->enc_vd, &codec->enc_op)) \
628 ogg_stream_packetin(&codec->enc_os, &codec->enc_op); \
632 if(!ogg_stream_pageout(&codec->enc_os, &codec->enc_og)) break; \
638 quicktime_write_chunk_header(file, trak, &chunk_atom); \
640 result = !quicktime_write_data(file, codec->enc_og.header, codec->enc_og.header_len); \
641 size += codec->enc_og.header_len; \
645 result = !quicktime_write_data(file, codec->enc_og.body, codec->enc_og.body_len); \
646 size += codec->enc_og.body_len; \
649 if(ogg_page_eos(&codec->enc_og)) break; \
655 static int encode(quicktime_t
*file
,
662 int64_t offset
= quicktime_position(file
);
663 quicktime_audio_map_t
*track_map
= &(file
->atracks
[track
]);
664 quicktime_trak_t
*trak
= track_map
->track
;
665 quicktime_vorbis_codec_t
*codec
= ((quicktime_codec_t
*)track_map
->codec
)->priv
;
666 int samplerate
= trak
->mdia
.minf
.stbl
.stsd
.table
[0].sample_rate
;
669 int chunk_started
= 0;
670 quicktime_atom_t chunk_atom
;
678 if(!codec
->encode_initialized
)
681 ogg_packet header_comm
;
682 ogg_packet header_code
;
685 codec
->encode_initialized
= 1;
687 trak
->mdia
.minf
.stbl
.stsd
.table
[0].sample_size
= 0;
688 vorbis_info_init(&codec
->enc_vi
);
692 result
= vorbis_encode_setup_managed(&codec
->enc_vi
,
696 codec
->nominal_bitrate
,
698 result
|= vorbis_encode_ctl(&codec
->enc_vi
, OV_ECTL_RATEMANAGE_AVG
, NULL
);
699 result
|= vorbis_encode_setup_init(&codec
->enc_vi
);
703 vorbis_encode_init(&codec
->enc_vi
,
707 codec
->nominal_bitrate
,
712 vorbis_comment_init(&codec
->enc_vc
);
713 vorbis_analysis_init(&codec
->enc_vd
, &codec
->enc_vi
);
714 vorbis_block_init(&codec
->enc_vd
, &codec
->enc_vb
);
716 ogg_stream_init(&codec
->enc_os
, rand());
719 vorbis_analysis_headerout(&codec
->enc_vd
,
725 ogg_stream_packetin(&codec
->enc_os
, &header
);
726 ogg_stream_packetin(&codec
->enc_os
, &header_comm
);
727 ogg_stream_packetin(&codec
->enc_os
, &header_code
);
732 output
= vorbis_analysis_buffer(&codec
->enc_vd
, samples
);
737 for(i
= 0; i
< track_map
->channels
; i
++)
739 for(j
= 0; j
< samples
; j
++)
741 output
[i
][j
] = (float)input_i
[i
][j
] / (float)32768;
749 for(i
= 0; i
< track_map
->channels
; i
++)
751 memcpy(output
[i
], input_f
[i
], sizeof(float) * samples
);
755 vorbis_analysis_wrote(&codec
->enc_vd
, samples
);
759 codec
->next_chunk_size
+= samples
;
764 int new_encoded_samples
= codec
->enc_vd
.granulepos
;
765 quicktime_write_chunk_footer(file
,
767 track_map
->current_chunk
,
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
;
781 static int set_parameter(quicktime_t
*file
,
786 quicktime_audio_map_t
*atrack
= &(file
->atracks
[track
]);
787 quicktime_vorbis_codec_t
*codec
= ((quicktime_codec_t
*)atrack
->codec
)->priv
;
790 if(!strcasecmp(key
, "vorbis_vbr"))
791 codec
->use_vbr
= *(int*)value
;
793 if(!strcasecmp(key
, "vorbis_bitrate"))
794 codec
->nominal_bitrate
= *(int*)value
;
796 if(!strcasecmp(key
, "vorbis_max_bitrate"))
797 codec
->max_bitrate
= *(int*)value
;
799 if(!strcasecmp(key
, "vorbis_min_bitrate"))
800 codec
->min_bitrate
= *(int*)value
;
805 static void flush(quicktime_t
*file
, int track
)
809 int64_t offset
= quicktime_position(file
);
810 quicktime_audio_map_t
*track_map
= &(file
->atracks
[track
]);
811 quicktime_vorbis_codec_t
*codec
= ((quicktime_codec_t
*)track_map
->codec
)->priv
;
812 long output_position
= codec
->enc_vd
.granulepos
;
813 int chunk_started
= 0;
814 quicktime_atom_t chunk_atom
;
815 quicktime_trak_t
*trak
= track_map
->track
;
817 //printf("flush 1\n");
818 vorbis_analysis_wrote(&codec
->enc_vd
,0);
822 //printf("flush 2 %d\n", size);
825 int new_encoded_samples
= codec
->enc_vd
.granulepos
;
826 quicktime_write_chunk_footer(file
,
828 track_map
->current_chunk
,
830 new_encoded_samples
- codec
->encoded_samples
);
831 track_map
->current_chunk
++;
832 codec
->next_chunk_size
= 0;
836 void quicktime_init_codec_vorbis(quicktime_audio_map_t
*atrack
)
838 quicktime_codec_t
*codec_base
= (quicktime_codec_t
*)atrack
->codec
;
839 quicktime_vorbis_codec_t
*codec
;
841 /* Init public items */
842 codec_base
->priv
= calloc(1, sizeof(quicktime_vorbis_codec_t
));
843 codec_base
->delete_acodec
= delete_codec
;
844 codec_base
->decode_audio
= decode
;
845 codec_base
->encode_audio
= encode
;
846 codec_base
->set_parameter
= set_parameter
;
847 codec_base
->flush
= flush
;
848 codec_base
->fourcc
= QUICKTIME_VORBIS
;
849 codec_base
->title
= "OGG Vorbis";
850 codec_base
->desc
= "OGG Vorbis for video. (Not standardized)";
852 codec
= codec_base
->priv
;
853 codec
->nominal_bitrate
= 128000;
854 codec
->max_bitrate
= -1;
855 codec
->min_bitrate
= -1;