Project

General

Profile

ffaudio-core.cc

Jim Turner, October 21, 2015 20:32

 
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
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright notice,
11
 *    this list of conditions, and the following disclaimer.
12
 *
13
 * 2. Redistributions in binary form must reproduce the above copyright notice,
14
 *    this list of conditions, and the following disclaimer in the documentation
15
 *    provided with the distribution.
16
 *
17
 * This software is provided "as is" and without any warranty, express or
18
 * implied. In no event shall the authors be liable for any damages arising from
19
 */
20

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

    
25
#include <pthread.h>
26

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

    
30
#include "ffaudio-stdinc.h"
31

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

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

    
50
#define SDL_AUDIO_BUFFER_SIZE 4096
51
#define MAX_AUDIO_FRAME_SIZE 192000
52

    
53

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

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

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

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

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

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

    
83
EXPORT FFaudio aud_plugin_instance;
84

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

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

    
100
static SimpleHash<String, AVInputFormat *> extension_dict;
101

    
102
static void create_extension_dict ();
103

    
104
static int lockmgr (void * * mutexp, enum AVLockOp op)
105
{
106
    switch (op)
107
    {
108
    case AV_LOCK_CREATE:
109
        * mutexp = new pthread_mutex_t;
110
        pthread_mutex_init ((pthread_mutex_t *) * mutexp, nullptr);
111
        break;
112
    case AV_LOCK_OBTAIN:
113
        pthread_mutex_lock ((pthread_mutex_t *) * mutexp);
114
        break;
115
    case AV_LOCK_RELEASE:
116
        pthread_mutex_unlock ((pthread_mutex_t *) * mutexp);
117
        break;
118
    case AV_LOCK_DESTROY:
119
        pthread_mutex_destroy ((pthread_mutex_t *) * mutexp);
120
        delete (pthread_mutex_t *) * mutexp;
121
        break;
122
    }
123

    
124
    return 0;
125
}
126

    
127
static void ffaudio_log_cb (void * avcl, int av_level, const char * fmt, va_list va)
128
{
129
    audlog::Level level = audlog::Debug;
130
    char message [2048];
131

    
132
    switch (av_level)
133
    {
134
    case AV_LOG_QUIET:
135
        return;
136
    case AV_LOG_PANIC:
137
    case AV_LOG_FATAL:
138
    case AV_LOG_ERROR:
139
        level = audlog::Error;
140
        break;
141
    case AV_LOG_WARNING:
142
        level = audlog::Warning;
143
        break;
144
    case AV_LOG_INFO:
145
        level = audlog::Info;
146
        break;
147
    default:
148
        break;
149
    }
150

    
151
    AVClass * avc = avcl ? * (AVClass * *) avcl : nullptr;
152

    
153
    vsnprintf (message, sizeof message, fmt, va);
154

    
155
    audlog::log (level, __FILE__, __LINE__, avc ? avc->item_name(avcl) : __FUNCTION__,
156
                 "<%p> %s", avcl, message);
157
}
158

    
159
bool FFaudio::init ()
160
{
161
    av_register_all();
162
    av_lockmgr_register (lockmgr);
163

    
164
    create_extension_dict ();
165

    
166
    av_log_set_callback (ffaudio_log_cb);
167
    play_video_wason = aud_get_bool ("ffaudio", "play_video");
168

    
169
    return true;
170
}
171

    
172
void FFaudio::cleanup ()
173
{
174
    extension_dict.clear ();
175

    
176
    av_lockmgr_register (nullptr);
177
}
178

    
179
static const char * ffaudio_strerror (int error)
180
{
181
    static char buf[256];
182
    return (! av_strerror (error, buf, sizeof buf)) ? buf : "unknown error";
183
}
184

    
185
static void create_extension_dict ()
186
{
187
    AVInputFormat * f;
188
    for (f = av_iformat_next (nullptr); f; f = av_iformat_next (f))
189
    {
190
        if (! f->extensions)
191
            continue;
192

    
193
        StringBuf exts = str_tolower (f->extensions);
194
        Index<String> extlist = str_list_to_index (exts, ",");
195

    
196
        for (auto & ext : extlist)
197
            extension_dict.add (ext, std::move (f));
198
    }
199
}
200

    
201
static AVInputFormat * get_format_by_extension (const char * name)
202
{
203
    StringBuf ext = uri_get_extension (name);
204
    if (! ext)
205
        return nullptr;
206

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

    
210
    if (f && * f)
211
        AUDDBG ("Format %s.\n", (* f)->name);
212
    else
213
        AUDDBG ("Format unknown.\n");
214

    
215
    return f ? * f : nullptr;
216
}
217

    
218
static AVInputFormat * get_format_by_content (const char * name, VFSFile & file)
219
{
220
    AUDDBG ("Get format by content: %s\n", name);
221

    
222
    AVInputFormat * f = nullptr;
223

    
224
    unsigned char buf[16384 + AVPROBE_PADDING_SIZE];
225
    int size = 16;
226
    int filled = 0;
227
    int target = 100;
228
    int score = 0;
229

    
230
    while (1)
231
    {
232
        if (filled < size)
233
            filled += file.fread (buf + filled, 1, size - filled);
234

    
235
        memset (buf + filled, 0, AVPROBE_PADDING_SIZE);
236
        AVProbeData d = {name, buf, filled};
237
        score = target;
238

    
239
        f = av_probe_input_format2 (& d, true, & score);
240
        if (f)
241
            break;
242

    
243
        if (size < 16384 && filled == size)
244
            size *= 4;
245
        else if (target > 10)
246
            target = 10;
247
        else
248
            break;
249
    }
250

    
251
    if (f)
252
        AUDDBG ("Format %s, buffer size %d, score %d.\n", f->name, filled, score);
253
    else
254
        AUDDBG ("Format unknown.\n");
255

    
256
    if (file.fseek (0, VFS_SEEK_SET) < 0)
257
        ; /* ignore errors here */
258

    
259
    return f;
260
}
261

    
262
static AVInputFormat * get_format (const char * name, VFSFile & file)
263
{
264
    AVInputFormat * f = get_format_by_extension (name);
265
    return f ? f : get_format_by_content (name, file);
266
}
267

    
268
bool isFromStdin ()  /* JWT: TRUE IF INPUT IS STREAMED IN VIA STDIN, FALSE OTHERWISE */
269
{
270
    return fromstdin;
271
}
272

    
273
static AVFormatContext * open_input_file (const char * name, VFSFile & file)
274
{
275
    AVFormatContext * c = NULL;
276

    
277
    play_video = aud_get_bool ("ffaudio", "play_video");   //JWT:RESET PLAY-VIDEO, CASE TURNED OFF ON PREV. PLAY
278
    const char * xname = name;
279
    if (fromstdin)
280
        xname = "pipe:";
281
    int ret = avformat_open_input (&c, xname, NULL, NULL);
282
    if (ret)
283
    {
284
        AUDERR ("avformat_open_input failed for %s: %s.\n", xname, ffaudio_strerror (ret));
285
        return nullptr;
286
    }
287

    
288
    return c;
289
}
290

    
291
static void close_input_file (AVFormatContext * c, CodecInfo * cinfo, CodecInfo * vcinfo)
292
{
293
    if (play_video_wason) {
294
        avcodec_close(vcinfo->context);
295
    }
296
    play_video_wason = play_video;
297
    avcodec_close(cinfo->context);
298
#if CHECK_LIBAVFORMAT_VERSION (53, 25, 0, 53, 17, 0)
299
    avformat_close_input (&c);
300
#else
301
    av_close_input_file (c);
302
#endif
303

    
304
}
305

    
306
static bool find_codec (AVFormatContext * c, CodecInfo * cinfo, CodecInfo * vcinfo)
307
{
308
    avformat_find_stream_info (c, NULL);
309

    
310
    int videoStream=-1;
311
    int audioStream=-1;
312
    for (unsigned i = 0; i < c->nb_streams; i++)
313
    {
314
        if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
315
            videoStream=i;
316
        else if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audioStream < 0)
317
            audioStream=i;
318
    }
319
    if (audioStream==-1)   //PUNT IF NO AUDIO SINCE AUDACIOUS IS AN *AUDIO* PLAYER!
320
        return false;
321

    
322
    AVCodec * codec = avcodec_find_decoder (c->streams[audioStream]->codec->codec_id);
323
    if (codec)
324
    {
325
        cinfo->stream_idx = audioStream;
326
        cinfo->stream = c->streams[audioStream];
327
        cinfo->context = c->streams[audioStream]->codec;
328
        cinfo->codec = codec;
329

    
330
        //JWT:NOW SEE IF WE GOT A VIDEO STREAM TOO:
331
        if (play_video && videoStream >= 0)
332
        {
333
            AVCodec * vcodec = avcodec_find_decoder (c->streams[videoStream]->codec->codec_id);
334
            if (vcodec)
335
            {
336
                vcinfo->stream_idx = videoStream;
337
                vcinfo->stream = c->streams[videoStream];
338
                vcinfo->context = c->streams[videoStream]->codec;
339
                vcinfo->codec = vcodec;
340
            }
341
        }
342
        return true;
343
    }
344

    
345
    return false;
346
}
347

    
348
bool FFaudio::is_our_file (const char * filename, VFSFile & file)
349
{
350
    return (bool) get_format (filename, file);
351
}
352

    
353
static const struct {
354
    Tuple::ValueType ttype;  /* Tuple field value type */
355
    Tuple::Field field;      /* Tuple field constant */
356
    const char * keys[5];    /* Keys to match (case-insensitive), ended by nullptr */
357
} metaentries[] = {
358
    {Tuple::String, Tuple::Artist, {"author", "hor", "artist", nullptr}},
359
    {Tuple::String, Tuple::Title, {"title", "le", nullptr}},
360
    {Tuple::String, Tuple::Album, {"album", "WM/AlbumTitle", nullptr}},
361
    {Tuple::String, Tuple::Performer, {"performer", nullptr}},
362
    {Tuple::String, Tuple::Copyright, {"copyright", nullptr}},
363
    {Tuple::String, Tuple::Genre, {"genre", "WM/Genre", nullptr}},
364
    {Tuple::String, Tuple::Comment, {"comment", nullptr}},
365
    {Tuple::String, Tuple::Composer, {"composer", nullptr}},
366
    {Tuple::Int, Tuple::Year, {"year", "WM/Year", "date", nullptr}},
367
    {Tuple::Int, Tuple::Track, {"track", "WM/TrackNumber", nullptr}},
368
};
369

    
370
static void read_metadata_dict (Tuple & tuple, AVDictionary * dict)
371
{
372
    for (auto & meta : metaentries)
373
    {
374
        AVDictionaryEntry * entry = nullptr;
375

    
376
        for (int j = 0; ! entry && meta.keys[j]; j ++)
377
            entry = av_dict_get (dict, meta.keys[j], nullptr, 0);
378

    
379
        if (entry && entry->value)
380
        {
381
            if (meta.ttype == Tuple::String)
382
                tuple.set_str (meta.field, entry->value);
383
            else if (meta.ttype == Tuple::Int)
384
                tuple.set_int (meta.field, atoi (entry->value));
385
        }
386
    }
387
}
388

    
389
Tuple FFaudio::read_tuple (const char * filename, VFSFile & file)
390
{
391
    Tuple tuple;
392
    fromstdin = strstr(filename, "://-.") ? true : false;
393
    if (fromstdin)
394
    {
395
        tuple.set_filename (filename);
396
    }
397
    else   /* JWT:THIS STUFF DEFERRED UNTIL PLAY FOR STDIN, BUT SEEMS TO HAVE TO BE HERE FOR DIRECT */
398
    {
399
        AVFormatContext * ic = open_input_file (filename, file);
400

    
401
        if (ic)
402
        {
403
            if (find_codec (ic, & cinfo, & vcinfo))
404
            {
405
                tuple.set_filename (filename);
406

    
407
                tuple.set_int (Tuple::Length, ic->duration / 1000);
408
                tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
409
                if (cinfo.codec->long_name)
410
                    tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
411

    
412
                if (ic->metadata)
413
                    read_metadata_dict (tuple, ic->metadata);
414
                if (cinfo.stream->metadata)
415
                    read_metadata_dict (tuple, cinfo.stream->metadata);
416
            }
417

    
418
            close_input_file (ic, & cinfo, & vcinfo);
419
        }
420

    
421
        if (tuple && ! file.fseek (0, VFS_SEEK_SET))
422
            audtag::tuple_read (tuple, file);
423
    }
424
AUDDBG ("---- returning tuple.\n");
425
    return tuple;
426
}
427

    
428
bool FFaudio::write_tuple (const char * filename, VFSFile & file, const Tuple & tuple)
429
{
430
    if (str_has_suffix_nocase (filename, ".ape"))
431
        return audtag::tuple_write (tuple, file, audtag::TagType::APE);
432

    
433
    return audtag::tuple_write (tuple, file, audtag::TagType::None);
434
}
435

    
436
Index<char> FFaudio::read_image (const char * filename, VFSFile & file)
437
{
438
    if (str_has_suffix_nocase (filename, ".m4a") || str_has_suffix_nocase (filename, ".mp4"))
439
        return read_itunes_cover (filename, file);
440

    
441
    return Index<char> ();
442
}
443

    
444
bool FFaudio::play (const char * filename, VFSFile & file)
445
{
446
    AUDDBG ("Playing %s.\n", filename);
447

    
448
    AVPacket pkt = AVPacket();
449
    int errcount;
450
    /* bool codec_opened = false; */
451
    int out_fmt;
452
    bool planar;
453
    bool error = false;
454
  SDL_Overlay     *bmp = nullptr;
455
  SDL_Surface     *screen = nullptr;
456
  SDL_Rect        rect;
457
  SDL_Event       event;
458
  int video_width = 0;
459
  int video_height = 0;
460
  play_video_wason = play_video;
461
  float video_aspect_ratio = 0;
462
    struct SwsContext *sws_ctx = NULL;
463

    
464
    Index<char> buf;
465

    
466
    AVFormatContext * ic = open_input_file (filename, file);
467
    const char * fileext = strrchr (filename, '.');
468
    if (ic)
469
    {
470
        if (fromstdin)  /* JWT:FOR STDIN: TRY TO GET "read_tuple()" STUFF NOW, SINCE FILE COULD NOT BE READ EARLIER IN read_tuple()! */
471
        {
472
            Tuple tuple;
473
AUDDBG ("---- playing from STDIN: get TUPLE stuff now: IC is defined\n");
474
            if (find_codec (ic, & cinfo, & vcinfo))
475
            {
476
                tuple.set_filename (filename);
477

    
478
                tuple.set_int (Tuple::Length, ic->duration / 1000);
479
                tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
480
                if (cinfo.codec->long_name)
481
                    tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
482

    
483
                if (ic->metadata)
484
                    read_metadata_dict (tuple, ic->metadata);
485
                if (cinfo.stream->metadata)
486
                    read_metadata_dict (tuple, cinfo.stream->metadata);
487
                set_playback_tuple (tuple.ref ());
488
            }
489
            else
490
            {
491
                AUDERR ("No codec found for %s.\n", filename);
492
                goto error_exit;
493
            }
494
        }
495
        else
496
        {
497
            if (! find_codec (ic, & cinfo, & vcinfo))
498
            {
499
                AUDERR ("No codec found for %s.\n", filename);
500
                goto error_exit;
501
            }
502
        }
503
    }
504
    else
505
        return false;
506

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

    
509
    if (avcodec_open2 (cinfo.context, cinfo.codec, NULL) < 0)
510
        goto error_exit;
511
    if (play_video)   //JWT:abUSER ALSO WANTS TO PLAY VIDEO, SO SET UP POP-UP VIDEO SCREEN:
512
    {
513
        String video_windowtitle;
514
        int video_sws_scale = 0;
515
        if (avcodec_open2 (vcinfo.context, vcinfo.codec, NULL) < 0)
516
            goto error_exit;
517

    
518
        // Allocate a place to put our YUV image on that screen (initialize to video's size,
519
        // then (later) resize to user's size prefs if specified (must do this way to get video to scale:
520
#ifndef __DARWIN__
521
        screen = SDL_SetVideoMode(vcinfo.context->width, vcinfo.context->height, 0, SDL_RESIZABLE);
522
AUDERR("--DARWIN--\n");
523
#else
524
        screen = SDL_SetVideoMode(vcinfo.context->width, vcinfo.context->height, 24, SDL_RESIZABLE);
525
AUDERR("--NOT Darwin--\n");
526
#endif
527

    
528
        video_windowtitle = aud_get_str ("ffaudio", "video_windowtitle");
529
        if (video_windowtitle)
530
            SDL_WM_SetCaption(video_windowtitle, NULL);
531
        if (aud_get_int ("ffaudio", "video_sws_scale"))
532
            video_sws_scale = aud_get_int ("ffaudio", "video_sws_scale");
533
        else
534
            video_sws_scale = SWS_BICUBIC;  //default=4
535

    
536
        bmp = SDL_CreateYUVOverlay(
537
            vcinfo.context->width,
538
            vcinfo.context->height,
539
            SDL_YV12_OVERLAY,
540
            screen
541
        );
542
AUDERR("-sws_scale=%d=\n", video_sws_scale);
543
        sws_ctx = sws_getContext (
544
                   vcinfo.context->width,
545
                   vcinfo.context->height,
546
                   vcinfo.context->pix_fmt,
547
                   vcinfo.context->width,
548
                   vcinfo.context->height,
549
                   PIX_FMT_YUV420P,
550
                   video_sws_scale,
551
                   NULL,
552
                   NULL,
553
                   NULL
554
        );
555

    
556
        //NOW CALCULATE THE WIDTH, HEIGHT, & ASPECT BASED ON VIDEO'S SIZE & AND ANY USER PARAMATERS GIVEN:
557
        video_aspect_ratio = vcinfo.context->height
558
            ? (float)vcinfo.context->width / (float)vcinfo.context->height : 1.0;
559
AUDDBG("-BEF: wxh =%d=%d= aspect=%f=\n", vcinfo.context->width, vcinfo.context->height, video_aspect_ratio);
560
        int vx = aud_get_int ("ffaudio", "video_xsize");
561
        int vy = aud_get_int ("ffaudio", "video_ysize");
562
        if (! strcmp_nocase (fileext, ".flv"))   //JWT:FIXME:FLV STREAMS ERROR OUT ON ATTEMPT TO RESIZE?!
563
            vx = vy = 0;
564
        if (vx && !vy)   //user specified width only, calc. height based on aspect:
565
        {
566
            vcinfo.context->width = video_width = vx;
567
            vcinfo.context->height = video_height = (int)((float)vx / video_aspect_ratio);
568
        }
569
        else if (!vx && vy)   //user specified height only, calc. height based on aspect:
570
        {
571
            vcinfo.context->height = video_height = vy;
572
            vcinfo.context->width = video_width = (int)((float)vy * video_aspect_ratio);
573
            
574
        }
575
        else if (vx && vy)   //user specified fixed width and height:
576
        {
577
            vcinfo.context->width = video_width = vx;
578
            vcinfo.context->height = video_height = vy;
579
        }
580
        else   //user specified nothing, use video's desired wXh:
581
        {
582
            video_width = vcinfo.context->width;
583
            video_height = vcinfo.context->height;
584
        }
585
        video_aspect_ratio = video_height
586
            ? (float)video_width / (float)video_height : 1.0;   //fall thru to square to avoid possibliity of "/0"!
587

    
588
        //NOW "RESIZE" screen to user's wXh, if user set something:
589
        if (vx || vy)
590
        {
591
#ifndef __DARWIN__
592
            screen = SDL_SetVideoMode(video_width, video_height, 0, SDL_RESIZABLE);
593
#else
594
            screen = SDL_SetVideoMode(video_width, video_height, 24, SDL_RESIZABLE);
595
#endif
596

    
597
AUDDBG("-AFT: wxh =%d=%d= =%d=%d= aspect=%f=\n", vcinfo.context->width, vcinfo.context->height, video_width, video_height, video_aspect_ratio);
598
            if(!screen) {
599
                AUDERR("SDL: could not re-set video mode - exiting\n");
600
                goto error_exit;
601
            }
602
        }
603
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
604
            AUDERR("Could not initialize SDL - %s\n", SDL_GetError());
605
            goto error_exit;
606
        }
607
        rect.x = 0;
608
        rect.y = 0;
609
    }
610

    
611
    /* codec_opened = true; */
612

    
613
    switch (cinfo.context->sample_fmt)
614
    {
615
        case AV_SAMPLE_FMT_U8: out_fmt = FMT_U8; planar = false; break;
616
        case AV_SAMPLE_FMT_S16: out_fmt = FMT_S16_NE; planar = false; break;
617
        case AV_SAMPLE_FMT_S32: out_fmt = FMT_S32_NE; planar = false; break;
618
        case AV_SAMPLE_FMT_FLT: out_fmt = FMT_FLOAT; planar = false; break;
619

    
620
        case AV_SAMPLE_FMT_U8P: out_fmt = FMT_U8; planar = true; break;
621
        case AV_SAMPLE_FMT_S16P: out_fmt = FMT_S16_NE; planar = true; break;
622
        case AV_SAMPLE_FMT_S32P: out_fmt = FMT_S32_NE; planar = true; break;
623
        case AV_SAMPLE_FMT_FLTP: out_fmt = FMT_FLOAT; planar = true; break;
624

    
625
    default:
626
        AUDERR ("Unsupported audio format %d\n", (int) cinfo.context->sample_fmt);
627
        goto error_exit;
628
    }
629

    
630
    /* Open audio output */
631
    AUDDBG("opening audio output - bitrate=%d=\n", ic->bit_rate);
632

    
633
    set_stream_bitrate(ic->bit_rate);
634

    
635
    open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels);
636

    
637
    errcount = 0;
638

    
639
//AUDDBG ("--starting loop\n");
640
    int seek_value, ret, frameFinished, decoded, len, size;
641
    while (! check_stop ())
642
    {
643
        seek_value = check_seek ();
644

    
645
        if (seek_value >= 0)
646
        {
647
AUDDBG("-----POSITIVE SEEK (%d)!\n", seek_value);
648
            SDL_Delay(100);
649
            if (av_seek_frame (ic, -1, (int64_t) seek_value * AV_TIME_BASE /
650
             1000, AVSEEK_FLAG_ANY) < 0)
651
            {
652
                AUDERR ("error while seeking\n");
653
            } else
654
                errcount = 0;
655

    
656
            seek_value = -1;
657
        }
658

    
659
        AVPacket tmp;
660

    
661
        /* Read next frame (or more) of data */
662
        if ((ret = av_read_frame(ic, &pkt)) < 0)
663
        {
664
            if (ret == (int) AVERROR_EOF)
665
            {
666
                AUDDBG("eof reached\n");
667
                break;
668
            }
669
            else
670
            {
671
                if (++errcount > 4)
672
                {
673
                    AUDERR ("av_read_frame error %d, giving up.\n", ret);
674
                    break;
675
                } else
676
                    continue;
677
            }
678
        } else
679
            errcount = 0;
680

    
681
        /* Ignore any other substreams */
682
        if (pkt.stream_index != cinfo.stream_idx)
683
        {
684
            if (!play_video || pkt.stream_index != vcinfo.stream_idx)
685
            {
686
                av_free_packet(&pkt);
687
                continue;
688
            }
689
        }
690

    
691
        /* Decode and play packet/frame */
692
        memcpy(&tmp, &pkt, sizeof(tmp));
693
        frameFinished = 0;
694
        while (tmp.size > 0 && ! check_stop ())
695
        {
696
            /* Check for seek request and bail out if we have one */
697
            if (seek_value < 0) {
698
                seek_value = check_seek ();
699
            }
700
            if (seek_value >= 0) {
701
AUDDBG("--SEEK_VALUE >= 0 (%d), *** EXEC BREAK! ***\n", seek_value);
702
                SDL_Delay(50);
703
                break;
704
            }
705

    
706
#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
707
            AVFrame * frame = av_frame_alloc ();
708
#else
709
            AVFrame * frame = avcodec_alloc_frame ();
710
#endif
711

    
712
            decoded = 0;
713
            if (pkt.stream_index == cinfo.stream_idx)  //PROCESS AUDIO PACKETS:
714
            {
715
//AUDDBG("-audio frame\n");
716
                len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);
717
                if (len < 0)
718
                {
719
                    AUDERR ("decode_audio() failed, code %d\n", len);
720
                    break;
721
                }
722

    
723
                tmp.size -= len;
724
                tmp.data += len;
725

    
726
                if (! decoded)
727
                {
728
#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
729
                    av_frame_free (& frame);
730
#elif CHECK_LIBAVCODEC_VERSION (54, 59, 100, 54, 28, 0)
731
                    avcodec_free_frame (& frame);
732
#else
733
                    av_free (frame);
734
#endif
735
AUDERR("****** CONTINUING! ******\n");  /* JWT:NOT SURE WHY THIS IS A CONTINUE INSTEAD OF A BREAK?! */
736
                    continue;
737
                }
738

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

    
741
                if (planar)
742
                {
743
                    if (size > buf.len ())
744
                        buf.resize (size);
745

    
746
                    audio_interlace ((const void * *) frame->data, out_fmt,
747
                     cinfo.context->channels, buf.begin (), frame->nb_samples);
748
                    write_audio (buf.begin (), size);
749
                }
750
                else
751
                    write_audio (frame->data[0], size);
752
            }
753
            else    /* JWT:PROCESS VIDEO PACKETS HERE: */
754
            {
755
//AUDDBG("-video frame\n");
756
                len = avcodec_decode_video2(vcinfo.context, frame, &frameFinished, &pkt);
757
                // Did we get a video frame?
758
                if (len < 0)
759
                {
760
                    AUDERR ("decode_video() failed, code %d\n", len);
761
                    break;
762
                }
763

    
764
                if (frameFinished) {
765
                    SDL_LockYUVOverlay(bmp);
766
                    AVPicture pict;
767
                    pict.data[0] = bmp->pixels[0];
768
                    pict.data[1] = bmp->pixels[2];
769
                    pict.data[2] = bmp->pixels[1];
770
                    pict.linesize[0] = bmp->pitches[0];
771
                    pict.linesize[1] = bmp->pitches[2];
772
                    pict.linesize[2] = bmp->pitches[1];
773
                    // Convert the image into YUV format that SDL uses
774
                    sws_scale(sws_ctx, (uint8_t const * const *)frame->data,
775
                        frame->linesize, 0, vcinfo.context->height,
776
                        pict.data, pict.linesize);
777
                    SDL_UnlockYUVOverlay(bmp);
778
        
779
                    rect.w = video_width;
780
                    rect.h = video_height;
781
                    SDL_DisplayYUVOverlay(bmp, &rect);
782
                    break;
783
                }
784
            }
785

    
786
#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
787
            av_frame_free (& frame);
788
#elif CHECK_LIBAVCODEC_VERSION (54, 59, 100, 54, 28, 0)
789
            avcodec_free_frame (& frame);
790
#else
791
            av_free (frame);
792
#endif
793

    
794
            if (play_video)
795
            {
796
                SDL_PollEvent(&event);
797
                switch(event.type) {
798
                case SDL_QUIT:
799
                    SDL_Quit();
800
                    play_video = false;
801
                    //goto error_exit;
802
                    break;
803
                case SDL_VIDEORESIZE:
804
                    //Resize the screen
805
                    float new_aspect_ratio;  //FOR SOME REASON C++ REQUIRES 2 LINES HERE?!
806
                    new_aspect_ratio = event.resize.h
807
                        ? (float)event.resize.w / (float)event.resize.h : 1.0;
808
AUDDBG("-Resize:  w=%d= h=%d=\n", vcinfo.context->width, vcinfo.context->height);
809
                    if (new_aspect_ratio > video_aspect_ratio)
810
                    {
811
                        video_height = event.resize.h;
812
      //FIXEDNOW?!                  if (video_height > vcinfo.context->height)  //JWT:SEGFAULTS OTHERWISE?!
813
      //                      video_height = vcinfo.context->height;
814
                        video_width = (int)(video_aspect_ratio * (float)video_height);
815
                    }
816
                    else
817
                    {
818
                        video_width = event.resize.w;
819
      //                  if (video_width > vcinfo.context->width)  //JWT:SEGFAULTS OTHERWISE?!
820
      //                      video_width = vcinfo.context->width;
821
                        video_height = (int)((float)video_width / video_aspect_ratio);
822
                    }
823
AUDDBG("-RESIZE to %d x %d, %d x %d! aspect=%f=\n", event.resize.w, event.resize.h, video_width, video_height, video_aspect_ratio);
824

    
825
#ifndef __DARWIN__
826
                    screen = SDL_SetVideoMode( video_width, video_height, 0, SDL_RESIZABLE );
827
#else
828
                    screen = SDL_SetVideoMode( video_width, video_height, 24, SDL_RESIZABLE );
829
#endif
830

    
831
                    //If there's an error
832
                    if( screen == NULL )
833
                        break;
834
                default:
835
                    break;
836
                }
837
            }
838
        }
839
        if (pkt.data)
840
            av_free_packet(&pkt);
841
    }
842

    
843
error_exit:
844
AUDDBG("-at error exit...\n");
845
    if (play_video)
846
        SDL_Quit();
847
    if (pkt.data)
848
        av_free_packet(&pkt);
849
    if (ic != nullptr)
850
        close_input_file(ic, & cinfo, & vcinfo);
851

    
852
    return ! error;
853
}
854

    
855
const char FFaudio::about[] =
856
 N_("Multi-format audio decoding plugin for Audacious using\n"
857
    "FFmpeg multimedia framework (http://www.ffmpeg.org/)\n"
858
    "\n"
859
    "Audacious plugin by:\n"
860
    "William Pitcock <nenolod@nenolod.net>\n"
861
    "Matti Hämäläinen <ccr@tnsp.org>");
862

    
863
const char * const FFaudio::exts[] = {
864
    /* musepack, SV7/SV8 */
865
    "mpc", "mp+", "mpp",
866

    
867
    /* windows media audio */
868
    "wma",
869

    
870
    /* shorten */
871
    "shn",
872

    
873
    /* atrac3 */
874
    "aa3", "oma",
875

    
876
    /* MPEG 2/4 AC3 */
877
    "ac3",
878

    
879
    /* monkey's audio */
880
    "ape",
881

    
882
    /* DTS */
883
    "dts",
884

    
885
    /* VQF */
886
    "vqf",
887

    
888
    /* MPEG-4 */
889
    "m4a", "mp4",
890

    
891
    /* WAV (there are some WAV formats sndfile can't handle) */
892
    "wav",
893

    
894
    /* Handle OGG streams (FLAC/Vorbis etc.) */
895
    "ogg", "oga",
896

    
897
    /* Opus */
898
    "opus",
899

    
900
    /* Speex */
901
    "spx",
902

    
903
    /* end of table */
904
    nullptr
905
};
906

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