2 Copyright (C) 2006 Sebastian Freundt
4 This file is part of SXEmacs
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.
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.
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/>. */
20 /* Synched up with: Not in FSF. */
30 #include "media-ffmpeg.h"
33 #include "media-sndfile.h"
35 #ifdef HAVE_INTERNAL_MEDIA
36 #include "media-internal.h"
39 #include "media-mad.h"
42 #include "media-gstreamer.h"
45 #include "media-sox.h"
48 #include "media-xine.h"
51 Lisp_Object Qmedia_streamp;
53 Lisp_Object Qunavailable;
54 /* media property syms */
55 Lisp_Object Qdemux, Qcodec, Qnchannels, Qsamplerate;
56 Lisp_Object Qbitrate, Qabitrate, Qvbitrate;
57 Lisp_Object Qwidth, Qheight, Qaspect, Qdriver, Qkind, Qfifo, Quri, Qtype;
58 Lisp_Object Qaudio, Qvideo, Qimage;
60 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver);
61 static void media_stream_print(Lisp_Object, Lisp_Object, int);
62 static void media_substream_print(media_substream *, Lisp_Object, int);
63 static void media_substream_finalise(void*, int);
66 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver preferred)
69 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
70 (preferred == MDRIVER_UNKNOWN ||
71 preferred == MDRIVER_FFMPEG)) {
72 MEDIA_DEBUG("trying ffmpeg.\n");
73 media_stream_set_meths(ms, media_ffmpeg);
74 media_stream_meth(ms, open)(ms);
78 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
79 (preferred == MDRIVER_UNKNOWN ||
80 preferred == MDRIVER_MAD)) {
81 MEDIA_DEBUG("trying mad.\n");
82 media_stream_set_meths(ms, media_mad);
83 media_stream_meth(ms, open)(ms);
87 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
88 (preferred == MDRIVER_UNKNOWN ||
89 preferred == MDRIVER_SOX)) {
90 MEDIA_DEBUG("trying sox.\n");
91 media_stream_set_meths(ms, media_sox);
92 media_stream_meth(ms, open)(ms);
96 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
97 (preferred == MDRIVER_UNKNOWN ||
98 preferred == MDRIVER_SNDFILE)) {
99 MEDIA_DEBUG("trying sndfile.\n");
100 media_stream_set_meths(ms, media_sndfile);
101 media_stream_meth(ms, open)(ms);
104 /* not working stuff here :) */
106 #ifdef HAVE_GSTREAMER
107 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
108 (preferred == MDRIVER_UNKNOWN ||
109 preferred == MDRIVER_GSTREAMER)) {
110 MEDIA_DEBUG("trying gstreamer.\n");
111 media_gstreamer_analyse_stream(ms);
116 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
117 (preferred == MDRIVER_UNKNOWN ||
118 preferred == MDRIVER_XINE)) {
119 MEDIA_DEBUG("trying xine.\n");
120 media_stream_set_meths(ms, media_xine);
121 media_stream_meth(ms, open)(ms);
124 #ifdef HAVE_INTERNAL_MEDIA
125 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
126 (preferred == MDRIVER_UNKNOWN ||
127 preferred == MDRIVER_INTERNAL)) {
128 MEDIA_DEBUG("trying internal.\n");
129 media_internal_analyse_stream(ms);
132 if (media_stream_driver(ms) == MDRIVER_UNKNOWN) {
133 MEDIA_DEBUG("giving up\n");
134 media_stream_set_meths(ms, NULL);
140 /*****************************************************************/
142 /*****************************************************************/
143 static Lisp_Object media_stream_mark(Lisp_Object obj)
145 switch (XMEDIA_STREAM_KIND(obj)) {
147 mark_object(XMEDIA_STREAM(obj)->
148 kind_properties.fprops->filename);
154 case NUMBER_OF_MEDIA_KINDS:
159 if (XMEDIA_STREAM_METHS(obj) &&
160 XMEDIA_STREAM_METH(obj, mark))
161 XMEDIA_STREAM_METH(obj, mark)(XMEDIA_STREAM_DATA(obj));
167 media_stream_finalise(void *header, int for_disksave)
169 Lisp_Media_Stream *ms = (Lisp_Media_Stream*)header;
170 media_substream *mss = NULL;
174 if (media_stream_meths(ms) &&
175 media_stream_meth(ms, close))
176 media_stream_meth(ms, close)(media_stream_data(ms));
178 mss = media_stream_first(ms);
180 media_substream_finalise(mss, for_disksave);
181 mss = media_substream_next(mss);
185 switch (media_stream_driver(ms)) {
188 if (media_stream_data(ms))
189 media_xine_close_context(media_stream_data(ms));
192 case MDRIVER_SNDFILE:
194 if (media_stream_data(ms))
195 sf_close(media_stream_data(ms));
200 if (media_stream_data(ms))
201 mad_decoder_finish(media_stream_data(ms));
206 if (media_stream_data(ms))
207 st_close(media_stream_data(ms));
215 switch (media_stream_kind(ms)) {
217 mkind_file_properties *mkfp;
218 mkfp = media_stream_kind_properties(ms).fprops;
225 mkind_string_properties *mksp;
226 mksp = media_stream_kind_properties(ms).sprops;
231 if (mksp->stream_data)
232 xfree(mksp->stream_data);
241 case NUMBER_OF_MEDIA_KINDS:
246 /* avoid some warning */
247 if (for_disksave || ms == NULL);
251 media_stream_print(Lisp_Object obj, Lisp_Object printcharfun, int ef)
253 Lisp_Media_Stream *ms = XMEDIA_STREAM(obj);
254 media_substream *mss;
256 write_c_string("#<media-stream", printcharfun);
258 write_c_string(" :kind ", printcharfun);
260 switch (media_stream_kind(ms)) {
263 media_stream_kind_properties(ms).fprops->filename;
265 write_c_string("#<file ", printcharfun);
266 print_internal(file, printcharfun, ef);
267 write_c_string(">", printcharfun);
271 write_c_string("#<string>", printcharfun);
274 write_c_string("#<fifo>", printcharfun);
277 write_c_string("#<stream>", printcharfun);
282 case NUMBER_OF_MEDIA_KINDS:
283 write_c_string("#<unknown>", printcharfun);
287 mss = media_stream_first(ms);
289 write_c_string(" ", printcharfun);
290 media_substream_print(mss, printcharfun, ef);
291 mss = media_substream_next(mss);
294 write_c_string(" driven by ", printcharfun);
295 switch (media_stream_driver(ms)) {
296 case MDRIVER_INTERNAL:
297 write_c_string("internal", printcharfun);
300 write_c_string("ffmpeg", printcharfun);
302 case MDRIVER_SNDFILE:
303 write_c_string("sndfile", printcharfun);
306 write_c_string("mad", printcharfun);
309 write_c_string("sox", printcharfun);
312 write_c_string("xine", printcharfun);
314 case MDRIVER_GSTREAMER:
315 write_c_string("gstreamer", printcharfun);
317 case MDRIVER_UNKNOWN:
318 case NUMBER_OF_MEDIA_DRIVERS:
320 XMEDIA_STREAM_SET_METHS(obj, NULL);
321 write_c_string("unknown", printcharfun);
325 if (XMEDIA_STREAM_METHS(obj) &&
326 XMEDIA_STREAM_METH(obj, print)) {
327 XMEDIA_STREAM_METH(obj, print)(obj, printcharfun, ef);
330 write_c_string(">", printcharfun);
334 media_stream_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
336 if (XMEDIA_STREAM_DATA(obj1) == XMEDIA_STREAM_DATA(obj2))
346 media_stream_hash (Lisp_Object obj, int depth)
348 return (unsigned long)obj;
354 static const struct lrecord_description media_stream_description[] = {
355 { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, first) },
356 { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, last) },
357 { XD_INT, offsetof(Lisp_Media_Stream, kind) },
358 { XD_INT, offsetof(Lisp_Media_Stream, driver) },
359 { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, kind_properties) },
360 { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, stream_data) },
364 DEFINE_LRECORD_IMPLEMENTATION("media_stream", media_stream,
365 media_stream_mark, media_stream_print,
366 media_stream_finalise,
367 media_stream_equal, media_stream_hash,
368 media_stream_description,
372 /*****************************************************************/
373 /* media substreams */
374 /*****************************************************************/
377 media_substream_finalise(void *header, int for_disksave)
379 media_substream *mss = (media_substream*)header;
381 switch (media_substream_type(mss)) {
383 if (media_substream_type_properties(mss).aprops)
384 xfree(media_substream_type_properties(mss).aprops);
387 if (media_substream_type_properties(mss).vprops)
388 xfree(media_substream_type_properties(mss).vprops);
392 case NUMBER_OF_MEDIA_TYPES:
398 pthread_mutex_destroy(&mss->substream_mutex);
401 media_substream_data(mss) = NULL;
403 /* avoid some warning */
408 media_substream_print_audio(media_substream *mss, Lisp_Object printcharfun)
410 mtype_audio_properties *mtap =
411 media_substream_type_properties(mss).aprops;
413 write_c_string("#<audio ", printcharfun);
414 if (mtap->name || mtap->codec_name) {
415 if (mtap->name && mtap->codec_name)
416 write_fmt_str(printcharfun, "%s (%s)",
417 mtap->name, mtap->codec_name);
419 write_fmt_str(printcharfun, "%s [???]", mtap->name);
420 else if (mtap->codec_name)
421 write_fmt_str(printcharfun, "??? (%s)", mtap->codec_name);
423 write_c_string("???", printcharfun);
425 switch (mtap->channels) {
427 write_c_string(", mono", printcharfun);
430 write_c_string(", stereo", printcharfun);
433 write_c_string(", chn:5", printcharfun);
436 write_c_string(", 5.1", printcharfun);
439 write_c_string(", chn:???", printcharfun);
443 if (mtap->samplerate)
444 write_fmt_str(printcharfun, ", %d Hz, %d Bit",
449 write_fmt_str(printcharfun, ", %d kb/s", mtap->bitrate/1000);
451 write_c_string(">", printcharfun);
455 media_substream_print_video(media_substream *mss, Lisp_Object printcharfun)
457 mtype_video_properties *mtvp =
458 media_substream_type_properties(mss).vprops;
460 write_c_string("#<video ", printcharfun);
461 if (mtvp->name || mtvp->codec_name) {
462 if (mtvp->name && mtvp->codec_name)
463 write_fmt_str(printcharfun, "%s (%s)",
464 mtvp->name, mtvp->codec_name);
466 write_fmt_str(printcharfun, "%s [???]", mtvp->name);
467 else if (mtvp->codec_name)
468 write_fmt_str(printcharfun, "??? (%s)", mtvp->codec_name);
470 write_c_string("???", printcharfun);
473 write_fmt_str(printcharfun, ", %d kb/s", mtvp->bitrate);
475 if (mtvp->width && mtvp->height) {
476 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1)
477 write_fmt_str(printcharfun, ", %dx%d (%d/%d)",
478 mtvp->width, mtvp->height,
479 mtvp->aspect_num, mtvp->aspect_den);
481 write_fmt_str(printcharfun, ", %dx%d (%.2f/1)",
482 mtvp->width, mtvp->height,
483 (double)mtvp->width/(double)mtvp->height);
485 write_c_string(">", printcharfun);
489 media_substream_print(media_substream *mss,
490 Lisp_Object printcharfun, int escapeflag)
492 write_c_string("#<media-substream :type ", printcharfun);
494 switch (media_substream_type(mss)) {
496 media_substream_print_audio(mss, printcharfun);
500 media_substream_print_video(mss, printcharfun);
503 write_c_string("#<image>", printcharfun);
507 case NUMBER_OF_MEDIA_TYPES:
508 write_c_string("#<unknown>", printcharfun);
512 write_c_string(">", printcharfun);
515 static Lisp_Media_Stream *
516 media_stream_allocate(void)
518 Lisp_Media_Stream *ms;
520 ms = alloc_lcrecord_type(Lisp_Media_Stream, &lrecord_media_stream);
525 Lisp_Object make_media_stream()
527 Lisp_Media_Stream *ms;
530 ms = media_stream_allocate();
531 media_stream_kind(ms) = MKIND_UNKNOWN;
532 media_stream_driver(ms) = MDRIVER_UNKNOWN;
533 media_stream_data(ms) = NULL;
535 /* now set the navigation */
536 media_stream_first(ms) = NULL;
537 media_stream_last(ms) = NULL;
539 XSETMEDIA_STREAM(lms, ms);
544 media_substream *make_media_substream(void)
546 /* this allocates and conses to the back of ms */
547 media_substream *mss;
549 mss = xnew_and_zero(media_substream);
550 media_substream_type(mss) = MTYPE_UNKNOWN;
551 media_substream_data(mss) = NULL;
554 media_substream_next(mss) = NULL;
555 media_substream_prev(mss) = NULL;
558 pthread_mutex_init(&mss->substream_mutex, NULL);
564 media_substream *make_media_substream_append(Lisp_Media_Stream *ms)
566 media_substream *mss;
568 mss = make_media_substream();
571 media_substream_next(mss) = NULL;
572 if (!(media_stream_last(ms))) {
573 media_substream_prev(mss) = NULL;
574 media_stream_first(ms) = mss;
576 media_substream_prev(mss) = media_stream_last(ms);
577 media_substream_next(media_stream_last(ms)) = mss;
580 media_stream_last(ms) = mss;
581 media_substream_up(mss) = ms;
586 media_substream *make_media_substream_prepend(Lisp_Media_Stream *ms)
588 media_substream *mss;
590 mss = make_media_substream();
593 media_substream_prev(mss) = NULL;
594 if (!(media_stream_first(ms))) {
595 media_substream_next(mss) = NULL;
596 media_stream_last(ms) = mss;
598 media_substream_next(mss) = media_stream_first(ms);
599 media_substream_prev(media_stream_first(ms)) = mss;
602 media_stream_first(ms) = mss;
603 media_substream_up(mss) = ms;
608 DEFUN("make-media-stream", Fmake_media_stream, 2, 3, 0, /*
609 Create a new media stream from DATA.
611 FROM is a keyword and defines how DATA is interpreted:
612 :file - DATA is the name of a file
613 :data - DATA is a string with the stream data
614 :url - DATA is a url (string) for streamed media contents
616 Optional argument DRIVER (a symbol) may be used to force
617 the use of a certain driver instead of automatically
618 detecting a suitable one. It is one of `ffmpeg', `sndfile',
619 `sox', `mad', `xine', `gstreamer', or `internal'.
621 (from, data, driver))
624 Lisp_Media_Stream *ms;
629 DATA_IS_DATA } datatype = DATA_IS_BULLSHIT;
630 media_driver pref = MDRIVER_UNKNOWN;
633 else if (EQ(from, Q_file))
634 datatype = DATA_IS_FILE;
635 else if (EQ(from, Q_data))
636 datatype = DATA_IS_DATA;
637 else if (EQ(from, Q_url))
638 datatype = DATA_IS_URL;
640 datatype = DATA_IS_BULLSHIT;
641 return Qnil; /* in this case, why bother? stupid user :) */
645 pref = MDRIVER_UNKNOWN;
647 else if (EQ(driver, Qmad))
651 else if (EQ(driver, Qffmpeg))
652 pref = MDRIVER_FFMPEG;
655 else if (EQ(driver, Qsox))
658 else if (EQ(driver, intern("xine")))
661 else if (EQ(driver, Qsndfile))
662 pref = MDRIVER_SNDFILE;
664 else if (EQ(driver, intern("internal")))
665 pref = MDRIVER_INTERNAL;
666 else if (EQ(driver, intern("gstreamer")))
667 pref = MDRIVER_GSTREAMER;
669 pref = MDRIVER_UNKNOWN;
671 /* hm, maybe data could be a symbol from the sound-alist?
672 * or a buffer or a network socket?
676 lms = make_media_stream();
677 ms = XMEDIA_STREAM(lms);
681 mkind_file_properties *fprops;
683 /* expand-file-name first and check for existence*/
684 data = Fexpand_file_name(data, Qnil);
685 if (!NILP(Ffile_directory_p(data)) ||
686 NILP(Ffile_readable_p(data)))
689 media_stream_kind(ms) = MKIND_FILE;
691 /* initialise a new file properties structure */
692 fprops = xnew_and_zero(mkind_file_properties);
694 /* copy the filename also as C string */
695 fprops->filename = data;
697 /* assign the file properties */
698 media_stream_kind_properties(ms).fprops = fprops;
700 determine_stream_type(ms, pref);
704 mkind_string_properties *sprops;
705 char *data_ext = NULL;
708 /* copy the filename also as C string */
709 TO_EXTERNAL_FORMAT(LISP_STRING, data,
710 MALLOC, (data_ext, data_len),
713 if (data_ext != NULL) {
714 media_stream_kind(ms) = MKIND_STRING;
716 /* initialise a new file properties structure */
717 sprops = xnew_and_zero(mkind_string_properties);
719 data_ext[data_len] = '\0';
721 sprops->stream_data = data_ext;
722 sprops->size = data_len;
724 /* assign the file properties */
725 media_stream_kind_properties(ms).sprops = sprops;
727 determine_stream_type(ms, pref);
734 case DATA_IS_BULLSHIT:
742 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
748 while (!NILP(from)) {
749 result = Fcons(XCAR(from), result);
755 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
756 Return non-nil if object is a media-stream.
760 if (MEDIA_STREAMP(object))
767 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
768 Return non-nil if object is a media-substream with audio data.
772 if (MEDIA_SUBSTREAMP(object) &&
773 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
779 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
780 Return non-nil if object is a media-substream with video data.
784 if (MEDIA_SUBSTREAMP(object) &&
785 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
792 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
793 Return a list of input formats in the underlying media libraries.
804 temp = media_ffmpeg_available_formats();
806 formats = recons(formats, temp);
811 formats = recons(formats, temp);
816 static inline void __attribute__((always_inline))
817 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
819 *reslist = Fcons(Fcons(key, val), *reslist);
824 media_substream_props(media_substream *mss, Lisp_Object *reslist)
826 switch (media_substream_type(mss)) {
828 mtype_audio_properties *mtap =
829 media_substream_type_properties(mss).aprops;
831 /* add the type property */
832 __add_prop(reslist, Qtype, Qaudio);
835 __add_prop(reslist, Qdemux, build_string(mtap->name));
837 if (mtap->codec_name) {
838 __add_prop(reslist, Qcodec,
839 build_string(mtap->codec_name));
842 if (mtap->channels) {
843 __add_prop(reslist, Qnchannels,
844 make_int(mtap->channels));
847 if (mtap->samplerate) {
848 __add_prop(reslist, Qsamplerate,
849 make_int(mtap->samplerate));
853 __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
860 mtype_video_properties *mtvp =
861 media_substream_type_properties(mss).vprops;
863 /* add the type property */
864 __add_prop(reslist, Qtype, Qvideo);
867 __add_prop(reslist, Qdemux, build_string(mtvp->name));
869 if (mtvp->codec_name) {
870 __add_prop(reslist, Qcodec,
871 build_string(mtvp->codec_name));
875 __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
879 __add_prop(reslist, Qwidth, make_int(mtvp->width));
883 __add_prop(reslist, Qheight, make_int(mtvp->height));
886 #if defined HAVE_MPQ && defined WITH_GMP && 0
887 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
888 __add_prop(reslist, Qaspect,
889 make_bigq(mtvp->aspect_num,
892 #elif defined HAVE_FPFLOAT
893 /* use float arithmetic */
894 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
895 __add_prop(reslist, Qaspect,
896 make_float((fpfloat)mtvp->aspect_num /
897 (fpfloat)mtvp->aspect_den));
898 } else if (mtvp->width && mtvp->height) {
899 __add_prop(reslist, Qaspect,
900 make_float((fpfloat)mtvp->width /
901 (fpfloat)mtvp->height));
908 __add_prop(reslist, Qtype, Qimage);
913 case NUMBER_OF_MEDIA_TYPES:
918 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
919 Return an alist of available properties of media-stream STREAM.
921 Depending on the underlying stream this alist may be made of
922 several of the following keys, grouped by media contents.
926 'file (string) the stream's filename
927 'uri (string) the stream's URI
928 'fifo (string) the stream's FIFO socket
929 'driver (symbol) the stream's demuxer/decoder driver
930 'kind (symbol) the stream's kind (file, fifo, string, uri, etc.)
931 'type (symbol) the stream's type (audio, video, image, subtitle, lyrics, etc.)
935 'codec (string) the suitable audio codec
936 'demux (string) the suitable demuxer
937 'title (string) the title of an audio track
938 'artist (string) the performing artist(s)
939 'album (string) the title of the album
940 'comment (string) an arbitrary comment
941 'genre (string) the genre identifier string
942 'year (integer) the year of release
943 'track (integer) the track number on the album
944 'length (integer) the length of the track in seconds
945 'abitrate (integer) the average bitrate of the track in kb/s
946 'samplerate (integer) the samplerate of the track in Hz
947 'nchannels (integer) the number of distinguished channels
951 'codec (string) the suitable audio codec
952 'demux (string) the suitable demuxer
953 'title (string) the title of a video track
954 'comment (string) an arbitrary comment
955 'year (integer) the year of release
956 'vbitrate (integer) the average bitrate of the track in kb/s
957 'width (integer) the x-resolution in pixels
958 'height (integer) the y-resolution in pixels
959 'aspect (bigq) the aspect quotient
961 Keys which do not apply to the underlying stream or are not
962 defined in the tag section of the stream are simply left out
967 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
968 media_substream *mss;
969 Lisp_Object resdl = Qnil;
971 switch (media_stream_kind(ms)) {
974 media_stream_kind_properties(ms).fprops->filename;
976 __add_prop(&resdl, Qfile, file);
977 __add_prop(&resdl, Qkind, Qfile);
981 __add_prop(&resdl, Qkind, Qfifo);
985 __add_prop(&resdl, Qkind, Quri);
989 __add_prop(&resdl, Qkind, Qstring);
992 case NUMBER_OF_MEDIA_KINDS:
994 __add_prop(&resdl, Qkind, Qunknown);
998 __add_prop(&resdl, Qdriver, Qunavailable);
999 switch (media_stream_driver(ms)) {
1000 case MDRIVER_INTERNAL:
1001 __add_prop(&resdl, Qdriver, Qinternal);
1003 case MDRIVER_FFMPEG:
1005 __add_prop(&resdl, Qdriver, Qffmpeg);
1007 streaminfo = media_ffmpeg_streaminfo(ms);
1011 case MDRIVER_SNDFILE:
1013 __add_prop(&resdl, Qdriver, Qsndfile);
1018 __add_prop(&resdl, Qdriver, Qmad);
1023 __add_prop(&resdl, Qdriver, Qsox);
1030 case MDRIVER_GSTREAMER:
1033 case MDRIVER_UNKNOWN:
1034 case NUMBER_OF_MEDIA_DRIVERS:
1036 __add_prop(&resdl, Qdriver, Qunknown);
1046 mss = media_stream_first(ms);
1048 media_substream_props(mss, &resdl);
1049 mss = media_substream_next(mss);
1055 /* convenience functions */
1056 DEFUN("media-stream-aspect", Fmedia_stream_aspect, 1, 3, 0, /*
1057 Return a list of aspect ratios in media stream STREAM.
1059 Optional argument SUBSTREAM names the index of a specific (video)
1060 substream, i.e. only video streams are counted, i.e. the substream 0
1061 names the first video track inside STREAM.
1062 The return value in that case is just a float or quotient, depending
1063 on the optional argument QUOTIENTP.
1065 Optional argument QUOTIENTP indicates that aspect ratios are to be
1066 returned as bigq quotients instead of floats (the default).
1068 By default, the aspect ratios of all the video tracks appear in the list,
1069 the first element in the list belongs to the first video track,
1070 the second element to the second one and so on.
1072 (stream, substream, quotientp))
1074 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1075 Lisp_Object res = Qnil;
1076 long int idx = INTP(substream) ? XINT(substream) : -1;
1078 for (media_substream *mss = media_stream_first(ms); mss;
1079 (mss = media_substream_next(mss))) {
1080 mtype_video_properties *mtvp;
1081 long int num = 0, den = 0;
1084 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1088 /* oh, it's a video stream, check if it's the one we wanted */
1089 if (UNLIKELY(idx-- > 0)) {
1093 mtvp = media_substream_type_properties(mss).vprops;
1094 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
1095 num = mtvp->aspect_num;
1096 den = mtvp->aspect_den;
1097 } else if (mtvp->width && mtvp->height) {
1098 /* good enough? just an approximation as
1099 * the aspect ratio may very well differ
1100 * from the width-by-height ratio */
1105 if (LIKELY(NILP(quotientp))) {
1106 tmp = make_float((fpfloat)num / (fpfloat)den);
1108 #if defined HAVE_MPQ && defined WITH_GMP
1110 tmp = make_bigq(num, den);
1114 dead_wrong_type_argument(Qfeaturep,quotientp);
1117 if (UNLIKELY(INTP(substream))) {
1120 /* the very very default case */
1121 res = Fcons(tmp, res);
1127 /* Audio Coercion */
1128 /* SXEmacs works internally with samples in 24bit resolution */
1130 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1133 sxe_msf_U8_up(void *d, void *s, size_t len)
1135 /* convert U8 samples to internal format (S24in32) */
1140 /* len is the number of samples (== #frame * #channels) */
1141 MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1143 for (i = len-1; i >= 0; i--)
1144 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1150 sxe_msf_U8_down(void *d, void *s, size_t len)
1152 /* convert samples from internal format (S24in32) to U8 */
1157 /* len is the number of samples (== #frame * #channels) */
1158 MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1160 for (i = 0; i < len; i++)
1161 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1166 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1169 sxe_msf_S16_up(void *d, void *s, size_t len)
1171 /* convert S16 samples to internal format (S24in32) */
1176 /* len is the number of samples (== #frame * #channels) */
1177 MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
1179 for (i = len-1; i >= 0; i--)
1180 dst[i] = (int32_t)(src[i]) << 8;
1181 MEDIA_DEBUG_FMT("d00:%d d01:%d\n", dst[0], dst[1]);
1187 sxe_msf_S16_down(void *d, void *s, size_t len)
1189 /* convert samples from internal format (S24in32) to S16 */
1194 /* len is the number of samples (== #frame * #channels) */
1195 MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1197 for (i = 0; i < len; i++)
1198 dst[i] = (int16_t)(src[i] >> 8);
1203 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1206 sxe_msf_S24_up(void *d, void *s, size_t len)
1208 MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1210 /* S24 _is_ the internal format */
1215 sxe_msf_S24_down(void *d, void *s, size_t len)
1217 MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1219 /* S24 _is_ the internal format */
1223 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1226 sxe_msf_S32_up(void *d, void *s, size_t len)
1228 /* convert S32 samples to internal format (S24in32) */
1233 /* len is the number of samples (== #frame * #channels) */
1234 MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1236 for (i = 0; i < len; i++)
1237 dst[i] = src[i] >> 8;
1243 sxe_msf_S32_down(void *d, void *s, size_t len)
1245 /* convert samples from internal format (S24in32) to S32 */
1250 /* len is the number of samples (== #frame * #channels) */
1251 MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1253 for (i = 0; i < len; i++)
1254 dst[i] = src[i] << 8;
1259 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1262 sxe_msf_FLT_up(void *d, void *s, size_t len)
1264 /* convert float samples to internal format (S24in32) */
1269 /* len is the number of samples (== #frame * #channels) */
1270 MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1272 for (i = 0; i < len; i++) {
1273 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1275 MEDIA_DEBUG_FMT("s00:%f d00:%d s01:%f d01:%d\n",
1276 src[0], dst[0], src[1], dst[1]);
1282 sxe_msf_FLT_down(void *d, void *s, size_t len)
1284 /* convert samples from internal format (S24in32) to float */
1289 /* len is the number of samples (== #frame * #channels) */
1290 MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1292 for (i = len-1; i >= 0; i--) {
1293 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1295 MEDIA_DEBUG_FMT("d00:%f d01:%f\n", dst[0], dst[1]);
1301 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1304 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1305 size_t len, void *ignored)
1307 /* mono to stereo converter */
1310 MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1312 /* len is the number of samples */
1313 for (i = len-1; i >= 0; i--) {
1315 dst[2*i+1] = src[i];
1321 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1324 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1325 size_t len, void *args)
1327 /* stereo to mono converter */
1329 sxe_mse_2ch_to_1ch_args *_args = args;
1332 MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1338 /* len is the number of samples */
1339 for (i = 0; i < len/2; i++) {
1340 dst[i] = src[2*i+c];
1346 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1349 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1350 size_t len, void *args)
1352 /* 5 channel to stereo converter */
1354 sxe_mse_5ch_to_2ch_args *_args = args;
1357 MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
1364 /* len is the number of samples */
1365 for (i = 0; i < len/5; i++) {
1366 dst[2*i] = src[5*i+c1];
1367 dst[2*i+1] = src[5*i+c2];
1373 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1376 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1377 size_t len, void *args)
1379 /* stereo to mono converter */
1381 sxe_mse_volume_args *_args = args;
1383 MEDIA_DEBUG_COE("volume: %u samples\n", len);
1385 /* len is the number of samples */
1386 for (i = 0; i < len; i+=_args->num_channels) {
1387 for (j = 0; j < (size_t)_args->num_channels; j++) {
1388 uint8_t vol = _args->volume[j];
1389 dst[i+j] = (src[i+j] * vol) >> 7;
1396 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1399 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1400 size_t len, void *args)
1402 /* rate converter */
1404 sxe_mse_rerate_args *_args = args;
1405 float trafo = (float)_args->srcrate / (float)_args->tgtrate
1407 int chans = _args->num_channels;
1408 int bound = len/chans/trafo;
1410 MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
1414 for (i = bound-1; i >= 0; i--) {
1415 int frame = i * trafo;
1416 dst[chans*i] = (src[chans*frame]);
1417 dst[chans*i+1] = (src[chans*frame+1]);
1419 } else if (trafo > 1.0) {
1420 for (i = 0; i < bound-1; i++) {
1421 int frame = i * trafo;
1422 dst[chans*i] = (src[chans*frame]);
1423 dst[chans*i+1] = (src[chans*frame+1]);
1427 return bound * chans;
1431 void syms_of_media(void)
1433 INIT_LRECORD_IMPLEMENTATION(media_stream);
1435 defsymbol(&Qmedia_streamp, "media-stream-p");
1440 DEFSYMBOL(Qnchannels);
1441 DEFSYMBOL(Qsamplerate);
1442 DEFSYMBOL(Qbitrate);
1443 DEFSYMBOL(Qabitrate);
1444 DEFSYMBOL(Qvbitrate);
1456 DEFSUBR(Fmake_media_stream);
1457 DEFSUBR(Fmedia_stream_p);
1459 DEFSUBR(Faudio_substream_p);
1460 DEFSUBR(Fvideo_substream_p);
1463 DEFSUBR(Fmedia_available_formats);
1464 DEFSUBR(Fmedia_properties);
1465 DEFSUBR(Fmedia_stream_aspect);
1468 defsymbol(&Qffmpeg, "ffmpeg");
1471 defsymbol(&Qmad, "mad");
1474 defsymbol(&Qsox, "sox");
1477 defsymbol(&Qsndfile, "sndfile");
1479 defsymbol(&Qunknown, "unknown");
1480 defsymbol(&Qunavailable, "unavailable");
1483 void vars_of_media(void)
1485 Fprovide(intern("media"));
1488 Fprovide(intern("media-ffmpeg"));
1491 Fprovide(intern("media-sndfile"));
1494 Fprovide(intern("media-mad"));
1497 Fprovide(intern("media-sox"));
1500 Fprovide(intern("media-xine"));
1502 #ifdef HAVE_GSTREAMER
1503 Fprovide(intern("media-gstreamer"));
1505 #ifdef HAVE_INTERNAL_MEDIA
1506 Fprovide(intern("media-internal"));
1510 /* media.c ends here */