


#include <linux/string.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include "mtk_mvd_bitstream.h"
#include "mtk_mvd_vdec_types.h"
#include "mtk_mvd_parser_hal.h"

#define BITSTREAM_MIN(A, B)                   (((A) < (B)) ? (A) : (B))
#define BITSTREAM_MAX(A, B)                   (((A) > (B)) ? (A) : (B))
//#define BITSTREAM_DBG               pr_debug
#define BITSTREAM_DBG(frm, ...)
//#define BITSTREAM_INFO              pr_info
#define BITSTREAM_INFO(frm, ...)
#define BITSTREAM_ERR               pr_err

static unsigned int readerESUpperBound(VdecESReader *reader)
{
	return reader->es_upper_bound;
}

static unsigned int readerESLowerBound(VdecESReader *reader)
{
	return reader->es_lower_bound;
}

static void readerResetESBoundary(VdecESReader *reader)
{
	reader->es_lower_bound = 0;
	reader->es_upper_bound = reader->es_buffer_length;
}

void readerUpdateEsBufStart(VdecESReader *reader, void *es_buffer_start, uint64_t es_buffer_start_pa)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[vpas] change ES buffer start %p pa 0x"PRIu64"\n", es_buffer_start, es_buffer_start_pa);

	reader->es_buffer_start = es_buffer_start;
	reader->es_buffer_start_pa = es_buffer_start_pa;
}

void readerInit(VdecESReader *reader, void *es_buffer_start, unsigned int es_buffer_length,
		uint64_t es_buffer_start_pa, int tsp_mode, void *bdma_channel)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_ERROR, "[vpas] ES buffer start %p length 0x%x tsp %d\n", es_buffer_start,
		       es_buffer_length, tsp_mode);

	reader->es_buffer_start = es_buffer_start;
	reader->es_buffer_length = es_buffer_length;
	reader->es_buffer_start_pa = es_buffer_start_pa;
	reader->tsp_mode = tsp_mode;
	reader->base_offset = INVALID_READER_OFFSET;
	reader->last_au_offset = INVALID_READER_OFFSET;
	reader->invalid_end_offset = INVALID_READER_OFFSET;
	readerResetESBoundary(reader);
#ifdef USE_BDMA
	if (IS_BDMA()) {
		reader->bdma_channel = bdma_channel;
		if (bdma_channel == NULL)
			PAS_DEBUG_LOG(PAS_LOG_LEVEL_ERROR, "[%s] %d  bdma_channel == NULL \n", __func__, __LINE__);
	}
#endif
}

static unsigned int add_offset(VdecESReader *reader, unsigned int offset,
			       unsigned int offset_addition)
{
	unsigned int result = offset + offset_addition;

	while (result > readerESUpperBound(reader))
		result = result - readerESUpperBound(reader) + readerESLowerBound(reader);
	return result;
}

static unsigned int subtract_offset(VdecESReader *reader, unsigned int offset,
				    unsigned int offset_subtraction)
{
	if (offset >= offset_subtraction + readerESLowerBound(reader)) {
		offset =  offset - offset_subtraction;
		while (offset >= readerESUpperBound(reader))
			offset = offset - readerESUpperBound(reader) + readerESLowerBound(reader);
	}
	else
		return offset +
		       (readerESUpperBound(reader) - readerESLowerBound(reader)) -
		       offset_subtraction;

	return offset;
}

void readerResetESInfo(VdecESReader *reader)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[vpas] reset ES\n");

	reader->base_offset = INVALID_READER_OFFSET;
	reader->last_au_offset = INVALID_READER_OFFSET;
	reader->read_offset_esb = 0;
	reader->available_end_offset = 0;
	reader->length_read_byte = 0;
}

void readerSetESInfo(VdecESReader *reader, unsigned int base_offset, unsigned int length_byte,
		     int incomplete)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[vpas] set ES base offset 0x%x len 0x%x incomplete %d\n", (int)base_offset,
		       length_byte, incomplete);

	reader->base_offset = base_offset;
	reader->read_offset_esb = base_offset;
	reader->available_end_offset = add_offset(reader, base_offset, length_byte);
	reader->length_read_byte = 0;
	reader->last_au_offset = INVALID_READER_OFFSET;
	reader->data_incomplete = incomplete;
	// reset ES boundry to whole ES buffer since partial ES buffer is only used when incomplete AU and it wraps around
	// reset it when we have another AU
	readerResetESBoundary(reader);
}

void readerPrintEsInfo(VdecESReader *reader)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_ERROR, "[Reader] base 0x%x esb 0x%x end 0x%x bound 0x%x ~ 0x%x es_buffer_start 0x%llx\n",
		reader->base_offset,
		reader->read_offset_esb,
		reader->available_end_offset,
		reader->es_lower_bound,
		reader->es_upper_bound,
		(unsigned long long)(size_t)(reader->es_buffer_start)
		);
}

int readerGetDataIncomplete(VdecESReader *reader)
{
	return reader->data_incomplete;
}

unsigned int readerGetDataEndOffset(VdecESReader *reader)
{
	return reader->available_end_offset;
}

int readerIsValidBase(VdecESReader *reader)
{
	return reader->base_offset != INVALID_READER_OFFSET;
}

unsigned int readerGetFreeSize(VdecESReader *reader)
{
	// if available_end_offset == read_offset_esb it means no more data that is all buffer is free
	if (reader->available_end_offset == reader->read_offset_esb)
		return readerESUpperBound(reader) - readerESLowerBound(reader);
	else
		return readerGetESOffsetDiff(reader, reader->available_end_offset,
					     reader->read_offset_esb);
}

void readerAddES(VdecESReader *reader, unsigned int base_offset, unsigned int length_byte,
		 int incomplete)
{
	unsigned int free_size;

	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING,
		"[vpas] add ES BS offset 0x%x len 0x%x, cur end 0x%x read offset 0x%x, incomplete %d\n",
		base_offset, length_byte, reader->available_end_offset, reader->read_offset_esb,
		incomplete);
	if (base_offset != INVALID_READER_OFFSET && base_offset != reader->available_end_offset) {
		if (base_offset == 0) {
			reader->es_upper_bound = reader->available_end_offset;
			reader->es_lower_bound = base_offset;
			// adjust if read point is not within boundry
			reader->read_offset_esb = add_offset(reader, reader->read_offset_esb, 0);
			PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[vpas] set lower 0x%x upper 0x%x read offset 0x%x\n",
						reader->es_lower_bound, reader->es_upper_bound,
						reader->read_offset_esb);
		} else {
			if (reader->invalid_end_offset != reader->available_end_offset) {
				PAS_DEBUG_LOG(PAS_LOG_LEVEL_ERROR,
					"[vpas] invalid offset, base_offset 0x%x avilable_end_offset 0x%x!!!\n",
						base_offset, reader->available_end_offset);
				reader->invalid_end_offset = reader->available_end_offset;
			}
			return;
		}
	} else if (!reader->tsp_mode) {
		//for broken by us case
		if ((base_offset + length_byte) > reader->es_upper_bound &&
		    (base_offset + length_byte) < reader->es_buffer_length) {
			PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING,
				"[vpas] extend es_upper_bound from 0x%x to 0x%x !!\n",
				reader->es_upper_bound, (base_offset + length_byte));
			reader->es_upper_bound = (base_offset + length_byte);
		}
	}

	if (length_byte) {
		PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "current 0x%x add 0x%x\n",
			reader->available_end_offset, length_byte);
	}
	free_size = readerGetFreeSize(reader);
	// free_size should not be zero
	if (free_size && length_byte >= free_size) {
		BITSTREAM_ERR("[readerAddES] error! length 0x%x is not smaller than free size 0x%x!!!\n",
			      length_byte, free_size);
		length_byte = free_size - 1;
	}
	reader->available_end_offset =
	    add_offset(reader, reader->available_end_offset, length_byte);
	reader->data_incomplete = incomplete;
}

unsigned int readerGetAvailSize(VdecESReader *reader)
{
	return readerGetESOffsetDiff(reader, reader->read_offset_esb, reader->available_end_offset);
}

unsigned int readerPeekByte(VdecESReader *reader, void *buffer, unsigned int length_byte)
{
	unsigned int copy_size;

	unsigned char *char_buffer;
	unsigned char *uncached_base;
	unsigned int wrap_around_size = 0;

	if (readerGetAvailSize(reader) < length_byte)
		length_byte = readerGetAvailSize(reader);

	if (length_byte == 0)
		return 0;

	char_buffer = buffer;
	uncached_base = reader->read_offset_esb + (unsigned char *)reader->es_buffer_start;

	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[%s] %d  read_offset_esb = 0x%llx es_buffer_start = 0x%llx Bound 0x%llx ~ 0x%llx  base_offset 0x%llx length_byte %d\n",__FUNCTION__,__LINE__,
		(unsigned long long)reader->read_offset_esb,
		(unsigned long long)(size_t)(reader->es_buffer_start),
		(unsigned long long)readerESUpperBound(reader),
		(unsigned long long)readerESLowerBound(reader),
		(unsigned long long)reader->base_offset,
		length_byte
		);

	// check if we wrap around
	if (reader->read_offset_esb + length_byte > readerESUpperBound(reader)) {
		wrap_around_size =
		    reader->read_offset_esb + length_byte - readerESUpperBound(reader);
		BITSTREAM_INFO
		    ("wrap around size %d, read offset 0x%x base 0x%x read byte 0x%x es length 0x%x\n",
		     wrap_around_size, reader->read_offset_esb, reader->base_offset,
		     reader->length_read_byte, readerESUpperBound(reader));
	}

	copy_size = length_byte - wrap_around_size;
	if (copy_size > length_byte || length_byte < wrap_around_size) {
		BITSTREAM_ERR("[%s] %d  copy_size %d length_byte %d wrap_around_size %d\n",
			__func__, __LINE__, copy_size, length_byte, wrap_around_size);
	} else {
		if (copy_size) {
			PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[%s] %d  copy_size %d uncached_base 0x%llx\n",
				__func__, __LINE__, copy_size, (unsigned long long)(size_t)uncached_base);
			memcpy(char_buffer, uncached_base, copy_size);
		}
	}

	if (copy_size + wrap_around_size > length_byte || wrap_around_size > length_byte) {
		BITSTREAM_ERR("[%s] %d  copy_size %d length_byte %d wrap_around_size %d\n",
			__func__, __LINE__, copy_size, length_byte, wrap_around_size);
	} else {
		if (wrap_around_size) {
			unsigned char *uncached_es_start =
			    (unsigned char *)reader->es_buffer_start + readerESLowerBound(reader);

			PAS_DEBUG_LOG(PAS_LOG_LEVEL_ERROR, "[%s] %d  wrap_around_size %d uncached_es_start 0x%llx\n",
				__func__, __LINE__, wrap_around_size, (unsigned long long)(size_t)uncached_es_start);

			memcpy(char_buffer + copy_size, uncached_es_start, wrap_around_size);
		}
	}

	return length_byte;
}

unsigned int readerSkipByte(VdecESReader *reader, unsigned int length_byte)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "skip 0x%x at offset 0x%x readByte 0x%x\n",
			length_byte, readerGetReadByte(reader), reader->read_offset_esb);
	if (readerGetAvailSize(reader) < length_byte)
		length_byte = readerGetAvailSize(reader);

	//Note: length_read_byte is a counter that is allowed to overflow or underflow. No need extra checking here!
	reader->length_read_byte += length_byte;
	reader->read_offset_esb = add_offset(reader, reader->read_offset_esb, length_byte);

	return length_byte;
}

unsigned int readerRewindByte(VdecESReader *reader, unsigned int length_byte)
{
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING,
		"rewind 0x%x at offset 0x%x avail end 0x%x readByte 0x%x free 0x%x\n",
		length_byte, reader->read_offset_esb, reader->available_end_offset,
		readerGetReadByte(reader), readerGetFreeSize(reader));

	// only check when wrap around is possible
	if (reader->data_incomplete) {
		unsigned int free_size;

		// example. es_buffer_length = 8, read_offset_esb = 6, available_end_offset = 1
		// in this case, free size = 5 (offset 1, 2, 3, 4 ,5)
		//              avail size = 3 (offset 6, 7, 0)
		// acceptable rewind length = 0, 1, 2, 3, 4
		// if we rewind 5, it makes read_offset_esb = available_end_offset = 5 which means there is no available data

		free_size =
		    readerGetESOffsetDiff(reader, reader->available_end_offset, reader->read_offset_esb);
		if (free_size && length_byte >= free_size) {
			BITSTREAM_ERR("[readerRewindByte] error! rewind 0x%x is not smaller than free size 0x%x!!!\n",
				      length_byte, free_size);
			length_byte = free_size - 1;
		}
	}
	//Note: length_read_byte is a counter that is allowed to overflow or underflow. No need extra checking here!
	reader->length_read_byte -= length_byte;
	reader->read_offset_esb = subtract_offset(reader, reader->read_offset_esb, length_byte);

	return length_byte;
}


// the value could overflow, use with caution
unsigned int readerGetReadByte(VdecESReader *reader)
{
	return reader->length_read_byte;
}

// get the read pointer with target_offset
unsigned int readerGetReadOffset(VdecESReader *reader, int target_offset)
{
	if (target_offset == 0)
		return reader->read_offset_esb;
	if (target_offset > 0) {
		return add_offset(reader, reader->read_offset_esb, target_offset);
	} else {
		unsigned int rewind_offset = -target_offset;

		return subtract_offset(reader, reader->read_offset_esb, rewind_offset);
	}
}

unsigned int readerGetESOffsetDiff(VdecESReader *reader, unsigned int start_offset,
				   unsigned int end_offset)
{
	if (end_offset >= start_offset)
		return end_offset - start_offset;
	else
		return (readerESUpperBound(reader) - readerESLowerBound(reader)) - (start_offset -
										    end_offset);
}

static const uint8_t start_code_3byte[3] = { 0, 0, 1 };

//#define PROFILE_SEEK_AU


static int check_start_code_at_read_offset(VdecESReader *reader)
{
	unsigned char *uncached_base;

	// check if we wrap around
	if (reader->read_offset_esb + sizeof(start_code_3byte) > readerESUpperBound(reader)) {
		uint8_t temp[sizeof(start_code_3byte)] = {0};

		readerPeekByte(reader, temp, sizeof(start_code_3byte));
		return memcmp(temp, start_code_3byte, sizeof(start_code_3byte));
	} else {
		uncached_base = reader->read_offset_esb + (unsigned char *)reader->es_buffer_start;
		return memcmp(uncached_base, start_code_3byte, sizeof(start_code_3byte));
	}
}

static void readerSWParse(VdecESReader *reader, unsigned int *skip_offset, int *found)
{
	unsigned char *found_ptr;
	unsigned char *uncached_base =
		reader->read_offset_esb + (unsigned char *)reader->es_buffer_start;

	if (reader->read_offset_esb + readerGetAvailSize(reader) > readerESUpperBound(reader)) {
		unsigned int available_size =
			(readerESUpperBound(reader) - reader->read_offset_esb);

		BITSTREAM_ERR("[%s] %d memchr wrap esb 0x%x avail 0x%x upper 0x%x\n",
			__func__, __LINE__,
			reader->read_offset_esb,
			readerGetAvailSize(reader), readerESUpperBound(reader));

		found_ptr = memchr(uncached_base, 0x1, available_size);
		if (found_ptr != NULL) {
			*found = 1;
			*skip_offset = (uintptr_t)(found_ptr - uncached_base);
			BITSTREAM_ERR("[%s] %d memchr wrap skip_offset 0x%x\n",
				__func__, __LINE__, *skip_offset);
		} else {
			unsigned char *uncached_start_base =
				(unsigned char *) reader->es_buffer_start;

			available_size = readerGetAvailSize(reader) - available_size;
			found_ptr = memchr(uncached_start_base, 0x1, available_size);

			if (found_ptr != NULL) {
				*found = 1;
				*skip_offset =
					(uintptr_t)
					(found_ptr - uncached_start_base +
					(readerESUpperBound(reader) -
					 reader->read_offset_esb));
				BITSTREAM_ERR("[%s] %d memchr wrap skip_offset 0x%x\n",
					__func__, __LINE__, *skip_offset);
			} else
				*found = 0;
		}
	} else {
		found_ptr = memchr(uncached_base, 0x1, readerGetAvailSize(reader));
		if (found_ptr != NULL) {
			*found = 1;
			*skip_offset = (uintptr_t)(found_ptr - uncached_base);
		} else
			*found = 0;
	}
}

static void readersetFrameInfo(VdecESReader *reader, VdecFrameInfo *frame_info)
{
	#define PARTITION_NUM_ONE 1
	#define PARTITION_NUM_TWO 2
	if (reader->last_au_offset <= reader->read_offset_esb) {
		frame_info->offset[0] = reader->last_au_offset;
		frame_info->length[0] =
		    readerGetESOffsetDiff(reader, reader->last_au_offset, reader->read_offset_esb);
		frame_info->partition_num = PARTITION_NUM_ONE;
	} else {
		frame_info->offset[0] = reader->last_au_offset;
		frame_info->length[0] = readerESUpperBound(reader) - reader->last_au_offset;
		frame_info->offset[1] = readerESLowerBound(reader);
		frame_info->length[1] = reader->read_offset_esb - readerESLowerBound(reader);
		if (frame_info->length[1] == 0)
			frame_info->partition_num = PARTITION_NUM_ONE;
		else
			frame_info->partition_num = PARTITION_NUM_TWO;
	}
}

int readerSeekAU(VdecESReader *reader, VdecFrameInfo *frame_info)
{
	uint8_t temp = 0;
	int comp_ret;
#ifdef PROFILE_SEEK_AU
	struct timespec64 start, end;

	ktime_get_real_ts64(&start);
#endif // PROFILE_SEEK_AU
#define REWIND_TO_01_GAP 1

	frame_info->offset[0] = frame_info->offset[1] = 0;
	frame_info->length[0] = frame_info->length[1] = 0;
	frame_info->partition_num = 0;

	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[%s] %d  read_offset_esb = 0x%llx es_buffer_start = 0x%llx Bound 0x%llx ~ 0x%llx  base_offset 0x%x last_au_offset 0x%x available 0x%x\n",
		__FUNCTION__,__LINE__,
		(unsigned long long)reader->read_offset_esb,
		(unsigned long long)(size_t)reader->es_buffer_start,
		(unsigned long long)readerESUpperBound(reader),
		(unsigned long long)readerESLowerBound(reader),
		reader->base_offset,
		reader->last_au_offset,
		readerGetAvailSize(reader)
		);

	if (reader->last_au_offset != INVALID_READER_OFFSET
	    && reader->last_au_offset == reader->read_offset_esb) {
		// we should be at the start of start code
		// when starting position is at the end, there is no more data and of course no AU could be found
		if (readerGetAvailSize(reader) < NUM_3)
			goto NOT_FOUND;
		comp_ret = check_start_code_at_read_offset(reader);
		if (comp_ret == 0) {
			// skip 3 byte since we alread found this start code
			readerSkipByte(reader, sizeof(start_code_3byte));
		} else {
			BITSTREAM_INFO
			    ("WARNING, not nal boundry, last nal 0x%x read offset 0x%x\n",
			     reader->last_au_offset, reader->read_offset_esb);
		}
	}

	while (readerGetAvailSize(reader)) {
		if (reader->read_offset_esb <= reader->available_end_offset) {
			unsigned int skip_offset = 0;
			int found;

#ifdef USE_BDMA
			if (IS_BDMA() && reader->bdma_channel) {
				unsigned int searchoffset = 0;
				unsigned int searchstart = reader->read_offset_esb;
				unsigned int searchsize = readerGetAvailSize(reader);
				int bdma_ret;
				if (reader->last_au_offset != INVALID_READER_OFFSET &&
					reader->last_au_offset + sizeof(start_code_3byte)
					<= reader->read_offset_esb) {
					reader->read_offset_esb = reader->read_offset_esb
						- sizeof(start_code_3byte) + 1;
					searchstart = reader->read_offset_esb;
					searchsize += sizeof(start_code_3byte) - 1;
					PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "[rewind] "
						"read_offset_esb: %d, last_au_offset: %d, searchsize: %d\n",
						reader->read_offset_esb, reader->last_au_offset,
						searchsize);
				}
				#define STARTCODE_PATTERN 0x00010000
				#define STARTCODE_MASK    0xff000000
				// search target is pattern & (~exclubit)
				// 0x00010000 & (0xff000000) = 0x01 00 00
				bdma_ret = mtk_bdma_dram_pattern_search(reader->bdma_channel,
					&searchoffset,
					reader->es_buffer_start_pa
					+ searchstart,
					searchsize,
					STARTCODE_PATTERN,
					STARTCODE_MASK);

				if (bdma_ret == 0) {
					// skip to 0x01
					skip_offset = searchoffset + sizeof(start_code_3byte) - REWIND_TO_01_GAP;
					found = 1;
				} else
					found = 0;
			} else
#endif
			{
				readerSWParse(reader, &skip_offset, &found);
			}
			if (!found) {
				readerSkipByte(reader, readerGetAvailSize(reader));
				break;
			} else
				readerSkipByte(reader, skip_offset);
		}

		readerPeekByte(reader, &temp, 1);
		if (temp == 0x1 && readerGetReadByte(reader) >= sizeof(start_code_3byte) - 1) {
			readerRewindByte(reader, sizeof(start_code_3byte) - 1);
			comp_ret = check_start_code_at_read_offset(reader);
			if (comp_ret == 0) {
				if (reader->last_au_offset != INVALID_READER_OFFSET) {
					goto FOUND;
				}
				reader->last_au_offset = reader->read_offset_esb;
			}

#ifdef USE_BDMA
			// skip sizeof(start_code_3byte) from start adress of start code
			readerSkipByte(reader, sizeof(start_code_3byte));
#else
			// skip sizeof(start_code_3byte) from position with val 1
			readerSkipByte(reader, sizeof(start_code_3byte) + sizeof(start_code_3byte) - 1);
#endif
		} else if (temp == 0x0)
			readerSkipByte(reader, 1);
		else
			readerSkipByte(reader, NUM_3);
	}

	if (reader->last_au_offset != INVALID_READER_OFFSET) {
		if (reader->tsp_mode == 0 && reader->data_incomplete == 0)
			goto FOUND;
	}

NOT_FOUND:

#ifdef PROFILE_SEEK_AU
	ktime_get_real_ts64(&end);
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "seek AU time %lldus\n",
		(end.tv_sec - start.tv_sec) * USEC_PER_SEC + (end.tv_nsec - start.tv_nsec) / NSEC_PER_USEC);
#endif
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "no AU in this ES\n");
	return 0;

FOUND:
	readersetFrameInfo(reader, frame_info);

#ifdef PROFILE_SEEK_AU
	ktime_get_real_ts64(&end);
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "seek AU time %lldus size %d %d\n",
		(end.tv_sec - start.tv_sec) * USEC_PER_SEC + (end.tv_nsec - start.tv_nsec) / NSEC_PER_USEC,
		frame_info->length[0], frame_info->length[1]);
#endif

	// current position is at the end of this AU, which is the start of nal header of next AU
	reader->last_au_offset = reader->read_offset_esb;
	PAS_DEBUG_LOG(PAS_LOG_LEVEL_FRAMING, "frame(%d) (offset,length) (0x%x, 0x%x) and (0x%x, 0x%x) next 0x%x\n",
		       frame_info->partition_num, frame_info->offset[0], frame_info->length[0],
		       frame_info->offset[1], frame_info->length[1], reader->last_au_offset);
	readerRewindByte(reader, frame_info->length[0] + frame_info->length[1]);

	return 1;
}

