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 }