ffmpeg: define fallback macro AV_VERSION_INT()
[deadbeef-zykure:deadbeef.git] / plugins / ffmpeg / ffmpeg.c
1 /*
2     DeaDBeeF - ultimate music player for GNU/Linux systems with X11
3     Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
4
5     This program is free software; you can redistribute it and/or
6     modify it under the terms of the GNU General Public License
7     as published by the Free Software Foundation; either version 2
8     of the License, or (at your option) any later version.
9     
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14     
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 //#include <alloca.h>
24 #include <errno.h>
25
26 #include "../../deadbeef.h"
27
28 #if !FFMPEG_OLD
29
30 #include <libavformat/avformat.h>
31 #include <libavcodec/avcodec.h>
32 #include <libavutil/avutil.h>
33 #include <libavutil/avstring.h>
34
35 #else
36
37 #include <ffmpeg/avformat.h>
38 #include <ffmpeg/avcodec.h>
39 #include <ffmpeg/avutil.h>
40 #include <ffmpeg/avstring.h>
41 #define AVERROR_EOF AVERROR(EPIPE)
42
43 #if LIBAVFORMAT_VERSION_MAJOR < 53
44 #define av_register_protocol register_protocol
45 #endif
46
47 #ifndef AV_VERSION_INT
48 #define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
49 #endif
50
51 #endif
52
53 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
54 #define trace(fmt,...)
55
56 #define min(x,y) ((x)<(y)?(x):(y))
57 #define max(x,y) ((x)>(y)?(x):(y))
58
59 static DB_decoder_t plugin;
60 static DB_functions_t *deadbeef;
61
62 #define DEFAULT_EXTS "m4a;wma;aa3;oma;ac3;vqf;amr"
63
64 #define EXT_MAX 100
65
66 static char * exts[EXT_MAX] = {NULL};
67
68 enum {
69     FT_ALAC = 0,
70     FT_WMA = 1,
71     FT_ATRAC3 = 2,
72     FT_VQF = 3,
73     FT_AC3 = 4,
74     FT_AMR = 5,
75     FT_UNKNOWN = 5
76 };
77
78 #define FF_PROTOCOL_NAME "deadbeef"
79
80 typedef struct {
81     DB_fileinfo_t info;
82     AVCodec *codec;
83     AVCodecContext *ctx;
84     AVFormatContext *fctx;
85     AVPacket pkt;
86     int stream_id;
87
88     int left_in_packet;
89     int have_packet;
90
91     char *buffer; // must be AVCODEC_MAX_AUDIO_FRAME_SIZE
92     int left_in_buffer;
93
94     int startsample;
95     int endsample;
96     int currentsample;
97 } ffmpeg_info_t;
98
99 static DB_playItem_t *current_track;
100 static DB_fileinfo_t *current_info;
101
102 static DB_fileinfo_t *
103 ffmpeg_open (uint32_t hints) {
104     DB_fileinfo_t *_info = malloc (sizeof (ffmpeg_info_t));
105     memset (_info, 0, sizeof (ffmpeg_info_t));
106     return _info;
107 }
108
109 static int
110 ffmpeg_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
111     ffmpeg_info_t *info = (ffmpeg_info_t *)_info;
112     trace ("ffmpeg init %s\n", deadbeef->pl_find_meta (it, ":URI"));
113     // prepare to decode the track
114     // return -1 on failure
115
116     int ret;
117     int l = strlen (deadbeef->pl_find_meta (it, ":URI"));
118     char *uri = alloca (l + sizeof (FF_PROTOCOL_NAME) + 1);
119     int i;
120
121     // construct uri
122     memcpy (uri, FF_PROTOCOL_NAME, sizeof (FF_PROTOCOL_NAME)-1);
123     memcpy (uri + sizeof (FF_PROTOCOL_NAME)-1, ":", 1);
124     memcpy (uri + sizeof (FF_PROTOCOL_NAME), deadbeef->pl_find_meta (it, ":URI"), l);
125     uri[sizeof (FF_PROTOCOL_NAME) + l] = 0;
126     trace ("ffmpeg: uri: %s\n", uri);
127
128     // open file
129     trace ("\033[0;31mffmpeg av_open_input_file\033[37;0m\n");
130     current_track = it;
131     current_info = _info;
132     if ((ret = av_open_input_file(&info->fctx, uri, NULL, 0, NULL)) < 0) {
133         current_track = NULL;
134         trace ("\033[0;31minfo->fctx is %p, ret %d/%s\033[0;31m\n", info->fctx, ret, strerror(-ret));
135         return -1;
136     }
137     trace ("\033[0;31mav_open_input_file done, ret=%d\033[0;31m\n", ret);
138     current_track = NULL;
139     current_info = NULL;
140
141     trace ("\033[0;31mffmpeg av_find_stream_info\033[37;0m\n");
142     info->stream_id = -1;
143     av_find_stream_info(info->fctx);
144     for (i = 0; i < info->fctx->nb_streams; i++)
145     {
146         info->ctx = info->fctx->streams[i]->codec;
147         if (info->ctx->codec_type ==
148 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
149             AVMEDIA_TYPE_AUDIO)
150 #else
151             CODEC_TYPE_AUDIO)
152 #endif
153         {
154             info->codec = avcodec_find_decoder (info->ctx->codec_id);
155             if (info->codec != NULL) {
156                 info->stream_id = i;
157                 break;
158             }
159         }
160     }
161
162     if (info->codec == NULL)
163     {
164         trace ("ffmpeg can't decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
165         return -1;
166     }
167     trace ("ffmpeg can decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
168     trace ("ffmpeg: codec=%s, stream=%d\n", info->codec->name, i);
169
170     if (avcodec_open (info->ctx, info->codec) < 0) {
171         trace ("ffmpeg: avcodec_open failed\n");
172         return -1;
173     }
174
175     deadbeef->pl_replace_meta (it, ":FILETYPE", info->codec->name);
176
177     int bps = av_get_bits_per_sample_format (info->ctx->sample_fmt);
178     int samplerate = info->ctx->sample_rate;
179     float duration = info->fctx->duration / (float)AV_TIME_BASE;
180     trace ("ffmpeg: bits per sample is %d\n", bps);
181     trace ("ffmpeg: samplerate is %d\n", samplerate);
182     trace ("ffmpeg: duration is %lld/%fsec\n", info->fctx->duration, duration);
183
184     int totalsamples = info->fctx->duration * samplerate / AV_TIME_BASE;
185     info->left_in_packet = 0;
186     info->left_in_buffer = 0;
187
188     memset (&info->pkt, 0, sizeof (info->pkt));
189     info->have_packet = 0;
190
191     int err = posix_memalign ((void **)&info->buffer, 16, AVCODEC_MAX_AUDIO_FRAME_SIZE);
192     if (err) {
193         fprintf (stderr, "ffmpeg: failed to allocate buffer memory\n");
194         return -1;
195     }
196
197     // fill in mandatory plugin fields
198     _info->plugin = &plugin;
199     _info->readpos = 0;
200     _info->fmt.bps = bps;
201     _info->fmt.channels = info->ctx->channels;
202     _info->fmt.samplerate = samplerate;
203
204
205     int64_t layout = info->ctx->channel_layout;
206     if (layout != 0, 0) {
207         _info->fmt.channelmask = layout;
208     }
209     else {
210         for (int i = 0; i < _info->fmt.channels; i++) {
211             _info->fmt.channelmask |= 1 << i;
212         }
213     }
214
215     // subtrack info
216     info->currentsample = 0;
217     if (it->endsample > 0) {
218         info->startsample = it->startsample;
219         info->endsample = it->endsample;
220         plugin.seek_sample (_info, 0);
221     }
222     else {
223         info->startsample = 0;
224         info->endsample = totalsamples - 1;
225     }
226     return 0;
227 }
228
229 static void
230 ffmpeg_free (DB_fileinfo_t *_info) {
231     trace ("ffmpeg: free\n");
232     ffmpeg_info_t *info = (ffmpeg_info_t*)_info;
233     if (info) {
234         if (info->buffer) {
235             free (info->buffer);
236         }
237         // free everything allocated in _init and _read
238         if (info->have_packet) {
239             av_free_packet (&info->pkt);
240         }
241         if (info->ctx) {
242             avcodec_close (info->ctx);
243         }
244         if (info->fctx) {
245             av_close_input_file (info->fctx);
246         }
247         free (info);
248     }
249 }
250
251 static int
252 ffmpeg_read (DB_fileinfo_t *_info, char *bytes, int size) {
253     trace ("ffmpeg_read_int16 %d\n", size);
254     ffmpeg_info_t *info = (ffmpeg_info_t*)_info;
255
256     int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
257
258     if (info->endsample >= 0 && info->currentsample + size / samplesize > info->endsample) {
259         size = (info->endsample - info->currentsample + 1) * samplesize;
260         if (size <= 0) {
261             return 0;
262         }
263     }
264
265     int initsize = size;
266
267     int encsize = 0;
268     int decsize = 0;
269
270     while (size > 0) {
271
272         if (info->left_in_buffer > 0) {
273 //            int sz = min (size, info->left_in_buffer);
274             int nsamples = size / samplesize;
275             int nsamples_buf = info->left_in_buffer / samplesize;
276             nsamples = min (nsamples, nsamples_buf);
277             int sz = nsamples * samplesize;
278             memcpy (bytes, info->buffer, nsamples*samplesize);
279             bytes += nsamples * samplesize;
280             size -= nsamples * samplesize;
281             if (sz != info->left_in_buffer) {
282                 memmove (info->buffer, info->buffer+sz, info->left_in_buffer-sz);
283             }
284             info->left_in_buffer -= sz;
285         }
286
287         while (info->left_in_packet > 0 && size > 0) {
288             int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
289             int len;
290             //trace ("in: out_size=%d(%d), size=%d\n", out_size, AVCODEC_MAX_AUDIO_FRAME_SIZE, size);
291 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,25,0)
292             len = avcodec_decode_audio3 (info->ctx, (int16_t *)info->buffer, &out_size, &info->pkt);
293 #else
294             len = avcodec_decode_audio2 (info->ctx, (int16_t *)info->buffer, &out_size, info->pkt.data, info->pkt.size);
295 #endif
296             trace ("out: out_size=%d, len=%d\n", out_size, len);
297             if (len <= 0) {
298                 break;
299             }
300             encsize += len;
301             decsize += out_size;
302             info->left_in_packet -= len;
303             info->left_in_buffer = out_size;
304         }
305         if (size == 0) {
306             break;
307         }
308
309         // read next packet
310         if (info->have_packet) {
311             av_free_packet (&info->pkt);
312             info->have_packet = 0;
313         }
314         int errcount = 0;
315         for (;;) {
316             int ret;
317             if ((ret = av_read_frame (info->fctx, &info->pkt)) < 0) {
318                 trace ("ffmpeg: error %d\n", ret);
319                 if (ret == AVERROR_EOF || ret == -1) {
320                     ret = -1;
321                     break;
322                 }
323                 else {
324                     if (++errcount > 4) {
325                         trace ("ffmpeg: too many errors in a row (last is %d); interrupting stream\n", ret);
326                         ret = -1;
327                         break;
328                     }
329                     else {
330                         continue;
331                     }
332                 }
333             }
334             else {
335                 trace ("av packet size: %d, numframes: %d\n", info->pkt.size, ret);
336                 errcount = 0;
337             }
338             if (ret == -1) {
339                 break;
340             }
341             //trace ("idx:%d, stream:%d\n", info->pkt.stream_index, info->stream_id);
342             if (info->pkt.stream_index != info->stream_id) {
343                 av_free_packet (&info->pkt);
344                 continue;
345             }
346             //trace ("got packet: size=%d\n", info->pkt.size);
347             info->have_packet = 1;
348             info->left_in_packet = info->pkt.size;
349
350             if (info->pkt.duration > 0) {
351                 AVRational *time_base = &info->fctx->streams[info->stream_id]->time_base;
352                 float sec = (float)info->pkt.duration * time_base->num / time_base->den;
353                 int bitrate = info->pkt.size/sec;
354                 if (bitrate > 0) {
355                     // FIXME: seems like duration translation is wrong
356                     deadbeef->streamer_set_bitrate (bitrate / 100);
357                 }
358             }
359
360             break;
361         }
362         if (!info->have_packet) {
363             break;
364         }
365     }
366
367     info->currentsample += (initsize-size) / samplesize;
368     _info->readpos = (float)info->currentsample / _info->fmt.samplerate;
369
370     return initsize-size;
371 }
372
373 static int
374 ffmpeg_seek_sample (DB_fileinfo_t *_info, int sample) {
375     ffmpeg_info_t *info = (ffmpeg_info_t*)_info;
376     // seek to specified sample (frame)
377     // return 0 on success
378     // return -1 on failure
379     if (info->have_packet) {
380         av_free_packet (&info->pkt);
381         info->have_packet = 0;
382     }
383     sample += info->startsample;
384     int64_t tm = (int64_t)sample/ _info->fmt.samplerate * AV_TIME_BASE;
385     trace ("ffmpeg: seek to sample: %d, t: %d\n", sample, (int)tm);
386     info->left_in_packet = 0;
387     info->left_in_buffer = 0;
388     if (av_seek_frame (info->fctx, -1, tm, AVSEEK_FLAG_ANY) < 0) {
389         trace ("ffmpeg: seek error\n");
390         return -1;
391     }
392     
393     // update readpos
394     info->currentsample = sample;
395     _info->readpos = (float)(sample - info->startsample) / _info->fmt.samplerate;
396     return 0;
397 }
398
399 static int
400 ffmpeg_seek (DB_fileinfo_t *_info, float time) {
401     ffmpeg_info_t *info = (ffmpeg_info_t*)_info;
402     // seek to specified time in seconds
403     // return 0 on success
404     // return -1 on failure
405     return ffmpeg_seek_sample (_info, time * _info->fmt.samplerate);
406 }
407
408 static const char *map[] = {
409     "artist", "artist",
410     "title", "title",
411     "album", "album",
412     "track", "track",
413     "date", "year",
414     "genre", "genre",
415     "comment", "comment",
416     "performer", "performer",
417     "album_artist", "band",
418     "composer", "composer",
419     "encoder", "encoder",
420     "encoded_by", "vendor",
421     "disc", "disc",
422     "copyright", "copyright",
423     "tracktotal", "numtracks",
424     "publisher", "publisher",
425     NULL
426 };
427
428 static int
429 ffmpeg_read_metadata_internal (DB_playItem_t *it, AVFormatContext *fctx) {
430 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52,43,0)
431     if (!strlen (fctx->title)) {
432         // title is empty, this call will set track title to filename without extension
433         deadbeef->pl_add_meta (it, "title", NULL);
434     }
435     else {
436         deadbeef->pl_add_meta (it, "title", fctx->title);
437     }
438     deadbeef->pl_add_meta (it, "artist", fctx->author);
439     deadbeef->pl_add_meta (it, "album", fctx->album);
440     deadbeef->pl_add_meta (it, "copyright", fctx->copyright);
441     deadbeef->pl_add_meta (it, "comment", fctx->comment);
442     deadbeef->pl_add_meta (it, "genre", fctx->genre);
443
444     char tmp[10];
445     snprintf (tmp, sizeof (tmp), "%d", fctx->year);
446     deadbeef->pl_add_meta (it, "year", tmp);
447     snprintf (tmp, sizeof (tmp), "%d", fctx->track);
448     deadbeef->pl_add_meta (it, "track", tmp);
449 #else
450 // read using other means?
451 // av_metadata_get?
452     AVMetadata *md = fctx->metadata;
453
454     for (int m = 0; map[m]; m += 2) {
455         AVMetadataTag *tag = NULL;
456         do {
457             tag = av_metadata_get (md, map[m], tag, AV_METADATA_DONT_STRDUP_KEY | AV_METADATA_DONT_STRDUP_VAL);
458             if (tag) {
459                 deadbeef->pl_append_meta (it, map[m+1], tag->value);
460             }
461         } while (tag);
462     }
463     deadbeef->pl_add_meta (it, "title", NULL);
464 #endif
465     return 0;
466 }
467
468 static DB_playItem_t *
469 ffmpeg_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
470     trace ("ffmpeg_insert %s\n", fname);
471     // read information from the track
472     // load/process cuesheet if exists
473     // insert track into playlist
474     // return track pointer on success
475     // return NULL on failure
476
477     AVCodec *codec = NULL;
478     AVCodecContext *ctx = NULL;
479     AVFormatContext *fctx = NULL;
480     int ret;
481     int l = strlen (fname);
482     char *uri = alloca (l + sizeof (FF_PROTOCOL_NAME) + 1);
483     int i;
484
485     // construct uri
486     memcpy (uri, FF_PROTOCOL_NAME, sizeof (FF_PROTOCOL_NAME)-1);
487     memcpy (uri + sizeof (FF_PROTOCOL_NAME)-1, ":", 1);
488     memcpy (uri + sizeof (FF_PROTOCOL_NAME), fname, l);
489     uri[sizeof (FF_PROTOCOL_NAME) + l] = 0;
490     trace ("ffmpeg: uri: %s\n", uri);
491
492     // open file
493     if ((ret = av_open_input_file(&fctx, uri, NULL, 0, NULL)) < 0) {
494         trace ("fctx is %p, ret %d/%s", fctx, ret, strerror(-ret));
495         return NULL;
496     }
497
498     av_find_stream_info(fctx);
499     for (i = 0; i < fctx->nb_streams; i++)
500     {
501         ctx = fctx->streams[i]->codec;
502         if (ctx->codec_type ==
503 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
504             AVMEDIA_TYPE_AUDIO)
505 #else
506             CODEC_TYPE_AUDIO)
507 #endif
508         {
509             codec = avcodec_find_decoder(ctx->codec_id);
510             if (codec != NULL && !strcasecmp (codec->name, "alac")) { // only open alac streams
511                 break;
512             }
513         }
514     }
515 //    AVStream *stream = fctx->streams[i];
516
517     if (codec == NULL)
518     {
519         trace ("ffmpeg can't decode %s\n", fname);
520         av_close_input_file(fctx);
521         return NULL;
522     }
523     trace ("ffmpeg can decode %s\n", fname);
524     trace ("ffmpeg: codec=%s, stream=%d\n", codec->name, i);
525
526     if (avcodec_open (ctx, codec) < 0) {
527         trace ("ffmpeg: avcodec_open failed\n");
528         av_close_input_file(fctx);
529         return NULL;
530     }
531
532     int bps = av_get_bits_per_sample_format (ctx->sample_fmt);
533     int samplerate = ctx->sample_rate;
534     float duration = fctx->duration / (float)AV_TIME_BASE;
535 //    float duration = stream->duration * stream->time_base.num / (float)stream->time_base.den;
536     trace ("ffmpeg: bits per sample is %d\n", bps);
537     trace ("ffmpeg: samplerate is %d\n", samplerate);
538     trace ("ffmpeg: duration is %f\n", duration);
539
540     int totalsamples = fctx->duration * samplerate / AV_TIME_BASE;
541
542     DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
543     deadbeef->pl_replace_meta (it, ":FILETYPE", codec->name);
544
545     if (!deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI"))) {
546         deadbeef->plt_set_item_duration (plt, it, -1);
547     }
548     else {
549         deadbeef->plt_set_item_duration (plt, it, duration);
550     }
551
552     // add metainfo
553     ffmpeg_read_metadata_internal (it, fctx);
554     
555     int64_t fsize = -1;
556
557     DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
558     if (fp) {
559         if (!fp->vfs->is_streaming ()) {
560             fsize = deadbeef->fgetlength (fp);
561         }
562         deadbeef->fclose (fp);
563     }
564
565     if (fsize >= 0 && duration > 0) {
566         char s[100];
567         snprintf (s, sizeof (s), "%lld", fsize);
568         deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
569         snprintf (s, sizeof (s), "%d", av_get_bits_per_sample_format (ctx->sample_fmt));
570         deadbeef->pl_add_meta (it, ":BPS", s);
571         snprintf (s, sizeof (s), "%d", ctx->channels);
572         deadbeef->pl_add_meta (it, ":CHANNELS", s);
573         snprintf (s, sizeof (s), "%d", samplerate);
574         deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
575         int br = (int)roundf(fsize / duration * 8 / 1000);
576         snprintf (s, sizeof (s), "%d", br);
577         deadbeef->pl_add_meta (it, ":BITRATE", s);
578     }
579
580     // free decoder
581     avcodec_close (ctx);
582     av_close_input_file(fctx);
583
584     // external cuesheet
585     DB_playItem_t *cue = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
586     if (cue) {
587         deadbeef->pl_item_unref (it);
588         deadbeef->pl_item_unref (cue);
589         return cue;
590     }
591     // now the track is ready, insert into playlist
592     after = deadbeef->plt_insert_item (plt, after, it);
593     deadbeef->pl_item_unref (it);
594     return after;
595 }
596
597 // vfs wrapper for ffmpeg
598 static int
599 ffmpeg_vfs_open(URLContext *h, const char *filename, int flags)
600 {
601     DB_FILE *f;
602     av_strstart(filename, FF_PROTOCOL_NAME ":", &filename);
603     if (flags & URL_WRONLY) {
604         return -ENOENT;
605     } else {
606         f = deadbeef->fopen (filename);
607     }
608
609     if (f == NULL)
610         return -ENOENT;
611
612     if (f->vfs->is_streaming ()) {
613         deadbeef->fset_track (f, current_track);
614         if (current_info) {
615             current_info->file = f;
616         }
617     }
618
619     h->priv_data = f;
620     return 0;
621 }
622
623 static int
624 ffmpeg_vfs_read(URLContext *h, unsigned char *buf, int size)
625 {
626     trace ("ffmpeg_vfs_read %d\n", size);
627     int res = deadbeef->fread (buf, 1, size, h->priv_data);
628     return res;
629 }
630
631 static int
632 ffmpeg_vfs_write(URLContext *h, const unsigned char *buf, int size)
633 {
634     return -1;
635 }
636
637 static int64_t
638 ffmpeg_vfs_seek(URLContext *h, int64_t pos, int whence)
639 {
640     trace ("ffmpeg_vfs_seek %d %d\n", pos, whence);
641     DB_FILE *f = h->priv_data;
642
643     if (whence == AVSEEK_SIZE) {
644         return f->vfs->is_streaming () ? -1 : deadbeef->fgetlength (h->priv_data);
645     }
646     else if (f->vfs->is_streaming ()) {
647         return -1;
648     }
649     else {
650         int ret = deadbeef->fseek (h->priv_data, pos, whence);
651         return ret;
652     }
653 }
654
655 static int
656 ffmpeg_vfs_close(URLContext *h)
657 {
658     trace ("ffmpeg_vfs_close\n");
659     deadbeef->fclose (h->priv_data);
660     return 0;
661 }
662
663 static URLProtocol vfswrapper = {
664     .name = FF_PROTOCOL_NAME,
665     .url_open = ffmpeg_vfs_open,
666     .url_read = ffmpeg_vfs_read,
667     .url_write = ffmpeg_vfs_write,
668     .url_seek = ffmpeg_vfs_seek,
669     .url_close = ffmpeg_vfs_close,
670 };
671
672 static void
673 ffmpeg_init_exts (void) {
674     deadbeef->conf_lock ();
675     const char *new_exts = deadbeef->conf_get_str_fast ("ffmpeg.extensions", DEFAULT_EXTS);
676     for (int i = 0; exts[i]; i++) {
677         free (exts[i]);
678     }
679     exts[0] = NULL;
680
681     int n = 0;
682     while (*new_exts) {
683         if (n >= EXT_MAX) {
684             fprintf (stderr, "ffmpeg: too many extensions, max is %d\n", EXT_MAX);
685             break;
686         }
687         const char *e = new_exts;
688         while (*e && *e != ';') {
689             e++;
690         }
691         if (e != new_exts) {
692             char *ext = malloc (e-new_exts+1);
693             memcpy (ext, new_exts, e-new_exts);
694             ext[e-new_exts] = 0;
695             exts[n++] = ext;
696         }
697         if (*e == 0) {
698             break;
699         }
700         new_exts = e+1;
701     }
702     exts[n] = NULL;
703     deadbeef->conf_unlock ();
704 }
705
706 static int
707 ffmpeg_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
708     switch (id) {
709     case DB_EV_CONFIGCHANGED:
710         ffmpeg_init_exts ();
711         break;
712     }
713     return 0;
714 }
715
716 static int
717 ffmpeg_start (void) {
718     ffmpeg_init_exts ();
719     avcodec_init ();
720     av_register_all ();
721 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
722     av_register_protocol2 (&vfswrapper, sizeof(vfswrapper));
723 #else
724     av_register_protocol (&vfswrapper);
725 #endif
726     return 0;
727 }
728
729 static int
730 ffmpeg_stop (void) {
731     for (int i = 0; exts[i]; i++) {
732         free (exts[i]);
733     }
734     exts[0] = NULL;
735     return 0;
736 }
737
738 int
739 ffmpeg_read_metadata (DB_playItem_t *it) {
740     trace ("ffmpeg_read_metadata: fname %s\n", deadbeef->pl_find_meta (it, ":URI"));
741     AVCodec *codec = NULL;
742     AVCodecContext *ctx = NULL;
743     AVFormatContext *fctx = NULL;
744     int ret;
745     int l = strlen (deadbeef->pl_find_meta (it, ":URI"));
746     char *uri = alloca (l + sizeof (FF_PROTOCOL_NAME) + 1);
747     int i;
748
749     // construct uri
750     memcpy (uri, FF_PROTOCOL_NAME, sizeof (FF_PROTOCOL_NAME)-1);
751     memcpy (uri + sizeof (FF_PROTOCOL_NAME)-1, ":", 1);
752     memcpy (uri + sizeof (FF_PROTOCOL_NAME), deadbeef->pl_find_meta (it, ":URI"), l);
753     uri[sizeof (FF_PROTOCOL_NAME) + l] = 0;
754     trace ("ffmpeg: uri: %s\n", uri);
755
756     // open file
757     if ((ret = av_open_input_file(&fctx, uri, NULL, 0, NULL)) < 0) {
758         trace ("fctx is %p, ret %d/%s", fctx, ret, strerror(-ret));
759         return -1;
760     }
761
762     av_find_stream_info(fctx);
763     for (i = 0; i < fctx->nb_streams; i++)
764     {
765         ctx = fctx->streams[i]->codec;
766         if (ctx->codec_type ==
767 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
768             AVMEDIA_TYPE_AUDIO)
769 #else
770             CODEC_TYPE_AUDIO)
771 #endif
772         {
773             codec = avcodec_find_decoder(ctx->codec_id);
774             if (codec != NULL)
775                 break;
776         }
777     }
778     if (codec == NULL)
779     {
780         trace ("ffmpeg can't decode %s\n", deadbeef->pl_find_meta (it, ":URI"));
781         av_close_input_file(fctx);
782         return -1;
783     }
784     if (avcodec_open (ctx, codec) < 0) {
785         trace ("ffmpeg: avcodec_open failed\n");
786         av_close_input_file(fctx);
787         return -1;
788     }
789
790     deadbeef->pl_delete_all_meta (it);
791     ffmpeg_read_metadata_internal (it, fctx);
792
793     av_close_input_file(fctx);
794     return 0;
795 }
796
797 static const char settings_dlg[] =
798     "property \"File Extensions (separate with ';')\" entry ffmpeg.extensions \"" DEFAULT_EXTS "\";\n"
799 ;
800
801 // define plugin interface
802 static DB_decoder_t plugin = {
803     .plugin.api_vmajor = 1,
804     .plugin.api_vminor = 0,
805     .plugin.version_major = 1,
806     .plugin.version_minor = 2,
807     .plugin.type = DB_PLUGIN_DECODER,
808     .plugin.id = "ffmpeg",
809     .plugin.name = "FFMPEG audio player",
810     .plugin.descr = "decodes audio formats using FFMPEG libavcodec",
811     .plugin.copyright = 
812         "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
813         "\n"
814         "This program is free software; you can redistribute it and/or\n"
815         "modify it under the terms of the GNU General Public License\n"
816         "as published by the Free Software Foundation; either version 2\n"
817         "of the License, or (at your option) any later version.\n"
818         "\n"
819         "This program is distributed in the hope that it will be useful,\n"
820         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
821         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
822         "GNU General Public License for more details.\n"
823         "\n"
824         "You should have received a copy of the GNU General Public License\n"
825         "along with this program; if not, write to the Free Software\n"
826         "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n"
827     ,
828     .plugin.website = "http://deadbeef.sf.net",
829     .plugin.start = ffmpeg_start,
830     .plugin.stop = ffmpeg_stop,
831     .plugin.configdialog = settings_dlg,
832     .plugin.message = ffmpeg_message,
833     .open = ffmpeg_open,
834     .init = ffmpeg_init,
835     .free = ffmpeg_free,
836     .read = ffmpeg_read,
837     .seek = ffmpeg_seek,
838     .seek_sample = ffmpeg_seek_sample,
839     .insert = ffmpeg_insert,
840     .read_metadata = ffmpeg_read_metadata,
841     .exts = (const char **)exts,
842 };
843
844 DB_plugin_t *
845 ffmpeg_load (DB_functions_t *api) {
846     deadbeef = api;
847     return DB_PLUGIN (&plugin);
848 }
849