Couple more warning fixes
[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                 char *buf = alloca(64);
413                 if (mtap->name && mtap->codec_name)
414                         snprintf(buf, 63, "%s (%s)",
415                                  mtap->name, mtap->codec_name);
416                 else if (mtap->name)
417                         snprintf(buf, 63, "%s [???]", mtap->name);
418                 else if (mtap->codec_name)
419                         snprintf(buf, 63, "??? (%s)", mtap->codec_name);
420
421                 write_c_string(buf, printcharfun);
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                 char *buf;
445                 buf = alloca(48);
446                 snprintf(buf, 47, ", %d Hz, %d Bit",
447                          mtap->samplerate,
448                          mtap->samplewidth);
449                 write_c_string(buf, printcharfun);
450         }
451
452         if (mtap->bitrate) {
453                 char *buf;
454                 buf = alloca(24);
455                 snprintf(buf, 23, ", %d kb/s", mtap->bitrate/1000);
456                 write_c_string(buf, printcharfun);
457         }
458
459         write_c_string(">", printcharfun);
460 }
461
462 static void
463 media_substream_print_video(media_substream *mss, Lisp_Object printcharfun)
464 {
465         mtype_video_properties *mtvp =
466                 media_substream_type_properties(mss).vprops;
467
468         write_c_string("#<video ", printcharfun);
469         if (mtvp->name || mtvp->codec_name) {
470                 char *buf = alloca(64);
471                 if (mtvp->name && mtvp->codec_name)
472                         snprintf(buf, 63, "%s (%s)",
473                                  mtvp->name, mtvp->codec_name);
474                 else if (mtvp->name)
475                         snprintf(buf, 63, "%s [???]", mtvp->name);
476                 else if (mtvp->codec_name)
477                         snprintf(buf, 63, "??? (%s)", mtvp->codec_name);
478
479                 write_c_string(buf, printcharfun);
480         } else
481                 write_c_string("???", printcharfun);
482
483         if (mtvp->bitrate) {
484                 char *buf = alloca(24);
485                 snprintf(buf, 23, ", %d kb/s", mtvp->bitrate);
486                 write_c_string(buf, printcharfun);
487         }
488
489         if (mtvp->width && mtvp->height) {
490                 char *buf = alloca(48);
491                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1)
492                         snprintf(buf, 47, ", %dx%d (%d/%d)",
493                                  mtvp->width, mtvp->height,
494                                  mtvp->aspect_num, mtvp->aspect_den);
495                 else
496                         snprintf(buf, 47, ", %dx%d (%.2f/1)",
497                                  mtvp->width, mtvp->height,
498                                  (double)mtvp->width/(double)mtvp->height);
499                 write_c_string(buf, printcharfun);
500         }
501         write_c_string(">", printcharfun);
502 }
503
504 static void
505 media_substream_print(media_substream *mss,
506                       Lisp_Object printcharfun, int escapeflag)
507 {
508         write_c_string("#<media-substream :type ", printcharfun);
509
510         switch (media_substream_type(mss)) {
511         case MTYPE_AUDIO: {
512                 media_substream_print_audio(mss, printcharfun);
513                 break;
514         }
515         case MTYPE_VIDEO:
516                 media_substream_print_video(mss, printcharfun);
517                 break;
518         case MTYPE_IMAGE:
519                 write_c_string("#<image>", printcharfun);
520                 break;
521         default:
522         case MTYPE_UNKNOWN:
523         case NUMBER_OF_MEDIA_TYPES:
524                 write_c_string("#<unknown>", printcharfun);
525                 break;
526         }
527
528         write_c_string(">", printcharfun);
529 }
530
531 static Lisp_Media_Stream *
532 media_stream_allocate(void)
533 {
534         Lisp_Media_Stream *ms;
535
536         ms = alloc_lcrecord_type(Lisp_Media_Stream, &lrecord_media_stream);
537         return ms;
538 }
539
540 \f
541 Lisp_Object make_media_stream()
542 {
543         Lisp_Media_Stream *ms;
544         Lisp_Object lms;
545
546         ms = media_stream_allocate();
547         media_stream_kind(ms) = MKIND_UNKNOWN;
548         media_stream_driver(ms) = MDRIVER_UNKNOWN;
549         media_stream_data(ms) = NULL;
550
551         /* now set the navigation */
552         media_stream_first(ms) = NULL;
553         media_stream_last(ms) = NULL;
554
555         XSETMEDIA_STREAM(lms, ms);
556
557         return lms;
558 }
559
560 media_substream *make_media_substream(void)
561 {
562 /* this allocates and conses to the back of ms */
563         media_substream *mss;
564
565         mss = xnew_and_zero(media_substream);
566         media_substream_type(mss) = MTYPE_UNKNOWN;
567         media_substream_data(mss) = NULL;
568
569         /* set next/prev */
570         media_substream_next(mss) = NULL;
571         media_substream_prev(mss) = NULL;
572
573 #ifdef HAVE_THREADS
574         pthread_mutex_init(&mss->substream_mutex, NULL);
575 #endif
576
577         return mss;
578 }
579
580 media_substream *make_media_substream_append(Lisp_Media_Stream *ms)
581 {
582         media_substream *mss;
583
584         mss = make_media_substream();
585
586         /* set next/prev */
587         media_substream_next(mss) = NULL;
588         if (!(media_stream_last(ms))) {
589                 media_substream_prev(mss) = NULL;
590                 media_stream_first(ms) = mss;
591         } else {
592                 media_substream_prev(mss) = media_stream_last(ms);
593                 media_substream_next(media_stream_last(ms)) = mss;
594         }
595
596         media_stream_last(ms) = mss;
597         media_substream_up(mss) = ms;
598
599         return mss;
600 }
601
602 media_substream *make_media_substream_prepend(Lisp_Media_Stream *ms)
603 {
604         media_substream *mss;
605
606         mss = make_media_substream();
607
608         /* set next/prev */
609         media_substream_prev(mss) = NULL;
610         if (!(media_stream_first(ms))) {
611                 media_substream_next(mss) = NULL;
612                 media_stream_last(ms) = mss;
613         } else {
614                 media_substream_next(mss) = media_stream_first(ms);
615                 media_substream_prev(media_stream_first(ms)) = mss;
616         }
617
618         media_stream_first(ms) = mss;
619         media_substream_up(mss) = ms;
620
621         return mss;
622 }
623
624 DEFUN("make-media-stream", Fmake_media_stream, 2, 3, 0, /*
625 Create a new media stream from DATA.
626
627 FROM is a keyword and defines how DATA is interpreted:
628 :file - DATA is the name of a file
629 :data - DATA is a string with the stream data
630 :url  - DATA is a url (string) for streamed media contents
631
632 Optional argument DRIVER (a symbol) may be used to force
633 the use of a certain driver instead of automatically
634 detecting a suitable one.  It is one of `ffmpeg', `sndfile',
635 `sox', `mad', `xine', `gstreamer', or `internal'.
636 */
637       (from, data, driver))
638 {
639         Lisp_Object lms;
640         Lisp_Media_Stream *ms;
641         enum whats_data {
642                 DATA_IS_BULLSHIT,
643                 DATA_IS_FILE,
644                 DATA_IS_URL,
645                 DATA_IS_DATA } datatype = DATA_IS_BULLSHIT;
646         media_driver pref = MDRIVER_UNKNOWN;
647
648         if (0);
649         else if (EQ(from, Q_file))
650                 datatype = DATA_IS_FILE;
651         else if (EQ(from, Q_data))
652                 datatype = DATA_IS_DATA;
653         else if (EQ(from, Q_url))
654                 datatype = DATA_IS_URL;
655         else {
656                 datatype = DATA_IS_BULLSHIT;
657                 return Qnil;    /* in this case, why bother? stupid user :) */
658         }
659
660         if (NILP(driver))
661                 pref = MDRIVER_UNKNOWN;
662 #ifdef HAVE_MAD
663         else if (EQ(driver, Qmad))
664                 pref = MDRIVER_MAD;
665 #endif
666 #ifdef HAVE_FFMPEG
667         else if (EQ(driver, Qffmpeg))
668                 pref = MDRIVER_FFMPEG;
669 #endif
670 #ifdef HAVE_SOX
671         else if (EQ(driver, Qsox))
672                 pref = MDRIVER_SOX;
673 #endif
674         else if (EQ(driver, intern("xine")))
675                 pref = MDRIVER_XINE;
676 #ifdef HAVE_SNDFILE
677         else if (EQ(driver, Qsndfile))
678                 pref = MDRIVER_SNDFILE;
679 #endif
680         else if (EQ(driver, intern("internal")))
681                 pref = MDRIVER_INTERNAL;
682         else if (EQ(driver, intern("gstreamer")))
683                 pref = MDRIVER_GSTREAMER;
684         else
685                 pref = MDRIVER_UNKNOWN;
686
687         /* hm, maybe data could be a symbol from the sound-alist?
688          * or a buffer or a network socket?
689          */
690         CHECK_STRING(data);
691
692         lms = make_media_stream();
693         ms = XMEDIA_STREAM(lms);
694
695         switch (datatype) {
696         case DATA_IS_FILE: {
697                 mkind_file_properties *fprops;
698
699                 /* expand-file-name first and check for existence*/
700                 data = Fexpand_file_name(data, Qnil);
701                 if (!NILP(Ffile_directory_p(data)) ||
702                     NILP(Ffile_readable_p(data)))
703                         break;
704
705                 media_stream_kind(ms) = MKIND_FILE;
706
707                 /* initialise a new file properties structure */
708                 fprops = xnew_and_zero(mkind_file_properties);
709
710                 /* copy the filename also as C string */
711                 fprops->filename = data;
712
713                 /* assign the file properties */
714                 media_stream_kind_properties(ms).fprops = fprops;
715
716                 determine_stream_type(ms, pref);
717                 break;
718         }
719         case DATA_IS_DATA: {
720                 mkind_string_properties *sprops;
721                 char *data_ext;
722                 int data_len = 0;
723
724                 media_stream_kind(ms) = MKIND_STRING;
725
726                 /* initialise a new file properties structure */
727                 sprops = xnew_and_zero(mkind_string_properties);
728
729                 /* copy the filename also as C string */
730                 TO_EXTERNAL_FORMAT(LISP_STRING, data,
731                                    MALLOC, (data_ext, data_len),
732                                    Qbinary);
733                 data_ext[data_len] = '\0';
734                 sprops->name = NULL;
735                 sprops->stream_data = data_ext;
736                 sprops->size = data_len;
737
738                 /* assign the file properties */
739                 media_stream_kind_properties(ms).sprops = sprops;
740
741                 determine_stream_type(ms, pref);
742                 break;
743         }
744         case DATA_IS_URL: {
745                 break;
746         }
747         case DATA_IS_BULLSHIT:
748         default:
749                 break;
750         }
751
752         return lms;
753 }
754
755 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
756 {
757         Lisp_Object result;
758
759         result = to;
760
761         while (!NILP(from)) {
762                 result = Fcons(XCAR(from), result);
763                 from = XCDR(from);
764         }
765         return result;
766 }
767
768 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
769 Return non-nil if object is a media-stream.
770 */
771       (object))
772 {
773         if (MEDIA_STREAMP(object))
774                 return Qt;
775         else
776                 return Qnil;
777 }
778
779 #if 0
780 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
781 Return non-nil if object is a media-substream with audio data.
782 */
783       (object))
784 {
785         if (MEDIA_SUBSTREAMP(object) &&
786             XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
787                 return Qt;
788         else
789                 return Qnil;
790 }
791
792 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
793 Return non-nil if object is a media-substream with video data.
794 */
795       (object))
796 {
797         if (MEDIA_SUBSTREAMP(object) &&
798             XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
799                 return Qt;
800         else
801                 return Qnil;
802 }
803 #endif  /* 0 */
804
805 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
806 Return a list of input formats in the underlying media libraries.
807 */
808       ())
809 {
810         Lisp_Object formats;
811         Lisp_Object temp;
812
813         formats = Qnil;
814         temp = Qnil;
815
816 #ifdef HAVE_FFMPEG
817         temp = media_ffmpeg_available_formats();
818 #endif
819         formats = recons(formats, temp);
820         
821 #ifdef HAVE_SNDFILE
822         temp = Qnil;
823 #endif
824         formats = recons(formats, temp);
825
826         return formats;
827 }
828
829 static inline void __attribute__((always_inline))
830 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
831 {
832         *reslist = Fcons(Fcons(key, val), *reslist);
833         return;
834 }
835
836 static void
837 media_substream_props(media_substream *mss, Lisp_Object *reslist)
838 {
839         switch (media_substream_type(mss)) {
840         case MTYPE_AUDIO: {
841                 mtype_audio_properties *mtap =
842                         media_substream_type_properties(mss).aprops;
843
844                 /* add the type property */
845                 __add_prop(reslist, Qtype, Qaudio);
846
847                 if (mtap->name) {
848                         __add_prop(reslist, Qdemux, build_string(mtap->name));
849                 }
850                 if (mtap->codec_name) {
851                         __add_prop(reslist, Qcodec,
852                                    build_string(mtap->codec_name));
853                 }
854
855                 if (mtap->channels) {
856                         __add_prop(reslist, Qnchannels,
857                                    make_int(mtap->channels));
858                 }
859
860                 if (mtap->samplerate) {
861                         __add_prop(reslist, Qsamplerate,
862                                    make_int(mtap->samplerate));
863                 }
864
865                 if (mtap->bitrate) {
866                         __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
867                 }
868
869                 break;
870         }
871
872         case MTYPE_VIDEO: {
873                 mtype_video_properties *mtvp =
874                         media_substream_type_properties(mss).vprops;
875
876                 /* add the type property */
877                 __add_prop(reslist, Qtype, Qvideo);
878
879                 if (mtvp->name) {
880                         __add_prop(reslist, Qdemux, build_string(mtvp->name));
881                 }
882                 if (mtvp->codec_name) {
883                         __add_prop(reslist, Qcodec,
884                                    build_string(mtvp->codec_name));
885                 }
886
887                 if (mtvp->bitrate) {
888                         __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
889                 }
890
891                 if (mtvp->width) {
892                         __add_prop(reslist, Qwidth, make_int(mtvp->width));
893                 }
894
895                 if (mtvp->height) {
896                         __add_prop(reslist, Qheight, make_int(mtvp->height));
897                 }
898
899 #if defined HAVE_MPQ && defined WITH_GMP && 0
900                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
901                         __add_prop(reslist, Qaspect,
902                                    make_bigq(mtvp->aspect_num,
903                                              mtvp->aspect_den));
904                 }
905 #elif defined HAVE_FPFLOAT
906 /* use float arithmetic */
907                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
908                         __add_prop(reslist, Qaspect,
909                                    make_float((fpfloat)mtvp->aspect_num /
910                                               (fpfloat)mtvp->aspect_den));
911                 } else if (mtvp->width && mtvp->height) {
912                         __add_prop(reslist, Qaspect,
913                                    make_float((fpfloat)mtvp->width /
914                                               (fpfloat)mtvp->height));
915                 }
916 #endif
917
918                 break;
919         }
920         case MTYPE_IMAGE: {
921                 __add_prop(reslist, Qtype, Qimage);
922                 break;
923         }
924         default:
925         case MTYPE_UNKNOWN:
926         case NUMBER_OF_MEDIA_TYPES:
927                 break;
928         }
929 }
930
931 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
932 Return an alist of available properties of media-stream STREAM.
933
934 Depending on the underlying stream this alist may be made of
935 several of the following keys, grouped by media contents.
936
937 general:
938 -------
939 'file (string) the stream's filename
940 'uri (string) the stream's URI
941 'fifo (string) the stream's FIFO socket
942 'driver (symbol) the stream's demuxer/decoder driver
943 'kind (symbol) the stream's kind (file, fifo, string, uri, etc.)
944 'type (symbol) the stream's type (audio, video, image, subtitle, lyrics, etc.)
945
946 audio:
947 -----
948 'codec (string) the suitable audio codec
949 'demux (string) the suitable demuxer
950 'title (string) the title of an audio track
951 'artist (string) the performing artist(s)
952 'album (string) the title of the album
953 'comment (string) an arbitrary comment
954 'genre (string) the genre identifier string
955 'year (integer) the year of release
956 'track (integer) the track number on the album
957 'length (integer) the length of the track in seconds
958 'abitrate (integer) the average bitrate of the track in kb/s
959 'samplerate (integer) the samplerate of the track in Hz
960 'nchannels (integer) the number of distinguished channels
961
962 video:
963 -----
964 'codec (string) the suitable audio codec
965 'demux (string) the suitable demuxer
966 'title (string) the title of a video track
967 'comment (string) an arbitrary comment
968 'year (integer) the year of release
969 'vbitrate (integer) the average bitrate of the track in kb/s
970 'width (integer) the x-resolution in pixels
971 'height (integer) the y-resolution in pixels
972 'aspect (bigq) the aspect quotient
973
974 Keys which do not apply to the underlying stream or are not
975 defined in the tag section of the stream are simply left out
976 in the result alist.
977 */
978       (stream))
979 {
980         Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
981         media_substream *mss;
982         Lisp_Object resdl = Qnil;
983
984         switch (media_stream_kind(ms)) {
985         case MKIND_FILE: {
986                 Lisp_Object file =
987                         media_stream_kind_properties(ms).fprops->filename;
988
989                 __add_prop(&resdl, Qfile, file);
990                 __add_prop(&resdl, Qkind, Qfile);
991                 break;
992         }
993         case MKIND_FIFO: {
994                 __add_prop(&resdl, Qkind, Qfifo);
995                 break;
996         }
997         case MKIND_STREAM: {
998                 __add_prop(&resdl, Qkind, Quri);
999                 break;
1000         }
1001         case MKIND_STRING:
1002                 __add_prop(&resdl, Qkind, Qstring);
1003                 break;
1004         case MKIND_UNKNOWN:
1005         case NUMBER_OF_MEDIA_KINDS:
1006         default:
1007                 __add_prop(&resdl, Qkind, Qunknown);
1008                 break;
1009         }
1010
1011         switch (media_stream_driver(ms)) {
1012         case MDRIVER_INTERNAL:
1013                 __add_prop(&resdl, Qdriver, Qinternal);
1014                 break;
1015         case MDRIVER_FFMPEG:
1016 #ifdef HAVE_FFMPEG
1017                 __add_prop(&resdl, Qdriver, Qffmpeg);
1018 #if 0
1019                 streaminfo = media_ffmpeg_streaminfo(ms);
1020 #endif
1021 #endif
1022                 break;
1023         case MDRIVER_SNDFILE:
1024 #ifdef HAVE_SNDFILE
1025                 __add_prop(&resdl, Qdriver, Qsndfile);
1026 #endif
1027                 break;
1028         case MDRIVER_MAD:
1029 #ifdef HAVE_MAD
1030                 __add_prop(&resdl, Qdriver, Qmad);
1031 #endif
1032                 break;
1033         case MDRIVER_SOX:
1034 #ifdef HAVE_SOX
1035                 __add_prop(&resdl, Qdriver, Qsox);
1036 #endif
1037                 break;
1038
1039         case MDRIVER_UNKNOWN:
1040         case NUMBER_OF_MEDIA_DRIVERS:
1041         default:
1042                 __add_prop(&resdl, Qdriver, Qunknown);
1043                 break;
1044         }
1045
1046 #if 0
1047         if (streaminfo) {
1048                 xfree(streaminfo);
1049         }
1050 #endif
1051
1052         mss = media_stream_first(ms);
1053         while (mss) {
1054                 media_substream_props(mss, &resdl);
1055                 mss = media_substream_next(mss);
1056         }
1057
1058         return resdl;
1059 }
1060
1061 /* convenience functions */
1062 DEFUN("media-stream-aspect", Fmedia_stream_aspect, 1, 3, 0, /*
1063 Return a list of aspect ratios in media stream STREAM.
1064
1065 Optional argument SUBSTREAM names the index of a specific (video)
1066 substream, i.e. only video streams are counted, i.e. the substream 0
1067 names the first video track inside STREAM.
1068 The return value in that case is just a float or quotient, depending
1069 on the optional argument QUOTIENTP.
1070
1071 Optional argument QUOTIENTP indicates that aspect ratios are to be
1072 returned as bigq quotients instead of floats (the default).
1073
1074 By default, the aspect ratios of all the video tracks appear in the list,
1075 the first element in the list belongs to the first video track,
1076 the second element to the second one and so on.
1077 */
1078       (stream, substream, quotientp))
1079 {
1080         Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1081         Lisp_Object res = Qnil;
1082         long int idx = INTP(substream) ? XINT(substream) : -1;
1083
1084         for (media_substream *mss = media_stream_first(ms); mss;
1085              (mss = media_substream_next(mss))) {
1086                 mtype_video_properties *mtvp;
1087                 long int num = 0, den = 0;
1088                 Lisp_Object tmp;
1089
1090                 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1091                         continue;
1092                 }
1093
1094                 /* oh, it's a video stream, check if it's the one we wanted */
1095                 if (UNLIKELY(idx--  > 0)) {
1096                         continue;
1097                 }
1098
1099                 mtvp = media_substream_type_properties(mss).vprops;
1100                 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
1101                         num = mtvp->aspect_num;
1102                         den = mtvp->aspect_den;
1103                 } else if (mtvp->width && mtvp->height) {
1104                         /* good enough? just an approximation as
1105                          * the aspect ratio may very well differ
1106                          * from the width-by-height ratio */
1107                         num = mtvp->width;
1108                         den = mtvp->height;
1109                 }
1110                         
1111                 if (LIKELY(NILP(quotientp))) {
1112                         tmp = make_float((fpfloat)num / (fpfloat)den);
1113                 } 
1114 #if defined HAVE_MPQ && defined WITH_GMP
1115                 else {
1116                         tmp = make_bigq(num, den);
1117                 }
1118 #else
1119                 else {
1120                   dead_wrong_type_argument(Qfeaturep,quotientp);
1121                 }
1122 #endif
1123                 if (UNLIKELY(INTP(substream))) {
1124                         return tmp;
1125                 }
1126                 /* the very very default case */
1127                 res = Fcons(tmp, res);
1128         }
1129         return res;
1130 }
1131
1132 \f
1133 /* Audio Coercion */
1134 /* SXEmacs works internally with samples in 24bit resolution */
1135
1136 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1137
1138 static void
1139 sxe_msf_U8_up(void *d, void *s, size_t len)
1140 {
1141         /* convert U8 samples to internal format (S24in32) */
1142         int i;
1143         int32_t *dst = d;
1144         uint8_t *src = s;
1145
1146         /* len is the number of samples (== #frame * #channels) */
1147         MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1148
1149         for (i = len-1; i >= 0; i--)
1150                 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1151
1152         return;
1153 }
1154
1155 static void
1156 sxe_msf_U8_down(void *d, void *s, size_t len)
1157 {
1158         /* convert samples from internal format (S24in32) to U8 */
1159         size_t i;
1160         uint8_t *dst = d;
1161         int32_t *src = s;
1162
1163         /* len is the number of samples (== #frame * #channels) */
1164         MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1165
1166         for (i = 0; i < len; i++)
1167                 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1168
1169         return;
1170 }
1171
1172 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1173
1174 static void
1175 sxe_msf_S16_up(void *d, void *s, size_t len)
1176 {
1177         /* convert S16 samples to internal format (S24in32) */
1178         int i;
1179         int32_t *dst = d;
1180         int16_t *src = s;
1181
1182         /* len is the number of samples (== #frame * #channels) */
1183         MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
1184
1185         for (i = len-1; i >= 0; i--)
1186                 dst[i] = (int32_t)(src[i]) << 8;
1187         MEDIA_DEBUG_FMT("d00:%d  d01:%d\n", dst[0], dst[1]);
1188
1189         return;
1190 }
1191
1192 static void
1193 sxe_msf_S16_down(void *d, void *s, size_t len)
1194 {
1195         /* convert samples from internal format (S24in32) to S16 */
1196         size_t i;
1197         int16_t *dst = d;
1198         int32_t *src = s;
1199
1200         /* len is the number of samples (== #frame * #channels) */
1201         MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1202
1203         for (i = 0; i < len; i++)
1204                 dst[i] = (int16_t)(src[i] >> 8);
1205
1206         return;
1207 }
1208
1209 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1210
1211 static void
1212 sxe_msf_S24_up(void *d, void *s, size_t len)
1213 {
1214         MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1215
1216         /* S24 _is_ the internal format */
1217         return;
1218 }
1219
1220 static void
1221 sxe_msf_S24_down(void *d, void *s, size_t len)
1222 {
1223         MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1224
1225         /* S24 _is_ the internal format */
1226         return;
1227 }
1228
1229 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1230
1231 static void
1232 sxe_msf_S32_up(void *d, void *s, size_t len)
1233 {
1234         /* convert S32 samples to internal format (S24in32) */
1235         size_t i;
1236         int32_t *dst = d;
1237         int32_t *src = s;
1238
1239         /* len is the number of samples (== #frame * #channels) */
1240         MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1241
1242         for (i = 0; i < len; i++)
1243                 dst[i] = src[i] >> 8;
1244
1245         return;
1246 }
1247
1248 static void
1249 sxe_msf_S32_down(void *d, void *s, size_t len)
1250 {
1251         /* convert samples from internal format (S24in32) to S32 */
1252         size_t i;
1253         int32_t *dst = d;
1254         int32_t *src = s;
1255
1256         /* len is the number of samples (== #frame * #channels) */
1257         MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1258
1259         for (i = 0; i < len; i++)
1260                 dst[i] = src[i] << 8;
1261
1262         return;
1263 }
1264
1265 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1266
1267 static void
1268 sxe_msf_FLT_up(void *d, void *s, size_t len)
1269 {
1270         /* convert float samples to internal format (S24in32) */
1271         size_t i;
1272         int32_t *dst = d;
1273         float *src = s;
1274
1275         /* len is the number of samples (== #frame * #channels) */
1276         MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1277
1278         for (i = 0; i < len; i++) {
1279                 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1280         }
1281         MEDIA_DEBUG_FMT("s00:%f d00:%d  s01:%f d01:%d\n",
1282                         src[0], dst[0], src[1], dst[1]);
1283
1284         return;
1285 }
1286
1287 static void
1288 sxe_msf_FLT_down(void *d, void *s, size_t len)
1289 {
1290         /* convert samples from internal format (S24in32) to float */
1291         int i;
1292         float *dst = d;
1293         int32_t *src = s;
1294
1295         /* len is the number of samples (== #frame * #channels) */
1296         MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1297
1298         for (i = len-1; i >= 0; i--) {
1299                 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1300         }
1301         MEDIA_DEBUG_FMT("d00:%f  d01:%f\n", dst[0], dst[1]);
1302
1303         return;
1304 }
1305
1306 /* `effects' */
1307 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1308
1309 static size_t
1310 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1311                     size_t len, void *ignored)
1312 {
1313         /* mono to stereo converter */
1314         int i;
1315
1316         MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1317
1318         /* len is the number of samples */
1319         for (i = len-1; i >= 0; i--) {
1320                 dst[2*i] = src[i];
1321                 dst[2*i+1] = src[i];
1322         }
1323
1324         return len * 2;
1325 }
1326
1327 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1328
1329 static size_t
1330 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1331                     size_t len, void *args)
1332 {
1333         /* stereo to mono converter */
1334         size_t i;
1335         sxe_mse_2ch_to_1ch_args *_args = args;
1336         int c = 0;
1337
1338         MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1339
1340         if (_args) {
1341                 c = _args->chan;
1342         }
1343
1344         /* len is the number of samples */
1345         for (i = 0; i < len/2; i++) {
1346                 dst[i] = src[2*i+c];
1347         }
1348
1349         return len / 2;
1350 }
1351
1352 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1353
1354 static size_t
1355 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1356                     size_t len, void *args)
1357 {
1358         /* 5 channel to stereo converter */
1359         size_t i;
1360         sxe_mse_5ch_to_2ch_args *_args = args;
1361         int c1 = 0, c2 = 1;
1362
1363         MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
1364
1365         if (_args) {
1366                 c1 = _args->chan1;
1367                 c2 = _args->chan1;
1368         }
1369
1370         /* len is the number of samples */
1371         for (i = 0; i < len/5; i++) {
1372                 dst[2*i] = src[5*i+c1];
1373                 dst[2*i+1] = src[5*i+c2];
1374         }
1375
1376         return len * 2 / 5;
1377 }
1378
1379 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1380
1381 static size_t
1382 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1383                 size_t len, void *args)
1384 {
1385         /* stereo to mono converter */
1386         size_t i, j;
1387         sxe_mse_volume_args *_args = args;
1388
1389         MEDIA_DEBUG_COE("volume: %u samples\n", len);
1390
1391         /* len is the number of samples */
1392         for (i = 0; i < len; i+=_args->num_channels) {
1393                 for (j = 0; j < (size_t)_args->num_channels; j++) {
1394                         uint8_t vol = _args->volume[j];
1395                         dst[i+j] = (src[i+j] * vol) >> 7;
1396                 }
1397         }
1398
1399         return len;
1400 }
1401
1402 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1403
1404 static size_t
1405 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1406                 size_t len, void *args)
1407 {
1408         /* rate converter */
1409         int i;
1410         sxe_mse_rerate_args *_args = args;
1411         float trafo = (float)_args->srcrate / (float)_args->tgtrate
1412                 * _args->tweak;
1413         int chans = _args->num_channels;
1414         int bound = len/chans/trafo;
1415
1416         MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
1417                         len, trafo, bound);
1418
1419         if (trafo < 1.0) {
1420                 for (i = bound-1; i >= 0; i--) {
1421                         int frame = i * trafo;
1422                         dst[chans*i] = (src[chans*frame]);
1423                         dst[chans*i+1] = (src[chans*frame+1]);
1424                 }
1425         } else if (trafo > 1.0) {
1426                 for (i = 0; i < bound-1; i++) {
1427                         int frame = i * trafo;
1428                         dst[chans*i] = (src[chans*frame]);
1429                         dst[chans*i+1] = (src[chans*frame+1]);
1430                 }
1431         }
1432
1433         return bound * chans;
1434 }
1435
1436 \f
1437 void syms_of_media(void)
1438 {
1439         INIT_LRECORD_IMPLEMENTATION(media_stream);
1440
1441         defsymbol(&Qmedia_streamp, "media-stream-p");
1442
1443         DEFSYMBOL(Qtype);
1444         DEFSYMBOL(Qdemux);
1445         DEFSYMBOL(Qcodec);
1446         DEFSYMBOL(Qnchannels);
1447         DEFSYMBOL(Qsamplerate);
1448         DEFSYMBOL(Qbitrate);
1449         DEFSYMBOL(Qabitrate);
1450         DEFSYMBOL(Qvbitrate);
1451         DEFSYMBOL(Qwidth);
1452         DEFSYMBOL(Qheight);
1453         DEFSYMBOL(Qaspect);
1454         DEFSYMBOL(Qaudio);
1455         DEFSYMBOL(Qvideo);
1456         DEFSYMBOL(Qimage);
1457         DEFSYMBOL(Qdriver);
1458         DEFSYMBOL(Qkind);
1459         DEFSYMBOL(Qfifo);
1460         DEFSYMBOL(Quri);
1461
1462         DEFSUBR(Fmake_media_stream);
1463         DEFSUBR(Fmedia_stream_p);
1464 #if 0
1465         DEFSUBR(Faudio_substream_p);
1466         DEFSUBR(Fvideo_substream_p);
1467 #endif
1468
1469         DEFSUBR(Fmedia_available_formats);
1470         DEFSUBR(Fmedia_properties);
1471         DEFSUBR(Fmedia_stream_aspect);
1472
1473 #ifdef HAVE_FFMPEG
1474         defsymbol(&Qffmpeg, "ffmpeg");
1475 #endif
1476 #ifdef HAVE_MAD
1477         defsymbol(&Qmad, "mad");
1478 #endif
1479 #ifdef HAVE_SOX
1480         defsymbol(&Qsox, "sox");
1481 #endif
1482 #ifdef HAVE_SNDFILE
1483         defsymbol(&Qsndfile, "sndfile");
1484 #endif
1485         defsymbol(&Qunknown, "unknown");
1486 }
1487
1488 void vars_of_media(void)
1489 {
1490         Fprovide(intern("media"));
1491
1492 #ifdef HAVE_FFMPEG
1493         Fprovide(intern("media-ffmpeg"));
1494 #endif
1495 #ifdef HAVE_SNDFILE
1496         Fprovide(intern("media-sndfile"));
1497 #endif
1498 #ifdef HAVE_MAD
1499         Fprovide(intern("media-mad"));
1500 #endif
1501 #ifdef HAVE_SOX
1502         Fprovide(intern("media-sox"));
1503 #endif
1504 #ifdef HAVE_XINE
1505         Fprovide(intern("media-xine"));
1506 #endif
1507 #ifdef HAVE_GSTREAMER
1508         Fprovide(intern("media-gstreamer"));
1509 #endif
1510 #ifdef HAVE_INTERNAL_MEDIA
1511         Fprovide(intern("media-internal"));
1512 #endif
1513 }
1514
1515 /* media.c ends here */