CLAM-Development  1.4.0
OggVorbisCodec.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #if USE_OGGVORBIS != 1
23 #error USE_OGGVORBIS was not set to 1 in your settings.cfg file, but you are including files that require this. Please fix your settings.cfg
24 #endif
25 
26 #include <cstdio>
27 #include <cstring>
28 #include <string>
29 #include <algorithm>
30 #include <vorbis/vorbisfile.h>
31 #include <iostream>
32 #include "AudioFileFormats.hxx"
33 #include "AudioFile.hxx"
34 #include "OggVorbisCodec.hxx"
35 #include "OggVorbisAudioStream.hxx"
36 
37 namespace CLAM
38 {
39 
40 namespace AudioCodecs
41 {
42  OggVorbisCodec::OggVorbisCodec()
43  {
44  }
45 
47  {
48  }
49 
51  {
52  static OggVorbisCodec theInstance;
53 
54  return theInstance;
55  }
56 
57  bool OggVorbisCodec::IsReadable( std::string uri ) const
58  {
59  FILE* fileHandle;
60  OggVorbis_File vorbisFile;
61 
62  memset( &vorbisFile, 0, sizeof(OggVorbis_File) );
63 
64  fileHandle = fopen( uri.c_str(), "rb" );
65 
66  if ( !fileHandle || ferror(fileHandle) != 0 )
67  {
68  //:TODO: possible exception throwing
69  //std::cerr << uri << std::endl;
70  //std::cerr << "Open failed! " << strerror( errno ) << std::endl;
71  return false;
72  }
73 
74  int retval = ov_open( fileHandle, &vorbisFile, NULL, 0 );
75 
76  if ( retval < 0 )
77  {
78  fclose( fileHandle );
79 
80  return false;
81  }
82 
83  // MRJ: No need to close the fileHandle since libvorbisfile takes
84  // its ownership if the ov_open call is successful
85  ov_clear( &vorbisFile );
86 
87  return true;
88 
89  }
90 
91  bool OggVorbisCodec::IsWritable( std::string uri, const AudioFileHeader& hdr ) const
92  {
93  // MRJ: These values were documented ( sort of ) in
94  // the Vorbis I specification document
95 
96  if ( (hdr.GetChannels() < 0) || ( hdr.GetChannels() > 255) )
97  return false;
98  if ( (hdr.GetSampleRate() < 8000.) || ( hdr.GetSampleRate() > 192000.) )
99  return false;
100 
101  return true;
102  }
103 
105  {
106  return new OggVorbisAudioStream(file);
107  }
108 
110  {
111  FILE* fileHandle;
112  OggVorbis_File vorbisFile;
113 
114  if ( ( fileHandle = fopen( uri.c_str(), "rb" ) ) == NULL )
115  return;
116 
117  if ( ov_open( fileHandle, &vorbisFile, NULL, 0 ) < 0 )
118  {
119  fclose( fileHandle );
120  return;
121  }
122 
123  vorbis_info* fileInfo = ov_info( &vorbisFile, -1 );
124 
125  if ( !fileInfo ) // File was encoded improperly
126  return;
127 
128  hdr.AddSampleRate();
129  hdr.AddChannels();
130  hdr.AddSamples();
131  hdr.AddFormat();
132  hdr.AddEncoding();
133  hdr.AddEndianess();
134  hdr.AddLength();
135  hdr.UpdateData();
136 
137  hdr.SetSampleRate( (TData)fileInfo->rate );
138  hdr.SetChannels( (TSize)fileInfo->channels );
139  hdr.SetLength( (TTime)ov_time_total( &vorbisFile, -1) * 1000. );
140  hdr.SetFormat( EAudioFileFormat::eVorbisMk1 );
141  hdr.SetEncoding( EAudioFileEncoding::eDefault );
142  hdr.SetEndianess( EAudioFileEndianess::eDefault );
143 
144  double duration = hdr.GetLength()/1000.;
145  hdr.SetSamples( TSize(duration*hdr.GetSampleRate()) );
146 
147  // MRJ: No need to close the fileHandle since libvorbisfile takes
148  // its ownership if the ov_open call is successful
149  ov_clear( &vorbisFile );
150  }
151 
153  {
154  FILE* fileHandle;
155  OggVorbis_File vorbisFile;
156 
157  if ( ( fileHandle = fopen( uri.c_str(), "rb" ) ) == NULL )
158  return;
159 
160  if ( ov_open( fileHandle, &vorbisFile, NULL, 0 ) < 0 )
161  {
162  fclose( fileHandle );
163  return;
164  }
165 
166  vorbis_info* fileInfo = ov_info( &vorbisFile, -1 );
167 
168  if ( !fileInfo ) // File was encoded improperly
169  return;
170 
171 
172  vorbis_comment* fileComments = ov_comment( &vorbisFile, -1 );
173 
174  if ( !fileComments ) // there were no comments in the file!
175  {
176  return;
177  }
178 
179  int nComments = fileComments->comments;
180  char** commentVector = fileComments->user_comments;
181  int* commentLenVector = fileComments->comment_lengths;
182 
183  for ( int i = 0; i < nComments; i++ )
184  {
185  // convert the current comment string into a std::string
186  std::string currentComment;
187  currentComment.assign( commentVector[i],
188  commentVector[i]+commentLenVector[i] );
189 
190  std::string::iterator eqPos = std::find( currentComment.begin(),
191  currentComment.end(), '=' );
192 
193  if ( eqPos < currentComment.end() )
194  {
195  std::string fieldName;
196  fieldName.assign( currentComment.begin(), eqPos );
197 
198  if( fieldName == "ARTIST" )
199  {
200  txtDesc.AddArtist();
201  txtDesc.UpdateData();
202  txtDesc.GetArtist().assign( eqPos+1, currentComment.end() );
203  }
204  else if ( fieldName == "TITLE" )
205  {
206  txtDesc.AddTitle();
207  txtDesc.UpdateData();
208  txtDesc.GetTitle().assign( eqPos+1, currentComment.end() );
209  }
210  else if ( fieldName == "ALBUM" )
211  {
212  txtDesc.AddAlbum();
213  txtDesc.UpdateData();
214  txtDesc.GetAlbum().assign( eqPos+1, currentComment.end() );
215  }
216  else if ( fieldName == "TRACKNUMBER" )
217  {
218  txtDesc.AddTrackNumber();
219  txtDesc.UpdateData();
220  txtDesc.GetTrackNumber().assign( eqPos+1, currentComment.end() );
221  }
222  else if ( fieldName == "PERFORMER" )
223  {
224  txtDesc.AddPerformer();
225  txtDesc.UpdateData();
226  txtDesc.GetPerformer().assign( eqPos+1, currentComment.end() );
227  }
228  else if ( fieldName == "COMPOSER" )
229  {
230  txtDesc.AddComposer();
231  txtDesc.UpdateData();
232  txtDesc.GetComposer().assign( eqPos+1, currentComment.end() );
233  }
234  else
235  {
236  std::string msg = fieldName;
237  msg+= ": Ignored comment field!";
238  //CLAM_WARNING( false, msg.c_str() );
239  }
240  }
241 
242  }
243 
244  ov_clear( &vorbisFile );
245  }
246 }
247 
248 }
249