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

Commit 4addb3e1 authored by Gilad Broner's avatar Gilad Broner
Browse files

media: dvb: Add buffer flushing API



Automatically flushing the output buffer when buffer overflows is
not always the desired behavior as this discards pending data while
user may actually want to read the data collected so far.
Add a new module parameter to allow turning off the automatic
buffer flushing as well as a new ioctl DMX_FLUSH_BUFFER to allow
user to flush the output buffer manually.

Change-Id: I191bfcdd1e3194cd47884f0eabbbaf36b0a44f7e
Signed-off-by: default avatarGilad Broner <gbroner@codeaurora.org>
parent 3a7f80c9
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@
/*
 * enum dmx_success: Success codes for the Demux Callback API.
 */

enum dmx_success {
	DMX_OK = 0, /* Received Ok */
	DMX_OK_PES_END, /* Received OK, data reached end of PES packet */
@@ -219,6 +218,7 @@ struct dmx_ts_feed {
	int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
			char *data, size_t size);
	int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
	int (*flush_buffer)(struct dmx_ts_feed *feed, size_t length);
};

/*--------------------------------------------------------------------------*/
@@ -272,6 +272,7 @@ struct dmx_section_feed {
	int (*oob_command) (struct dmx_section_feed *feed,
				struct dmx_oob_command *cmd);
	int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
	int (*flush_buffer)(struct dmx_section_feed *feed, size_t length);
};

/*--------------------------------------------------------------------------*/
+309 −270

File changed.

Preview size limit exceeded, changes collapsed.

+57 −7
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 *		       & Marcus Metzler <marcus@convergence.de>
 *			 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
@@ -523,6 +523,7 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
	int p;
	int ccok;
	u8 cc;
	int ret;

	if (count == 0)
		return -1;
@@ -544,20 +545,24 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
		feed->pusi_seen = 1;
		feed->peslen = 0;
		feed->pes_tei_counter = 0;
		feed->pes_ts_packets_num = 0;
		feed->pes_cont_err_counter = 0;
		feed->pes_ts_packets_num = 0;
	}

	if (feed->pusi_seen == 0)
		return 0;

	feed->pes_ts_packets_num++;
	ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);

	/* Verify TS packet was copied successfully */
	if (!ret) {
		feed->pes_cont_err_counter += !ccok;
		feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;

		feed->pes_ts_packets_num++;
		feed->peslen += count;
	}

	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
	return ret;
}

static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@@ -2540,6 +2545,49 @@ static int dmx_ts_set_tsp_out_format(
	return 0;
}

/**
 * dvbdmx_ts_reset_pes_state() - Reset the current PES length and PES counters
 *
 * @feed: dvb demux feed object
 */
void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed)
{
	unsigned long flags;

	/*
	 * Reset PES state.
	 * PUSI seen indication is kept so we can get partial PES.
	 */
	spin_lock_irqsave(&feed->demux->lock, flags);

	feed->peslen = 0;
	feed->pes_tei_counter = 0;
	feed->pes_cont_err_counter = 0;
	feed->pes_ts_packets_num = 0;

	spin_unlock_irqrestore(&feed->demux->lock, flags);
}
EXPORT_SYMBOL(dvbdmx_ts_reset_pes_state);

static int dvbdmx_ts_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length)
{
	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
	struct dvb_demux *demux = feed->demux;
	int ret = 0;

	if (mutex_lock_interruptible(&demux->mutex))
		return -ERESTARTSYS;

	dvbdmx_ts_reset_pes_state(feed);

	if ((feed->ts_type & TS_DECODER) && demux->flush_decoder_buffer)
		/* Call decoder specific flushing if one exists */
		ret = demux->flush_decoder_buffer(feed, length);

	mutex_unlock(&demux->mutex);
	return ret;
}

static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
				   struct dmx_ts_feed **ts_feed,
				   dmx_ts_cb callback)
@@ -2597,6 +2645,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
	(*ts_feed)->ts_insertion_terminate = NULL;
	(*ts_feed)->ts_insertion_insert_buffer =
		dvbdmx_ts_insertion_insert_buffer;
	(*ts_feed)->flush_buffer = dvbdmx_ts_flush_buffer;

	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
		feed->state = DMX_STATE_FREE;
@@ -3013,6 +3062,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
	(*feed)->set_cipher_ops = dmx_section_set_cipher_ops;
	(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
	(*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
	(*feed)->flush_buffer = NULL;

	mutex_unlock(&dvbdmx->mutex);
	return 0;
+2 −0
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ struct dvb_demux {
			 const u8 timestamp[TIMESTAMP_LEN],
			 u64 *timestampIn27Mhz);
	int (*set_indexing)(struct dvb_demux_feed *feed);
	int (*flush_decoder_buffer)(struct dvb_demux_feed *feed, size_t length);

	int users;
#define MAX_DVB_DEMUX_USERS 10
@@ -335,6 +336,7 @@ void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock);
int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
	struct dmx_data_ready *event, int should_lock);
void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed);

/**
 * dvb_dmx_is_video_feed - Returns whether the PES feed
+62 −8
Original line number Diff line number Diff line
/* 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 General Public License version 2 and
@@ -246,6 +246,14 @@ int mpq_streambuffer_pkt_write(
		return -ENODEV;
	}

	/* Make sure we can go to the next linear buffer */
	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR &&
		sbuff->pending_buffers_count == sbuff->buffers_num &&
		packet->raw_data_len) {
		spin_unlock(&sbuff->packet_data.lock);
		return -ENOSPC;
	}

	len = sizeof(struct mpq_streambuffer_packet_header) +
		packet->user_data_len;

@@ -272,12 +280,8 @@ int mpq_streambuffer_pkt_write(
	dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);

	/* Move write pointer to next linear buffer for subsequent writes */
	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
		(packet->raw_data_len > 0)) {
		if (sbuff->pending_buffers_count == sbuff->buffers_num) {
			spin_unlock(&sbuff->packet_data.lock);
			return -ENOSPC;
		}
	if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode &&
		packet->raw_data_len) {
		DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
				sizeof(struct mpq_streambuffer_buffer_desc));
		sbuff->pending_buffers_count++;
@@ -340,7 +344,7 @@ ssize_t mpq_streambuffer_data_write(

		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
			((desc->size - desc->write_ptr) < len)) {
			MPQ_DVB_ERR_PRINT(
			MPQ_DVB_DBG_PRINT(
				"%s: No space available! %d pending buffers out of %d total buffers. write_ptr=%d, size=%d\n",
				__func__,
				sbuff->pending_buffers_count,
@@ -771,3 +775,53 @@ ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff)
}
EXPORT_SYMBOL(mpq_streambuffer_metadata_free);

int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff)
{
	struct mpq_streambuffer_buffer_desc *desc;
	size_t len;
	int idx;
	int ret = 0;

	if (NULL == sbuff)
		return -EINVAL;

	spin_lock(&sbuff->packet_data.lock);
	spin_lock(&sbuff->raw_data.lock);

	/* Check if buffer was released */
	if (sbuff->packet_data.error == -ENODEV ||
		sbuff->raw_data.error == -ENODEV) {
		ret = -ENODEV;
		goto end;
	}

	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
		while (sbuff->pending_buffers_count) {
			desc = (struct mpq_streambuffer_buffer_desc *)
				&sbuff->raw_data.data[sbuff->raw_data.pread];
			desc->write_ptr = 0;
			desc->read_ptr = 0;
			DVB_RINGBUFFER_SKIP(&sbuff->raw_data,
				sizeof(struct mpq_streambuffer_buffer_desc));
			sbuff->pending_buffers_count--;
		}
	else
		dvb_ringbuffer_flush(&sbuff->raw_data);

	/*
	 * Dispose all packets (simply flushing is not enough since we want
	 * the packets' status to move to disposed).
	 */
	do {
		idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, -1, &len);
		if (idx >= 0)
			dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
	} while (idx >= 0);

end:
	spin_unlock(&sbuff->raw_data.lock);
	spin_unlock(&sbuff->packet_data.lock);
	return ret;
}
EXPORT_SYMBOL(mpq_streambuffer_flush);
Loading