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