2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2007 John ffitch
5 ** This program is free software ; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation ; either version 2.1 of the License, or
8 ** (at your option) any later version.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY ; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU Lesser General Public License for more details.
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program ; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #if HAVE_EXTERNAL_LIBS
43 static int ogg_close (SF_PRIVATE
*psf
) ;
44 static int ogg_stream_classify (SF_PRIVATE
*psf
, OGG_PRIVATE
* odata
) ;
45 static int ogg_page_classify (SF_PRIVATE
* psf
, const ogg_page
* og
) ;
48 ogg_open (SF_PRIVATE
*psf
)
49 { OGG_PRIVATE
* odata
= calloc (1, sizeof (OGG_PRIVATE
)) ;
50 sf_count_t pos
= psf_ftell (psf
) ;
53 psf
->container_data
= odata
;
54 psf
->container_close
= ogg_close
;
56 if (psf
->file
.mode
== SFM_RDWR
)
57 return SFE_BAD_MODE_RW
;
59 if (psf
->file
.mode
== SFM_READ
)
60 if ((error
= ogg_stream_classify (psf
, odata
)) != 0)
63 /* Reset everything to an initial state. */
64 ogg_sync_clear (&odata
->osync
) ;
65 ogg_stream_clear (&odata
->ostream
) ;
66 psf_fseek (psf
, pos
, SEEK_SET
) ;
68 switch (psf
->sf
.format
)
69 { case SF_FORMAT_OGG
| SF_FORMAT_VORBIS
:
70 return ogg_vorbis_open (psf
) ;
72 case SF_FORMAT_OGGFLAC
:
73 free (psf
->container_data
) ;
74 psf
->container_data
= NULL
;
75 psf
->container_close
= NULL
;
76 return flac_open (psf
) ;
78 #if ENABLE_EXPERIMENTAL_CODE
79 case SF_FORMAT_OGG
| SF_FORMAT_SPEEX
:
80 return ogg_speex_open (psf
) ;
82 case SF_FORMAT_OGG
| SF_FORMAT_PCM_16
:
83 case SF_FORMAT_OGG
| SF_FORMAT_PCM_24
:
84 return ogg_pcm_open (psf
) ;
91 psf_log_printf (psf
, "%s : mode should be SFM_READ or SFM_WRITE.\n", __func__
) ;
97 ogg_close (SF_PRIVATE
*psf
)
98 { OGG_PRIVATE
* odata
= psf
->container_data
;
100 ogg_sync_clear (&odata
->osync
) ;
101 ogg_stream_clear (&odata
->ostream
) ;
107 ogg_stream_classify (SF_PRIVATE
*psf
, OGG_PRIVATE
* odata
)
111 /* Call this here so it only gets called once, so no memory is leaked. */
112 ogg_sync_init (&odata
->osync
) ;
116 /* Weird stuff happens if these aren't called. */
117 ogg_stream_reset (&odata
->ostream
) ;
118 ogg_sync_reset (&odata
->osync
) ;
121 ** Grab some data at the head of the stream. We want the first page
122 ** (which is guaranteed to be small and only contain the Vorbis
123 ** stream initial header) We need the first page to get the stream
127 /* Expose the buffer */
128 buffer
= ogg_sync_buffer (&odata
->osync
, 4096L) ;
130 /* Grab the part of the header that has already been read. */
131 memcpy (buffer
, psf
->header
, psf
->headindex
) ;
132 bytes
= psf
->headindex
;
134 /* Submit a 4k block to libvorbis' Ogg layer */
135 bytes
+= psf_fread (buffer
+ psf
->headindex
, 1, 4096 - psf
->headindex
, psf
) ;
136 ogg_sync_wrote (&odata
->osync
, bytes
) ;
138 /* Get the first page. */
139 if ((nn
= ogg_sync_pageout (&odata
->osync
, &odata
->opage
)) != 1)
141 /* Have we simply run out of data? If so, we're done. */
145 /* Error case. Must not be Vorbis data */
146 psf_log_printf (psf
, "Input does not appear to be an Ogg bitstream.\n") ;
147 return SFE_MALFORMED_FILE
;
151 ** Get the serial number and set up the rest of decode.
152 ** Serialno first ; use it to set up a logical stream.
154 ogg_stream_clear (&odata
->ostream
) ;
155 ogg_stream_init (&odata
->ostream
, ogg_page_serialno (&odata
->opage
)) ;
157 if (ogg_stream_pagein (&odata
->ostream
, &odata
->opage
) < 0)
158 { /* Error ; stream version mismatch perhaps. */
159 psf_log_printf (psf
, "Error reading first page of Ogg bitstream data\n") ;
160 return SFE_MALFORMED_FILE
;
163 if (ogg_stream_packetout (&odata
->ostream
, &odata
->opacket
) != 1)
164 { /* No page? must not be vorbis. */
165 psf_log_printf (psf
, "Error reading initial header packet.\n") ;
166 return SFE_MALFORMED_FILE
;
169 odata
->codec
= ogg_page_classify (psf
, &odata
->opage
) ;
171 switch (odata
->codec
)
173 psf
->sf
.format
= SF_FORMAT_OGG
| SF_FORMAT_VORBIS
;
178 psf
->sf
.format
= SF_FORMAT_OGGFLAC
;
182 psf
->sf
.format
= SF_FORMAT_OGG
| SF_FORMAT_SPEEX
;
186 psf_log_printf (psf
, "Detected Ogg/PCM data. This is not supported yet.\n") ;
187 return SFE_UNIMPLEMENTED
;
193 psf_log_printf (psf
, "This Ogg bitstream contains some uknown data type.\n") ;
194 return SFE_UNIMPLEMENTED
;
195 } /* ogg_stream_classify */
197 /*==============================================================================
201 { const char *str
, *name
;
204 { { "Annodex", "Annodex", 8, OGG_ANNODEX
},
205 { "AnxData", "AnxData", 7, OGG_ANXDATA
},
206 { "\177FLAC", "Flac1", 5, OGG_FLAC
},
207 { "fLaC", "Flac0", 4, OGG_FLAC0
},
208 { "PCM ", "PCM", 8, OGG_PCM
},
209 { "Speex", "Speex", 5, OGG_SPEEX
},
210 { "\001vorbis", "Vorbis", 7, OGG_VORBIS
},
214 ogg_page_classify (SF_PRIVATE
* psf
, const ogg_page
* og
)
217 for (k
= 0 ; k
< ARRAY_LEN (codec_lookup
) ; k
++)
218 { if (codec_lookup
[k
].len
> og
->body_len
)
221 if (memcmp (og
->body
, codec_lookup
[k
].str
, codec_lookup
[k
].len
) == 0)
222 { psf_log_printf (psf
, "Ogg stream data : %s\n", codec_lookup
[k
].name
) ;
223 psf_log_printf (psf
, "Stream serialno : %010D\n", (int64_t) ogg_page_serialno (og
)) ;
224 return codec_lookup
[k
].codec
;
228 len
= og
->body_len
< 8 ? og
->body_len
: 8 ;
230 psf_log_printf (psf
, "Ogg_stream data : '") ;
231 for (k
= 0 ; k
< len
; k
++)
232 psf_log_printf (psf
, "%c", isprint (og
->body
[k
]) ? og
->body
[k
] : '.') ;
233 psf_log_printf (psf
, "' ") ;
234 for (k
= 0 ; k
< len
; k
++)
235 psf_log_printf (psf
, " %02x", og
->body
[k
] & 0xff) ;
236 psf_log_printf (psf
, "\n") ;
239 } /* ogg_page_classify */
241 #else /* HAVE_EXTERNAL_LIBS */
244 ogg_open (SF_PRIVATE
*psf
)
246 psf_log_printf (psf
, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
247 return SFE_UNIMPLEMENTED
;