Пример #1
0
int main( int argc, char **argv ) {

    Movie movie;
    Track track;
    Media media;
    short refNum;
    short resID = 0;
    Boolean wasChanged;
    OSErr err = noErr;
    FSSpec fsspec;
    AudioFormatAtomPtr outAudioAtom;
    CmpSoundHeader outSoundInfo;
    SoundComponentData theInputFormat,
                       theOutputFormat;
    SoundConverter mySoundConverter = NULL;
//    SCFillBufferData scFillBufferData = { NULL };
    Ptr pDecomBuffer0 = NULL,
        pDecomBuffer1 = NULL;
    long kMaxOutputBuffer = 64 * 1024;
    long noFrames = 0,
                  niFrames = 0,
                  noBytes = 0,
                  noSamples = 0;
#define MAX_BUFFER_SIZE 256 * 1024 * 1024


    /** Initialise MovieToolbox */
    EnterMovies();

    /** Open the movie file from the first argument */
    printf( "opening audio file: '%s'\n", argv[1] );
    path2fss( &fsspec, argv[1] );
    err = OpenMovieFile( &fsspec, &refNum, fsRdPerm );
    if ( err != noErr ) {
        printf( "failed to open audio: %d\n", GetMoviesError() );
        exit( -1 );
      }

    /** Instantiate the movie */
    err = NewMovieFromFile( &movie, refNum, &resID, NULL,
                            newMovieActive, &wasChanged );
    if ( err ) {
        printf( "failed to instantiate movie\n" );
        exit( -1 );
      }

    CloseMovieFile( refNum );
    refNum = 0;

    /** Get the first sound track */
    track = GetMovieIndTrackType( movie, 1, SoundMediaType,
                                  movieTrackMediaType );
    if ( track == NULL ) {
        printf( "failed to get sound track\n" );
        exit( -1 );
      }

    /** Get the sound track media */
    media = GetTrackMedia( track );
    if ( media == NULL ) {
        printf( "failed to get media from audio track\n" );
        exit( -1 );
      }

    Size size;
    Handle extension;
    SoundDescriptionHandle sourceSoundDescription;

    sourceSoundDescription = (SoundDescriptionHandle)NewHandle(0);

    /** Get the description of the sample data */
    GetMediaSampleDescription( media, 1,
                               (SampleDescriptionHandle)sourceSoundDescription );
    err = GetMoviesError();
    if ( err ) {
        printf( "failed to get description of sample data\n" );
        exit( -1 );
      }

    extension = NewHandle( 0 );

    // get the "magic" decompression atom
    // This extension to the SoundDescription information stores
    // data specific to a given audio decompressor. Some audio
    // decompression algorithms require a set of out-of-stream
    // values to configure the decompressor.
    err = 
        GetSoundDescriptionExtension( (SoundDescriptionHandle)sourceSoundDescription,
                                      &extension, siDecompressionParams );
    if ( noErr == err ) {
        size = GetHandleSize( extension );
        printf( "transferring data to audio buffer: %d bytes\n", size );
        HLock( extension );
        outAudioAtom = (AudioFormatAtom*)NewPtr( size );
        err = MemError();
        // copy the atom data to our buffer...
        BlockMoveData( *extension, outAudioAtom, size );
        HUnlock( extension );
      } else {
        // if it doesn't have an atom, that's ok
        outAudioAtom = NULL;
        err = noErr;
      }

    /** Setup our sound header */
    outSoundInfo.format = (*sourceSoundDescription)->dataFormat;
    outSoundInfo.numChannels = (*sourceSoundDescription)->numChannels;
    outSoundInfo.sampleSize = (*sourceSoundDescription)->sampleSize;
    outSoundInfo.sampleRate = (*sourceSoundDescription)->sampleRate;
    outSoundInfo.compressionID = (*sourceSoundDescription)->compressionID;

    float db = ((float)outSoundInfo.sampleRate)/(1<<16);

    printf( "sample: %d\tchannels: %d\tsample size: %d\tsample rate: %f\tcompressionID: %d\n",
            outSoundInfo.format, outSoundInfo.numChannels, outSoundInfo.sampleSize,
            db, outSoundInfo.compressionID );

    DisposeHandle( extension );
    DisposeHandle( (Handle)sourceSoundDescription );

    /** 
     * Now that we've figured out what the audio file is, allocate buffers
     * and so on for conversion and playback
     */

    printf( "initialising input/output conversion buffers\n" );

    /** setup input/output format for sound converter */
    theInputFormat.flags = 0;
    theInputFormat.format = outSoundInfo.format;
    theInputFormat.numChannels = outSoundInfo.numChannels;
    theInputFormat.sampleSize = outSoundInfo.sampleSize;
    theInputFormat.sampleRate = outSoundInfo. sampleRate;
    theInputFormat.sampleCount = 0;
    theInputFormat.buffer = NULL;
    theInputFormat.reserved = 0;

    theOutputFormat.flags = 0;
    theOutputFormat.format = kSoundNotCompressed;
    theOutputFormat.numChannels = theInputFormat.numChannels;
    theOutputFormat.sampleSize = theInputFormat.sampleSize;
    theOutputFormat.sampleRate = theInputFormat.sampleRate;
    theOutputFormat.sampleCount = 0;
    theOutputFormat.buffer = NULL;
    theOutputFormat.reserved = 0;

    // variableCompression means we're going to use the commonFrameSize field and the kExtendedSoundCommonFrameSizeValid flag
//    scFillBufferData.isSourceVBR = (outSoundInfo.compressionID == variableCompression );

    err = SoundConverterOpen( &theInputFormat, &theOutputFormat, 
                              &mySoundConverter );
    if ( err != noErr ) {
        printf( "failed to open sound converter\n" );
        exit( -1 );
      } else {
        printf( "opened sound converter ok\n" );
      }

    // this isn't crucial or even required for decompression only, but it does tell
    // the sound converter that we're cool with VBR audio
    Ptr tptr = NewPtr( 1 );
    tptr[0] = 1;
    SoundConverterSetInfo( mySoundConverter, siClientAcceptsVBR, tptr );
    free( tptr );

    /**
     * Set up the sound converters decompresson 'environment' by passing
     * in the 'magic' decompression atom
     */
    err = 
        SoundConverterSetInfo( mySoundConverter, siDecompressionParams,
                               outAudioAtom );
    if ( err != noErr ) {
        printf( "failed to set sound converter info\n" );
        exit( -1 );
      } else {
        printf( "set sound converter info ok\n" );
      }

    if ( outAudioAtom ) {
        DisposePtr( (Ptr)outAudioAtom );
      }

    if ( siUnknownInfoType == err ) {
        // clear this error, the decompressor didn't
        // need the decompression atom and that's OK
        err = noErr;
      } else {
//        BailErr(err);
      }

    /** 
     * The input buffer has to be large enough so GetMediaSample isn't
     * going to fail, your mileage may vary
     */
    Handle inputBuffer = NewHandle( MAX_BUFFER_SIZE );
//    HLock( inputBuffer );

    /** Start the sound conversion */
    err = SoundConverterBeginConversion(mySoundConverter);
//    BailErr(err);

    /** Extract compressed audio from media track */
    TimeValue tperSample = 0;
    err = 
        GetMediaSample( media, inputBuffer, 0, 
                        &noBytes, 0, NULL, &tperSample, NULL, NULL, 0, &noSamples, NULL );
    if ( err != noErr ) {
        printf( "failed to fetch media sample data: %d\n", GetMoviesError() );
        exit( -1 );
      } else {
        printf( "media sample: %d (%d) bytes / %ld samples / %d per sample\n", 
                noBytes, GetHandleSize( inputBuffer ), noSamples, tperSample );
      }

    unsigned long niBytes = 0;
    SoundConverterGetBufferSizes( mySoundConverter, noBytes * noSamples,
                                  &niFrames, &niBytes, &noBytes );

    printf( "buffer sizes: frames: %d\tibytes: %d\tobytes: %d\n",
            niFrames, niBytes, noBytes );

    /** Convert into uncompressed audio */
    Ptr outputBuffer = NewPtr( noBytes * 1.2 );
    SoundConverterConvertBuffer( mySoundConverter, inputBuffer, noSamples /* niFrames */, 
                                 outputBuffer, &noFrames, &noBytes );

    printf( "converted: %d frames / %d bytes\n", noFrames, noBytes );

    /** Shutdown the sound converter */
    err = SoundConverterEndConversion( mySoundConverter, outputBuffer, &noFrames, &noBytes );

    printf( "converted final: %d frames / %d bytes\n", noFrames, noBytes );

//    HUnlock( inputBuffer );

    /** We now should have decompressed audio for the input file */
    /** 
     * So, generate visuals using a sliding sample grid at the
     * given framerate
     */

    /** Create a new movie clip with audio and video tracks */

    /** PROJECTM CRAP HERE -- stuff frames into QuickTime */

    /** Close movie file */

    /** Shutdown MovieToolbox */
    ExitMovies();

    return 0;
  }
Пример #2
0
/*****************************************************************************
 * OpenAudio:
 *****************************************************************************/
static int OpenAudio( decoder_t *p_dec )
{
    decoder_sys_t *p_sys;

    int             i_error;
    char            fcc[4];
    unsigned long   WantedBufferSize;
    unsigned long   InputBufferSize = 0;
    unsigned long   OutputBufferSize = 0;

    /* get lock, avoid segfault */
    vlc_mutex_lock( &qt_mutex );

    p_sys = calloc( 1, sizeof( decoder_sys_t ) );
    p_dec->p_sys = p_sys;
    p_dec->pf_decode_audio = DecodeAudio;

    if( p_dec->fmt_in.i_original_fourcc )
        memcpy( fcc, &p_dec->fmt_in.i_original_fourcc, 4 );
    else
        memcpy( fcc, &p_dec->fmt_in.i_codec, 4 );

#ifdef __APPLE__
    EnterMovies();
#endif

    if( QTAudioInit( p_dec ) )
    {
        msg_Err( p_dec, "cannot initialize QT");
        goto exit_error;
    }

#ifndef __APPLE__
    if( ( i_error = p_sys->InitializeQTML( 6 + 16 ) ) )
    {
        msg_Dbg( p_dec, "error on InitializeQTML = %d", i_error );
        goto exit_error;
    }
#endif

    /* input format settings */
    p_sys->InputFormatInfo.flags       = 0;
    p_sys->InputFormatInfo.sampleCount = 0;
    p_sys->InputFormatInfo.buffer      = NULL;
    p_sys->InputFormatInfo.reserved    = 0;
    p_sys->InputFormatInfo.numChannels = p_dec->fmt_in.audio.i_channels;
    p_sys->InputFormatInfo.sampleSize  = p_dec->fmt_in.audio.i_bitspersample;
    p_sys->InputFormatInfo.sampleRate  = p_dec->fmt_in.audio.i_rate;
    p_sys->InputFormatInfo.format      = FCC( fcc[0], fcc[1], fcc[2], fcc[3] );

    /* output format settings */
    p_sys->OutputFormatInfo.flags       = 0;
    p_sys->OutputFormatInfo.sampleCount = 0;
    p_sys->OutputFormatInfo.buffer      = NULL;
    p_sys->OutputFormatInfo.reserved    = 0;
    p_sys->OutputFormatInfo.numChannels = p_dec->fmt_in.audio.i_channels;
    p_sys->OutputFormatInfo.sampleSize  = 16;
    p_sys->OutputFormatInfo.sampleRate  = p_dec->fmt_in.audio.i_rate;
    p_sys->OutputFormatInfo.format      = FCC( 'N', 'O', 'N', 'E' );


    i_error = p_sys->SoundConverterOpen( &p_sys->InputFormatInfo,
                                         &p_sys->OutputFormatInfo,
                                         &p_sys->myConverter );
    if( i_error )
    {
        msg_Err( p_dec, "error on SoundConverterOpen = %d", i_error );
        goto exit_error;
    }

#if 0
    /* tell the sound converter we accept VBR formats */
    i_error = SoundConverterSetInfo( p_dec->myConverter, siClientAcceptsVBR,
                                     (void *)true );
#endif

    if( p_dec->fmt_in.i_extra > 36 + 8 )
    {
        i_error = p_sys->SoundConverterSetInfo( p_sys->myConverter,
                                                FCC( 'w', 'a', 'v', 'e' ),
                                                ((uint8_t*)p_dec->fmt_in.p_extra) + 36 + 8 );

        msg_Dbg( p_dec, "error on SoundConverterSetInfo = %d", i_error );
    }

    WantedBufferSize = p_sys->OutputFormatInfo.numChannels *
                       p_sys->OutputFormatInfo.sampleRate * 2;
    p_sys->FramesToGet = 0;

    i_error = p_sys->SoundConverterGetBufferSizes( p_sys->myConverter,
                                                   WantedBufferSize,
                                                   &p_sys->FramesToGet,
                                                   &InputBufferSize,
                                                   &OutputBufferSize );

    msg_Dbg( p_dec, "WantedBufferSize=%li InputBufferSize=%li "
             "OutputBufferSize=%li FramesToGet=%li",
             WantedBufferSize, InputBufferSize, OutputBufferSize,
             p_sys->FramesToGet );

    p_sys->InFrameSize  = (InputBufferSize + p_sys->FramesToGet - 1 ) /
                            p_sys->FramesToGet;
    p_sys->OutFrameSize = OutputBufferSize / p_sys->FramesToGet;

    msg_Dbg( p_dec, "frame size %d -> %d",
             p_sys->InFrameSize, p_sys->OutFrameSize );

    if( (i_error = p_sys->SoundConverterBeginConversion(p_sys->myConverter)) )
    {
        msg_Err( p_dec,
                 "error on SoundConverterBeginConversion = %d", i_error );
        goto exit_error;
    }


    es_format_Init( &p_dec->fmt_out, AUDIO_ES, VLC_CODEC_S16N );
    p_dec->fmt_out.audio.i_rate = p_sys->OutputFormatInfo.sampleRate;
    p_dec->fmt_out.audio.i_channels = p_sys->OutputFormatInfo.numChannels;
    p_dec->fmt_out.audio.i_physical_channels =
    p_dec->fmt_out.audio.i_original_channels =
        pi_channels_maps[p_sys->OutputFormatInfo.numChannels];

    date_Init( &p_sys->date, p_dec->fmt_out.audio.i_rate, 1 );

    p_sys->i_buffer      = 0;
    p_sys->i_buffer_size = 100*1000;
    p_sys->p_buffer      = malloc( p_sys->i_buffer_size );
    if( !p_sys->p_buffer )
        goto exit_error;

    p_sys->i_out = 0;
    p_sys->i_out_frames = 0;

    vlc_mutex_unlock( &qt_mutex );
    return VLC_SUCCESS;

exit_error:

#ifdef LOADER
    Restore_LDT_Keeper( p_sys->ldt_fs );
#endif
    vlc_mutex_unlock( &qt_mutex );

    free( p_sys );
    return VLC_EGENERIC;
}
Пример #3
0
bool QTImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks,
                                  int *outNumTracks)
{
   OSErr err = noErr;

   //
   // Determine the file format.
   //

   // GetMediaSampleDescription takes a SampleDescriptionHandle, but apparently
   // if the media is a sound (which presumably we know it is) then it will treat
   // it as a SoundDescriptionHandle (which in addition to the format of single
   // samples, also tells you sample rate, number of channels, etc.)
   // Pretty messed up interface, if you ask me.
   SoundDescriptionHandle soundDescription = (SoundDescriptionHandle)NewHandle(0);
   GetMediaSampleDescription(mMedia, 1, (SampleDescriptionHandle)soundDescription);

   // If this is a compressed format, it may have out-of-stream compression
   // parameters that need to be passed to the sound converter.  We retrieve
   // these in the form of an audio atom.  To do this, however we have to
   // get the data by way of a handle, then copy it manually from the handle to
   // the atom.  These interfaces get worse all the time!
   Handle decompressionParamsHandle = NewHandle(0);
   AudioFormatAtomPtr decompressionParamsAtom = NULL;
   err = GetSoundDescriptionExtension(soundDescription, &decompressionParamsHandle,
                                      siDecompressionParams);
   if(err == noErr)
   {
      // this stream has decompression parameters.  copy from the handle to the atom.
      int paramsSize = GetHandleSize(decompressionParamsHandle);
      HLock(decompressionParamsHandle);
      decompressionParamsAtom = (AudioFormatAtomPtr)NewPtr(paramsSize);
      //err = MemError();
      BlockMoveData(*decompressionParamsHandle, decompressionParamsAtom, paramsSize);
      HUnlock(decompressionParamsHandle);
   }

   if(decompressionParamsHandle)
      DisposeHandle(decompressionParamsHandle);

   //
   // Now we set up a sound converter to decompress the data if it is compressed.
   //

   SoundComponentData inputFormat;
   SoundComponentData outputFormat;
   SoundConverter     soundConverter = NULL;

   inputFormat.flags       = outputFormat.flags       = 0;
   inputFormat.sampleCount = outputFormat.sampleCount = 0;
   inputFormat.reserved    = outputFormat.reserved    = 0;
   inputFormat.buffer      = outputFormat.buffer      = NULL;
   inputFormat.numChannels = outputFormat.numChannels = (*soundDescription)->numChannels;
   inputFormat.sampleSize  = outputFormat.sampleSize  = (*soundDescription)->sampleSize;
   inputFormat.sampleRate  = outputFormat.sampleRate  = (*soundDescription)->sampleRate;

   inputFormat.format = (*soundDescription)->dataFormat;
   outputFormat.format = kSoundNotCompressed;

   err = SoundConverterOpen(&inputFormat, &outputFormat, &soundConverter);

   //
   // Create the Audacity WaveTracks to house the new data
   //

   *outNumTracks = outputFormat.numChannels;
   WaveTrack **channels = new WaveTrack *[*outNumTracks];

   // determine sample format

   sampleFormat format;
   int bytesPerSample;

   // TODO: do we know for sure that 24 and 32 bit samples are the same kind
   // of 24 and 32 bit samples we expect?
   switch(outputFormat.sampleSize) {
      case 16:
         format = int16Sample;
         bytesPerSample = 2;
         break;

      case 24:
         format = int24Sample;
         bytesPerSample = 3;
         break;

      case 32:
         format = floatSample;
         bytesPerSample = 4;
         break;

      default:
         printf("I can't import a %d-bit file!\n", outputFormat.sampleSize);
         return false;
   }

   int c;
   for (c = 0; c < *outNumTracks; c++)
   {
      channels[c] = trackFactory->NewWaveTrack(format);
      channels[c]->SetRate(outputFormat.sampleRate / 65536.0);

      if(*outNumTracks == 2)
      {
         if(c == 0)
         {
            channels[c]->SetChannel(Track::LeftChannel);
            channels[c]->SetLinked(true);
         }
         else if(c == 1)
         {
            channels[c]->SetChannel(Track::RightChannel);
         }
      }
   }

   //
   // Give the converter the decompression atom.
   //

   // (judging from the sample code, it's OK if the atom is NULL, which
   // it will be if there was no decompression information)

   err = SoundConverterSetInfo(soundConverter, siDecompressionParams, decompressionParamsAtom);
   if(err == siUnknownInfoType)
   {
      // the decompressor didn't need the decompression atom, but that's ok.
      err = noErr;
   }

   // Tell the converter we're cool with VBR audio
   SoundConverterSetInfo(soundConverter, siClientAcceptsVBR, Ptr(true));

   //
   // Determine buffer sizes and allocate output buffer
   //

   int inputBufferSize = 655360;
   int outputBufferSize = 524288;
   char *outputBuffer = new char[outputBufferSize];

   //
   // Populate the structure of data that is passed to the callback
   //

   CallbackData cbData;
   memset(&cbData.compData, 0, sizeof(ExtendedSoundComponentData));

   cbData.isSourceVBR        = ((*soundDescription)->compressionID == variableCompression);
   cbData.sourceMedia        = mMedia;
   cbData.getMediaAtThisTime = 0;
   cbData.sourceDuration     = GetMediaDuration(mMedia);
   cbData.isThereMoreSource  = true;
   cbData.maxBufferSize      = inputBufferSize;

   // allocate source media buffer
   cbData.hSource            = NewHandle((long)cbData.maxBufferSize);
   MoveHHi(cbData.hSource);
   HLock(cbData.hSource);

   cbData.compData.desc = inputFormat;
   cbData.compData.desc.buffer = (BytePtr)*cbData.hSource;

   cbData.compData.desc.flags = kExtendedSoundData;
   cbData.compData.extendedFlags = kExtendedSoundBufferSizeValid |
                                   kExtendedSoundSampleCountNotValid;
   if(cbData.isSourceVBR)
      cbData.compData.extendedFlags |= kExtendedSoundCommonFrameSizeValid;

   cbData.compData.bufferSize = 0; // filled in during callback

   // this doesn't make sense to me, but it is taken from sample code
   cbData.compData.recordSize = sizeof(ExtendedSoundComponentData);


   //
   // Begin the Conversion
   //

   err = SoundConverterBeginConversion(soundConverter);

   SoundConverterFillBufferDataUPP fillBufferUPP;
   fillBufferUPP = NewSoundConverterFillBufferDataUPP(SoundConverterFillBufferCallback);

   bool done = false;
   bool cancelled = false;
   sampleCount samplesSinceLastCallback = 0;
   UInt32 outputFrames;
   UInt32 outputBytes;
   UInt32 outputFlags;

#define SAMPLES_PER_CALLBACK 10000

   while(!done && !cancelled)
   {
      err = SoundConverterFillBuffer(soundConverter,    // a sound converter
                                     fillBufferUPP,     // the callback
                                     &cbData,           // refCon passed to FillDataProc
                                     outputBuffer,      // the buffer to decompress into
                                     outputBufferSize,  // size of that buffer
                                     &outputBytes,      // number of bytes actually output
                                     &outputFrames,     // number of frames actually output
                                     &outputFlags);     // fillbuffer retured advisor flags
      if (err)
         break;

      if((outputFlags & kSoundConverterHasLeftOverData) == false)
         done = true;

      for(c = 0; c < *outNumTracks; c++)
         channels[c]->Append(outputBuffer + (c*bytesPerSample),
                             format,
                             outputFrames,
                             *outNumTracks);

      samplesSinceLastCallback += outputFrames;
      if( samplesSinceLastCallback > SAMPLES_PER_CALLBACK )
      {
         if( mProgressCallback )
            cancelled = mProgressCallback(mUserData,
                                          (float)cbData.getMediaAtThisTime /
                                          cbData.sourceDuration);
         samplesSinceLastCallback -= SAMPLES_PER_CALLBACK;
      }
   }

   HUnlock(cbData.hSource);

   // Flush any remaining data to the output buffer.
   // It appears that we have no way of telling this routine how big the output
   // buffer is!  We had better hope that there isn't more data left than
   // the buffer is big.
   SoundConverterEndConversion(soundConverter, outputBuffer, &outputFrames, &outputBytes);

   for(c = 0; c < *outNumTracks; c++)
   {
       channels[c]->Append(outputBuffer + (c*bytesPerSample),
                           format,
                           outputFrames,
                           *outNumTracks);
      channels[c]->Flush();
   }

   delete[] outputBuffer;
   DisposeHandle(cbData.hSource);
   SoundConverterClose(soundConverter);
   DisposeMovie(mMovie);

   if (cancelled || err != noErr) {
      for (c = 0; c < *outNumTracks; c++)
         delete channels[c];
      delete[] channels;

      return false;
   }
   else {
      *outTracks = new Track *[*outNumTracks];
      for(c = 0; c < *outNumTracks; c++)
         (*outTracks)[c] = channels[c];
      delete[] channels;

      return true;
   }
}