media: dvb: Add events API for demux

user-space programs using demux require to be notified
on several kinds of events such new PES event,
new section event, new recording-chunk event and
other error events. demux API was extended to meet
this requirement

Change-Id: I768b6acde346139e194a3e6637b6fc0fc9648446
Signed-off-by: Hamad Kadmany <hkadmany@codeaurora.org>
This commit is contained in:
Hamad Kadmany
2012-07-15 15:06:01 +03:00
committed by Stephen Boyd
parent 9ddbbe478f
commit 24dffcb5c8
11 changed files with 1078 additions and 117 deletions

View File

@@ -64,6 +64,8 @@
enum dmx_success {
DMX_OK = 0, /* Received Ok */
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 */
@@ -72,6 +74,41 @@ enum dmx_success {
DMX_MISSED_ERROR /* Receiver missed packet */
} ;
/*
* struct dmx_data_ready: Parameters for event notification callback.
* Event notification notifies demux device that data is written
* and available in the device's output buffer or provides
* notification on errors and other events. In the latter case
* data_length is zero.
*/
struct dmx_data_ready {
enum dmx_success status;
/*
* data_length may be 0 in case of DMX_OK_PES_END
* and in non-DMX_OK_XXX events. In DMX_OK_PES_END,
* data_length is for data comming after the end of PES.
*/
int data_length;
union {
struct {
int start_gap;
int actual_length;
int disc_indicator_set;
int pes_length_mismatch;
u64 stc;
} pes_end;
struct {
u64 pcr;
u64 stc;
int disc_indicator_set;
} pcr;
};
};
/*--------------------------------------------------------------------------*/
/* TS packet reception */
/*--------------------------------------------------------------------------*/
@@ -123,6 +160,10 @@ enum dmx_ts_pes
#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
#define DMX_TS_PES_PCR DMX_TS_PES_PCR0
struct dmx_ts_feed;
typedef int (*dmx_ts_data_ready_cb)(
struct dmx_ts_feed *source,
struct dmx_data_ready *dmx_data_ready);
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
@@ -141,6 +182,8 @@ struct dmx_ts_feed {
int (*get_decoder_buff_status)(
struct dmx_ts_feed *feed,
struct dmx_buffer_status *dmx_buffer_status);
int (*data_ready_cb)(struct dmx_ts_feed *feed,
dmx_ts_data_ready_cb callback);
};
/*--------------------------------------------------------------------------*/
@@ -155,6 +198,11 @@ struct dmx_section_filter {
void* priv; /* Pointer to private data of the API client */
};
struct dmx_section_feed;
typedef int (*dmx_section_data_ready_cb)(
struct dmx_section_filter *source,
struct dmx_data_ready *dmx_data_ready);
struct dmx_section_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux* parent; /* Back-pointer */
@@ -177,6 +225,8 @@ struct dmx_section_feed {
struct dmx_section_filter* filter);
int (*start_filtering) (struct dmx_section_feed* feed);
int (*stop_filtering) (struct dmx_section_feed* feed);
int (*data_ready_cb)(struct dmx_section_feed *feed,
dmx_section_data_ready_cb callback);
};
/*--------------------------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,35 @@ struct dmxdev_feed {
struct list_head next;
};
struct dmxdev_events_queue {
#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
/*
* indices used to manage events queue.
* read_index advanced when relevent data is read
* from the buffer.
* notified_index is the index from which next events
* are returned.
* read_index <= notified_index <= write_index
*
* If user reads the data without getting the respective
* event first, the read/notified indices are updated
* automatically to reflect the actual data that exist
* in the buffer.
*/
u32 read_index;
u32 write_index;
u32 notified_index;
/* Bytes read by user without having respective event in the queue */
u32 bytes_read_no_event;
/* internal tracking of PES and recording events */
u32 current_event_data_size;
u32 current_event_start_offset;
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
@@ -78,6 +107,8 @@ struct dmxdev_filter {
struct dmx_pes_filter_params pes;
} params;
struct dmxdev_events_queue events;
enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
@@ -88,6 +119,8 @@ struct dmxdev_filter {
/* relevent for decoder PES */
unsigned long pes_buffer_size;
u32 rec_chunk_size;
/* only for sections */
struct timer_list timer;
int todo;
@@ -107,8 +140,7 @@ struct dmxdev {
int capabilities;
#define DMXDEV_CAP_DUPLEX 0x1
#define DMXDEV_CAP_PULL_MODE 0x2
#define DMXDEV_CAP_PCR_EXTRACTION 0x4
#define DMXDEV_CAP_INDEXING 0x8
#define DMXDEV_CAP_INDEXING 0x4
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
@@ -120,6 +152,8 @@ struct dmxdev {
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
struct dmxdev_events_queue dvr_output_events;
struct dvb_ringbuffer dvr_input_buffer;
struct workqueue_struct *dvr_input_workqueue;

View File

@@ -145,8 +145,15 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
/* PUSI ? */
if (buf[1] & 0x40) {
feed->peslen = 0xfffa;
if (feed->pusi_seen)
/* We had seen PUSI before, this means
* that previous PES can be closed now.
*/
feed->cb.ts(NULL, 0, NULL, 0,
&feed->feed.ts, DMX_OK_PES_END);
feed->pusi_seen = 1;
feed->peslen = 0;
}
if (feed->pusi_seen == 0)
@@ -204,6 +211,11 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
if (dvb_demux_performancecheck)
demux->total_crc_time +=
dvb_dmx_calc_time_delta(pre_crc_time);
/* Notify on CRC error */
feed->cb.sec(NULL, 0, NULL, 0,
&f->filter, DMX_CRC_ERROR);
return -1;
}
@@ -1053,6 +1065,25 @@ static int dmx_ts_feed_decoder_buff_status(struct dmx_ts_feed *ts_feed,
return ret;
}
static int dmx_ts_feed_data_ready_cb(struct dmx_ts_feed *feed,
dmx_ts_data_ready_cb callback)
{
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
mutex_lock(&dvbdmx->mutex);
if (dvbdmxfeed->state == DMX_STATE_GO) {
mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
dvbdmxfeed->data_ready_cb.ts = callback;
mutex_unlock(&dvbdmx->mutex);
return 0;
}
static int dmx_ts_set_indexing_params(
struct dmx_ts_feed *ts_feed,
struct dmx_indexing_video_params *params)
@@ -1084,7 +1115,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->cb.ts = callback;
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->peslen = 0;
feed->buffer = NULL;
memset(&feed->indexing_params, 0,
sizeof(struct dmx_indexing_video_params));
@@ -1105,6 +1136,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
(*ts_feed)->set = dmx_ts_feed_set;
(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
@@ -1312,6 +1344,26 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
return ret;
}
static int dmx_section_feed_data_ready_cb(struct dmx_section_feed *feed,
dmx_section_data_ready_cb callback)
{
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
mutex_lock(&dvbdmx->mutex);
if (dvbdmxfeed->state == DMX_STATE_GO) {
mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
dvbdmxfeed->data_ready_cb.sec = callback;
mutex_unlock(&dvbdmx->mutex);
return 0;
}
static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dmx_section_filter *filter)
{
@@ -1381,6 +1433,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
(*feed)->start_filtering = dmx_section_feed_start_filtering;
(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
(*feed)->release_filter = dmx_section_feed_release_filter;
(*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
mutex_unlock(&dvbdmx->mutex);
return 0;

View File

@@ -78,6 +78,11 @@ struct dvb_demux_feed {
dmx_section_cb sec;
} cb;
union {
dmx_ts_data_ready_cb ts;
dmx_section_data_ready_cb sec;
} data_ready_cb;
struct dvb_demux *demux;
void *priv;
int type;

View File

@@ -111,6 +111,10 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
/* advance write ptr by <num> bytes */
#define DVB_RINGBUFFER_PUSH(rbuf, num) \
((rbuf)->pwrite = (((rbuf)->pwrite+(num))%(rbuf)->size))
/*
** read <len> bytes from ring buffer into <buf>
** <usermem> specifies whether <buf> resides in user space

View File

@@ -33,16 +33,6 @@
sizeof(struct mpq_streambuffer_packet_header) + \
sizeof(struct mpq_adapter_video_meta_data)))
/*
* PCR/STC information length saved in ring-buffer.
* PCR / STC are saved in ring-buffer in the following form:
* <8 bit flags><64 bits of STC> <64bits of PCR>
* STC and PCR values are in 27MHz.
* The current flags that are defined:
* 0x00000001: discontinuity_indicator
*/
#define PCR_STC_LEN 17
/* Number of demux devices, has default of linux configuration */
static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
@@ -1906,10 +1896,9 @@ int mpq_dmx_process_pcr_packet(
struct dvb_demux_feed *feed,
const u8 *buf)
{
int i;
u64 pcr;
u64 stc;
u8 output[PCR_STC_LEN];
struct dmx_data_ready data;
struct mpq_demux *mpq_demux = feed->demux->priv;
const struct ts_packet_header *ts_header;
const struct ts_adaptation_field *adaptation_field;
@@ -1960,17 +1949,13 @@ int mpq_dmx_process_pcr_packet(
stc += buf[188];
stc *= 256; /* convert from 105.47 KHZ to 27MHz */
output[0] = adaptation_field->discontinuity_indicator;
data.data_length = 0;
data.pcr.pcr = pcr;
data.pcr.stc = stc;
data.pcr.disc_indicator_set = adaptation_field->discontinuity_indicator;
data.status = DMX_OK_PCR;
feed->data_ready_cb.ts(&feed->feed.ts, &data);
for (i = 1; i <= 8; i++)
output[i] = (stc >> ((8-i) << 3)) & 0xFF;
for (i = 9; i <= 16; i++)
output[i] = (pcr >> ((16-i) << 3)) & 0xFF;
feed->cb.ts(output, PCR_STC_LEN,
NULL, 0,
&feed->feed.ts, DMX_OK);
return 0;
}
EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);

View File

@@ -641,7 +641,6 @@ static int mpq_tsif_dmx_init(
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;

View File

@@ -752,7 +752,6 @@ static int mpq_tspp_dmx_init(
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;

View File

@@ -139,7 +139,6 @@ static int mpq_tspp_dmx_init(
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;

View File

@@ -36,6 +36,9 @@
#define DMX_FILTER_SIZE 16
/* Min recording chunk upon which event is generated */
#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188)
typedef enum
{
DMX_OUT_DECODER, /* Streaming directly to decoder. */
@@ -135,7 +138,6 @@ struct dmx_indexing_video_params {
enum dmx_indexing_video_profile profile;
};
struct dmx_pes_filter_params
{
__u16 pid;
@@ -144,6 +146,18 @@ struct dmx_pes_filter_params
dmx_pes_type_t pes_type;
__u32 flags;
/*
* The following configures when the event
* DMX_EVENT_NEW_REC_CHUNK will be triggered.
* When new recorded data is received with size
* equal or larger than this value a new event
* will be triggered. This is relevent when
* output is DMX_OUT_TS_TAP or DMX_OUT_TSDEMUX_TAP,
* size must be at least DMX_REC_BUFF_CHUNK_MIN_SIZE
* and smaller than buffer size.
*/
__u32 rec_chunk_size;
struct dmx_indexing_video_params video_params;
};
@@ -170,6 +184,129 @@ struct dmx_buffer_status {
int error;
};
/* Events associated with each demux filter */
enum dmx_event {
/* New PES packet is ready to be consumed */
DMX_EVENT_NEW_PES,
/* New section is ready to be consumed */
DMX_EVENT_NEW_SECTION,
/* New recording chunk is ready to be consumed */
DMX_EVENT_NEW_REC_CHUNK,
/* New PCR value is ready */
DMX_EVENT_NEW_PCR,
/* Overflow */
DMX_EVENT_BUFFER_OVERFLOW,
/* Section was dropped due to CRC error */
DMX_EVENT_SECTION_CRC_ERROR,
/* End-of-stream, no more data from this filter */
DMX_EVENT_EOS
};
/* Flags passed in filter events */
/* Continuity counter error was detected */
#define DMX_FILTER_CC_ERROR 0x01
/* Discontinuity indicator was set */
#define DMX_FILTER_DISCONTINUITY_INDEICATOR 0x02
/* PES legnth in PES header is not correct */
#define DMX_FILTER_PES_LENGTH_ERROR 0x04
/* PES info associated with DMX_EVENT_NEW_PES event */
struct dmx_pes_event_info {
/* Offset at which PES information starts */
__u32 base_offset;
/*
* Start offset at which PES data
* from the stream starts.
* Equal to base_offset if PES data
* starts from the beginning.
*/
__u32 start_offset;
/* Total length holding the PES information */
__u32 total_length;
/* Actual length holding the PES data */
__u32 actual_length;
/* Local receiver timestamp in 27MHz */
__u64 stc;
/* Flags passed in filter events */
__u32 flags;
};
/* Section info associated with DMX_EVENT_NEW_SECTION event */
struct dmx_section_event_info {
/* Offset at which section information starts */
__u32 base_offset;
/*
* Start offset at which section data
* from the stream starts.
* Equal to base_offset if section data
* starts from the beginning.
*/
__u32 start_offset;
/* Total length holding the section information */
__u32 total_length;
/* Actual length holding the section data */
__u32 actual_length;
/* Flags passed in filter events */
__u32 flags;
};
/* Recording info associated with DMX_EVENT_NEW_REC_CHUNK event */
struct dmx_rec_chunk_event_info {
/* Offset at which recording chunk starts */
__u32 offset;
/* Size of recording chunk in bytes */
__u32 size;
};
/* PCR info associated with DMX_EVENT_NEW_PCR event */
struct dmx_pcr_event_info {
/* Local timestamp in 27MHz
* when PCR packet was received
*/
__u64 stc;
/* PCR value in 27MHz */
__u64 pcr;
/* Flags passed in filter events */
__u32 flags;
};
/*
* Filter's event returned through DMX_GET_EVENT.
* poll with POLLPRI would block until events are available.
*/
struct dmx_filter_event {
enum dmx_event type;
union {
struct dmx_pes_event_info pes;
struct dmx_section_event_info section;
struct dmx_rec_chunk_event_info recording_chunk;
struct dmx_pcr_event_info pcr;
} params;
};
typedef struct dmx_caps {
__u32 caps;
@@ -292,5 +429,6 @@ struct dmx_stc {
#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)
#endif /*_DVBDMX_H_*/