diff options
-rw-r--r-- | apps/plugin.c | 5 | ||||
-rw-r--r-- | apps/plugin.h | 7 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/disk_buf.c | 37 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_linkedlist.c | 151 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_linkedlist.h | 71 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_misc.c | 60 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_misc.h | 26 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.h | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_mgr.c | 52 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_mgr.h | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_thread.h | 7 | ||||
-rw-r--r-- | firmware/export/general.h | 15 | ||||
-rw-r--r-- | firmware/general.c | 37 | ||||
-rw-r--r-- | firmware/kernel.c | 35 |
15 files changed, 199 insertions, 313 deletions
diff --git a/apps/plugin.c b/apps/plugin.c index 90380a0039..b45220acdb 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -724,6 +724,11 @@ static const struct plugin_api rockbox_api = { | |||
724 | #ifdef AUDIOHW_HAVE_EQ | 724 | #ifdef AUDIOHW_HAVE_EQ |
725 | sound_enum_hw_eq_band_setting, | 725 | sound_enum_hw_eq_band_setting, |
726 | #endif | 726 | #endif |
727 | |||
728 | #if CONFIG_CODEC == SWCODEC | ||
729 | find_array_ptr, | ||
730 | remove_array_ptr, | ||
731 | #endif | ||
727 | }; | 732 | }; |
728 | 733 | ||
729 | int plugin_load(const char* plugin, const void* parameter) | 734 | int plugin_load(const char* plugin, const void* parameter) |
diff --git a/apps/plugin.h b/apps/plugin.h index 108a283596..785ba6f6a2 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -142,7 +142,7 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
142 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 142 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
143 | 143 | ||
144 | /* increase this every time the api struct changes */ | 144 | /* increase this every time the api struct changes */ |
145 | #define PLUGIN_API_VERSION 185 | 145 | #define PLUGIN_API_VERSION 186 |
146 | 146 | ||
147 | /* update this to latest version if a change to the api struct breaks | 147 | /* update this to latest version if a change to the api struct breaks |
148 | backwards compatibility (and please take the opportunity to sort in any | 148 | backwards compatibility (and please take the opportunity to sort in any |
@@ -889,6 +889,11 @@ int (*round_value_to_list32)(unsigned long value, | |||
889 | int (*sound_enum_hw_eq_band_setting)(unsigned int band, | 889 | int (*sound_enum_hw_eq_band_setting)(unsigned int band, |
890 | unsigned int band_setting); | 890 | unsigned int band_setting); |
891 | #endif /* AUDIOHW_HAVE_EQ */ | 891 | #endif /* AUDIOHW_HAVE_EQ */ |
892 | |||
893 | #if CONFIG_CODEC == SWCODEC | ||
894 | void ** (*find_array_ptr)(void **arr, void *ptr); | ||
895 | int (*remove_array_ptr)(void **arr, void *ptr); | ||
896 | #endif | ||
892 | }; | 897 | }; |
893 | 898 | ||
894 | /* plugin header */ | 899 | /* plugin header */ |
diff --git a/apps/plugins/mpegplayer/SOURCES b/apps/plugins/mpegplayer/SOURCES index 5ca0fcd86e..cf1e54aff5 100644 --- a/apps/plugins/mpegplayer/SOURCES +++ b/apps/plugins/mpegplayer/SOURCES | |||
@@ -29,6 +29,5 @@ disk_buf.c | |||
29 | mpeg_settings.c | 29 | mpeg_settings.c |
30 | stream_mgr.c | 30 | stream_mgr.c |
31 | mpegplayer.c | 31 | mpegplayer.c |
32 | mpeg_linkedlist.c | ||
33 | mpeg_parser.c | 32 | mpeg_parser.c |
34 | mpeg_misc.c | 33 | mpeg_misc.c |
diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c index af349c302a..4d0f98e5a3 100644 --- a/apps/plugins/mpegplayer/disk_buf.c +++ b/apps/plugins/mpegplayer/disk_buf.c | |||
@@ -30,7 +30,7 @@ static struct queue_sender_list disk_buf_queue_send SHAREDBSS_ATTR; | |||
30 | static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; | 30 | static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; |
31 | 31 | ||
32 | struct disk_buf disk_buf SHAREDBSS_ATTR; | 32 | struct disk_buf disk_buf SHAREDBSS_ATTR; |
33 | static struct list_item nf_list; | 33 | static void *nf_list[MPEGPLAYER_MAX_STREAMS+1]; |
34 | 34 | ||
35 | static inline void disk_buf_lock(void) | 35 | static inline void disk_buf_lock(void) |
36 | { | 36 | { |
@@ -45,13 +45,12 @@ static inline void disk_buf_unlock(void) | |||
45 | static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh) | 45 | static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh) |
46 | { | 46 | { |
47 | DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n", | 47 | DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n", |
48 | STR_FROM_HEADER(sh)->id); | 48 | STR_FROM_HDR(sh)->id); |
49 | list_remove_item(&sh->nf); | 49 | list_remove_item(nf_list, sh); |
50 | } | 50 | } |
51 | 51 | ||
52 | |||
53 | inline bool disk_buf_is_data_ready(struct stream_hdr *sh, | 52 | inline bool disk_buf_is_data_ready(struct stream_hdr *sh, |
54 | ssize_t margin) | 53 | ssize_t margin) |
55 | { | 54 | { |
56 | /* Data window available? */ | 55 | /* Data window available? */ |
57 | off_t right = sh->win_right; | 56 | off_t right = sh->win_right; |
@@ -71,7 +70,7 @@ void dbuf_l2_init(struct dbuf_l2_cache *l2_p) | |||
71 | 70 | ||
72 | static int disk_buf_on_data_notify(struct stream_hdr *sh) | 71 | static int disk_buf_on_data_notify(struct stream_hdr *sh) |
73 | { | 72 | { |
74 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HEADER(sh)->id); | 73 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HDR(sh)->id); |
75 | 74 | ||
76 | if (sh->win_left <= sh->win_right) | 75 | if (sh->win_left <= sh->win_right) |
77 | { | 76 | { |
@@ -85,7 +84,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh) | |||
85 | sh->win_left, sh->win_right, | 84 | sh->win_left, sh->win_right, |
86 | disk_buf.win_left, disk_buf.win_right); | 85 | disk_buf.win_left, disk_buf.win_right); |
87 | /* Be sure it's not listed though if multiple requests were made */ | 86 | /* Be sure it's not listed though if multiple requests were made */ |
88 | list_remove_item(&sh->nf); | 87 | list_remove_item(nf_list, sh); |
89 | return DISK_BUF_NOTIFY_OK; | 88 | return DISK_BUF_NOTIFY_OK; |
90 | } | 89 | } |
91 | 90 | ||
@@ -95,7 +94,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh) | |||
95 | case TSTATE_BUFFERING: | 94 | case TSTATE_BUFFERING: |
96 | case TSTATE_INIT: | 95 | case TSTATE_INIT: |
97 | disk_buf.state = TSTATE_BUFFERING; | 96 | disk_buf.state = TSTATE_BUFFERING; |
98 | list_add_item(&nf_list, &sh->nf); | 97 | list_add_item(nf_list, sh); |
99 | DEBUGF("(registered)\n" | 98 | DEBUGF("(registered)\n" |
100 | " swl:%lu swr:%lu\n" | 99 | " swl:%lu swr:%lu\n" |
101 | " dwl:%lu dwr:%lu\n", | 100 | " dwl:%lu dwr:%lu\n", |
@@ -109,20 +108,17 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh) | |||
109 | return DISK_BUF_NOTIFY_ERROR; | 108 | return DISK_BUF_NOTIFY_ERROR; |
110 | } | 109 | } |
111 | 110 | ||
112 | static bool check_data_notifies_callback(struct list_item *item, | 111 | static bool check_data_notifies_callback(struct stream_hdr *sh, intptr_t data) |
113 | intptr_t data) | ||
114 | { | 112 | { |
115 | struct stream_hdr *sh = TYPE_FROM_MEMBER(struct stream_hdr, item, nf); | ||
116 | |||
117 | if (disk_buf_is_data_ready(sh, 0)) | 113 | if (disk_buf_is_data_ready(sh, 0)) |
118 | { | 114 | { |
119 | /* Remove from list then post notification - post because send | 115 | /* Remove from list then post notification - post because send |
120 | * could result in a wait for each thread to finish resulting | 116 | * could result in a wait for each thread to finish resulting |
121 | * in deadlock */ | 117 | * in deadlock */ |
122 | list_remove_item(item); | 118 | list_remove_item(nf_list, sh); |
123 | str_post_msg(STR_FROM_HEADER(sh), DISK_BUF_DATA_NOTIFY, 0); | 119 | str_post_msg(STR_FROM_HDR(sh), DISK_BUF_DATA_NOTIFY, 0); |
124 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n", | 120 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n", |
125 | STR_FROM_HEADER(sh)->id); | 121 | STR_FROM_HDR(sh)->id); |
126 | } | 122 | } |
127 | 123 | ||
128 | return true; | 124 | return true; |
@@ -130,15 +126,17 @@ static bool check_data_notifies_callback(struct list_item *item, | |||
130 | } | 126 | } |
131 | 127 | ||
132 | /* Check registered streams and notify them if their data is available */ | 128 | /* Check registered streams and notify them if their data is available */ |
133 | static void check_data_notifies(void) | 129 | static inline void check_data_notifies(void) |
134 | { | 130 | { |
135 | list_enum_items(&nf_list, check_data_notifies_callback, 0); | 131 | list_enum_items(nf_list, |
132 | (list_enum_callback_t)check_data_notifies_callback, | ||
133 | 0); | ||
136 | } | 134 | } |
137 | 135 | ||
138 | /* Clear all registered notifications - do not post them */ | 136 | /* Clear all registered notifications - do not post them */ |
139 | static inline void clear_data_notifies(void) | 137 | static inline void clear_data_notifies(void) |
140 | { | 138 | { |
141 | list_clear_all(&nf_list); | 139 | list_clear_all(nf_list); |
142 | } | 140 | } |
143 | 141 | ||
144 | /* Background buffering when streaming */ | 142 | /* Background buffering when streaming */ |
@@ -492,7 +490,7 @@ static void disk_buf_thread(void) | |||
492 | disk_buf_buffer(); | 490 | disk_buf_buffer(); |
493 | 491 | ||
494 | /* Check for any due notifications if any are pending */ | 492 | /* Check for any due notifications if any are pending */ |
495 | if (nf_list.next != NULL) | 493 | if (*nf_list != NULL) |
496 | check_data_notifies(); | 494 | check_data_notifies(); |
497 | 495 | ||
498 | /* Still more data left? */ | 496 | /* Still more data left? */ |
@@ -915,7 +913,6 @@ void disk_buf_reply_msg(intptr_t retval) | |||
915 | bool disk_buf_init(void) | 913 | bool disk_buf_init(void) |
916 | { | 914 | { |
917 | disk_buf.thread = 0; | 915 | disk_buf.thread = 0; |
918 | list_initialize(&nf_list); | ||
919 | 916 | ||
920 | rb->mutex_init(&disk_buf_mtx); | 917 | rb->mutex_init(&disk_buf_mtx); |
921 | 918 | ||
diff --git a/apps/plugins/mpegplayer/mpeg_linkedlist.c b/apps/plugins/mpegplayer/mpeg_linkedlist.c deleted file mode 100644 index f2d01ee493..0000000000 --- a/apps/plugins/mpegplayer/mpeg_linkedlist.c +++ /dev/null | |||
@@ -1,151 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Linked list API definitions | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | #include "mpeg_linkedlist.h" | ||
26 | |||
27 | /* Initialize a master list head */ | ||
28 | void list_initialize(struct list_item *master_list_head) | ||
29 | { | ||
30 | master_list_head->prev = master_list_head->next = NULL; | ||
31 | } | ||
32 | |||
33 | /* Are there items after the head item? */ | ||
34 | bool list_is_empty(struct list_item *head_item) | ||
35 | { | ||
36 | return head_item->next == NULL; | ||
37 | } | ||
38 | |||
39 | /* Does the item belong to a list? */ | ||
40 | bool list_is_item_listed(struct list_item *item) | ||
41 | { | ||
42 | return item->prev != NULL; | ||
43 | } | ||
44 | |||
45 | /* Is the item a member in a particular list? */ | ||
46 | bool list_is_member(struct list_item *master_list_head, | ||
47 | struct list_item *item) | ||
48 | { | ||
49 | if (item != master_list_head && item->prev != NULL) | ||
50 | { | ||
51 | struct list_item *curr = master_list_head->next; | ||
52 | |||
53 | while (curr != NULL) | ||
54 | { | ||
55 | if (item != curr) | ||
56 | { | ||
57 | curr = curr->next; | ||
58 | continue; | ||
59 | } | ||
60 | |||
61 | return true; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return false; | ||
66 | } | ||
67 | |||
68 | /* Remove an item from a list - no head item needed */ | ||
69 | void list_remove_item(struct list_item *item) | ||
70 | { | ||
71 | if (item->prev == NULL) | ||
72 | { | ||
73 | /* Not in a list - no change - could be the master list head | ||
74 | * as well which cannot be removed */ | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | item->prev->next = item->next; | ||
79 | |||
80 | if (item->next != NULL) | ||
81 | { | ||
82 | /* Not last item */ | ||
83 | item->next->prev = item->prev; | ||
84 | } | ||
85 | |||
86 | /* Mark as not in a list */ | ||
87 | item->prev = NULL; | ||
88 | } | ||
89 | |||
90 | /* Add a list item after the base item */ | ||
91 | void list_add_item(struct list_item *head_item, | ||
92 | struct list_item *item) | ||
93 | { | ||
94 | if (item->prev != NULL) | ||
95 | { | ||
96 | /* Already in a list - no change */ | ||
97 | DEBUGF("list_add_item: item already in a list\n"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | if (item == head_item) | ||
102 | { | ||
103 | /* Cannot add the item to itself */ | ||
104 | DEBUGF("list_add_item: item == head_item\n"); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | /* Insert first */ | ||
109 | item->prev = head_item; | ||
110 | item->next = head_item->next; | ||
111 | |||
112 | if (head_item->next != NULL) | ||
113 | { | ||
114 | /* Not first item */ | ||
115 | head_item->next->prev = item; | ||
116 | } | ||
117 | |||
118 | head_item->next = item; | ||
119 | } | ||
120 | |||
121 | /* Clear list items after the head item */ | ||
122 | void list_clear_all(struct list_item *head_item) | ||
123 | { | ||
124 | struct list_item *curr = head_item->next; | ||
125 | |||
126 | while (curr != NULL) | ||
127 | { | ||
128 | list_remove_item(curr); | ||
129 | curr = head_item->next; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* Enumerate all items after the head item - passing each item in turn | ||
134 | * to the callback as well as the data value. The current item may be | ||
135 | * safely removed. Items added after the current position will be enumated | ||
136 | * but not ones added before it. The callback may return false to stop | ||
137 | * the enumeration. */ | ||
138 | void list_enum_items(struct list_item *head_item, | ||
139 | list_enum_callback_t callback, | ||
140 | intptr_t data) | ||
141 | { | ||
142 | struct list_item *next = head_item->next; | ||
143 | |||
144 | while (next != NULL) | ||
145 | { | ||
146 | struct list_item *curr = next; | ||
147 | next = curr->next; | ||
148 | if (!callback(curr, data)) | ||
149 | break; | ||
150 | } | ||
151 | } | ||
diff --git a/apps/plugins/mpegplayer/mpeg_linkedlist.h b/apps/plugins/mpegplayer/mpeg_linkedlist.h deleted file mode 100644 index d4f8305d7d..0000000000 --- a/apps/plugins/mpegplayer/mpeg_linkedlist.h +++ /dev/null | |||
@@ -1,71 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Linked list API declarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef MPEG_LINKEDLIST_H | ||
24 | #define MPEG_LINKEDLIST_H | ||
25 | |||
26 | struct list_item | ||
27 | { | ||
28 | struct list_item *prev; /* previous item in list */ | ||
29 | struct list_item *next; /* next item in list */ | ||
30 | }; | ||
31 | |||
32 | /* Utility macros to help get the actual structure pointer back */ | ||
33 | #define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername) | ||
34 | #define TYPE_FROM_MEMBER(type, memberptr, membername) \ | ||
35 | ((type *)((intptr_t)(memberptr) - OFFSETOF(type, membername))) | ||
36 | |||
37 | /* Initialize a master list head */ | ||
38 | void list_initialize(struct list_item *master_list_head); | ||
39 | |||
40 | /* Are there items after the head item? */ | ||
41 | bool list_is_empty(struct list_item *head_item); | ||
42 | |||
43 | /* Does the item belong to a list? */ | ||
44 | bool list_is_item_listed(struct list_item *item); | ||
45 | |||
46 | /* Is the item a member in a particular list? */ | ||
47 | bool list_is_member(struct list_item *master_list_head, | ||
48 | struct list_item *item); | ||
49 | |||
50 | /* Remove an item from a list - no head item needed */ | ||
51 | void list_remove_item(struct list_item *item); | ||
52 | |||
53 | /* Add a list item after the base item */ | ||
54 | void list_add_item(struct list_item *head_item, | ||
55 | struct list_item *item); | ||
56 | |||
57 | /* Clear list items after the head item */ | ||
58 | void list_clear_all(struct list_item *head_item); | ||
59 | |||
60 | /* Enumerate all items after the head item - passing each item in turn | ||
61 | * to the callback as well as the data value. The current item may be | ||
62 | * safely removed. Items added after the current position will be enumated | ||
63 | * but not ones added before it. The callback may return false to stop | ||
64 | * the enumeration. */ | ||
65 | typedef bool (*list_enum_callback_t)(struct list_item *item, intptr_t data); | ||
66 | |||
67 | void list_enum_items(struct list_item *head_item, | ||
68 | list_enum_callback_t callback, | ||
69 | intptr_t data); | ||
70 | |||
71 | #endif /* MPEG_LINKEDLIST_H */ | ||
diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c index 8e6ccf650f..e201aa69c7 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.c +++ b/apps/plugins/mpegplayer/mpeg_misc.c | |||
@@ -102,3 +102,63 @@ uint32_t muldiv_uint32(uint32_t multiplicand, | |||
102 | 102 | ||
103 | return UINT32_MAX; /* Saturate */ | 103 | return UINT32_MAX; /* Saturate */ |
104 | } | 104 | } |
105 | |||
106 | |||
107 | /** Lists **/ | ||
108 | |||
109 | /* Does the list have any members? */ | ||
110 | bool list_is_empty(void **list) | ||
111 | { | ||
112 | return *list == NULL; | ||
113 | } | ||
114 | |||
115 | /* Is the item inserted into a particular list? */ | ||
116 | bool list_is_member(void **list, void *item) | ||
117 | { | ||
118 | return *rb->find_array_ptr(list, item) != NULL; | ||
119 | } | ||
120 | |||
121 | /* Removes an item from a list - returns true if item was found | ||
122 | * and thus removed. */ | ||
123 | bool list_remove_item(void **list, void *item) | ||
124 | { | ||
125 | return rb->remove_array_ptr(list, item) != -1; | ||
126 | } | ||
127 | |||
128 | /* Adds a list item, insert last, if not already present. */ | ||
129 | void list_add_item(void **list, void *item) | ||
130 | { | ||
131 | void **item_p = rb->find_array_ptr(list, item); | ||
132 | if (*item_p == NULL) | ||
133 | *item_p = item; | ||
134 | } | ||
135 | |||
136 | /* Clears the entire list. */ | ||
137 | void list_clear_all(void **list) | ||
138 | { | ||
139 | while (*list != NULL) | ||
140 | *list++ = NULL; | ||
141 | } | ||
142 | |||
143 | /* Enumerate all items in the array, passing each item in turn to the | ||
144 | * callback as well as the data value. The current item may be safely | ||
145 | * removed. Other changes during enumeration are undefined. The callback | ||
146 | * may return 'false' to stop the enumeration early. */ | ||
147 | void list_enum_items(void **list, | ||
148 | list_enum_callback_t callback, | ||
149 | intptr_t data) | ||
150 | { | ||
151 | for (;;) | ||
152 | { | ||
153 | void *item = *list; | ||
154 | |||
155 | if (item == NULL) | ||
156 | break; | ||
157 | |||
158 | if (callback != NULL && !callback(item, data)) | ||
159 | break; | ||
160 | |||
161 | if (*list == item) | ||
162 | list++; /* Item still there */ | ||
163 | } | ||
164 | } | ||
diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h index 5f60193d52..c36f4faddc 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.h +++ b/apps/plugins/mpegplayer/mpeg_misc.h | |||
@@ -202,4 +202,30 @@ uint32_t muldiv_uint32(uint32_t multiplicand, | |||
202 | uint32_t multiplier, | 202 | uint32_t multiplier, |
203 | uint32_t divisor); | 203 | uint32_t divisor); |
204 | 204 | ||
205 | |||
206 | /** Lists **/ | ||
207 | |||
208 | /* Does the list have any members? */ | ||
209 | bool list_is_empty(void **list); | ||
210 | |||
211 | /* Is the item inserted into a particular list? */ | ||
212 | bool list_is_member(void **list, void *item); | ||
213 | |||
214 | /* Removes an item from a list - returns true if item was found | ||
215 | * and thus removed. */ | ||
216 | bool list_remove_item(void **list, void *item); | ||
217 | |||
218 | /* Adds a list item, insert last, if not already present. */ | ||
219 | void list_add_item(void **list, void *item); | ||
220 | |||
221 | /* Clears the entire list. */ | ||
222 | void list_clear_all(void **list); | ||
223 | |||
224 | /* Enumerate all items in the array. */ | ||
225 | typedef bool (*list_enum_callback_t)(void *item, intptr_t data); | ||
226 | |||
227 | void list_enum_items(void **list, | ||
228 | list_enum_callback_t callback, | ||
229 | intptr_t data); | ||
230 | |||
205 | #endif /* MPEG_MISC_H */ | 231 | #endif /* MPEG_MISC_H */ |
diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h index bf223c3330..f6617cedff 100644 --- a/apps/plugins/mpegplayer/mpegplayer.h +++ b/apps/plugins/mpegplayer/mpegplayer.h | |||
@@ -31,6 +31,9 @@ | |||
31 | #endif | 31 | #endif |
32 | /* #else function-like empty macros are defined in the headers */ | 32 | /* #else function-like empty macros are defined in the headers */ |
33 | 33 | ||
34 | /* Should be enough for now */ | ||
35 | #define MPEGPLAYER_MAX_STREAMS 4 | ||
36 | |||
34 | /* Memory allotments for various subsystems */ | 37 | /* Memory allotments for various subsystems */ |
35 | #define MIN_MEMMARGIN (4*1024) | 38 | #define MIN_MEMMARGIN (4*1024) |
36 | 39 | ||
@@ -85,7 +88,6 @@ | |||
85 | #include "mpeg2.h" | 88 | #include "mpeg2.h" |
86 | #include "video_out.h" | 89 | #include "video_out.h" |
87 | #include "mpeg_stream.h" | 90 | #include "mpeg_stream.h" |
88 | #include "mpeg_linkedlist.h" | ||
89 | #include "mpeg_misc.h" | 91 | #include "mpeg_misc.h" |
90 | #include "mpeg_alloc.h" | 92 | #include "mpeg_alloc.h" |
91 | #include "stream_thread.h" | 93 | #include "stream_thread.h" |
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c index 065843a344..2eed3d355d 100644 --- a/apps/plugins/mpegplayer/stream_mgr.c +++ b/apps/plugins/mpegplayer/stream_mgr.c | |||
@@ -148,21 +148,21 @@ void stream_add_stream(struct stream *str) | |||
148 | { | 148 | { |
149 | actl_lock(); | 149 | actl_lock(); |
150 | 150 | ||
151 | list_remove_item(&str->l); | 151 | list_remove_item(stream_mgr.strl, str); |
152 | list_add_item(&stream_mgr.strl, &str->l); | 152 | list_add_item(stream_mgr.strl, str); |
153 | 153 | ||
154 | actl_unlock(); | 154 | actl_unlock(); |
155 | } | 155 | } |
156 | 156 | ||
157 | /* Callback for various list-moving operations */ | 157 | /* Callback for various list-moving operations */ |
158 | static bool strl_enum_callback(struct list_item *item, intptr_t data) | 158 | static bool strl_enum_callback(struct stream *str, intptr_t data) |
159 | { | 159 | { |
160 | actl_lock(); | 160 | actl_lock(); |
161 | 161 | ||
162 | list_remove_item(item); | 162 | list_remove_item(stream_mgr.strl, str); |
163 | 163 | ||
164 | if (data == 1) | 164 | if (data == 1) |
165 | list_add_item(&stream_mgr.actl, item); | 165 | list_add_item(stream_mgr.actl, str); |
166 | 166 | ||
167 | actl_unlock(); | 167 | actl_unlock(); |
168 | 168 | ||
@@ -172,38 +172,38 @@ static bool strl_enum_callback(struct list_item *item, intptr_t data) | |||
172 | /* Clear all streams from active and playback pools */ | 172 | /* Clear all streams from active and playback pools */ |
173 | void stream_remove_streams(void) | 173 | void stream_remove_streams(void) |
174 | { | 174 | { |
175 | list_enum_items(&stream_mgr.strl, strl_enum_callback, 0); | 175 | list_enum_items(stream_mgr.strl, |
176 | (list_enum_callback_t)strl_enum_callback, 0); | ||
176 | } | 177 | } |
177 | 178 | ||
178 | /* Move the playback pool to the active list */ | 179 | /* Move the playback pool to the active list */ |
179 | void move_strl_to_actl(void) | 180 | void move_strl_to_actl(void) |
180 | { | 181 | { |
181 | list_enum_items(&stream_mgr.strl, strl_enum_callback, 1); | 182 | list_enum_items(stream_mgr.strl, |
183 | (list_enum_callback_t)strl_enum_callback, 1); | ||
182 | } | 184 | } |
183 | 185 | ||
184 | /* Remove a stream from the active list and return it to the pool */ | 186 | /* Remove a stream from the active list and return it to the pool */ |
185 | static bool actl_stream_remove(struct stream *str) | 187 | static bool actl_stream_remove(struct stream *str) |
186 | { | 188 | { |
187 | if (list_is_member(&stream_mgr.actl, &str->l)) | 189 | bool retval; |
188 | { | ||
189 | actl_lock(); | ||
190 | 190 | ||
191 | list_remove_item(&str->l); | 191 | actl_lock(); |
192 | list_add_item(&stream_mgr.strl, &str->l); | ||
193 | 192 | ||
194 | actl_unlock(); | 193 | retval = list_remove_item(stream_mgr.actl, str); |
195 | return true; | 194 | |
196 | } | 195 | if (retval) |
196 | list_add_item(stream_mgr.strl, str); | ||
197 | 197 | ||
198 | return false; | 198 | actl_unlock(); |
199 | |||
200 | return retval; | ||
199 | } | 201 | } |
200 | 202 | ||
201 | /* Broadcast a message to all active streams */ | 203 | /* Broadcast a message to all active streams */ |
202 | static bool actl_stream_broadcast_callback(struct list_item *item, | 204 | static bool actl_stream_broadcast_callback(struct stream *str, |
203 | struct str_broadcast_data *sbd) | 205 | struct str_broadcast_data *sbd) |
204 | { | 206 | { |
205 | struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l); | ||
206 | |||
207 | switch (sbd->cmd) | 207 | switch (sbd->cmd) |
208 | { | 208 | { |
209 | case STREAM_PLAY: | 209 | case STREAM_PLAY: |
@@ -215,8 +215,8 @@ static bool actl_stream_broadcast_callback(struct list_item *item, | |||
215 | { | 215 | { |
216 | actl_lock(); | 216 | actl_lock(); |
217 | 217 | ||
218 | list_remove_item(item); | 218 | list_remove_item(stream_mgr.actl, str); |
219 | list_add_item(&stream_mgr.strl, item); | 219 | list_add_item(stream_mgr.strl, str); |
220 | 220 | ||
221 | actl_unlock(); | 221 | actl_unlock(); |
222 | sbd->data = 0; | 222 | sbd->data = 0; |
@@ -236,7 +236,7 @@ static void actl_stream_broadcast(int cmd, intptr_t data) | |||
236 | struct str_broadcast_data sbd; | 236 | struct str_broadcast_data sbd; |
237 | sbd.cmd = cmd; | 237 | sbd.cmd = cmd; |
238 | sbd.data = data; | 238 | sbd.data = data; |
239 | list_enum_items(&stream_mgr.actl, | 239 | list_enum_items(stream_mgr.actl, |
240 | (list_enum_callback_t)actl_stream_broadcast_callback, | 240 | (list_enum_callback_t)actl_stream_broadcast_callback, |
241 | (intptr_t)&sbd); | 241 | (intptr_t)&sbd); |
242 | } | 242 | } |
@@ -623,7 +623,7 @@ static void stream_on_ev_complete(struct stream *str) | |||
623 | { | 623 | { |
624 | /* No - remove this stream from the active list */ | 624 | /* No - remove this stream from the active list */ |
625 | DEBUGF(" finished: 0x%02x\n", str->id); | 625 | DEBUGF(" finished: 0x%02x\n", str->id); |
626 | if (list_is_empty(&stream_mgr.actl)) | 626 | if (list_is_empty(stream_mgr.actl)) |
627 | { | 627 | { |
628 | /* All streams have acked - stop playback */ | 628 | /* All streams have acked - stop playback */ |
629 | stream_on_stop(false); | 629 | stream_on_stop(false); |
@@ -820,10 +820,9 @@ void stream_wait_status(void) | |||
820 | 820 | ||
821 | /* Returns the smallest file window that includes all active streams' | 821 | /* Returns the smallest file window that includes all active streams' |
822 | * windows */ | 822 | * windows */ |
823 | static bool stream_get_window_callback(struct list_item *item, | 823 | static bool stream_get_window_callback(struct stream *str, |
824 | struct stream_window *sw) | 824 | struct stream_window *sw) |
825 | { | 825 | { |
826 | struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l); | ||
827 | off_t swl = str->hdr.win_left; | 826 | off_t swl = str->hdr.win_left; |
828 | off_t swr = str->hdr.win_right; | 827 | off_t swr = str->hdr.win_right; |
829 | 828 | ||
@@ -845,7 +844,7 @@ bool stream_get_window(struct stream_window *sw) | |||
845 | sw->right = LONG_MIN; | 844 | sw->right = LONG_MIN; |
846 | 845 | ||
847 | actl_lock(); | 846 | actl_lock(); |
848 | list_enum_items(&stream_mgr.actl, | 847 | list_enum_items(stream_mgr.actl, |
849 | (list_enum_callback_t)stream_get_window_callback, | 848 | (list_enum_callback_t)stream_get_window_callback, |
850 | (intptr_t)sw); | 849 | (intptr_t)sw); |
851 | actl_unlock(); | 850 | actl_unlock(); |
@@ -981,7 +980,6 @@ int stream_init(void) | |||
981 | 980 | ||
982 | stream_mgr.status = STREAM_STOPPED; | 981 | stream_mgr.status = STREAM_STOPPED; |
983 | stream_mgr_init_state(); | 982 | stream_mgr_init_state(); |
984 | list_initialize(&stream_mgr.actl); | ||
985 | 983 | ||
986 | /* Initialize our window to the outside world first */ | 984 | /* Initialize our window to the outside world first */ |
987 | rb->mutex_init(&stream_mgr.str_mtx); | 985 | rb->mutex_init(&stream_mgr.str_mtx); |
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h index a00b39f189..a07305a847 100644 --- a/apps/plugins/mpegplayer/stream_mgr.h +++ b/apps/plugins/mpegplayer/stream_mgr.h | |||
@@ -35,8 +35,8 @@ struct stream_mgr | |||
35 | bool seeked; /* A seek happened and things must be | 35 | bool seeked; /* A seek happened and things must be |
36 | resynced */ | 36 | resynced */ |
37 | int status; /* Current playback status */ | 37 | int status; /* Current playback status */ |
38 | struct list_item strl; /* List of available streams */ | 38 | void *strl[MPEGPLAYER_MAX_STREAMS+1]; /* List of available streams */ |
39 | struct list_item actl; /* List of active streams */ | 39 | void *actl[MPEGPLAYER_MAX_STREAMS+1]; /* List of active streams */ |
40 | struct mutex str_mtx; /* Main stream manager mutex */ | 40 | struct mutex str_mtx; /* Main stream manager mutex */ |
41 | struct mutex actl_mtx; /* Lock for current-streams list */ | 41 | struct mutex actl_mtx; /* Lock for current-streams list */ |
42 | union /* A place for reusable non-cacheable parameters */ | 42 | union /* A place for reusable non-cacheable parameters */ |
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h index 30bf46e6ff..1d3a445735 100644 --- a/apps/plugins/mpegplayer/stream_thread.h +++ b/apps/plugins/mpegplayer/stream_thread.h | |||
@@ -39,7 +39,6 @@ struct stream_hdr | |||
39 | off_t pos; /* Start/current position for random-access read */ | 39 | off_t pos; /* Start/current position for random-access read */ |
40 | }; | 40 | }; |
41 | off_t limit; /* Limit for random-access read */ | 41 | off_t limit; /* Limit for random-access read */ |
42 | struct list_item nf; /* List for data notification */ | ||
43 | }; | 42 | }; |
44 | 43 | ||
45 | struct stream | 44 | struct stream |
@@ -48,8 +47,6 @@ struct stream | |||
48 | unsigned int thread; /* Stream's thread */ | 47 | unsigned int thread; /* Stream's thread */ |
49 | uint8_t* curr_packet; /* Current stream packet beginning */ | 48 | uint8_t* curr_packet; /* Current stream packet beginning */ |
50 | uint8_t* curr_packet_end; /* Current stream packet end */ | 49 | uint8_t* curr_packet_end; /* Current stream packet end */ |
51 | struct list_item l; /* List of streams - either reserve pool | ||
52 | or active pool */ | ||
53 | int state; /* State machine parsing mode */ | 50 | int state; /* State machine parsing mode */ |
54 | uint32_t start_pts; /* First timestamp for stream */ | 51 | uint32_t start_pts; /* First timestamp for stream */ |
55 | uint32_t end_pts; /* Last timestamp for stream */ | 52 | uint32_t end_pts; /* Last timestamp for stream */ |
@@ -58,6 +55,8 @@ struct stream | |||
58 | unsigned id; /* Stream identifier */ | 55 | unsigned id; /* Stream identifier */ |
59 | }; | 56 | }; |
60 | 57 | ||
58 | #define STR_FROM_HDR(sh) ((struct stream *)(sh)) | ||
59 | |||
61 | /* Make sure there there is always enough data buffered ahead for | 60 | /* Make sure there there is always enough data buffered ahead for |
62 | * the worst possible case - regardless of whether a valid stream | 61 | * the worst possible case - regardless of whether a valid stream |
63 | * would actually produce that */ | 62 | * would actually produce that */ |
@@ -145,8 +144,6 @@ enum stream_status | |||
145 | STREAM_NOT_FOUND, /* Match not found */ | 144 | STREAM_NOT_FOUND, /* Match not found */ |
146 | }; | 145 | }; |
147 | 146 | ||
148 | #define STR_FROM_HEADER(sh) ((struct stream *)(sh)) | ||
149 | |||
150 | /* Clip time to range for a particular stream */ | 147 | /* Clip time to range for a particular stream */ |
151 | static inline uint32_t clip_time(struct stream *str, uint32_t time) | 148 | static inline uint32_t clip_time(struct stream *str, uint32_t time) |
152 | { | 149 | { |
diff --git a/firmware/export/general.h b/firmware/export/general.h index 8da4a0ad59..16c824086b 100644 --- a/firmware/export/general.h +++ b/firmware/export/general.h | |||
@@ -72,4 +72,19 @@ char *create_datetime_filename(char *buffer, const char *path, | |||
72 | bool unique_time); | 72 | bool unique_time); |
73 | #endif /* CONFIG_RTC */ | 73 | #endif /* CONFIG_RTC */ |
74 | 74 | ||
75 | /*** | ||
76 | ** Compacted pointer lists | ||
77 | ** | ||
78 | ** N-length list requires N+1 elements to ensure NULL-termination. | ||
79 | **/ | ||
80 | |||
81 | /* Find a pointer in a pointer array. Returns the addess of the element if | ||
82 | found or the address of the terminating NULL otherwise. This can be used | ||
83 | to bounds check and add items. */ | ||
84 | void ** find_array_ptr(void **arr, void *ptr); | ||
85 | |||
86 | /* Remove a pointer from a pointer array if it exists. Compacts it so that | ||
87 | no gaps exist. Returns 0 on success and -1 if the element wasn't found. */ | ||
88 | int remove_array_ptr(void **arr, void *ptr); | ||
89 | |||
75 | #endif /* GENERAL_H */ | 90 | #endif /* GENERAL_H */ |
diff --git a/firmware/general.c b/firmware/general.c index fa1025492b..20b0277c09 100644 --- a/firmware/general.c +++ b/firmware/general.c | |||
@@ -196,3 +196,40 @@ char *create_datetime_filename(char *buffer, const char *path, | |||
196 | return buffer; | 196 | return buffer; |
197 | } | 197 | } |
198 | #endif /* CONFIG_RTC */ | 198 | #endif /* CONFIG_RTC */ |
199 | |||
200 | /*** | ||
201 | ** Compacted pointer lists | ||
202 | ** | ||
203 | ** N-length list requires N+1 elements to ensure NULL-termination. | ||
204 | **/ | ||
205 | |||
206 | /* Find a pointer in a pointer array. Returns the addess of the element if | ||
207 | * found or the address of the terminating NULL otherwise. This can be used | ||
208 | * to bounds check and add items. */ | ||
209 | void ** find_array_ptr(void **arr, void *ptr) | ||
210 | { | ||
211 | void *curr; | ||
212 | for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr)); | ||
213 | return arr; | ||
214 | } | ||
215 | |||
216 | /* Remove a pointer from a pointer array if it exists. Compacts it so that | ||
217 | * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */ | ||
218 | int remove_array_ptr(void **arr, void *ptr) | ||
219 | { | ||
220 | void *curr; | ||
221 | arr = find_array_ptr(arr, ptr); | ||
222 | |||
223 | if (*arr == NULL) | ||
224 | return -1; | ||
225 | |||
226 | /* Found. Slide up following items. */ | ||
227 | do | ||
228 | { | ||
229 | void **arr1 = arr + 1; | ||
230 | *arr++ = curr = *arr1; | ||
231 | } | ||
232 | while (curr != NULL); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
diff --git a/firmware/kernel.c b/firmware/kernel.c index d8c67e8485..fe40c35002 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "system.h" | 27 | #include "system.h" |
28 | #include "panic.h" | 28 | #include "panic.h" |
29 | #include "debug.h" | 29 | #include "debug.h" |
30 | #include "general.h" | ||
30 | 31 | ||
31 | /* Make this nonzero to enable more elaborate checks on objects */ | 32 | /* Make this nonzero to enable more elaborate checks on objects */ |
32 | #if defined(DEBUG) || defined(SIMULATOR) | 33 | #if defined(DEBUG) || defined(SIMULATOR) |
@@ -62,40 +63,6 @@ static struct | |||
62 | } all_queues SHAREDBSS_ATTR; | 63 | } all_queues SHAREDBSS_ATTR; |
63 | 64 | ||
64 | /**************************************************************************** | 65 | /**************************************************************************** |
65 | * Common utilities | ||
66 | ****************************************************************************/ | ||
67 | |||
68 | /* Find a pointer in a pointer array. Returns the addess of the element if | ||
69 | * found or the address of the terminating NULL otherwise. */ | ||
70 | static void ** find_array_ptr(void **arr, void *ptr) | ||
71 | { | ||
72 | void *curr; | ||
73 | for(curr = *arr; curr != NULL && curr != ptr; curr = *(++arr)); | ||
74 | return arr; | ||
75 | } | ||
76 | |||
77 | /* Remove a pointer from a pointer array if it exists. Compacts it so that | ||
78 | * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */ | ||
79 | static int remove_array_ptr(void **arr, void *ptr) | ||
80 | { | ||
81 | void *curr; | ||
82 | arr = find_array_ptr(arr, ptr); | ||
83 | |||
84 | if(*arr == NULL) | ||
85 | return -1; | ||
86 | |||
87 | /* Found. Slide up following items. */ | ||
88 | do | ||
89 | { | ||
90 | void **arr1 = arr + 1; | ||
91 | *arr++ = curr = *arr1; | ||
92 | } | ||
93 | while(curr != NULL); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /**************************************************************************** | ||
99 | * Standard kernel stuff | 66 | * Standard kernel stuff |
100 | ****************************************************************************/ | 67 | ****************************************************************************/ |
101 | void kernel_init(void) | 68 | void kernel_init(void) |