Hi Nicholas,

That was my problem you are referring to. I did manage to figure it out, but not without some hassles.

Here are the classes I'm now using (successfully).


hope this helps!
Paul



   // inherit and override the callbacks, so it will write to a vector<>
   // Note: Protected inheritance!  We want to make a different interface.
// Note2: Keeps results as a reference! so ensure the lifespan of the results exceeds the lifespan of instances of this class.
   // Note3: Assumes that we are ALWAYS dealing with signed shorts.

   class Flac_Encoder : protected FLAC::Encoder::SeekableStream, noncopyable
   {
      // keep cursor as an index
      // it doesn't invalidate when the results are resized
      ostream & results;
      ::FLAC__StreamMetadata app;
      ::FLAC__StreamMetadata* metadata_seq[1];

   public:
      struct Error : runtime_error
      {
         Error(string const& s) : runtime_error(s) {}
      };

      Flac_Encoder( unsigned int channels, string app_metadata, ostream & 
results )
         : results(results)
      {
         unsigned int bits = sizeof(short)*8;
         // do this via the C-API style, demonstrated in a test file
         metadata_seq[0] = &app;
         app.is_last = true;
         app.type = FLAC__METADATA_TYPE_APPLICATION;
         app.length = 4 + app_metadata.size();
         copy(&flac_id[0],&flac_id[4],&app.data.application.id[0]);
         app.data.application.data = new FLAC__byte[app_metadata.size()];

copy(app_metadata.begin(),app_metadata.end(),&app.data.application.data[0]);
         set_metadata(metadata_seq,1);

         set_channels(channels);
         set_bits_per_sample(bits);

         init();
      }

      // returns our results as a const-reference
      template <class It>
      void operator()( It begin, It end )
      {
         vector<FLAC__int32> samples(begin,end);
         if (!process_interleaved(&samples[0],samples.size()/get_channels()))
            throw Error("Flac_Encoder::process_interleaved() failed");
      }

      virtual ~Flac_Encoder()
      {
         finish();
      }

      // overridden functions
   protected:
      virtual ::FLAC__SeekableStreamEncoderSeekStatus
         seek_callback(FLAC__uint64 absolute_byte_offset)
         {
            try {
               results.seekp(absolute_byte_offset,ios::beg);
               return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
            }
            catch (ostream::failure & e)
            {
               return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR;
            }
         }

      virtual ::FLAC__SeekableStreamEncoderTellStatus
         tell_callback(FLAC__uint64 *absolute_byte_offset)
         {
            try {
               *absolute_byte_offset = results.tellp();
               return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
            }
            catch (ostream::failure & e)
            {
               return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR;
            }
         }

      virtual ::FLAC__StreamEncoderWriteStatus
write_callback (const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame)
         {
            try {
               results.write(reinterpret_cast<const char*>(buffer),bytes);
               return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
            }
            catch (ostream::failure & e)
            {
               return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
            }
         }
   };




   class Flac_Decoder : protected FLAC::Decoder::SeekableStream, noncopyable
   {
   public:
      string const& metadata() const { return results_metadata; }
      vector<FLAC__int32> const& samples() const { return results; }

      // call this to drop the first N samples out of the buffer
      void clear_n_samples( size_t n )
      {
         assert(results.size() >= n);
         results.erase( results.begin(), next(results.begin(),n));
      }

      Flac_Decoder( shared_ptr<istream> b ) : data(b), got_eof(false)
      {
         set_md5_checking(true);
         set_metadata_respond_all();
         init();
         process_until_end_of_metadata();
      }

      virtual ~Flac_Decoder()
      {
         finish();
      }

      bool read_frame()
      {
         return process_single();
      }

      void print_decoder_state() const
      {
         switch (get_stream_decoder_state())
         {
            case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
               log_file() << "SEARCH_FOR_METADATA" << endl;
               break;

            case FLAC__STREAM_DECODER_READ_METADATA:
               log_file() << "READ_METADATA" << endl;
               break;

            case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
               log_file() << "SEARCH_FOR_FRAME_SYNC" << endl;
               break;

            case FLAC__STREAM_DECODER_READ_FRAME:
               log_file() << "READ_FRAME" << endl;
               break;

            case FLAC__STREAM_DECODER_END_OF_STREAM:
               log_file() << "END_OF_STREAM" << endl;
               break;

            case FLAC__STREAM_DECODER_ABORTED:
               log_file() << "ABORTED" << endl;
               break;

            case FLAC__STREAM_DECODER_UNPARSEABLE_STREAM:
               log_file() << "UNPARSEABLE_STREAM" << endl;
               break;

            case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
               log_file() << "MEMORY_ALLOCATION_ERROR" << endl;
               break;

            case FLAC__STREAM_DECODER_ALREADY_INITIALIZED:
               log_file() << "ALREADY_INITIALIZED" << endl;
               break;

            case FLAC__STREAM_DECODER_INVALID_CALLBACK:
               log_file() << "INVALID_CALLBACK" << endl;
               break;

            case FLAC__STREAM_DECODER_UNINITIALIZED:
               log_file() << "UNINITIALIZED" << endl;
               break;
         }
      }

      void print_state() const
      {
         switch (get_state())
         {
            case FLAC__SEEKABLE_STREAM_DECODER_OK:
               log_file() << "OK" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:
               log_file() << "SEEKING" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
               log_file() << "END_OF_STREAM" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
               log_file() << "MEMORY_ALLOCATION_ERROR" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR:
log_file() << "SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR:
               log_file() << "READ_ERROR" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR:
               log_file() << "SEEK_ERROR" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED:
               log_file() << "ALREADY_INITIALIZED" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK:
               log_file() << "INVALID_CALLBACK" << endl;
               break;
            case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED:
               log_file() << "UNINITIALIZED" << endl;
               break;
         }
      }

      unsigned int channels() const
      {
         return get_channels();
      }

   private:
      shared_ptr<istream> data;
      vector<FLAC__int32> results;
      string results_metadata;
      bool got_eof;

   protected:
      virtual ::FLAC__SeekableStreamDecoderReadStatus
         read_callback (FLAC__byte buffer[], unsigned *bytes)
         {
            try {
               // check for EOF errors first
               if (got_eof)
                  return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
               data->read(reinterpret_cast<char*>(buffer),*bytes);
               return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
            }
            catch (istream::failure & e)
            {
               // ignore EOF-generated failures
               if (data->eof())
               {
                  got_eof = true;
                  return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
               }
               return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
            }
         }

      virtual ::FLAC__SeekableStreamDecoderSeekStatus
         seek_callback (FLAC__uint64 absolute_byte_offset)
         {
            try {
               data->seekg(absolute_byte_offset,ios::beg);
               return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
            }
            catch (istream::failure & e)
            {
               return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
            }
         }

      virtual ::FLAC__SeekableStreamDecoderTellStatus
         tell_callback (FLAC__uint64 *absolute_byte_offset)
         {
            try {
               *absolute_byte_offset = data->tellg();
               return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
            }
            catch (istream::failure & e)
            {
               return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
            }
         }

      virtual ::FLAC__SeekableStreamDecoderLengthStatus
         length_callback (FLAC__uint64 *stream_length)
         {
            try {
               streampos old = data->tellg();
               data->seekg (0, ios::end);
               *stream_length = data->tellg();
               data->seekg (old, ios::beg);
               return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
            }
            catch (istream::failure & e)
            {
               return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
            }
         }

      virtual bool eof_callback ()
      {
         return data->eof();
      }

      virtual ::FLAC__StreamDecoderWriteStatus
write_callback (const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[])
         {
            // read it back, interleaved!
            // this is more inefficient, but at the moment we expect blocks
            // to be interleaved, so we keep it that way.
            for ( unsigned int b = 0; b != frame->header.blocksize; ++b )
               for ( unsigned int c = 0; c != frame->header.channels; ++c )
                  results.push_back( buffer[c][b] );
            return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
         }

      virtual void metadata_callback (const ::FLAC__StreamMetadata *metadata)
      {
         switch (metadata->type)
         {
            case FLAC__METADATA_TYPE_APPLICATION:
               // compare the ids
               if (metadata->data.application.id[0] == flac_id[0] and
                     metadata->data.application.id[1] == flac_id[1] and
                     metadata->data.application.id[2] == flac_id[2] and
                     metadata->data.application.id[3] == flac_id[3])
               {
                  results_metadata.resize( metadata->length-4 );
copy( &metadata->data.application.data[0], &metadata->data.application.data[results_metadata.size()], &results_metadata[0] );
               }
               break;

            default: ; // do nothing
         }
      }

      virtual void error_callback ( ::FLAC__StreamDecoderErrorStatus status)
      {
         log_file() << "Error: ";
         print_state();
      }
   };




Padfield, Nicholas wrote:
I refer to a problem that appeared on the flac list last August that was
either solved off-list or abandoned.
(http://lists.xiph.org/pipermail/flac/2005-August/000468.html)

The problem is with using the C++ encoder classes, particularly the
FLAC::Encoder::File:set_metadata
function. JC said that the developers version of how to add a simple
metadata block looked right, but it did not work for him. I have tried
the same and also can not get it to work, but with a different error.

To recap... (I've left out is-valid checks in the listing for brevity)

//////////

// Create an application block
FLAC::Metadata::Application header_flac;
FLAC__byte header_flac_id[4] = { 1, 2, 3, 4 };
header_flac.set_id(header_flac_id);
header_flac.set_data((FLAC__byte*)(header_str.begin()),header_str.size()
);

// Add the block to a metadata array and pass the array to the encoder
object
FLAC::Metadata::Prototype *meta[] = { &header_flac };
set_metadata(meta, sizeof(meta) / sizeof(meta[0]));
        
// Ready to go - initialise the encoder
if(init() != ::FLAC__FILE_ENCODER_OK)
        return die("Init failed");

///////////

And this returns the following ...

FAILED, Init failed, state = 2
(FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR)
      seekable stream encoder state = 1
(FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR)
      stream encoder state = 16 (FLAC__STREAM_ENCODER_INVALID_METADATA)

I have invalid metadata! I have tried the same with VorbisComment and
Padding objects, with similar results.

Do I need to set the is_last flag for the last block in my array or does
the decoder object do that?

Any ideas about what is wrong?

Thanks
Paddy
_______________________________________________
Flac mailing list
[email protected]
http://lists.xiph.org/mailman/listinfo/flac

_______________________________________________
Flac mailing list
[email protected]
http://lists.xiph.org/mailman/listinfo/flac

Reply via email to