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;
708 media_stream_kind(ms) = MKIND_STRING;
710 /* initialise a new file properties structure */
711 sprops = xnew_and_zero(mkind_string_properties);
713 /* copy the filename also as C string */
714 TO_EXTERNAL_FORMAT(LISP_STRING, data,
715 MALLOC, (data_ext, data_len),
717 data_ext[data_len] = '\0';
719 sprops->stream_data = data_ext;
720 sprops->size = data_len;
722 /* assign the file properties */
723 media_stream_kind_properties(ms).sprops = sprops;
725 determine_stream_type(ms, pref);
731 case DATA_IS_BULLSHIT:
739 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
745 while (!NILP(from)) {
746 result = Fcons(XCAR(from), result);
752 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
753 Return non-nil if object is a media-stream.
757 if (MEDIA_STREAMP(object))
764 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
765 Return non-nil if object is a media-substream with audio data.
769 if (MEDIA_SUBSTREAMP(object) &&
770 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
776 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
777 Return non-nil if object is a media-substream with video data.
781 if (MEDIA_SUBSTREAMP(object) &&
782 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
789 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
790 Return a list of input formats in the underlying media libraries.
801 temp = media_ffmpeg_available_formats();
803 formats = recons(formats, temp);
808 formats = recons(formats, temp);
813 static inline void __attribute__((always_inline))
814 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
816 *reslist = Fcons(Fcons(key, val), *reslist);
821 media_substream_props(media_substream *mss, Lisp_Object *reslist)
823 switch (media_substream_type(mss)) {
825 mtype_audio_properties *mtap =
826 media_substream_type_properties(mss).aprops;
828 /* add the type property */
829 __add_prop(reslist, Qtype, Qaudio);
832 __add_prop(reslist, Qdemux, build_string(mtap->name));
834 if (mtap->codec_name) {
835 __add_prop(reslist, Qcodec,
836 build_string(mtap->codec_name));
839 if (mtap->channels) {
840 __add_prop(reslist, Qnchannels,
841 make_int(mtap->channels));
844 if (mtap->samplerate) {
845 __add_prop(reslist, Qsamplerate,
846 make_int(mtap->samplerate));
850 __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
857 mtype_video_properties *mtvp =
858 media_substream_type_properties(mss).vprops;
860 /* add the type property */
861 __add_prop(reslist, Qtype, Qvideo);
864 __add_prop(reslist, Qdemux, build_string(mtvp->name));
866 if (mtvp->codec_name) {
867 __add_prop(reslist, Qcodec,
868 build_string(mtvp->codec_name));
872 __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
876 __add_prop(reslist, Qwidth, make_int(mtvp->width));
880 __add_prop(reslist, Qheight, make_int(mtvp->height));
883 #if defined HAVE_MPQ && defined WITH_GMP && 0
884 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
885 __add_prop(reslist, Qaspect,
886 make_bigq(mtvp->aspect_num,
889 #elif defined HAVE_FPFLOAT
890 /* use float arithmetic */
891 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
892 __add_prop(reslist, Qaspect,
893 make_float((fpfloat)mtvp->aspect_num /
894 (fpfloat)mtvp->aspect_den));
895 } else if (mtvp->width && mtvp->height) {
896 __add_prop(reslist, Qaspect,
897 make_float((fpfloat)mtvp->width /
898 (fpfloat)mtvp->height));
905 __add_prop(reslist, Qtype, Qimage);
910 case NUMBER_OF_MEDIA_TYPES:
915 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
916 Return an alist of available properties of media-stream STREAM.
918 Depending on the underlying stream this alist may be made of
919 several of the following keys, grouped by media contents.
923 'file (string) the stream's filename
924 'uri (string) the stream's URI
925 'fifo (string) the stream's FIFO socket
926 'driver (symbol) the stream's demuxer/decoder driver
927 'kind (symbol) the stream's kind (file, fifo, string, uri, etc.)
928 'type (symbol) the stream's type (audio, video, image, subtitle, lyrics, etc.)
932 'codec (string) the suitable audio codec
933 'demux (string) the suitable demuxer
934 'title (string) the title of an audio track
935 'artist (string) the performing artist(s)
936 'album (string) the title of the album
937 'comment (string) an arbitrary comment
938 'genre (string) the genre identifier string
939 'year (integer) the year of release
940 'track (integer) the track number on the album
941 'length (integer) the length of the track in seconds
942 'abitrate (integer) the average bitrate of the track in kb/s
943 'samplerate (integer) the samplerate of the track in Hz
944 'nchannels (integer) the number of distinguished channels
948 'codec (string) the suitable audio codec
949 'demux (string) the suitable demuxer
950 'title (string) the title of a video track
951 'comment (string) an arbitrary comment
952 'year (integer) the year of release
953 'vbitrate (integer) the average bitrate of the track in kb/s
954 'width (integer) the x-resolution in pixels
955 'height (integer) the y-resolution in pixels
956 'aspect (bigq) the aspect quotient
958 Keys which do not apply to the underlying stream or are not
959 defined in the tag section of the stream are simply left out
964 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
965 media_substream *mss;
966 Lisp_Object resdl = Qnil;
968 switch (media_stream_kind(ms)) {
971 media_stream_kind_properties(ms).fprops->filename;
973 __add_prop(&resdl, Qfile, file);
974 __add_prop(&resdl, Qkind, Qfile);
978 __add_prop(&resdl, Qkind, Qfifo);
982 __add_prop(&resdl, Qkind, Quri);
986 __add_prop(&resdl, Qkind, Qstring);
989 case NUMBER_OF_MEDIA_KINDS:
991 __add_prop(&resdl, Qkind, Qunknown);
995 __add_prop(&resdl, Qdriver, Qunavailable);
996 switch (media_stream_driver(ms)) {
997 case MDRIVER_INTERNAL:
998 __add_prop(&resdl, Qdriver, Qinternal);
1000 case MDRIVER_FFMPEG:
1002 __add_prop(&resdl, Qdriver, Qffmpeg);
1004 streaminfo = media_ffmpeg_streaminfo(ms);
1008 case MDRIVER_SNDFILE:
1010 __add_prop(&resdl, Qdriver, Qsndfile);
1015 __add_prop(&resdl, Qdriver, Qmad);
1020 __add_prop(&resdl, Qdriver, Qsox);
1027 case MDRIVER_GSTREAMER:
1030 case MDRIVER_UNKNOWN:
1031 case NUMBER_OF_MEDIA_DRIVERS:
1033 __add_prop(&resdl, Qdriver, Qunknown);
1043 mss = media_stream_first(ms);
1045 media_substream_props(mss, &resdl);
1046 mss = media_substream_next(mss);
1052 /* convenience functions */
1053 DEFUN("media-stream-aspect", Fmedia_stream_aspect, 1, 3, 0, /*
1054 Return a list of aspect ratios in media stream STREAM.
1056 Optional argument SUBSTREAM names the index of a specific (video)
1057 substream, i.e. only video streams are counted, i.e. the substream 0
1058 names the first video track inside STREAM.
1059 The return value in that case is just a float or quotient, depending
1060 on the optional argument QUOTIENTP.
1062 Optional argument QUOTIENTP indicates that aspect ratios are to be
1063 returned as bigq quotients instead of floats (the default).
1065 By default, the aspect ratios of all the video tracks appear in the list,
1066 the first element in the list belongs to the first video track,
1067 the second element to the second one and so on.
1069 (stream, substream, quotientp))
1071 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1072 Lisp_Object res = Qnil;
1073 long int idx = INTP(substream) ? XINT(substream) : -1;
1075 for (media_substream *mss = media_stream_first(ms); mss;
1076 (mss = media_substream_next(mss))) {
1077 mtype_video_properties *mtvp;
1078 long int num = 0, den = 0;
1081 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1085 /* oh, it's a video stream, check if it's the one we wanted */
1086 if (UNLIKELY(idx-- > 0)) {
1090 mtvp = media_substream_type_properties(mss).vprops;
1091 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
1092 num = mtvp->aspect_num;
1093 den = mtvp->aspect_den;
1094 } else if (mtvp->width && mtvp->height) {
1095 /* good enough? just an approximation as
1096 * the aspect ratio may very well differ
1097 * from the width-by-height ratio */
1102 if (LIKELY(NILP(quotientp))) {
1103 tmp = make_float((fpfloat)num / (fpfloat)den);
1105 #if defined HAVE_MPQ && defined WITH_GMP
1107 tmp = make_bigq(num, den);
1111 dead_wrong_type_argument(Qfeaturep,quotientp);
1114 if (UNLIKELY(INTP(substream))) {
1117 /* the very very default case */
1118 res = Fcons(tmp, res);
1124 /* Audio Coercion */
1125 /* SXEmacs works internally with samples in 24bit resolution */
1127 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1130 sxe_msf_U8_up(void *d, void *s, size_t len)
1132 /* convert U8 samples to internal format (S24in32) */
1137 /* len is the number of samples (== #frame * #channels) */
1138 MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1140 for (i = len-1; i >= 0; i--)
1141 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1147 sxe_msf_U8_down(void *d, void *s, size_t len)
1149 /* convert samples from internal format (S24in32) to U8 */
1154 /* len is the number of samples (== #frame * #channels) */
1155 MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1157 for (i = 0; i < len; i++)
1158 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1163 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1166 sxe_msf_S16_up(void *d, void *s, size_t len)
1168 /* convert S16 samples to internal format (S24in32) */
1173 /* len is the number of samples (== #frame * #channels) */
1174 MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
1176 for (i = len-1; i >= 0; i--)
1177 dst[i] = (int32_t)(src[i]) << 8;
1178 MEDIA_DEBUG_FMT("d00:%d d01:%d\n", dst[0], dst[1]);
1184 sxe_msf_S16_down(void *d, void *s, size_t len)
1186 /* convert samples from internal format (S24in32) to S16 */
1191 /* len is the number of samples (== #frame * #channels) */
1192 MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1194 for (i = 0; i < len; i++)
1195 dst[i] = (int16_t)(src[i] >> 8);
1200 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1203 sxe_msf_S24_up(void *d, void *s, size_t len)
1205 MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1207 /* S24 _is_ the internal format */
1212 sxe_msf_S24_down(void *d, void *s, size_t len)
1214 MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1216 /* S24 _is_ the internal format */
1220 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1223 sxe_msf_S32_up(void *d, void *s, size_t len)
1225 /* convert S32 samples to internal format (S24in32) */
1230 /* len is the number of samples (== #frame * #channels) */
1231 MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1233 for (i = 0; i < len; i++)
1234 dst[i] = src[i] >> 8;
1240 sxe_msf_S32_down(void *d, void *s, size_t len)
1242 /* convert samples from internal format (S24in32) to S32 */
1247 /* len is the number of samples (== #frame * #channels) */
1248 MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1250 for (i = 0; i < len; i++)
1251 dst[i] = src[i] << 8;
1256 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1259 sxe_msf_FLT_up(void *d, void *s, size_t len)
1261 /* convert float samples to internal format (S24in32) */
1266 /* len is the number of samples (== #frame * #channels) */
1267 MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1269 for (i = 0; i < len; i++) {
1270 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1272 MEDIA_DEBUG_FMT("s00:%f d00:%d s01:%f d01:%d\n",
1273 src[0], dst[0], src[1], dst[1]);
1279 sxe_msf_FLT_down(void *d, void *s, size_t len)
1281 /* convert samples from internal format (S24in32) to float */
1286 /* len is the number of samples (== #frame * #channels) */
1287 MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1289 for (i = len-1; i >= 0; i--) {
1290 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1292 MEDIA_DEBUG_FMT("d00:%f d01:%f\n", dst[0], dst[1]);
1298 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1301 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1302 size_t len, void *ignored)
1304 /* mono to stereo converter */
1307 MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1309 /* len is the number of samples */
1310 for (i = len-1; i >= 0; i--) {
1312 dst[2*i+1] = src[i];
1318 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1321 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1322 size_t len, void *args)
1324 /* stereo to mono converter */
1326 sxe_mse_2ch_to_1ch_args *_args = args;
1329 MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1335 /* len is the number of samples */
1336 for (i = 0; i < len/2; i++) {
1337 dst[i] = src[2*i+c];
1343 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1346 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1347 size_t len, void *args)
1349 /* 5 channel to stereo converter */
1351 sxe_mse_5ch_to_2ch_args *_args = args;
1354 MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
1361 /* len is the number of samples */
1362 for (i = 0; i < len/5; i++) {
1363 dst[2*i] = src[5*i+c1];
1364 dst[2*i+1] = src[5*i+c2];
1370 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1373 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1374 size_t len, void *args)
1376 /* stereo to mono converter */
1378 sxe_mse_volume_args *_args = args;
1380 MEDIA_DEBUG_COE("volume: %u samples\n", len);
1382 /* len is the number of samples */
1383 for (i = 0; i < len; i+=_args->num_channels) {
1384 for (j = 0; j < (size_t)_args->num_channels; j++) {
1385 uint8_t vol = _args->volume[j];
1386 dst[i+j] = (src[i+j] * vol) >> 7;
1393 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1396 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1397 size_t len, void *args)
1399 /* rate converter */
1401 sxe_mse_rerate_args *_args = args;
1402 float trafo = (float)_args->srcrate / (float)_args->tgtrate
1404 int chans = _args->num_channels;
1405 int bound = len/chans/trafo;
1407 MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
1411 for (i = bound-1; i >= 0; i--) {
1412 int frame = i * trafo;
1413 dst[chans*i] = (src[chans*frame]);
1414 dst[chans*i+1] = (src[chans*frame+1]);
1416 } else if (trafo > 1.0) {
1417 for (i = 0; i < bound-1; i++) {
1418 int frame = i * trafo;
1419 dst[chans*i] = (src[chans*frame]);
1420 dst[chans*i+1] = (src[chans*frame+1]);
1424 return bound * chans;
1428 void syms_of_media(void)
1430 INIT_LRECORD_IMPLEMENTATION(media_stream);
1432 defsymbol(&Qmedia_streamp, "media-stream-p");
1437 DEFSYMBOL(Qnchannels);
1438 DEFSYMBOL(Qsamplerate);
1439 DEFSYMBOL(Qbitrate);
1440 DEFSYMBOL(Qabitrate);
1441 DEFSYMBOL(Qvbitrate);
1453 DEFSUBR(Fmake_media_stream);
1454 DEFSUBR(Fmedia_stream_p);
1456 DEFSUBR(Faudio_substream_p);
1457 DEFSUBR(Fvideo_substream_p);
1460 DEFSUBR(Fmedia_available_formats);
1461 DEFSUBR(Fmedia_properties);
1462 DEFSUBR(Fmedia_stream_aspect);
1465 defsymbol(&Qffmpeg, "ffmpeg");
1468 defsymbol(&Qmad, "mad");
1471 defsymbol(&Qsox, "sox");
1474 defsymbol(&Qsndfile, "sndfile");
1476 defsymbol(&Qunknown, "unknown");
1477 defsymbol(&Qunavailable, "unavailable");
1480 void vars_of_media(void)
1482 Fprovide(intern("media"));
1485 Fprovide(intern("media-ffmpeg"));
1488 Fprovide(intern("media-sndfile"));
1491 Fprovide(intern("media-mad"));
1494 Fprovide(intern("media-sox"));
1497 Fprovide(intern("media-xine"));
1499 #ifdef HAVE_GSTREAMER
1500 Fprovide(intern("media-gstreamer"));
1502 #ifdef HAVE_INTERNAL_MEDIA
1503 Fprovide(intern("media-internal"));
1507 /* media.c ends here */