Simplify mpegplayer a bit and use array-based lists rather than linked lists for stream management. Move a couple useful functions to handle pointer arrays from kernel.c into general.c; mpeglayer now makes use of them.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26101 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2010-05-17 12:34:05 +00:00
parent 9fde12676b
commit fcf36dd4f9
15 changed files with 199 additions and 313 deletions

View file

@ -724,6 +724,11 @@ static const struct plugin_api rockbox_api = {
#ifdef AUDIOHW_HAVE_EQ #ifdef AUDIOHW_HAVE_EQ
sound_enum_hw_eq_band_setting, sound_enum_hw_eq_band_setting,
#endif #endif
#if CONFIG_CODEC == SWCODEC
find_array_ptr,
remove_array_ptr,
#endif
}; };
int plugin_load(const char* plugin, const void* parameter) int plugin_load(const char* plugin, const void* parameter)

View file

@ -142,7 +142,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 185 #define PLUGIN_API_VERSION 186
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
@ -889,6 +889,11 @@ int (*round_value_to_list32)(unsigned long value,
int (*sound_enum_hw_eq_band_setting)(unsigned int band, int (*sound_enum_hw_eq_band_setting)(unsigned int band,
unsigned int band_setting); unsigned int band_setting);
#endif /* AUDIOHW_HAVE_EQ */ #endif /* AUDIOHW_HAVE_EQ */
#if CONFIG_CODEC == SWCODEC
void ** (*find_array_ptr)(void **arr, void *ptr);
int (*remove_array_ptr)(void **arr, void *ptr);
#endif
}; };
/* plugin header */ /* plugin header */

View file

@ -29,6 +29,5 @@ disk_buf.c
mpeg_settings.c mpeg_settings.c
stream_mgr.c stream_mgr.c
mpegplayer.c mpegplayer.c
mpeg_linkedlist.c
mpeg_parser.c mpeg_parser.c
mpeg_misc.c mpeg_misc.c

View file

@ -30,7 +30,7 @@ static struct queue_sender_list disk_buf_queue_send SHAREDBSS_ATTR;
static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)];
struct disk_buf disk_buf SHAREDBSS_ATTR; struct disk_buf disk_buf SHAREDBSS_ATTR;
static struct list_item nf_list; static void *nf_list[MPEGPLAYER_MAX_STREAMS+1];
static inline void disk_buf_lock(void) static inline void disk_buf_lock(void)
{ {
@ -45,11 +45,10 @@ static inline void disk_buf_unlock(void)
static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh) static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh)
{ {
DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n", DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n",
STR_FROM_HEADER(sh)->id); STR_FROM_HDR(sh)->id);
list_remove_item(&sh->nf); list_remove_item(nf_list, sh);
} }
inline bool disk_buf_is_data_ready(struct stream_hdr *sh, inline bool disk_buf_is_data_ready(struct stream_hdr *sh,
ssize_t margin) ssize_t margin)
{ {
@ -71,7 +70,7 @@ void dbuf_l2_init(struct dbuf_l2_cache *l2_p)
static int disk_buf_on_data_notify(struct stream_hdr *sh) static int disk_buf_on_data_notify(struct stream_hdr *sh)
{ {
DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HEADER(sh)->id); DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HDR(sh)->id);
if (sh->win_left <= sh->win_right) if (sh->win_left <= sh->win_right)
{ {
@ -85,7 +84,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
sh->win_left, sh->win_right, sh->win_left, sh->win_right,
disk_buf.win_left, disk_buf.win_right); disk_buf.win_left, disk_buf.win_right);
/* Be sure it's not listed though if multiple requests were made */ /* Be sure it's not listed though if multiple requests were made */
list_remove_item(&sh->nf); list_remove_item(nf_list, sh);
return DISK_BUF_NOTIFY_OK; return DISK_BUF_NOTIFY_OK;
} }
@ -95,7 +94,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
case TSTATE_BUFFERING: case TSTATE_BUFFERING:
case TSTATE_INIT: case TSTATE_INIT:
disk_buf.state = TSTATE_BUFFERING; disk_buf.state = TSTATE_BUFFERING;
list_add_item(&nf_list, &sh->nf); list_add_item(nf_list, sh);
DEBUGF("(registered)\n" DEBUGF("(registered)\n"
" swl:%lu swr:%lu\n" " swl:%lu swr:%lu\n"
" dwl:%lu dwr:%lu\n", " dwl:%lu dwr:%lu\n",
@ -109,20 +108,17 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
return DISK_BUF_NOTIFY_ERROR; return DISK_BUF_NOTIFY_ERROR;
} }
static bool check_data_notifies_callback(struct list_item *item, static bool check_data_notifies_callback(struct stream_hdr *sh, intptr_t data)
intptr_t data)
{ {
struct stream_hdr *sh = TYPE_FROM_MEMBER(struct stream_hdr, item, nf);
if (disk_buf_is_data_ready(sh, 0)) if (disk_buf_is_data_ready(sh, 0))
{ {
/* Remove from list then post notification - post because send /* Remove from list then post notification - post because send
* could result in a wait for each thread to finish resulting * could result in a wait for each thread to finish resulting
* in deadlock */ * in deadlock */
list_remove_item(item); list_remove_item(nf_list, sh);
str_post_msg(STR_FROM_HEADER(sh), DISK_BUF_DATA_NOTIFY, 0); str_post_msg(STR_FROM_HDR(sh), DISK_BUF_DATA_NOTIFY, 0);
DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n", DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n",
STR_FROM_HEADER(sh)->id); STR_FROM_HDR(sh)->id);
} }
return true; return true;
@ -130,15 +126,17 @@ static bool check_data_notifies_callback(struct list_item *item,
} }
/* Check registered streams and notify them if their data is available */ /* Check registered streams and notify them if their data is available */
static void check_data_notifies(void) static inline void check_data_notifies(void)
{ {
list_enum_items(&nf_list, check_data_notifies_callback, 0); list_enum_items(nf_list,
(list_enum_callback_t)check_data_notifies_callback,
0);
} }
/* Clear all registered notifications - do not post them */ /* Clear all registered notifications - do not post them */
static inline void clear_data_notifies(void) static inline void clear_data_notifies(void)
{ {
list_clear_all(&nf_list); list_clear_all(nf_list);
} }
/* Background buffering when streaming */ /* Background buffering when streaming */
@ -492,7 +490,7 @@ static void disk_buf_thread(void)
disk_buf_buffer(); disk_buf_buffer();
/* Check for any due notifications if any are pending */ /* Check for any due notifications if any are pending */
if (nf_list.next != NULL) if (*nf_list != NULL)
check_data_notifies(); check_data_notifies();
/* Still more data left? */ /* Still more data left? */
@ -915,7 +913,6 @@ void disk_buf_reply_msg(intptr_t retval)
bool disk_buf_init(void) bool disk_buf_init(void)
{ {
disk_buf.thread = 0; disk_buf.thread = 0;
list_initialize(&nf_list);
rb->mutex_init(&disk_buf_mtx); rb->mutex_init(&disk_buf_mtx);

View file

@ -1,151 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Linked list API definitions
*
* Copyright (c) 2007 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "mpegplayer.h"
#include "mpeg_linkedlist.h"
/* Initialize a master list head */
void list_initialize(struct list_item *master_list_head)
{
master_list_head->prev = master_list_head->next = NULL;
}
/* Are there items after the head item? */
bool list_is_empty(struct list_item *head_item)
{
return head_item->next == NULL;
}
/* Does the item belong to a list? */
bool list_is_item_listed(struct list_item *item)
{
return item->prev != NULL;
}
/* Is the item a member in a particular list? */
bool list_is_member(struct list_item *master_list_head,
struct list_item *item)
{
if (item != master_list_head && item->prev != NULL)
{
struct list_item *curr = master_list_head->next;
while (curr != NULL)
{
if (item != curr)
{
curr = curr->next;
continue;
}
return true;
}
}
return false;
}
/* Remove an item from a list - no head item needed */
void list_remove_item(struct list_item *item)
{
if (item->prev == NULL)
{
/* Not in a list - no change - could be the master list head
* as well which cannot be removed */
return;
}
item->prev->next = item->next;
if (item->next != NULL)
{
/* Not last item */
item->next->prev = item->prev;
}
/* Mark as not in a list */
item->prev = NULL;
}
/* Add a list item after the base item */
void list_add_item(struct list_item *head_item,
struct list_item *item)
{
if (item->prev != NULL)
{
/* Already in a list - no change */
DEBUGF("list_add_item: item already in a list\n");
return;
}
if (item == head_item)
{
/* Cannot add the item to itself */
DEBUGF("list_add_item: item == head_item\n");
return;
}
/* Insert first */
item->prev = head_item;
item->next = head_item->next;
if (head_item->next != NULL)
{
/* Not first item */
head_item->next->prev = item;
}
head_item->next = item;
}
/* Clear list items after the head item */
void list_clear_all(struct list_item *head_item)
{
struct list_item *curr = head_item->next;
while (curr != NULL)
{
list_remove_item(curr);
curr = head_item->next;
}
}
/* Enumerate all items after the head item - passing each item in turn
* to the callback as well as the data value. The current item may be
* safely removed. Items added after the current position will be enumated
* but not ones added before it. The callback may return false to stop
* the enumeration. */
void list_enum_items(struct list_item *head_item,
list_enum_callback_t callback,
intptr_t data)
{
struct list_item *next = head_item->next;
while (next != NULL)
{
struct list_item *curr = next;
next = curr->next;
if (!callback(curr, data))
break;
}
}

View file

@ -1,71 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Linked list API declarations
*
* Copyright (c) 2007 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef MPEG_LINKEDLIST_H
#define MPEG_LINKEDLIST_H
struct list_item
{
struct list_item *prev; /* previous item in list */
struct list_item *next; /* next item in list */
};
/* Utility macros to help get the actual structure pointer back */
#define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername)
#define TYPE_FROM_MEMBER(type, memberptr, membername) \
((type *)((intptr_t)(memberptr) - OFFSETOF(type, membername)))
/* Initialize a master list head */
void list_initialize(struct list_item *master_list_head);
/* Are there items after the head item? */
bool list_is_empty(struct list_item *head_item);
/* Does the item belong to a list? */
bool list_is_item_listed(struct list_item *item);
/* Is the item a member in a particular list? */
bool list_is_member(struct list_item *master_list_head,
struct list_item *item);
/* Remove an item from a list - no head item needed */
void list_remove_item(struct list_item *item);
/* Add a list item after the base item */
void list_add_item(struct list_item *head_item,
struct list_item *item);
/* Clear list items after the head item */
void list_clear_all(struct list_item *head_item);
/* Enumerate all items after the head item - passing each item in turn
* to the callback as well as the data value. The current item may be
* safely removed. Items added after the current position will be enumated
* but not ones added before it. The callback may return false to stop
* the enumeration. */
typedef bool (*list_enum_callback_t)(struct list_item *item, intptr_t data);
void list_enum_items(struct list_item *head_item,
list_enum_callback_t callback,
intptr_t data);
#endif /* MPEG_LINKEDLIST_H */

View file

@ -102,3 +102,63 @@ uint32_t muldiv_uint32(uint32_t multiplicand,
return UINT32_MAX; /* Saturate */ return UINT32_MAX; /* Saturate */
} }
/** Lists **/
/* Does the list have any members? */
bool list_is_empty(void **list)
{
return *list == NULL;
}
/* Is the item inserted into a particular list? */
bool list_is_member(void **list, void *item)
{
return *rb->find_array_ptr(list, item) != NULL;
}
/* Removes an item from a list - returns true if item was found
* and thus removed. */
bool list_remove_item(void **list, void *item)
{
return rb->remove_array_ptr(list, item) != -1;
}
/* Adds a list item, insert last, if not already present. */
void list_add_item(void **list, void *item)
{
void **item_p = rb->find_array_ptr(list, item);
if (*item_p == NULL)
*item_p = item;
}
/* Clears the entire list. */
void list_clear_all(void **list)
{
while (*list != NULL)
*list++ = NULL;
}
/* Enumerate all items in the array, passing each item in turn to the
* callback as well as the data value. The current item may be safely
* removed. Other changes during enumeration are undefined. The callback
* may return 'false' to stop the enumeration early. */
void list_enum_items(void **list,
list_enum_callback_t callback,
intptr_t data)
{
for (;;)
{
void *item = *list;
if (item == NULL)
break;
if (callback != NULL && !callback(item, data))
break;
if (*list == item)
list++; /* Item still there */
}
}

View file

@ -202,4 +202,30 @@ uint32_t muldiv_uint32(uint32_t multiplicand,
uint32_t multiplier, uint32_t multiplier,
uint32_t divisor); uint32_t divisor);
/** Lists **/
/* Does the list have any members? */
bool list_is_empty(void **list);
/* Is the item inserted into a particular list? */
bool list_is_member(void **list, void *item);
/* Removes an item from a list - returns true if item was found
* and thus removed. */
bool list_remove_item(void **list, void *item);
/* Adds a list item, insert last, if not already present. */
void list_add_item(void **list, void *item);
/* Clears the entire list. */
void list_clear_all(void **list);
/* Enumerate all items in the array. */
typedef bool (*list_enum_callback_t)(void *item, intptr_t data);
void list_enum_items(void **list,
list_enum_callback_t callback,
intptr_t data);
#endif /* MPEG_MISC_H */ #endif /* MPEG_MISC_H */

View file

@ -31,6 +31,9 @@
#endif #endif
/* #else function-like empty macros are defined in the headers */ /* #else function-like empty macros are defined in the headers */
/* Should be enough for now */
#define MPEGPLAYER_MAX_STREAMS 4
/* Memory allotments for various subsystems */ /* Memory allotments for various subsystems */
#define MIN_MEMMARGIN (4*1024) #define MIN_MEMMARGIN (4*1024)
@ -85,7 +88,6 @@
#include "mpeg2.h" #include "mpeg2.h"
#include "video_out.h" #include "video_out.h"
#include "mpeg_stream.h" #include "mpeg_stream.h"
#include "mpeg_linkedlist.h"
#include "mpeg_misc.h" #include "mpeg_misc.h"
#include "mpeg_alloc.h" #include "mpeg_alloc.h"
#include "stream_thread.h" #include "stream_thread.h"

View file

@ -148,21 +148,21 @@ void stream_add_stream(struct stream *str)
{ {
actl_lock(); actl_lock();
list_remove_item(&str->l); list_remove_item(stream_mgr.strl, str);
list_add_item(&stream_mgr.strl, &str->l); list_add_item(stream_mgr.strl, str);
actl_unlock(); actl_unlock();
} }
/* Callback for various list-moving operations */ /* Callback for various list-moving operations */
static bool strl_enum_callback(struct list_item *item, intptr_t data) static bool strl_enum_callback(struct stream *str, intptr_t data)
{ {
actl_lock(); actl_lock();
list_remove_item(item); list_remove_item(stream_mgr.strl, str);
if (data == 1) if (data == 1)
list_add_item(&stream_mgr.actl, item); list_add_item(stream_mgr.actl, str);
actl_unlock(); actl_unlock();
@ -172,38 +172,38 @@ static bool strl_enum_callback(struct list_item *item, intptr_t data)
/* Clear all streams from active and playback pools */ /* Clear all streams from active and playback pools */
void stream_remove_streams(void) void stream_remove_streams(void)
{ {
list_enum_items(&stream_mgr.strl, strl_enum_callback, 0); list_enum_items(stream_mgr.strl,
(list_enum_callback_t)strl_enum_callback, 0);
} }
/* Move the playback pool to the active list */ /* Move the playback pool to the active list */
void move_strl_to_actl(void) void move_strl_to_actl(void)
{ {
list_enum_items(&stream_mgr.strl, strl_enum_callback, 1); list_enum_items(stream_mgr.strl,
(list_enum_callback_t)strl_enum_callback, 1);
} }
/* Remove a stream from the active list and return it to the pool */ /* Remove a stream from the active list and return it to the pool */
static bool actl_stream_remove(struct stream *str) static bool actl_stream_remove(struct stream *str)
{ {
if (list_is_member(&stream_mgr.actl, &str->l)) bool retval;
{
actl_lock(); actl_lock();
list_remove_item(&str->l); retval = list_remove_item(stream_mgr.actl, str);
list_add_item(&stream_mgr.strl, &str->l);
if (retval)
list_add_item(stream_mgr.strl, str);
actl_unlock(); actl_unlock();
return true;
}
return false; return retval;
} }
/* Broadcast a message to all active streams */ /* Broadcast a message to all active streams */
static bool actl_stream_broadcast_callback(struct list_item *item, static bool actl_stream_broadcast_callback(struct stream *str,
struct str_broadcast_data *sbd) struct str_broadcast_data *sbd)
{ {
struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l);
switch (sbd->cmd) switch (sbd->cmd)
{ {
case STREAM_PLAY: case STREAM_PLAY:
@ -215,8 +215,8 @@ static bool actl_stream_broadcast_callback(struct list_item *item,
{ {
actl_lock(); actl_lock();
list_remove_item(item); list_remove_item(stream_mgr.actl, str);
list_add_item(&stream_mgr.strl, item); list_add_item(stream_mgr.strl, str);
actl_unlock(); actl_unlock();
sbd->data = 0; sbd->data = 0;
@ -236,7 +236,7 @@ static void actl_stream_broadcast(int cmd, intptr_t data)
struct str_broadcast_data sbd; struct str_broadcast_data sbd;
sbd.cmd = cmd; sbd.cmd = cmd;
sbd.data = data; sbd.data = data;
list_enum_items(&stream_mgr.actl, list_enum_items(stream_mgr.actl,
(list_enum_callback_t)actl_stream_broadcast_callback, (list_enum_callback_t)actl_stream_broadcast_callback,
(intptr_t)&sbd); (intptr_t)&sbd);
} }
@ -623,7 +623,7 @@ static void stream_on_ev_complete(struct stream *str)
{ {
/* No - remove this stream from the active list */ /* No - remove this stream from the active list */
DEBUGF(" finished: 0x%02x\n", str->id); DEBUGF(" finished: 0x%02x\n", str->id);
if (list_is_empty(&stream_mgr.actl)) if (list_is_empty(stream_mgr.actl))
{ {
/* All streams have acked - stop playback */ /* All streams have acked - stop playback */
stream_on_stop(false); stream_on_stop(false);
@ -820,10 +820,9 @@ void stream_wait_status(void)
/* Returns the smallest file window that includes all active streams' /* Returns the smallest file window that includes all active streams'
* windows */ * windows */
static bool stream_get_window_callback(struct list_item *item, static bool stream_get_window_callback(struct stream *str,
struct stream_window *sw) struct stream_window *sw)
{ {
struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l);
off_t swl = str->hdr.win_left; off_t swl = str->hdr.win_left;
off_t swr = str->hdr.win_right; off_t swr = str->hdr.win_right;
@ -845,7 +844,7 @@ bool stream_get_window(struct stream_window *sw)
sw->right = LONG_MIN; sw->right = LONG_MIN;
actl_lock(); actl_lock();
list_enum_items(&stream_mgr.actl, list_enum_items(stream_mgr.actl,
(list_enum_callback_t)stream_get_window_callback, (list_enum_callback_t)stream_get_window_callback,
(intptr_t)sw); (intptr_t)sw);
actl_unlock(); actl_unlock();
@ -981,7 +980,6 @@ int stream_init(void)
stream_mgr.status = STREAM_STOPPED; stream_mgr.status = STREAM_STOPPED;
stream_mgr_init_state(); stream_mgr_init_state();
list_initialize(&stream_mgr.actl);
/* Initialize our window to the outside world first */ /* Initialize our window to the outside world first */
rb->mutex_init(&stream_mgr.str_mtx); rb->mutex_init(&stream_mgr.str_mtx);

View file

@ -35,8 +35,8 @@ struct stream_mgr
bool seeked; /* A seek happened and things must be bool seeked; /* A seek happened and things must be
resynced */ resynced */
int status; /* Current playback status */ int status; /* Current playback status */
struct list_item strl; /* List of available streams */ void *strl[MPEGPLAYER_MAX_STREAMS+1]; /* List of available streams */
struct list_item actl; /* List of active streams */ void *actl[MPEGPLAYER_MAX_STREAMS+1]; /* List of active streams */
struct mutex str_mtx; /* Main stream manager mutex */ struct mutex str_mtx; /* Main stream manager mutex */
struct mutex actl_mtx; /* Lock for current-streams list */ struct mutex actl_mtx; /* Lock for current-streams list */
union /* A place for reusable non-cacheable parameters */ union /* A place for reusable non-cacheable parameters */

View file

@ -39,7 +39,6 @@ struct stream_hdr
off_t pos; /* Start/current position for random-access read */ off_t pos; /* Start/current position for random-access read */
}; };
off_t limit; /* Limit for random-access read */ off_t limit; /* Limit for random-access read */
struct list_item nf; /* List for data notification */
}; };
struct stream struct stream
@ -48,8 +47,6 @@ struct stream
unsigned int thread; /* Stream's thread */ unsigned int thread; /* Stream's thread */
uint8_t* curr_packet; /* Current stream packet beginning */ uint8_t* curr_packet; /* Current stream packet beginning */
uint8_t* curr_packet_end; /* Current stream packet end */ uint8_t* curr_packet_end; /* Current stream packet end */
struct list_item l; /* List of streams - either reserve pool
or active pool */
int state; /* State machine parsing mode */ int state; /* State machine parsing mode */
uint32_t start_pts; /* First timestamp for stream */ uint32_t start_pts; /* First timestamp for stream */
uint32_t end_pts; /* Last timestamp for stream */ uint32_t end_pts; /* Last timestamp for stream */
@ -58,6 +55,8 @@ struct stream
unsigned id; /* Stream identifier */ unsigned id; /* Stream identifier */
}; };
#define STR_FROM_HDR(sh) ((struct stream *)(sh))
/* Make sure there there is always enough data buffered ahead for /* Make sure there there is always enough data buffered ahead for
* the worst possible case - regardless of whether a valid stream * the worst possible case - regardless of whether a valid stream
* would actually produce that */ * would actually produce that */
@ -145,8 +144,6 @@ enum stream_status
STREAM_NOT_FOUND, /* Match not found */ STREAM_NOT_FOUND, /* Match not found */
}; };
#define STR_FROM_HEADER(sh) ((struct stream *)(sh))
/* Clip time to range for a particular stream */ /* Clip time to range for a particular stream */
static inline uint32_t clip_time(struct stream *str, uint32_t time) static inline uint32_t clip_time(struct stream *str, uint32_t time)
{ {

View file

@ -72,4 +72,19 @@ char *create_datetime_filename(char *buffer, const char *path,
bool unique_time); bool unique_time);
#endif /* CONFIG_RTC */ #endif /* CONFIG_RTC */
/***
** Compacted pointer lists
**
** N-length list requires N+1 elements to ensure NULL-termination.
**/
/* Find a pointer in a pointer array. Returns the addess of the element if
found or the address of the terminating NULL otherwise. This can be used
to bounds check and add items. */
void ** find_array_ptr(void **arr, void *ptr);
/* Remove a pointer from a pointer array if it exists. Compacts it so that
no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
int remove_array_ptr(void **arr, void *ptr);
#endif /* GENERAL_H */ #endif /* GENERAL_H */

View file

@ -196,3 +196,40 @@ char *create_datetime_filename(char *buffer, const char *path,
return buffer; return buffer;
} }
#endif /* CONFIG_RTC */ #endif /* CONFIG_RTC */
/***
** Compacted pointer lists
**
** N-length list requires N+1 elements to ensure NULL-termination.
**/
/* Find a pointer in a pointer array. Returns the addess of the element if
* found or the address of the terminating NULL otherwise. This can be used
* to bounds check and add items. */
void ** find_array_ptr(void **arr, void *ptr)
{
void *curr;
for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
return arr;
}
/* Remove a pointer from a pointer array if it exists. Compacts it so that
* no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
int remove_array_ptr(void **arr, void *ptr)
{
void *curr;
arr = find_array_ptr(arr, ptr);
if (*arr == NULL)
return -1;
/* Found. Slide up following items. */
do
{
void **arr1 = arr + 1;
*arr++ = curr = *arr1;
}
while (curr != NULL);
return 0;
}

View file

@ -27,6 +27,7 @@
#include "system.h" #include "system.h"
#include "panic.h" #include "panic.h"
#include "debug.h" #include "debug.h"
#include "general.h"
/* Make this nonzero to enable more elaborate checks on objects */ /* Make this nonzero to enable more elaborate checks on objects */
#if defined(DEBUG) || defined(SIMULATOR) #if defined(DEBUG) || defined(SIMULATOR)
@ -61,40 +62,6 @@ static struct
IF_COP( struct corelock cl; ) IF_COP( struct corelock cl; )
} all_queues SHAREDBSS_ATTR; } all_queues SHAREDBSS_ATTR;
/****************************************************************************
* Common utilities
****************************************************************************/
/* Find a pointer in a pointer array. Returns the addess of the element if
* found or the address of the terminating NULL otherwise. */
static void ** find_array_ptr(void **arr, void *ptr)
{
void *curr;
for(curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
return arr;
}
/* Remove a pointer from a pointer array if it exists. Compacts it so that
* no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
static int remove_array_ptr(void **arr, void *ptr)
{
void *curr;
arr = find_array_ptr(arr, ptr);
if(*arr == NULL)
return -1;
/* Found. Slide up following items. */
do
{
void **arr1 = arr + 1;
*arr++ = curr = *arr1;
}
while(curr != NULL);
return 0;
}
/**************************************************************************** /****************************************************************************
* Standard kernel stuff * Standard kernel stuff
****************************************************************************/ ****************************************************************************/