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. */
31 #include "media-ffmpeg.h"
34 #include "media-sndfile.h"
36 #ifdef HAVE_INTERNAL_MEDIA
37 #include "media-internal.h"
40 #include "media-mad.h"
43 #include "media-gstreamer.h"
46 #include "media-sox.h"
49 #include "media-xine.h"
52 Lisp_Object Qmedia_streamp;
54 Lisp_Object Qunavailable;
55 /* media property syms */
56 Lisp_Object Qdemux, Qcodec, Qnchannels, Qsamplerate;
57 Lisp_Object Qbitrate, Qabitrate, Qvbitrate;
58 Lisp_Object Qwidth, Qheight, Qaspect, Qdriver, Qkind, Qfifo, Quri, Qtype;
59 Lisp_Object Qaudio, Qvideo, Qimage;
61 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver);
62 static void media_stream_print(Lisp_Object, Lisp_Object, int);
63 static void media_substream_print(media_substream *, Lisp_Object, int);
64 static void media_substream_finalise(void*, int);
67 static void determine_stream_type(Lisp_Media_Stream *ms, media_driver preferred)
70 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
71 (preferred == MDRIVER_UNKNOWN ||
72 preferred == MDRIVER_FFMPEG)) {
73 MEDIA_DEBUG("trying ffmpeg.\n");
74 media_stream_set_meths(ms, media_ffmpeg);
75 media_stream_meth(ms, open)(ms);
79 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
80 (preferred == MDRIVER_UNKNOWN ||
81 preferred == MDRIVER_MAD)) {
82 MEDIA_DEBUG("trying mad.\n");
83 media_stream_set_meths(ms, media_mad);
84 media_stream_meth(ms, open)(ms);
88 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
89 (preferred == MDRIVER_UNKNOWN ||
90 preferred == MDRIVER_SOX)) {
91 MEDIA_DEBUG("trying sox.\n");
92 media_stream_set_meths(ms, media_sox);
93 media_stream_meth(ms, open)(ms);
97 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
98 (preferred == MDRIVER_UNKNOWN ||
99 preferred == MDRIVER_SNDFILE)) {
100 MEDIA_DEBUG("trying sndfile.\n");
101 media_stream_set_meths(ms, media_sndfile);
102 media_stream_meth(ms, open)(ms);
105 /* not working stuff here :) */
107 #ifdef HAVE_GSTREAMER
108 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
109 (preferred == MDRIVER_UNKNOWN ||
110 preferred == MDRIVER_GSTREAMER)) {
111 MEDIA_DEBUG("trying gstreamer.\n");
112 media_gstreamer_analyse_stream(ms);
117 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
118 (preferred == MDRIVER_UNKNOWN ||
119 preferred == MDRIVER_XINE)) {
120 MEDIA_DEBUG("trying xine.\n");
121 media_stream_set_meths(ms, media_xine);
122 media_stream_meth(ms, open)(ms);
125 #ifdef HAVE_INTERNAL_MEDIA
126 if ((media_stream_driver(ms) == MDRIVER_UNKNOWN) &&
127 (preferred == MDRIVER_UNKNOWN ||
128 preferred == MDRIVER_INTERNAL)) {
129 MEDIA_DEBUG("trying internal.\n");
130 media_internal_analyse_stream(ms);
133 if (media_stream_driver(ms) == MDRIVER_UNKNOWN) {
134 MEDIA_DEBUG("giving up\n");
135 media_stream_set_meths(ms, NULL);
141 /*****************************************************************/
143 /*****************************************************************/
144 static Lisp_Object media_stream_mark(Lisp_Object obj)
146 switch (XMEDIA_STREAM_KIND(obj)) {
148 mark_object(XMEDIA_STREAM(obj)->
149 kind_properties.fprops->filename);
155 case NUMBER_OF_MEDIA_KINDS:
160 if (XMEDIA_STREAM_METHS(obj) &&
161 XMEDIA_STREAM_METH(obj, mark))
162 XMEDIA_STREAM_METH(obj, mark)(XMEDIA_STREAM_DATA(obj));
168 media_stream_finalise(void *header, int for_disksave)
170 Lisp_Media_Stream *ms = (Lisp_Media_Stream*)header;
171 media_substream *mss = NULL;
175 if (media_stream_meths(ms) &&
176 media_stream_meth(ms, close))
177 media_stream_meth(ms, close)(media_stream_data(ms));
179 mss = media_stream_first(ms);
181 media_substream_finalise(mss, for_disksave);
182 mss = media_substream_next(mss);
186 switch (media_stream_driver(ms)) {
189 if (media_stream_data(ms))
190 media_xine_close_context(media_stream_data(ms));
193 case MDRIVER_SNDFILE:
195 if (media_stream_data(ms))
196 sf_close(media_stream_data(ms));
201 if (media_stream_data(ms))
202 mad_decoder_finish(media_stream_data(ms));
207 if (media_stream_data(ms))
208 st_close(media_stream_data(ms));
216 switch (media_stream_kind(ms)) {
218 mkind_file_properties *mkfp;
219 mkfp = media_stream_kind_properties(ms).fprops;
226 mkind_string_properties *mksp;
227 mksp = media_stream_kind_properties(ms).sprops;
232 if (mksp->stream_data)
233 xfree(mksp->stream_data);
242 case NUMBER_OF_MEDIA_KINDS:
247 /* avoid some warning */
248 if (for_disksave || ms == NULL);
252 media_stream_print(Lisp_Object obj, Lisp_Object printcharfun, int ef)
254 Lisp_Media_Stream *ms = XMEDIA_STREAM(obj);
255 media_substream *mss;
257 write_c_string("#<media-stream", printcharfun);
259 write_c_string(" :kind ", printcharfun);
261 switch (media_stream_kind(ms)) {
264 media_stream_kind_properties(ms).fprops->filename;
266 write_c_string("#<file ", printcharfun);
267 print_internal(file, printcharfun, ef);
268 write_c_string(">", printcharfun);
272 write_c_string("#<string>", printcharfun);
275 write_c_string("#<fifo>", printcharfun);
278 write_c_string("#<stream>", printcharfun);
283 case NUMBER_OF_MEDIA_KINDS:
284 write_c_string("#<unknown>", printcharfun);
288 mss = media_stream_first(ms);
290 write_c_string(" ", printcharfun);
291 media_substream_print(mss, printcharfun, ef);
292 mss = media_substream_next(mss);
295 write_c_string(" driven by ", printcharfun);
296 switch (media_stream_driver(ms)) {
297 case MDRIVER_INTERNAL:
298 write_c_string("internal", printcharfun);
301 write_c_string("ffmpeg", printcharfun);
303 case MDRIVER_SNDFILE:
304 write_c_string("sndfile", printcharfun);
307 write_c_string("mad", printcharfun);
310 write_c_string("sox", printcharfun);
313 write_c_string("xine", printcharfun);
315 case MDRIVER_GSTREAMER:
316 write_c_string("gstreamer", printcharfun);
318 case MDRIVER_UNKNOWN:
319 case NUMBER_OF_MEDIA_DRIVERS:
321 XMEDIA_STREAM_SET_METHS(obj, NULL);
322 write_c_string("unknown", printcharfun);
326 if (XMEDIA_STREAM_METHS(obj) &&
327 XMEDIA_STREAM_METH(obj, print)) {
328 XMEDIA_STREAM_METH(obj, print)(obj, printcharfun, ef);
331 write_c_string(">", printcharfun);
335 media_stream_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
337 if (XMEDIA_STREAM_DATA(obj1) == XMEDIA_STREAM_DATA(obj2))
347 media_stream_hash (Lisp_Object obj, int depth)
349 return (unsigned long)obj;
355 static const struct lrecord_description media_stream_description[] = {
356 { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, first) },
357 { XD_LISP_OBJECT, offsetof(Lisp_Media_Stream, last) },
358 { XD_INT, offsetof(Lisp_Media_Stream, kind) },
359 { XD_INT, offsetof(Lisp_Media_Stream, driver) },
360 { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, kind_properties) },
361 { XD_OPAQUE_PTR, offsetof(Lisp_Media_Stream, stream_data) },
365 DEFINE_LRECORD_IMPLEMENTATION("media_stream", media_stream,
366 media_stream_mark, media_stream_print,
367 media_stream_finalise,
368 media_stream_equal, media_stream_hash,
369 media_stream_description,
373 /*****************************************************************/
374 /* media substreams */
375 /*****************************************************************/
378 media_substream_finalise(void *header, int for_disksave)
380 media_substream *mss = (media_substream*)header;
382 switch (media_substream_type(mss)) {
384 if (media_substream_type_properties(mss).aprops)
385 xfree(media_substream_type_properties(mss).aprops);
388 if (media_substream_type_properties(mss).vprops)
389 xfree(media_substream_type_properties(mss).vprops);
393 case NUMBER_OF_MEDIA_TYPES:
399 pthread_mutex_destroy(&mss->substream_mutex);
402 media_substream_data(mss) = NULL;
404 /* avoid some warning */
409 media_substream_print_audio(media_substream *mss, Lisp_Object printcharfun)
411 mtype_audio_properties *mtap =
412 media_substream_type_properties(mss).aprops;
414 write_c_string("#<audio ", printcharfun);
415 if (mtap->name || mtap->codec_name) {
416 if (mtap->name && mtap->codec_name)
417 write_fmt_str(printcharfun, "%s (%s)",
418 mtap->name, mtap->codec_name);
420 write_fmt_str(printcharfun, "%s [???]", mtap->name);
421 else if (mtap->codec_name)
422 write_fmt_str(printcharfun, "??? (%s)", mtap->codec_name);
424 write_c_string("???", printcharfun);
426 switch (mtap->channels) {
428 write_c_string(", mono", printcharfun);
431 write_c_string(", stereo", printcharfun);
434 write_c_string(", chn:5", printcharfun);
437 write_c_string(", 5.1", printcharfun);
440 write_c_string(", chn:???", printcharfun);
444 if (mtap->samplerate)
445 write_fmt_str(printcharfun, ", %d Hz, %d Bit",
450 write_fmt_str(printcharfun, ", %d kb/s", mtap->bitrate/1000);
452 write_c_string(">", printcharfun);
456 media_substream_print_video(media_substream *mss, Lisp_Object printcharfun)
458 mtype_video_properties *mtvp =
459 media_substream_type_properties(mss).vprops;
461 write_c_string("#<video ", printcharfun);
462 if (mtvp->name || mtvp->codec_name) {
463 if (mtvp->name && mtvp->codec_name)
464 write_fmt_str(printcharfun, "%s (%s)",
465 mtvp->name, mtvp->codec_name);
467 write_fmt_str(printcharfun, "%s [???]", mtvp->name);
468 else if (mtvp->codec_name)
469 write_fmt_str(printcharfun, "??? (%s)", mtvp->codec_name);
471 write_c_string("???", printcharfun);
474 write_fmt_str(printcharfun, ", %d kb/s", mtvp->bitrate);
476 if (mtvp->width && mtvp->height) {
477 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1)
478 write_fmt_str(printcharfun, ", %dx%d (%d/%d)",
479 mtvp->width, mtvp->height,
480 mtvp->aspect_num, mtvp->aspect_den);
482 write_fmt_str(printcharfun, ", %dx%d (%.2f/1)",
483 mtvp->width, mtvp->height,
484 (double)mtvp->width/(double)mtvp->height);
486 write_c_string(">", printcharfun);
490 media_substream_print(media_substream *mss,
491 Lisp_Object printcharfun, int escapeflag)
493 write_c_string("#<media-substream :type ", printcharfun);
495 switch (media_substream_type(mss)) {
497 media_substream_print_audio(mss, printcharfun);
501 media_substream_print_video(mss, printcharfun);
504 write_c_string("#<image>", printcharfun);
508 case NUMBER_OF_MEDIA_TYPES:
509 write_c_string("#<unknown>", printcharfun);
513 write_c_string(">", printcharfun);
516 static Lisp_Media_Stream *
517 media_stream_allocate(void)
519 Lisp_Media_Stream *ms;
521 ms = alloc_lcrecord_type(Lisp_Media_Stream, &lrecord_media_stream);
526 Lisp_Object make_media_stream()
528 Lisp_Media_Stream *ms;
531 ms = media_stream_allocate();
532 media_stream_kind(ms) = MKIND_UNKNOWN;
533 media_stream_driver(ms) = MDRIVER_UNKNOWN;
534 media_stream_data(ms) = NULL;
536 /* now set the navigation */
537 media_stream_first(ms) = NULL;
538 media_stream_last(ms) = NULL;
540 XSETMEDIA_STREAM(lms, ms);
545 media_substream *make_media_substream(void)
547 /* this allocates and conses to the back of ms */
548 media_substream *mss;
550 mss = xnew_and_zero(media_substream);
551 media_substream_type(mss) = MTYPE_UNKNOWN;
552 media_substream_data(mss) = NULL;
555 media_substream_next(mss) = NULL;
556 media_substream_prev(mss) = NULL;
559 pthread_mutex_init(&mss->substream_mutex, NULL);
565 media_substream *make_media_substream_append(Lisp_Media_Stream *ms)
567 media_substream *mss;
569 mss = make_media_substream();
572 media_substream_next(mss) = NULL;
573 if (!(media_stream_last(ms))) {
574 media_substream_prev(mss) = NULL;
575 media_stream_first(ms) = mss;
577 media_substream_prev(mss) = media_stream_last(ms);
578 media_substream_next(media_stream_last(ms)) = mss;
581 media_stream_last(ms) = mss;
582 media_substream_up(mss) = ms;
587 media_substream *make_media_substream_prepend(Lisp_Media_Stream *ms)
589 media_substream *mss;
591 mss = make_media_substream();
594 media_substream_prev(mss) = NULL;
595 if (!(media_stream_first(ms))) {
596 media_substream_next(mss) = NULL;
597 media_stream_last(ms) = mss;
599 media_substream_next(mss) = media_stream_first(ms);
600 media_substream_prev(media_stream_first(ms)) = mss;
603 media_stream_first(ms) = mss;
604 media_substream_up(mss) = ms;
609 DEFUN("make-media-stream", Fmake_media_stream, 2, 3, 0, /*
610 Create a new media stream from DATA.
612 FROM is a keyword and defines how DATA is interpreted:
613 :file - DATA is the name of a file
614 :data - DATA is a string with the stream data
615 :url - DATA is a url (string) for streamed media contents
617 Optional argument DRIVER (a symbol) may be used to force
618 the use of a certain driver instead of automatically
619 detecting a suitable one. It is one of `ffmpeg', `sndfile',
620 `sox', `mad', `xine', `gstreamer', or `internal'.
622 (from, data, driver))
625 Lisp_Media_Stream *ms;
630 DATA_IS_DATA } datatype = DATA_IS_BULLSHIT;
631 media_driver pref = MDRIVER_UNKNOWN;
634 else if (EQ(from, Q_file))
635 datatype = DATA_IS_FILE;
636 else if (EQ(from, Q_data))
637 datatype = DATA_IS_DATA;
638 else if (EQ(from, Q_url))
639 datatype = DATA_IS_URL;
641 datatype = DATA_IS_BULLSHIT;
642 return Qnil; /* in this case, why bother? stupid user :) */
646 pref = MDRIVER_UNKNOWN;
648 else if (EQ(driver, Qmad))
652 else if (EQ(driver, Qffmpeg))
653 pref = MDRIVER_FFMPEG;
656 else if (EQ(driver, Qsox))
659 else if (EQ(driver, intern("xine")))
662 else if (EQ(driver, Qsndfile))
663 pref = MDRIVER_SNDFILE;
665 else if (EQ(driver, intern("internal")))
666 pref = MDRIVER_INTERNAL;
667 else if (EQ(driver, intern("gstreamer")))
668 pref = MDRIVER_GSTREAMER;
670 pref = MDRIVER_UNKNOWN;
672 /* hm, maybe data could be a symbol from the sound-alist?
673 * or a buffer or a network socket?
677 lms = make_media_stream();
678 ms = XMEDIA_STREAM(lms);
682 mkind_file_properties *fprops;
684 /* expand-file-name first and check for existence*/
685 data = Fexpand_file_name(data, Qnil);
686 if (!NILP(Ffile_directory_p(data)) ||
687 NILP(Ffile_readable_p(data)))
690 media_stream_kind(ms) = MKIND_FILE;
692 /* initialise a new file properties structure */
693 fprops = xnew_and_zero(mkind_file_properties);
695 /* copy the filename also as C string */
696 fprops->filename = data;
698 /* assign the file properties */
699 media_stream_kind_properties(ms).fprops = fprops;
701 determine_stream_type(ms, pref);
705 mkind_string_properties *sprops;
706 char *data_ext = NULL;
709 /* copy the filename also as C string */
710 TO_EXTERNAL_FORMAT(LISP_STRING, data,
711 MALLOC, (data_ext, data_len),
714 if (data_ext != NULL) {
715 media_stream_kind(ms) = MKIND_STRING;
717 /* initialise a new file properties structure */
718 sprops = xnew_and_zero(mkind_string_properties);
720 data_ext[data_len] = '\0';
722 sprops->stream_data = data_ext;
723 sprops->size = data_len;
725 /* assign the file properties */
726 media_stream_kind_properties(ms).sprops = sprops;
728 determine_stream_type(ms, pref);
735 case DATA_IS_BULLSHIT:
743 static Lisp_Object recons(Lisp_Object to, Lisp_Object from)
749 while (!NILP(from)) {
750 result = Fcons(XCAR(from), result);
756 DEFUN("media-stream-p", Fmedia_stream_p, 1, 1, 0, /*
757 Return non-nil if object is a media-stream.
761 if (MEDIA_STREAMP(object))
768 DEFUN("audio-substream-p", Faudio_substream_p, 1, 1, 0, /*
769 Return non-nil if object is a media-substream with audio data.
773 if (MEDIA_SUBSTREAMP(object) &&
774 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_AUDIO)
780 DEFUN("video-substream-p", Fvideo_substream_p, 1, 1, 0, /*
781 Return non-nil if object is a media-substream with video data.
785 if (MEDIA_SUBSTREAMP(object) &&
786 XMEDIA_SUBSTREAM_TYPE(object) == MTYPE_VIDEO)
793 DEFUN("media-available-formats", Fmedia_available_formats, 0, 0, 0, /*
794 Return a list of input formats in the underlying media libraries.
805 temp = media_ffmpeg_available_formats();
807 formats = recons(formats, temp);
812 formats = recons(formats, temp);
817 static inline void __attribute__((always_inline))
818 __add_prop(Lisp_Object *reslist, Lisp_Object key, Lisp_Object val)
820 *reslist = Fcons(Fcons(key, val), *reslist);
825 media_substream_props(media_substream *mss, Lisp_Object *reslist)
827 switch (media_substream_type(mss)) {
829 mtype_audio_properties *mtap =
830 media_substream_type_properties(mss).aprops;
832 /* add the type property */
833 __add_prop(reslist, Qtype, Qaudio);
836 __add_prop(reslist, Qdemux, build_string(mtap->name));
838 if (mtap->codec_name) {
839 __add_prop(reslist, Qcodec,
840 build_string(mtap->codec_name));
843 if (mtap->channels) {
844 __add_prop(reslist, Qnchannels,
845 make_int(mtap->channels));
848 if (mtap->samplerate) {
849 __add_prop(reslist, Qsamplerate,
850 make_int(mtap->samplerate));
854 __add_prop(reslist, Qabitrate, make_int(mtap->bitrate));
861 mtype_video_properties *mtvp =
862 media_substream_type_properties(mss).vprops;
864 /* add the type property */
865 __add_prop(reslist, Qtype, Qvideo);
868 __add_prop(reslist, Qdemux, build_string(mtvp->name));
870 if (mtvp->codec_name) {
871 __add_prop(reslist, Qcodec,
872 build_string(mtvp->codec_name));
876 __add_prop(reslist, Qvbitrate, make_int(mtvp->bitrate));
880 __add_prop(reslist, Qwidth, make_int(mtvp->width));
884 __add_prop(reslist, Qheight, make_int(mtvp->height));
887 #if defined HAVE_MPQ && defined WITH_GMP && 0
888 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
889 __add_prop(reslist, Qaspect,
890 make_bigq(mtvp->aspect_num,
893 #elif defined HAVE_FPFLOAT
894 /* use float arithmetic */
895 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
896 __add_prop(reslist, Qaspect,
897 make_float((fpfloat)mtvp->aspect_num /
898 (fpfloat)mtvp->aspect_den));
899 } else if (mtvp->width && mtvp->height) {
900 __add_prop(reslist, Qaspect,
901 make_float((fpfloat)mtvp->width /
902 (fpfloat)mtvp->height));
909 __add_prop(reslist, Qtype, Qimage);
914 case NUMBER_OF_MEDIA_TYPES:
919 DEFUN("media-properties", Fmedia_properties, 1, 1, 0, /*
920 Return an alist of available properties of media-stream STREAM.
922 Depending on the underlying stream this alist may be made of
923 several of the following keys, grouped by media contents.
927 'file (string) the stream's filename
928 'uri (string) the stream's URI
929 'fifo (string) the stream's FIFO socket
930 'driver (symbol) the stream's demuxer/decoder driver
931 'kind (symbol) the stream's kind (file, fifo, string, uri, etc.)
932 'type (symbol) the stream's type (audio, video, image, subtitle, lyrics, etc.)
936 'codec (string) the suitable audio codec
937 'demux (string) the suitable demuxer
938 'title (string) the title of an audio track
939 'artist (string) the performing artist(s)
940 'album (string) the title of the album
941 'comment (string) an arbitrary comment
942 'genre (string) the genre identifier string
943 'year (integer) the year of release
944 'track (integer) the track number on the album
945 'length (integer) the length of the track in seconds
946 'abitrate (integer) the average bitrate of the track in kb/s
947 'samplerate (integer) the samplerate of the track in Hz
948 'nchannels (integer) the number of distinguished channels
952 'codec (string) the suitable audio codec
953 'demux (string) the suitable demuxer
954 'title (string) the title of a video track
955 'comment (string) an arbitrary comment
956 'year (integer) the year of release
957 'vbitrate (integer) the average bitrate of the track in kb/s
958 'width (integer) the x-resolution in pixels
959 'height (integer) the y-resolution in pixels
960 'aspect (bigq) the aspect quotient
962 Keys which do not apply to the underlying stream or are not
963 defined in the tag section of the stream are simply left out
968 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
969 media_substream *mss;
970 Lisp_Object resdl = Qnil;
972 switch (media_stream_kind(ms)) {
975 media_stream_kind_properties(ms).fprops->filename;
977 __add_prop(&resdl, Qfile, file);
978 __add_prop(&resdl, Qkind, Qfile);
982 __add_prop(&resdl, Qkind, Qfifo);
986 __add_prop(&resdl, Qkind, Quri);
990 __add_prop(&resdl, Qkind, Qstring);
993 case NUMBER_OF_MEDIA_KINDS:
995 __add_prop(&resdl, Qkind, Qunknown);
999 __add_prop(&resdl, Qdriver, Qunavailable);
1000 switch (media_stream_driver(ms)) {
1001 case MDRIVER_INTERNAL:
1002 __add_prop(&resdl, Qdriver, Qinternal);
1004 case MDRIVER_FFMPEG:
1006 __add_prop(&resdl, Qdriver, Qffmpeg);
1008 streaminfo = media_ffmpeg_streaminfo(ms);
1012 case MDRIVER_SNDFILE:
1014 __add_prop(&resdl, Qdriver, Qsndfile);
1019 __add_prop(&resdl, Qdriver, Qmad);
1024 __add_prop(&resdl, Qdriver, Qsox);
1031 case MDRIVER_GSTREAMER:
1034 case MDRIVER_UNKNOWN:
1035 case NUMBER_OF_MEDIA_DRIVERS:
1037 __add_prop(&resdl, Qdriver, Qunknown);
1047 mss = media_stream_first(ms);
1049 media_substream_props(mss, &resdl);
1050 mss = media_substream_next(mss);
1056 /* convenience functions */
1057 DEFUN("media-stream-aspect", Fmedia_stream_aspect, 1, 3, 0, /*
1058 Return a list of aspect ratios in media stream STREAM.
1060 Optional argument SUBSTREAM names the index of a specific (video)
1061 substream, i.e. only video streams are counted, i.e. the substream 0
1062 names the first video track inside STREAM.
1063 The return value in that case is just a float or quotient, depending
1064 on the optional argument QUOTIENTP.
1066 Optional argument QUOTIENTP indicates that aspect ratios are to be
1067 returned as bigq quotients instead of floats (the default).
1069 By default, the aspect ratios of all the video tracks appear in the list,
1070 the first element in the list belongs to the first video track,
1071 the second element to the second one and so on.
1073 (stream, substream, quotientp))
1075 Lisp_Media_Stream *ms = XMEDIA_STREAM(stream);
1076 Lisp_Object res = Qnil;
1077 long int idx = INTP(substream) ? XINT(substream) : -1;
1079 for (media_substream *mss = media_stream_first(ms); mss;
1080 (mss = media_substream_next(mss))) {
1081 mtype_video_properties *mtvp;
1082 long int num = 0, den = 0;
1083 Lisp_Object tmp = Qnil;
1085 if (LIKELY(media_substream_type(mss) != MTYPE_VIDEO)) {
1089 /* oh, it's a video stream, check if it's the one we wanted */
1090 if (UNLIKELY(idx-- > 0)) {
1094 mtvp = media_substream_type_properties(mss).vprops;
1095 if (mtvp->aspect_num > 1 && mtvp->aspect_den >= 1) {
1096 num = mtvp->aspect_num;
1097 den = mtvp->aspect_den;
1098 } else if (mtvp->width && mtvp->height) {
1099 /* good enough? just an approximation as
1100 * the aspect ratio may very well differ
1101 * from the width-by-height ratio */
1106 if (LIKELY(NILP(quotientp))) {
1109 tmp = make_float((fpfloat)num / (fpfloat)den);
1111 #if defined HAVE_MPQ && defined WITH_GMP
1113 tmp = make_bigq(num, den);
1117 dead_wrong_type_argument(Qfeaturep,quotientp);
1120 if (UNLIKELY(INTP(substream))) {
1123 /* the very very default case */
1124 res = Fcons(tmp, res);
1130 /* Audio Coercion */
1131 /* SXEmacs works internally with samples in 24bit resolution */
1133 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_U8);
1136 sxe_msf_U8_up(void *d, void *s, size_t len)
1138 /* convert U8 samples to internal format (S24in32) */
1143 /* len is the number of samples (== #frame * #channels) */
1144 MEDIA_DEBUG_FMT("upsampling U8->internal: %u samples\n", len);
1146 for (i = len-1; i >= 0; i--)
1147 dst[i] = (int32_t)(src[i] ^ 0x80) << 16;
1153 sxe_msf_U8_down(void *d, void *s, size_t len)
1155 /* convert samples from internal format (S24in32) to U8 */
1160 /* len is the number of samples (== #frame * #channels) */
1161 MEDIA_DEBUG_FMT("downsampling internal->U8: %u samples\n", len);
1163 for (i = 0; i < len; i++)
1164 dst[i] = (uint8_t)(src[i] >> 16) ^ 0x80;
1169 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S16);
1172 sxe_msf_S16_up(void *d, void *s, size_t len)
1174 /* convert S16 samples to internal format (S24in32) */
1179 /* len is the number of samples (== #frame * #channels) */
1180 MEDIA_DEBUG_FMT("upsampling S16->internal: %u samples\n", len);
1182 for (i = len-1; i >= 0; i--)
1183 dst[i] = (int32_t)(src[i]) << 8;
1184 MEDIA_DEBUG_FMT("d00:%d d01:%d\n", dst[0], dst[1]);
1190 sxe_msf_S16_down(void *d, void *s, size_t len)
1192 /* convert samples from internal format (S24in32) to S16 */
1197 /* len is the number of samples (== #frame * #channels) */
1198 MEDIA_DEBUG_FMT("downsampling internal->S16: %u samples\n", len);
1200 for (i = 0; i < len; i++)
1201 dst[i] = (int16_t)(src[i] >> 8);
1206 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S24); /* format internally used */
1209 sxe_msf_S24_up(void *d, void *s, size_t len)
1211 MEDIA_DEBUG_FMT("upsampling S24->internal: %u samples\n", len);
1213 /* S24 _is_ the internal format */
1218 sxe_msf_S24_down(void *d, void *s, size_t len)
1220 MEDIA_DEBUG_FMT("downsampling internal->S24: %u samples\n", len);
1222 /* S24 _is_ the internal format */
1226 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_S32);
1229 sxe_msf_S32_up(void *d, void *s, size_t len)
1231 /* convert S32 samples to internal format (S24in32) */
1236 /* len is the number of samples (== #frame * #channels) */
1237 MEDIA_DEBUG_FMT("upsampling S32->internal: %u samples\n", len);
1239 for (i = 0; i < len; i++)
1240 dst[i] = src[i] >> 8;
1246 sxe_msf_S32_down(void *d, void *s, size_t len)
1248 /* convert samples from internal format (S24in32) to S32 */
1253 /* len is the number of samples (== #frame * #channels) */
1254 MEDIA_DEBUG_FMT("downsampling internal->S32: %u samples\n", len);
1256 for (i = 0; i < len; i++)
1257 dst[i] = src[i] << 8;
1262 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_FLT);
1265 sxe_msf_FLT_up(void *d, void *s, size_t len)
1267 /* convert float samples to internal format (S24in32) */
1272 /* len is the number of samples (== #frame * #channels) */
1273 MEDIA_DEBUG_FMT("upsampling FLT->internal: %u samples\n", len);
1275 for (i = 0; i < len; i++) {
1276 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1278 MEDIA_DEBUG_FMT("s00:%f d00:%d s01:%f d01:%d\n",
1279 src[0], dst[0], src[1], dst[1]);
1285 sxe_msf_FLT_down(void *d, void *s, size_t len)
1287 /* convert samples from internal format (S24in32) to float */
1292 /* len is the number of samples (== #frame * #channels) */
1293 MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
1295 for (i = len-1; i >= 0; i--) {
1296 dst[i] = (float)(src[i]) / SXE_MAX_S24;
1298 MEDIA_DEBUG_FMT("d00:%f d01:%f\n", dst[0], dst[1]);
1303 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_DBL);
1306 sxe_msf_DBL_up(void *d, void *s, size_t len)
1308 /* convert double samples to internal format (S24in32) */
1313 /* len is the number of samples (== #frame * #channels) */
1314 MEDIA_DEBUG_FMT("upsampling DBL->internal: %u samples\n", len);
1316 for (i = 0; i < len; i++) {
1317 dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
1319 MEDIA_DEBUG_FMT("s00:%f d00:%d s01:%f d01:%d\n",
1320 src[0], dst[0], src[1], dst[1]);
1326 sxe_msf_DBL_down(void *d, void *s, size_t len)
1328 /* convert samples from internal format (S24in32) to double */
1333 /* len is the number of samples (== #frame * #channels) */
1334 MEDIA_DEBUG_FMT("downsampling internal->DBL: %u samples\n", len);
1336 for (i = len-1; i >= 0; i--) {
1337 dst[i] = (double)(src[i]) / SXE_MAX_S24;
1339 MEDIA_DEBUG_FMT("d00:%f d01:%f\n", dst[0], dst[1]);
1345 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
1348 _sxe_mse_1ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1349 size_t len, void *ignored)
1351 /* mono to stereo converter */
1354 MEDIA_DEBUG_COE("mono->stereo: %u samples\n", len);
1356 /* len is the number of samples */
1357 for (i = len-1; i >= 0; i--) {
1359 dst[2*i+1] = src[i];
1365 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch, _sxe_mse_2ch_to_1ch);
1368 _sxe_mse_2ch_to_1ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1369 size_t len, void *args)
1371 /* stereo to mono converter */
1373 sxe_mse_2ch_to_1ch_args *_args = args;
1376 MEDIA_DEBUG_COE("stereo->mono: %u samples\n", len);
1382 /* len is the number of samples */
1383 for (i = 0; i < len/2; i++) {
1384 dst[i] = src[2*i+c];
1390 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_5ch_to_2ch, _sxe_mse_5ch_to_2ch);
1393 _sxe_mse_5ch_to_2ch(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1394 size_t len, void *args)
1396 /* 5 channel to stereo converter */
1398 sxe_mse_5ch_to_2ch_args *_args = args;
1401 MEDIA_DEBUG_COE("5ch->stereo: %u samples\n", len);
1408 /* len is the number of samples */
1409 for (i = 0; i < len/5; i++) {
1410 dst[2*i] = src[5*i+c1];
1411 dst[2*i+1] = src[5*i+c2];
1417 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_volume, _sxe_mse_volume);
1420 _sxe_mse_volume(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1421 size_t len, void *args)
1423 /* stereo to mono converter */
1425 sxe_mse_volume_args *_args = args;
1427 MEDIA_DEBUG_COE("volume: %u samples\n", len);
1429 /* len is the number of samples */
1430 for (i = 0; i < len; i+=_args->num_channels) {
1431 for (j = 0; j < (size_t)_args->num_channels; j++) {
1432 uint8_t vol = _args->volume[j];
1433 dst[i+j] = (src[i+j] * vol) >> 7;
1440 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_rerate, _sxe_mse_rerate);
1443 _sxe_mse_rerate(sxe_media_sample_t *dst, sxe_media_sample_t *src,
1444 size_t len, void *args)
1446 /* rate converter */
1448 sxe_mse_rerate_args *_args = args;
1449 float trafo = (float)_args->srcrate / (float)_args->tgtrate
1451 int chans = _args->num_channels;
1452 int bound = len/chans/trafo;
1454 MEDIA_DEBUG_COE("rerate: %u samples, final trafo: %f, bound is: %d\n",
1458 for (i = bound-1; i >= 0; i--) {
1459 int frame = i * trafo;
1460 dst[chans*i] = (src[chans*frame]);
1461 dst[chans*i+1] = (src[chans*frame+1]);
1463 } else if (trafo > 1.0) {
1464 for (i = 0; i < bound-1; i++) {
1465 int frame = i * trafo;
1466 dst[chans*i] = (src[chans*frame]);
1467 dst[chans*i+1] = (src[chans*frame+1]);
1471 return bound * chans;
1475 void syms_of_media(void)
1477 INIT_LRECORD_IMPLEMENTATION(media_stream);
1479 defsymbol(&Qmedia_streamp, "media-stream-p");
1484 DEFSYMBOL(Qnchannels);
1485 DEFSYMBOL(Qsamplerate);
1486 DEFSYMBOL(Qbitrate);
1487 DEFSYMBOL(Qabitrate);
1488 DEFSYMBOL(Qvbitrate);
1500 DEFSUBR(Fmake_media_stream);
1501 DEFSUBR(Fmedia_stream_p);
1503 DEFSUBR(Faudio_substream_p);
1504 DEFSUBR(Fvideo_substream_p);
1507 DEFSUBR(Fmedia_available_formats);
1508 DEFSUBR(Fmedia_properties);
1509 DEFSUBR(Fmedia_stream_aspect);
1512 defsymbol(&Qffmpeg, "ffmpeg");
1515 defsymbol(&Qmad, "mad");
1518 defsymbol(&Qsox, "sox");
1521 defsymbol(&Qsndfile, "sndfile");
1523 defsymbol(&Qunknown, "unknown");
1524 defsymbol(&Qunavailable, "unavailable");
1527 void vars_of_media(void)
1529 Fprovide(intern("media"));
1532 Fprovide(intern("media-ffmpeg"));
1535 Fprovide(intern("media-sndfile"));
1538 Fprovide(intern("media-mad"));
1541 Fprovide(intern("media-sox"));
1544 Fprovide(intern("media-xine"));
1546 #ifdef HAVE_GSTREAMER
1547 Fprovide(intern("media-gstreamer"));
1549 #ifdef HAVE_INTERNAL_MEDIA
1550 Fprovide(intern("media-internal"));
1554 /* media.c ends here */