Mercurial > pt1.oyama
comparison libdlna-0.2.3/src/profiles.c @ 129:4f6d9621ee00
add multi session streaming & add depending librarys.
- libupnp-1.6.6
- libdlna-0.2.3
author | Naoya OYAMA <naoya.oyama@gmail.com> |
---|---|
date | Sun, 10 Oct 2010 15:33:18 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
128:3a7d8d2f0585 | 129:4f6d9621ee00 |
---|---|
1 /* | |
2 * libdlna: reference DLNA standards implementation. | |
3 * Copyright (C) 2007 Benjamin Zores <ben@geexbox.org> | |
4 * | |
5 * This file is part of libdlna. | |
6 * | |
7 * libdlna is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * libdlna is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with libdlna; if not, write to the Free Software | |
19 * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include <stdlib.h> | |
23 #include <string.h> | |
24 | |
25 #include "dlna_internals.h" | |
26 #include "profiles.h" | |
27 #include "containers.h" | |
28 | |
29 extern dlna_registered_profile_t dlna_profile_image_jpeg; | |
30 extern dlna_registered_profile_t dlna_profile_image_png; | |
31 extern dlna_registered_profile_t dlna_profile_audio_ac3; | |
32 extern dlna_registered_profile_t dlna_profile_audio_amr; | |
33 extern dlna_registered_profile_t dlna_profile_audio_atrac3; | |
34 extern dlna_registered_profile_t dlna_profile_audio_lpcm; | |
35 extern dlna_registered_profile_t dlna_profile_audio_mp3; | |
36 extern dlna_registered_profile_t dlna_profile_audio_mpeg4; | |
37 extern dlna_registered_profile_t dlna_profile_audio_wma; | |
38 extern dlna_registered_profile_t dlna_profile_av_mpeg1; | |
39 extern dlna_registered_profile_t dlna_profile_av_mpeg2; | |
40 extern dlna_registered_profile_t dlna_profile_av_mpeg4_part2; | |
41 extern dlna_registered_profile_t dlna_profile_av_mpeg4_part10; | |
42 extern dlna_registered_profile_t dlna_profile_av_wmv9; | |
43 | |
44 static void | |
45 dlna_register_profile (dlna_t *dlna, dlna_registered_profile_t *profile) | |
46 { | |
47 void **p; | |
48 | |
49 if (!dlna) | |
50 return; | |
51 | |
52 if (!dlna->inited) | |
53 dlna = dlna_init (); | |
54 | |
55 p = &dlna->first_profile; | |
56 while (*p != NULL) | |
57 { | |
58 if (((dlna_registered_profile_t *) *p)->id == profile->id) | |
59 return; /* already registered */ | |
60 p = (void *) &((dlna_registered_profile_t *) *p)->next; | |
61 } | |
62 *p = profile; | |
63 profile->next = NULL; | |
64 } | |
65 | |
66 void | |
67 dlna_register_all_media_profiles (dlna_t *dlna) | |
68 { | |
69 if (!dlna) | |
70 return; | |
71 | |
72 if (!dlna->inited) | |
73 dlna = dlna_init (); | |
74 | |
75 dlna_register_profile (dlna, &dlna_profile_image_jpeg); | |
76 dlna_register_profile (dlna, &dlna_profile_image_png); | |
77 dlna_register_profile (dlna, &dlna_profile_audio_ac3); | |
78 dlna_register_profile (dlna, &dlna_profile_audio_amr); | |
79 dlna_register_profile (dlna, &dlna_profile_audio_atrac3); | |
80 dlna_register_profile (dlna, &dlna_profile_audio_lpcm); | |
81 dlna_register_profile (dlna, &dlna_profile_audio_mp3); | |
82 dlna_register_profile (dlna, &dlna_profile_audio_mpeg4); | |
83 dlna_register_profile (dlna, &dlna_profile_audio_wma); | |
84 dlna_register_profile (dlna, &dlna_profile_av_mpeg1); | |
85 dlna_register_profile (dlna, &dlna_profile_av_mpeg2); | |
86 dlna_register_profile (dlna, &dlna_profile_av_mpeg4_part2); | |
87 dlna_register_profile (dlna, &dlna_profile_av_mpeg4_part10); | |
88 dlna_register_profile (dlna, &dlna_profile_av_wmv9); | |
89 } | |
90 | |
91 void | |
92 dlna_register_media_profile (dlna_t *dlna, dlna_media_profile_t profile) | |
93 { | |
94 if (!dlna) | |
95 return; | |
96 | |
97 if (!dlna->inited) | |
98 dlna = dlna_init (); | |
99 | |
100 switch (profile) | |
101 { | |
102 case DLNA_PROFILE_IMAGE_JPEG: | |
103 dlna_register_profile (dlna, &dlna_profile_image_jpeg); | |
104 break; | |
105 case DLNA_PROFILE_IMAGE_PNG: | |
106 dlna_register_profile (dlna, &dlna_profile_image_png); | |
107 break; | |
108 case DLNA_PROFILE_AUDIO_AC3: | |
109 dlna_register_profile (dlna, &dlna_profile_audio_ac3); | |
110 break; | |
111 case DLNA_PROFILE_AUDIO_AMR: | |
112 dlna_register_profile (dlna, &dlna_profile_audio_amr); | |
113 break; | |
114 case DLNA_PROFILE_AUDIO_ATRAC3: | |
115 dlna_register_profile (dlna, &dlna_profile_audio_atrac3); | |
116 break; | |
117 case DLNA_PROFILE_AUDIO_LPCM: | |
118 dlna_register_profile (dlna, &dlna_profile_audio_lpcm); | |
119 break; | |
120 case DLNA_PROFILE_AUDIO_MP3: | |
121 dlna_register_profile (dlna, &dlna_profile_audio_mp3); | |
122 break; | |
123 case DLNA_PROFILE_AUDIO_MPEG4: | |
124 dlna_register_profile (dlna, &dlna_profile_audio_mpeg4); | |
125 break; | |
126 case DLNA_PROFILE_AUDIO_WMA: | |
127 dlna_register_profile (dlna, &dlna_profile_audio_wma); | |
128 break; | |
129 case DLNA_PROFILE_AV_MPEG1: | |
130 dlna_register_profile (dlna, &dlna_profile_av_mpeg1); | |
131 break; | |
132 case DLNA_PROFILE_AV_MPEG2: | |
133 dlna_register_profile (dlna, &dlna_profile_av_mpeg2); | |
134 break; | |
135 case DLNA_PROFILE_AV_MPEG4_PART2: | |
136 dlna_register_profile (dlna, &dlna_profile_av_mpeg4_part2); | |
137 break; | |
138 case DLNA_PROFILE_AV_MPEG4_PART10: | |
139 dlna_register_profile (dlna, &dlna_profile_av_mpeg4_part10); | |
140 break; | |
141 case DLNA_PROFILE_AV_WMV9: | |
142 dlna_register_profile (dlna, &dlna_profile_av_wmv9); | |
143 break; | |
144 default: | |
145 break; | |
146 } | |
147 } | |
148 | |
149 dlna_t * | |
150 dlna_init (void) | |
151 { | |
152 dlna_t *dlna; | |
153 | |
154 dlna = malloc (sizeof (dlna_t)); | |
155 dlna->inited = 1; | |
156 dlna->verbosity = 0; | |
157 dlna->first_profile = NULL; | |
158 | |
159 /* register all FFMPEG demuxers */ | |
160 av_register_all (); | |
161 | |
162 return dlna; | |
163 } | |
164 | |
165 void | |
166 dlna_uninit (dlna_t *dlna) | |
167 { | |
168 if (!dlna) | |
169 return; | |
170 | |
171 dlna->inited = 0; | |
172 if (dlna->verbosity) | |
173 fprintf (stderr, "DLNA: uninit\n"); | |
174 dlna->first_profile = NULL; | |
175 free (dlna); | |
176 } | |
177 | |
178 void | |
179 dlna_set_verbosity (dlna_t *dlna, int level) | |
180 { | |
181 if (!dlna) | |
182 return; | |
183 | |
184 dlna->verbosity = level; | |
185 } | |
186 | |
187 void | |
188 dlna_set_extension_check (dlna_t *dlna, int level) | |
189 { | |
190 if (!dlna) | |
191 return; | |
192 | |
193 dlna->check_extensions = level; | |
194 } | |
195 | |
196 static av_codecs_t * | |
197 av_profile_get_codecs (AVFormatContext *ctx) | |
198 { | |
199 av_codecs_t *codecs = NULL; | |
200 unsigned int i; | |
201 int audio_stream = -1, video_stream = -1; | |
202 | |
203 codecs = malloc (sizeof (av_codecs_t)); | |
204 | |
205 for (i = 0; i < ctx->nb_streams; i++) | |
206 { | |
207 if (audio_stream == -1 && | |
208 ctx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) | |
209 { | |
210 audio_stream = i; | |
211 continue; | |
212 } | |
213 else if (video_stream == -1 && | |
214 ctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) | |
215 { | |
216 video_stream = i; | |
217 continue; | |
218 } | |
219 } | |
220 | |
221 codecs->as = audio_stream >= 0 ? ctx->streams[audio_stream] : NULL; | |
222 codecs->ac = audio_stream >= 0 ? ctx->streams[audio_stream]->codec : NULL; | |
223 | |
224 codecs->vs = video_stream >= 0 ? ctx->streams[video_stream] : NULL; | |
225 codecs->vc = video_stream >= 0 ? ctx->streams[video_stream]->codec : NULL; | |
226 | |
227 /* check for at least one video stream and one audio stream in container */ | |
228 if (!codecs->ac && !codecs->vc) | |
229 { | |
230 free (codecs); | |
231 return NULL; | |
232 } | |
233 | |
234 return codecs; | |
235 } | |
236 | |
237 static int | |
238 match_file_extension (const char *filename, const char *extensions) | |
239 { | |
240 const char *ext, *p; | |
241 char ext1[32], *q; | |
242 | |
243 if (!filename) | |
244 return 0; | |
245 | |
246 ext = strrchr (filename, '.'); | |
247 if (ext) | |
248 { | |
249 ext++; | |
250 p = extensions; | |
251 for (;;) | |
252 { | |
253 q = ext1; | |
254 while (*p != '\0' && *p != ',' && (q - ext1 < (int) sizeof (ext1) - 1)) | |
255 *q++ = *p++; | |
256 *q = '\0'; | |
257 if (!strcasecmp (ext1, ext)) | |
258 return 1; | |
259 if (*p == '\0') | |
260 break; | |
261 p++; | |
262 } | |
263 } | |
264 | |
265 return 0; | |
266 } | |
267 | |
268 dlna_profile_t * | |
269 dlna_guess_media_profile (dlna_t *dlna, const char *filename) | |
270 { | |
271 AVFormatContext *ctx; | |
272 dlna_registered_profile_t *p; | |
273 dlna_profile_t *profile = NULL; | |
274 dlna_container_type_t st; | |
275 av_codecs_t *codecs; | |
276 | |
277 if (!dlna) | |
278 return NULL; | |
279 | |
280 if (!dlna->inited) | |
281 dlna = dlna_init (); | |
282 | |
283 if (av_open_input_file (&ctx, filename, NULL, 0, NULL) != 0) | |
284 { | |
285 if (dlna->verbosity) | |
286 fprintf (stderr, "can't open file: %s\n", filename); | |
287 return NULL; | |
288 } | |
289 | |
290 if (av_find_stream_info (ctx) < 0) | |
291 { | |
292 if (dlna->verbosity) | |
293 fprintf (stderr, "can't find stream info\n"); | |
294 return NULL; | |
295 } | |
296 | |
297 #ifdef HAVE_DEBUG | |
298 dump_format (ctx, 0, NULL, 0); | |
299 #endif /* HAVE_DEBUG */ | |
300 | |
301 /* grab codecs info */ | |
302 codecs = av_profile_get_codecs (ctx); | |
303 if (!codecs) | |
304 return NULL; | |
305 | |
306 /* check for container type */ | |
307 st = stream_get_container (ctx); | |
308 | |
309 p = dlna->first_profile; | |
310 while (p) | |
311 { | |
312 dlna_profile_t *prof; | |
313 | |
314 if (dlna->check_extensions) | |
315 { | |
316 if (p->extensions) | |
317 { | |
318 /* check for valid file extension */ | |
319 if (!match_file_extension (filename, p->extensions)) | |
320 { | |
321 p = p->next; | |
322 continue; | |
323 } | |
324 } | |
325 } | |
326 | |
327 prof = p->probe (ctx, st, codecs); | |
328 if (prof) | |
329 { | |
330 profile = prof; | |
331 profile->class = p->class; | |
332 break; | |
333 } | |
334 p = p->next; | |
335 } | |
336 | |
337 av_close_input_file (ctx); | |
338 free (codecs); | |
339 return profile; | |
340 } | |
341 | |
342 /* UPnP ContentDirectory Object Item */ | |
343 #define UPNP_OBJECT_ITEM_PHOTO "object.item.imageItem.photo" | |
344 #define UPNP_OBJECT_ITEM_AUDIO "object.item.audioItem.musicTrack" | |
345 #define UPNP_OBJECT_ITEM_VIDEO "object.item.videoItem.movie" | |
346 | |
347 char * | |
348 dlna_profile_upnp_object_item (dlna_profile_t *profile) | |
349 { | |
350 if (!profile) | |
351 return NULL; | |
352 | |
353 switch (profile->class) | |
354 { | |
355 case DLNA_CLASS_IMAGE: | |
356 return UPNP_OBJECT_ITEM_PHOTO; | |
357 case DLNA_CLASS_AUDIO: | |
358 return UPNP_OBJECT_ITEM_AUDIO; | |
359 case DLNA_CLASS_AV: | |
360 return UPNP_OBJECT_ITEM_VIDEO; | |
361 default: | |
362 break; | |
363 } | |
364 | |
365 return NULL; | |
366 } | |
367 | |
368 int | |
369 stream_ctx_is_image (AVFormatContext *ctx, | |
370 av_codecs_t *codecs, dlna_container_type_t st) | |
371 { | |
372 /* should only have 1 stream */ | |
373 if (ctx->nb_streams > 1) | |
374 return 0; | |
375 | |
376 /* should be inside image container */ | |
377 if (st != CT_IMAGE) | |
378 return 0; | |
379 | |
380 if (!codecs->vc) | |
381 return 0; | |
382 | |
383 return 1; | |
384 } | |
385 | |
386 int | |
387 stream_ctx_is_audio (av_codecs_t *codecs) | |
388 { | |
389 /* we need an audio codec ... */ | |
390 if (!codecs->ac) | |
391 return 0; | |
392 | |
393 /* ... but no video one */ | |
394 if (codecs->vc) | |
395 return 0; | |
396 | |
397 return 1; | |
398 } | |
399 | |
400 int | |
401 stream_ctx_is_av (av_codecs_t *codecs) | |
402 { | |
403 if (!codecs->as || !codecs->ac || !codecs->vs || !codecs->vc) | |
404 return 0; | |
405 | |
406 return 1; | |
407 } | |
408 | |
409 char * | |
410 get_file_extension (const char *filename) | |
411 { | |
412 char *str = NULL; | |
413 | |
414 str = strrchr (filename, '.'); | |
415 if (str) | |
416 str++; | |
417 | |
418 return str; | |
419 } | |
420 | |
421 char * | |
422 dlna_write_protocol_info (dlna_protocol_info_type_t type, | |
423 dlna_org_play_speed_t speed, | |
424 dlna_org_conversion_t ci, | |
425 dlna_org_operation_t op, | |
426 dlna_org_flags_t flags, | |
427 dlna_profile_t *p) | |
428 { | |
429 char protocol[512]; | |
430 char dlna_info[448]; | |
431 | |
432 if (type == DLNA_PROTOCOL_INFO_TYPE_HTTP) | |
433 sprintf (protocol, "http-get:*:"); | |
434 | |
435 strcat (protocol, p->mime); | |
436 strcat (protocol, ":"); | |
437 | |
438 sprintf (dlna_info, "%s=%d;%s=%d;%s=%.2x;%s=%s;%s=%.8x%.24x", | |
439 "DLNA.ORG_PS", speed, "DLNA.ORG_CI", ci, | |
440 "DLNA.ORG_OP", op, "DLNA.ORG_PN", p->id, | |
441 "DLNA.ORG_FLAGS", flags, 0); | |
442 strcat (protocol, dlna_info); | |
443 | |
444 return strdup (protocol); | |
445 } | |
446 | |
447 audio_profile_t | |
448 audio_profile_guess (AVCodecContext *ac) | |
449 { | |
450 audio_profile_t ap = AUDIO_PROFILE_INVALID; | |
451 | |
452 if (!ac) | |
453 return ap; | |
454 | |
455 ap = audio_profile_guess_aac (ac); | |
456 if (ap != AUDIO_PROFILE_INVALID) | |
457 return ap; | |
458 | |
459 ap = audio_profile_guess_ac3 (ac); | |
460 if (ap != AUDIO_PROFILE_INVALID) | |
461 return ap; | |
462 | |
463 ap = audio_profile_guess_amr (ac); | |
464 if (ap != AUDIO_PROFILE_INVALID) | |
465 return ap; | |
466 | |
467 ap = audio_profile_guess_atrac (ac); | |
468 if (ap != AUDIO_PROFILE_INVALID) | |
469 return ap; | |
470 | |
471 ap = audio_profile_guess_g726 (ac); | |
472 if (ap != AUDIO_PROFILE_INVALID) | |
473 return ap; | |
474 | |
475 ap = audio_profile_guess_lpcm (ac); | |
476 if (ap != AUDIO_PROFILE_INVALID) | |
477 return ap; | |
478 | |
479 ap = audio_profile_guess_mp2 (ac); | |
480 if (ap != AUDIO_PROFILE_INVALID) | |
481 return ap; | |
482 | |
483 ap = audio_profile_guess_mp3 (ac); | |
484 if (ap != AUDIO_PROFILE_INVALID) | |
485 return ap; | |
486 | |
487 ap = audio_profile_guess_wma (ac); | |
488 if (ap != AUDIO_PROFILE_INVALID) | |
489 return ap; | |
490 | |
491 return AUDIO_PROFILE_INVALID; | |
492 } |