diff options
Diffstat (limited to 'src/media.c')
-rw-r--r-- | src/media.c | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/src/media.c b/src/media.c index 9f6acd19..5d88fbc4 100644 --- a/src/media.c +++ b/src/media.c | |||
@@ -23,26 +23,44 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
23 | #include "media.h" | 23 | #include "media.h" |
24 | #include "gmdocument.h" | 24 | #include "gmdocument.h" |
25 | #include "ui/window.h" | 25 | #include "ui/window.h" |
26 | #include "audio/player.h" | ||
26 | 27 | ||
27 | #include <the_Foundation/ptrarray.h> | 28 | #include <the_Foundation/ptrarray.h> |
28 | #include <stb_image.h> | 29 | #include <stb_image.h> |
29 | #include <SDL_hints.h> | 30 | #include <SDL_hints.h> |
30 | #include <SDL_render.h> | 31 | #include <SDL_render.h> |
31 | 32 | ||
33 | iDeclareType(GmMediaProps) | ||
34 | |||
35 | struct Impl_GmMediaProps { | ||
36 | iGmLinkId linkId; | ||
37 | iString mime; | ||
38 | iBool isPermanent; | ||
39 | }; | ||
40 | |||
41 | static void init_GmMediaProps_(iGmMediaProps *d) { | ||
42 | d->linkId = 0; | ||
43 | init_String(&d->mime); | ||
44 | d->isPermanent = iFalse; | ||
45 | } | ||
46 | |||
47 | static void deinit_GmMediaProps_(iGmMediaProps *d) { | ||
48 | deinit_String(&d->mime); | ||
49 | } | ||
50 | |||
51 | /*----------------------------------------------------------------------------------------------*/ | ||
52 | |||
32 | iDeclareType(GmImage) | 53 | iDeclareType(GmImage) |
33 | 54 | ||
34 | struct Impl_GmImage { | 55 | struct Impl_GmImage { |
56 | iGmMediaProps props; | ||
35 | iInt2 size; | 57 | iInt2 size; |
36 | size_t numBytes; | 58 | size_t numBytes; |
37 | iString mime; | ||
38 | iGmLinkId linkId; | ||
39 | iBool isPermanent; | ||
40 | SDL_Texture *texture; | 59 | SDL_Texture *texture; |
41 | }; | 60 | }; |
42 | 61 | ||
43 | void init_GmImage(iGmImage *d, const iBlock *data) { | 62 | void init_GmImage(iGmImage *d, const iBlock *data) { |
44 | init_String(&d->mime); | 63 | init_GmMediaProps_(&d->props); |
45 | d->isPermanent = iFalse; | ||
46 | d->numBytes = size_Block(data); | 64 | d->numBytes = size_Block(data); |
47 | uint8_t *imgData = stbi_load_from_memory( | 65 | uint8_t *imgData = stbi_load_from_memory( |
48 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | 66 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); |
@@ -60,30 +78,53 @@ void init_GmImage(iGmImage *d, const iBlock *data) { | |||
60 | SDL_FreeSurface(surface); | 78 | SDL_FreeSurface(surface); |
61 | stbi_image_free(imgData); | 79 | stbi_image_free(imgData); |
62 | } | 80 | } |
63 | d->linkId = 0; | ||
64 | } | 81 | } |
65 | 82 | ||
66 | void deinit_GmImage(iGmImage *d) { | 83 | void deinit_GmImage(iGmImage *d) { |
67 | SDL_DestroyTexture(d->texture); | 84 | SDL_DestroyTexture(d->texture); |
68 | deinit_String(&d->mime); | 85 | deinit_GmMediaProps_(&d->props); |
69 | } | 86 | } |
70 | 87 | ||
71 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) | 88 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) |
72 | 89 | ||
73 | /*----------------------------------------------------------------------------------------------*/ | 90 | /*----------------------------------------------------------------------------------------------*/ |
74 | 91 | ||
92 | iDeclareType(GmAudio) | ||
93 | |||
94 | struct Impl_GmAudio { | ||
95 | iGmMediaProps props; | ||
96 | iPlayer *player; | ||
97 | }; | ||
98 | |||
99 | void init_GmAudio(iGmAudio *d) { | ||
100 | init_GmMediaProps_(&d->props); | ||
101 | d->player = new_Player(); | ||
102 | } | ||
103 | |||
104 | void deinit_GmAudio(iGmAudio *d) { | ||
105 | delete_Player(d->player); | ||
106 | deinit_GmMediaProps_(&d->props); | ||
107 | } | ||
108 | |||
109 | iDefineTypeConstruction(GmAudio) | ||
110 | |||
111 | /*----------------------------------------------------------------------------------------------*/ | ||
112 | |||
75 | struct Impl_Media { | 113 | struct Impl_Media { |
76 | iPtrArray images; | 114 | iPtrArray images; |
115 | iPtrArray audio; | ||
77 | }; | 116 | }; |
78 | 117 | ||
79 | iDefineTypeConstruction(Media) | 118 | iDefineTypeConstruction(Media) |
80 | 119 | ||
81 | void init_Media(iMedia *d) { | 120 | void init_Media(iMedia *d) { |
82 | init_PtrArray(&d->images); | 121 | init_PtrArray(&d->images); |
122 | init_PtrArray(&d->audio); | ||
83 | } | 123 | } |
84 | 124 | ||
85 | void deinit_Media(iMedia *d) { | 125 | void deinit_Media(iMedia *d) { |
86 | clear_Media(d); | 126 | clear_Media(d); |
127 | deinit_PtrArray(&d->audio); | ||
87 | deinit_PtrArray(&d->images); | 128 | deinit_PtrArray(&d->images); |
88 | } | 129 | } |
89 | 130 | ||
@@ -92,25 +133,35 @@ void clear_Media(iMedia *d) { | |||
92 | deinit_GmImage(i.ptr); | 133 | deinit_GmImage(i.ptr); |
93 | } | 134 | } |
94 | clear_PtrArray(&d->images); | 135 | clear_PtrArray(&d->images); |
136 | iForEach(PtrArray, a, &d->audio) { | ||
137 | deinit_GmAudio(a.ptr); | ||
138 | } | ||
139 | clear_PtrArray(&d->audio); | ||
95 | } | 140 | } |
96 | 141 | ||
97 | void setImage_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlock *data, | 142 | void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlock *data, |
98 | iBool allowHide) { | 143 | iBool allowHide) { |
99 | if (!mime || !data) { | 144 | if (!mime || !data) { |
100 | iGmImage *img; | 145 | iMediaId existing = findLinkImage_Media(d, linkId); |
101 | const iMediaId existing = findLinkImage_Media(d, linkId); | ||
102 | if (existing) { | 146 | if (existing) { |
147 | iGmImage *img; | ||
103 | take_PtrArray(&d->images, existing - 1, (void **) &img); | 148 | take_PtrArray(&d->images, existing - 1, (void **) &img); |
104 | delete_GmImage(img); | 149 | delete_GmImage(img); |
105 | } | 150 | } |
151 | else if ((existing = findLinkAudio_Media(d, linkId)) != 0) { | ||
152 | iGmAudio *audio; | ||
153 | take_PtrArray(&d->audio, existing - 1, (void **) &audio); | ||
154 | delete_GmAudio(audio); | ||
155 | } | ||
106 | } | 156 | } |
107 | else { | 157 | else { |
108 | /* TODO: check if we know this MIME type */ | 158 | if (startsWith_String(mime, "image/")) { |
109 | /* Upload the image. */ { | 159 | /* Copy the image to a texture. */ |
160 | /* TODO: Resize down to min(maximum texture size, window size). */ | ||
110 | iGmImage *img = new_GmImage(data); | 161 | iGmImage *img = new_GmImage(data); |
111 | img->linkId = linkId; /* TODO: use a hash? */ | 162 | img->props.linkId = linkId; /* TODO: use a hash? */ |
112 | img->isPermanent = !allowHide; | 163 | img->props.isPermanent = !allowHide; |
113 | set_String(&img->mime, mime); | 164 | set_String(&img->props.mime, mime); |
114 | if (img->texture) { | 165 | if (img->texture) { |
115 | pushBack_PtrArray(&d->images, img); | 166 | pushBack_PtrArray(&d->images, img); |
116 | } | 167 | } |
@@ -118,15 +169,34 @@ void setImage_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo | |||
118 | delete_GmImage(img); | 169 | delete_GmImage(img); |
119 | } | 170 | } |
120 | } | 171 | } |
172 | else if (startsWith_String(mime, "audio/")) { | ||
173 | iGmAudio *audio = new_GmAudio(); | ||
174 | audio->props.linkId = linkId; | ||
175 | audio->props.isPermanent = !allowHide; | ||
176 | set_String(&audio->props.mime, mime); | ||
177 | /* TODO: What about update/complete, for streaming? */ | ||
178 | updateSourceData_Player(audio->player, data, replace_PlayerUpdate); | ||
179 | pushBack_PtrArray(&d->audio, audio); | ||
180 | } | ||
121 | } | 181 | } |
122 | // doLayout_GmDocument_(d); | ||
123 | } | 182 | } |
124 | 183 | ||
125 | iMediaId findLinkImage_Media(const iMedia *d, iGmLinkId linkId) { | 184 | iMediaId findLinkImage_Media(const iMedia *d, iGmLinkId linkId) { |
126 | /* TODO: use a hash */ | 185 | /* TODO: use a hash */ |
127 | iConstForEach(PtrArray, i, &d->images) { | 186 | iConstForEach(PtrArray, i, &d->images) { |
128 | const iGmImage *img = i.ptr; | 187 | const iGmImage *img = i.ptr; |
129 | if (img->linkId == linkId) { | 188 | if (img->props.linkId == linkId) { |
189 | return index_PtrArrayConstIterator(&i) + 1; | ||
190 | } | ||
191 | } | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | iMediaId findLinkAudio_Media(const iMedia *d, iGmLinkId linkId) { | ||
196 | /* TODO: use a hash */ | ||
197 | iConstForEach(PtrArray, i, &d->audio) { | ||
198 | const iGmAudio *audio = i.ptr; | ||
199 | if (audio->props.linkId == linkId) { | ||
130 | return index_PtrArrayConstIterator(&i) + 1; | 200 | return index_PtrArrayConstIterator(&i) + 1; |
131 | } | 201 | } |
132 | } | 202 | } |
@@ -141,15 +211,34 @@ SDL_Texture *imageTexture_Media(const iMedia *d, uint16_t imageId) { | |||
141 | return NULL; | 211 | return NULL; |
142 | } | 212 | } |
143 | 213 | ||
144 | void imageInfo_Media(const iMedia *d, uint16_t imageId, iGmImageInfo *info_out) { | 214 | iBool imageInfo_Media(const iMedia *d, iMediaId imageId, iGmImageInfo *info_out) { |
145 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { | 215 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { |
146 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); | 216 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); |
147 | info_out->size = img->size; | 217 | info_out->size = img->size; |
148 | info_out->numBytes = img->numBytes; | 218 | info_out->numBytes = img->numBytes; |
149 | info_out->mime = cstr_String(&img->mime); | 219 | info_out->mime = cstr_String(&img->props.mime); |
150 | info_out->isPermanent = img->isPermanent; | 220 | info_out->isPermanent = img->props.isPermanent; |
221 | return iTrue; | ||
151 | } | 222 | } |
152 | else { | 223 | iZap(*info_out); |
153 | iZap(*info_out); | 224 | return iFalse; |
225 | } | ||
226 | |||
227 | iPlayer *audioData_Media(const iMedia *d, iMediaId audioId) { | ||
228 | if (audioId > 0 && audioId <= size_PtrArray(&d->audio)) { | ||
229 | const iGmAudio *audio = constAt_PtrArray(&d->audio, audioId - 1); | ||
230 | return audio->player; | ||
231 | } | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | iBool audioInfo_Media(const iMedia *d, iMediaId audioId, iGmAudioInfo *info_out) { | ||
236 | if (audioId > 0 && audioId <= size_PtrArray(&d->audio)) { | ||
237 | const iGmAudio *audio = constAt_PtrArray(&d->audio, audioId - 1); | ||
238 | info_out->mime = cstr_String(&audio->props.mime); | ||
239 | info_out->isPermanent = audio->props.isPermanent; | ||
240 | return iTrue; | ||
154 | } | 241 | } |
242 | iZap(*info_out); | ||
243 | return iFalse; | ||
155 | } | 244 | } |