Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8154aebb authored by Gilad Broner's avatar Gilad Broner
Browse files

media: dvb: Fix processing of indexing descriptors



While parsing indexing descriptor data it may appear that match TSP
address precedes the PUSI TSP address, in such case the PUSI TSP
address does not belong to the current recording chunk, but rather
to the previous recording chunk.
In addition, partial indexing descriptors are now processed as well,
to maximize indexing data for the current recording chunk.

Change-Id: Idbc0434724ce3a7d0b40f509f8f3e52c1fc03be5
Signed-off-by: default avatarGilad Broner <gbroner@codeaurora.org>
parent 03ccedbc
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 * Copyright (c) 2000 Nokia Research Center
 *                    Tampere, FINLAND
 *
 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
@@ -38,6 +38,8 @@
/* Common definitions */
/*--------------------------------------------------------------------------*/

#define DMX_EVENT_QUEUE_SIZE	500 /* number of events */

/*
 * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
 */
+2 −3
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
 *                    for convergence integrated media GmbH
 *
 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
@@ -70,11 +70,10 @@ struct dmxdev_sec_feed {
	struct dmx_cipher_operations cipher_ops;
};

#define DMX_EVENT_QUEUE_SIZE	500 /* number of events */
struct dmxdev_events_queue {
	/*
	 * indices used to manage events queue.
	 * read_index advanced when relevent data is read
	 * read_index advanced when relevant data is read
	 * from the buffer.
	 * notified_index is the index from which next events
	 * are returned.
+3 −2
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
 *                         for convergence integrated media GmbH
 *
 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
@@ -75,7 +75,8 @@ struct dmx_index_entry {
	struct list_head next;
};

#define DMX_IDX_EVENT_QUEUE_SIZE	100
#define DMX_IDX_EVENT_QUEUE_SIZE	DMX_EVENT_QUEUE_SIZE

struct dvb_demux_rec_info {
	/* Reference counter for number of feeds using this information */
	int ref_count;
+217 −107
Original line number Diff line number Diff line
@@ -3451,33 +3451,171 @@ static int mpq_dmx_tspp2_calc_tsp_num_delta(
	return tsp_num / (int)packet_size;
}

/**
 * mpq_dmx_tspp2_offset_in_range() - return whether some buffer offset is in
 * the given offsets range, taking wrap-around into consideration.
 *
 * @offset:	offset to check
 * @from:	range "left" boundary
 * @to:		range "right"boundary
 *
 * Return true if offset is in range, false otherwise
 */
static bool mpq_dmx_tspp2_offset_in_range(u32 offset, u32 from, u32 to)
{
	if (from <= to)
		return (offset >= from && offset < to);

	return !(offset >= to && offset < from);
}

/**
 * mpq_dmx_tspp2_match_after_pusi() - check if PUSI offset precedes the
 * TSP match offset in the recording chunk.
 *
 * @pusi:		pusi tsp offset
 * @match:		match tsp offset
 * @chunk_start:	recording chunk start offset
 * @chunk_size:		recording chunk size
 * @buffer_size:	recording buffer size
 *
 * Return true if PUSI offset precedes match offset, false otherwise
 */
static bool mpq_dmx_tspp2_match_after_pusi(u32 pusi, u32 match,
	u32 chunk_start, size_t chunk_size, size_t buffer_size)
{
	u32 end_offset = (chunk_start + chunk_size) % buffer_size;

	if ((chunk_start + chunk_size) >= buffer_size) {
		if ((pusi >= chunk_start && match >= chunk_start) ||
			(pusi < end_offset && match < end_offset))
			return (pusi <= match);

		return (pusi > match);
	}

	return (pusi <= match);
}

/**
 * mpq_dmx_tspp2_process_index_desc() - process one indexing descriptor
 * (descriptor might be partial)
 *
 * @feed:		dvb_demux feed object
 * @rec_pipe:		recording pipe info
 * @idx_desc:		indexing descriptor to process
 * @rec_data_size:	recording chunk size
 * @ts_pkt_size:	TS packet size
 */
static void mpq_dmx_tspp2_process_index_desc(struct dvb_demux_feed *feed,
	struct pipe_info *rec_pipe, struct mpq_tspp2_index_desc *idx_desc,
	size_t rec_data_size, size_t ts_pkt_size)
{
	struct dmx_index_event_info idx_event;
	struct mpq_tspp2_index_table *index_table;
	struct dvb_dmx_video_patterns_results pattern;
	u8 pattern_id;
	u8 table_id;
	int tsp_delta;
	u32 match_tsp_offset;
	u32 pusi_tsp_offset;
	u32 from = rec_pipe->tspp_write_offset;
	u32 to = (rec_pipe->tspp_write_offset + rec_data_size) %
		rec_pipe->buffer.size;

	/* Convert addresses in the indexing desc. from big-endian */
	idx_desc->matched_tsp_addr = be32_to_cpu(idx_desc->matched_tsp_addr);
	idx_desc->pusi_tsp_addr = be32_to_cpu(idx_desc->pusi_tsp_addr);
	idx_desc->last_tsp_addr = 0;	/* unused */

	idx_event.pid = feed->pid;
	idx_event.stc = mpq_dmx_tspp2_get_stc(idx_desc->stc, 7);

	pattern_id = idx_desc->pattern_id & INDEX_DESC_PATTERN_ID_MASK;
	table_id = (idx_desc->pattern_id & INDEX_DESC_TABLE_ID_MASK) >> 5;
	index_table = &mpq_dmx_tspp2_info.index_tables[table_id];
	idx_event.type = index_table->patterns[pattern_id].type;

	MPQ_DVB_DBG_PRINT(
		"%s: Index info: pattern_id=0x%x, pusi=0x%x, match=0x%x\n",
		__func__, idx_desc->pattern_id, idx_desc->pusi_tsp_addr,
		idx_desc->matched_tsp_addr);

	if (idx_desc->matched_tsp_addr &&
		idx_desc->matched_tsp_addr != ULONG_MAX) {
		match_tsp_offset =
			idx_desc->matched_tsp_addr - ts_pkt_size + 1 -
			rec_pipe->buffer.iova;
		pusi_tsp_offset =
			idx_desc->pusi_tsp_addr - rec_pipe->buffer.iova;

		tsp_delta = mpq_dmx_tspp2_calc_tsp_num_delta(
			pusi_tsp_offset, rec_pipe->tspp_write_offset,
			rec_data_size, rec_pipe->buffer.size,
			ts_pkt_size);

		/*
		 * PUSI address and match address are both in the chunk,
		 * but if PUSI address is after the match address then
		 * it is really from previous chunk.
		 */
		if (mpq_dmx_tspp2_offset_in_range(pusi_tsp_offset, from, to)
			&& !mpq_dmx_tspp2_match_after_pusi(pusi_tsp_offset,
				match_tsp_offset, rec_pipe->tspp_write_offset,
				rec_data_size, rec_pipe->buffer.size))
			idx_event.last_pusi_tsp_num =
				feed->rec_info->ts_output_count -
				((rec_pipe->buffer.size / ts_pkt_size) -
				tsp_delta);
		else
			idx_event.last_pusi_tsp_num =
				feed->rec_info->ts_output_count + tsp_delta;

		idx_event.match_tsp_num = feed->rec_info->ts_output_count +
			mpq_dmx_tspp2_calc_tsp_num_delta(
				match_tsp_offset,
				rec_pipe->tspp_write_offset, rec_data_size,
				rec_pipe->buffer.size, ts_pkt_size);
		feed->last_pattern_tsp_num = idx_event.match_tsp_num;

		MPQ_DVB_DBG_PRINT(
			"%s: PUSI tsp num=%llu, Match tsp num=%llu (tsp_delta=%d)\n",
			__func__, idx_event.last_pusi_tsp_num,
			idx_event.match_tsp_num, tsp_delta);

		pattern.info[0].type =
			index_table->patterns[pattern_id].type;
		pattern.info[0].offset = 0;
		pattern.info[0].used_prefix_size = 0;

		dvb_dmx_process_idx_pattern(feed, &pattern, 0, idx_event.stc,
			0, idx_event.match_tsp_num, 0,
			idx_event.last_pusi_tsp_num, 0);
	}
}

/**
 * mpq_dmx_tspp2_index_pipe_handler() - Handler for index pipe notifications
 *
 * @index_pipe:		pipe_info for the indexing pipe
 * @rec_pipe:			pipe_info for the recording payload pipe
 * @index_pipe:			pipe_info for the indexing pipe
 * @ts_packet_size:		Recording TS packet size
 * @event:			Notification event type
 * @rec_data_size:		Recording chunk size
 * @tspp_index_last_addr:	Index pipe last write address sampled
 *
 * Return error status
 */
static int mpq_dmx_tspp2_index_pipe_handler(struct pipe_info *rec_pipe,
	struct pipe_info *index_pipe, u32 tspp_index_last_addr,
	size_t ts_packet_size, enum mpq_dmx_tspp2_pipe_event event,
	size_t rec_data_size)
	struct pipe_info *index_pipe, size_t ts_packet_size,
	enum mpq_dmx_tspp2_pipe_event event, size_t rec_data_size,
	u32 tspp_index_last_addr)
{
	int i;
	struct dvb_demux_feed *feed;
	u32 num_desc;
	u32 desc_offset;
	struct dmx_index_event_info idx_event;
	u32 desc_leftover = 0;
	struct mpq_tspp2_feed *tspp2_feed;
	struct mpq_tspp2_index_desc index_desc;
	struct mpq_tspp2_index_table *index_table;
	struct dvb_dmx_video_patterns_results pattern;
	size_t data_size;
	u8 pattern_id;
	u8 table_id;

	if (!index_pipe->ref_count) {
		MPQ_DVB_ERR_PRINT(
@@ -3504,97 +3642,69 @@ static int mpq_dmx_tspp2_index_pipe_handler(struct pipe_info *rec_pipe,
	tspp2_feed = index_pipe->parent;
	feed = tspp2_feed->mpq_feed->dvb_demux_feed;

	/* Calculate new data in indexing pipe */
	data_size = mpq_dmx_tspp2_calc_pipe_data(index_pipe,
		tspp_index_last_addr);
	index_pipe->tspp_last_addr = tspp_index_last_addr;
	index_pipe->tspp_write_offset += data_size;
	if (index_pipe->tspp_write_offset >= index_pipe->buffer.size)
		index_pipe->tspp_write_offset -= index_pipe->buffer.size;

	/*
	 * Calculate total data to process, disregarding leftover from previous
	 * partial descriptor that was processed.
	 */
	if (index_pipe->tspp_read_offset % TSPP2_DMX_SPS_INDEXING_DESC_SIZE) {
		desc_leftover = TSPP2_DMX_SPS_INDEXING_DESC_SIZE -
			index_pipe->tspp_read_offset %
			TSPP2_DMX_SPS_INDEXING_DESC_SIZE;
		if (desc_leftover <= data_size)
			mpq_dmx_release_data(index_pipe, desc_leftover);
		else
			return 0;
	}
	data_size = mpq_dmx_calc_fullness(index_pipe->tspp_write_offset,
		index_pipe->tspp_read_offset, index_pipe->buffer.size);
	if (data_size == 0)
		return 0;

	num_desc = data_size / TSPP2_DMX_SPS_INDEXING_DESC_SIZE;
	idx_event.pid = feed->pid;
	MPQ_DVB_DBG_PRINT("%s: TS output count=%llu, last_pusi_addr=0x%X\n",
		__func__, feed->rec_info->ts_output_count,
		tspp2_feed->last_pusi_addr);

	for (i = 0; i < num_desc; i++) {
		desc_offset = index_pipe->tspp_write_offset +
			i * TSPP2_DMX_SPS_INDEXING_DESC_SIZE;
		if (desc_offset >= index_pipe->buffer.size)
			desc_offset -= index_pipe->buffer.size;
		memcpy(&index_desc, index_pipe->buffer.mem + desc_offset,
			sizeof(index_desc));

		/* Convert addresses in the indexing desc. from big-endian */
		index_desc.matched_tsp_addr =
			be32_to_cpu(index_desc.matched_tsp_addr);
		index_desc.pusi_tsp_addr =
			be32_to_cpu(index_desc.pusi_tsp_addr);
		index_desc.last_tsp_addr =
			be32_to_cpu(index_desc.last_tsp_addr);

		idx_event.pid = feed->pid;
		idx_event.stc = mpq_dmx_tspp2_get_stc(index_desc.stc, 7);

		pattern_id = index_desc.pattern_id & INDEX_DESC_PATTERN_ID_MASK;
		table_id =
			(index_desc.pattern_id & INDEX_DESC_TABLE_ID_MASK) >> 5;
		index_table = &mpq_dmx_tspp2_info.index_tables[table_id];
		idx_event.type = index_table->patterns[pattern_id].type;

	MPQ_DVB_DBG_PRINT(
			"%s: Index desc(#%d, offset=%u): id=0x%X(0x%llx), match TSP=0x%X, PUSI=0x%X, last TSP=0x%X\n",
			__func__, i, desc_offset, index_desc.pattern_id,
			idx_event.type, index_desc.matched_tsp_addr,
			index_desc.pusi_tsp_addr, index_desc.last_tsp_addr);

		if (index_desc.matched_tsp_addr) {
			u32 match_tsp_offset = index_desc.matched_tsp_addr
				- ts_packet_size + 1 - rec_pipe->buffer.iova;
			pattern_id = index_desc.pattern_id &
				INDEX_DESC_PATTERN_ID_MASK;

			idx_event.last_pusi_tsp_num =
				feed->rec_info->ts_output_count +
				mpq_dmx_tspp2_calc_tsp_num_delta(
					index_desc.pusi_tsp_addr -
					rec_pipe->buffer.iova,
					rec_pipe->tspp_write_offset,
					rec_data_size, rec_pipe->buffer.size,
					ts_packet_size);

			idx_event.match_tsp_num =
				feed->rec_info->ts_output_count +
				mpq_dmx_tspp2_calc_tsp_num_delta(
					match_tsp_offset,
					rec_pipe->tspp_write_offset,
					rec_data_size, rec_pipe->buffer.size,
					ts_packet_size);
			feed->last_pattern_tsp_num = idx_event.match_tsp_num;

		"\n%s: TS output count=%llu, desc_data=%u, desc_leftover=%u\n",
		__func__, feed->rec_info->ts_output_count, data_size,
		desc_leftover);
	MPQ_DVB_DBG_PRINT(
				"%s: PUSI tsp num=%llu, Match tsp num=%llu\n",
				__func__, idx_event.last_pusi_tsp_num,
				idx_event.match_tsp_num);
		"%s: Recording chunk: from=%u, to=%u, size=%u\n\n",
		__func__, rec_pipe->tspp_write_offset,
		(rec_pipe->tspp_write_offset + rec_data_size) %
		rec_pipe->buffer.size,
		rec_data_size);

			pattern.info[0].type =
				index_table->patterns[pattern_id].type;
			pattern.info[0].offset = 0;
			pattern.info[0].used_prefix_size = 0;
	/*
	 * Loop over the indexing descriptors and process each one.
	 * The last descriptor might be a partial descriptor (24 bytes out of
	 * 28 total) which does not contain the information where the frame/PES
	 * ends, but we don't use this field anyway so we process it too.
	 */
	while (data_size >= TSPP2_DMX_MIN_INDEXING_DESC_SIZE) {
		memcpy(&index_desc,
			index_pipe->buffer.mem + index_pipe->tspp_read_offset,
			sizeof(index_desc));

			dvb_dmx_process_idx_pattern(feed, &pattern, 0,
				idx_event.stc, 0, idx_event.match_tsp_num, 0,
				idx_event.last_pusi_tsp_num, 0);
		mpq_dmx_tspp2_process_index_desc(feed, rec_pipe, &index_desc,
			rec_data_size, ts_packet_size);
		/*
		 * Descriptor was processed - advance the index pipe read offset
		 */
		if (data_size >= TSPP2_DMX_SPS_INDEXING_DESC_SIZE) {
			mpq_dmx_release_data(index_pipe,
				TSPP2_DMX_SPS_INDEXING_DESC_SIZE);
			data_size -= TSPP2_DMX_SPS_INDEXING_DESC_SIZE;
		} else {
			mpq_dmx_release_data(index_pipe, data_size);
			data_size = 0;
		}
	}

	index_pipe->tspp_last_addr = tspp_index_last_addr;
	index_pipe->tspp_write_offset +=
		num_desc * TSPP2_DMX_SPS_INDEXING_DESC_SIZE;
	if (index_pipe->tspp_write_offset >= index_pipe->buffer.size)
		index_pipe->tspp_write_offset -= index_pipe->buffer.size;

	mpq_dmx_release_data(index_pipe,
		num_desc * TSPP2_DMX_SPS_INDEXING_DESC_SIZE);

	return 0;
}

@@ -3710,7 +3820,7 @@ static int mpq_dmx_tspp2_rec_pipe_handler(struct pipe_info *pipe_info,
	u32 tspp_last_addr;
	u32 tspp_index_last_addr;
	struct dmx_data_ready data;
	struct pipe_info *index_pipe = NULL;
	struct pipe_info *index_pipe = pipe_info->parent->secondary_pipe;
	int ret = 0;

	if (!pipe_info->ref_count || pipe_info->type != REC_PIPE) {
@@ -3739,15 +3849,15 @@ static int mpq_dmx_tspp2_rec_pipe_handler(struct pipe_info *pipe_info,
	}

	/*
	 * Sample indexing pipe before the recording pipe, to prevent indexing
	 * reported on recorded data that will be sampled only in the next
	 * iteration.
	 * Sample indexing pipe before sampling the recording pipe.
	 * This ensures indexing data refers to the current recording chunk,
	 * or the previous recording chunk (as we might still miss indexing
	 * descriptor that was written immediately after we sampled the pipe,
	 * which will be processed in the next iteration).
	 */
	if (pipe_info->parent->secondary_pipe != NULL) {
		index_pipe = pipe_info->parent->secondary_pipe;
	if (index_pipe)
		tspp2_pipe_last_address_used_get(index_pipe->handle,
			&tspp_index_last_addr);
	}

	tspp2_pipe_last_address_used_get(pipe_info->handle, &tspp_last_addr);
	data_size = mpq_dmx_tspp2_calc_pipe_data(pipe_info, tspp_last_addr);
@@ -3782,10 +3892,10 @@ static int mpq_dmx_tspp2_rec_pipe_handler(struct pipe_info *pipe_info,
		mpq_dmx_tspp2_index(feed, pipe_info, data_size, ts_packet_size);

		/* Handle HW indexing results */
		if (index_pipe != NULL)
		if (index_pipe)
			mpq_dmx_tspp2_index_pipe_handler(pipe_info, index_pipe,
				tspp_index_last_addr, ts_packet_size, event,
				data_size);
				ts_packet_size, event, data_size,
				tspp_index_last_addr);

		/*
		 * Limit indexing notification to the last TS packet in the
@@ -4353,7 +4463,7 @@ static int mpq_dmx_tspp2_allocate_index_pipe(struct dvb_demux_feed *feed)
	}

	ret = mpq_dmx_init_out_pipe(mpq_demux, pipe_info,
		TSPP2_DMX_SPS_INDEXING_MAX_BUFF_SIZE, &sps_cfg,
		TSPP2_DMX_INDEX_PIPE_BUFFER_SIZE, &sps_cfg,
		&pull_cfg, 1, ION_HEAP(tspp2_buff_heap), 0);

	if (ret) {
+8 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#define TSPP2_DMX_SPS_SECTION_DESC_SIZE		188	/* size of TS packet */
#define TSPP2_DMX_SPS_PCR_DESC_SIZE		195	/* size of PCR packet */
#define TSPP2_DMX_SPS_INDEXING_DESC_SIZE	28	/* index entry size */
#define TSPP2_DMX_MIN_INDEXING_DESC_SIZE	24	/* partial index desc */
#define TSPP2_DMX_SPS_VPES_HEADER_DESC_SIZE	(1 + 2*VPES_HEADER_DATA_SIZE)
#define TSPP2_DMX_SPS_VPES_PAYLOAD_DESC_SIZE	2048	/* Video PES payload */
#define TSPP2_DMX_SPS_NON_VID_PES_DESC_SIZE	256	/* Non-Video PES */
@@ -130,6 +131,13 @@
#define PES_ASM_STATUS_SIZE_MISMATCH	0x04
#define PES_ASM_STATUS_TX_FAILED	0x08

/*
 * Indexing header pipe should contain no more headers than is possible
 * to report.
 */
#define TSPP2_DMX_INDEX_PIPE_BUFFER_SIZE	\
	(TSPP2_DMX_SPS_INDEXING_DESC_SIZE * DMX_EVENT_QUEUE_SIZE)

#define INDEX_TABLE_PREFIX_LENGTH	3
#define INDEX_TABLE_PREFIX_VALUE	0x00000001
#define INDEX_TABLE_PREFIX_MASK		0x00FFFFFF