mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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:
parent
9fde12676b
commit
fcf36dd4f9
15 changed files with 199 additions and 313 deletions
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 */
|
|
|
@ -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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue