/*
 *  probe_xml.c
 *
 *  Copyright (C) Marzio Malanchini - March 2003
 *
 *  This file is part of transcode, a video stream processing tool
 *
 *  transcode is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  transcode is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "transcode.h"
#include "tcinfo.h"
#include "ioaux.h"
#include "tc.h"
#include "libtc/libtc.h"

#include <sys/types.h>

#ifdef HAVE_LIBXML2

#include "ioxml.h"
#include "probe_xml.h"

#define MAX_BUF 1024

extern int binary_dump;


static int f_check_video_H_W(audiovideo_t *p_audio_video)
{
	audiovideo_t *p_temp;
	int s_rc=0,s_video_tg_height=0,s_video_tg_width=0,s_v_height=0,s_v_width=0;

	for (p_temp=p_audio_video;p_temp != NULL;p_temp=p_temp->p_next)
	{
		if (s_v_height == 0)
			s_v_height=p_temp->s_v_height;
		else if (s_v_height != p_temp->s_v_height)
			s_rc|=0x01;
		if (s_v_width == 0)
			s_v_width=p_temp->s_v_width;
		else if (s_v_width != p_temp->s_v_width)
			s_rc|=0x02;
		if ((p_temp->s_v_tg_height != 0) && (s_video_tg_height==0))
			s_video_tg_height=p_temp->s_v_tg_height;
		else if (p_temp->s_v_tg_height != 0)
		{
			if (p_temp->s_v_tg_height != s_video_tg_height)
			{
				tc_log_warn(__FILE__,"setting target height to %d (the target must be the same for all statements)",s_video_tg_height);
				p_temp->s_v_tg_height=s_video_tg_height;
			}
		}
		if ((p_temp->s_v_tg_width != 0) && (s_video_tg_width==0))
			s_video_tg_width=p_temp->s_v_tg_width;
		else if (p_temp->s_v_tg_width != 0)
		{
			if (p_temp->s_v_tg_width != s_video_tg_width)
			{
				tc_log_warn(__FILE__,"setting target width to %d (the target must be the same for all statements)",s_video_tg_width);
				p_temp->s_v_tg_width=s_video_tg_width;
			}
		}
	}
	if (s_rc !=0)
	{
		if ((s_rc == 0x03) && (s_video_tg_height == 0) && (s_video_tg_width == 0))
		{
			tc_log_error(__FILE__,"the height and the width of the video tracks are different. Please specify target-width and target-height if you want to process the xml file");
			return(1);
		}
		else if ((s_rc == 0x01) && (s_video_tg_height == 0))
		{
			tc_log_error(__FILE__,"the height of the video tracks are different. Please specify target-height if you want to process the xml file");
			return(1);
		}
		else if ((s_rc == 0x02) && (s_video_tg_width == 0))
		{
			tc_log_error(__FILE__,"the width of the video tracks are different. Please specify target-height if you want to process the xml file");
			return(1);
		}
	}
	for (p_temp=p_audio_video;p_temp != NULL;p_temp=p_temp->p_next) //initialize all unset codec
	{
		if (s_video_tg_height!=0)
			p_temp->s_v_tg_height=s_video_tg_height;
		if (s_video_tg_width!=0)
			p_temp->s_v_tg_width=s_video_tg_width;
	}
	return(0);
}

static void f_det_totale_video_frame(audiovideo_t *p_audio_video)
{
	if ((p_audio_video->s_video_smpte==smpte)||(p_audio_video->s_video_smpte==smpte25))
		p_audio_video->s_fps=25.00;
	else if (p_audio_video->s_video_smpte==smpte30drop)
		p_audio_video->s_fps=29.97;
	p_audio_video->s_start_video+=(long)p_audio_video->s_start_v_time * p_audio_video->s_fps;
	p_audio_video->s_end_video+=(long)p_audio_video->s_end_v_time * p_audio_video->s_fps;
}

static void f_det_totale_audio_frame(audiovideo_t *p_audio_video)
{
	if ((p_audio_video->s_audio_smpte==smpte)||(p_audio_video->s_audio_smpte==smpte25))
		p_audio_video->s_fps=25.00;
	else if (p_audio_video->s_audio_smpte==smpte30drop)
		p_audio_video->s_fps=29.97;
	p_audio_video->s_start_audio+=(long)p_audio_video->s_start_a_time * p_audio_video->s_fps;
	p_audio_video->s_end_audio+=(long)p_audio_video->s_end_a_time * p_audio_video->s_fps;
}


int f_build_xml_tree(info_t *ipipe,audiovideo_t *p_audiovideo,ProbeInfo *p_first_audio,ProbeInfo *p_first_video,long *s_tot_frames_audio, long *s_tot_frames_video)
{
	audiovideo_t	*p_audio_video;
	char	s_probe_cmd_buf[MAX_BUF+1];
	FILE	*p_fd;
	ProbeInfo	s_other_audio;
	ProbeInfo	s_other_video;
	int	s_first_element=0;
	pid_t   tc_probe_pid;

	*s_tot_frames_audio=*s_tot_frames_video=0;
	ipipe->error=f_manage_input_xml(ipipe->name,1,p_audiovideo);

	if (ipipe->error==1)
	{
		f_manage_input_xml(ipipe->name,0,p_audiovideo);
		return(-1);
	}
	for (p_audio_video=p_audiovideo->p_next;p_audio_video!=NULL;p_audio_video=p_audio_video->p_next)
	{
		if (p_audio_video->p_nome_video != NULL)
		{
			if(tc_snprintf(s_probe_cmd_buf, MAX_BUF, "tcprobe -i %s -d %d ",p_audio_video->p_nome_video,ipipe->verbose) < 0)
			{
	                	tc_log_error(__FILE__,"Buffer overflow");
				ipipe->error=1;
				break;
			}
			if (binary_dump)
			{
				if(tc_snprintf(s_probe_cmd_buf+strlen(s_probe_cmd_buf), MAX_BUF-strlen(s_probe_cmd_buf), "-B ") < 0)
				{
		                	tc_log_error(__FILE__,"Buffer overflow");
					ipipe->error=1;
					break;
				}

				if((p_fd = popen(s_probe_cmd_buf, "r"))== NULL)
				{
	                		tc_log_error(__FILE__,"Cannot open pipe: %s",strerror(errno));
					ipipe->error=1;
					break;
				}

                                if (fread(&tc_probe_pid, sizeof(pid_t), 1, p_fd) !=1)
                                {
	                		tc_log_error(__FILE__,"Cannot read pipe");
                                        ipipe->error=1;
                                        break;
                                }

				if (fread(&s_other_video, sizeof(ProbeInfo), 1, p_fd) !=1)
				{
	                		tc_log_error(__FILE__,"Cannot read pipe");
					ipipe->error=1;
					break;
				}
				pclose(p_fd);
				p_audio_video->s_v_real_codec=s_other_video.codec;
				p_audio_video->s_v_width=s_other_video.width;
				p_audio_video->s_v_height=s_other_video.height;
				p_audio_video->s_a_real_codec=s_other_video.track[0].format;
				p_audio_video->s_a_rate=s_other_video.track[0].samplerate;
				p_audio_video->s_a_bits=s_other_video.track[0].bits;
				p_audio_video->s_a_chan=s_other_video.track[0].chan;
				p_audio_video->s_fps=s_other_video.fps;
				if(s_other_video.magic == TC_MAGIC_UNKNOWN || s_other_video.magic == TC_MAGIC_PIPE || s_other_video.magic == TC_MAGIC_ERROR)
				{
					tc_log_error(__FILE__,"this version of transcode supports only");
					tc_log_error(__FILE__,"xml file who containing dv avi or mov file type.");
					tc_log_error(__FILE__,"Please clean up the %s file and restart.", ipipe->name);
					tc_log_error(__FILE__,"file %s with filetype %s is invalid for this operation mode.", p_audio_video->p_nome_video, filetype(s_other_video.magic));
					ipipe->error=1;
				}
				if (p_audio_video->s_v_magic == TC_MAGIC_UNKNOWN)	//forced by ioxml.c
				{
					if (s_other_video.magic == TC_MAGIC_AVI)	//if the magic is AVI and the codec is DV -> i need to use DV
						if (s_other_video.codec == TC_CODEC_DV)
							p_audio_video->s_v_magic=TC_MAGIC_DV_PAL;
						else
							p_audio_video->s_v_magic=s_other_video.magic;
					else
						p_audio_video->s_v_magic=s_other_video.magic;
				}
				if ((s_first_element & 0x02) == 0)
				{
					s_first_element|=0x02;
					ac_memcpy(p_first_video,&s_other_video,sizeof(ProbeInfo));
				}
				f_det_totale_video_frame(p_audio_video);
				if (p_audio_video->s_start_video > p_audio_video->s_end_video)
				{
					tc_log_error(__FILE__, "error: start frame is greater than end frame in file %s",p_audio_video->p_nome_video);
					ipipe->error=1;
				}
	                        *s_tot_frames_video+=(p_audio_video->s_end_video - p_audio_video->s_start_video);       //selected frames
			}
			else
				system(s_probe_cmd_buf);
		}
		if (p_audio_video->p_nome_audio != NULL)
		{
			if(tc_snprintf(s_probe_cmd_buf, MAX_BUF, "tcprobe -i %s -d %d ",p_audio_video->p_nome_audio,ipipe->verbose) < 0)
			{
	                	tc_log_error(__FILE__,"Buffer overflow");
				ipipe->error=1;
				break;
			}
			if (binary_dump)
			{
				if(tc_snprintf(s_probe_cmd_buf+strlen(s_probe_cmd_buf), MAX_BUF-strlen(s_probe_cmd_buf), "-B ") < 0)
				{
	                		tc_log_error(__FILE__,"Buffer overflow");
					ipipe->error=1;
					break;
				}
				if((p_fd = popen(s_probe_cmd_buf, "r"))== NULL)
				{
	                		tc_log_error(__FILE__,"Cannot open pipe: %s",strerror(errno));
					ipipe->error=1;
					break;
				}

                                if (fread(&tc_probe_pid, sizeof(pid_t), 1, p_fd) !=1)
                                {
	                		tc_log_error(__FILE__,"Cannot read pipe");
                                        ipipe->error=1;
                                        break;
                                }

				if (fread(&s_other_audio, sizeof(ProbeInfo), 1, p_fd) !=1)
				{
	                		tc_log_error(__FILE__,"Cannot read pipe");
					ipipe->error=1;
					break;
				}
				pclose(p_fd);
				p_audio_video->s_a_real_codec=s_other_audio.track[0].format;
				p_audio_video->s_a_rate=s_other_video.track[0].samplerate;
				p_audio_video->s_a_bits=s_other_video.track[0].bits;
				p_audio_video->s_a_chan=s_other_video.track[0].chan;
				if(s_other_audio.magic == TC_MAGIC_UNKNOWN || s_other_audio.magic == TC_MAGIC_PIPE || s_other_audio.magic == TC_MAGIC_ERROR)
				{
					tc_log_error(__FILE__,"this version of transcode supports only");
					tc_log_error(__FILE__,"xml file who containing dv avi or mov file type.");
					tc_log_error(__FILE__,"Please clean up the %s file and restart.", ipipe->name);
					tc_log_error(__FILE__,"file %s with filetype %s is invalid for this operation mode.", p_audio_video->p_nome_audio, filetype(s_other_audio.magic));
					ipipe->error=1;
				}
				if (p_audio_video->s_a_magic == TC_MAGIC_UNKNOWN)	//forced by ioxml.c
				{
					if (s_other_audio.magic == TC_MAGIC_AVI)	//if the magic is AVI and the codec is DV -> i need to use DV
						if (s_other_audio.track[0].format == CODEC_PCM)	//for instant only PCM work
							p_audio_video->s_a_magic=TC_MAGIC_AVI;
						else
							p_audio_video->s_a_magic=s_other_audio.magic;
					else
						p_audio_video->s_a_magic=s_other_audio.magic;
				}
				if ((s_first_element & 0x01) == 0)
				{
					s_first_element|=0x01;
					ac_memcpy(p_first_audio,&s_other_audio,sizeof(ProbeInfo));
				}
				f_det_totale_audio_frame(p_audio_video);
				if (p_audio_video->s_start_audio > p_audio_video->s_end_audio)
				{
					tc_log_error(__FILE__,"start frame is greater than end frame in file %s",p_audio_video->p_nome_video);
					ipipe->error=1;
				}
	                        *s_tot_frames_audio+=(p_audio_video->s_end_audio - p_audio_video->s_start_audio);       //selected frames
			}
		}
	}
	if (p_audiovideo->p_next !=NULL)
	{
		if ((ipipe->error=f_check_video_H_W(p_audiovideo->p_next)) == 0)		//check height and width compatibility
		{
			if (p_audiovideo->p_next->s_v_tg_height !=0)
				p_first_video->height=p_audiovideo->p_next->s_v_tg_height;	//force height to target-height
			if (p_audiovideo->p_next->s_v_tg_width !=0)
				p_first_video->width=p_audiovideo->p_next->s_v_tg_width;	//force width to target-width
		}
	}
	return(s_first_element);
}

void probe_xml(info_t *ipipe)
{
	audiovideo_t s_audiovideo;
	ProbeInfo	s_first_audio;
	ProbeInfo	s_first_video;
	long	s_tot_frames_audio,s_tot_frames_video;
	int s_first_element;


	if ((s_first_element=f_build_xml_tree(ipipe,&s_audiovideo,&s_first_audio,&s_first_video,&s_tot_frames_audio,&s_tot_frames_video)) == -1)
	{
		//there's an error during the call of f_build_xml_tree
		return;
	}

	f_manage_input_xml(NULL,0,&s_audiovideo);

	if (s_first_element & 0x03)	//have video and audio tracks
	{
		ac_memcpy(ipipe->probe_info,&s_first_video,sizeof(ProbeInfo)); //setup the probe_info structure
		ipipe->probe_info->frames=s_tot_frames_video;		//Force sum of selected frames
		ipipe->probe_info->num_tracks=s_first_audio.num_tracks;
		ac_memcpy(ipipe->probe_info->track,&(s_first_audio.track),TC_MAX_AUD_TRACKS*sizeof(ProbeTrackInfo));
	}
	else if (s_first_element & 0x02)     //have only video track
	{
		ac_memcpy(ipipe->probe_info,&s_first_video,sizeof(ProbeInfo)); //setup the probe_info structure
		ipipe->probe_info->frames=s_tot_frames_video;		//Force sum of selected frames
	}
	else if (s_first_element & 0x01)     //have only audio tracks
	{
		ac_memcpy(ipipe->probe_info,&s_first_audio,sizeof(ProbeInfo)); //setup the probe_info structure
		ipipe->probe_info->frames=s_tot_frames_audio;		//Force sum of selected frames
	}
	s_first_element=0;
}

#else  // HAVE_LIBXML2

void probe_xml(info_t *ipipe)
{
        tc_log_error(__FILE__, "no support for XML compiled - exit.");
        ipipe->error=1;
        return;
}

#endif
