FLACEncodeInputPin.cpp

Go to the documentation of this file.
00001 //===========================================================================
00002 //Copyright (C) 2003, 2004 Zentaro Kavanagh
00003 //
00004 //Redistribution and use in source and binary forms, with or without
00005 //modification, are permitted provided that the following conditions
00006 //are met:
00007 //
00008 //- Redistributions of source code must retain the above copyright
00009 //  notice, this list of conditions and the following disclaimer.
00010 //
00011 //- Redistributions in binary form must reproduce the above copyright
00012 //  notice, this list of conditions and the following disclaimer in the
00013 //  documentation and/or other materials provided with the distribution.
00014 //
00015 //- Neither the name of Zentaro Kavanagh nor the names of contributors 
00016 //  may be used to endorse or promote products derived from this software 
00017 //  without specific prior written permission.
00018 //
00019 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00022 //PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00023 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00024 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00025 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00026 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00027 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00028 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 //===========================================================================
00031 
00032 #include "stdafx.h"
00033 #include "FLACencodeinputpin.h"
00034 
00035 FLACEncodeInputPin::FLACEncodeInputPin(AbstractTransformFilter* inParentFilter, CCritSec* inFilterLock, AbstractTransformOutputPin* inOutputPin, vector<CMediaType*> inAcceptableMediaTypes)
00036         :       AbstractTransformInputPin(inParentFilter, inFilterLock, inOutputPin, NAME("FLACEncodeInputPin"), L"PCM In", inAcceptableMediaTypes)
00037         ,       mTweakedHeaders(false)
00038         ,       mBegun(false)
00039         ,       mWaveFormat(NULL)
00040         ,       mUptoFrame(0)
00041         
00042         
00043 {
00044         //debugLog.open("G:\\logs\\FLACenc.log", ios_base::out);
00045 }
00046 
00047 FLACEncodeInputPin::~FLACEncodeInputPin(void)
00048 {
00049         //debugLog.close();
00050         DestroyCodec();
00051 }
00052 
00053 
00054 //PURE VIRTUALS
00055 HRESULT FLACEncodeInputPin::TransformData(unsigned char* inBuf, long inNumBytes) {
00056 
00057         if (mBegun == false) {
00058 
00059                 //First bit of data, set up the encoder.
00060                 mBegun = true;
00061                 init();
00062         }
00063         FLAC__int32* locFLACBuff = NULL;
00064         FLACEncodeFilter* locParentFilter = (FLACEncodeFilter*)mParentFilter;   //View only don't delete.
00065         unsigned long locFLACBuffSize = (inNumBytes * 8) / locParentFilter->mFLACFormatBlock.numBitsPerSample;
00066         unsigned long locNumSamplesPerChannel = locFLACBuffSize / locParentFilter->mFLACFormatBlock.numChannels;
00067 
00068         locFLACBuff = new FLAC__int32[locFLACBuffSize];
00069 
00070         //QUERY::: Are the flac buffers supposed to stretch the data to 32 bits ?
00071         //Assuming No for now, otherwise whats the point of set_sample_size.
00072 
00073         //POTENTIAL BUG::: This assumes 16 bit samples !!
00074 
00075         short locTempShort = 0;
00076         for (int i = 0; i < inNumBytes; i += 2) {
00077                 locTempShort = *((short*)(inBuf + i));
00078                 locFLACBuff[i/2] = locTempShort;
00079         }
00080 
00081         bool locRetVal = process_interleaved(locFLACBuff, locNumSamplesPerChannel);
00082 
00083         if (locRetVal == true) {
00084                 return 0;
00085         } else {
00086                 return -1;
00087         }
00088 
00089 }
00090 bool FLACEncodeInputPin::ConstructCodec() 
00091 {
00092 
00093         set_channels(mWaveFormat->nChannels);
00094         set_sample_rate(mWaveFormat->nSamplesPerSec);
00095         set_bits_per_sample(mWaveFormat->wBitsPerSample);
00096 
00097         FLACEncodeFilter* locParentFilter = (FLACEncodeFilter*)mParentFilter;   //View only don't delete.
00098         locParentFilter->mFLACFormatBlock.numBitsPerSample = mWaveFormat->wBitsPerSample;
00099         locParentFilter->mFLACFormatBlock.numChannels = mWaveFormat->nChannels;
00100         locParentFilter->mFLACFormatBlock.sampleRate = mWaveFormat->nSamplesPerSec;
00101         
00102         //This can't be here, it causes callbacks to fire, and the data can't be delivered
00103         // because the filter is not fully set up yet.
00104         //init();
00105 
00107         return true;
00108 }
00109 void FLACEncodeInputPin::DestroyCodec()
00110 {
00111 
00112         //Should there be some cleanup function ??
00113 }
00114 
00115 
00116 
00117 
00118 ::FLAC__StreamEncoderWriteStatus FLACEncodeInputPin::write_callback(const FLAC__byte inBuffer[], unsigned inNumBytes, unsigned inNumSamples, unsigned inCurrentFrame) {
00119 
00120         //This is called back with encoded data after raw data is fed in by stream_encoder_process or
00121         // stream_encoder_process_interleaved.
00122 
00123 
00124         //debugLog<<"Write CAllback.."<<endl;
00125         LONGLONG locFrameStart = 0;
00126         LONGLONG locFrameEnd = 0;
00127 
00128 
00129         if (!mTweakedHeaders) {
00130                 //debugLog<<"Still tweaking headers..."<<endl;
00131                 //Still handling headers...
00132                 unsigned char* locBuf = new unsigned char[inNumBytes];
00133                 memcpy((void*)locBuf, (const void*) inBuffer, inNumBytes);
00134                 //debugLog<<"Sending header to tweaker..."<<endl;
00135                 FLACHeaderTweaker::eFLACAcceptHeaderResult locResult = mHeaderTweaker.acceptHeader(new OggPacket(locBuf, inNumBytes, false, false));
00136                 //debugLog<<"Tweaker returned... "<<(int)locResult<<endl;
00137                 if (locResult == FLACHeaderTweaker::LAST_HEADER_ACCEPTED) {
00138                         //debugLog<<"Last Header accepted..."<<endl;
00139                         //Send all the headers
00140                         mTweakedHeaders = true;
00141 
00142                         for (unsigned long i = 0; i < mHeaderTweaker.numNewHeaders(); i++) {
00143                                 //Loop through firing out all the headers.
00144                                 //debugLog<<"Sending new header "<<i<<endl;
00145 
00146                                 //Get a pointer to a new sample stamped with our time
00147                                 IMediaSample* locSample;
00148                                 HRESULT locHR = mOutputPin->GetDeliveryBuffer(&locSample, NULL, NULL, NULL);
00149 
00150                                 if (FAILED(locHR)) {
00151                                         //We get here when the application goes into stop mode usually.
00152                                         //locThis->debugLog<<"Getting buffer failed"<<endl;
00153                                         return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
00154                                 }       
00155                                 
00156                                 BYTE* locBuffer = NULL;
00157 
00158                                 //Make our pointers set to point to the samples buffer
00159                                 locSample->GetPointer(&locBuffer);
00160 
00161                                 memcpy((void*)locBuffer, (const void*)mHeaderTweaker.getHeader(i)->packetData(), mHeaderTweaker.getHeader(i)->packetSize());
00162                                 
00163                                 //Set the sample parameters. (stamps will be 0)
00164                                 SetSampleParams(locSample, mHeaderTweaker.getHeader(i)->packetSize(), &locFrameStart, &locFrameEnd);
00165 
00166                                 {
00167                                         CAutoLock locLock(m_pLock);
00168 
00169                                         
00170                                         HRESULT locHR = ((FLACEncodeOutputPin*)(mOutputPin))->mDataQueue->Receive(locSample);                                           //->DownstreamFilter()->Receive(locSample);
00171                                         if (locHR != S_OK) {
00172                                                 //debugLog<<"Sample rejected"<<endl;
00173                                         } else {
00174                                                 //debugLog<<"Sample Delivered"<<endl;
00175                                         }
00176                                 }
00177 
00178                                 
00179 
00180 
00181                         }
00182 
00183                         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
00184                 } else if (locResult == FLACHeaderTweaker::HEADER_ACCEPTED) {
00185                         //Another header added.
00186                         //debugLog<<"Header accepted"<<endl;
00187                         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
00188                 } else {
00189                         //debugLog<<"Header failed..."<<endl;
00190                         return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
00191                 }
00192 
00193         }
00194 
00195         locFrameStart = mUptoFrame;
00196         if (inNumSamples != 0) {
00197                 mUptoFrame += inNumSamples;
00198         }
00199         locFrameEnd = mUptoFrame;
00200 
00201 
00202         //Get a pointer to a new sample stamped with our time
00203         IMediaSample* locSample;
00204         HRESULT locHR = mOutputPin->GetDeliveryBuffer(&locSample, &locFrameStart, &locFrameEnd, NULL);
00205 
00206         if (FAILED(locHR)) {
00207                 //We get here when the application goes into stop mode usually.
00208                 //locThis->debugLog<<"Getting buffer failed"<<endl;
00209                 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
00210         }       
00211         
00212         BYTE* locBuffer = NULL;
00213 
00214         //Make our pointers set to point to the samples buffer
00215         locSample->GetPointer(&locBuffer);
00216 
00217         //**** WARNING 4018::: Leave this alone.
00218         if (locSample->GetSize() >= inNumBytes) {
00219 
00220                 memcpy((void*)locBuffer, (const void*)inBuffer, inNumBytes);
00221                 
00222                 //Set the sample parameters.
00223                 SetSampleParams(locSample, inNumBytes, &locFrameStart, &locFrameEnd);
00224 
00225                 {
00226                         CAutoLock locLock(m_pLock);
00227 
00228                         
00229                         HRESULT locHR = ((FLACEncodeOutputPin*)(mOutputPin))->mDataQueue->Receive(locSample);                                           //->DownstreamFilter()->Receive(locSample);
00230                         if (locHR != S_OK) {
00231                                 //locThis->debugLog<<"Sample rejected"<<endl;
00232                         } else {
00233                                 //locThis->debugLog<<"Sample Delivered"<<endl;
00234                         }
00235                 }
00236 
00237                 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
00238         } else {
00239                 throw 0;
00240         }
00241 
00242 
00243 }
00244 void FLACEncodeInputPin::metadata_callback(const ::FLAC__StreamMetadata *metadata) 
00245 {
00246 
00247         //Ignore it.
00248 }
00249 
00250 STDMETHODIMP FLACEncodeInputPin::EndOfStream(void) {
00251         //Catch the end of stream so we can send a finish signal.
00252         finish();                       //Tell flac we are done so it can flush
00253         return AbstractTransformInputPin::EndOfStream();                //Call the base class.
00254 }
00255 
00256 HRESULT FLACEncodeInputPin::SetMediaType(const CMediaType* inMediaType) 
00257 {
00258 
00259         if (    (inMediaType->subtype == MEDIASUBTYPE_PCM) &&
00260                         (inMediaType->formattype == FORMAT_WaveFormatEx)) {
00261 
00262                 mWaveFormat = (WAVEFORMATEX*)inMediaType->pbFormat;
00263                 
00264         } else {
00265                 //Failed... should never be here !
00266                 throw 0;
00267         }
00268         //This is here and not the constructor because we need audio params from the
00269         // input pin to construct properly.     
00270         
00271         ConstructCodec();
00272 
00273         return CBaseInputPin::SetMediaType(inMediaType);
00274 
00275 }

Generated on Tue Feb 15 14:54:15 2005 for oggdsf by  doxygen 1.3.9