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 /* 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;
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);
65 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver preferred)
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);
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);
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);
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);
103 /* not working stuff here :) */
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);
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);
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);
131 if (media_stream_driver(ms) == MDRIVER_UNKNOWN) {
132 MEDIA_DEBUG("giving up\n");
133 media_stream_set_meths(ms, NULL);
139 /*****************************************************************/
141 /*****************************************************************/
142 static Lisp_Object media_stream_mark(Lisp_Object obj)
144 switch (XMEDIA_STREAM_KIND(obj)) {
146 mark_object(XMEDIA_STREAM(obj)->
147 kind_properties.fprops->filename);
153 case NUMBER_OF_MEDIA_KINDS:
158 if (XMEDIA_STREAM_METHS(obj) &&
159 XMEDIA_STREAM_METH(obj, mark))
160 XMEDIA_STREAM_METH(obj, mark)(XMEDIA_STREAM_DATA(obj));
166 media_stream_finalise(void *header, int for_disksave)
168 Lisp_Media_Stream *ms = (Lisp_Media_Stream*)header;
169 media_substream *mss = NULL;
171 if (media_stream_meths(ms) &&
172 media_stream_meth(ms, close))
173 media_stream_meth(ms, close)(media_stream_data(ms));
175 mss = media_stream_first(ms);
177 media_substream_finalise(mss, for_disksave);
178 mss = media_substream_next(mss);
182 switch (media_stream_driver(ms)) {
185 if (media_stream_data(ms))
186 media_xine_close_context(media_stream_data(ms));
189 case MDRIVER_SNDFILE:
191 if (media_stream_data(ms))
192 sf_close(media_stream_data(ms));
197 if (media_stream_data(ms))
198 mad_decoder_finish(media_stream_data(ms));
203 if (media_stream_data(ms))
204 st_close(media_stream_data(ms));
212 switch (media_stream_kind(ms)) {
214 mkind_file_properties *mkfp;
215 mkfp = media_stream_kind_properties(ms).fprops;
222 mkind_string_properties *mksp;
223 mksp = media_stream_kind_properties(ms).sprops;
228 if (mksp->stream_data)
229 xfree(mksp->stream_data);
238 case NUMBER_OF_MEDIA_KINDS:
243 /* avoid some warning */
244 if (for_disksave || ms == NULL);
248 media_stream_print(Lisp_Object obj, Lisp_Object printcharfun, int ef)
250 Lisp_Media_Stream *ms = XMEDIA_STREAM(obj);
251 media_substream *mss;
253 write_c_string("#<media-stream", printcharfun);
255 write_c_string(" :kind ", printcharfun);
257 switch (media_stream_kind(ms)) {
260 media_stream_kind_properties(ms).fprops->filename;
262 write_c_string("#<file ", printcharfun);
263 print_internal(file, printcharfun, ef);
264 write_c_string(">", printcharfun);
268 write_c_string("#<string>", printcharfun);
271 write_c_string("#<fifo>", printcharfun);
274 write_c_string("#<stream>", printcharfun);
279 case NUMBER_OF_MEDIA_KINDS:
280 write_c_string("#<unknown>", printcharfun);
284 mss = media_stream_first(ms);
286 write_c_string(" ", printcharfun);
287 media_substream_print(mss, printcharfun, ef);
288 mss = media_substream_next(mss);
291 write_c_string(" driven by ", printcharfun);
292 switch (media_stream_driver(ms)) {
293 case MDRIVER_INTERNAL:
294 write_c_string("internal", printcharfun);
297 write_c_string("ffmpeg", printcharfun);
299 case MDRIVER_SNDFILE:
300 write_c_string("sndfile", printcharfun);
303 write_c_string("mad", printcharfun);
306 write_c_string("sox", printcharfun);
309 write_c_string("xine", printcharfun);
311 case MDRIVER_GSTREAMER:
312 write_c_string("gstreamer", printcharfun);
314 case MDRIVER_UNKNOWN:
315 case NUMBER_OF_MEDIA_DRIVERS:
317 XMEDIA_STREAM_SET_METHS(obj, NULL);
318 write_c_string("unknown", printcharfun);
322 if (XMEDIA_STREAM_METHS(obj) &&
323 XMEDIA_STREAM_METH(obj, print)) {
324 XMEDIA_STREAM_METH(obj, print)(obj, printcharfun, ef);
327 write_c_string(">", printcharfun);
331 media_stream_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
333 if (XMEDIA_STREAM_DATA(obj1) == XMEDIA_STREAM_DATA(obj2))
343 media_stream_hash (Lisp_Object obj, int depth)
345 return (unsigned long)obj;
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) },
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,
369 /*****************************************************************/
370 /* media substreams */
371 /*****************************************************************/
374 media_substream_finalise(void *header, int for_disksave)
376 media_substream *mss = (media_substream*)header;
378 switch (media_substream_type(mss)) {
380 if (media_substream_type_properties(mss).aprops)
381 xfree(media_substream_type_properties(mss).aprops);
384 if (media_substream_type_properties(mss).vprops)
385 xfree(media_substream_type_properties(mss).vprops);
389 case NUMBER_OF_MEDIA_TYPES:
395 pthread_mutex_destroy(&mss->substream_mutex);
398 media_substream_data(mss) = NULL;
400 /* avoid some warning */
405 media_substream_print_audio(media_substream *mss, Lisp_Object printcharfun)
407 mtype_audio_properties *mtap =
408 media_substream_type_properties(mss).aprops;
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);
416 write_fmt_str(printcharfun, "%s [???]", mtap->name);
417 else if (mtap->codec_name)
418 write_fmt_str(printcharfun, "??? (%s)", mtap->codec_name);
420 write_c_string("???", printcharfun);
422 switch (mtap->channels) {
424 write_c_string(", mono", printcharfun);
427 write_c_string(", stereo", printcharfun);
430 write_c_string(", chn:5", printcharfun);
433 write_c_string(", 5.1", printcharfun);
436 write_c_string(", chn:???", printcharfun);
440 if (mtap->samplerate)
441 write_fmt_str(printcharfun, ", %d Hz, %d Bit",
446 write_fmt_str(printcharfun, ", %d kb/s", mtap->bitrate/1000);
448 write_c_string(">", printcharfun);
452 media_substream_print_video(media_substream *mss, Lisp_Object printcharfun)
454 mtype_video_properties *mtvp =
455 media_substream_type_properties(mss).vprops;
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);
463 write_fmt_str(printcharfun, "%s [???]", mtvp->name);
464 else if (mtvp->codec_name)
465 write_fmt_str(printcharfun, "??? (%s)", mtvp->codec_name);
467 write_c_string("???", printcharfun);
470 write_fmt_str(printcharfun, ", %d kb/s", mtvp->bitrate);
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);
478 write_fmt_str(printcharfun, ", %dx%d (%.2f/1)",
479 mtvp->width, mtvp->height,
480 (double)mtvp->width/(double)mtvp->height);
482 write_c_string(">", printcharfun);
486 media_substream_print(media_substream *mss,
487 Lisp_Object printcharfun, int escapeflag)
489 write_c_string("#<media-substream :type ", printcharfun);
491 switch (media_substream_type(mss)) {
493 media_substream_print_audio(mss, printcharfun);
497 media_substream_print_video(mss, printcharfun);
500 write_c_string("#<image>", printcharfun);
504 case NUMBER_OF_MEDIA_TYPES:
505 write_c_string("#<unknown>", printcharfun);
509 write_c_string(">", printcharfun);
512 static Lisp_Media_Stream *
513 media_stream_allocate(void)
515 Lisp_Media_Stream *ms;
517 ms = alloc_lcrecord_type(Lisp_Media_Stream, &lrecord_media_stream);
522 Lisp_Object make_media_stream()
524 Lisp_Media_Stream *ms;
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;
532 /* now set the navigation */
533 media_stream_first(ms) = NULL;
534 media_stream_last(ms) = NULL;
536 XSETMEDIA_STREAM(lms, ms);
541 media_substream *make_media_substream(void)
543 /* this allocates and conses to the back of ms */
544 media_substream *mss;
546 mss = xnew_and_zero(media_substream);
547 media_substream_type(mss) = MTYPE_UNKNOWN;
548 media_substream_data(mss) = NULL;
551 media_substream_next(mss) = NULL;
552 media_substream_prev(mss) = NULL;
555 pthread_mutex_init(&mss->substream_mutex, NULL);
561 media_substream *make_media_substream_append(Lisp_Media_Stream *ms)
563 media_substream *mss;
565 mss = make_media_substream();
568 media_substream_next(mss) = NULL;
569 if (!(media_stream_last(ms))) {
570 media_substream_prev(mss) = NULL;
571 media_stream_first(ms) = mss;
573 media_substream_prev(mss) = media_stream_last(ms);
574 media_substream_next(media_stream_last(ms)) = mss;
577 media_stream_last(ms) = mss;
578 media_substream_up(mss) = ms;
583 media_substream *make_media_substream_prepend(Lisp_Media_Stream *ms)
585 media_substream *mss;
587 mss = make_media_substream();
590 media_substream_prev(mss) = NULL;
591 if (!(media_stream_first(ms))) {
592 media_substream_next(mss) = NULL;
593 media_stream_last(ms) = mss;
595 media_substream_next(mss) = media_stream_first(ms);
596 media_substream_prev(media_stream_first(ms)) = mss;
599 media_stream_first(ms) = mss;
600 media_substream_up(mss) = ms;
605 DEFUN("make-media-stream", Fmake_media_stream, 2, 3, 0, /*
606 Create a new media stream from DATA.
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
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'.
618 (from, data, driver))
621 Lisp_Media_Stream *ms;
626 DATA_IS_DATA } datatype = DATA_IS_BULLSHIT;
627 media_driver pref = MDRIVER_UNKNOWN;
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;
637 datatype = DATA_IS_BULLSHIT;
638 return Qnil; /* in this case, why bother? stupid user :) */
642 pref = MDRIVER_UNKNOWN;
644 else if (EQ(driver, Qmad))
648 else if (EQ(driver, Qffmpeg))
649 pref = MDRIVER_FFMPEG;
652 else if (EQ(driver, Qsox))
655 else if (EQ(driver, intern("xine")))
658 else if (EQ(driver, Qsndfile))
659 pref = MDRIVER_SNDFILE;
661 else if (EQ(driver, intern("internal")))
662 pref = MDRIVER_INTERNAL;
663 else if (EQ(driver, intern("gstreamer")))
664 pref = MDRIVER_GSTREAMER;
666 pref = MDRIVER_UNKNOWN;
668 /* hm, maybe data could be a symbol from the sound-alist?
669 * or a buffer or a network socket?
673 lms = make_media_stream();
674 ms = XMEDIA_STREAM(lms);
678 mkind_file_properties *fprops;
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)))
686 media_stream_kind(ms) = MKIND_FILE;
688 /* initialise a new file properties structure */
689 fprops = xnew_and_zero(mkind_file_properties);
691 /* copy the filename also as C string */
692 fprops->filename = data;
694 /* assign the file properties */
695 media_stream_kind_properties(ms).fprops = fprops;
697 determine_stream_type(ms, pref);
701 mkind_string_properties *sprops;
705 media_stream_kind(ms) = MKIND_STRING;
707 /* initialise a new file properties structure */
708 sprops = xnew_and_zero(mkind_string_properties);
710 /* copy the filename also as C string */
711 TO_EXTERNAL_FORMAT(LISP_STRING, data,
712 MALLOC, (data_ext, data_len),
714 data_ext[data_len] = '\0';
716 sprops->stream_data = data_ext;
717 sprops->size = data_len;
719 /* assign the file properties */
720 media_stream_kind_properties(ms).sprops = sprops;
722 determine_stream_type(ms, pref);
728 case DATA_IS_BULLSHIT:
736 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
742 while (!NILP(from)) {
743 result = Fcons(XCAR(from), result);
749 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
750 Return non-nil if object is a media-stream.
754 if (MEDIA_STREAMP(object))
761 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
762 Return non-nil if object is a media-substream with audio data.
766 if (MEDIA_SUBSTREAMP(object) &&
767 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
773 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
774 Return non-nil if object is a media-substream with video data.
778 if (MEDIA_SUBSTREAMP(object) &&
779 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
786 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
787 Return a list of input formats in the underlying media libraries.
798 temp = media_ffmpeg_available_formats();
800 formats = recons(formats, temp);
805 formats = recons(formats, temp);
810 static inline void __attribute__((always_inline))
811 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
813 *reslist = Fcons(Fcons(key, val), *reslist);
818 media_substream_props(media_substream *mss, Lisp_Object *reslist)
820 switch (media_substream_type(mss)) {
822 mtype_audio_properties *mtap =
823 media_substream_type_properties(mss).aprops;
825 /* add the type property */
826 __add_prop(reslist, Qtype, Qaudio);
829 __add_prop(reslist, Qdemux, build_string(mtap->name));
831 if (mtap->codec_name) {
832 __add_prop(reslist, Qcodec,
833 build_string(mtap->codec_name));
836 if (mtap->channels) {
837 __add_prop(reslist, Qnchannels,
838 make_int(mtap->channels));
841 if (mtap->samplerate) {
842 __add_prop(reslist, Qsamplerate,
843 make_int(mtap->samplerate));
847 __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
854 mtype_video_properties *mtvp =
855 media_substream_type_properties(mss).vprops;
857 /* add the type property */
858 __add_prop(reslist, Qtype, Qvideo);
861 __add_prop(reslist, Qdemux, build_string(mtvp->name));
863 if (mtvp->codec_name) {
864 __add_prop(reslist, Qcodec,
865 build_string(mtvp->codec_name));
869 __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
873 __add_prop(reslist, Qwidth, make_int(mtvp->width));
877 __add_prop(reslist, Qheight, make_int(mtvp->height));
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,
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));
902 __add_prop(reslist, Qtype, Qimage);
907 case NUMBER_OF_MEDIA_TYPES:
912 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
913 Return an alist of available properties of media-stream STREAM.
915 Depending on the underlying stream this alist may be made of
916 several of the following keys, grouped by media contents.
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.)
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
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
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
961 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
962 media_substream *mss;
963 Lisp_Object resdl = Qnil;
965 switch (media_stream_kind(ms)) {
968 media_stream_kind_properties(ms).fprops->filename;
970 __add_prop(&resdl, Qfile, file);
971 __add_prop(&resdl, Qkind, Qfile);
975 __add_prop(&resdl, Qkind, Qfifo);
979 __add_prop(&resdl, Qkind, Quri);
983 __add_prop(&resdl, Qkind, Qstring);
986 case NUMBER_OF_MEDIA_KINDS:
988 __add_prop(&resdl, Qkind, Qunknown);
992 switch (media_stream_driver(ms)) {
993 case MDRIVER_INTERNAL:
994 __add_prop(&resdl, Qdriver, Qinternal);
998 __add_prop(&resdl, Qdriver, Qffmpeg);
1000 streaminfo = media_ffmpeg_streaminfo(ms);
1004 case MDRIVER_SNDFILE:
1006 __add_prop(&resdl, Qdriver, Qsndfile);
1011 __add_prop(&resdl, Qdriver, Qmad);
1016 __add_prop(&resdl, Qdriver, Qsox);
1020 case MDRIVER_UNKNOWN:
1021 case NUMBER_OF_MEDIA_DRIVERS:
1023 __add_prop(&resdl, Qdriver, Qunknown);
1033 mss = media_stream_first(ms);
1035 media_substream_props(mss, &resdl);
1036 mss = media_substream_next(mss);
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.
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.
1052 Optional argument QUOTIENTP indicates that aspect ratios are to be
1053 returned as bigq quotients instead of floats (the default).
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.
1059 (stream, substream, quotientp))
1061 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1062 Lisp_Object res = Qnil;
1063 long int idx = INTP(substream) ? XINT(substream) : -1;
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;
1071 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1075 /* oh, it's a video stream, check if it's the one we wanted */
1076 if (UNLIKELY(idx-- > 0)) {
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 */
1092 if (LIKELY(NILP(quotientp))) {
1093 tmp = make_float((fpfloat)num / (fpfloat)den);
1095 #if defined HAVE_MPQ && defined WITH_GMP
1097 tmp = make_bigq(num, den);
1101 dead_wrong_type_argument(Qfeaturep,quotientp);
1104 if (UNLIKELY(INTP(substream))) {
1107 /* the very very default case */
1108 res = Fcons(tmp, res);
1114 /* Audio Coercion */
1115 /* SXEmacs works internally with samples in 24bit resolution */
1117 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1120 sxe_msf_U8_up(void *d, void *s, size_t len)
1122 /* convert U8 samples to internal format (S24in32) */
1127 /* len is the number of samples (== #frame * #channels) */
1128 MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1130 for (i = len-1; i >= 0; i--)
1131 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1137 sxe_msf_U8_down(void *d, void *s, size_t len)
1139 /* convert samples from internal format (S24in32) to U8 */
1144 /* len is the number of samples (== #frame * #channels) */
1145 MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1147 for (i = 0; i < len; i++)
1148 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1153 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1156 sxe_msf_S16_up(void *d, void *s, size_t len)
1158 /* convert S16 samples to internal format (S24in32) */
1163 /* len is the number of samples (== #frame * #channels) */
1164 MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
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]);
1174 sxe_msf_S16_down(void *d, void *s, size_t len)
1176 /* convert samples from internal format (S24in32) to S16 */
1181 /* len is the number of samples (== #frame * #channels) */
1182 MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1184 for (i = 0; i < len; i++)
1185 dst[i] = (int16_t)(src[i] >> 8);
1190 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1193 sxe_msf_S24_up(void *d, void *s, size_t len)
1195 MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1197 /* S24 _is_ the internal format */
1202 sxe_msf_S24_down(void *d, void *s, size_t len)
1204 MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1206 /* S24 _is_ the internal format */
1210 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1213 sxe_msf_S32_up(void *d, void *s, size_t len)
1215 /* convert S32 samples to internal format (S24in32) */
1220 /* len is the number of samples (== #frame * #channels) */
1221 MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1223 for (i = 0; i < len; i++)
1224 dst[i] = src[i] >> 8;
1230 sxe_msf_S32_down(void *d, void *s, size_t len)
1232 /* convert samples from internal format (S24in32) to S32 */
1237 /* len is the number of samples (== #frame * #channels) */
1238 MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1240 for (i = 0; i < len; i++)
1241 dst[i] = src[i] << 8;
1246 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1249 sxe_msf_FLT_up(void *d, void *s, size_t len)
1251 /* convert float samples to internal format (S24in32) */
1256 /* len is the number of samples (== #frame * #channels) */
1257 MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1259 for (i = 0; i < len; i++) {
1260 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1262 MEDIA_DEBUG_FMT("s00:%f d00:%d s01:%f d01:%d\n",
1263 src[0], dst[0], src[1], dst[1]);
1269 sxe_msf_FLT_down(void *d, void *s, size_t len)
1271 /* convert samples from internal format (S24in32) to float */
1276 /* len is the number of samples (== #frame * #channels) */
1277 MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1279 for (i = len-1; i >= 0; i--) {
1280 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1282 MEDIA_DEBUG_FMT("d00:%f d01:%f\n", dst[0], dst[1]);
1288 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1291 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1292 size_t len, void *ignored)
1294 /* mono to stereo converter */
1297 MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1299 /* len is the number of samples */
1300 for (i = len-1; i >= 0; i--) {
1302 dst[2*i+1] = src[i];
1308 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1311 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1312 size_t len, void *args)
1314 /* stereo to mono converter */
1316 sxe_mse_2ch_to_1ch_args *_args = args;
1319 MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1325 /* len is the number of samples */
1326 for (i = 0; i < len/2; i++) {
1327 dst[i] = src[2*i+c];
1333 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1336 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1337 size_t len, void *args)
1339 /* 5 channel to stereo converter */
1341 sxe_mse_5ch_to_2ch_args *_args = args;
1344 MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
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];
1360 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1363 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1364 size_t len, void *args)
1366 /* stereo to mono converter */
1368 sxe_mse_volume_args *_args = args;
1370 MEDIA_DEBUG_COE("volume: %u samples\n", len);
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;
1383 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1386 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1387 size_t len, void *args)
1389 /* rate converter */
1391 sxe_mse_rerate_args *_args = args;
1392 float trafo = (float)_args->srcrate / (float)_args->tgtrate
1394 int chans = _args->num_channels;
1395 int bound = len/chans/trafo;
1397 MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
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]);
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]);
1414 return bound * chans;
1418 void syms_of_media(void)
1420 INIT_LRECORD_IMPLEMENTATION(media_stream);
1422 defsymbol(&Qmedia_streamp, "media-stream-p");
1427 DEFSYMBOL(Qnchannels);
1428 DEFSYMBOL(Qsamplerate);
1429 DEFSYMBOL(Qbitrate);
1430 DEFSYMBOL(Qabitrate);
1431 DEFSYMBOL(Qvbitrate);
1443 DEFSUBR(Fmake_media_stream);
1444 DEFSUBR(Fmedia_stream_p);
1446 DEFSUBR(Faudio_substream_p);
1447 DEFSUBR(Fvideo_substream_p);
1450 DEFSUBR(Fmedia_available_formats);
1451 DEFSUBR(Fmedia_properties);
1452 DEFSUBR(Fmedia_stream_aspect);
1455 defsymbol(&Qffmpeg, "ffmpeg");
1458 defsymbol(&Qmad, "mad");
1461 defsymbol(&Qsox, "sox");
1464 defsymbol(&Qsndfile, "sndfile");
1466 defsymbol(&Qunknown, "unknown");
1469 void vars_of_media(void)
1471 Fprovide(intern("media"));
1474 Fprovide(intern("media-ffmpeg"));
1477 Fprovide(intern("media-sndfile"));
1480 Fprovide(intern("media-mad"));
1483 Fprovide(intern("media-sox"));
1486 Fprovide(intern("media-xine"));
1488 #ifdef HAVE_GSTREAMER
1489 Fprovide(intern("media-gstreamer"));
1491 #ifdef HAVE_INTERNAL_MEDIA
1492 Fprovide(intern("media-internal"));
1496 /* media.c ends here */