#ifndef _EUTERPE_FFMPEG_AUDIO_INPUT_H_
#define _EUTERPE_FFMPEG_AUDIO_INPUT_H_

//#include "euterpe/plugin_interfaces.h"

//#define WDL_RESAMPLE_TYPE SAM

#include "euterpe_gen/ffmpeg_glue.h"
#include "euterpe/euterpe_plugin_public.h"
#include "WDL/wdlstring.h"
#include "WDL/heapbuf.h"
#include "WDL/queue.h"
#include "WDL/resample.h"

extern double (*GetHardwareSampleRate)();
extern int (*GetResamplerSinc)();

struct CodecInfo
{
  int stream_index;
  AVStream *stream;
  AVCodec *codec;
};

struct ScopedContext
{
  AVCodecContext *ptr;

  AVCodecContext *operator->()
  {
    return ptr;
  }

  ScopedContext(const CodecInfo *codec_info)
    : ptr(NULL)
  {
    ptr = avcodec_alloc_context3(codec_info->codec);
    avcodec_parameters_to_context(ptr, codec_info->stream->codecpar);
    //ptr->sample_rate = codec_info->stream->codecpar->sample_rate;
    //ptr->channels = codec_info->stream->codecpar->channels;
    //ptr->channel_layout = codec_info->stream->codecpar->channel_layout;
  }

  ~ScopedContext()
  {
    avcodec_free_context(&ptr);
  }
};

struct ScopedPacket : public AVPacket
{
  ScopedPacket()
    : AVPacket()
  {
    av_init_packet(this);
    this->data = NULL;
    this->size = 0;
  }

  ~ScopedPacket()
  {
    av_packet_unref(this);
  }
};

struct ScopedFrame
{
  AVFrame *ptr;

  AVFrame *operator->()
  {
    return ptr;
  }

  ScopedFrame()
    : ptr(NULL)
  {
    ptr = av_frame_alloc();
  }

  ~ScopedFrame()
  {
    av_frame_free(&ptr);
    //av_frame_unref(ptr);
  }
};

class RSE_FFmpegInput : public RSE_IFileInput
{
public:
  RSE_FFmpegInput();
  ~RSE_FFmpegInput();

  bool Open(const char *filename);

  const char *GetType();

  const char *GetFileName();

  int GetChannels();

  double GetSampleRate();

  double GetLength();

  int GetBitsPerSample();

  double GetPosition();

  void Seek(double time);

  int GetSamples(SAM *buffer, int length);

  bool IsStreaming();

  int Extended(int call, void *parm1, void *parm2, void *parm3);

private:
  bool FindCodec();
  bool ConvertFormat(int ff_fmt, int *fmt, bool *planar);
  void PrintFormat(int fmt, bool planar);
  int SizeOfFormat(int fmt);
  void ReadNext();

  CodecInfo m_codec_info;
  RSE_FFmpegFileProtocol *m_protocol;
  RSE_FFmpegGlue *m_glue;
  ScopedContext *m_context;
  SwrContext *m_resampler;

  WDL_TypedQueue<SAM> m_buffer_queue;
  //WDL_TypedQueue<SAM> m_resampled_bq;
  WDL_Resampler m_rs;
  double m_hw_samplerate;

  bool m_eof;

  double m_position;

  double m_samplerate;
  int m_bits_per_sample;
  WDL_INT64 m_timestamp;

  WDL_FastString m_filename;
  WDL_FastString m_type;
};

#endif // _EUTERPE_FFMPEG_AUDIO_INPUT_H_
