/*****************************************************************************
 *
 *  video_struct.h -- Most common video structures.
 *
 *  Copyright (C) 2010 Starbuck <starbuck@labdv.com>
 *  All rights reserved.
 *
 *  GNU Lesser General Public License Usage
 *  This file may be used under the terms of the GNU Lesser General
 *  Public License version 2.1 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.LGPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU Lesser General Public License version 2.1 requirements
 *  will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 *  GNU General Public License Usage
 *  Alternatively, this file may be used under the terms of the GNU
 *  General Public License version 3.0 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.GPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU General Public License version 3.0 requirements will be
 *  met: http://www.gnu.org/copyleft/gpl.html.
 *
 *  MPEG2 notes:
 *		     Code	Aspect Ratio			  Frame Rate
 *			0 0000	 forbidden					forbidden
 *			1 0001	 1:1						24000/1001 (23.976)
 *			2 0010	 4:3						24
 *			3 0011	 16:9						25
 *			4 0100	 2.21:1(not used in DVD)	30000/1001 (29.97)
 *			5 0101	 1.85:1(added for DVDx4)	30
 *			6 0110	 2.35:1(added for DVDx4)	50
 *			7 0111	 reserved					60000/1001 (59.94)
 *			8 1000	 reserved					60
 *			9 1001	 reserved					reserved
 *				    	:
 *			15 1111	 reserved					reserved
 *
 * Due to non-squareness of pixels in Standard-definition TV, there are two types 
 * of Picture Aspect Ratio: Storage Aspect Ratio (SAR) and Display Aspect Ratio (DAR). 
 * Storage Aspect Ratio is the ratio of the image width to height in pixels, and can 
 * be easily calculated from the video file. Display Aspect Ratio is the ratio of 
 * image width to height (in a unit of length such as centimeters or inches) when 
 * displayed on screen, and is calculated from the combination of Pixel Aspect Ratio 
 * and Storage Aspect Ratio.
 *
 * aspect_ratio_information -- This is a four-bit integer defined in the Table 6-3.
 *
 * aspect_ratio_information either specifies that the “sample aspect ratio” (SAR)
 * of the reconstructed frame is 1,0 (square samples) or alternatively it gives 
 * the “display aspect ratio” (DAR).
 *
 * -	If sequence_display_extension() is not present then it is intended that 
 *		the entire reconstructed frame is intended to be mapped to the entire
 *		active region of the display.  The sample aspect ratio may be calculated 
 *		as follows:
 *						SAR = DAR x horizontal_size / vertical_size
 *
 * NOTE - In this case horizontal_size and vertical_size are constrained by the 
 *        SAR of the source and the DAR selected.
 *
 * -	If sequence_display_extension() is present then the sample aspect ratio 
 *		may be calculated as follows:
 *						SAR = DAR x display_horizontal_size / display_vertical_size
 *
 * frame_rate_code -- This is a four-bit integer used to define frame_rate_value as 
 *                    shown in Table 6-4.  
 *
 * frame_rate may be derived from frame_rate_value, frame_rate_extension_n and 
 * frame_rate_extension_d as follows:
 *
 * frame_rate = frame_rate_value * (frame_rate_extension_n + 1) ÷ (frame_rate_extension_d + 1)
 *
 * When an entry for the frame rate exists directly in Table 6-4, frame_rate_extension_n 
 * and frame_rate_extension_d shall be zero. (frame_rate_extension_n + 1) and 
 * (frame_rate_extension_d + 1) shall not have a common divisor greater than one.
 *
 * If progressive_sequence is ‘1’ the period between two successive frames at the output 
 * of the decoding process is the reciprocal of the frame_rate. 
 *
 * If progressive_sequence is ‘0’ the period between two successive fields at the output
 * of the decoding process is half of the reciprocal of the frame_rate. 
 *
 * The frame_rate signalled in the enhancement layer of  temporal scalability is the 
 * combined frame rate after the temporal remultiplex operation if picture_mux_enable 
 * in the sequence_scalable_extension() is set to '1'.
 *
 *****************************************************************************/

#ifndef DVDX_VIDEO_TYPES_H
#define DVDX_VIDEO_TYPES_H

#include "video_constants.h"
#include <QString>
#include <QStringList>
#include <QMap>
#include <QRect>

// Output file split
struct split_t
{
	int size;		// size of a volume (usually in MiB, MillionsBytes: 1,000,000 Bytes)
	int volumes;	// number of volumes to split output into

	// Reset split to 1 CD 700MB/80min for default new instance
	split_t() { reset(); }

	// Initialize new instance
	split_t(int s, int v) { size = s; volumes = v; }

	void reset(){
		size = 681;
		volumes = 2;
	}
};

// Video track
struct video_t
{
	int media;		// 0 ie audio file, 1 or 2 for File or DVD
	int title;
	int angle;
	QString format;
	QString codec;
	int	bpp;
	QSize rez;
	QSize scaledRez;
	QString standard;	// NTSC, PAL
	int interlaced;		// -1 undefined, 0 progressive, 1 interlaced
	int scan_order;	// -1 undefined, 0 bottom field first, 1 top field first, 2 2:3 Pulldown, 3 2:2:2:2:2:2:2:2:2:2:2:3 Pulldown
	double display_aspect;  // scalar value
	double pixel_aspect;  // scalar value
	double fps;
	double kbps;
	double length;

	// Ensure structure initialization
	video_t() { clear(); }

	void clear() 
	{
		media = 0;  // idle
		title = 1;
		angle = 1;
		format.clear();
		codec.clear();
		bpp = 0;
		rez = QSize(0,0);
		scaledRez = QSize(0,0);
		standard.clear();
		interlaced = -1;
		scan_order = -1;
		display_aspect = 0.0;
		pixel_aspect = 0.0;
		fps = 0.0;
		kbps = 0.0;
		length = 0.0;
	}

	inline bool idle() { return media == 0; };
};

// Audio track
struct audio_t
{
	int source;	// 0 for main intput source, >1 for additionnal sources (relocate to source-1)
	int n;		// stream number (starting from 0 for DVD, track number from 1 for files cause 0 is video)
	int aid;	// stream id (usually 0x80 (128), 0x81 (129) etc.)
	QString format;  // ac3, LPCM, A_AAC/MPEG2/LC/SBR, MPEG Audio, AMR
	QString codec;	 // mp3
	double kbps;	 // 0.0 is interpreted as VBR
	QString channels;  // 5.1, stereo
	int channel_number;		// 2, 6
	QString channel_positions;  // Front: L C R, Side: L R, LFE
	int sampling;	// in Hz
	double size;		// stream size in MiB (1000*1000 Bytes)
	QString language;  // en, fr
	QString description;  // commentaire, director cut, Audio ESP (doblaje antiguo), Audio JAP

	// Ensure structure initialization
	audio_t() { clear(); }

	void clear() 
	{
		source = 0;
		n = -1;		// idle (ie: no audio)
		aid = -1;
		format.clear();
		codec.clear();
		kbps = 0.0;
		channels.clear();
		channel_number = 0;
		channel_positions.clear();
		sampling = 0;
		size = 0.0;
		language.clear();
		description.clear();
	}

	inline bool idle() { return n == -1; };
};

// Subtitle
struct subtitle_t
{
	int source;  // 0 for main intput source, >1 for additionnal sources (relocate to source-1)
	int n;		// track number (starting from 1 for files ; =sid for DVD)
	int sid;	// subtitle id (starting from 0)
	int id;		// 32 (0x20)
	QString format;  // S_TEXT/UTF8, S_VOBSUB
	QString language;  // en, fr
	QString description;  // Subs audio ESP (doblaje antiguo), Subs audio ESP

	// Ensure structure initialization
	subtitle_t() { clear(); }

	void clear() 
	{
		source = 0;
		n = -1;		//idle (ie: no subtitle)
		sid = -1;
		id = 0;
		format.clear();
		language.clear();
		description.clear();
	}

	inline bool idle() { return n == -1; };
};

// DVD title
struct title_t
{
	int n;	// title number (starting from 1)
	QString format;
	QString codec;
	QSize rez;
	QSize scaledRez; // output rezolution (applying aspect ration)
	QString standard;	// NTSC, PAL
	int interlaced;		// -1 undefined, 0 progressive, 1 interlaced
	int scan_order;	// -1 undefined, 0 bottom field first, 1 top field first, 2 2:3 Pulldown, 3 2:2:2:2:2:2:2:2:2:2:2:3 Pulldown
	double display_aspect;  // scalar value
	double pixel_aspect;  // scalar value
	int mpeg_aspect;  // MPEG2 code
	int mpeg_fps;  // MPEG2 code for FPS
	double kbps;
	double length;
	bool ignored;  // to ignore unrelevant titles (too short)
	int angleN;
	int chapterN;
	QList<double> chapter;
	int audioN;  // number of audio streams
	QList<audio_t> audio;
	int subtitleN; // number of subtitles
	QList<subtitle_t> subtitle;

	// Ensure structure initialization
	title_t() { clear(); }

	void clear() 
	{
		n = 0;  // idle
		format.clear();
		codec.clear();
		rez = QSize(0,0);
		scaledRez = QSize(0,0);
		standard.clear();
		interlaced = -1;
		scan_order = -1;
		display_aspect = 0.0;
		pixel_aspect = 0.0;
		mpeg_aspect = 0;
		mpeg_fps = 0;
		kbps = 0.0;
		length = 0.0;
		ignored = false;
		chapterN = 0;
		chapter.clear();
		angleN = 0;
		audioN = 0;
		audio.clear();
		subtitleN = 0;
		subtitle.clear();
	}

	inline bool idle() { return n == 0; };
};

// Movie
struct movie_t
{
	QString format;
	bool novideo;
	QString codec;
	int	bpp;
	QSize rez;
	QSize scaledRez; // output rezolution (applying aspect ration)
	QString standard;	// NTSC, PAL
	int interlaced;		// -1 undefined, 0 progressive, 1 interlaced
	int scan_order;	// -1 undefined, 0 bottom field first, 1 top field first, 2 2:3 Pulldown, 3 2:2:2:2:2:2:2:2:2:2:2:3 Pulldown
	QString aspect_ratio;	// display aspect ratio as a string with : (16:9, 4:3)
	double display_aspect;  // scalar value
	double pixel_aspect;	// scalar value
	double fps;
	double kbps;
	double length;
	int audioN;  // number of audio streams
	QList<audio_t> audio;
	int subtitleN; // number of subtitles
	QList<subtitle_t> subtitle;

	// Ensure structure initialization
	movie_t() { clear(); }
	
	void clear() 
	{
		format.clear();
		novideo = false;
		codec.clear();
		bpp = 0;
		rez = QSize(0,0);
		scaledRez = QSize(0,0);
		standard.clear();
		interlaced = -1;
		scan_order = -1;
		aspect_ratio.clear();
		display_aspect = 0.0;
		pixel_aspect = 0.0;
		fps = 0.0;
		kbps = 0.0;
		length = 0.0;
		audioN = 0;
		audio.clear();
		subtitleN = 0;
		subtitle.clear();
	}
};

// Video slice
struct slice_t
{
	// int title;
	int chapter;
	// double start;
	// double stop;

	// Ensure structure initialization
	slice_t() { clear(); }

	void clear() 
	{
		chapter = 0;
	}
};

// Video player format
struct video_clip_t
{
	int media;
	QString format;
	bool novideo;
	QString codec;
	int	bpp;
	QSize rez;
	QSize scaledRez; // output rezolution (applying aspect ration)
	int mpeg_aspect;  // MPEG2 code
	double display_aspect;  // scalar value
	double pixel_aspect;	// SAR = DAR x horizontal_size / vertical_size
	int mpeg_fps;  // MPEG2 code
	double fps;  // scalar value
	double kbps;
	int interlaced;		// -1 undefined, 0 progressive, 1 interlaced
	int scan_order;	// -1 undefined, 0 bottom field first, 1 top field first, 2 2:3 Pulldown, 3 2:2:2:2:2:2:2:2:2:2:2:3 Pulldown
	double length;
	int chapterN;
	QList<double> chapter;
	int angleN;
	int audioN;
	audio_t audio;
	int subtitleN;
	subtitle_t subtitle;

	// Ensure structure initialization
	video_clip_t() { clear(); }

	void clear() 
	{
		media = 0;
		format.clear();
		novideo = false;
		codec.clear();
		bpp = 0;
		rez = QSize(0,0);
		scaledRez = QSize(0,0);
		mpeg_aspect = 0;
		display_aspect = 0.0;
		pixel_aspect = 0.0;
		mpeg_fps = 0;
		fps = 0.0;
		kbps = 0.0;
		interlaced = -1;
		scan_order = -1;
		length = 0.0;
		chapterN = 0;
		chapter.clear();
		angleN = 0;
		audioN = 0;
		audio.clear();
		subtitleN = 0;
		subtitle.clear();
	}
};

// Video settings
struct encoder_video_settings_t
{
	QString codec;
	QString standard;
	QSize rez;
	double bitrate;
	double fps;
	QString preset;
	QString profile;
	QStringList opts;
	QStringList filters;

	encoder_video_settings_t() { clear(); };

	void clear() 
	{
		codec.clear();
		standard.clear();
		rez = QSize(0,0); // 0,0 for no correction
		bitrate = 0.0;
		fps= 0.0;
		preset.clear();
		profile.clear();
		opts.clear();
		filters.clear();
	}
};

// Audio settings
struct encoder_audio_settings_t
{
	QString codec;
	int volume;			// audio correction (DVDx may restrict to -+48dB)
						//  Mencoder filter: -af volume=<-200-60> -200dB mute, +60dB max
						//  memo: +3dB x2, +6dB x4, +9bB x8, +12dB x16, +20dB x100
	int sampling;		// resample audio (in Hz)
	double kbps;
	QStringList opts;
	QStringList filters;

	encoder_audio_settings_t() { clear(); };

	void clear() 
	{
		volume = 0;		// 0dB (no correction)
		sampling = 0;	// 0 for no resampling
		kbps = 0.0;
		codec.clear();
		opts.clear();
		filters.clear();
	}
};

// Subtitle settings
struct encoder_subtitle_settings_t
{
	QString codec;

	encoder_subtitle_settings_t() { clear(); };

	void clear() 
	{
		codec.clear();
	}
};

// Encoder target
struct encoder_target_t
{
	QString dir;
	QString name;
	QString ext;
	QString muxer;
	split_t split;	// to split output in volumes

	encoder_target_t() { clear(); }

	void clear() 
	{
		dir.clear();
		name.clear();
		ext.clear();
		muxer.clear();
		split.reset();
	}

	QString fileName() { return name + ext; }
};

// Encoder video profile
struct encoder_video_profile_t
{
	QString muxer;

	QString codec;
	int level;
	QString standard;

	QSize rez;
	double bitrate;
};

// Encoder audio profile
struct encoder_audio_profile_t
{
	QString muxer;

	QString codec;
	int level;

	int sampling;
	double bitrate;
};

// Encoder profile
struct encoder_profile_t
{
	QString name;
	QString muxer;
	int level;
	QString title;
	QString standard;

	struct encoder_profile_video_data_t
	{
		QString codec;
		QSize rez;
		double bitrate;
	} video;

	struct encoder_profile_audio_data_t
	{
		QString codec;
		int sampling;
		double bitrate;
	} audio;

	encoder_profile_t() { level = Video::Profile::None; }
};


// Encoder settings
struct encoder_settings_t
{
	// Input
	struct input_t 
	{

		struct source_t
		{
			QString path;
			int media;
			
			source_t() { clear(); }

			void clear() 
			{
				path.clear();
				media = 0;		// idle
			}
		} source;

		video_t video;
		bool no_video;
		audio_t audio;
		bool no_audio;
		subtitle_t subtitle;
		bool no_subtitle;

		QList<source_t> additionalSource;
		QList<audio_t> additionalAudio;
		QList<subtitle_t> additionalSubtitle;

		QMap<int, int> additionalAudioMap; // only for stream in additional sources
		QMap<int, int> additionalSubtitleMap;

		void clear() 
		{
			source.clear();
			video.clear();
			no_video = true;
			audio.clear();
			no_audio = true;
			subtitle.clear();
			no_subtitle = true;
			additionalSource.clear();
			additionalAudio.clear();
			additionalAudioMap.clear();
			additionalSubtitle.clear();
			additionalSubtitleMap.clear();
		}
	} input;

	// Output
	struct output_t 
	{
		QString muxer;
		
		encoder_profile_t profile;

		encoder_video_settings_t video;
		encoder_audio_settings_t audio;
		encoder_subtitle_settings_t subtitle;
		QList<encoder_audio_settings_t> additionalAudio;
		QList<encoder_subtitle_settings_t> additionalSubtitle;

		QMap<QString, QString> options;
		
		//*experimental, use options instead
		int frames;					// number of frames to encode (0: no limit)
		int seconds;				// seconds to encode (0: no limit, frames has priority)

		output_t() { clear(); }
		
		void clear() 
		{
			muxer.clear();
			profile.level = Video::Profile::None;
			video.clear();
			audio.clear();
			subtitle.clear();
			additionalAudio.clear();
			additionalSubtitle.clear();

			frames = 0;
			seconds = 0;
		}

	} output;

	void clear() 
	{
		input.clear();
		output.clear();
	}

	// Ensure structure initialization
	encoder_settings_t() { clear(); }
};

// Codec video or audio
struct codec_t
{
	int code;
	QString name;
	QString description;
};

struct muxer_t
{
	int code;
	QString name;
	QString description;
	QString ext;	// file extension
};

// Driver video or audio
struct driver_t
{
	QString name;
	QString description;
};

// Video encoder capabilities
struct encoder_engine_capability_t
{
	QMap<QString, QString> *video;
	QMap<QString, QString> *audio;
	QMap<QString, QString> *subtitle;
	QMap<QString, QString> *muxer;

	QMap<QString, QStringList> *libVideo;
	QMap<QString, QStringList> *libAudio;
	QMap<QString, QStringList> *libSubtitle;
	QMap<QString, QStringList> *libMuxer;
};

// Video player capabilities
struct player_engine_capability_t
{
	QMap<QString, QString> *video;
	QMap<QString, QString> *audio;
};

// Video encoder signature
struct encoder_engine_status_t
{
	int state;
	QByteArray cout;
	QByteArray cerr;
	QString encoder;
	QString version;

	// Ensure structure initialization
	encoder_engine_status_t() { clear(); }

	void clear() 
	{
		state = Video::Status::IdleEngine;
		cout.clear();
		cerr.clear();
		encoder.clear();
		version.clear();
	}
};

// Video player signature
struct player_engine_status_t
{
	int state;
	QByteArray cout;
	QByteArray cerr;
	QString player;
	QString version;
#if defined( WIN32 )
	bool supportsOpenGL;  // more a capability than a status
#endif

	// Ensure structure initialization
	player_engine_status_t() { clear(); }

	void clear() 
	{
		state = Video::Status::IdleEngine;
		cout.clear();
		cerr.clear();
		player.clear();
		version.clear();
#if defined( WIN32 )
		supportsOpenGL = false;
#endif
	}
};

// Utility signature
struct utility_status_t
{
	int state;
	QByteArray cout;
	QByteArray cerr;
	QString utility;
	QString version;

	// Ensure structure initialization
	utility_status_t() { clear(); }

	void clear() 
	{
		state = Video::Status::IdleEngine;
		cout.clear();
		cerr.clear();
		utility.clear();
		version.clear();
	}
};

#endif
