Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / media / media.c
1 /* Media functions.
2    Copyright (C) 2006 Sebastian Freundt
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Synched up with: Not in FSF. */
21
22 #include <config.h>
23 #include "lisp.h"
24
25 #include "buffer.h"
26
27 #include "media.h"
28 #include "sound.h"
29 #ifdef HAVE_FFMPEG
30 #include "media-ffmpeg.h"
31 #endif
32 #ifdef HAVE_SNDFILE
33 #include "media-sndfile.h"
34 #endif
35 #ifdef HAVE_INTERNAL_MEDIA
36 #include "media-internal.h"
37 #endif
38 #ifdef HAVE_MAD
39 #include "media-mad.h"
40 #endif
41 #ifdef HAVE_GSTREAMER
42 #include "media-gstreamer.h"
43 #endif
44 #ifdef HAVE_SOX
45 #include "media-sox.h"
46 #endif
47 #ifdef HAVE_XINE
48 #include "media-xine.h"
49 #endif
50
51 Lisp_Object Qmedia_streamp;
52 Lisp_Object Qunknown;
53 Lisp_Object Qunavailable;
54 /* media property syms */
55 Lisp_Object Qdemux, Qcodec, Qnchannels, Qsamplerate;
56 Lisp_Object Qbitrate, Qabitrate, Qvbitrate;
57 Lisp_Object Qwidth, Qheight, Qaspect, Qdriver, Qkind, Qfifo, Quri, Qtype;
58 Lisp_Object Qaudio, Qvideo, Qimage;
59
60 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver);
61 static void media_stream_print(Lisp_Object, Lisp_Object, int);
62 static void media_substream_print(media_substream *, Lisp_Object, int);
63 static void media_substream_finalise(void*, int);
64
65 \f
66 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver preferred)
67 {
68 #ifdef HAVE_FFMPEG
69         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
70             (preferred == MDRIVER_UNKNOWN ||
71              preferred == MDRIVER_FFMPEG)) {
72                 MEDIA_DEBUG("trying ffmpeg.\n");
73                 media_stream_set_meths(ms, media_ffmpeg);
74                 media_stream_meth(ms, open)(ms);
75         }
76 #endif
77 #ifdef HAVE_MAD
78         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
79             (preferred == MDRIVER_UNKNOWN ||
80              preferred == MDRIVER_MAD)) {
81                 MEDIA_DEBUG("trying mad.\n");
82                 media_stream_set_meths(ms, media_mad);
83                 media_stream_meth(ms, open)(ms);
84         }
85 #endif
86 #ifdef HAVE_SOX
87         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
88             (preferred == MDRIVER_UNKNOWN ||
89              preferred == MDRIVER_SOX)) {
90                 MEDIA_DEBUG("trying sox.\n");
91                 media_stream_set_meths(ms, media_sox);
92                 media_stream_meth(ms, open)(ms);
93         }
94 #endif
95 #ifdef HAVE_SNDFILE
96         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
97             (preferred == MDRIVER_UNKNOWN ||
98              preferred == MDRIVER_SNDFILE)) {
99                 MEDIA_DEBUG("trying sndfile.\n");
100                 media_stream_set_meths(ms, media_sndfile);
101                 media_stream_meth(ms, open)(ms);
102         }
103 #endif
104 /* not working stuff here :) */
105 #if 0
106 #ifdef HAVE_GSTREAMER
107         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
108             (preferred == MDRIVER_UNKNOWN ||
109              preferred == MDRIVER_GSTREAMER)) {
110                 MEDIA_DEBUG("trying gstreamer.\n");
111                 media_gstreamer_analyse_stream(ms);
112         }
113 #endif
114 #endif
115 #ifdef HAVE_XINE
116         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
117             (preferred == MDRIVER_UNKNOWN ||
118              preferred == MDRIVER_XINE)) {
119                 MEDIA_DEBUG("trying xine.\n");
120                 media_stream_set_meths(ms, media_xine);
121                 media_stream_meth(ms, open)(ms);
122         }
123 #endif
124 #ifdef HAVE_INTERNAL_MEDIA
125         if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
126             (preferred == MDRIVER_UNKNOWN ||
127              preferred == MDRIVER_INTERNAL)) {
128                 MEDIA_DEBUG("trying internal.\n");
129                 media_internal_analyse_stream(ms);
130         }
131 #endif
132         if (media_stream_driver(ms) == MDRIVER_UNKNOWN) {
133                 MEDIA_DEBUG("giving up\n");
134                 media_stream_set_meths(ms, NULL);
135         }
136         return;
137 }
138
139 \f
140 /*****************************************************************/
141 /*                          media streams                        */
142 /*****************************************************************/
143 static Lisp_Object media_stream_mark(Lisp_Object obj)
144 {
145         switch (XMEDIA_STREAM_KIND(obj)) {
146         case MKIND_FILE:
147                 mark_object(XMEDIA_STREAM(obj)->
148                             kind_properties.fprops->filename);
149                 break;
150         case MKIND_STRING:
151         case MKIND_FIFO:
152         case MKIND_STREAM:
153         case MKIND_UNKNOWN:
154         case NUMBER_OF_MEDIA_KINDS:
155         default:
156                 break;
157         }
158
159         if (XMEDIA_STREAM_METHS(obj) &&
160             XMEDIA_STREAM_METH(obj, mark))
161                 XMEDIA_STREAM_METH(obj, mark)(XMEDIA_STREAM_DATA(obj));
162
163         return Qnil;
164 }
165
166 static void
167 media_stream_finalise(void *header, int for_disksave)
168 {
169         Lisp_Media_Stream *ms = (Lisp_Media_Stream*)header;
170         media_substream *mss = NULL;
171
172         if(ms == NULL)
173                 return;
174         if (media_stream_meths(ms) &&
175             media_stream_meth(ms, close))
176                 media_stream_meth(ms, close)(media_stream_data(ms));
177
178         mss = media_stream_first(ms);
179         while (mss) {
180                 media_substream_finalise(mss, for_disksave);
181                 mss = media_substream_next(mss);
182         }
183
184 #if 0
185         switch (media_stream_driver(ms)) {
186         case MDRIVER_XINE:
187 #ifdef HAVE_XINE
188                 if (media_stream_data(ms))
189                         media_xine_close_context(media_stream_data(ms));
190 #endif
191                 break;
192         case MDRIVER_SNDFILE:
193 #ifdef HAVE_SNDFILE
194                 if (media_stream_data(ms))
195                         sf_close(media_stream_data(ms));
196 #endif
197                 break;
198         case MDRIVER_MAD:
199 #ifdef HAVE_MAD
200                 if (media_stream_data(ms))
201                         mad_decoder_finish(media_stream_data(ms));
202 #endif
203                 break;
204         case MDRIVER_SOX:
205 #ifdef HAVE_SOX
206                 if (media_stream_data(ms))
207                         st_close(media_stream_data(ms));
208 #endif
209                 break;
210         default:
211                 break;
212         }
213 #endif
214
215         switch (media_stream_kind(ms)) {
216         case MKIND_FILE: {
217                 mkind_file_properties *mkfp;
218                 mkfp = media_stream_kind_properties(ms).fprops;
219                 if (mkfp) {
220                         xfree(mkfp);
221                 }
222                 break;
223         }
224         case MKIND_STRING: {
225                 mkind_string_properties *mksp;
226                 mksp = media_stream_kind_properties(ms).sprops;
227                 if (mksp) {
228                         if (mksp->name)
229                                 xfree(mksp->name);
230 #if 0
231                         if (mksp->stream_data)
232                                 xfree(mksp->stream_data);
233 #endif
234                         xfree(mksp);
235                 }
236                 break;
237         }
238         case MKIND_UNKNOWN:
239         case MKIND_FIFO:
240         case MKIND_STREAM:
241         case NUMBER_OF_MEDIA_KINDS:
242         default:
243                 break;
244         }
245
246         /* avoid some warning */
247         if (for_disksave || ms == NULL);
248 }
249
250 static void
251 media_stream_print(Lisp_Object obj, Lisp_Object printcharfun, int ef)
252 {
253         Lisp_Media_Stream *ms = XMEDIA_STREAM(obj);
254         media_substream *mss;
255
256         write_c_string("#<media-stream", printcharfun);
257
258         write_c_string(" :kind ", printcharfun);
259
260         switch (media_stream_kind(ms)) {
261         case MKIND_FILE: {
262                 Lisp_Object file =
263                         media_stream_kind_properties(ms).fprops->filename;
264
265                 write_c_string("#<file ", printcharfun);
266                 print_internal(file, printcharfun, ef);
267                 write_c_string(">", printcharfun);
268                 break;
269         }
270         case MKIND_STRING:
271                 write_c_string("#<string>", printcharfun);
272                 break;
273         case MKIND_FIFO:
274                 write_c_string("#<fifo>", printcharfun);
275                 break;
276         case MKIND_STREAM:
277                 write_c_string("#<stream>", printcharfun);
278                 break;
279
280         default:
281         case MKIND_UNKNOWN:
282         case NUMBER_OF_MEDIA_KINDS:
283                 write_c_string("#<unknown>", printcharfun);
284                 break;
285         }
286
287         mss = media_stream_first(ms);
288         while (mss) {
289                 write_c_string(" ", printcharfun);
290                 media_substream_print(mss, printcharfun, ef);
291                 mss = media_substream_next(mss);
292         }
293
294         write_c_string(" driven by ", printcharfun);
295         switch (media_stream_driver(ms)) {
296         case MDRIVER_INTERNAL:
297                 write_c_string("internal", printcharfun);
298                 break;
299         case MDRIVER_FFMPEG:
300                 write_c_string("ffmpeg", printcharfun);
301                 break;
302         case MDRIVER_SNDFILE:
303                 write_c_string("sndfile", printcharfun);
304                 break;
305         case MDRIVER_MAD:
306                 write_c_string("mad", printcharfun);
307                 break;
308         case MDRIVER_SOX:
309                 write_c_string("sox", printcharfun);
310                 break;
311         case MDRIVER_XINE:
312                 write_c_string("xine", printcharfun);
313                 break;
314         case MDRIVER_GSTREAMER:
315                 write_c_string("gstreamer", printcharfun);
316                 break;
317         case MDRIVER_UNKNOWN:
318         case NUMBER_OF_MEDIA_DRIVERS:
319         default:
320                 XMEDIA_STREAM_SET_METHS(obj, NULL);
321                 write_c_string("unknown", printcharfun);
322                 break;
323         }
324
325         if (XMEDIA_STREAM_METHS(obj) &&
326             XMEDIA_STREAM_METH(obj, print)) {
327                 XMEDIA_STREAM_METH(obj, print)(obj, printcharfun, ef);
328         }
329
330         write_c_string(">", printcharfun);
331 }
332
333 static int
334 media_stream_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
335 {
336         if (XMEDIA_STREAM_DATA(obj1) == XMEDIA_STREAM_DATA(obj2))
337                 return Qt;
338         else
339                 return Qnil;
340
341         /* less warnings */
342         if (depth);
343 }
344
345 static unsigned long
346 media_stream_hash (Lisp_Object obj, int depth)
347 {
348         return (unsigned long)obj;
349
350         /* less warnings */
351         if (depth);
352 }
353
354 static const struct lrecord_description media_stream_description[] = {
355         { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, first) },
356         { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, last) },
357         { XD_INT, offsetof(Lisp_Media_Stream, kind) },
358         { XD_INT, offsetof(Lisp_Media_Stream, driver) },
359         { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, kind_properties) },
360         { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, stream_data) },
361         { XD_END }
362 };
363
364 DEFINE_LRECORD_IMPLEMENTATION("media_stream", media_stream,
365                               media_stream_mark, media_stream_print,
366                               media_stream_finalise,
367                               media_stream_equal, media_stream_hash,
368                               media_stream_description,
369                               Lisp_Media_Stream);
370
371 \f
372 /*****************************************************************/
373 /*                          media substreams                     */
374 /*****************************************************************/
375
376 static void
377 media_substream_finalise(void *header, int for_disksave)
378 {
379         media_substream *mss = (media_substream*)header;
380
381         switch (media_substream_type(mss)) {
382         case MTYPE_AUDIO:
383                 if (media_substream_type_properties(mss).aprops)
384                         xfree(media_substream_type_properties(mss).aprops);
385                 break;
386         case MTYPE_VIDEO:
387                 if (media_substream_type_properties(mss).vprops)
388                         xfree(media_substream_type_properties(mss).vprops);
389                 break;
390         case MTYPE_UNKNOWN:
391         case MTYPE_IMAGE:
392         case NUMBER_OF_MEDIA_TYPES:
393         default:
394                 break;
395         }
396
397 #ifdef HAVE_THREADS
398         pthread_mutex_destroy(&mss->substream_mutex);
399 #endif
400
401         media_substream_data(mss) = NULL;
402
403         /* avoid some warning */
404         if (for_disksave);
405 }
406
407 static void
408 media_substream_print_audio(media_substream *mss, Lisp_Object printcharfun)
409 {
410         mtype_audio_properties *mtap =
411                 media_substream_type_properties(mss).aprops;
412
413         write_c_string("#<audio ", printcharfun);
414         if (mtap->name || mtap->codec_name) {
415                 if (mtap->name && mtap->codec_name)
416                         write_fmt_str(printcharfun, "%s (%s)",
417                                       mtap->name, mtap->codec_name);
418                 else if (mtap->name)
419                         write_fmt_str(printcharfun, "%s [???]", mtap->name);
420                 else if (mtap->codec_name)
421                         write_fmt_str(printcharfun, "??? (%s)", mtap->codec_name);
422         } else
423                 write_c_string("???", printcharfun);
424
425         switch (mtap->channels) {
426         case 1:
427                 write_c_string(", mono", printcharfun);
428                 break;
429         case 2:
430                 write_c_string(", stereo", printcharfun);
431                 break;
432         case 5:
433                 write_c_string(", chn:5", printcharfun);
434                 break;
435         case 6:
436                 write_c_string(", 5.1", printcharfun);
437                 break;
438         default:
439                 write_c_string(", chn:???", printcharfun);
440                 break;
441         }
442
443         if (mtap->samplerate)
444                 write_fmt_str(printcharfun, ", %d Hz, %d Bit",
445                               mtap->samplerate,
446                               mtap->samplewidth);
447
448         if (mtap->bitrate)
449                 write_fmt_str(printcharfun, ", %d kb/s", mtap->bitrate/1000);
450
451         write_c_string(">", printcharfun);
452 }
453
454 static void
455 media_substream_print_video(media_substream *mss, Lisp_Object printcharfun)
456 {
457         mtype_video_properties *mtvp =
458                 media_substream_type_properties(mss).vprops;
459
460         write_c_string("#<video ", printcharfun);
461         if (mtvp->name || mtvp->codec_name) {
462                 if (mtvp->name && mtvp->codec_name)
463                         write_fmt_str(printcharfun, "%s (%s)",
464                                       mtvp->name, mtvp->codec_name);
465                 else if (mtvp->name)
466                         write_fmt_str(printcharfun, "%s [???]", mtvp->name);
467                 else if (mtvp->codec_name)
468                         write_fmt_str(printcharfun, "??? (%s)", mtvp->codec_name);
469         } else
470                 write_c_string("???", printcharfun);
471
472         if (mtvp->bitrate)
473                 write_fmt_str(printcharfun, ", %d kb/s", mtvp->bitrate);
474
475         if (mtvp->width && mtvp->height) {
476                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1)
477                         write_fmt_str(printcharfun, ", %dx%d (%d/%d)",
478                                       mtvp->width, mtvp->height,
479                                       mtvp->aspect_num, mtvp->aspect_den);
480                 else
481                         write_fmt_str(printcharfun, ", %dx%d (%.2f/1)",
482                                       mtvp->width, mtvp->height,
483                                       (double)mtvp->width/(double)mtvp->height);
484         }
485         write_c_string(">", printcharfun);
486 }
487
488 static void
489 media_substream_print(media_substream *mss,
490                       Lisp_Object printcharfun, int escapeflag)
491 {
492         write_c_string("#<media-substream :type ", printcharfun);
493
494         switch (media_substream_type(mss)) {
495         case MTYPE_AUDIO: {
496                 media_substream_print_audio(mss, printcharfun);
497                 break;
498         }
499         case MTYPE_VIDEO:
500                 media_substream_print_video(mss, printcharfun);
501                 break;
502         case MTYPE_IMAGE:
503                 write_c_string("#<image>", printcharfun);
504                 break;
505         default:
506         case MTYPE_UNKNOWN:
507         case NUMBER_OF_MEDIA_TYPES:
508                 write_c_string("#<unknown>", printcharfun);
509                 break;
510         }
511
512         write_c_string(">", printcharfun);
513 }
514
515 static Lisp_Media_Stream *
516 media_stream_allocate(void)
517 {
518         Lisp_Media_Stream *ms;
519
520         ms = alloc_lcrecord_type(Lisp_Media_Stream, &lrecord_media_stream);
521         return ms;
522 }
523
524 \f
525 Lisp_Object make_media_stream()
526 {
527         Lisp_Media_Stream *ms;
528         Lisp_Object lms;
529
530         ms = media_stream_allocate();
531         media_stream_kind(ms) = MKIND_UNKNOWN;
532         media_stream_driver(ms) = MDRIVER_UNKNOWN;
533         media_stream_data(ms) = NULL;
534
535         /* now set the navigation */
536         media_stream_first(ms) = NULL;
537         media_stream_last(ms) = NULL;
538
539         XSETMEDIA_STREAM(lms, ms);
540
541         return lms;
542 }
543
544 media_substream *make_media_substream(void)
545 {
546 /* this allocates and conses to the back of ms */
547         media_substream *mss;
548
549         mss = xnew_and_zero(media_substream);
550         media_substream_type(mss) = MTYPE_UNKNOWN;
551         media_substream_data(mss) = NULL;
552
553         /* set next/prev */
554         media_substream_next(mss) = NULL;
555         media_substream_prev(mss) = NULL;
556
557 #ifdef HAVE_THREADS
558         pthread_mutex_init(&mss->substream_mutex, NULL);
559 #endif
560
561         return mss;
562 }
563
564 media_substream *make_media_substream_append(Lisp_Media_Stream *ms)
565 {
566         media_substream *mss;
567
568         mss = make_media_substream();
569
570         /* set next/prev */
571         media_substream_next(mss) = NULL;
572         if (!(media_stream_last(ms))) {
573                 media_substream_prev(mss) = NULL;
574                 media_stream_first(ms) = mss;
575         } else {
576                 media_substream_prev(mss) = media_stream_last(ms);
577                 media_substream_next(media_stream_last(ms)) = mss;
578         }
579
580         media_stream_last(ms) = mss;
581         media_substream_up(mss) = ms;
582
583         return mss;
584 }
585
586 media_substream *make_media_substream_prepend(Lisp_Media_Stream *ms)
587 {
588         media_substream *mss;
589
590         mss = make_media_substream();
591
592         /* set next/prev */
593         media_substream_prev(mss) = NULL;
594         if (!(media_stream_first(ms))) {
595                 media_substream_next(mss) = NULL;
596                 media_stream_last(ms) = mss;
597         } else {
598                 media_substream_next(mss) = media_stream_first(ms);
599                 media_substream_prev(media_stream_first(ms)) = mss;
600         }
601
602         media_stream_first(ms) = mss;
603         media_substream_up(mss) = ms;
604
605         return mss;
606 }
607
608 DEFUN("make-media-stream", Fmake_media_stream, 2, 3, 0, /*
609 Create a new media stream from DATA.
610
611 FROM is a keyword and defines how DATA is interpreted:
612 :file - DATA is the name of a file
613 :data - DATA is a string with the stream data
614 :url  - DATA is a url (string) for streamed media contents
615
616 Optional argument DRIVER (a symbol) may be used to force
617 the use of a certain driver instead of automatically
618 detecting a suitable one.  It is one of `ffmpeg', `sndfile',
619 `sox', `mad', `xine', `gstreamer', or `internal'.
620 */
621       (from, data, driver))
622 {
623         Lisp_Object lms;
624         Lisp_Media_Stream *ms;
625         enum whats_data {
626                 DATA_IS_BULLSHIT,
627                 DATA_IS_FILE,
628                 DATA_IS_URL,
629                 DATA_IS_DATA } datatype = DATA_IS_BULLSHIT;
630         media_driver pref = MDRIVER_UNKNOWN;
631
632         if (0);
633         else if (EQ(from, Q_file))
634                 datatype = DATA_IS_FILE;
635         else if (EQ(from, Q_data))
636                 datatype = DATA_IS_DATA;
637         else if (EQ(from, Q_url))
638                 datatype = DATA_IS_URL;
639         else {
640                 datatype = DATA_IS_BULLSHIT;
641                 return Qnil;    /* in this case, why bother? stupid user :) */
642         }
643
644         if (NILP(driver))
645                 pref = MDRIVER_UNKNOWN;
646 #ifdef HAVE_MAD
647         else if (EQ(driver, Qmad))
648                 pref = MDRIVER_MAD;
649 #endif
650 #ifdef HAVE_FFMPEG
651         else if (EQ(driver, Qffmpeg))
652                 pref = MDRIVER_FFMPEG;
653 #endif
654 #ifdef HAVE_SOX
655         else if (EQ(driver, Qsox))
656                 pref = MDRIVER_SOX;
657 #endif
658         else if (EQ(driver, intern("xine")))
659                 pref = MDRIVER_XINE;
660 #ifdef HAVE_SNDFILE
661         else if (EQ(driver, Qsndfile))
662                 pref = MDRIVER_SNDFILE;
663 #endif
664         else if (EQ(driver, intern("internal")))
665                 pref = MDRIVER_INTERNAL;
666         else if (EQ(driver, intern("gstreamer")))
667                 pref = MDRIVER_GSTREAMER;
668         else
669                 pref = MDRIVER_UNKNOWN;
670
671         /* hm, maybe data could be a symbol from the sound-alist?
672          * or a buffer or a network socket?
673          */
674         CHECK_STRING(data);
675
676         lms = make_media_stream();
677         ms = XMEDIA_STREAM(lms);
678
679         switch (datatype) {
680         case DATA_IS_FILE: {
681                 mkind_file_properties *fprops;
682
683                 /* expand-file-name first and check for existence*/
684                 data = Fexpand_file_name(data, Qnil);
685                 if (!NILP(Ffile_directory_p(data)) ||
686                     NILP(Ffile_readable_p(data)))
687                         break;
688
689                 media_stream_kind(ms) = MKIND_FILE;
690
691                 /* initialise a new file properties structure */
692                 fprops = xnew_and_zero(mkind_file_properties);
693
694                 /* copy the filename also as C string */
695                 fprops->filename = data;
696
697                 /* assign the file properties */
698                 media_stream_kind_properties(ms).fprops = fprops;
699
700                 determine_stream_type(ms, pref);
701                 break;
702         }
703         case DATA_IS_DATA: {
704                 mkind_string_properties *sprops;
705                 char *data_ext = NULL;
706                 int data_len = 0;
707
708                 /* copy the filename also as C string */
709                 TO_EXTERNAL_FORMAT(LISP_STRING, data,
710                                    MALLOC, (data_ext, data_len),
711                                    Qbinary);
712
713                 if (data_ext != NULL) {
714                         media_stream_kind(ms) = MKIND_STRING;
715
716                         /* initialise a new file properties structure */
717                         sprops = xnew_and_zero(mkind_string_properties);
718
719                         data_ext[data_len] = '\0';
720                         sprops->name = NULL;
721                         sprops->stream_data = data_ext;
722                         sprops->size = data_len;
723
724                         /* assign the file properties */
725                         media_stream_kind_properties(ms).sprops = sprops;
726
727                         determine_stream_type(ms, pref);
728                 }
729                 break;
730         }
731         case DATA_IS_URL: {
732                 break;
733         }
734         case DATA_IS_BULLSHIT:
735         default:
736                 break;
737         }
738
739         return lms;
740 }
741
742 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
743 {
744         Lisp_Object result;
745
746         result = to;
747
748         while (!NILP(from)) {
749                 result = Fcons(XCAR(from), result);
750                 from = XCDR(from);
751         }
752         return result;
753 }
754
755 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
756 Return non-nil if object is a media-stream.
757 */
758       (object))
759 {
760         if (MEDIA_STREAMP(object))
761                 return Qt;
762         else
763                 return Qnil;
764 }
765
766 #if 0
767 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
768 Return non-nil if object is a media-substream with audio data.
769 */
770       (object))
771 {
772         if (MEDIA_SUBSTREAMP(object) &&
773             XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
774                 return Qt;
775         else
776                 return Qnil;
777 }
778
779 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
780 Return non-nil if object is a media-substream with video data.
781 */
782       (object))
783 {
784         if (MEDIA_SUBSTREAMP(object) &&
785             XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
786                 return Qt;
787         else
788                 return Qnil;
789 }
790 #endif  /* 0 */
791
792 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
793 Return a list of input formats in the underlying media libraries.
794 */
795       ())
796 {
797         Lisp_Object formats;
798         Lisp_Object temp;
799
800         formats = Qnil;
801         temp = Qnil;
802
803 #ifdef HAVE_FFMPEG
804         temp = media_ffmpeg_available_formats();
805 #endif
806         formats = recons(formats, temp);
807
808 #ifdef HAVE_SNDFILE
809         temp = Qnil;
810 #endif
811         formats = recons(formats, temp);
812
813         return formats;
814 }
815
816 static inline void __attribute__((always_inline))
817 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
818 {
819         *reslist = Fcons(Fcons(key, val), *reslist);
820         return;
821 }
822
823 static void
824 media_substream_props(media_substream *mss, Lisp_Object *reslist)
825 {
826         switch (media_substream_type(mss)) {
827         case MTYPE_AUDIO: {
828                 mtype_audio_properties *mtap =
829                         media_substream_type_properties(mss).aprops;
830
831                 /* add the type property */
832                 __add_prop(reslist, Qtype, Qaudio);
833
834                 if (mtap->name) {
835                         __add_prop(reslist, Qdemux, build_string(mtap->name));
836                 }
837                 if (mtap->codec_name) {
838                         __add_prop(reslist, Qcodec,
839                                    build_string(mtap->codec_name));
840                 }
841
842                 if (mtap->channels) {
843                         __add_prop(reslist, Qnchannels,
844                                    make_int(mtap->channels));
845                 }
846
847                 if (mtap->samplerate) {
848                         __add_prop(reslist, Qsamplerate,
849                                    make_int(mtap->samplerate));
850                 }
851
852                 if (mtap->bitrate) {
853                         __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
854                 }
855
856                 break;
857         }
858
859         case MTYPE_VIDEO: {
860                 mtype_video_properties *mtvp =
861                         media_substream_type_properties(mss).vprops;
862
863                 /* add the type property */
864                 __add_prop(reslist, Qtype, Qvideo);
865
866                 if (mtvp->name) {
867                         __add_prop(reslist, Qdemux, build_string(mtvp->name));
868                 }
869                 if (mtvp->codec_name) {
870                         __add_prop(reslist, Qcodec,
871                                    build_string(mtvp->codec_name));
872                 }
873
874                 if (mtvp->bitrate) {
875                         __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
876                 }
877
878                 if (mtvp->width) {
879                         __add_prop(reslist, Qwidth, make_int(mtvp->width));
880                 }
881
882                 if (mtvp->height) {
883                         __add_prop(reslist, Qheight, make_int(mtvp->height));
884                 }
885
886 #if defined HAVE_MPQ && defined WITH_GMP && 0
887                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
888                         __add_prop(reslist, Qaspect,
889                                    make_bigq(mtvp->aspect_num,
890                                              mtvp->aspect_den));
891                 }
892 #elif defined HAVE_FPFLOAT
893 /* use float arithmetic */
894                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
895                         __add_prop(reslist, Qaspect,
896                                    make_float((fpfloat)mtvp->aspect_num /
897                                               (fpfloat)mtvp->aspect_den));
898                 } else if (mtvp->width && mtvp->height) {
899                         __add_prop(reslist, Qaspect,
900                                    make_float((fpfloat)mtvp->width /
901                                               (fpfloat)mtvp->height));
902                 }
903 #endif
904
905                 break;
906         }
907         case MTYPE_IMAGE: {
908                 __add_prop(reslist, Qtype, Qimage);
909                 break;
910         }
911         default:
912         case MTYPE_UNKNOWN:
913         case NUMBER_OF_MEDIA_TYPES:
914                 break;
915         }
916 }
917
918 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
919 Return an alist of available properties of media-stream STREAM.
920
921 Depending on the underlying stream this alist may be made of
922 several of the following keys, grouped by media contents.
923
924 general:
925 -------
926 'file (string) the stream's filename
927 'uri (string) the stream's URI
928 'fifo (string) the stream's FIFO socket
929 'driver (symbol) the stream's demuxer/decoder driver
930 'kind (symbol) the stream's kind (file, fifo, string, uri, etc.)
931 'type (symbol) the stream's type (audio, video, image, subtitle, lyrics, etc.)
932
933 audio:
934 -----
935 'codec (string) the suitable audio codec
936 'demux (string) the suitable demuxer
937 'title (string) the title of an audio track
938 'artist (string) the performing artist(s)
939 'album (string) the title of the album
940 'comment (string) an arbitrary comment
941 'genre (string) the genre identifier string
942 'year (integer) the year of release
943 'track (integer) the track number on the album
944 'length (integer) the length of the track in seconds
945 'abitrate (integer) the average bitrate of the track in kb/s
946 'samplerate (integer) the samplerate of the track in Hz
947 'nchannels (integer) the number of distinguished channels
948
949 video:
950 -----
951 'codec (string) the suitable audio codec
952 'demux (string) the suitable demuxer
953 'title (string) the title of a video track
954 'comment (string) an arbitrary comment
955 'year (integer) the year of release
956 'vbitrate (integer) the average bitrate of the track in kb/s
957 'width (integer) the x-resolution in pixels
958 'height (integer) the y-resolution in pixels
959 'aspect (bigq) the aspect quotient
960
961 Keys which do not apply to the underlying stream or are not
962 defined in the tag section of the stream are simply left out
963 in the result alist.
964 */
965       (stream))
966 {
967         Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
968         media_substream *mss;
969         Lisp_Object resdl = Qnil;
970
971         switch (media_stream_kind(ms)) {
972         case MKIND_FILE: {
973                 Lisp_Object file =
974                         media_stream_kind_properties(ms).fprops->filename;
975
976                 __add_prop(&resdl, Qfile, file);
977                 __add_prop(&resdl, Qkind, Qfile);
978                 break;
979         }
980         case MKIND_FIFO: {
981                 __add_prop(&resdl, Qkind, Qfifo);
982                 break;
983         }
984         case MKIND_STREAM: {
985                 __add_prop(&resdl, Qkind, Quri);
986                 break;
987         }
988         case MKIND_STRING:
989                 __add_prop(&resdl, Qkind, Qstring);
990                 break;
991         case MKIND_UNKNOWN:
992         case NUMBER_OF_MEDIA_KINDS:
993         default:
994                 __add_prop(&resdl, Qkind, Qunknown);
995                 break;
996         }
997
998         __add_prop(&resdl, Qdriver, Qunavailable);
999         switch (media_stream_driver(ms)) {
1000         case MDRIVER_INTERNAL:
1001                 __add_prop(&resdl, Qdriver, Qinternal);
1002                 break;
1003         case MDRIVER_FFMPEG:
1004 #ifdef HAVE_FFMPEG
1005                 __add_prop(&resdl, Qdriver, Qffmpeg);
1006 #if 0
1007                 streaminfo = media_ffmpeg_streaminfo(ms);
1008 #endif
1009 #endif
1010                 break;
1011         case MDRIVER_SNDFILE:
1012 #ifdef HAVE_SNDFILE
1013                 __add_prop(&resdl, Qdriver, Qsndfile);
1014 #endif
1015                 break;
1016         case MDRIVER_MAD:
1017 #ifdef HAVE_MAD
1018                 __add_prop(&resdl, Qdriver, Qmad);
1019 #endif
1020                 break;
1021         case MDRIVER_SOX:
1022 #ifdef HAVE_SOX
1023                 __add_prop(&resdl, Qdriver, Qsox);
1024 #endif
1025                 break;
1026
1027         case MDRIVER_XINE:
1028                 break;
1029
1030         case MDRIVER_GSTREAMER:
1031                 break;
1032
1033         case MDRIVER_UNKNOWN:
1034         case NUMBER_OF_MEDIA_DRIVERS:
1035         default:
1036                 __add_prop(&resdl, Qdriver, Qunknown);
1037                 break;
1038         }
1039
1040 #if 0
1041         if (streaminfo) {
1042                 xfree(streaminfo);
1043         }
1044 #endif
1045
1046         mss = media_stream_first(ms);
1047         while (mss) {
1048                 media_substream_props(mss, &resdl);
1049                 mss = media_substream_next(mss);
1050         }
1051
1052         return resdl;
1053 }
1054
1055 /* convenience functions */
1056 DEFUN("media-stream-aspect", Fmedia_stream_aspect, 1, 3, 0, /*
1057 Return a list of aspect ratios in media stream STREAM.
1058
1059 Optional argument SUBSTREAM names the index of a specific (video)
1060 substream, i.e. only video streams are counted, i.e. the substream 0
1061 names the first video track inside STREAM.
1062 The return value in that case is just a float or quotient, depending
1063 on the optional argument QUOTIENTP.
1064
1065 Optional argument QUOTIENTP indicates that aspect ratios are to be
1066 returned as bigq quotients instead of floats (the default).
1067
1068 By default, the aspect ratios of all the video tracks appear in the list,
1069 the first element in the list belongs to the first video track,
1070 the second element to the second one and so on.
1071 */
1072       (stream, substream, quotientp))
1073 {
1074         Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1075         Lisp_Object res = Qnil;
1076         long int idx = INTP(substream) ? XINT(substream) : -1;
1077
1078         for (media_substream *mss = media_stream_first(ms); mss;
1079              (mss = media_substream_next(mss))) {
1080                 mtype_video_properties *mtvp;
1081                 long int num = 0, den = 0;
1082                 Lisp_Object tmp;
1083
1084                 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1085                         continue;
1086                 }
1087
1088                 /* oh, it's a video stream, check if it's the one we wanted */
1089                 if (UNLIKELY(idx--  > 0)) {
1090                         continue;
1091                 }
1092
1093                 mtvp = media_substream_type_properties(mss).vprops;
1094                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
1095                         num = mtvp->aspect_num;
1096                         den = mtvp->aspect_den;
1097                 } else if (mtvp->width && mtvp->height) {
1098                         /* good enough? just an approximation as
1099                          * the aspect ratio may very well differ
1100                          * from the width-by-height ratio */
1101                         num = mtvp->width;
1102                         den = mtvp->height;
1103                 }
1104
1105                 if (LIKELY(NILP(quotientp))) {
1106                         tmp = make_float((fpfloat)num / (fpfloat)den);
1107                 }
1108 #if defined HAVE_MPQ && defined WITH_GMP
1109                 else {
1110                         tmp = make_bigq(num, den);
1111                 }
1112 #else
1113                 else {
1114                   dead_wrong_type_argument(Qfeaturep,quotientp);
1115                 }
1116 #endif
1117                 if (UNLIKELY(INTP(substream))) {
1118                         return tmp;
1119                 }
1120                 /* the very very default case */
1121                 res = Fcons(tmp, res);
1122         }
1123         return res;
1124 }
1125
1126 \f
1127 /* Audio Coercion */
1128 /* SXEmacs works internally with samples in 24bit resolution */
1129
1130 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1131
1132 static void
1133 sxe_msf_U8_up(void *d, void *s, size_t len)
1134 {
1135         /* convert U8 samples to internal format (S24in32) */
1136         int i;
1137         int32_t *dst = d;
1138         uint8_t *src = s;
1139
1140         /* len is the number of samples (== #frame * #channels) */
1141         MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1142
1143         for (i = len-1; i >= 0; i--)
1144                 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1145
1146         return;
1147 }
1148
1149 static void
1150 sxe_msf_U8_down(void *d, void *s, size_t len)
1151 {
1152         /* convert samples from internal format (S24in32) to U8 */
1153         size_t i;
1154         uint8_t *dst = d;
1155         int32_t *src = s;
1156
1157         /* len is the number of samples (== #frame * #channels) */
1158         MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1159
1160         for (i = 0; i < len; i++)
1161                 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1162
1163         return;
1164 }
1165
1166 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1167
1168 static void
1169 sxe_msf_S16_up(void *d, void *s, size_t len)
1170 {
1171         /* convert S16 samples to internal format (S24in32) */
1172         int i;
1173         int32_t *dst = d;
1174         int16_t *src = s;
1175
1176         /* len is the number of samples (== #frame * #channels) */
1177         MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
1178
1179         for (i = len-1; i >= 0; i--)
1180                 dst[i] = (int32_t)(src[i]) << 8;
1181         MEDIA_DEBUG_FMT("d00:%d  d01:%d\n", dst[0], dst[1]);
1182
1183         return;
1184 }
1185
1186 static void
1187 sxe_msf_S16_down(void *d, void *s, size_t len)
1188 {
1189         /* convert samples from internal format (S24in32) to S16 */
1190         size_t i;
1191         int16_t *dst = d;
1192         int32_t *src = s;
1193
1194         /* len is the number of samples (== #frame * #channels) */
1195         MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1196
1197         for (i = 0; i < len; i++)
1198                 dst[i] = (int16_t)(src[i] >> 8);
1199
1200         return;
1201 }
1202
1203 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1204
1205 static void
1206 sxe_msf_S24_up(void *d, void *s, size_t len)
1207 {
1208         MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1209
1210         /* S24 _is_ the internal format */
1211         return;
1212 }
1213
1214 static void
1215 sxe_msf_S24_down(void *d, void *s, size_t len)
1216 {
1217         MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1218
1219         /* S24 _is_ the internal format */
1220         return;
1221 }
1222
1223 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1224
1225 static void
1226 sxe_msf_S32_up(void *d, void *s, size_t len)
1227 {
1228         /* convert S32 samples to internal format (S24in32) */
1229         size_t i;
1230         int32_t *dst = d;
1231         int32_t *src = s;
1232
1233         /* len is the number of samples (== #frame * #channels) */
1234         MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1235
1236         for (i = 0; i < len; i++)
1237                 dst[i] = src[i] >> 8;
1238
1239         return;
1240 }
1241
1242 static void
1243 sxe_msf_S32_down(void *d, void *s, size_t len)
1244 {
1245         /* convert samples from internal format (S24in32) to S32 */
1246         size_t i;
1247         int32_t *dst = d;
1248         int32_t *src = s;
1249
1250         /* len is the number of samples (== #frame * #channels) */
1251         MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1252
1253         for (i = 0; i < len; i++)
1254                 dst[i] = src[i] << 8;
1255
1256         return;
1257 }
1258
1259 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1260
1261 static void
1262 sxe_msf_FLT_up(void *d, void *s, size_t len)
1263 {
1264         /* convert float samples to internal format (S24in32) */
1265         size_t i;
1266         int32_t *dst = d;
1267         float *src = s;
1268
1269         /* len is the number of samples (== #frame * #channels) */
1270         MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1271
1272         for (i = 0; i < len; i++) {
1273                 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1274         }
1275         MEDIA_DEBUG_FMT("s00:%f d00:%d  s01:%f d01:%d\n",
1276                         src[0], dst[0], src[1], dst[1]);
1277
1278         return;
1279 }
1280
1281 static void
1282 sxe_msf_FLT_down(void *d, void *s, size_t len)
1283 {
1284         /* convert samples from internal format (S24in32) to float */
1285         int i;
1286         float *dst = d;
1287         int32_t *src = s;
1288
1289         /* len is the number of samples (== #frame * #channels) */
1290         MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1291
1292         for (i = len-1; i >= 0; i--) {
1293                 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1294         }
1295         MEDIA_DEBUG_FMT("d00:%f  d01:%f\n", dst[0], dst[1]);
1296
1297         return;
1298 }
1299
1300 /* `effects' */
1301 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1302
1303 static size_t
1304 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1305                     size_t len, void *ignored)
1306 {
1307         /* mono to stereo converter */
1308         int i;
1309
1310         MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1311
1312         /* len is the number of samples */
1313         for (i = len-1; i >= 0; i--) {
1314                 dst[2*i] = src[i];
1315                 dst[2*i+1] = src[i];
1316         }
1317
1318         return len * 2;
1319 }
1320
1321 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1322
1323 static size_t
1324 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1325                     size_t len, void *args)
1326 {
1327         /* stereo to mono converter */
1328         size_t i;
1329         sxe_mse_2ch_to_1ch_args *_args = args;
1330         int c = 0;
1331
1332         MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1333
1334         if (_args) {
1335                 c = _args->chan;
1336         }
1337
1338         /* len is the number of samples */
1339         for (i = 0; i < len/2; i++) {
1340                 dst[i] = src[2*i+c];
1341         }
1342
1343         return len / 2;
1344 }
1345
1346 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1347
1348 static size_t
1349 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1350                     size_t len, void *args)
1351 {
1352         /* 5 channel to stereo converter */
1353         size_t i;
1354         sxe_mse_5ch_to_2ch_args *_args = args;
1355         int c1 = 0, c2 = 1;
1356
1357         MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
1358
1359         if (_args) {
1360                 c1 = _args->chan1;
1361                 c2 = _args->chan1;
1362         }
1363
1364         /* len is the number of samples */
1365         for (i = 0; i < len/5; i++) {
1366                 dst[2*i] = src[5*i+c1];
1367                 dst[2*i+1] = src[5*i+c2];
1368         }
1369
1370         return len * 2 / 5;
1371 }
1372
1373 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1374
1375 static size_t
1376 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1377                 size_t len, void *args)
1378 {
1379         /* stereo to mono converter */
1380         size_t i, j;
1381         sxe_mse_volume_args *_args = args;
1382
1383         MEDIA_DEBUG_COE("volume: %u samples\n", len);
1384
1385         /* len is the number of samples */
1386         for (i = 0; i < len; i+=_args->num_channels) {
1387                 for (j = 0; j < (size_t)_args->num_channels; j++) {
1388                         uint8_t vol = _args->volume[j];
1389                         dst[i+j] = (src[i+j] * vol) >> 7;
1390                 }
1391         }
1392
1393         return len;
1394 }
1395
1396 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1397
1398 static size_t
1399 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1400                 size_t len, void *args)
1401 {
1402         /* rate converter */
1403         int i;
1404         sxe_mse_rerate_args *_args = args;
1405         float trafo = (float)_args->srcrate / (float)_args->tgtrate
1406                 * _args->tweak;
1407         int chans = _args->num_channels;
1408         int bound = len/chans/trafo;
1409
1410         MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
1411                         len, trafo, bound);
1412
1413         if (trafo < 1.0) {
1414                 for (i = bound-1; i >= 0; i--) {
1415                         int frame = i * trafo;
1416                         dst[chans*i] = (src[chans*frame]);
1417                         dst[chans*i+1] = (src[chans*frame+1]);
1418                 }
1419         } else if (trafo > 1.0) {
1420                 for (i = 0; i < bound-1; i++) {
1421                         int frame = i * trafo;
1422                         dst[chans*i] = (src[chans*frame]);
1423                         dst[chans*i+1] = (src[chans*frame+1]);
1424                 }
1425         }
1426
1427         return bound * chans;
1428 }
1429
1430 \f
1431 void syms_of_media(void)
1432 {
1433         INIT_LRECORD_IMPLEMENTATION(media_stream);
1434
1435         defsymbol(&Qmedia_streamp, "media-stream-p");
1436
1437         DEFSYMBOL(Qtype);
1438         DEFSYMBOL(Qdemux);
1439         DEFSYMBOL(Qcodec);
1440         DEFSYMBOL(Qnchannels);
1441         DEFSYMBOL(Qsamplerate);
1442         DEFSYMBOL(Qbitrate);
1443         DEFSYMBOL(Qabitrate);
1444         DEFSYMBOL(Qvbitrate);
1445         DEFSYMBOL(Qwidth);
1446         DEFSYMBOL(Qheight);
1447         DEFSYMBOL(Qaspect);
1448         DEFSYMBOL(Qaudio);
1449         DEFSYMBOL(Qvideo);
1450         DEFSYMBOL(Qimage);
1451         DEFSYMBOL(Qdriver);
1452         DEFSYMBOL(Qkind);
1453         DEFSYMBOL(Qfifo);
1454         DEFSYMBOL(Quri);
1455
1456         DEFSUBR(Fmake_media_stream);
1457         DEFSUBR(Fmedia_stream_p);
1458 #if 0
1459         DEFSUBR(Faudio_substream_p);
1460         DEFSUBR(Fvideo_substream_p);
1461 #endif
1462
1463         DEFSUBR(Fmedia_available_formats);
1464         DEFSUBR(Fmedia_properties);
1465         DEFSUBR(Fmedia_stream_aspect);
1466
1467 #ifdef HAVE_FFMPEG
1468         defsymbol(&Qffmpeg, "ffmpeg");
1469 #endif
1470 #ifdef HAVE_MAD
1471         defsymbol(&Qmad, "mad");
1472 #endif
1473 #ifdef HAVE_SOX
1474         defsymbol(&Qsox, "sox");
1475 #endif
1476 #ifdef HAVE_SNDFILE
1477         defsymbol(&Qsndfile, "sndfile");
1478 #endif
1479         defsymbol(&Qunknown, "unknown");
1480         defsymbol(&Qunavailable, "unavailable");
1481 }
1482
1483 void vars_of_media(void)
1484 {
1485         Fprovide(intern("media"));
1486
1487 #ifdef HAVE_FFMPEG
1488         Fprovide(intern("media-ffmpeg"));
1489 #endif
1490 #ifdef HAVE_SNDFILE
1491         Fprovide(intern("media-sndfile"));
1492 #endif
1493 #ifdef HAVE_MAD
1494         Fprovide(intern("media-mad"));
1495 #endif
1496 #ifdef HAVE_SOX
1497         Fprovide(intern("media-sox"));
1498 #endif
1499 #ifdef HAVE_XINE
1500         Fprovide(intern("media-xine"));
1501 #endif
1502 #ifdef HAVE_GSTREAMER
1503         Fprovide(intern("media-gstreamer"));
1504 #endif
1505 #ifdef HAVE_INTERNAL_MEDIA
1506         Fprovide(intern("media-internal"));
1507 #endif
1508 }
1509
1510 /* media.c ends here */