Mercurial > audlegacy-plugins
comparison src/flac/libflac/ogg_encoder_aspect.c @ 722:454ad11020ec trunk
[svn] * Delete flac112
* Rename flac113 -> flac
* Change configure.ac
author | js |
---|---|
date | Sat, 24 Feb 2007 16:17:26 -0800 |
parents | src/flac113/libflac/ogg_encoder_aspect.c@a9b178bc4ae4 |
children |
comparison
equal
deleted
inserted
replaced
721:574de61036a3 | 722:454ad11020ec |
---|---|
1 /* libFLAC - Free Lossless Audio Codec | |
2 * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
8 * - Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * | |
11 * - Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * | |
15 * - Neither the name of the Xiph.org Foundation nor the names of its | |
16 * contributors may be used to endorse or promote products derived from | |
17 * this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR | |
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 */ | |
31 | |
32 #if HAVE_CONFIG_H | |
33 # include <config.h> | |
34 #endif | |
35 | |
36 #include <string.h> /* for memset() */ | |
37 #include "FLAC/assert.h" | |
38 #include "private/ogg_encoder_aspect.h" | |
39 #include "private/ogg_mapping.h" | |
40 | |
41 static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1; | |
42 static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0; | |
43 | |
44 /*********************************************************************** | |
45 * | |
46 * Public class methods | |
47 * | |
48 ***********************************************************************/ | |
49 | |
50 FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect) | |
51 { | |
52 /* we will determine the serial number later if necessary */ | |
53 if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0) | |
54 return false; | |
55 | |
56 aspect->seen_magic = false; | |
57 aspect->is_first_packet = true; | |
58 aspect->samples_written = 0; | |
59 | |
60 return true; | |
61 } | |
62 | |
63 void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect) | |
64 { | |
65 (void)ogg_stream_clear(&aspect->stream_state); | |
66 /*@@@ what about the page? */ | |
67 } | |
68 | |
69 void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value) | |
70 { | |
71 aspect->serial_number = value; | |
72 } | |
73 | |
74 FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value) | |
75 { | |
76 if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) { | |
77 aspect->num_metadata = value; | |
78 return true; | |
79 } | |
80 else | |
81 return false; | |
82 } | |
83 | |
84 void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect) | |
85 { | |
86 aspect->serial_number = 0; | |
87 aspect->num_metadata = 0; | |
88 } | |
89 | |
90 /* | |
91 * The basic FLAC -> Ogg mapping goes like this: | |
92 * | |
93 * - 'fLaC' magic and STREAMINFO block get combined into the first | |
94 * packet. The packet is prefixed with | |
95 * + the one-byte packet type 0x7F | |
96 * + 'FLAC' magic | |
97 * + the 2 byte Ogg FLAC mapping version number | |
98 * + tne 2 byte big-endian # of header packets | |
99 * - The first packet is flushed to the first page. | |
100 * - Each subsequent metadata block goes into its own packet. | |
101 * - Each metadata packet is flushed to page (this is not required, | |
102 * the mapping only requires that a flush must occur after all | |
103 * metadata is written). | |
104 * - Each subsequent FLAC audio frame goes into its own packet. | |
105 * | |
106 * WATCHOUT: | |
107 * This depends on the behavior of FLAC__StreamEncoder that we get a | |
108 * separate write callback for the fLaC magic, and then separate write | |
109 * callbacks for each metadata block and audio frame. | |
110 */ | |
111 FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data) | |
112 { | |
113 /* WATCHOUT: | |
114 * This depends on the behavior of FLAC__StreamEncoder that 'samples' | |
115 * will be 0 for metadata writes. | |
116 */ | |
117 const FLAC__bool is_metadata = (samples == 0); | |
118 | |
119 /* | |
120 * Treat fLaC magic packet specially. We will note when we see it, then | |
121 * wait until we get the STREAMINFO and prepend it in that packet | |
122 */ | |
123 if(aspect->seen_magic) { | |
124 ogg_packet packet; | |
125 FLAC__byte synthetic_first_packet_body[ | |
126 FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + | |
127 FLAC__OGG_MAPPING_MAGIC_LENGTH + | |
128 FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + | |
129 FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + | |
130 FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + | |
131 FLAC__STREAM_SYNC_LENGTH + | |
132 FLAC__STREAM_METADATA_HEADER_LENGTH + | |
133 FLAC__STREAM_METADATA_STREAMINFO_LENGTH | |
134 ]; | |
135 | |
136 memset(&packet, 0, sizeof(packet)); | |
137 packet.granulepos = aspect->samples_written + samples; | |
138 | |
139 if(aspect->is_first_packet) { | |
140 FLAC__byte *b = synthetic_first_packet_body; | |
141 if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) { | |
142 /* | |
143 * If we get here, our assumption about the way write callbacks happen | |
144 * (explained above) is wrong | |
145 */ | |
146 FLAC__ASSERT(0); | |
147 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
148 } | |
149 /* add first header packet type */ | |
150 *b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; | |
151 b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; | |
152 /* add 'FLAC' mapping magic */ | |
153 memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH); | |
154 b += FLAC__OGG_MAPPING_MAGIC_LENGTH; | |
155 /* add Ogg FLAC mapping major version number */ | |
156 memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH); | |
157 b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; | |
158 /* add Ogg FLAC mapping minor version number */ | |
159 memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH); | |
160 b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH; | |
161 /* add number of header packets */ | |
162 *b = (FLAC__byte)(aspect->num_metadata >> 8); | |
163 b++; | |
164 *b = (FLAC__byte)(aspect->num_metadata); | |
165 b++; | |
166 /* add native FLAC 'fLaC' magic */ | |
167 memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH); | |
168 b += FLAC__STREAM_SYNC_LENGTH; | |
169 /* add STREAMINFO */ | |
170 memcpy(b, buffer, bytes); | |
171 FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body)); | |
172 packet.packet = (unsigned char *)synthetic_first_packet_body; | |
173 packet.bytes = sizeof(synthetic_first_packet_body); | |
174 | |
175 packet.b_o_s = 1; | |
176 aspect->is_first_packet = false; | |
177 } | |
178 else { | |
179 packet.packet = (unsigned char *)buffer; | |
180 packet.bytes = bytes; | |
181 } | |
182 | |
183 if(is_last_block) { | |
184 /* we used to check: | |
185 * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples); | |
186 * but it's really not useful since total_samples_estimate is an estimate and can be inexact | |
187 */ | |
188 packet.e_o_s = 1; | |
189 } | |
190 | |
191 if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0) | |
192 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
193 | |
194 /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */ | |
195 if(is_metadata) { | |
196 while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) { | |
197 if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) | |
198 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
199 if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) | |
200 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
201 } | |
202 } | |
203 else { | |
204 while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) { | |
205 if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) | |
206 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
207 if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) | |
208 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
209 } | |
210 } | |
211 } | |
212 else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) { | |
213 aspect->seen_magic = true; | |
214 } | |
215 else { | |
216 /* | |
217 * If we get here, our assumption about the way write callbacks happen | |
218 * explained above is wrong | |
219 */ | |
220 FLAC__ASSERT(0); | |
221 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |
222 } | |
223 | |
224 aspect->samples_written += samples; | |
225 | |
226 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; | |
227 } |