Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / media / media-ffmpeg.c
1 /* media-ffmpeg.c - analyse audio files or streams via ffmpeg
2
3    Copyright (C) 2006 Sebastian Freundt
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "lisp.h"
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <string.h>
34 #if defined HAVE_STDINT_H
35 # include <stdint.h>
36 #endif  /* HAVE_STDINT_H */
37
38 #include "buffer.h"
39 #include "sysdep.h"
40 #include "sysfile.h"
41
42 #include "media-ffmpeg.h"
43
44 static int media_ffmpeg_bitrate(AVCodecContext*);
45 static AVFormatContext *media_ffmpeg_open_file(const char*);
46 AVFormatContext *media_ffmpeg_open_data(char*, size_t);
47
48 static void media_ffmpeg_analyse_audio(media_substream*, AVFormatContext*, int);
49 static void media_ffmpeg_analyse_video(media_substream*, AVFormatContext*, int);
50
51 #define MYSELF MDRIVER_FFMPEG
52
53 Lisp_Object Qffmpeg;
54
55 #define __FFMPEG_DEBUG__(args...)       fprintf(stderr, "FFMPEG " args)
56 #ifndef FFMPEG_DEBUG_FLAG
57 #define FFMPEG_DEBUG(args...)
58 #else
59 #define FFMPEG_DEBUG(args...)           __FFMPEG_DEBUG__(args)
60 #endif
61 #define FFMPEG_DEBUG_AVF(args...)       FFMPEG_DEBUG("[avformat]: " args)
62 #define FFMPEG_DEBUG_AVC(args...)       FFMPEG_DEBUG("[avcodec]: " args)
63 #define FFMPEG_DEBUG_AVS(args...)       FFMPEG_DEBUG("[stream]: " args)
64 #define FFMPEG_CRITICAL(args...)        __FFMPEG_DEBUG__("CRITICAL: " args)
65
66 \f
67 DECLARE_MEDIA_DRIVER_OPEN_METH(media_ffmpeg);
68 DECLARE_MEDIA_DRIVER_CLOSE_METH(media_ffmpeg);
69 DECLARE_MEDIA_DRIVER_PRINT_METH(media_ffmpeg);
70 DECLARE_MEDIA_DRIVER_READ_METH(media_ffmpeg);
71 DECLARE_MEDIA_DRIVER_REWIND_METH(media_ffmpeg);
72
73 DEFINE_MEDIA_DRIVER_CUSTOM(media_ffmpeg,
74                            media_ffmpeg_open, media_ffmpeg_close,
75                            media_ffmpeg_print, NULL,
76                            media_ffmpeg_read, NULL,
77                            media_ffmpeg_rewind, NULL);
78
79 DECLARE_MEDIA_DRIVER_OPEN_METH(new_media_ffmpeg);
80 DECLARE_MEDIA_DRIVER_READ_METH(new_media_ffmpeg);
81 DECLARE_MEDIA_DRIVER_REWIND_METH(new_media_ffmpeg);
82
83 DEFINE_MEDIA_DRIVER_CUSTOM(new_media_ffmpeg,
84                            new_media_ffmpeg_open, NULL,
85                            NULL, NULL,
86                            new_media_ffmpeg_read, NULL,
87                            new_media_ffmpeg_rewind, NULL);
88
89 \f
90 static int
91 media_ffmpeg_bitrate(AVCodecContext *enc)
92 {
93         int bitrate;
94
95         /* for PCM codecs, compute bitrate directly */
96         switch ((unsigned int)enc->codec_id) {
97         case CODEC_ID_PCM_S32LE:
98         case CODEC_ID_PCM_S32BE:
99         case CODEC_ID_PCM_U32LE:
100         case CODEC_ID_PCM_U32BE:
101                 bitrate = enc->sample_rate * enc->channels * 32;
102                 break;
103         case CODEC_ID_PCM_S24LE:
104         case CODEC_ID_PCM_S24BE:
105         case CODEC_ID_PCM_U24LE:
106         case CODEC_ID_PCM_U24BE:
107         case CODEC_ID_PCM_S24DAUD:
108                 bitrate = enc->sample_rate * enc->channels * 24;
109                 break;
110         case CODEC_ID_PCM_S16LE:
111         case CODEC_ID_PCM_S16BE:
112         case CODEC_ID_PCM_U16LE:
113         case CODEC_ID_PCM_U16BE:
114                 bitrate = enc->sample_rate * enc->channels * 16;
115                 break;
116         case CODEC_ID_PCM_S8:
117         case CODEC_ID_PCM_U8:
118         case CODEC_ID_PCM_ALAW:
119         case CODEC_ID_PCM_MULAW:
120                 bitrate = enc->sample_rate * enc->channels * 8;
121                 break;
122         default:
123                 bitrate = enc->bit_rate;
124                 break;
125         }
126         return bitrate;
127 }
128
129 char *media_ffmpeg_streaminfo(Lisp_Media_Stream *ms)
130 {
131         AVFormatContext *avfc = NULL;
132         char *out;
133         int chars_left = 4095;
134
135         avfc = media_stream_data(ms);
136         out = xmalloc_atomic(chars_left+1);
137         out[0] = '\0';
138         out[chars_left] = '\0';
139
140         /* cannot use ffmpeg on corrupt streams */
141         if (media_stream_driver(ms) != MYSELF || avfc == NULL)
142                 return out;
143
144         if (avfc->author && *avfc->author) {
145                 strncat(out, " :author \"", chars_left);
146                 chars_left -= 10;
147                 strncat(out, avfc->author, chars_left);
148                 chars_left -= strlen(avfc->author);
149                 strncat(out, "\"", chars_left--);
150         }
151         if (avfc->title && *avfc->title) {
152                 strncat(out, " :title: \"", chars_left);
153                 chars_left -= 10;
154                 strncat(out, avfc->title, chars_left);
155                 chars_left -= strlen(avfc->title);
156                 strncat(out, "\"", chars_left--);
157         }
158         if (avfc->year) {
159                 char year[12];
160                 int sz = snprintf(year, sizeof(year), "%d", avfc->year);
161                 assert(sz>=0 && sz<sizeof(year));
162                 strncat(out, " :year ", chars_left);
163                 chars_left -= 7;
164                 strncat(out, year, chars_left);
165         }
166
167         return out;
168 }
169
170 static void
171 media_ffmpeg_print(Lisp_Object ms, Lisp_Object pcfun, int ef)
172 {
173         return;
174 }
175
176 static AVFormatContext*
177 media_ffmpeg_open_file(const char *file)
178 {
179 #if defined HAVE_AVFORMAT_ALLOC_CONTEXT
180         AVFormatContext *avfc = avformat_alloc_context();
181 #elif defined HAVE_AV_ALLOC_FORMAT_CONTEXT
182         /* deprecated already, but `people' like Horst still use this */
183         AVFormatContext *avfc = av_alloc_format_context();
184 #else
185 # error "Your ffmpeg library is too old.  Adopt a new one."
186 #endif  /* HAVE_AVFORMAT_ALLOC_CONTEXT */
187
188         /* open the file */
189         if (av_open_input_file(&avfc, file, NULL, 0, NULL) < 0) {
190                 FFMPEG_DEBUG_AVF("opening file failed.\n");
191                 if (avfc)
192                         xfree(avfc);
193                 return NULL;
194         }
195
196         /* Retrieve stream information */
197         if (av_find_stream_info(avfc) < 0) {
198                 FFMPEG_DEBUG_AVS("opening stream inside file failed.\n");
199                 av_close_input_file(avfc);
200                 if (avfc)
201                         xfree(avfc);
202                 return NULL;
203         }
204
205         return avfc;
206 }
207
208 \f
209 static int
210 media_ffmpeg_vio_open(URLContext *h, const char *filename, int flags)
211 {
212         return 0;
213 }
214
215 static int
216 media_ffmpeg_vio_read(URLContext *h, unsigned char *buf, int size)
217 {
218         media_data *sd = (media_data*)h->priv_data;
219
220         FFMPEG_DEBUG_AVS("reading %d bytes to 0x%x, respecting seek %ld\n",
221                          size, (unsigned int)buf, sd->seek);
222
223         if ((long int)sd->length <= sd->seek) {
224                 FFMPEG_DEBUG_AVS("eof\n");
225                 return -1;
226         }
227
228         memcpy(buf, sd->data+sd->seek, size);
229         sd->seek += size;
230
231         return size;
232 }
233
234 static int
235 media_ffmpeg_vio_write(URLContext *h, unsigned char *buf, int size)
236 {
237         return -1;
238 }
239
240 static int64_t
241 media_ffmpeg_vio_seek(URLContext *h, int64_t pos, int whence)
242 {
243         media_data *sd = (media_data*)h->priv_data;
244
245         FFMPEG_DEBUG_AVS("seeking to %ld via %d\n", (long int)pos, whence);
246
247         switch (whence) {
248         case SEEK_SET:
249                 sd->seek = pos;
250                 break;
251         case SEEK_CUR:
252                 sd->seek = sd->seek+pos;
253                 break;
254         case SEEK_END:
255                 sd->seek = sd->length+pos;
256                 break;
257         default:
258                 /* be prolific */
259                 abort();
260         }
261         return sd->seek;
262 }
263
264 static int
265 media_ffmpeg_vio_close(URLContext *h)
266 {
267         if (h->priv_data)
268                 xfree(h->priv_data);
269         h->priv_data = NULL;
270         return 0;
271 }
272
273 /* this is a memory-i/o protocol in case we have to deal with string data */
274 static URLProtocol media_ffmpeg_protocol = {
275         "SXEmff",
276         media_ffmpeg_vio_open,
277         media_ffmpeg_vio_read,
278         media_ffmpeg_vio_write,
279         media_ffmpeg_vio_seek,
280         media_ffmpeg_vio_close,
281 };
282
283 /** Size of probe buffer, for guessing file type from file contents. */
284 #define PROBE_BUF_MIN 2048
285 #define PROBE_BUF_MAX 131072
286
287 AVFormatContext*
288 media_ffmpeg_open_data(char *data, size_t size)
289 {
290 #if defined HAVE_AVFORMAT_ALLOC_CONTEXT
291         AVFormatContext *avfc = avformat_alloc_context();
292 #elif defined HAVE_AV_ALLOC_FORMAT_CONTEXT
293         /* deprecated already, but `people' like Horst still use this */
294         AVFormatContext *avfc = av_alloc_format_context();
295 #else
296 # error "Your ffmpeg library is too old.  Adopt a new one."
297 #endif  /* HAVE_AVFORMAT_ALLOC_CONTEXT */
298         AVProbeData *pd = NULL;
299         ByteIOContext *bioctx = NULL;
300         AVInputFormat *fmt = NULL;
301         char file[] = "SXEmff:SXEmacs.mp3\000";
302         media_data *sd = NULL;
303
304         /* register our virtual i/o */
305 #if defined HAVE_AV_REGISTER_PROTOCOL
306         av_register_protocol(&media_ffmpeg_protocol);
307 #elif defined HAVE_REGISTER_PROTOCOL
308         register_protocol(&media_ffmpeg_protocol);
309 #else
310 # error "Get a recent ffmpeg or get a life."
311 #endif
312
313         /* initialise our media_data */
314         sd = xnew_and_zero(media_data);
315         sd->length = size;
316         sd->seek = 0;
317         sd->data = data;
318
319         /* register ffmpeg byteio */
320         bioctx = xnew_and_zero(ByteIOContext);
321 #if defined FFMPEG_URL_FOPEN_BIOCTX_STAR_STAR
322         url_fopen(&bioctx, file, URL_RDONLY);
323 #elif defined FFMPEG_URL_FOPEN_BIOCTX_STAR
324         url_fopen(bioctx, file, URL_RDONLY);
325 #endif
326         /* erm, register us at the byteio context */
327         ((URLContext*)(bioctx->opaque))->priv_data = sd;
328
329         /* take a probe */
330         pd = xnew_and_zero(AVProbeData);
331         pd->filename = file;
332         pd->buf = NULL;
333         pd->buf_size = 0;
334
335         pd->buf = (void*)sd->data;
336         pd->buf_size = PROBE_BUF_MIN;
337         fmt = av_probe_input_format(pd, 1);
338
339         /* if still no format found, error */
340         if (!fmt) {
341                 xfree(pd);
342                 xfree(bioctx);
343                 xfree(sd);
344                 xfree(avfc);
345                 return NULL;
346         }
347
348         /* open the file */
349         if (av_open_input_stream(&avfc, bioctx, file, fmt, NULL) < 0) {
350                 xfree(pd);
351                 xfree(bioctx);
352                 xfree(sd);
353                 xfree(avfc);
354                 return NULL;
355         }
356
357         /* Retrieve stream information */
358         if (av_find_stream_info(avfc) < 0) {
359                 xfree(pd);
360                 xfree(bioctx);
361                 xfree(sd);
362                 xfree(avfc);
363                 return NULL;
364         }
365
366         return avfc;
367 }
368
369 static void
370 media_ffmpeg_close(ms_driver_data_t data)
371 {
372         AVFormatContext *avfc = (AVFormatContext*)data;
373         FFMPEG_DEBUG_AVF("closing AVFormatContext: 0x%lx\n",
374                          (long unsigned int)avfc);
375         if (avfc && avfc->iformat)
376                 av_close_input_file(avfc);
377 }
378
379 static void
380 media_ffmpeg_analyse_audio(media_substream *mss, AVFormatContext *avfc, int st)
381 {
382         mtype_audio_properties *mtap;
383         const char *name = NULL;
384         const char *codec_name = NULL;
385         /* libavformat cruft */
386         AVStream *avst = NULL;
387         AVCodecContext *avcc = NULL;
388
389         /* unpack the stream and codec context from the container, again */
390         if (avfc)
391           avst = avfc->streams[st];
392         if (avst)
393           avcc = avst->codec;
394
395         /* initialise */
396         mtap = xnew_and_zero(mtype_audio_properties);
397
398         /* copy the name */
399         if (avfc && avfc->iformat)
400                 name = avfc->iformat->name;
401         if (avcc && avcc->codec)
402                 codec_name = avcc->codec->name;
403
404         mtap->name = name;
405         mtap->codec_name = codec_name;
406         if (avcc ) {
407                 mtap->channels = avcc->channels;
408                 mtap->samplerate = avcc->sample_rate;
409                 mtap->bitrate = media_ffmpeg_bitrate(avcc);
410
411                 /* samplewidth and framesize */
412                 switch (avcc->sample_fmt) {
413                 case SAMPLE_FMT_U8:
414                         mtap->samplewidth = 8;
415                         mtap->framesize = mtap->channels * 1;
416                         mtap->msf = sxe_msf_U8;
417                         break;
418                 case SAMPLE_FMT_S16:
419                         mtap->samplewidth = 16;
420                         mtap->framesize = mtap->channels * 2;
421                         mtap->msf = sxe_msf_S16;
422                         break;
423 #if defined SAMPLE_FMT_S24
424                 case SAMPLE_FMT_S24:
425                         mtap->samplewidth = 32;
426                         mtap->framesize = mtap->channels * 4;
427                         mtap->msf = sxe_msf_S24;
428                         break;
429 #endif  /* SAMPLE_FMT_S24 */
430                 case SAMPLE_FMT_S32:
431                         mtap->samplewidth = 32;
432                         mtap->framesize = mtap->channels * 4;
433                         mtap->msf = sxe_msf_S32;
434                         break;
435                 case SAMPLE_FMT_FLT:
436                         mtap->samplewidth = 8*sizeof(float);
437                         mtap->framesize = mtap->channels * sizeof(float);
438                         mtap->msf = sxe_msf_FLT;
439                         break;
440                 case SAMPLE_FMT_NONE:
441                 default:
442                         mtap->samplewidth = 0;
443                         break;
444                 }
445         }
446         mtap->endianness = 0;
447
448         /* now assign */
449         media_substream_type_properties(mss).aprops = mtap;
450         media_substream_data(mss) = (void*)st;
451 }
452
453 static void
454 media_ffmpeg_analyse_video(media_substream *mss, AVFormatContext *avfc, int st)
455 {
456         mtype_video_properties *mtvp;
457         const char *name = NULL;
458         const char *codec_name = NULL;
459         /* libavformat cruft */
460         AVStream *avst = NULL;
461         AVCodecContext *avcc = NULL;
462
463         /* unpack the stream and codec context from the container, again */
464         if (avfc)
465           avst = avfc->streams[st];
466         if (avst)
467           avcc = avst->codec;
468
469         /* initialise */
470         mtvp = xnew_and_zero(mtype_video_properties);
471
472         /* copy the name */
473         if (avfc && avfc->iformat)
474                 name = avfc->iformat->name;
475         if (avcc && avcc->codec)
476                 codec_name = avcc->codec->name;
477
478         mtvp->name = name;
479         mtvp->codec_name = codec_name;
480         if (avcc) {
481           mtvp->bitrate = avcc->bit_rate;
482           mtvp->width = avcc->width;
483           mtvp->height = avcc->height;
484           mtvp->aspect_num = avcc->sample_aspect_ratio.num;
485           mtvp->aspect_den = avcc->sample_aspect_ratio.den;
486         }
487
488         mtvp->endianness = 0;
489
490         /* now assign */
491         media_substream_type_properties(mss).vprops = mtvp;
492         media_substream_data(mss) = (void*)st;
493 }
494
495 /* main analysis function */
496 static ms_driver_data_t
497 media_ffmpeg_open(Lisp_Media_Stream *ms)
498 {
499         /* stream stuff */
500         media_substream *mss;
501         /* libavformat stuff */
502         AVFormatContext *avfc = NULL;
503         AVStream *avst = NULL;
504         AVCodecContext *avcc = NULL;
505         AVCodec *avc = NULL;
506
507         /* initialise */
508         av_register_all();
509
510         switch (media_stream_kind(ms)) {
511         case MKIND_FILE: {
512                 mkind_file_properties *mkfp = NULL;
513                 const char *file;
514                 int file_len = 0;
515
516                 /* open the file */
517                 mkfp = media_stream_kind_properties(ms).fprops;
518                 TO_EXTERNAL_FORMAT(LISP_STRING, mkfp->filename,
519                                    ALLOCA, (file, file_len), Qnil);
520                 avfc = media_ffmpeg_open_file(file);
521                 if (!avfc) {
522                         media_stream_set_meths(ms, NULL);
523                         media_stream_driver(ms) = MDRIVER_UNKNOWN;
524                         return NULL;
525                 }
526
527                 /* store the filesize */
528                 mkfp->filesize = avfc->file_size;
529                 break;
530         }
531         case MKIND_STRING: {
532                 mkind_string_properties *mksp = NULL;
533                 char *data;
534                 uint32_t size;
535
536                 /* open the file */
537                 mksp = media_stream_kind_properties(ms).sprops;
538                 data = mksp->stream_data;
539                 size = mksp->size;
540                 avfc = media_ffmpeg_open_data(data, size);
541
542                 if (!avfc) {
543                         media_stream_set_meths(ms, NULL);
544                         media_stream_driver(ms) = MDRIVER_UNKNOWN;
545                         return NULL;
546                 }
547                 break;
548         }
549         case MKIND_UNKNOWN:
550         case MKIND_FIFO:
551         case MKIND_STREAM:
552         case NUMBER_OF_MEDIA_KINDS:
553         default:
554                 break;
555         }
556
557         if (avfc)
558                 /* check if there is at least one usable stream */
559                 for (size_t st = 0; st < avfc->nb_streams; st++) {
560                         avst = avfc->streams[st];
561                         avcc = avst->codec;
562                         if (avcc &&
563                             avcc->codec_id != CODEC_ID_NONE &&
564                             avcc->codec_type != CODEC_TYPE_DATA &&
565                             (avc = avcodec_find_decoder(avcc->codec_id)) &&
566                             (avc && (avcodec_open(avcc, avc) >= 0))) {
567
568                                 /* create a substream */
569                                 mss = make_media_substream_append(ms);
570
571                                 switch ((unsigned int)avcc->codec_type) {
572                                 case CODEC_TYPE_VIDEO:
573                                         /* assign substream props */
574                                         media_substream_type(mss) = MTYPE_VIDEO;
575                                         media_ffmpeg_analyse_video(mss, avfc, st);
576                                         break;
577                                 case CODEC_TYPE_AUDIO:
578                                         /* assign substream props */
579                                         media_substream_type(mss) = MTYPE_AUDIO;
580                                         media_ffmpeg_analyse_audio(mss, avfc, st);
581                                         /* set some stream handlers */
582                                         media_stream_set_meths(ms, media_ffmpeg);
583                                         break;
584                                 case CODEC_TYPE_DATA:
585                                         media_substream_type(mss) = MTYPE_IMAGE;
586                                         break;
587                                 default:
588                                         media_substream_type(mss) = MTYPE_UNKNOWN;
589                                         break;
590                                 }
591                         }
592                 }
593
594         /* keep the format context */
595         media_stream_data(ms) = avfc;
596
597         /* set me as driver indicator */
598         media_stream_driver(ms) = MYSELF;
599
600         return avfc;
601 }
602
603 \f
604 static inline void
605 handle_packet(AVFormatContext *avfc, AVPacket *pkt)
606 {
607 #if 0
608         AVFrame picture;
609         AVStream *st;
610         int ret, got_picture;
611
612         st = avfc->streams[pkt->stream_index];
613
614         /* XXX: allocate picture correctly */
615         avcodec_get_frame_defaults(&picture);
616
617         ret = avcodec_decode_video(
618                 st->codec, &picture, &got_picture, pkt->data, pkt->size);
619
620         if (!got_picture) {
621                 /* no picture yet */
622                 goto discard_packet;
623         }
624 #endif
625
626         FFMPEG_DEBUG_AVF("got video frame\n");
627
628 #if 0                           /* not yet */
629 discard_packet:
630 #endif
631         av_free_packet(pkt);
632         return;
633 }
634
635 static size_t
636 media_ffmpeg_read(media_substream *mss, void *outbuf, size_t length)
637 {
638 /* read at most `length' frames into `outbuf' */
639 /* convert them to internal format */
640         /* stream stuff */
641         Lisp_Media_Stream *ms = mss->up;
642         mtype_audio_properties *mtap;
643         media_sample_format_t *fmt;
644         /* libavformat */
645         AVFormatContext *avfc;
646         AVStream *avst;
647         AVCodecContext *avcc;
648         AVCodec *avc;
649         AVPacket pkt;
650         /* buffering */
651         /* the size we present here, is _not_ the size we want, however
652          * ffmpeg is quite pedantic about the buffer size,
653          * we just pass the least possible value here to please him */
654         int size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
655         uint16_t framesize;
656         /* result */
657         long int bufseek = 0, si = -1;
658         int declen, dec, rf_status = 0;
659
660         /* check the integrity of the media stream */
661         if (media_stream_driver(ms) != MYSELF)
662                 return 0;
663
664         /* fetch the format context */
665         avfc = media_stream_data(ms);
666
667         if (!avfc)
668                 return 0;
669
670         si = (long int)mss->substream_data;
671         avst = avfc->streams[si];
672         avcc = avst->codec;
673         avc = avcc->codec;
674
675         /* unpack the substream */
676         if ((mtap = media_substream_type_properties(mss).aprops) == NULL) {
677                 FFMPEG_DEBUG_AVS("stream information missing. Uh Oh.\n");
678                 return 0;
679         }
680
681         /* fetch audio info */
682         framesize = mtap->framesize;
683         fmt = mtap->msf;
684
685         /* initialise the packet */
686         pkt.pts = pkt.dts = pkt.size = 0;
687         FFMPEG_DEBUG_AVF("initialised packet: "
688                          "pts:%lld dts:%lld psz:%d\n",
689                          (long long int)pkt.pts,
690                          (long long int)pkt.dts,
691                          pkt.size);
692
693         /* read a frame and decode it */
694         while ((size_t)bufseek <= length*framesize &&
695                (rf_status = av_read_frame(avfc, &pkt)) >= 0) {
696                 if (pkt.stream_index != si) {
697                         FFMPEG_DEBUG_AVF("SKIP reason: "
698                                          "sought after stream %ld, got %ld\n",
699                                          (long int)si,
700                                          (long int)pkt.stream_index);
701                         handle_packet(avfc, &pkt);
702                         continue;
703                 }
704
705                 FFMPEG_DEBUG_AVF("read frame: "
706                                  "pts:%lld dts:%lld psz:%d\n",
707                                  (long long int)pkt.pts,
708                                  (long long int)pkt.dts,
709                                  pkt.size);
710
711                 dec = pkt.size;
712                 /* decode the demuxed packet */
713 #ifdef HAVE_AVCODEC_DECODE_AUDIO2
714 /* prefer decode_audio2() if available */
715                 size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
716                 declen = avcodec_decode_audio2(
717                         avcc, (void*)((char*)outbuf+bufseek),
718                         &size, pkt.data, pkt.size);
719 #elif defined HAVE_AVCODEC_DECODE_AUDIO
720                 declen = avcodec_decode_audio(
721                         avcc, (void*)((char*)outbuf+bufseek),
722                         &size, pkt.data, pkt.size);
723 #else
724                 abort();
725 #endif
726
727                 if (dec > 0 && size > 0) {
728                         FFMPEG_DEBUG_AVF("pts:%lld dts:%lld psz:%d s:%d d:%d\n",
729                                          (long long int)pkt.pts,
730                                          (long long int)pkt.dts,
731                                          pkt.size, size, declen);
732
733                         /* memcpy(outbuf+bufseek, (char*)buffer, size); */
734                         bufseek += size;
735                 }
736
737                 FFMPEG_DEBUG_AVF("packet state: "
738                                  "pts:%lld dts:%lld psz:%d\n",
739                                  (long long int)pkt.pts,
740                                  (long long int)pkt.dts,
741                                  (int)pkt.size);
742                 av_free_packet(&pkt);
743         }
744         av_free_packet(&pkt);
745
746         FFMPEG_DEBUG_AVF("finished reading, bufseek=%ld, rf_status=%ld\n",
747                          (long int)bufseek, (long int)rf_status);
748
749         /* convert the pig */
750         size = bufseek/framesize;
751         MEDIA_SAMPLE_FORMAT_UPSAMPLE(fmt)(outbuf, outbuf, size*mtap->channels);
752
753         /* shutdown */
754         return size;
755 }
756
757 static void
758 media_ffmpeg_rewind(media_substream *mss)
759 {
760 /* rewind the stream to the first frame */
761         /* libavformat */
762         AVFormatContext *avfc;
763         AVStream *avst;
764         Lisp_Media_Stream *ms = mss->up;
765         int64_t start_time;
766         int res = 0;
767         long int si;
768
769         /* check the integrity of the media stream */
770         if (media_stream_driver(ms) != MYSELF)
771                 return;
772
773         FFMPEG_DEBUG_AVF("rewind substream 0x%lx\n",
774                          (long unsigned int)mss);
775
776         /* fetch the format context */
777         if (!(avfc = media_stream_data(ms)))
778                 return;
779
780         si = (long int)mss->substream_data;
781         avst = avfc->streams[si];
782         if ((start_time = avst->start_time) < 0) {
783                 start_time = 0;
784         }
785
786         FFMPEG_DEBUG_AVF("rewind (idx:%ld) to %lld\n",
787                          si, (long long int)start_time);
788
789         /* ... and reset the stream */
790         res = av_seek_frame(avfc, si, AV_NOPTS_VALUE, AVSEEK_FLAG_BACKWARD);
791
792         if (res >= 0) {
793                 FFMPEG_DEBUG_AVF("rewind succeeded\n");
794                 return;
795         } else {
796                 FFMPEG_DEBUG_AVF("rewind exitted with %d\n", res);
797                 return;
798         }
799 }
800
801 \f
802 /* NOTE:
803  * the size must be big enough to compensate the hardware audio buffersize size
804  */
805 #define SAMPLE_ARRAY_SIZE (2*65536)
806 #define VIDEO_PICTURE_QUEUE_SIZE 1
807 #define SUBPICTURE_QUEUE_SIZE 4
808 #define AUDIO_DIFF_AVG_NB   20
809 #define SDL_AUDIO_BUFFER_SIZE 1024
810
811 #define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
812 #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
813 #define MAX_SUBTITLEQ_SIZE (5 * 16 * 1024)
814
815 #define FF_ALLOC_EVENT   0
816 #define FF_REFRESH_EVENT 1
817 #define FF_QUIT_EVENT    2
818
819 typedef struct PacketQueue {
820         AVPacketList *first_pkt, *last_pkt;
821         int nb_packets;
822         int size;
823         int abort_request;
824         struct sxe_semaphore_s sem;
825 } PacketQueue;
826
827 typedef struct VideoPicture {
828         /* presentation time stamp for this picture */
829         double pts;
830         void *bmp;
831         int width, height; /* source height & width */
832         int allocated;
833 } VideoPicture;
834
835 typedef struct SubPicture {
836         double pts; /* presentation time stamp for this picture */
837         AVSubtitle sub;
838 } SubPicture;
839
840 typedef struct VideoState {
841         void *parse_tid;
842         void *video_tid;
843         AVInputFormat *iformat;
844         int no_background;
845         int abort_request;
846         int paused;
847         int last_paused;
848         int seek_req;
849         int seek_flags;
850         int64_t seek_pos;
851         AVFormatContext *ic;
852         int dtg_active_format;
853
854         int audio_stream;
855
856         int av_sync_type;
857         double external_clock; /* external clock base */
858         int64_t external_clock_time;
859
860         double audio_clock;
861         double audio_diff_cum; /* used for AV difference average computation */
862         double audio_diff_avg_coef;
863         double audio_diff_threshold;
864         int audio_diff_avg_count;
865         AVStream *audio_st;
866         PacketQueue audioq;
867         int audio_hw_buf_size;
868         /* samples output by the codec. we reserve more space for avsync
869            compensation */
870         uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]
871         /* fixme, this is very gcc centric, what's aligned(x) in icc? */
872         __attribute__((aligned(16)));
873         unsigned int audio_buf_size; /* in bytes */
874         int audio_buf_index; /* in bytes */
875         AVPacket audio_pkt;
876         uint8_t *audio_pkt_data;
877         int audio_pkt_size;
878
879         int show_audio; /* if true, display audio samples */
880         int16_t sample_array[SAMPLE_ARRAY_SIZE];
881         int sample_array_index;
882         int last_i_start;
883
884         void *subtitle_tid;
885         int subtitle_stream;
886         int subtitle_stream_changed;
887         AVStream *subtitle_st;
888         PacketQueue subtitleq;
889         SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
890         int subpq_size, subpq_rindex, subpq_windex;
891         struct sxe_semaphore_s subpq_sem;
892
893         double frame_timer;
894         double frame_last_pts;
895         double frame_last_delay;
896         /* pts of last decoded frame / predicted pts of next decoded frame */
897         double video_clock;
898         int video_stream;
899         AVStream *video_st;
900         PacketQueue videoq;
901         /* current displayed pts (different from video_clock
902          * if frame fifos are used */
903         double video_current_pts;
904         /* time (av_gettime) at which we updated video_current_pts - used
905          * to have running video pts */
906         int64_t video_current_pts_time;
907         VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
908         int pictq_size, pictq_rindex, pictq_windex;
909         struct sxe_semaphore_s pictq_sem;
910
911         /* QETimer *video_timer; */
912         char *filename;
913         size_t filelen;
914
915         int width, height, xleft, ytop;
916 } VideoState;
917
918 /* since we have only one decoding thread, we can use a global
919    variable instead of a thread local variable */
920 static VideoState *global_video_state;
921 AVPacket flush_pkt;
922
923 /* packet queue handling */
924 static void
925 packet_queue_init(PacketQueue *q)
926 {
927         memset(q, 0, sizeof(PacketQueue));
928         SXE_SEMAPH_INIT(&q->sem);
929 }
930
931 static void
932 packet_queue_flush(PacketQueue *q)
933 {
934         AVPacketList *pkt, *pkt1;
935
936         SXE_SEMAPH_LOCK(&q->sem);
937         for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
938                 pkt1 = pkt->next;
939                 av_free_packet(&pkt->pkt);
940                 av_freep(&pkt);
941         }
942         q->last_pkt = NULL;
943         q->first_pkt = NULL;
944         q->nb_packets = 0;
945         q->size = 0;
946         SXE_SEMAPH_UNLOCK(&q->sem);
947 }
948
949 static void
950 packet_queue_end(PacketQueue *q)
951 {
952         packet_queue_flush(q);
953         SXE_SEMAPH_FINI(&q->sem);
954 }
955
956 static int
957 packet_queue_put(PacketQueue *q, AVPacket *pkt)
958 {
959         AVPacketList *pkt1;
960
961         /* duplicate the packet */
962         if (pkt!=&flush_pkt && av_dup_packet(pkt) < 0)
963                 return -1;
964
965         pkt1 = av_malloc(sizeof(AVPacketList));
966         if (!pkt1)
967                 return -1;
968         pkt1->pkt = *pkt;
969         pkt1->next = NULL;
970
971
972         SXE_SEMAPH_LOCK(&q->sem);
973
974         if (!q->last_pkt)
975
976                 q->first_pkt = pkt1;
977         else
978                 q->last_pkt->next = pkt1;
979         q->last_pkt = pkt1;
980         q->nb_packets++;
981         q->size += pkt1->pkt.size;
982         /* XXX: should duplicate packet data in DV case */
983         SXE_SEMAPH_SIGNAL(&q->sem);
984         SXE_SEMAPH_UNLOCK(&q->sem);
985         return 0;
986 }
987
988 static void
989 packet_queue_abort(PacketQueue *q)
990 {
991         SXE_SEMAPH_LOCK(&q->sem);
992
993         q->abort_request = 1;
994
995         SXE_SEMAPH_SIGNAL(&q->sem);
996         SXE_SEMAPH_UNLOCK(&q->sem);
997 }
998
999 /* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
1000 static int
1001 packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
1002         __attribute__((unused));
1003
1004 static int
1005 packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
1006 {
1007         AVPacketList *pkt1;
1008         int ret;
1009
1010         SXE_SEMAPH_LOCK(&q->sem);
1011
1012         for(;;) {
1013                 if (q->abort_request) {
1014                         ret = -1;
1015                         break;
1016                 }
1017
1018                 pkt1 = q->first_pkt;
1019                 if (pkt1) {
1020                         q->first_pkt = pkt1->next;
1021                         if (!q->first_pkt)
1022                                 q->last_pkt = NULL;
1023                         q->nb_packets--;
1024                         q->size -= pkt1->pkt.size;
1025                         *pkt = pkt1->pkt;
1026                         av_free(pkt1);
1027                         ret = 1;
1028                         break;
1029                 } else if (!block) {
1030                         ret = 0;
1031                         break;
1032                 } else {
1033                         SXE_SEMAPH_WAIT(&q->sem);
1034                 }
1035         }
1036         SXE_SEMAPH_UNLOCK(&q->sem);
1037         return ret;
1038 }
1039
1040 static uint64_t global_video_pkt_pts = AV_NOPTS_VALUE;
1041
1042 static int
1043 my_get_buffer(struct AVCodecContext *c, AVFrame *pic)
1044 {
1045         int ret= avcodec_default_get_buffer(c, pic);
1046         uint64_t *pts= av_malloc(sizeof(uint64_t));
1047         *pts= global_video_pkt_pts;
1048         pic->opaque= pts;
1049         return ret;
1050 }
1051
1052 static void
1053 my_release_buffer(struct AVCodecContext *c, AVFrame *pic)
1054 {
1055         if(pic) av_freep(&pic->opaque);
1056         avcodec_default_release_buffer(c, pic);
1057 }
1058
1059
1060 static int
1061 stream_component_open(VideoState *is, int stream_index, Lisp_Media_Stream *ms)
1062 {
1063         /* stream stuff */
1064         media_substream *mss = NULL;
1065         AVFormatContext *ic = is->ic;
1066         AVCodecContext *enc;
1067         AVCodec *codec;
1068
1069         if (stream_index < 0 || (size_t)stream_index >= ic->nb_streams) {
1070                 return -1;
1071         }
1072         enc = ic->streams[stream_index]->codec;
1073
1074         /* prepare audio output */
1075         if (enc->codec_type == CODEC_TYPE_AUDIO) {
1076 #if 0
1077                 wanted_spec.freq = enc->sample_rate;
1078                 wanted_spec.format = AUDIO_S16SYS;
1079 #endif
1080                 /* hack for AC3. XXX: suppress that */
1081                 if (enc->channels > 2)
1082                         enc->channels = 2;
1083 #if 0
1084                 wanted_spec.channels = enc->channels;
1085                 wanted_spec.silence = 0;
1086                 wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
1087                 wanted_spec.callback = sdl_audio_callback;
1088                 wanted_spec.userdata = is;
1089 #endif
1090                 is->audio_hw_buf_size = 0 /* spec.size */;
1091         }
1092
1093         codec = avcodec_find_decoder(enc->codec_id);
1094         enc->debug_mv = 0 /* debug_mv */;
1095         enc->debug = 0 /* debug */;
1096         enc->workaround_bugs = 0 /* workaround_bugs */;
1097         enc->lowres = 0 /* lowres */;
1098         if (0 /* lowres */)
1099                 enc->flags |= CODEC_FLAG_EMU_EDGE;
1100         enc->idct_algo = FF_IDCT_AUTO; /* idct; */
1101         if (0 /* fast */)
1102                 enc->flags2 |= CODEC_FLAG2_FAST;
1103         enc->skip_frame = AVDISCARD_DEFAULT; /* skip_frame; */
1104         enc->skip_idct = AVDISCARD_DEFAULT; /* skip_idct; */
1105         enc->skip_loop_filter = AVDISCARD_DEFAULT; /* skip_loop_filter; */
1106 #if 0
1107         enc->error_resilience = FF_ER_CAREFUL; /* error_resilience; */
1108 #endif
1109         enc->error_concealment = 3; /* error_concealment; */
1110         if (!codec ||
1111             avcodec_open(enc, codec) < 0)
1112                 return -1;
1113         if (1 /* thread_count */ > 1)
1114                 avcodec_thread_init(enc, 1 /*thread_count*/);
1115         enc->thread_count= 1 /* thread_count */;
1116
1117         /* create a substream */
1118         mss = make_media_substream_append(ms);
1119
1120         switch ((unsigned int)enc->codec_type) {
1121         case CODEC_TYPE_AUDIO:
1122                 is->audio_stream = stream_index;
1123                 is->audio_st = ic->streams[stream_index];
1124                 is->audio_buf_size = 0;
1125                 is->audio_buf_index = 0;
1126
1127                 /* init averaging filter */
1128                 is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
1129                 is->audio_diff_avg_count = 0;
1130                 /* since we do not have a precise anough audio fifo fullness,
1131                    we correct audio sync only if larger than this threshold */
1132                 is->audio_diff_threshold =
1133                         2.0 * SDL_AUDIO_BUFFER_SIZE / enc->sample_rate;
1134
1135                 memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
1136                 packet_queue_init(&is->audioq);
1137
1138                 media_substream_type(mss) = MTYPE_AUDIO;
1139                 media_ffmpeg_analyse_audio(mss, is->ic, stream_index);
1140                 break;
1141         case CODEC_TYPE_VIDEO:
1142                 is->video_stream = stream_index;
1143                 is->video_st = ic->streams[stream_index];
1144
1145                 is->frame_last_delay = 40e-3;
1146                 {
1147                         int64_t tmp = av_gettime();
1148                         is->frame_timer = (double)tmp / 1000000.0f;
1149                 }
1150                 is->video_current_pts_time = av_gettime();
1151
1152                 packet_queue_init(&is->videoq);
1153                 is->video_tid = 0 /* SDL_CreateThread(video_thread, is) */;
1154
1155                 enc->    get_buffer=     my_get_buffer;
1156                 enc->release_buffer= my_release_buffer;
1157
1158                 media_substream_type(mss) = MTYPE_VIDEO;
1159                 media_ffmpeg_analyse_video(mss, is->ic, stream_index);
1160                 break;
1161         case CODEC_TYPE_SUBTITLE:
1162                 is->subtitle_stream = stream_index;
1163                 is->subtitle_st = ic->streams[stream_index];
1164                 packet_queue_init(&is->subtitleq);
1165
1166                 is->subtitle_tid = 0 /*SDL_CreateThread(subtitle_thread, is)*/;
1167                 break;
1168         default:
1169                 break;
1170         }
1171         return 0;
1172 }
1173
1174 static void
1175 stream_component_close(VideoState *is, int stream_index)
1176 {
1177         AVFormatContext *ic = is->ic;
1178         AVCodecContext *enc;
1179
1180         if (stream_index < 0 || (size_t)stream_index >= ic->nb_streams) {
1181                 return;
1182         }
1183         enc = ic->streams[stream_index]->codec;
1184
1185         switch ((unsigned int)enc->codec_type) {
1186         case CODEC_TYPE_AUDIO:
1187                 packet_queue_abort(&is->audioq);
1188 #if 0
1189                 SDL_CloseAudio();
1190 #endif
1191                 packet_queue_end(&is->audioq);
1192                 break;
1193         case CODEC_TYPE_VIDEO:
1194                 packet_queue_abort(&is->videoq);
1195
1196                 /* note: we also signal this mutex to make sure we deblock the
1197                    video thread in all cases */
1198                 SXE_SEMAPH_LOCK(&is->pictq_sem);
1199                 SXE_SEMAPH_SIGNAL(&is->pictq_sem);
1200                 SXE_SEMAPH_UNLOCK(&is->pictq_sem);
1201 #if 0
1202                 SDL_WaitThread(is->video_tid, NULL);
1203 #endif
1204                 packet_queue_end(&is->videoq);
1205                 break;
1206         case CODEC_TYPE_SUBTITLE:
1207                 packet_queue_abort(&is->subtitleq);
1208
1209                 /* note: we also signal this mutex to make sure we deblock the
1210                    video thread in all cases */
1211                 SXE_SEMAPH_LOCK(&is->subpq_sem);
1212                 is->subtitle_stream_changed = 1;
1213
1214                 SXE_SEMAPH_SIGNAL(&is->subpq_sem);
1215                 SXE_SEMAPH_UNLOCK(&is->subpq_sem);
1216 #if 0
1217                 SDL_WaitThread(is->subtitle_tid, NULL);
1218 #endif
1219                 packet_queue_end(&is->subtitleq);
1220                 break;
1221         default:
1222                 break;
1223         }
1224
1225         avcodec_close(enc);
1226         switch ((unsigned int)enc->codec_type) {
1227         case CODEC_TYPE_AUDIO:
1228                 is->audio_st = NULL;
1229                 is->audio_stream = -1;
1230                 break;
1231         case CODEC_TYPE_VIDEO:
1232                 is->video_st = NULL;
1233                 is->video_stream = -1;
1234                 break;
1235         case CODEC_TYPE_SUBTITLE:
1236                 is->subtitle_st = NULL;
1237                 is->subtitle_stream = -1;
1238                 break;
1239         default:
1240                 break;
1241         }
1242 }
1243
1244 static void
1245 dump_stream_info(const AVFormatContext *s)
1246 {
1247         if (s->track != 0)
1248                 fprintf(stderr, "Track: %d\n", s->track);
1249         if (s->title[0] != '\0')
1250                 fprintf(stderr, "Title: %s\n", s->title);
1251         if (s->author[0] != '\0')
1252                 fprintf(stderr, "Author: %s\n", s->author);
1253         if (s->copyright[0] != '\0')
1254                 fprintf(stderr, "Copyright: %s\n", s->copyright);
1255         if (s->comment[0] != '\0')
1256                 fprintf(stderr, "Comment: %s\n", s->comment);
1257         if (s->album[0] != '\0')
1258                 fprintf(stderr, "Album: %s\n", s->album);
1259         if (s->year != 0)
1260                 fprintf(stderr, "Year: %d\n", s->year);
1261         if (s->genre[0] != '\0')
1262                 fprintf(stderr, "Genre: %s\n", s->genre);
1263 }
1264
1265 enum {
1266         AV_SYNC_AUDIO_MASTER, /* default choice */
1267         AV_SYNC_VIDEO_MASTER,
1268         AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
1269 };
1270
1271 static VideoState *
1272 stream_open(char *filename, size_t filelen)
1273 {
1274         VideoState *is = xnew(VideoState);
1275         AVFormatParameters params, *ap = &params;
1276         int err = 0;
1277
1278         is->filename = filename;
1279         is->filelen = filelen;
1280         is->iformat = av_find_input_format("fmt");
1281         is->ytop = 0;
1282         is->xleft = 0;
1283
1284         /* initialise some semaphores */
1285         SXE_SEMAPH_INIT(&is->pictq_sem);
1286         SXE_SEMAPH_INIT(&is->subpq_sem);
1287
1288         is->av_sync_type = AV_SYNC_AUDIO_MASTER;
1289         is->parse_tid = 0; /* SDL_CreateThread(decode_thread, is); */
1290
1291         memset(ap, 0, sizeof(*ap));
1292         /* we force a pause when starting an RTSP stream */
1293         ap->initial_pause = 1;
1294
1295         ap->width = 0; /* frame_width; */
1296         ap->height= 0; /* frame_height; */
1297         ap->time_base= (AVRational){1, 25};
1298         ap->pix_fmt = PIX_FMT_NONE; /* frame_pix_fmt; */
1299
1300         err = av_open_input_file(&is->ic, is->filename, is->iformat, 0, ap);
1301         if (UNLIKELY(err < 0)) {
1302                 FFMPEG_DEBUG_AVF("Could not open \"%s\" (errno %d)\n",
1303                                  is->filename, err);
1304                 goto fail;
1305         }
1306
1307         return is;
1308
1309 fail:
1310         xfree(is);
1311         return NULL;
1312 }
1313
1314 /* main analysis function */
1315 static ms_driver_data_t
1316 new_media_ffmpeg_open(Lisp_Media_Stream *ms)
1317 {
1318         /* the final result */
1319         VideoState *vs = NULL;
1320         int err = 0, use_play = 0;
1321         int wanted_audio_stream = 0;
1322         int wanted_video_stream = 0;
1323         int video_index = -1, audio_index = -1;
1324         mkind_file_properties *mkfp = NULL;
1325         char *file;
1326         int file_len = 0;
1327
1328         /* initialise */
1329         av_register_all();
1330
1331         if (media_stream_kind(ms) != MKIND_FILE) {
1332                 return NULL;
1333         }
1334
1335         /* open the file */
1336         mkfp = media_stream_kind_properties(ms).fprops;
1337         TO_EXTERNAL_FORMAT(LISP_STRING, mkfp->filename,
1338                            MALLOC, (file, file_len), Qnil);
1339         if (UNLIKELY((vs = stream_open(file, file_len)) == NULL)) {
1340                 media_stream_set_meths(ms, NULL);
1341                 media_stream_driver(ms) = MDRIVER_UNKNOWN;
1342                 return NULL;
1343         }
1344
1345 #ifdef CONFIG_RTSP_DEMUXER
1346         use_play = (ic->iformat == &rtsp_demuxer);
1347 #else
1348         use_play = 0;
1349 #endif
1350
1351         if (1 /* genpts */) {
1352                 vs->ic->flags |= AVFMT_FLAG_GENPTS;
1353         }
1354
1355         if (!use_play) {
1356                 err = av_find_stream_info(vs->ic);
1357                 if (err < 0) {
1358                         FFMPEG_DEBUG_AVF("\"%s\": "
1359                                          "could not find codec parameters\n",
1360                                          vs->filename);
1361                         goto fail;
1362                 }
1363                 /* FIXME hack,
1364                  * ffplay maybe should not use url_feof() to test for the end */
1365 #if defined FFMPEG_URL_FOPEN_BIOCTX_STAR_STAR
1366                 vs->ic->pb->eof_reached = 0;
1367 #elif defined FFMPEG_URL_FOPEN_BIOCTX_STAR
1368                 vs->ic->pb.eof_reached = 0;
1369 #endif
1370         }
1371
1372         /* now we can begin to play (RTSP stream only) */
1373         av_read_play(vs->ic);
1374
1375         if (use_play) {
1376                 err = av_find_stream_info(vs->ic);
1377                 if (err < 0) {
1378                         FFMPEG_DEBUG_AVF("\"%s\": "
1379                                          "could not find codec parameters\n",
1380                                          vs->filename);
1381                         goto fail;
1382                 }
1383         }
1384
1385         for (size_t i = 0; i < vs->ic->nb_streams; i++) {
1386                 AVCodecContext *enc = vs->ic->streams[i]->codec;
1387                 switch ((unsigned int)enc->codec_type) {
1388                 case CODEC_TYPE_AUDIO:
1389                         if ((audio_index < 0 || wanted_audio_stream-- > 0)) {
1390                                 audio_index = i;
1391                         }
1392                         break;
1393                 case CODEC_TYPE_VIDEO:
1394                         if ((video_index < 0 || wanted_video_stream-- > 0)) {
1395                                 video_index = i;
1396                         }
1397                         break;
1398                 default:
1399                         break;
1400                 }
1401         }
1402         if (1 /* show_status */) {
1403                 dump_format(vs->ic, 0, vs->filename, 0);
1404                 dump_stream_info(vs->ic);
1405         }
1406
1407         /* open the streams */
1408         if (audio_index >= 0) {
1409                 stream_component_open(vs, audio_index, ms);
1410         }
1411
1412         if (video_index >= 0) {
1413                 stream_component_open(vs, video_index, ms);
1414         } else {
1415                 vs->show_audio = 1;
1416         }
1417
1418         if (vs->video_stream < 0 && vs->audio_stream < 0) {
1419                 FFMPEG_DEBUG_AVF("\"%s\": could not open codecs\n",
1420                                  vs->filename);
1421                 goto fail;
1422         }
1423
1424         /* keep the context */
1425         media_stream_data(ms) = vs;
1426         /* set me as driver indicator */
1427         media_stream_driver(ms) = MYSELF;
1428
1429         return vs;
1430
1431 fail:
1432         xfree(vs);
1433         return NULL;
1434 }
1435
1436 static size_t
1437 new_media_ffmpeg_read(media_substream *mss, void *outbuf, size_t length)
1438 {
1439         VideoState *is = media_stream_data(mss->up); /* was arg */
1440         int ret;
1441         AVPacket pkt1, *pkt = &pkt1;
1442 #if 0
1443         /* stuff normally set on the command line */
1444         int64_t start_time = AV_NOPTS_VALUE;
1445 #endif
1446         av_init_packet(&flush_pkt);
1447         FFMPEG_CRITICAL("read\n");
1448
1449 #if 0
1450         /* if seeking requested, we execute it */
1451         if (start_time != AV_NOPTS_VALUE) {
1452                 int64_t timestamp;
1453
1454                 timestamp = start_time;
1455                 /* add the stream start time */
1456                 if (ic->start_time != AV_NOPTS_VALUE)
1457                         timestamp += ic->start_time;
1458                 ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
1459                 if (ret < 0) {
1460                         fprintf(stderr, "%s: could not seek to position %0.3f\n",
1461                                 is->filename, (double)timestamp / AV_TIME_BASE);
1462                 }
1463         }
1464 #endif
1465
1466         for(;;) {
1467                 if (is->abort_request) {
1468                         FFMPEG_DEBUG_AVF("\n");
1469                         break;
1470                 }
1471                 if (is->paused != is->last_paused) {
1472                         is->last_paused = is->paused;
1473                         if (is->paused)
1474                                 av_read_pause(is->ic);
1475                         else
1476                                 av_read_play(is->ic);
1477                 }
1478 #ifdef CONFIG_RTSP_DEMUXER
1479                 if (is->paused && is->ic->iformat == &rtsp_demuxer) {
1480                         /* wait 10 ms to avoid trying to get another packet */
1481                         /* XXX: horrible */
1482                         SDL_Delay(10);
1483                         continue;
1484                 }
1485 #endif
1486                 if (is->seek_req) {
1487                         int stream_index= -1;
1488                         int64_t seek_target= is->seek_pos;
1489
1490                         if (is->video_stream >= 0)
1491                                 stream_index = is->video_stream;
1492                         else if (is->audio_stream >= 0)
1493                                 stream_index = is->audio_stream;
1494                         else if (is->subtitle_stream >= 0)
1495                                 stream_index = is->subtitle_stream;
1496
1497                         if (stream_index >= 0) {
1498                                 seek_target = av_rescale_q(
1499                                         seek_target, AV_TIME_BASE_Q,
1500                                         is->ic->streams[stream_index]->
1501                                         time_base);
1502                         }
1503
1504                         ret = av_seek_frame(is->ic, stream_index,
1505                                             seek_target, is->seek_flags);
1506                         if (ret < 0) {
1507                                 FFMPEG_DEBUG_AVS("\"%s: \""
1508                                                  "error while seeking\n",
1509                                                  is->ic->filename);
1510                         } else {
1511                                 if (is->audio_stream >= 0) {
1512                                         packet_queue_flush(&is->audioq);
1513                                         packet_queue_put(&is->audioq, &flush_pkt);
1514                                 }
1515                                 if (is->subtitle_stream >= 0) {
1516                                         packet_queue_flush(&is->subtitleq);
1517                                         packet_queue_put(&is->subtitleq, &flush_pkt);
1518                                 }
1519                                 if (is->video_stream >= 0) {
1520                                         packet_queue_flush(&is->videoq);
1521                                         packet_queue_put(&is->videoq, &flush_pkt);
1522                                 }
1523                         }
1524                         is->seek_req = 0;
1525                 }
1526
1527                 /* if the queue are full, no need to read more */
1528                 if (is->audioq.size > MAX_AUDIOQ_SIZE ||
1529                     is->videoq.size > MAX_VIDEOQ_SIZE ||
1530                     is->subtitleq.size > MAX_SUBTITLEQ_SIZE ||
1531 #if defined FFMPEG_URL_FOPEN_BIOCTX_STAR_STAR
1532                     url_feof(is->ic->pb)
1533 #elif defined FFMPEG_URL_FOPEN_BIOCTX_STAR
1534                     url_feof(&is->ic->pb)
1535 #endif
1536                         ) {
1537                         /* wait 10 ms */
1538                         usleep(10);
1539                         continue;
1540                 }
1541                 ret = av_read_frame(is->ic, pkt);
1542                 if (ret < 0) {
1543                         if (url_ferror(
1544 #if defined FFMPEG_URL_FOPEN_BIOCTX_STAR_STAR
1545                                     is->ic->pb
1546 #elif defined FFMPEG_URL_FOPEN_BIOCTX_STAR
1547                                     &is->ic->pb
1548 #endif
1549                                     ) == 0) {
1550                                 usleep(100); /* wait for user event */
1551                                 continue;
1552                         } else
1553                                 break;
1554                 }
1555                 if (pkt->stream_index == is->audio_stream) {
1556                         packet_queue_put(&is->audioq, pkt);
1557                 } else if (pkt->stream_index == is->video_stream) {
1558                         packet_queue_put(&is->videoq, pkt);
1559                 } else if (pkt->stream_index == is->subtitle_stream) {
1560                         packet_queue_put(&is->subtitleq, pkt);
1561                 } else {
1562                         av_free_packet(pkt);
1563                 }
1564         }
1565         /* wait until the end */
1566         while (!is->abort_request) {
1567                 usleep(100);
1568         }
1569
1570         ret = 0;
1571         /* disable interrupting */
1572         global_video_state = NULL;
1573
1574         /* close each stream */
1575         if (is->audio_stream >= 0)
1576                 stream_component_close(is, is->audio_stream);
1577         if (is->video_stream >= 0)
1578                 stream_component_close(is, is->video_stream);
1579         if (is->subtitle_stream >= 0)
1580                 stream_component_close(is, is->subtitle_stream);
1581         if (is->ic) {
1582                 av_close_input_file(is->ic);
1583                 is->ic = NULL; /* safety */
1584         }
1585         url_set_interrupt_cb(NULL);
1586
1587         if (ret != 0) {
1588 #if 0
1589                 SDL_Event event;
1590
1591                 event.type = FF_QUIT_EVENT;
1592                 event.user.data1 = is;
1593                 SDL_PushEvent(&event);
1594 #endif
1595         }
1596         return 0;
1597 }
1598
1599 static void
1600 new_media_ffmpeg_rewind(media_substream *mss)
1601 {
1602 /* rewind the stream to the first frame */
1603         /* libavformat */
1604         AVFormatContext *avfc;
1605         AVStream *avst;
1606         Lisp_Media_Stream *ms = mss->up;
1607         int64_t start_time;
1608         int res = 0;
1609         long int si;
1610
1611         /* check the integrity of the media stream */
1612         if (media_stream_driver(ms) != MYSELF)
1613                 return;
1614
1615         FFMPEG_DEBUG_AVF("rewind substream 0x%lx\n",
1616                          (long unsigned int)mss);
1617
1618         /* fetch the format context */
1619         if (!(avfc = media_stream_data(ms)))
1620                 return;
1621
1622         si = (long int)mss->substream_data;
1623         avst = avfc->streams[si];
1624         if ((start_time = avst->start_time) < 0) {
1625                 start_time = 0;
1626         }
1627
1628         FFMPEG_DEBUG_AVF("rewind (idx:%ld) to %lld\n",
1629                          si, (long long int)start_time);
1630
1631         /* ... and reset the stream */
1632         res = av_seek_frame(avfc, -1, start_time, AVSEEK_FLAG_BACKWARD);
1633
1634         if (res >= 0) {
1635                 FFMPEG_DEBUG_AVF("rewind succeeded\n");
1636                 return;
1637         } else {
1638                 FFMPEG_DEBUG_AVF("rewind exitted with %d\n", res);
1639                 return;
1640         }
1641 }
1642
1643 \f
1644 Lisp_Object
1645 media_ffmpeg_available_formats(void)
1646 {
1647         Lisp_Object formats;
1648         AVInputFormat *avif;
1649
1650         formats = Qnil;
1651
1652         av_register_all();
1653         avif = first_iformat;
1654
1655         while (avif) {
1656                 if (avif->name) {
1657                         const Lisp_Object fmtname =
1658                                 Fintern(build_string(avif->name), Qnil);
1659                         formats = Fcons(fmtname, formats);
1660                 }
1661                 avif = avif->next;
1662         }
1663
1664         return formats;
1665 }
1666
1667 #undef MYSELF