root/src/kits/media/MediaDecoder.cpp
/***********************************************************************
 * AUTHOR: Andrew Bachmann, Marcus Overhagen
 *   FILE: MediaDecoder.cpp
 *  DESCR: 
 ***********************************************************************/
#include <MediaDecoder.h>
#include <DecoderPlugin.h>
#include <new>
#include "PluginManager.h"
#include "MediaDebug.h"

/*************************************************************
 * public BMediaDecoder
 *************************************************************/

BMediaDecoder::BMediaDecoder()
 :      fDecoder(NULL),
        fInitStatus(B_NO_INIT)
{
}


BMediaDecoder::BMediaDecoder(const media_format *in_format,
                                                         const void *info,
                                                         size_t info_size)
 :      fDecoder(NULL),
        fInitStatus(B_NO_INIT)
{
        SetTo(in_format, info, info_size);
}


BMediaDecoder::BMediaDecoder(const media_codec_info *mci)
 :      fDecoder(NULL),
        fInitStatus(B_NO_INIT)
{
        SetTo(mci);
}


/* virtual */
BMediaDecoder::~BMediaDecoder()
{
        gPluginManager.DestroyDecoder(fDecoder);
}


status_t 
BMediaDecoder::InitCheck() const
{
        return fInitStatus;
}


status_t 
BMediaDecoder::SetTo(const media_format *in_format,
                                         const void *info,
                                         size_t info_size)
{
        gPluginManager.DestroyDecoder(fDecoder);
        fDecoder = NULL;

        status_t err = gPluginManager.CreateDecoder(&fDecoder, *in_format);
        if (err < B_OK)
                goto fail;

        err = AttachToDecoder();
        if (err < B_OK)
                goto fail;

        err = SetInputFormat(in_format, info, info_size);
        if (err < B_OK)
                goto fail;

        fInitStatus = B_OK;
        return B_OK;

fail:
        gPluginManager.DestroyDecoder(fDecoder);
        fDecoder = NULL;
        fInitStatus = B_NO_INIT;
        return err;
}


status_t 
BMediaDecoder::SetTo(const media_codec_info *mci)
{
        gPluginManager.DestroyDecoder(fDecoder);
        fDecoder = NULL;

        status_t err = gPluginManager.CreateDecoder(&fDecoder, *mci);
        if (err < B_OK)
                goto fail;

        err = AttachToDecoder();
        if (err < B_OK)
                goto fail;

        fInitStatus = B_OK;
        return B_OK;

fail:
        gPluginManager.DestroyDecoder(fDecoder);
        fDecoder = NULL;
        fInitStatus = B_NO_INIT;
        return err;
}


/**     SetInputFormat() sets the input data format to in_format.
 *      Unlike SetTo(), the SetInputFormat() function does not
 *      select a codec, so the currently-selected codec will
 *      continue to be used.  You should only use SetInputFormat()
 *      to refine the format settings if it will not require the
 *      use of a different decoder.
 */

status_t 
BMediaDecoder::SetInputFormat(const media_format *in_format,
                                                          const void *in_info,
                                                          size_t in_size)
{
        if (!fDecoder)
                return B_NO_INIT;

        media_format format = *in_format;
        return fDecoder->Setup(&format, in_info, in_size);
}


/**     SetOutputFormat() sets the format the decoder should output.
 *      On return, the output_format is changed to match the actual
 *      format that will be output; this can be different if you
 *      specified any wildcards.
 */

status_t 
BMediaDecoder::SetOutputFormat(media_format *output_format)
{
        if (!fDecoder)
                return B_NO_INIT;

        return fDecoder->NegotiateOutputFormat(output_format);
}


/**     Decodes a chunk of media data into the output buffer specified
 *      by out_buffer.  On return, out_frameCount is set to indicate how
 *      many frames of data were decoded, and out_mh is the header for
 *      the decoded buffer.  The media_decode_info structure info is used
 *      on input to specify decoding parameters.
 *
 *      The amount of data decoded is part of the format determined by
 *      SetTo() or SetInputFormat().  For audio, it's the buffer_size.
 *      For video, it's one frame, which is height*row_bytes.  The data
 *      to be decoded will be fetched from the source by the decoder
 *      add-on calling the derived class' GetNextChunk() function.
 */

status_t 
BMediaDecoder::Decode(void *out_buffer, 
                                          int64 *out_frameCount,
                                          media_header *out_mh, 
                                          media_decode_info *info)
{
        if (!fDecoder)
                return B_NO_INIT;

        return fDecoder->Decode(out_buffer, out_frameCount, out_mh, info);
}


status_t 
BMediaDecoder::GetDecoderInfo(media_codec_info *out_info) const
{
        if (!fDecoder)
                return B_NO_INIT;

        return gPluginManager.GetDecoderInfo(fDecoder, out_info);
}


/*************************************************************
 * protected BMediaDecoder
 *************************************************************/


/*************************************************************
 * private BMediaDecoder
 *************************************************************/

/*
// unimplemented
BMediaDecoder::BMediaDecoder(const BMediaDecoder &);
BMediaDecoder::BMediaDecoder & operator=(const BMediaDecoder &);
*/

status_t
BMediaDecoder::AttachToDecoder()
{
        class MediaDecoderChunkProvider : public ChunkProvider {
        private:
                BMediaDecoder * fDecoder;
        public:
                MediaDecoderChunkProvider(BMediaDecoder * decoder) {
                        fDecoder = decoder;
                }
                virtual status_t GetNextChunk(const void **chunkBuffer, size_t *chunkSize,
                                              media_header *mediaHeader) {
                        return fDecoder->GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
                }
        } * provider = new(std::nothrow) MediaDecoderChunkProvider(this);
        
        if (!provider)
                return B_NO_MEMORY;
        
        fDecoder->SetChunkProvider(provider);
        return B_OK;
}


status_t BMediaDecoder::_Reserved_BMediaDecoder_0(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_1(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_2(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_3(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_4(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_5(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_6(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_7(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_8(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_9(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_10(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_11(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_12(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_13(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_14(int32 arg, ...) { return B_ERROR; }
status_t BMediaDecoder::_Reserved_BMediaDecoder_15(int32 arg, ...) { return B_ERROR; }

/*************************************************************
 * public BMediaBufferDecoder
 *************************************************************/

BMediaBufferDecoder::BMediaBufferDecoder()
 :      BMediaDecoder()
 ,      fBufferSize(0)
{
}


BMediaBufferDecoder::BMediaBufferDecoder(const media_format *in_format,
                                                                                 const void *info,
                                                                                 size_t info_size)
 :      BMediaDecoder(in_format, info, info_size)
 ,      fBufferSize(0)
{
}


BMediaBufferDecoder::BMediaBufferDecoder(const media_codec_info *mci)
 :      BMediaDecoder(mci)
 ,      fBufferSize(0)
{
}


status_t 
BMediaBufferDecoder::DecodeBuffer(const void *input_buffer, 
                                                                  size_t input_size,
                                                                  void *out_buffer, 
                                                                  int64 *out_frameCount,
                                                                  media_header *out_mh,
                                                                  media_decode_info *info)
{
        fBuffer = input_buffer;
        fBufferSize = input_size;
        return Decode(out_buffer, out_frameCount, out_mh,info);
}


/*************************************************************
 * protected BMediaBufferDecoder
 *************************************************************/

/* virtual */
status_t
BMediaBufferDecoder::GetNextChunk(const void **chunkData,
                                                                  size_t *chunkLen,
                                  media_header *mh)
{
        if (!fBufferSize)
                return B_LAST_BUFFER_ERROR;

        *chunkData = fBuffer;
        *chunkLen = fBufferSize;
        fBufferSize = 0;
        return B_OK;
}