~ubuntu-branches/ubuntu/raring/flac/raring

« back to all changes in this revision

Viewing changes to src/libOggFLAC/ogg_decoder_aspect.c

  • Committer: Bazaar Package Importer
  • Author(s): Joshua Kwan
  • Date: 2007-05-29 22:56:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070529225636-ljeff8xxip09qaap
Tags: 1.1.4-1
* New upstream release. closes: #405167, #411311
  - libOggFLAC and libOggFLAC++ have been merged into libFLAC, so
    remove their corresponding packages.
  - Because of the API changes required to effect the above, there has
    been yet another soname bump. libflac7 -> libflac8 and
    libflac++5 -> libflac++6. Emails have been dispatched to the
    maintainers of dependent packages.
* Some notes on patches that were removed:
  - 02_stdin_stdout, 06_manpage_mention_utf8_convert: merged upstream
  - 08_manpage_warnings: Upstream has changed the manpage so it defintely
    can't fit in in 80 cols, so just forget about it. We'll live.
  - 05_eof_warnings_are_errors: Upstream decided to add a -w option to
    flac to treat all warnings as errors. I am going to defer to that
    for now, but if people think it's stupid let me know and I'll port
    the patch forward.
  - 04_stack_smasher: was a backport from 1.1.3, so it's obsolete.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* libOggFLAC - Free Lossless Audio Codec + Ogg library
2
 
 * Copyright (C) 2002,2003,2004,2005  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
 
#include <string.h> /* for memcpy() */
33
 
#include "FLAC/assert.h"
34
 
#include "private/ogg_decoder_aspect.h"
35
 
#include "private/ogg_mapping.h"
36
 
 
37
 
#ifdef max
38
 
#undef max
39
 
#endif
40
 
#define max(x,y) ((x)>(y)?(x):(y))
41
 
 
42
 
/***********************************************************************
43
 
 *
44
 
 * Public class methods
45
 
 *
46
 
 ***********************************************************************/
47
 
 
48
 
FLAC__bool OggFLAC__ogg_decoder_aspect_init(OggFLAC__OggDecoderAspect *aspect)
49
 
{
50
 
        /* we will determine the serial number later if necessary */
51
 
        if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
52
 
                return false;
53
 
 
54
 
        if(ogg_sync_init(&aspect->sync_state) != 0)
55
 
                return false;
56
 
 
57
 
        aspect->version_major = ~(0u);
58
 
        aspect->version_minor = ~(0u);
59
 
 
60
 
        aspect->need_serial_number = aspect->use_first_serial_number;
61
 
 
62
 
        aspect->end_of_stream = false;
63
 
        aspect->have_working_page = false;
64
 
 
65
 
        return true;
66
 
}
67
 
 
68
 
void OggFLAC__ogg_decoder_aspect_finish(OggFLAC__OggDecoderAspect *aspect)
69
 
{
70
 
        (void)ogg_sync_clear(&aspect->sync_state);
71
 
        (void)ogg_stream_clear(&aspect->stream_state);
72
 
}
73
 
 
74
 
void OggFLAC__ogg_decoder_aspect_set_serial_number(OggFLAC__OggDecoderAspect *aspect, long value)
75
 
{
76
 
        aspect->use_first_serial_number = false;
77
 
        aspect->serial_number = value;
78
 
}
79
 
 
80
 
void OggFLAC__ogg_decoder_aspect_set_defaults(OggFLAC__OggDecoderAspect *aspect)
81
 
{
82
 
        aspect->use_first_serial_number = true;
83
 
}
84
 
 
85
 
void OggFLAC__ogg_decoder_aspect_flush(OggFLAC__OggDecoderAspect *aspect)
86
 
{
87
 
        (void)ogg_stream_reset(&aspect->stream_state);
88
 
        (void)ogg_sync_reset(&aspect->sync_state);
89
 
        aspect->end_of_stream = false;
90
 
        aspect->have_working_page = false;
91
 
}
92
 
 
93
 
void OggFLAC__ogg_decoder_aspect_reset(OggFLAC__OggDecoderAspect *aspect)
94
 
{
95
 
        OggFLAC__ogg_decoder_aspect_flush(aspect);
96
 
 
97
 
        if(aspect->use_first_serial_number)
98
 
                aspect->need_serial_number = true;
99
 
}
100
 
 
101
 
OggFLAC__OggDecoderAspectReadStatus OggFLAC__ogg_decoder_aspect_read_callback_wrapper(OggFLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], unsigned *bytes, OggFLAC__OggDecoderAspectReadCallbackProxy read_callback, void *decoder, void *client_data)
102
 
{
103
 
        static const unsigned OGG_BYTES_CHUNK = 8192;
104
 
        const unsigned bytes_requested = *bytes;
105
 
 
106
 
        /*
107
 
         * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
108
 
         * is push-based.  In libFLAC, when you ask to decode a frame, the
109
 
         * decoder will eventually call the read callback to supply some data,
110
 
         * but how much it asks for depends on how much free space it has in
111
 
         * its internal buffer.  It does not try to grow its internal buffer
112
 
         * to accomodate a whole frame because then the internal buffer size
113
 
         * could not be limited, which is necessary in embedded applications.
114
 
         *
115
 
         * Ogg however grows its internal buffer until a whole page is present;
116
 
         * only then can you get decoded data out.  So we can't just ask for
117
 
         * the same number of bytes from Ogg, then pass what's decoded down to
118
 
         * libFLAC.  If what libFLAC is asking for will not contain a whole
119
 
         * page, then we will get no data from ogg_sync_pageout(), and at the
120
 
         * same time cannot just read more data from the client for the purpose
121
 
         * of getting a whole decoded page because the decoded size might be
122
 
         * larger than libFLAC's internal buffer.
123
 
         *
124
 
         * Instead, whenever this read callback wrapper is called, we will
125
 
         * continually request data from the client until we have at least one
126
 
         * page, and manage pages internally so that we can send pieces of
127
 
         * pages down to libFLAC in such a way that we obey its size
128
 
         * requirement.  To limit the amount of callbacks, we will always try
129
 
         * to read in enough pages to return the full number of bytes
130
 
         * requested.
131
 
         */
132
 
        *bytes = 0;
133
 
        while (*bytes < bytes_requested && !aspect->end_of_stream) {
134
 
                if (aspect->have_working_page) {
135
 
                        if (aspect->have_working_packet) {
136
 
                                unsigned n = bytes_requested - *bytes;
137
 
                                if ((unsigned)aspect->working_packet.bytes <= n) {
138
 
                                        /* the rest of the packet will fit in the buffer */
139
 
                                        n = aspect->working_packet.bytes;
140
 
                                        memcpy(buffer, aspect->working_packet.packet, n);
141
 
                                        *bytes += n;
142
 
                                        buffer += n;
143
 
                                        aspect->have_working_packet = false;
144
 
                                }
145
 
                                else {
146
 
                                        /* only n bytes of the packet will fit in the buffer */
147
 
                                        memcpy(buffer, aspect->working_packet.packet, n);
148
 
                                        *bytes += n;
149
 
                                        buffer += n;
150
 
                                        aspect->working_packet.packet += n;
151
 
                                        aspect->working_packet.bytes -= n;
152
 
                                }
153
 
                        }
154
 
                        else {
155
 
                                /* try and get another packet */
156
 
                                const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
157
 
                                if (ret > 0) {
158
 
                                        aspect->have_working_packet = true;
159
 
                                        /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
160
 
                                        if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == OggFLAC__MAPPING_FIRST_HEADER_PACKET_TYPE) {
161
 
                                                const FLAC__byte *b = aspect->working_packet.packet;
162
 
                                                const unsigned header_length =
163
 
                                                        OggFLAC__MAPPING_PACKET_TYPE_LENGTH +
164
 
                                                        OggFLAC__MAPPING_MAGIC_LENGTH +
165
 
                                                        OggFLAC__MAPPING_VERSION_MAJOR_LENGTH +
166
 
                                                        OggFLAC__MAPPING_VERSION_MINOR_LENGTH +
167
 
                                                        OggFLAC__MAPPING_NUM_HEADERS_LENGTH;
168
 
                                                if (aspect->working_packet.bytes < (long)header_length)
169
 
                                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
170
 
                                                b += OggFLAC__MAPPING_PACKET_TYPE_LENGTH;
171
 
                                                if (memcmp(b, OggFLAC__MAPPING_MAGIC, OggFLAC__MAPPING_MAGIC_LENGTH))
172
 
                                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
173
 
                                                b += OggFLAC__MAPPING_MAGIC_LENGTH;
174
 
                                                aspect->version_major = (unsigned)(*b);
175
 
                                                b += OggFLAC__MAPPING_VERSION_MAJOR_LENGTH;
176
 
                                                aspect->version_minor = (unsigned)(*b);
177
 
                                                if (aspect->version_major != 1)
178
 
                                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
179
 
                                                aspect->working_packet.packet += header_length;
180
 
                                                aspect->working_packet.bytes -= header_length;
181
 
                                        }
182
 
                                }
183
 
                                else if (ret == 0) {
184
 
                                        aspect->have_working_page = false;
185
 
                                }
186
 
                                else { /* ret < 0 */
187
 
                                        /* lost sync, we'll leave the working page for the next call */
188
 
                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
189
 
                                }
190
 
                        }
191
 
                }
192
 
                else {
193
 
                        /* try and get another page */
194
 
                        const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
195
 
                        if (ret > 0) {
196
 
                                /* got a page, grab the serial number if necessary */
197
 
                                if(aspect->need_serial_number) {
198
 
                                        aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
199
 
                                        aspect->need_serial_number = false;
200
 
                                }
201
 
                                if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
202
 
                                        aspect->have_working_page = true;
203
 
                                        aspect->have_working_packet = false;
204
 
                                }
205
 
                                /* else do nothing, could be a page from another stream */
206
 
                        }
207
 
                        else if (ret == 0) {
208
 
                                /* need more data */
209
 
                                const unsigned ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
210
 
                                char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
211
 
 
212
 
                                if(0 == oggbuf) {
213
 
                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
214
 
                                }
215
 
                                else {
216
 
                                        unsigned ogg_bytes_read = ogg_bytes_to_read;
217
 
 
218
 
                                        switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
219
 
                                                case OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
220
 
                                                        break;
221
 
                                                case OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
222
 
                                                        aspect->end_of_stream = true;
223
 
                                                        break;
224
 
                                                case OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
225
 
                                                        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
226
 
                                                default:
227
 
                                                        FLAC__ASSERT(0);
228
 
                                        }
229
 
 
230
 
                                        if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
231
 
                                                /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
232
 
                                                FLAC__ASSERT(0);
233
 
                                                return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
234
 
                                        }
235
 
                                }
236
 
                        }
237
 
                        else { /* ret < 0 */
238
 
                                /* lost sync, bail out */
239
 
                                return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
240
 
                        }
241
 
                }
242
 
        }
243
 
 
244
 
        if (aspect->end_of_stream && *bytes == 0) {
245
 
                return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
246
 
        }
247
 
 
248
 
        return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
249
 
}