/// @brief Indexes the file
/// @return The number of frames found in the file
/// This function goes through the file, finds and parses all file and frame headers,
/// and creates a seek table that lists the byte positions of all frames so seeking
/// can easily be done.
int YUV4MPEGVideoProvider::IndexFile() {
	int framecount = 0;

	// the ParseFileHeader() call in LoadVideo() will already have read
	// the file header for us and set the seek position correctly
	while (true) {
		int64_t curpos = ftello(sf); // update position
		if (curpos < 0)
			throw VideoOpenError("IndexFile: ftello failed");

		// continue reading headers until no more are found
		std::vector<std::string> tags = ReadHeader(curpos);
		curpos = ftello(sf);
		if (curpos < 0)
			throw VideoOpenError("IndexFile: ftello failed");

		if (tags.empty())
			break; // no more headers

		Y4M_FrameFlags flags = Y4M_FFLAG_NOTSET;
		if (tags.front() == "YUV4MPEG2") {
			ParseFileHeader(tags);
			continue;
		}
		else if (tags.front() == "FRAME")
			flags = ParseFrameHeader(tags);

		if (flags == Y4M_FFLAG_NONE) {
			framecount++;
			seek_table.push_back(curpos);
			// seek to next frame header start position
			if (fseeko(sf, frame_sz, SEEK_CUR))
				throw VideoOpenError("IndexFile: failed seeking to position " + std::to_string(curpos + frame_sz));
		}
		else {
			/// @todo implement rff flags etc
		}
	}

	return framecount;
}
////////////////////////////////////////////////////////////////////////////
///
/// Parse the frame header and store the results for when we emit the frame.
///
FrameParserStatus_t   FrameParser_AudioMlp_c::ReadHeaders( void )
{
FrameParserStatus_t Status;

    //
    // Perform the common portion of the read headers function
    //

    FrameParser_Audio_c::ReadHeaders();

//

    Status = ParseFrameHeader( BufferData, &ParsedFrameHeader, BufferLength );
    if( Status != FrameParserNoError )
    {
    	FRAME_ERROR("Failed to parse frame header, bad collator selected?\n");
    	return Status;
    }
    
    if (ParsedFrameHeader.Length != BufferLength)
    {
    	FRAME_ERROR("Buffer length is inconsistant with frame header, bad collator selected?\n");
    	return FrameParserError;
    }

    FrameToDecode = true;

    if( CurrentStreamParameters.AccumulatedFrameNumber != ParsedFrameHeader.AudioFrameNumber )
    {
    	Status = GetNewStreamParameters( (void **) &StreamParameters );
    	if( Status != FrameParserNoError )
    	{
    	    FRAME_ERROR( "Cannot get new stream parameters\n" );
    	    return Status;
    	}
    	        
        StreamParameters->AccumulatedFrameNumber = ParsedFrameHeader.AudioFrameNumber;
	CurrentStreamParameters.AccumulatedFrameNumber = ParsedFrameHeader.AudioFrameNumber;

        UpdateStreamParameters = true;
    }

    Status = GetNewFrameParameters( (void **) &FrameParameters );
    if( Status != FrameParserNoError )
    {
    	FRAME_ERROR( "Cannot get new frame parameters\n" );
    	return Status;
    }

    // Nick inserted some default values here
    ParsedFrameParameters->FirstParsedParametersForOutputFrame          = true;
    ParsedFrameParameters->FirstParsedParametersAfterInputJump          = FirstDecodeAfterInputJump;
    ParsedFrameParameters->SurplusDataInjected                          = SurplusDataInjected;
    ParsedFrameParameters->ContinuousReverseJump                        = ContinuousReverseJump;
    ParsedFrameParameters->KeyFrame                                     = true;
    ParsedFrameParameters->ReferenceFrame                               = false;

    ParsedFrameParameters->NewFrameParameters		 = true;
    ParsedFrameParameters->SizeofFrameParameterStructure = sizeof(MlpAudioFrameParameters_t);
    ParsedFrameParameters->FrameParameterStructure       = FrameParameters;
    
    ParsedAudioParameters->Source.BitsPerSample = 0; // filled in by codec
    ParsedAudioParameters->Source.ChannelCount = 0;  // filled in by codec
    ParsedAudioParameters->Source.SampleRateHz = MlpSamplingFreq[ParsedFrameHeader.SamplingFrequency];
    ParsedAudioParameters->SampleCount = ParsedFrameHeader.NumberOfSamples;
    ParsedAudioParameters->Organisation = 0; // filled in by codec
    
    return FrameParserNoError;
}
////////////////////////////////////////////////////////////////////////////
///
/// Parse the frame header and store the results for when we emit the frame.
///
FrameParserStatus_t   FrameParser_AudioLpcm_c::ReadHeaders(void)
{
	FrameParserStatus_t Status;
	LpcmAudioParsedFrameHeader_t ParsedFrameHeader;
	FRAME_DEBUG(">><<\n");
	//
	// Perform the common portion of the read headers function
	//
	FrameParser_Audio_c::ReadHeaders();
	//
	// the frame type is required to (re)parse the private data area
	ParsedFrameHeader.Type = StreamType;
	Status = ParseFrameHeader(BufferData, &ParsedFrameHeader, BufferLength);
	if (Status != FrameParserNoError)
	{
		FRAME_ERROR("Failed to parse frame header, bad collator selected?\n");
		return Status;
	}
	if ((ParsedFrameHeader.Length + AudioPesPrivateDataLength[ParsedFrameHeader.Type]) != BufferLength)
	{
		FRAME_ERROR("Buffer length (%d) is inconsistent with frame header (%d), bad collator selected?\n",
					BufferLength, ParsedFrameHeader.Length);
		return FrameParserError;
	}
	FrameToDecode = true;
	Status = GetNewFrameParameters((void **) &FrameParameters);
	if (Status != FrameParserNoError)
	{
		FRAME_ERROR("Cannot get new frame parameters\n");
		return Status;
	}
	// Nick inserted some default values here
	ParsedFrameParameters->FirstParsedParametersForOutputFrame          = true;
	ParsedFrameParameters->FirstParsedParametersAfterInputJump          = FirstDecodeAfterInputJump;
	ParsedFrameParameters->SurplusDataInjected                          = SurplusDataInjected;
	ParsedFrameParameters->ContinuousReverseJump                        = ContinuousReverseJump;
	ParsedFrameParameters->KeyFrame                                     = true;
	ParsedFrameParameters->ReferenceFrame                               = false;
	ParsedFrameParameters->NewFrameParameters        = true;
	ParsedFrameParameters->SizeofFrameParameterStructure = sizeof(LpcmAudioFrameParameters_t);
	ParsedFrameParameters->FrameParameterStructure       = FrameParameters;
	FrameParameters->DrcCode = ParsedFrameHeader.DrcCode;
	FrameParameters->NumberOfSamples = ParsedFrameHeader.NumberOfSamples;
	ParsedFrameParameters->DataOffset = AudioPesPrivateDataLength[ParsedFrameHeader.Type];
	// A SetGlobal Comand needs to be sent to update the frame parameters,
	// if some important part of the frame have been modified
	if ((CurrentStreamParameters.WordSize1 != ParsedFrameHeader.WordSize1) ||
			(CurrentStreamParameters.EmphasisFlag != ParsedFrameHeader.EmphasisFlag) ||
			(CurrentStreamParameters.MuteFlag != ParsedFrameHeader.MuteFlag) ||
			(CurrentStreamParameters.NumberOfChannels != ParsedFrameHeader.NumberOfChannels) ||
			(CurrentStreamParameters.SamplingFrequency1 != ParsedFrameHeader.SamplingFrequency1) ||
			(CurrentStreamParameters.Type == TypeLpcmInvalid))
	{
		UpdateStreamParameters = true;
		Status = GetNewStreamParameters((void **) &StreamParameters);
		if (Status != FrameParserNoError)
		{
			FRAME_ERROR("Cannot get new stream parameters\n");
			return Status;
		}
		memcpy(StreamParameters, &ParsedFrameHeader, sizeof(LpcmAudioStreamParameters_t));
		memcpy(&CurrentStreamParameters, &ParsedFrameHeader, sizeof(LpcmAudioStreamParameters_t));
	}
	else
	{
		UpdateStreamParameters = false;
	}
	ParsedAudioParameters->Source.BitsPerSample = 0; // filled in by codec
	ParsedAudioParameters->Source.ChannelCount = 0;  // filled in by codec
	ParsedAudioParameters->Source.SampleRateHz = LpcmDVDSamplingFreq[ParsedFrameHeader.SamplingFrequency1];
	ParsedAudioParameters->SampleCount = ParsedFrameHeader.NumberOfSamples;
	ParsedAudioParameters->Organisation = 0; // filled in by codec
	return FrameParserNoError;
}
////////////////////////////////////////////////////////////////////////////
///
/// Parse the frame header and store the results for when we emit the frame.
///
FrameParserStatus_t   FrameParser_AudioAac_c::ReadHeaders(void)
{
	FrameParserStatus_t Status;
	//
	// Perform the common portion of the read headers function
	//
	FrameParser_Audio_c::ReadHeaders();
	//
	// save the previous frame parameters
	AacAudioParsedFrameHeader_t LastParsedFrameHeader;
	memcpy(&LastParsedFrameHeader, &ParsedFrameHeader, sizeof(AacAudioParsedFrameHeader_t));
	Status = ParseFrameHeader(BufferData, &ParsedFrameHeader, BufferLength, AAC_GET_FRAME_PROPERTIES, true);
	if (Status != FrameParserNoError)
	{
		if (Status == FrameParserHeaderUnplayable)
		{
			NumHeaderUnplayableErrors++;
			if (NumHeaderUnplayableErrors >= UnplayabilityThreshold)
			{
				// this is clearly not a passing bit error
				FRAME_ERROR("Too many unplayability reports, marking stream unplayable\n");
				Player->MarkStreamUnPlayable(Stream);
			}
		}
		else
		{
			FRAME_ERROR("Failed to parse frame header, bad collator selected?\n");
		}
		return Status;
	}
	if (ParsedFrameHeader.Length != BufferLength)
	{
		FRAME_ERROR("Buffer length is inconsistent with frame header, bad collator selected?\n");
		return FrameParserError;
	}
	if (isFirstFrame)
	{
		isFirstFrame = false;
		FRAME_TRACE("AAC Frame type: %s, FrameSize %d, Number of samples: %d, SamplingFrequency %d, \n",
					FrameTypeName[ParsedFrameHeader.Type],
					ParsedFrameHeader.Length,
					ParsedFrameHeader.NumberOfSamples,
					ParsedFrameHeader.SamplingFrequency);
	}
	if ((ParsedFrameHeader.SamplingFrequency == 0) || (ParsedFrameHeader.NumberOfSamples == 0))
	{
		// the current frame has no such properties, we must refer to the previous frame...
		if ((LastParsedFrameHeader.SamplingFrequency == 0) || (LastParsedFrameHeader.NumberOfSamples == 0))
		{
			// the previous frame has no properties either, we cannot decode this frame...
			FrameToDecode = false;
			FRAME_ERROR("This frame should not be sent for decode (it relies on previous frame for audio parameters)\n");
			return FrameParserError;
		}
		else
		{
			FrameToDecode = true;
			// make the previous frame properties the current ones..
			memcpy(&ParsedFrameHeader, &LastParsedFrameHeader, sizeof(AacAudioParsedFrameHeader_t));
		}
	}
	else
	{
		FrameToDecode = true;
	}
	NumHeaderUnplayableErrors = 0;
	Status = GetNewFrameParameters((void **) &FrameParameters);
	if (Status != FrameParserNoError)
	{
		FRAME_ERROR("Cannot get new frame parameters\n");
		return Status;
	}
	// Nick inserted some default values here
	ParsedFrameParameters->FirstParsedParametersForOutputFrame          = true;
	ParsedFrameParameters->FirstParsedParametersAfterInputJump          = FirstDecodeAfterInputJump;
	ParsedFrameParameters->SurplusDataInjected                          = SurplusDataInjected;
	ParsedFrameParameters->ContinuousReverseJump                        = ContinuousReverseJump;
	ParsedFrameParameters->KeyFrame                                     = true;
	ParsedFrameParameters->ReferenceFrame                               = false;
	ParsedFrameParameters->NewFrameParameters        = true;
	ParsedFrameParameters->SizeofFrameParameterStructure = sizeof(AacAudioFrameParameters_t);
	ParsedFrameParameters->FrameParameterStructure       = FrameParameters;
	FrameParameters->FrameSize = ParsedFrameHeader.Length;
	FrameParameters->Type     = ParsedFrameHeader.Type;
	ParsedAudioParameters->Source.BitsPerSample = 0; // filled in by codec
	ParsedAudioParameters->Source.ChannelCount = 0;  // filled in by codec
	ParsedAudioParameters->Source.SampleRateHz = ParsedFrameHeader.SamplingFrequency;
	ParsedAudioParameters->SampleCount = ParsedFrameHeader.NumberOfSamples;
	ParsedAudioParameters->Organisation = 0; // filled in by codec
	return FrameParserNoError;
}
////////////////////////////////////////////////////////////////////////////
///
/// Parse the frame header and store the results for when we emit the frame.
///
FrameParserStatus_t   FrameParser_AudioAvs_c::ReadHeaders( void )
{
FrameParserStatus_t Status;
unsigned int ExtensionLength;

    //
    // Perform the common portion of the read headers function
    //

    FrameParser_Audio_c::ReadHeaders();

//

    Status = ParseFrameHeader( BufferData, &ParsedFrameHeader );
    if( Status != FrameParserNoError )
    {
    	FRAME_ERROR("Failed to parse frame header, bad collator selected?\n");
    	return Status;
    }
    
    if (ParsedFrameHeader.Length != BufferLength)
    {
	// if the length is wrong that might be because we haven't considered any extensions
	Status = ParseExtensionHeader( BufferData + ParsedFrameHeader.Length, &ExtensionLength );
	
	if( ( Status != FrameParserNoError ) ||
            ( ParsedFrameHeader.Length + ExtensionLength != BufferLength ) )
        {
	    FRAME_ERROR("Buffer length is inconsistant with frame header, bad collator selected?\n");
    	    return FrameParserError;
        }
	
	// that was it, adjust the recorded frame length accordingly
	ParsedFrameHeader.Length += ExtensionLength;
    }

    FrameToDecode = true;
 
    if( CurrentStreamParameters.Layer != ParsedFrameHeader.Layer )
    {
    	Status = GetNewStreamParameters( (void **) &StreamParameters );
    	if( Status != FrameParserNoError )
    	{
    	    FRAME_ERROR( "Cannot get new stream parameters\n" );
    	    return Status;
    	}
    	        
        StreamParameters->Layer = CurrentStreamParameters.Layer = ParsedFrameHeader.Layer;
        
        UpdateStreamParameters = true;
    }

    Status = GetNewFrameParameters( (void **) &FrameParameters );
    if( Status != FrameParserNoError )
    {
    	FRAME_ERROR( "Cannot get new frame parameters\n" );
    	return Status;
    }

    // Nick inserted some default values here
    ParsedFrameParameters->FirstParsedParametersForOutputFrame          = true;
    ParsedFrameParameters->FirstParsedParametersAfterInputJump          = FirstDecodeAfterInputJump;
    ParsedFrameParameters->SurplusDataInjected                          = SurplusDataInjected;
    ParsedFrameParameters->ContinuousReverseJump                        = ContinuousReverseJump;
    ParsedFrameParameters->KeyFrame                                     = true;
    ParsedFrameParameters->ReferenceFrame                               = false;

    ParsedFrameParameters->NewFrameParameters		 = true;
    ParsedFrameParameters->SizeofFrameParameterStructure = sizeof(MpegAudioFrameParameters_t);
    ParsedFrameParameters->FrameParameterStructure       = FrameParameters;
    
    // this does look a little pointless but I don't want to trash it until we
    // have got a few more audio formats supported (see \todo in mpeg_audio.h).    
    FrameParameters->BitRate = ParsedFrameHeader.BitRate;
    FrameParameters->FrameSize = ParsedFrameHeader.Length;

    ParsedAudioParameters->Source.BitsPerSample = 0; // filled in by codec
    ParsedAudioParameters->Source.ChannelCount = 0;  // filled in by codec
    ParsedAudioParameters->Source.SampleRateHz = ParsedFrameHeader.SamplingFrequency;
    ParsedAudioParameters->SampleCount = ParsedFrameHeader.NumberOfSamples;
    ParsedAudioParameters->Organisation = 0; // filled in by codec
    
    return FrameParserNoError;
}