Project

General

Profile

ffaudio-core.cc

Source - Jim Turner, October 24, 2015 21:43

 
1
/*
2
 * Audacious FFaudio Plugin
3
 * Copyright © 2009 William Pitcock <nenolod@dereferenced.org>
4
 *                  Matti Hämäläinen <ccr@tnsp.org>
5
 * Copyright © 2011 John Lindgren <john.lindgren@tds.net>
6
 * Video-playing capability added Copyright © 2015 Jim Turner <turnerjw784@yahoo.com>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are met:
10
 *
11
 * 1. Redistributions of source code must retain the above copyright notice,
12
 *    this list of conditions, and the following disclaimer.
13
 *
14
 * 2. Redistributions in binary form must reproduce the above copyright notice,
15
 *    this list of conditions, and the following disclaimer in the documentation
16
 *    provided with the distribution.
17
 *
18
 * This software is provided "as is" and without any warranty, express or
19
 * implied. In no event shall the authors be liable for any damages arising from
20
 */
21

    
22
#include <stdlib.h>
23
#include <stdio.h>
24
#include <string.h>
25

    
26
#include <pthread.h>
27

    
28
#undef FFAUDIO_DOUBLECHECK  /* Doublecheck probing result for debugging purposes */
29
#undef FFAUDIO_NO_BLACKLIST /* Don't blacklist any recognized codecs/formats */
30

    
31
#include "ffaudio-stdinc.h"
32

    
33
#include <audacious/audtag.h>
34
#include <libaudcore/audstrings.h>
35
#include <libaudcore/i18n.h>
36
#include <libaudcore/multihash.h>
37
#include <libaudcore/runtime.h>
38

    
39
#include <stdint.h>
40
#include "libavutil/common.h"
41
#include "libavutil/dict.h"
42
#include "libavutil/log.h"
43
#include "libavformat/version.h"
44
#include "libavformat/avio.h"
45
extern "C" {
46
#include <libswscale/swscale.h>
47
}
48
#include <SDL.h>
49
#include <SDL_thread.h>
50

    
51
#define SDL_AUDIO_BUFFER_SIZE 4096
52
#define MAX_AUDIO_FRAME_SIZE 192000
53

    
54

    
55
class FFaudio : public InputPlugin
56
{
57
public:
58
    static const char about[];
59
    static const char * const exts[], * const mimes[];
60

    
61
    static constexpr PluginInfo info = {
62
        N_("FFmpeg Plugin"),
63
        PACKAGE,
64
        about
65
    };
66

    
67
    static constexpr auto iinfo = InputInfo (FlagWritesTag)
68
        .with_priority (10) /* lowest priority fallback */
69
        .with_exts (exts)
70
        .with_mimes (mimes);
71

    
72
    constexpr FFaudio () : InputPlugin (info, iinfo) {}
73

    
74
    bool init ();
75
    void cleanup ();
76

    
77
    bool is_our_file (const char * filename, VFSFile & file);
78
    Tuple read_tuple (const char * filename, VFSFile & file);
79
    Index<char> read_image (const char * filename, VFSFile & file);
80
    bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
81
    bool play (const char * filename, VFSFile & file);
82
};
83

    
84
EXPORT FFaudio aud_plugin_instance;
85

    
86
static bool play_video;          /* JWT: TRUE IF USER IS CURRENTLY PLAYING VIDEO (KILLINV VID. WINDOW TURNS OFF! */
87
static bool play_video_wason;    /* JWT: TRUE IF USER WANTS VIDEO PART OF VIDEO FILES DISPLAYED */
88
static bool fromstdin;           /* JWT: TRUE IF INPUT IS STREAMED IN VIA STDIN, FALSE OTHERWISE */
89

    
90
typedef struct
91
{
92
    int stream_idx;
93
    AVStream * stream;
94
    AVCodecContext * context;
95
    AVCodec * codec;
96
}
97
CodecInfo;
98
static CodecInfo cinfo;          /* JWT: SAVE THE AUDIO & VIDEO CODEC STRUCTURES SINCE NOW REFERENCED IN 2 FUNCTIONS: */
99
static CodecInfo vcinfo;
100

    
101
/* 
102
    JWT: ADDED ALL THIS QUEUE STUFF TO SMOOTH VIDEO PERFORMANCE SO THAT VIDEO FRAMES WOULD 
103
    BE OUTPUT MORE INTERLACED WITH THE AUDIO FRAMES BY QUEUEING VIDEO FRAMES UNTIL AN 
104
    AUDIO FRAME IS PROCESSED, THEN DEQUEUEING AND PROCESSING 'EM WITH EACH AUDIO FRAME.  
105
    THE SIZE OF THIS QUEUE IS SET BY video_qsize CONFIG PARAMETER AND DEFAULTS TO 20.
106
    HAVING TOO MANY CAN RESULT IN DELAYED VIDEO, SO EXPERIMENT.  IDEALLY, PACKETS SHOULD 
107
    BE PROCESSED:  V A V A V A..., BUT THIS HANDLES:  
108
    V1 V2 V3 V4 V5 A1 A2 A3 A4 A5 A6 A7 V7 A8... AS: 
109
    (Q:V1 V2 V3 V4 V5 V6) A1 A2 V1 A3 A4 V2 A5 A6 V3 A7 A8...
110
    WE DON'T WANT TO INTERRUPT AUDIO PERFORMANCE AND I DON'T KNOW HOW TO THREAD IT UP,
111
    BUT THIS SIMPLE APPROACH SEEMS TO WORK PRETTY SMOOTH FOR ME!  OTHERWISE TRY 
112
    INCREASING video_qsize IN config file OTHERWISE.
113
    BORROWED THESE FUNCTIONS FROM:
114
    http://www.thelearningpoint.net/computer-science/data-structures-queues--with-c-program-source-code
115
*/
116

    
117
typedef struct 
118
{
119
    int capacity;
120
    int size;
121
    int front;
122
    int rear;
123
    AVPacket *elements;
124
}
125
pktQueue;
126

    
127
pktQueue * createQueue (int maxElements)
128
{
129
    /* Create a Queue */
130
    pktQueue *Q;
131
    Q = (pktQueue *)malloc(sizeof(pktQueue));
132
    /* Initialise its properties */
133
    Q->elements = (AVPacket *)malloc(sizeof(AVPacket)*maxElements);
134
    Q->size = 0;
135
    Q->capacity = maxElements;
136
    Q->front = 0;
137
    Q->rear = -1;
138
    /* Return the pointer */
139
    return Q;
140
}
141

    
142
bool Dequeue (pktQueue *Q)
143
{
144
    /* If Queue size is zero then it is empty. So we cannot pop */
145
    if(Q->size==0)
146
        return false;
147
    /* Removing an element is equivalent to incrementing index of front by one */
148
    else
149
    {
150
        Q->size--;
151
        if (Q->elements[Q->front].data)
152
            av_free_packet(&Q->elements[Q->front]);
153

    
154
        Q->front++;
155
        /* As we fill elements in circular fashion */
156
        if(Q->front==Q->capacity)
157
        {
158
                Q->front=0;
159
        }
160
    }
161
    return true;
162
}
163

    
164
AVPacket * QFront (pktQueue *Q)
165
{
166
    if(Q->size==0)
167
    {
168
            AUDDBG("Queue is Empty\n");
169
            return nullptr;
170
    }
171
    /* Return the element which is at the front*/
172
    return &Q->elements[Q->front];
173
}
174

    
175
bool isQueueFull (pktQueue *Q)
176
{
177
    return (Q->size == Q->capacity) ? true : false;
178
}
179

    
180
bool Enqueue (pktQueue *Q, AVPacket element)
181
{
182
    /* If the Queue is full, we cannot push an element into it as there is no space for it.*/
183
    if(Q->size == Q->capacity)
184
    {
185
            printf("Queue is Full\n");
186
            return false;
187
    }
188
    else
189
    {
190
            Q->size++;
191
            Q->rear = Q->rear + 1;
192
            /* As we fill the queue in circular fashion */
193
            if(Q->rear == Q->capacity)
194
            {
195
                    Q->rear = 0;
196
            }
197
            /* Insert the element in its rear side */ 
198
            Q->elements[Q->rear] = element;
199
    }
200
    return true;
201
}
202

    
203
/* JWT:END OF ADDED VIDEO PACKET QUEUEING FUNCTIONS */
204

    
205
static SimpleHash<String, AVInputFormat *> extension_dict;
206

    
207
static void create_extension_dict ();
208

    
209
static int lockmgr (void * * mutexp, enum AVLockOp op)
210
{
211
    switch (op)
212
    {
213
    case AV_LOCK_CREATE:
214
        * mutexp = new pthread_mutex_t;
215
        pthread_mutex_init ((pthread_mutex_t *) * mutexp, nullptr);
216
        break;
217
    case AV_LOCK_OBTAIN:
218
        pthread_mutex_lock ((pthread_mutex_t *) * mutexp);
219
        break;
220
    case AV_LOCK_RELEASE:
221
        pthread_mutex_unlock ((pthread_mutex_t *) * mutexp);
222
        break;
223
    case AV_LOCK_DESTROY:
224
        pthread_mutex_destroy ((pthread_mutex_t *) * mutexp);
225
        delete (pthread_mutex_t *) * mutexp;
226
        break;
227
    }
228

    
229
    return 0;
230
}
231

    
232
static void ffaudio_log_cb (void * avcl, int av_level, const char * fmt, va_list va)
233
{
234
    audlog::Level level = audlog::Debug;
235
    char message [2048];
236

    
237
    switch (av_level)
238
    {
239
    case AV_LOG_QUIET:
240
        return;
241
    case AV_LOG_PANIC:
242
    case AV_LOG_FATAL:
243
    case AV_LOG_ERROR:
244
        level = audlog::Error;
245
        break;
246
    case AV_LOG_WARNING:
247
        level = audlog::Warning;
248
        break;
249
    case AV_LOG_INFO:
250
        level = audlog::Info;
251
        break;
252
    default:
253
        break;
254
    }
255

    
256
    AVClass * avc = avcl ? * (AVClass * *) avcl : nullptr;
257

    
258
    vsnprintf (message, sizeof message, fmt, va);
259

    
260
    audlog::log (level, __FILE__, __LINE__, avc ? avc->item_name(avcl) : __FUNCTION__,
261
                 "<%p> %s", avcl, message);
262
}
263

    
264
bool FFaudio::init ()
265
{
266
    av_register_all();
267
    av_lockmgr_register (lockmgr);
268

    
269
    create_extension_dict ();
270

    
271
    av_log_set_callback (ffaudio_log_cb);
272
    /* JWT:SAVE config OPTION VALUE FOR CLOSING THINGS, IN CASE USER KILLS VIDEO WINDOW 
273
        THUS TURNING "play_video" OFF DURING PLAY.
274
    */
275
    play_video_wason = aud_get_bool ("ffaudio", "play_video");
276

    
277
    return true;
278
}
279

    
280
void FFaudio::cleanup ()
281
{
282
    extension_dict.clear ();
283

    
284
    av_lockmgr_register (nullptr);
285
}
286

    
287
static const char * ffaudio_strerror (int error)
288
{
289
    static char buf[256];
290
    return (! av_strerror (error, buf, sizeof buf)) ? buf : "unknown error";
291
}
292

    
293
static void create_extension_dict ()
294
{
295
    AVInputFormat * f;
296
    for (f = av_iformat_next (nullptr); f; f = av_iformat_next (f))
297
    {
298
        if (! f->extensions)
299
            continue;
300

    
301
        StringBuf exts = str_tolower (f->extensions);
302
        Index<String> extlist = str_list_to_index (exts, ",");
303

    
304
        for (auto & ext : extlist)
305
            extension_dict.add (ext, std::move (f));
306
    }
307
}
308

    
309
static AVInputFormat * get_format_by_extension (const char * name)
310
{
311
    StringBuf ext = uri_get_extension (name);
312
    if (! ext)
313
        return nullptr;
314

    
315
    AUDDBG ("Get format by extension: %s\n", name);
316
    AVInputFormat * * f = extension_dict.lookup (String (str_tolower (ext)));
317

    
318
    if (f && * f)
319
        AUDDBG ("Format %s.\n", (* f)->name);
320
    else
321
        AUDDBG ("Format unknown.\n");
322

    
323
    return f ? * f : nullptr;
324
}
325

    
326
static AVInputFormat * get_format_by_content (const char * name, VFSFile & file)
327
{
328
    AUDDBG ("Get format by content: %s\n", name);
329

    
330
    AVInputFormat * f = nullptr;
331

    
332
    unsigned char buf[16384 + AVPROBE_PADDING_SIZE];
333
    int size = 16;
334
    int filled = 0;
335
    int target = 100;
336
    int score = 0;
337

    
338
    while (1)
339
    {
340
        if (filled < size)
341
            filled += file.fread (buf + filled, 1, size - filled);
342

    
343
        memset (buf + filled, 0, AVPROBE_PADDING_SIZE);
344
        AVProbeData d = {name, buf, filled};
345
        score = target;
346

    
347
        f = av_probe_input_format2 (& d, true, & score);
348
        if (f)
349
            break;
350

    
351
        if (size < 16384 && filled == size)
352
            size *= 4;
353
        else if (target > 10)
354
            target = 10;
355
        else
356
            break;
357
    }
358

    
359
    if (f)
360
        AUDDBG ("Format %s, buffer size %d, score %d.\n", f->name, filled, score);
361
    else
362
        AUDDBG ("Format unknown.\n");
363

    
364
    if (file.fseek (0, VFS_SEEK_SET) < 0)
365
        ; /* ignore errors here */
366

    
367
    return f;
368
}
369

    
370
static AVInputFormat * get_format (const char * name, VFSFile & file)
371
{
372
    AVInputFormat * f = get_format_by_extension (name);
373
    return f ? f : get_format_by_content (name, file);
374
}
375

    
376
bool isFromStdin ()  /* JWT: TRUE IF INPUT IS STREAMED IN VIA STDIN, FALSE OTHERWISE */
377
{
378
    return fromstdin;
379
}
380

    
381
static AVFormatContext * open_input_file (const char * name, VFSFile & file)
382
{
383
    AVFormatContext * c = NULL;
384

    
385
    play_video = aud_get_bool ("ffaudio", "play_video");   //JWT:RESET PLAY-VIDEO, CASE TURNED OFF ON PREV. PLAY
386
    const char * xname = name;
387
    if (fromstdin)
388
        xname = "pipe:";
389
    int ret = avformat_open_input (&c, xname, NULL, NULL);
390
    if (ret)
391
    {
392
        AUDERR ("avformat_open_input failed for %s: %s.\n", xname, ffaudio_strerror (ret));
393
        return nullptr;
394
    }
395

    
396
    return c;
397
}
398

    
399
static void close_input_file (AVFormatContext * c, CodecInfo * cinfo, CodecInfo * vcinfo)
400
{
401
    if (play_video_wason)
402
        avcodec_close(vcinfo->context);
403
    play_video_wason = play_video;
404
    avcodec_close(cinfo->context);
405
#if CHECK_LIBAVFORMAT_VERSION (53, 25, 0, 53, 17, 0)
406
    avformat_close_input (&c);
407
#else
408
    av_close_input_file (c);
409
#endif
410

    
411
}
412

    
413
static bool find_codec (AVFormatContext * c, CodecInfo * cinfo, CodecInfo * vcinfo)
414
{
415
    avformat_find_stream_info (c, NULL);
416

    
417
    int videoStream=-1;
418
    int audioStream=-1;
419
    for (unsigned i = 0; i < c->nb_streams; i++)
420
    {
421
        if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
422
            videoStream=i;
423
        else if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audioStream < 0)
424
            audioStream=i;
425
    }
426
    if (audioStream==-1)   /* PUNT IF NO AUDIO SINCE AUDACIOUS IS AN *AUDIO* PLAYER! */
427
        return false;
428

    
429
    AVCodec * codec = avcodec_find_decoder (c->streams[audioStream]->codec->codec_id);
430
    if (codec)
431
    {
432
        cinfo->stream_idx = audioStream;
433
        cinfo->stream = c->streams[audioStream];
434
        cinfo->context = c->streams[audioStream]->codec;
435
        cinfo->codec = codec;
436

    
437
        /* JWT: NOW IF USER WANTS VIDEO, SEE IF WE GOT A VIDEO STREAM TOO: */
438
        if (play_video && videoStream >= 0)
439
        {
440
            AVCodec * vcodec = avcodec_find_decoder (c->streams[videoStream]->codec->codec_id);
441
            if (vcodec)
442
            {
443
                vcinfo->stream_idx = videoStream;
444
                vcinfo->stream = c->streams[videoStream];
445
                vcinfo->context = c->streams[videoStream]->codec;
446
                vcinfo->codec = vcodec;
447
            }
448
        }
449
        else
450
            play_video = false;  /* turn off video playback, since we could not find stream! */
451

    
452
        return true;
453
    }
454

    
455
    return false;
456
}
457

    
458
bool FFaudio::is_our_file (const char * filename, VFSFile & file)
459
{
460
    return (bool) get_format (filename, file);
461
}
462

    
463
static const struct {
464
    Tuple::ValueType ttype;  /* Tuple field value type */
465
    Tuple::Field field;      /* Tuple field constant */
466
    const char * keys[5];    /* Keys to match (case-insensitive), ended by nullptr */
467
} metaentries[] = {
468
    {Tuple::String, Tuple::Artist, {"author", "hor", "artist", nullptr}},
469
    {Tuple::String, Tuple::Title, {"title", "le", nullptr}},
470
    {Tuple::String, Tuple::Album, {"album", "WM/AlbumTitle", nullptr}},
471
    {Tuple::String, Tuple::Performer, {"performer", nullptr}},
472
    {Tuple::String, Tuple::Copyright, {"copyright", nullptr}},
473
    {Tuple::String, Tuple::Genre, {"genre", "WM/Genre", nullptr}},
474
    {Tuple::String, Tuple::Comment, {"comment", nullptr}},
475
    {Tuple::String, Tuple::Composer, {"composer", nullptr}},
476
    {Tuple::Int, Tuple::Year, {"year", "WM/Year", "date", nullptr}},
477
    {Tuple::Int, Tuple::Track, {"track", "WM/TrackNumber", nullptr}},
478
};
479

    
480
static void read_metadata_dict (Tuple & tuple, AVDictionary * dict)
481
{
482
    for (auto & meta : metaentries)
483
    {
484
        AVDictionaryEntry * entry = nullptr;
485

    
486
        for (int j = 0; ! entry && meta.keys[j]; j ++)
487
            entry = av_dict_get (dict, meta.keys[j], nullptr, 0);
488

    
489
        if (entry && entry->value)
490
        {
491
            if (meta.ttype == Tuple::String)
492
                tuple.set_str (meta.field, entry->value);
493
            else if (meta.ttype == Tuple::Int)
494
                tuple.set_int (meta.field, atoi (entry->value));
495
        }
496
    }
497
}
498

    
499
Tuple FFaudio::read_tuple (const char * filename, VFSFile & file)
500
{
501
    Tuple tuple;
502
    fromstdin = (!strcmp(filename, "-") || strstr(filename, "://-.")) ? true : false;
503
    AUDDBG("Filename =%s=\n", filename);
504
    if (fromstdin)
505
    {
506
        tuple.set_filename (filename);
507
    }
508
    else   /* JWT:THIS STUFF DEFERRED UNTIL PLAY FOR STDIN, BUT SEEMS TO HAVE TO BE HERE FOR DIRECT */
509
    {
510
        AVFormatContext * ic = open_input_file (filename, file);
511

    
512
        if (ic)
513
        {
514
            if (find_codec (ic, & cinfo, & vcinfo))
515
            {
516
                tuple.set_filename (filename);
517

    
518
                tuple.set_int (Tuple::Length, ic->duration / 1000);
519
                tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
520
                if (cinfo.codec->long_name)
521
                    tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
522
                if (ic->metadata)
523
                    read_metadata_dict (tuple, ic->metadata);
524
                if (cinfo.stream->metadata)
525
                    read_metadata_dict (tuple, cinfo.stream->metadata);
526
                if (play_video && vcinfo.stream->metadata)
527
                    read_metadata_dict (tuple, vcinfo.stream->metadata);
528
            }
529

    
530
            close_input_file (ic, & cinfo, & vcinfo);
531
        }
532

    
533
        if (tuple && ! file.fseek (0, VFS_SEEK_SET))
534
            audtag::tuple_read (tuple, file);
535
            /* JWT:BUILD NOTE:  IF USING LATEST AUDACIOUS VERSIONS YOU MAY NEED TO REPLACE ABOVE LINE WITH:
536
                audtag::read_tag (file, & tuple, nullptr);
537
            */
538
    }
539

    
540
    return tuple;
541
}
542

    
543
bool FFaudio::write_tuple (const char * filename, VFSFile & file, const Tuple & tuple)
544
{
545
    if (str_has_suffix_nocase (filename, ".ape"))
546
        return audtag::tuple_write (tuple, file, audtag::TagType::APE);
547

    
548
    return audtag::tuple_write (tuple, file, audtag::TagType::None);
549
}
550

    
551
Index<char> FFaudio::read_image (const char * filename, VFSFile & file)
552
{
553
    if (str_has_suffix_nocase (filename, ".m4a") || str_has_suffix_nocase (filename, ".mp4"))
554
        return read_itunes_cover (filename, file);
555

    
556
    return Index<char> ();
557
}
558

    
559
/* JWT: NEW FUNCTION TO WRITE VIDEO FRAMES TO THE POPUP WINDOW: */
560
bool write_videoframe (SwsContext * sws_ctx, AVFrame * vframe, SDL_Overlay * bmp, 
561
    AVPacket *pkt, int * frameFinished, int video_width, int video_height)
562
{
563
    SDL_Rect rect;
564
    int len = avcodec_decode_video2 (vcinfo.context, vframe, frameFinished, pkt);
565
    // Did we get a video frame?
566
    if (len < 0)
567
    {
568
        AUDERR ("decode_video() failed, code %d\n", len);
569
        return false;
570
    }
571
    if (*frameFinished)
572
    {
573
        SDL_LockYUVOverlay(bmp);
574
        AVPicture pict;
575
        pict.data[0] = bmp->pixels[0];
576
        pict.data[1] = bmp->pixels[2];
577
        pict.data[2] = bmp->pixels[1];
578
        pict.linesize[0] = bmp->pitches[0];
579
        pict.linesize[1] = bmp->pitches[2];
580
        pict.linesize[2] = bmp->pitches[1];
581
        // Convert the image into YUV format that SDL uses
582
        sws_scale(sws_ctx, (uint8_t const * const *)vframe->data,
583
            vframe->linesize, 0, vcinfo.context->height,
584
            pict.data, pict.linesize);
585
        SDL_UnlockYUVOverlay(bmp);
586

    
587
        rect.x = 0;
588
        rect.y = 0;
589
        rect.w = video_width;
590
        rect.h = video_height;
591
        SDL_DisplayYUVOverlay(bmp, &rect);
592
        return false;
593
    }
594
    return true;
595
}
596

    
597
bool FFaudio::play (const char * filename, VFSFile & file)
598
{
599
    AUDDBG ("Playing %s.\n", filename);
600

    
601
    AVPacket pkt = AVPacket();
602
    int errcount;
603
    /* bool codec_opened = false;  //JWT:DON'T THINK WE NEED ANYMORE. */
604
    int out_fmt;
605
    bool planar;
606
    bool error = false;
607
    SDL_Overlay     *bmp = nullptr;    /* JWT: ALL SDL_* STUFF IS FOR PLAYING VIDEOS */
608
    SDL_Surface     *screen = nullptr;
609
    SDL_Event       event;
610
    int video_width = 0;
611
    int video_height = 0;
612
    play_video_wason = play_video;
613
    float video_aspect_ratio = 0;
614
    struct SwsContext *sws_ctx = NULL;
615

    
616
    Index<char> buf;
617

    
618
    AVFormatContext * ic = open_input_file (filename, file);
619
    const char * fileext = strrchr (filename, '.');
620
    if (ic)
621
    {
622
        if (fromstdin)  /* JWT: FOR STDIN: TRY TO GET "read_tuple()" STUFF NOW, SINCE FILE COULD NOT BE OPENED EARLIER IN read_tuple()! */
623
        {
624
            Tuple tuple;
625

    
626
            AUDDBG ("---- playing from STDIN: get TUPLE stuff now: IC is defined\n");
627
            if (find_codec (ic, & cinfo, & vcinfo))
628
            {
629
                tuple.set_filename (filename);
630

    
631
                tuple.set_int (Tuple::Length, ic->duration / 1000);
632
                tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
633
                if (cinfo.codec->long_name)
634
                    tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
635
                if (ic->metadata)
636
                    read_metadata_dict (tuple, ic->metadata);
637
                if (cinfo.stream->metadata)
638
                    read_metadata_dict (tuple, cinfo.stream->metadata);
639
                if (play_video && vcinfo.stream->metadata)
640
                    read_metadata_dict (tuple, vcinfo.stream->metadata);
641
                set_playback_tuple (tuple.ref ());
642
            }
643
            else
644
            {
645
                AUDERR ("No codec found for %s.\n", filename);
646
                goto error_exit;
647
            }
648
        }
649
        else
650
        {
651
            if (! find_codec (ic, & cinfo, & vcinfo))
652
            {
653
                AUDERR ("No codec found for %s.\n", filename);
654
                goto error_exit;
655
            }
656
        }
657
    }
658
    else
659
        return false;
660

    
661
    AUDDBG("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx);
662

    
663
    if (avcodec_open2 (cinfo.context, cinfo.codec, NULL) < 0)
664
        goto error_exit;
665

    
666
    /* JWT: IF abUSER ALSO WANTS TO PLAY VIDEO THEN WE SET UP POP-UP VIDEO SCREEN: */
667
    if (play_video)
668
    {
669
        String video_windowtitle;
670
        int video_sws_scale = 0;
671
        if (avcodec_open2 (vcinfo.context, vcinfo.codec, NULL) < 0)
672
            goto error_exit;
673

    
674
        // Allocate a place to put our YUV image on that screen (initialize to video's size,
675
        // then (later) resize to user's size prefs if specified (must do this way to get video to scale:
676
#ifndef __DARWIN__
677
        screen = SDL_SetVideoMode(vcinfo.context->width, vcinfo.context->height, 0, SDL_RESIZABLE);
678
#else
679
        screen = SDL_SetVideoMode(vcinfo.context->width, vcinfo.context->height, 24, SDL_RESIZABLE);
680
#endif
681

    
682
        video_windowtitle = aud_get_str ("ffaudio", "video_windowtitle");
683
        if (video_windowtitle)
684
            SDL_WM_SetCaption(video_windowtitle, NULL);
685
        if (aud_get_int ("ffaudio", "video_sws_scale"))   //USER CAN CHOOSE SWS_SCALE VALUE.
686
            video_sws_scale = aud_get_int ("ffaudio", "video_sws_scale");
687
        else
688
            video_sws_scale = SWS_BICUBIC;  //default=4
689

    
690
        bmp = SDL_CreateYUVOverlay(
691
            vcinfo.context->width,
692
            vcinfo.context->height,
693
            SDL_YV12_OVERLAY,
694
            screen
695
        );
696
        sws_ctx = sws_getContext (
697
                   vcinfo.context->width,
698
                   vcinfo.context->height,
699
                   vcinfo.context->pix_fmt,
700
                   vcinfo.context->width,
701
                   vcinfo.context->height,
702
                   PIX_FMT_YUV420P,
703
                   video_sws_scale,
704
                   NULL,
705
                   NULL,
706
                   NULL
707
        );
708

    
709
        /* NOW CALCULATE THE WIDTH, HEIGHT, & ASPECT BASED ON VIDEO'S SIZE & AND ANY USER PARAMATERS GIVEN: */
710
        video_aspect_ratio = vcinfo.context->height
711
            ? (float)vcinfo.context->width / (float)vcinfo.context->height : 1.0;
712
        int vx = aud_get_int ("ffaudio", "video_xsize");
713
        int vy = aud_get_int ("ffaudio", "video_ysize");
714
        /* JWT:FIXME:FLV AND SWF STREAMS ERROR OUT ON ATTEMPT TO CHANGE SIZE AT STARTUP?!
715
            THOUGH USER CAN STILL RESIZE WINDOW LATER!  ERROR MSG:
716
            "Assertion ref->size >= offset + s->mb_stride * ((f->height+15)/16) failed 
717
            at libavcodec/mpegvideo.c:1963 
718
        */
719
        if (! strcmp_nocase (fileext, ".flv") || ! strcmp_nocase (fileext, ".swf"))
720
            vx = vy = 0;
721
        if (vx && !vy)   //user specified width only, calc. height based on aspect:
722
        {
723
            vcinfo.context->width = video_width = vx;
724
            vcinfo.context->height = video_height = (int)((float)vx / video_aspect_ratio);
725
        }
726
        else if (!vx && vy)   //user specified height only, calc. height based on aspect:
727
        {
728
            vcinfo.context->height = video_height = vy;
729
            vcinfo.context->width = video_width = (int)((float)vy * video_aspect_ratio);
730
            
731
        }
732
        else if (vx && vy)   //user specified fixed width and height:
733
        {
734
            vcinfo.context->width = video_width = vx;
735
            vcinfo.context->height = video_height = vy;
736
        }
737
        else   //user specified nothing, use video's desired wXh:
738
        {
739
            video_width = vcinfo.context->width;
740
            video_height = vcinfo.context->height;
741
        }
742
        video_aspect_ratio = video_height
743
            ? (float)video_width / (float)video_height : 1.0;   //fall thru to square to avoid possibliity of "/0"!
744

    
745
        //NOW "RESIZE" screen to user's wXh, if user set something:
746
        if (vx || vy)
747
        {
748
#ifndef __DARWIN__
749
            screen = SDL_SetVideoMode(video_width, video_height, 0, SDL_RESIZABLE);
750
#else
751
            screen = SDL_SetVideoMode(video_width, video_height, 24, SDL_RESIZABLE);
752
#endif
753

    
754
            if(!screen) {
755
                AUDERR("SDL: could not re-set video mode - exiting\n");
756
                goto error_exit;
757
            }
758
        }
759
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
760
            AUDERR("Could not initialize SDL - %s\n", SDL_GetError());
761
            goto error_exit;
762
        }
763
    }
764

    
765
    /* codec_opened = true;  //JWT:DON'T THINK WE NEED ANYMORE. */
766

    
767
    switch (cinfo.context->sample_fmt)
768
    {
769
        case AV_SAMPLE_FMT_U8: out_fmt = FMT_U8; planar = false; break;
770
        case AV_SAMPLE_FMT_S16: out_fmt = FMT_S16_NE; planar = false; break;
771
        case AV_SAMPLE_FMT_S32: out_fmt = FMT_S32_NE; planar = false; break;
772
        case AV_SAMPLE_FMT_FLT: out_fmt = FMT_FLOAT; planar = false; break;
773

    
774
        case AV_SAMPLE_FMT_U8P: out_fmt = FMT_U8; planar = true; break;
775
        case AV_SAMPLE_FMT_S16P: out_fmt = FMT_S16_NE; planar = true; break;
776
        case AV_SAMPLE_FMT_S32P: out_fmt = FMT_S32_NE; planar = true; break;
777
        case AV_SAMPLE_FMT_FLTP: out_fmt = FMT_FLOAT; planar = true; break;
778

    
779
    default:
780
        AUDERR ("Unsupported audio format %d\n", (int) cinfo.context->sample_fmt);
781
        goto error_exit;
782
    }
783

    
784
    /* Open audio output */
785
    AUDDBG("opening audio output - bitrate=%d=\n", ic->bit_rate);
786

    
787
    set_stream_bitrate(ic->bit_rate);
788

    
789
    open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels);
790

    
791
    errcount = 0;
792

    
793
    int seek_value, ret, frameFinished, decoded, len, size, video_qsize, acount, vcount;
794
    bool knit1perl2;
795
    acount = 0; vcount = 0;  /* JWT:LET'S COUNT PACKETS OF EACH SIZE FOR DEBUGGING. */
796
    AVFrame * frame;
797
    AVFrame * vframe;
798
    /* JWT:video_qsize:  MAX # VIDEO PACKETS TO QUEUE UP FOR INTERLACING TO SMOOTH VIDEO 
799
        PLAYBACK - GOOD RANGE IS 8-56, NOT ENOUGH=JITTERY VIDEO, 
800
        TOO MANY=AUDIO/VIDEO BECOME NOTICABLY OUT OF SYNC!
801
    */
802
    video_qsize = (aud_get_int ("ffaudio", "video_qsize"))
803
        ? aud_get_int ("ffaudio", "video_qsize") : 16;
804
    if (video_qsize < 1)
805
        video_qsize = 1;
806

    
807
    pktQueue *pktQ;
808
    pktQ = createQueue(video_qsize);
809
    /* 
810
        JWT: THIS FLAG FORCES THE VIDEO QUEUE TO BE POPPED ONCE FOR EVERY *TWO* AUDIO 
811
        PACKETS - MOST VIDEOS SEEM TO HAVE A/B 2-1 RATIO OF AUDIO TO VIDEO PACKETS & 
812
        THIS PRETTY MUCH *ELIMINATED* THE VIDEO JITTER!!!
813
    */
814
    knit1perl2 = true;  /* ALTERNATES BETWEEN ON AND OFF EVERY OTHER AUDIO PACKET */
815

    
816
    AUDDBG("video queue size %d\n", video_qsize);
817
#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
818
    frame = av_frame_alloc ();
819
    vframe = av_frame_alloc ();
820
#else
821
    frame = avcodec_alloc_frame ();
822
    vframe = avcodec_alloc_frame ();
823
#endif
824

    
825
    while (! check_stop ())
826
    {
827
        seek_value = check_seek ();
828

    
829
        if (seek_value >= 0)
830
        {
831
            /* JWT:FIRST, PROCESS VIDEO PACKETS SITTING IN THE QUEUE TO CLEAR THE QUEUE! */
832
            while (Dequeue (pktQ))
833
                continue;
834

    
835
            /* JWT: HAD TO CHANGE THIS FROM "AVSEEK_FLAG_ANY" TO AVSEEK_FLAG_BACKWARD 
836
                TO GET SEEK TO NOT RANDOMLY BRICK?! */
837
            if (av_seek_frame (ic, -1, (int64_t) seek_value * AV_TIME_BASE /
838
                1000, AVSEEK_FLAG_BACKWARD) < 0)
839
            {
840
                AUDERR ("error while seeking\n");
841
            } else
842
                errcount = 0;
843

    
844
            seek_value = -1;
845
        }
846

    
847
        AVPacket tmp;
848

    
849
        /* Read next frame (or more) of data */
850
        if ((ret = av_read_frame(ic, &pkt)) < 0)
851
        {
852
            if (ret == (int) AVERROR_EOF)
853
            {
854
                AUDDBG("eof reached\n");
855
                break;
856
            }
857
            else
858
            {
859
                if (++errcount > 4)
860
                {
861
                    AUDERR ("av_read_frame error %d, giving up.\n", ret);
862
                    break;
863
                } else
864
                    continue;
865
            }
866
        } else
867
            errcount = 0;
868

    
869
        /* Ignore any other substreams */
870
        if (pkt.stream_index != cinfo.stream_idx)
871
        {
872
            if (!play_video || pkt.stream_index != vcinfo.stream_idx)
873
            {
874
                av_free_packet(&pkt);
875
                continue;
876
            }
877
        }
878

    
879
        /* Decode and play packet/frame */
880
        memcpy(&tmp, &pkt, sizeof(tmp));
881
        frameFinished = 0;
882
        while (tmp.size > 0 && ! check_stop ())
883
        {
884
            /* Check for seek request and bail out if we have one */
885
            if (seek_value < 0)
886
                seek_value = check_seek ();
887

    
888
            if (seek_value >= 0)
889
                break;
890

    
891
            decoded = 0;
892
            if (pkt.stream_index == cinfo.stream_idx)  /* PROCESS AUDIO PACKET: */
893
            {
894
                ++acount;
895
                /* JWT:IF PLAYING VIDEO, CHECK VIDEO QUEUE. */
896
                if (play_video)
897
                {
898
                    int i,pkts2pop;
899
                    /* FIRST PROCESS THE NEXT # VIDEO PACKETS, IF ANY IN THE QUEUE:
900
                        FOR EVERY *OTHER* AUDIO PACKET, GRAB 1 VIDEO PKT. OFF QUEUE,
901
                        UNLESS QUEUE IS FULL, THEN GRAB 2 SO WE HAVE ROOM FOR THE NEXT ONE!
902
                    */
903
                    pkts2pop = knit1perl2 ? ((pktQ->size == pktQ->capacity) ? 2 : 1) : 0;
904
                    if (pkts2pop > video_qsize)
905
                        pkts2pop = video_qsize;
906
                    knit1perl2 = ! knit1perl2;  //WE'RE ASSUMING LIKELY NEAR 2x AUDIO TO VIDEO FRAMES:
907
                    AVPacket * pktRef;
908
                    for (i=1; i<=pkts2pop; i++)
909
                    {
910
                        pktRef = QFront (pktQ);
911
                        if (pktRef)
912
                        {
913

    
914
                            while (1)
915
                            {
916
                                if (!write_videoframe (sws_ctx, vframe, bmp, pktRef, &frameFinished, 
917
                                        video_width, video_height))
918
                                    break;
919
                            }
920
                            if (!Dequeue (pktQ))
921
                                AUDERR("Queue is Empty\n");
922
                        }
923
                    }
924
                }
925
                len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);
926
                if (len < 0)
927
                {
928
                    AUDERR ("decode_audio() failed, code %d\n", len);
929
                    break;
930
                }
931

    
932
                tmp.size -= len;
933
                tmp.data += len;
934

    
935
                if (! decoded)
936
                    /* continue;  // JWT:NOT SURE WHY THIS WAS A CONTINUE INSTEAD OF A BREAK?! */
937
                    break;
938

    
939
                size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples;
940

    
941
                if (planar)
942
                {
943
                    if (size > buf.len ())
944
                        buf.resize (size);
945

    
946
                    audio_interlace ((const void * *) frame->data, out_fmt,
947
                     cinfo.context->channels, buf.begin (), frame->nb_samples);
948
                    write_audio (buf.begin (), size);
949
                }
950
                else
951
                    write_audio (frame->data[0], size);
952

    
953
            }
954
            else    /* JWT:PROCESS VIDEO PACKET HERE: */
955
            {
956
                ++vcount;
957
                /* JWT: IF QUEUE IS FULL, PROCESS NEXT 2 VIDEO PACKETS FROM QUEUE. */
958
                if (isQueueFull (pktQ))
959
                {
960
                    int i, pkts2pop;
961
                    AVPacket * pktRef;
962

    
963
                    pkts2pop = (video_qsize > 1) ? 2 : 1;
964
                    for (i=1; i<=pkts2pop; i++)
965
                    {
966
                        pktRef = QFront (pktQ);
967
                        if (pktRef)
968
                        {
969
                            while (1)
970
                            {
971
                                if (!write_videoframe (sws_ctx, vframe, bmp, pktRef, &frameFinished, 
972
                                        video_width, video_height))
973
                                    break;
974
                            }
975
                            if (!Dequeue (pktQ))
976
                                AUDERR("Queue is Empty\n");
977
                        }
978
                    }
979
                    AUDDBG("Queue filled.\n");
980
                }
981
                if (Enqueue(pktQ, pkt)) {  /* VIDEO PACKETS TAKE A NUMBER & GET IN LINE! */
982
                    break;
983
                }
984
                AUDERR("Could not enqueue packet, refuses to wait in line, so process NOW!\n");
985
                if (!write_videoframe (sws_ctx, vframe, bmp, &pkt, &frameFinished, 
986
                        video_width, video_height))
987
                    break;
988
            }
989

    
990
            /* JWT: NOW HANDLE VIDEO UI EVENTS SUCH AS RESIZE OR KILL SCREEN: */
991
            if (play_video)
992
            {
993
                SDL_Rect rect;
994

    
995
                SDL_PollEvent(&event);
996
                switch(event.type) {
997
                case SDL_QUIT:
998
                    SDL_Quit();
999
                    play_video = false;
1000
                    //goto error_exit;
1001
                    break;
1002

    
1003
                case SDL_VIDEORESIZE:
1004
                    //Resize the screen
1005
                    float new_aspect_ratio;  //FOR SOME REASON C++ REQUIRES 2 LINES HERE?!
1006
                    new_aspect_ratio = event.resize.h
1007
                        ? (float)event.resize.w / (float)event.resize.h : 1.0;
1008
                    if (new_aspect_ratio > video_aspect_ratio)
1009
                    {
1010
                        video_height = event.resize.h;
1011
                        video_width = (int)(video_aspect_ratio * (float)video_height);
1012
                    }
1013
                    else
1014
                    {
1015
                        video_width = event.resize.w;
1016
                        video_height = (int)((float)video_width / video_aspect_ratio);
1017
                    }
1018

    
1019
#ifndef __DARWIN__
1020
                    screen = SDL_SetVideoMode( video_width, video_height, 0, SDL_RESIZABLE );
1021
#else
1022
                    screen = SDL_SetVideoMode( video_width, video_height, 24, SDL_RESIZABLE );
1023
#endif
1024

    
1025
                    //If there's an error
1026
                    if( screen == NULL )
1027
                        break;
1028

    
1029
                case SDL_VIDEOEXPOSE:
1030
                    rect.x = 0;
1031
                    rect.y = 0;
1032
                    rect.w = video_width;
1033
                    rect.h = video_height;
1034
                    SDL_DisplayYUVOverlay(bmp, &rect);
1035
                    break;
1036

    
1037
                default:
1038
                    break;
1039
                }
1040
            }
1041
        }
1042
    }
1043

    
1044
error_exit:
1045
    AUDDBG("end of playback - % audio frames, % video frames processed.", acount, vcount);
1046
    if (play_video)
1047
        SDL_Quit();
1048

    
1049
#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
1050
    av_frame_free (& vframe);
1051
    av_frame_free (& frame);
1052
#elif CHECK_LIBAVCODEC_VERSION (54, 59, 100, 54, 28, 0)
1053
    avcodec_free_frame (& vframe);
1054
    avcodec_free_frame (& frame);
1055
#else
1056
    av_free (vframe);
1057
    av_free (frame);
1058
#endif
1059

    
1060
    if (pkt.data)
1061
        av_free_packet(&pkt);
1062
    if (ic != nullptr)
1063
        close_input_file(ic, & cinfo, & vcinfo);
1064

    
1065
    return ! error;
1066
}
1067

    
1068
const char FFaudio::about[] =
1069
 N_("Multi-format audio decoding plugin for Audacious using\n"
1070
    "FFmpeg multimedia framework (http://www.ffmpeg.org/)\n"
1071
    "\n"
1072
    "Audacious plugin by:\n"
1073
    "William Pitcock <nenolod@nenolod.net>\n"
1074
    "Matti Hämäläinen <ccr@tnsp.org>");
1075

    
1076
const char * const FFaudio::exts[] = {
1077
    /* musepack, SV7/SV8 */
1078
    "mpc", "mp+", "mpp",
1079

    
1080
    /* windows media audio */
1081
    "wma",
1082

    
1083
    /* shorten */
1084
    "shn",
1085

    
1086
    /* atrac3 */
1087
    "aa3", "oma",
1088

    
1089
    /* MPEG 2/4 AC3 */
1090
    "ac3",
1091

    
1092
    /* monkey's audio */
1093
    "ape",
1094

    
1095
    /* DTS */
1096
    "dts",
1097

    
1098
    /* VQF */
1099
    "vqf",
1100

    
1101
    /* MPEG-4 */
1102
    "m4a", "mp4",
1103

    
1104
    /* WAV (there are some WAV formats sndfile can't handle) */
1105
    "wav",
1106

    
1107
    /* Handle OGG streams (FLAC/Vorbis etc.) */
1108
    "ogg", "oga",
1109

    
1110
    /* Opus */
1111
    "opus",
1112

    
1113
    /* Speex */
1114
    "spx",
1115

    
1116
    /* True Audio */
1117
    "tta",
1118

    
1119
    /* AVI  // JWT:ADDED */
1120
    "avi",
1121

    
1122
    /* FLV  // JWT:ADDED */
1123
    "flv",
1124

    
1125
    /* end of table */
1126
    nullptr
1127
};
1128

    
1129
const char * const FFaudio::mimes[] = {"application/ogg", nullptr};