#pragma once

#include <streams.h>
#include "../CSimpleFilter/CSimpleFilter.h"

#include "wavpack.h"

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "../lib/strmbase.lib")
#pragma comment(lib, "../lib/CSimpleFilter.lib")


static const GUID CLSID_DecodeWv = 
{ 0x9b4644d6, 0xec42, 0x4c49, { 0xbc, 0x77, 0x93, 0x82, 0x9a, 0x22, 0xc0, 0x17 } };

#define WAVE_FORMAT_WAVPACK4 0x5756
static const GUID MEDIASUBTYPE_WAVPACK4 = {WAVE_FORMAT_WAVPACK4, 0x000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };

typedef struct
{
   uint32_t block_samples;   
   uint32_t array_flags[10]; 
} common_frame_data;

typedef struct
{
   char *data;
   int pos;           
   int len;           
   int total_len;     
   uint32_t nb_block;
} frame_buffer;

frame_buffer* frame_buffer_new();
void frame_buffer_free(frame_buffer* fb);
int frame_reserve_space(frame_buffer* dst, int len);
int frame_append_data(frame_buffer* dst, char* src, int len);
int frame_append_data2(frame_buffer* dst, WavpackStreamReader *io, int len);
void frame_reset(frame_buffer* dst);
int reconstruct_wavpack_frame(frame_buffer *frame, common_frame_data *common_data, char *pSrc, uint32_t SrcLength, int is_main_frame, int several_blocks, int version);
int strip_wavpack_block(frame_buffer *frame, WavpackHeader *wphfr, WavpackStreamReader *io, uint32_t block_data_size, int is_main_frame, int several_blocks);

#define wp_alloc(__length) GlobalAlloc(GMEM_ZEROINIT, __length)
#define wp_realloc(__mem,__length) GlobalReAlloc(__mem,__length,GMEM_MOVEABLE)
#define wp_free(__dest) GlobalFree(__dest)
#define wp_memcpy(__buff1,__buff2,__length) CopyMemory(__buff1,__buff2,__length)
#define wp_memclear(__dest,__length) ZeroMemory(__dest,__length)
#define wp_memcmp(__buff1,__buff2,__length) memcmp(__buff1,__buff2,__length)

#define constrain(x,y,z) (((y) < (x)) ? (x) : ((y) > (z)) ? (z) : (y))

typedef struct
{
   WavpackStreamReader sr;
    
   char* buffer;
   uint32_t position;
   uint32_t length;
} frame_stream_reader;

typedef struct
{
   frame_stream_reader* fsr;
   frame_stream_reader* fsrc;
   WavpackContext *wpc;
   char wavpack_error_msg[512];
} wavpack_buffer_decoder;


wavpack_buffer_decoder* wavpack_buffer_decoder_new();
int wavpack_buffer_decoder_load_frame(wavpack_buffer_decoder* wbd, char* data, int length, char* correction_data, int cd_length);
uint32_t wavpack_buffer_decoder_unpack(wavpack_buffer_decoder* wbd, int32_t* buffer, uint32_t samples);
void wavpack_buffer_decoder_free(wavpack_buffer_decoder* wbd);
void wavpack_buffer_format_samples(wavpack_buffer_decoder* wbd, uchar *dst, long *src, uint32_t samples);

class CDecodeWv : public CSimpleTransform
{
public:
   DECLARE_IUNKNOWN

   
   CDecodeWv(LPUNKNOWN, HRESULT *);
   ~CDecodeWv();

   
   static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);

   
   HRESULT OnConnectInPin(const CMediaType *);
   HRESULT OnConnectOutPin(const CMediaType *, int, CMediaType *, int *);
   HRESULT OnTransform(IMediaSample *, IMediaSample *);

   
   HRESULT OnStart();
   HRESULT OnSeek();

private:

   
   WAVEFORMATEX m_outFormat;
   wavpack_buffer_decoder *m_pBufferDecoder;
   frame_buffer *m_pFrameBuffer;
   int *m_pnOutBuffer;
   int m_nDecodeVersion;
   REFERENCE_TIME m_rtCurrent;
};

