/////////////////////////////////////////////////////////////////////////////
// Name:        mediatrc_ffmpeg.h
// Purpose:     FFMPEG Media Transcoder
// Author:      Alex Thuering
// Created:     26.04.2008
// RCS-ID:      $Id: mediatrc_ffmpeg.h,v 1.22 2011/11/27 22:52:56 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#ifndef WX_FFMPEG_MEDIA_TRANSCODER_H
#define WX_FFMPEG_MEDIA_TRANSCODER_H

#include "mediatrc.h"
#include <stdint.h>
#include <math.h>
#include <map>

#define INT64_C(val) val##LL
#define UINT64_C(val) val##ULL
extern "C" {
#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

// select an input stream for an output stream
typedef struct StreamMap {
    int file_index;
    int stream_index;
    int sync_file_index;
    int sync_stream_index;
} StreamMap;

// select an input file for an output file
typedef struct MetadataMap {
	int  file;      // file index  
	char type;      // type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
	int  index;     // stream/chapter/program number 
} MetadataMap;

typedef struct ChapterMap {
    int in_file;
    int out_file;
} ChapterMap;

struct InputStream;
struct OutputStream;
struct AVDictionary;
struct InputFile;
struct OutputFile;

#define MAX_FILES 50
#define CODEC_TYPE_COUNT (int) CODEC_TYPE_NB

class wxFfmpegMediaTranscoder : public wxMediaTranscoder {
public:
	wxFfmpegMediaTranscoder(int threadCount = 1);
	~wxFfmpegMediaTranscoder();
	static void Init();
	
	/** Adds input file. */
	bool AddInputFile(const wxString& fileName, bool disableVideo = false, bool disableAudio = false,
			bool disableSubtitle = false);
	
	/** Sets output file and video/audio/subtitle formats. */
	bool SetOutputFile(const wxString& fileName, VideoFormat videoFormat, AudioFormat audioFormat,
			SubtitleFormat subtitleFormat, int videoBitrate = 6000, bool vbr = false, int audioBitrate = 224);
	/** Sets output file and video/audio/subtitle formats. */
	bool SetOutputFile(const wxString& fileName, VideoFormat videoFormat, wxArrayInt audioFormats,
			wxArrayInt subtitleFormats, int videoBitrate = 6000, bool vbr = false, int audioBitrate = 224);
	/** Sets interlaced encoding flag */
	void SetInterlaced(bool value);
	/** Sets first field flag (Auto, TFF, BFF) */
	void SetFirstField(FirstField firstField);
	/** Sets start time */
	void SetStartTime(double startTime);
	/** Sets recording time */
	void SetRecordingTime(double recordingTime);
	/** Sets video filters */
	void SetVideoFilters(const wxString& videoFilters) { m_videoFilters = videoFilters; }
	/** Sets audio volume (256=normal) */
	void SetAudioVolume(int streamIndex, int audioVolume) { m_audioVolume[streamIndex] = audioVolume; }
	
	/** Starts transcoding. */
	bool Run(bool& canceled);
	/** Ends ttanscoding and closes all fiies. */
	void End();
	
private:
	wxString m_videoFilters;
	void PrintError(const wxString& fileName, int err);
	bool AddInputStreams(AVFormatContext *ic, bool disableVideo, bool disableAudio, bool disableSubtitle);
	OutputStream* NewOutputStream(AVFormatContext *oc, AVMediaType type, int format);
	bool AddVideoStream(AVFormatContext *oc, VideoFormat videoFormat, int bitrate, bool vbr);
	bool AddAudioStream(AVFormatContext *oc, AudioFormat audioFormat, int bitrate);
	bool AddSubtitleStream(AVFormatContext *oc, SubtitleFormat subtitleFormat);
	bool OutputPacket(InputStream *ist, int ist_index, OutputStream *ost_table, int nb_ostreams, const AVPacket *pkt);
	double get_sync_ipts(const OutputStream *ost);
	bool WriteFrame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx,
			AVBitStreamFilterContext *bsfc);
	bool DoAudioOut(AVFormatContext *s, OutputStream *ost, InputStream *ist, unsigned char *buf, int size);
	void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp);
	bool DoVideoOut(AVFormatContext *s, OutputStream *ost, InputStream *ist,
			AVFrame *in_picture, int *frame_size, int bit_buffer_size, uint8_t* bit_buffer);
	bool DoSubtitleOut(AVFormatContext *s, OutputStream *ost, InputStream *ist,
			AVSubtitle *sub, int64_t pts);
	void PrintReport(OutputFile *output_files, OutputStream *ost_table, int nb_ostreams, int is_last_report);
	int CopyChapters(int infile, int outfile);
	AVDictionary *ts_scale;
	int  nb_ts_scale;

    StreamMap* stream_maps;
	int nb_stream_maps;

	MetadataMap (*meta_data_maps)[2];
    int nb_meta_data_maps;
    int metadata_global_autocopy;
    int metadata_streams_autocopy;
    int metadata_chapters_autocopy;

    ChapterMap* chapter_maps;
    int nb_chapter_maps;
    
    int chapters_input_file;
    
    /* indexed by output file stream index */
    int *streamid_map;
    unsigned int nb_streamid_map;

    int frame_width;
    int frame_height;
    float frame_aspect_ratio;
    PixelFormat frame_pix_fmt;
    int frame_bits_per_raw_sample;
    SampleFormat audio_sample_fmt;
    int max_frames[4];
    AVRational frame_rate;
    float video_qscale;
    uint16_t *intra_matrix;
    uint16_t *inter_matrix;
    const char *video_rc_override_string;
    unsigned int video_codec_tag;
    char *video_language; 
    int same_quant;
    int do_interlace;
    int do_deinterlace;
    int top_field_first;
    int me_threshold;
    int intra_dc_precision;
    int loop_input;
    int loop_output;
    int qp_hist;

    int intra_only;
    int audio_sample_rate;
    float audio_qscale;
    int audio_channels;
    unsigned int audio_codec_tag;
    char *audio_language;
    
    char *subtitle_language;
    unsigned int subtitle_codec_tag;
    
    float mux_preload;
    float mux_max_delay;

    int64_t recording_time;
    int64_t start_time;
    int64_t input_ts_offset;
    AVDictionary *metadata;
    int do_psnr;
    int do_pass;
    const char *pass_logfilename_prefix;
    int video_sync_method;
    int audio_sync_method;
    float audio_drift_threshold;
    int copy_ts;
    int copy_tb;
    int opt_shortest;
    char *vstats_filename;
    FILE *vstats_file;
    int opt_programid;
    int copy_initial_nonkeyframes;

    int rate_emu;

    map<int, int> m_audioVolume; // stream index -> audio volume

    int exit_on_error;
    int verbose;
    int thread_count;
    int q_pressed;
    int64_t video_size;
    int64_t audio_size;
    int64_t extra_size;
    int nb_frames_dup;
    int nb_frames_drop;
    int input_sync;
    uint64_t limit_filesize; //
	int force_fps;

    int pgmyuv_compatibility_hack;
    float dts_delta_threshold;
    int64_t timer_start;
    
    uint8_t *audio_buf;
    uint8_t *audio_out;
    unsigned int allocated_audio_out_size, allocated_audio_buf_size;

    short *samples;
    int bit_buffer_size;
    uint8_t *bit_buffer;

    AVBitStreamFilterContext *video_bitstream_filters;
    AVBitStreamFilterContext *audio_bitstream_filters;
    AVBitStreamFilterContext *subtitle_bitstream_filters;
    
    InputStream *input_streams;
    int nb_input_streams;
    InputFile *input_files;
    int nb_input_files;
    
    OutputStream *output_streams;
	int nb_output_streams;
	OutputFile *output_files;
    int nb_output_files;
    
    AVDictionary *format_opts;
    AVDictionary *codec_opts;
};

#endif // WX_FFMPEG_MEDIA_TRANSCODER_H
