/*
#
# Interface functions for mpeg parse library
#
# $Id: mpegparse.h,v 1.6 2005/03/20 20:18:33 nemesis Exp $
#
# Copyright (C) 2005 Kees Cook
# kees@outflux.net, http://outflux.net/
# 
# This program 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
# of the License, or (at your option) any later version.
# 
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
#
*/
#ifndef _MPEGPARSE_H_
#define _MPEGPARSE_H_

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

// is there a way to directly test the size of off_t?
#if _FILE_OFFSET_BITS!=64
# error "'off_t' must be 64 bits!  Make sure _FILE_OFFSET_BITS=64"
#endif

#include <sys/types.h> // off_t
#include <stdint.h>

typedef struct mpegparse_t mpegparse;

enum mpegparse_packet {
	MPEGPARSE_NOT_MPEG2 = -3, // if the stream headers don't match PES
	MPEGPARSE_INVALID_LOCATION = -2, // NULL location pointer
	MPEGPARSE_INVALID_PARSER = -1, // NULL mpegparse pointer
	MPEGPARSE_END = 0, // EOF of input
	MPEGPARSE_NONE, // not initialized
	MPEGPARSE_OTHER, //ecm, emm, dsmcc, ancilary
	MPEGPARSE_RESERVED,
	MPEGPARSE_PACK,
	MPEGPARSE_SYSTEM,
	MPEGPARSE_PES_VIDEO,
	MPEGPARSE_VIDEO_GOP,
	MPEGPARSE_VIDEO_SEQ_START,
	MPEGPARSE_PROGRAM_END,
	MPEGPARSE_VIDEO_PICTURE,
	MPEGPARSE_VIDEO_SLICE,
	MPEGPARSE_PES_AUDIO,
	MPEGPARSE_PES_PS_MAP,
	MPEGPARSE_PES_PRIV_1,
	MPEGPARSE_PES_PRIV_2,
	MPEGPARSE_PES_ISO,
	MPEGPARSE_PES_ANCILLARY,
	MPEGPARSE_USER_DATA,
	MPEGPARSE_SEQ_HEADER,
	MPEGPARSE_SEQ_ERROR,
	MPEGPARSE_EXTENSION_START,
	MPEGPARSE_PES_PADDING,
	MPEGPARSE_PES_PS_DIRECTORY,
};

struct mpegparse_header_pes_complex
{
        uint8_t         PES_scrambling_control:2;
	uint8_t         PES_priority:1;
	uint8_t         data_alignment_indicator:1;
	uint8_t         copyright:1;
	uint8_t         original_or_copy:1;
		
	uint8_t         PTS_DTS_flags:2;
	uint8_t         ESCR_flag:1;
	uint8_t         ES_rate_flag:1;
	uint8_t         DSM_trick_mode_flag:1;
	uint8_t         additional_copy_info_flag:1;
	uint8_t         PES_CRC_flag:1;
	uint8_t         PES_extension_flag:1;

	uint8_t		PES_header_data_length;

};

struct mpegparse_header_pack
{
	uint64_t system_clock_ref_base:33;
	uint16_t system_clock_ref_ext:9;
	uint32_t program_mux_rate:22;
	uint8_t  pack_stuffing_length:3;
};

typedef struct mpegparse_header_pes_complex mpegparse_header_pes_video;
typedef struct mpegparse_header_pes_complex mpegparse_header_pes_audio;
typedef struct mpegparse_header_pes_complex mpegparse_header_pes_priv_1;
typedef struct mpegparse_header_pes_complex mpegparse_header_pes_iso;
typedef struct mpegparse_header_pes_complex mpegparse_header_pes_ancillary;

/* There is no content in a PES "simple" (just length)
struct mpegparse_header_pes_simple
{
};

typedef struct mpegparse_header_pes_simple mpegparse_header_system;
typedef struct mpegparse_header_pes_simple mpegparse_header_pes_ps_map;
typedef struct mpegparse_header_pes_simple mpegparse_header_pes_padding;
typedef struct mpegparse_header_pes_simple mpegparse_header_pes_priv_2;
typedef struct mpegparse_header_pes_simple mpegparse_header_pes_other;
typedef struct mpegparse_header_pes_simple mpegparse_header_pes_reserved;
*/

struct mpegparse_packet_info {
	enum mpegparse_packet	packet;        // packet type
	uint8_t			code;          // MPEG code
	off_t			code_offset;   // location of start code
	off_t			header_offset; // location of headers
	size_t			header_length; // size of header
	off_t			data_offset;   // location of start of data
	size_t			data_length;   // size of data
	int			header_parsed; // did the header get parsed?
	union {
		struct mpegparse_header_pack		pack;
		/*
		struct mpegparse_header_system		system;
		*/
		struct mpegparse_header_pes_complex	pes_complex;
		mpegparse_header_pes_video		pes_video;
		mpegparse_header_pes_audio		pes_audio;
	} header;
};

// initializes a new reader on a file
mpegparse * mpegparse_open_program_stream(char * filename);

// finds the next packet, and returns the kind of packet in the enum.
// "location" is where to seek to before parsing.  Must be set to "0"
// on the first call.  It is updated by mpegparse_find_packet to automatically
// seek to the next packet.  If this is set to "0" each time, the parser
// will continue on, looking for mpeg start codes.
// returns a pointer to a structure containing current packet information.
// this memory is only valid until the next call to "mpegparse_find_packet".
struct mpegparse_packet_info *
mpegparse_find_packet(mpegparse * parser, off_t * location);

// copies raw packet data from start code on into buffer.  1==success 0==fail
int mpegparse_get_raw_packet_contents(mpegparse * parser, uint8_t * bytes);

// report position in file
off_t mpegparse_tell(mpegparse * parser);

// free resources
void mpegparse_shutdown(mpegparse * parser);

#endif /* _MPEGPARSE_H_ */
