media: dvb: mpq: Support new elementary stream data events
Video elemenatry stream data is usually passed from demux to a video
consumer (e.g. video decoder) in kernel-space via tunneling. However
there are cases when the video consumer is a user-space application
controlled by the middleware. This change adds support for notifying
user-space about newly available elementary stream data and
associated meta-data, using the existing events queue mechanism.
Change-Id: I6d104c6ad7ccc791b29b75e7bf376c985416585e
Signed-off-by: Liron Kuch <lkuch@codeaurora.org>
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index ed657d7..042ba37 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -64,14 +64,15 @@
enum dmx_success {
DMX_OK = 0, /* Received Ok */
- DMX_OK_PES_END, /* Received ok, data reached end of PES packet */
+ DMX_OK_PES_END, /* Received OK, data reached end of PES packet */
DMX_OK_PCR, /* Received OK, data with new PCR/STC pair */
DMX_LENGTH_ERROR, /* Incorrect length */
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
DMX_CRC_ERROR, /* Incorrect CRC */
DMX_FRAME_ERROR, /* Frame alignment error */
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
- DMX_MISSED_ERROR /* Receiver missed packet */
+ DMX_MISSED_ERROR, /* Receiver missed packet */
+ DMX_OK_DECODER_BUF /* Received OK, new ES data in decoder buffer */
} ;
@@ -106,6 +107,21 @@
u64 stc;
int disc_indicator_set;
} pcr;
+
+ struct {
+ int handle;
+ int cookie;
+ u32 offset;
+ u32 len;
+ int pts_exists;
+ u64 pts;
+ int dts_exists;
+ u64 dts;
+ u32 tei_counter;
+ u32 cont_err_counter;
+ u32 ts_packets_num;
+ u32 ts_dropped_bytes;
+ } buf;
};
};
@@ -202,6 +218,9 @@
int (*get_decoder_buff_status)(
struct dmx_ts_feed *feed,
struct dmx_buffer_status *dmx_buffer_status);
+ int (*reuse_decoder_buffer)(
+ struct dmx_ts_feed *feed,
+ int cookie);
int (*data_ready_cb)(struct dmx_ts_feed *feed,
dmx_ts_data_ready_cb callback);
int (*notify_data_read)(struct dmx_ts_feed *feed,
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e956170..2c3afd6 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1395,6 +1395,29 @@
return 0;
}
+static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter,
+ int cookie)
+{
+ if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
+ (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
+ struct dmxdev_feed *feed;
+ int ret = -ENODEV;
+
+ /* Only one feed should be in the list in case of decoder */
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ if (feed->ts->reuse_decoder_buffer)
+ ret = feed->ts->reuse_decoder_buffer(
+ feed->ts,
+ cookie);
+
+ return ret;
+ }
+
+ return -EPERM;
+}
+
static int dvb_dmxdev_ts_fullness_callback(
struct dmx_ts_feed *filter,
int required_space)
@@ -1535,9 +1558,12 @@
{
struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
-
- spin_lock_irq(&dmxdevfilter->dev->lock);
-
+ /*
+ * Note: Taking the dmxdevfilter->dev->lock spinlock is required only
+ * when getting the status of the Demux-userspace data ringbuffer .
+ * In case we are getting the status of a decoder buffer, taking this
+ * spinlock is not required and in fact might lead to a deadlock.
+ */
if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
(dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
struct dmxdev_feed *feed;
@@ -1555,10 +1581,11 @@
else
ret = -ENODEV;
- spin_unlock_irq(&dmxdevfilter->dev->lock);
return ret;
}
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+
if (!buf->data) {
spin_unlock_irq(&dmxdevfilter->dev->lock);
return -EINVAL;
@@ -1629,6 +1656,10 @@
spin_lock_irq(&dmxdevfilter->dev->lock);
res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event);
+ if (res) {
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ return res;
+ }
if (event->type == DMX_EVENT_BUFFER_OVERFLOW) {
/*
@@ -1645,6 +1676,15 @@
dmxdevfilter->buffer.error = 0;
}
+ /*
+ * Decoder filters have no data in the data buffer and their
+ * events can be removed now from the queue.
+ */
+ if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)
+ dmxdevfilter->events.read_index =
+ dvb_dmxdev_advance_event_idx(
+ dmxdevfilter->events.read_index);
+
spin_unlock_irq(&dmxdevfilter->dev->lock);
/*
@@ -1980,7 +2020,7 @@
event.params.pcr.stc = dmx_data_ready->pcr.stc;
if (dmx_data_ready->pcr.disc_indicator_set)
event.params.pcr.flags =
- DMX_FILTER_DISCONTINUITY_INDEICATOR;
+ DMX_FILTER_DISCONTINUITY_INDICATOR;
else
event.params.pcr.flags = 0;
@@ -1990,6 +2030,30 @@
return 0;
}
+ if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
+ event.type = DMX_EVENT_NEW_ES_DATA;
+ event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
+ event.params.es_data.cookie = dmx_data_ready->buf.cookie;
+ event.params.es_data.offset = dmx_data_ready->buf.offset;
+ event.params.es_data.data_len = dmx_data_ready->buf.len;
+ event.params.es_data.pts_valid = dmx_data_ready->buf.pts_exists;
+ event.params.es_data.pts = dmx_data_ready->buf.pts;
+ event.params.es_data.dts_valid = dmx_data_ready->buf.dts_exists;
+ event.params.es_data.dts = dmx_data_ready->buf.dts;
+ event.params.es_data.transport_error_indicator_counter =
+ dmx_data_ready->buf.tei_counter;
+ event.params.es_data.continuity_error_counter =
+ dmx_data_ready->buf.cont_err_counter;
+ event.params.es_data.ts_packets_num =
+ dmx_data_ready->buf.ts_packets_num;
+ event.params.es_data.ts_dropped_bytes =
+ dmx_data_ready->buf.ts_dropped_bytes;
+ dvb_dmxdev_add_event(events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
if ((dmxdevfilter->params.pes.output == DMX_OUT_DECODER) ||
(buffer->error)) {
spin_unlock(&dmxdevfilter->dev->lock);
@@ -2038,7 +2102,7 @@
event.params.pes.flags = 0;
if (dmx_data_ready->pes_end.disc_indicator_set)
event.params.pes.flags |=
- DMX_FILTER_DISCONTINUITY_INDEICATOR;
+ DMX_FILTER_DISCONTINUITY_INDICATOR;
if (dmx_data_ready->pes_end.pes_length_mismatch)
event.params.pes.flags |=
DMX_FILTER_PES_LENGTH_ERROR;
@@ -3017,6 +3081,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_REUSE_DECODER_BUFFER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_reuse_decoder_buf(dmxdevfilter, arg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 978cb38d..eea83c2 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1128,21 +1128,47 @@
struct dvb_demux *demux = feed->demux;
int ret;
- spin_lock_irq(&demux->lock);
+ mutex_lock(&demux->mutex);
if (feed->state < DMX_STATE_GO) {
- spin_unlock_irq(&demux->lock);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
if (!demux->decoder_buffer_status) {
- spin_unlock_irq(&demux->lock);
+ mutex_unlock(&demux->mutex);
return -ENODEV;
}
ret = demux->decoder_buffer_status(feed, dmx_buffer_status);
- spin_unlock_irq(&demux->lock);
+ mutex_unlock(&demux->mutex);
+
+ return ret;
+}
+
+static int dmx_ts_feed_reuse_decoder_buffer(struct dmx_ts_feed *ts_feed,
+ int cookie)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+ int ret;
+
+ mutex_lock(&demux->mutex);
+
+ if (feed->state < DMX_STATE_GO) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+
+ if (!demux->reuse_decoder_buffer) {
+ mutex_unlock(&demux->mutex);
+ return -ENODEV;
+ }
+
+ ret = demux->reuse_decoder_buffer(feed, cookie);
+
+ mutex_unlock(&demux->mutex);
return ret;
}
@@ -1239,6 +1265,7 @@
(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
(*ts_feed)->set_tsp_out_format = dmx_ts_set_tsp_out_format;
(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
+ (*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer;
(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
(*ts_feed)->notify_data_read = NULL;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index f89367b..2e4a468 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -127,6 +127,8 @@
int (*decoder_fullness_abort)(struct dvb_demux_feed *feed);
int (*decoder_buffer_status)(struct dvb_demux_feed *feed,
struct dmx_buffer_status *dmx_buffer_status);
+ int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed,
+ int cookie);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 94fa1b7..722e317 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -39,11 +39,15 @@
static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
module_param(mpq_demux_device_num, int, S_IRUGO);
-/* ION head ID to be used when calling ion_alloc for video decoder buffer */
+/* ION heap ID to be used when calling ion_alloc for video decoder buffer */
static int video_ion_alloc_heap = ION_CP_MM_HEAP_ID;
module_param(video_ion_alloc_heap, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(video_ion_alloc_heap, "ION heap ID for allocation");
+static int generate_es_events;
+module_param(generate_es_events, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(generate_es_events, "Generate new elementary stream data events");
+
/**
* Maximum allowed framing pattern size
*/
@@ -923,6 +927,62 @@
}
EXPORT_SYMBOL(mpq_dmx_unmap_buffer);
+int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie)
+{
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+
+ if (!generate_es_events) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Cannot release decoder buffer when not working with new elementary stream data events\n",
+ __func__);
+ return -EPERM;
+ }
+
+ if (cookie < 0) {
+ MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_streambuffer *stream_buffer;
+ int ret;
+
+ spin_lock(&mpq_demux->feed_lock);
+
+ if (feed->priv == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed->priv is NULL\n",
+ __func__);
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ feed_data = feed->priv;
+ stream_buffer = feed_data->video_buffer;
+ if (stream_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed_data->video_buffer is NULL\n",
+ __func__);
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1);
+
+ spin_unlock(&mpq_demux->feed_lock);
+
+ return ret;
+ }
+
+ /* else */
+ MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n",
+ __func__, feed->pes_type);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_reuse_decoder_buffer);
+
/**
* Handles the details of internal decoder buffer allocation via ION.
* Internal helper function.
@@ -977,23 +1037,11 @@
feed_data->buffer_desc.desc[0].size = actual_buffer_size;
feed_data->buffer_desc.desc[0].read_ptr = 0;
feed_data->buffer_desc.desc[0].write_ptr = 0;
- feed_data->buffer_desc.desc[0].handle =
- ion_share_dma_buf(
- client,
- temp_handle);
- if (IS_ERR_VALUE(feed_data->buffer_desc.desc[0].handle)) {
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to share payload buffer %d\n",
- __func__, ret);
- ret = -ENOMEM;
- goto init_failed_unmap_payload_buffer;
- }
+ /* TODO: share handle using ion_share_dma_buf */
+ feed_data->buffer_desc.desc[0].handle = -1;
return 0;
-init_failed_unmap_payload_buffer:
- ion_unmap_kernel(client, temp_handle);
- feed_data->buffer_desc.desc[0].base = NULL;
init_failed_free_payload_buffer:
ion_free(client, temp_handle);
feed_data->buffer_desc.ion_handle[0] = NULL;
@@ -1290,6 +1338,12 @@
feed_data->saved_info_used = 1;
feed_data->new_info_exists = 0;
feed_data->first_pts_dts_copy = 1;
+ feed_data->tei_errs = 0;
+ feed_data->last_continuity = -1;
+ feed_data->continuity_errs = 0;
+ feed_data->ts_packets_num = 0;
+ feed_data->ts_dropped_bytes = 0;
+ feed_data->last_pkt_index = -1;
spin_lock(&mpq_demux->feed_lock);
feed->priv = (void *)feed_data;
@@ -1314,7 +1368,6 @@
struct ion_client *client)
{
int buf_num = 0;
- struct dmx_decoder_buffers *dec_buffs = feed->feed.ts.decoder_buffers;
int i;
mpq_adapter_unregister_stream_if(feed_data->stream_interface);
@@ -1322,6 +1375,7 @@
vfree(feed_data->video_buffer->packet_data.data);
buf_num = feed_data->buffer_desc.decoder_buffers_num;
+
for (i = 0; i < buf_num; i++) {
if (feed_data->buffer_desc.ion_handle[i]) {
if (feed_data->buffer_desc.desc[i].base) {
@@ -1329,17 +1383,10 @@
feed_data->buffer_desc.ion_handle[i]);
feed_data->buffer_desc.desc[i].base = NULL;
}
+ /* TODO: un-share kernel buffer handle */
ion_free(client, feed_data->buffer_desc.ion_handle[i]);
feed_data->buffer_desc.ion_handle[i] = NULL;
feed_data->buffer_desc.desc[i].size = 0;
-
- /*
- * Call put_unused_fd only if kernel it the one that
- * shared the buffer handle.
- */
- if (0 == dec_buffs->buffers_num)
- put_unused_fd(
- feed_data->buffer_desc.desc[i].handle);
}
}
}
@@ -1770,6 +1817,73 @@
return 0;
}
+static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data,
+ int current_continuity,
+ int discontinuity_indicator)
+{
+ const int max_continuity = 0x0F; /* 4 bits in the TS packet header */
+
+ /* sanity check */
+ if (unlikely((current_continuity < 0) ||
+ (current_continuity > max_continuity))) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: received invalid continuity counter value %d\n",
+ __func__, current_continuity);
+ return;
+ }
+
+ /* reset last continuity */
+ if ((feed_data->last_continuity == -1) ||
+ (discontinuity_indicator)) {
+ feed_data->last_continuity = current_continuity;
+ return;
+ }
+
+ /* check for continuity errors */
+ if (current_continuity !=
+ ((feed_data->last_continuity + 1) & max_continuity))
+ feed_data->continuity_errs++;
+
+ /* save for next time */
+ feed_data->last_continuity = current_continuity;
+}
+
+static inline void mpq_dmx_prepare_es_event_data(
+ struct mpq_streambuffer_packet_header *packet,
+ struct mpq_adapter_video_meta_data *meta_data,
+ struct mpq_video_feed_info *feed_data,
+ struct mpq_streambuffer *stream_buffer,
+ struct dmx_data_ready *data)
+{
+ size_t len = 0;
+
+ data->data_length = 0;
+ data->buf.handle = packet->raw_data_handle;
+ /* this has to succeed when called here, after packet was written */
+ data->buf.cookie = mpq_streambuffer_pkt_next(stream_buffer,
+ feed_data->last_pkt_index, &len);
+ data->buf.offset = packet->raw_data_offset;
+ data->buf.len = packet->raw_data_len;
+ data->buf.pts_exists = meta_data->info.framing.pts_dts_info.pts_exist;
+ data->buf.pts = meta_data->info.framing.pts_dts_info.pts;
+ data->buf.dts_exists = meta_data->info.framing.pts_dts_info.dts_exist;
+ data->buf.dts = meta_data->info.framing.pts_dts_info.dts;
+ data->buf.tei_counter = feed_data->tei_errs;
+ data->buf.cont_err_counter = feed_data->continuity_errs;
+ data->buf.ts_packets_num = feed_data->ts_packets_num;
+ data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes;
+ data->status = DMX_OK_DECODER_BUF;
+
+ /* save for next time: */
+ feed_data->last_pkt_index = data->buf.cookie;
+
+ /* reset counters */
+ feed_data->ts_packets_num = 0;
+ feed_data->ts_dropped_bytes = 0;
+ feed_data->tei_errs = 0;
+ feed_data->continuity_errs = 0;
+}
+
static int mpq_dmx_process_video_packet_framing(
struct dvb_demux_feed *feed,
const u8 *buf)
@@ -1793,6 +1907,8 @@
int is_video_frame = 0;
int pending_data_len = 0;
int ret = 0;
+ int discontinuity_indicator = 0;
+ struct dmx_data_ready data;
mpq_demux = feed->demux->priv;
@@ -1854,9 +1970,18 @@
ts_payload_offset = sizeof(struct ts_packet_header);
- /* Skip adaptation field if exists */
- if (ts_header->adaptation_field_control == 3)
+ /*
+ * Skip adaptation field if exists.
+ * Save discontinuity indicator if exists.
+ */
+ if (ts_header->adaptation_field_control == 3) {
+ const struct ts_adaptation_field *adaptation_field;
+ adaptation_field = (const struct ts_adaptation_field *)
+ (buf + ts_payload_offset);
+ discontinuity_indicator =
+ adaptation_field->discontinuity_indicator;
ts_payload_offset += buf[ts_payload_offset] + 1;
+ }
/* 188 bytes: the size of a TS packet including the TS packet header */
bytes_avail = 188 - ts_payload_offset;
@@ -1940,6 +2065,13 @@
return 0;
}
+ /* Update error counters based on TS header */
+ feed_data->ts_packets_num++;
+ feed_data->tei_errs += ts_header->transport_error_indicator;
+ mpq_dmx_check_continuity(feed_data,
+ ts_header->continuity_counter,
+ discontinuity_indicator);
+
/*
* write prefix used to find first Sequence pattern, if needed.
* feed_data->patterns[0].pattern always contains the Sequence
@@ -1951,6 +2083,8 @@
feed_data->first_prefix_size) < 0) {
mpq_demux->decoder_drop_count +=
feed_data->first_prefix_size;
+ feed_data->ts_dropped_bytes +=
+ feed_data->first_prefix_size;
MPQ_DVB_DBG_PRINT("%s: could not write prefix\n",
__func__);
} else {
@@ -2003,6 +2137,7 @@
(buf + ts_payload_offset + bytes_written),
bytes_to_write) < 0) {
mpq_demux->decoder_drop_count += bytes_to_write;
+ feed_data->ts_dropped_bytes += bytes_to_write;
MPQ_DVB_DBG_PRINT(
"%s: Couldn't write %d bytes to data buffer\n",
__func__, bytes_to_write);
@@ -2043,6 +2178,15 @@
"Should never happen\n",
__func__);
}
+
+ if (generate_es_events) {
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data, feed_data,
+ stream_buffer, &data);
+
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ }
+
feed_data->pending_pattern_len = 0;
mpq_streambuffer_get_data_rw_offset(
feed_data->video_buffer,
@@ -2064,6 +2208,7 @@
pending_data_len);
if (ret < 0) {
mpq_demux->decoder_drop_count += pending_data_len;
+ feed_data->ts_dropped_bytes += pending_data_len;
MPQ_DVB_DBG_PRINT(
"%s: Couldn't write %d bytes to data buffer\n",
__func__, pending_data_len);
@@ -2087,6 +2232,8 @@
struct mpq_streambuffer *stream_buffer;
struct pes_packet_header *pes_header;
struct mpq_demux *mpq_demux;
+ int discontinuity_indicator = 0;
+ struct dmx_data_ready data;
mpq_demux = feed->demux->priv;
@@ -2100,7 +2247,7 @@
ts_header = (const struct ts_packet_header *)buf;
- stream_buffer = feed_data->video_buffer;
+ stream_buffer = feed_data->video_buffer;
pes_header = &feed_data->pes_header;
@@ -2153,11 +2300,22 @@
"Couldn't write packet. "
"Should never happen\n",
__func__);
+
/* Save write offset where new PES will begin */
mpq_streambuffer_get_data_rw_offset(
stream_buffer,
NULL,
&feed_data->frame_offset);
+
+ if (generate_es_events) {
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data,
+ feed_data,
+ stream_buffer, &data);
+
+ feed->data_ready_cb.ts(
+ &feed->feed.ts, &data);
+ }
} else {
MPQ_DVB_ERR_PRINT(
"%s: received PUSI"
@@ -2191,9 +2349,18 @@
ts_payload_offset = sizeof(struct ts_packet_header);
- /* Skip adaptation field if exists */
- if (ts_header->adaptation_field_control == 3)
+ /*
+ * Skip adaptation field if exists.
+ * Save discontinuity indicator if exists.
+ */
+ if (ts_header->adaptation_field_control == 3) {
+ const struct ts_adaptation_field *adaptation_field;
+ adaptation_field = (const struct ts_adaptation_field *)
+ (buf + ts_payload_offset);
+ discontinuity_indicator =
+ adaptation_field->discontinuity_indicator;
ts_payload_offset += buf[ts_payload_offset] + 1;
+ }
/* 188 bytes: size of a TS packet including the TS packet header */
bytes_avail = 188 - ts_payload_offset;
@@ -2224,13 +2391,22 @@
return 0;
}
+ /* Update error counters based on TS header */
+ feed_data->ts_packets_num++;
+ feed_data->tei_errs += ts_header->transport_error_indicator;
+ mpq_dmx_check_continuity(feed_data,
+ ts_header->continuity_counter,
+ discontinuity_indicator);
+
if (mpq_streambuffer_data_write(
stream_buffer,
buf+ts_payload_offset,
- bytes_avail) < 0)
+ bytes_avail) < 0) {
mpq_demux->decoder_drop_count += bytes_avail;
- else
+ feed_data->ts_dropped_bytes += bytes_avail;
+ } else {
feed->peslen += bytes_avail;
+ }
spin_unlock(&mpq_demux->feed_lock);
@@ -2261,8 +2437,13 @@
spin_unlock(&mpq_demux->feed_lock);
return -EINVAL;
}
+
feed_data = feed->priv;
video_buff = feed_data->video_buffer;
+ if (!video_buff) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
dmx_buffer_status->error = video_buff->raw_data.error;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index 744900a..ff196d6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -333,6 +333,15 @@
* new_pts_dts_info that should be saved to saved_pts_dts_info.
* @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs
* to be copied from the currently parsed PES header to the saved_pts_dts_info.
+ * @tei_errs: Transport stream Transport Error Indicator (TEI) counter.
+ * @last_continuity: last continuity counter value found in TS packet header.
+ * Initialized to -1.
+ * @continuity_errs: Transport stream continuity error counter.
+ * @ts_packets_num: TS packets counter.
+ * @ts_dropped_bytes: counts the number of bytes dropped due to insufficient
+ * buffer space.
+ * @last_pkt_index: used to save the last streambuffer packet index reported in
+ * a new elementary stream data event.
*/
struct mpq_video_feed_info {
void *plugin_data;
@@ -358,6 +367,12 @@
int saved_info_used;
int new_info_exists;
int first_pts_dts_copy;
+ u32 tei_errs;
+ int last_continuity;
+ u32 continuity_errs;
+ u32 ts_packets_num;
+ u32 ts_dropped_bytes;
+ int last_pkt_index;
};
/**
@@ -500,6 +515,20 @@
struct dmx_buffer_status *dmx_buffer_status);
/**
+ * mpq_dmx_reuse_decoder_buffer - release buffer passed to decoder for reuse
+ * by the stream-buffer.
+ *
+ * @feed: The decoder's feed.
+ * @cookie: stream-buffer handle of the buffer.
+ *
+ * Return error code
+ *
+ * The function releases the buffer provided by the stream-buffer
+ * connected to the decoder back to the stream-buffer for reuse.
+ */
+int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie);
+
+/**
* mpq_dmx_process_video_packet - Assemble PES data and output it
* to the stream-buffer connected to the decoder.
*
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index c5c3518..3ad3d21 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -668,6 +668,9 @@
mpq_demux->demux.decoder_buffer_status =
mpq_dmx_decoder_buffer_status;
+ mpq_demux->demux.reuse_decoder_buffer =
+ mpq_dmx_reuse_decoder_buffer;
+
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
if (result < 0) {
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 61c1761..46be260 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1090,6 +1090,9 @@
mpq_demux->demux.decoder_buffer_status =
mpq_dmx_decoder_buffer_status;
+ mpq_demux->demux.reuse_decoder_buffer =
+ mpq_dmx_reuse_decoder_buffer;
+
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
if (result < 0) {
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
index e4858fa..4211d6c 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -125,6 +125,7 @@
mpq_demux->demux.decoder_fullness_wait = NULL;
mpq_demux->demux.decoder_fullness_abort = NULL;
mpq_demux->demux.decoder_buffer_status = NULL;
+ mpq_demux->demux.reuse_decoder_buffer = NULL;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index fd4447f..460cba3 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -208,7 +208,10 @@
DMX_EVENT_SECTION_CRC_ERROR,
/* End-of-stream, no more data from this filter */
- DMX_EVENT_EOS
+ DMX_EVENT_EOS,
+
+ /* New Elementary Stream data is ready */
+ DMX_EVENT_NEW_ES_DATA
};
/* Flags passed in filter events */
@@ -217,7 +220,7 @@
#define DMX_FILTER_CC_ERROR 0x01
/* Discontinuity indicator was set */
-#define DMX_FILTER_DISCONTINUITY_INDEICATOR 0x02
+#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02
/* PES legnth in PES header is not correct */
#define DMX_FILTER_PES_LENGTH_ERROR 0x04
@@ -296,6 +299,57 @@
};
/*
+ * Elementary stream data information associated
+ * with DMX_EVENT_NEW_ES_DATA event
+ */
+struct dmx_es_data_event_info {
+ /* Buffer user-space handle */
+ int buf_handle;
+
+ /*
+ * Cookie to provide when releasing the buffer
+ * using the DMX_RELEASE_DECODER_BUFFER ioctl command
+ */
+ int cookie;
+
+ /* Offset of data from the beginning of the buffer */
+ __u32 offset;
+
+ /* Length of data in buffer (in bytes) */
+ __u32 data_len;
+
+ /* Indication whether PTS value is valid */
+ int pts_valid;
+
+ /* PTS value associated with the buffer */
+ __u64 pts;
+
+ /* Indication whether DTS value is valid */
+ int dts_valid;
+
+ /* DTS value associated with the buffer */
+ __u64 dts;
+
+ /*
+ * Number of TS packets with Transport Error Indicator (TEI) set
+ * in the TS packet header since last reported event
+ */
+ __u32 transport_error_indicator_counter;
+
+ /* Number of continuity errors since last reported event */
+ __u32 continuity_error_counter;
+
+ /* Total number of TS packets processed since last reported event */
+ __u32 ts_packets_num;
+
+ /*
+ * Number of dropped bytes due to insufficient buffer space,
+ * since last reported event
+ */
+ __u32 ts_dropped_bytes;
+};
+
+/*
* Filter's event returned through DMX_GET_EVENT.
* poll with POLLPRI would block until events are available.
*/
@@ -307,6 +361,7 @@
struct dmx_section_event_info section;
struct dmx_rec_chunk_event_info recording_chunk;
struct dmx_pcr_event_info pcr;
+ struct dmx_es_data_event_info es_data;
} params;
};
@@ -525,10 +580,10 @@
#define DMX_RELEASE_DATA _IO('o', 57)
#define DMX_FEED_DATA _IO('o', 58)
#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t)
-#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event)
-#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode)
-#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer)
+#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event)
+#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode)
+#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer)
#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers)
-
+#define DMX_REUSE_DECODER_BUFFER _IO('o', 64)
#endif /*_DVBDMX_H_*/