5a6
>  * Video-playing capability added Copyright © 2015 Jim Turner <turnerjw784@yahoo.com>
20a22,25
> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
> 
33a39,56
> #include <stdint.h>
> #include "libavutil/common.h"
> #include "libavutil/dict.h"
> #include "libavutil/log.h"
> #include "libavformat/version.h"
> #include "libavformat/avio.h"
> extern "C" {
> #include <SDL_syswm.h>
> #include <libswscale/swscale.h>
> }
> #include <X11/Xlib.h>
> #include <SDL.h>
> #include <SDL_thread.h>
> 
> #define SDL_AUDIO_BUFFER_SIZE 4096
> #define MAX_AUDIO_FRAME_SIZE 192000
> 
> 
64a88,89
> static bool play_video;  /* JWT: TRUE IF USER IS CURRENTLY PLAYING VIDEO (KILLING VID. WINDOW TURNS OFF! */
> 
73a99,217
> /* 
>     JWT: ADDED ALL THIS QUEUE STUFF TO SMOOTH VIDEO PERFORMANCE SO THAT VIDEO FRAMES WOULD 
>     BE OUTPUT MORE INTERLACED WITH THE AUDIO FRAMES BY QUEUEING VIDEO FRAMES UNTIL AN 
>     AUDIO FRAME IS PROCESSED, THEN DEQUEUEING AND PROCESSING 'EM WITH EACH AUDIO FRAME.  
>     THE SIZE OF THIS QUEUE IS SET BY video_qsize CONFIG PARAMETER AND DEFAULTS TO 16.
>     HAVING TOO MANY CAN RESULT IN DELAYED VIDEO, SO EXPERIMENT.  IDEALLY, PACKETS SHOULD 
>     BE PROCESSED:  V A V A V A..., BUT THIS HANDLES:  
>     V1 V2 V3 V4 V5 A1 A2 A3 A4 A5 A6 A7 V7 A8... AS: 
>     (q:V1 V2 V3 V4 V5 V6) A1 A2 dq:V1 A3 A4 dq:V2 A5 A6 dq:V3 A7 A8...
>     WE DON'T WANT TO INTERRUPT AUDIO PERFORMANCE AND I DON'T KNOW HOW TO THREAD IT UP,
>     BUT THIS SIMPLE APPROACH SEEMS TO WORK PRETTY SMOOTH FOR ME!  OTHERWISE TRY 
>     INCREASING video_qsize IN config file OTHERWISE.
>     BORROWED THESE FUNCTIONS FROM:
>     http://www.thelearningpoint.net/computer-science/data-structures-queues--with-c-program-source-code
> */
> 
> typedef struct 
> {
>     int capacity;
>     int size;
>     int front;
>     int rear;
>     AVPacket *elements;
> }
> pktQueue;
> 
> pktQueue * createQueue (int maxElements)
> {
>     /* Create a Queue */
>     pktQueue *Q;
>     Q = (pktQueue *)malloc(sizeof(pktQueue));
>     /* Initialise its properties */
>     Q->elements = (AVPacket *)malloc(sizeof(AVPacket)*maxElements);
>     Q->size = 0;
>     Q->capacity = maxElements;
>     Q->front = 0;
>     Q->rear = -1;
>     /* Return the pointer */
>     return Q;
> }
> 
> bool Dequeue (pktQueue *Q)
> {
>     /* If Queue size is zero then it is empty. So we cannot pop */
>     if(Q->size==0)
>         return false;
>     /* Removing an element is equivalent to incrementing index of front by one */
>     else
>     {
>         Q->size--;
>         if (Q->elements[Q->front].data)
>             av_free_packet(&Q->elements[Q->front]);
> 
>         Q->front++;
>         /* As we fill elements in circular fashion */
>         if(Q->front==Q->capacity)
>             Q->front=0;
>     }
>     return true;
> }
> 
> /* JWT:FLUSH AND FREE EVERYTHING IN THE QUEUE */
> void QFlush (pktQueue *Q)
> {
>     while (Q->size > 0)
>     {
>         Q->size--;
>         if (Q->elements[Q->front].data)
>             av_free_packet(&Q->elements[Q->front]);
> 
>         Q->front++;
>         /* As we fill elements in circular fashion */
>         if(Q->front==Q->capacity)
>             Q->front=0;
>     }
> 
> }
> 
> AVPacket * QFront (pktQueue *Q)
> {
>     if(Q->size==0)
>     {
>             AUDDBG("Queue is Empty\n");
>             return nullptr;
>     }
>     /* Return the element which is at the front*/
>     return &Q->elements[Q->front];
> }
> 
> bool isQueueFull (pktQueue *Q)
> {
>     return (Q->size == Q->capacity) ? true : false;
> }
> 
> bool Enqueue (pktQueue *Q, AVPacket element)
> {
>     /* If the Queue is full, we cannot push an element into it as there is no space for it.*/
>     if(Q->size == Q->capacity)
>     {
>             printf("Queue is Full\n");
>             return false;
>     }
>     else
>     {
>             Q->size++;
>             Q->rear = Q->rear + 1;
>             /* As we fill the queue in circular fashion */
>             if(Q->rear == Q->capacity)
>             {
>                     Q->rear = 0;
>             }
>             /* Insert the element in its rear side */ 
>             Q->elements[Q->rear] = element;
>     }
>     return true;
> }
> 
> /* JWT:END OF ADDED VIDEO PACKET QUEUEING FUNCTIONS */
> 
243c387,388
<     AVInputFormat * f = get_format (name, file);
---
>     int ret;
>     AVFormatContext * c;
245c390,391
<     if (! f)
---
>     play_video = aud_get_bool ("ffaudio", "play_video");   /* JWT:RESET PLAY-VIDEO, CASE TURNED OFF ON PREV. PLAY. */
>     if (!strcmp(name, "-") || strstr(name, "://-."))
247,248c393,401
<         AUDERR ("Unknown format for %s.\n", name);
<         return nullptr;
---
>         AUDDBG("-open_input_file(stdin)\n");
>         c = NULL;
>         const char * xname = "pipe:";
>         ret = avformat_open_input (&c, xname, NULL, NULL);
>         if (ret < 0)
>         {
>             AUDERR ("avformat_open_input failed for %s: %s.\n", xname, ffaudio_strerror (ret));
>             return nullptr;
>         }
249a403,406
>     else
>     {
>         AUDDBG("-open_input_file(%s)\n", name);
>         AVInputFormat * f = get_format (name, file);
251,253c408,412
<     AVFormatContext * c = avformat_alloc_context ();
<     AVIOContext * io = io_context_new (file);
<     c->pb = io;
---
>         if (! f)
>         {
>             AUDERR ("Unknown format for %s.\n", name);
>             return nullptr;
>         }
255c414,416
<     int ret = avformat_open_input (& c, name, f, nullptr);
---
>         AVFormatContext * c = avformat_alloc_context ();
>         AVIOContext * io = io_context_new (file);
>         c->pb = io;
257,261c418,424
<     if (ret < 0)
<     {
<         AUDERR ("avformat_open_input failed for %s: %s.\n", name, ffaudio_strerror (ret));
<         io_context_free (io);
<         return nullptr;
---
>         ret = avformat_open_input (&c, name, f, nullptr);
>         if (ret < 0)
>         {
>             AUDERR ("avformat_open_input failed for %s: %s.\n", name, ffaudio_strerror (ret));
>             io_context_free (io);
>             return nullptr;
>         }
263a427
>     AUDDBG("-open_input_file - success!\n");
267c431
< static void close_input_file (AVFormatContext * c)
---
> static void close_input_file (AVFormatContext * c, bool fromstdin)
269c433,436
<     AVIOContext * io = c->pb;
---
>     AVIOContext * io = NULL;
> 
>     if (!fromstdin)
>         io = c->pb;
277c444,445
<     io_context_free (io);
---
>     if (!fromstdin)
>         io_context_free (io);
280c448
< static bool find_codec (AVFormatContext * c, CodecInfo * cinfo)
---
> static bool find_codec (AVFormatContext * c, CodecInfo * cinfo, CodecInfo * vcinfo)
282c450,452
<     avformat_find_stream_info (c, nullptr);
---
>     int videoStream;
>     int audioStream;
>     avformat_find_stream_info (c, NULL);
283a454,455
>     videoStream=-1;
>     audioStream=-1;
286c458,464
<         AVStream * stream = c->streams[i];
---
>         if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
>             videoStream=i;
>         else if (c->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audioStream < 0)
>             audioStream=i;
>     }
>     if (audioStream==-1)   /* PUNT IF NO AUDIO SINCE AUDACIOUS IS AN *AUDIO* PLAYER! */
>         return false;
288,290c466,472
<         if (stream && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
<         {
<             AVCodec * codec = avcodec_find_decoder (stream->codec->codec_id);
---
>     AVCodec * codec = avcodec_find_decoder (c->streams[audioStream]->codec->codec_id);
>     if (codec)
>     {
>         cinfo->stream_idx = audioStream;
>         cinfo->stream = c->streams[audioStream];
>         cinfo->context = c->streams[audioStream]->codec;
>         cinfo->codec = codec;
292c474,478
<             if (codec)
---
>         /* JWT: NOW IF USER WANTS VIDEO, SEE IF WE GOT A VIDEO STREAM TOO: */
>         if (play_video && videoStream >= 0)
>         {
>             AVCodec * vcodec = avcodec_find_decoder (c->streams[videoStream]->codec->codec_id);
>             if (vcodec)
294,299c480,483
<                 cinfo->stream_idx = i;
<                 cinfo->stream = stream;
<                 cinfo->context = stream->codec;
<                 cinfo->codec = codec;
< 
<                 return true;
---
>                 vcinfo->stream_idx = videoStream;
>                 vcinfo->stream = c->streams[videoStream];
>                 vcinfo->context = c->streams[videoStream]->codec;
>                 vcinfo->codec = vcodec;
301a486,489
>         else
>             play_video = false;  /* turn off video playback, since we could not find stream! */
> 
>         return true;
351,353c539,545
<     AVFormatContext * ic = open_input_file (filename, file);
< 
<     if (ic)
---
>     bool fromstdin;
>     
>     fromstdin = (!strcmp(filename, "-") || strstr(filename, "://-.")) ? true : false;
>     AUDDBG("Filename =%s=\n", filename);
>     if (fromstdin)
>         tuple.set_filename (filename);
>     else   /* JWT:THIS STUFF DEFERRED UNTIL PLAY() FOR STDIN, BUT SEEMS TO HAVE TO BE HERE FOR DIRECT */
355c547
<         CodecInfo cinfo;
---
>         AVFormatContext * ic = open_input_file (filename, file);
357c549
<         if (find_codec (ic, & cinfo))
---
>         if (ic)
359c551
<             tuple.set_filename (filename);
---
>             CodecInfo cinfo, vcinfo;
361,362c553,555
<             tuple.set_int (Tuple::Length, ic->duration / 1000);
<             tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
---
>             if (find_codec (ic, & cinfo, & vcinfo))
>             {
>                 tuple.set_filename (filename);
364,365c557,567
<             if (cinfo.codec->long_name)
<                 tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
---
>                 tuple.set_int (Tuple::Length, ic->duration / 1000);
>                 tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
>                 if (cinfo.codec->long_name)
>                     tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
>                 if (ic->metadata)
>                     read_metadata_dict (tuple, ic->metadata);
>                 if (cinfo.stream->metadata)
>                     read_metadata_dict (tuple, cinfo.stream->metadata);
>                 if (play_video && vcinfo.stream->metadata)
>                     read_metadata_dict (tuple, vcinfo.stream->metadata);
>             }
367,370c569
<             if (ic->metadata)
<                 read_metadata_dict (tuple, ic->metadata);
<             if (cinfo.stream->metadata)
<                 read_metadata_dict (tuple, cinfo.stream->metadata);
---
>             close_input_file (ic, fromstdin);
373c572,576
<         close_input_file (ic);
---
>         if (tuple && ! file.fseek (0, VFS_SEEK_SET))
>             audtag::tuple_read (tuple, file);
>             /* JWT:BUILD NOTE:  IF USING LATEST AUDACIOUS VERSIONS YOU MAY NEED TO REPLACE ABOVE LINE WITH:
>                 audtag::read_tag (file, & tuple, nullptr);
>             */
376,378d578
<     if (tuple && ! file.fseek (0, VFS_SEEK_SET))
<         audtag::read_tag (file, & tuple, nullptr);
< 
387c587,592
<     return audtag::tuple_write (tuple, file, audtag::TagType::None);
---
>     /* return audtag::tuple_write (tuple, file, audtag::TagType::None); */
>     /* JWT:FIXME: FOR SOME REASON ABOVE LINE WON'T COMPILE WITH SDL_syswm.h AND X11/Xlib.h INCLUDED?!?!
>         "error: expected unqualified-id before numeric constant return audtag::tuple_write (tuple, file, audtag::TagType::None);"
>         SO REPLACED WITH NEXT LINE:
>     */
>     return audtag::tuple_write (tuple, file, audtag::TagType::ID3v2);
397a603,670
> /* JWT: NEW FUNCTION TO WRITE VIDEO FRAMES TO THE POPUP WINDOW: */
> void write_videoframe (SwsContext * sws_ctx, CodecInfo * cinfo, CodecInfo * vcinfo, 
>     AVFrame * vframe, SDL_Overlay * bmp, AVPacket *pkt, int video_width, int video_height)
> {
>     SDL_Rect rect;
> 
>     int len = 0;
>     int frameFinished = 0;
>     while (1)
>     {
>         len = avcodec_decode_video2 (vcinfo->context, vframe, &frameFinished, pkt);
>         /* Did we get a video frame? */
>         if (len < 0)
>         {
>             AUDERR ("decode_video() failed, code %d\n", len);
>             return;
>         }
>         else if (frameFinished)
>         {
>             AVPicture pict = { { 0 } };
>             SDL_LockYUVOverlay(bmp);
>             pict.data[0] = bmp->pixels[0];
>             pict.data[1] = bmp->pixels[2];
>             pict.data[2] = bmp->pixels[1];
>             pict.linesize[0] = bmp->pitches[0];
>             pict.linesize[1] = bmp->pitches[2];
>             pict.linesize[2] = bmp->pitches[1];
>             /* Convert the image into YUV format that SDL uses. */
>             sws_scale(sws_ctx, (uint8_t const * const *)vframe->data,
>                 vframe->linesize, 0, vcinfo->context->height,
>                 pict.data, pict.linesize);
>             SDL_UnlockYUVOverlay(bmp);
> 
>             rect.x = 0;
>             rect.y = 0;
>             rect.w = video_width;
>             rect.h = video_height;
>             SDL_DisplayYUVOverlay(bmp, &rect);
>             AUDDBG("+++++Process video packet\n");
>             return;
>         }
>     }
> }
> 
> /* JWT: (*nix ONLY) NEW FUNCTION TO SAVE POPUP VIDEO WINDOW'S LOCATION TO CONFIG SO IT POPS UP THERE NEXT TIME! */
> /* FIXME:NEED DIFFERENT CODE TO ADD THIS FEATURE TO WINDOWS! */
> void save_window_xy ()
> {
> #ifndef _WINDOWS
>     SDL_SysWMinfo info;
>     SDL_VERSION(&info.version);
>     if (SDL_GetWMInfo(&info) > 0)
>     {
>         int x=0,y=0;
>         Window chldwin;
>         XWindowAttributes attr0, attr;
>         info.info.x11.lock_func();
>         XGetWindowAttributes(info.info.x11.display, info.info.x11.wmwindow, &attr0);
>         XGetWindowAttributes(info.info.x11.display, info.info.x11.window, &attr);
>         XTranslateCoordinates(info.info.x11.display, info.info.x11.window, attr.root, attr.x, attr.y, &x, &y, &chldwin);
>         info.info.x11.unlock_func();
>         aud_set_int ("ffaudio", "video_window_x", (x-attr0.x)-1);
>         aud_set_int ("ffaudio", "video_window_y", (y-attr0.y)-1);
>         aud_set_int ("ffaudio", "video_window_w", attr.width);
>         aud_set_int ("ffaudio", "video_window_h", attr.height);
>     }
> #endif
> }
404a678
>     bool vcodec_opened = false;
407,408c681,694
<     bool error = false;
< 
---
>     bool error;
>     SDL_Overlay     *bmp;    /* JWT: ALL SDL_* STUFF IS FOR PLAYING VIDEOS */
>     SDL_Surface     *screen;
>     SDL_Event       event;
>     int video_width;
>     int video_height;
>     int video_window_x;
>     int video_window_y;
>     int video_window_w;
>     int video_window_h;
>     float video_aspect_ratio;
>     int video_resizedelay;
>     bool fromstdin;   /* JWT:SAVE (static)fromstdin's STATE AT START OF PLAY, SINCE PROBES WILL CHANGE IT IN PLAYLIST ADVANCE BEFORE WE CLOSE! */
>     struct SwsContext *sws_ctx;
410a697,710
>     video_width = 0;
>     video_height = 0;
>     video_window_x = 0;
>     video_window_y = 0;
>     video_window_w = 0;
>     video_window_h = 0;
>     video_aspect_ratio = 0;
>     video_resizedelay = aud_get_int ("ffaudio", "video_resizedelay");
> 
>     fromstdin = (!strcmp(filename, "-") || strstr(filename, "://-.")) ? true : false;
>     error = false;
>     bmp = nullptr;
>     screen = nullptr;
>     sws_ctx = NULL;
415c715
<     CodecInfo cinfo;
---
>     CodecInfo cinfo, vcinfo;
417c717
<     if (! find_codec (ic, & cinfo))
---
>     if (fromstdin)  /* JWT: FOR STDIN: TRY TO GET "read_tuple()" STUFF NOW, SINCE FILE COULD NOT BE OPENED EARLIER IN read_tuple()! */
419,420c719,750
<         AUDERR ("No codec found for %s.\n", filename);
<         goto error_exit;
---
>         Tuple tuple;
> 
>         AUDDBG ("---- playing from STDIN: get TUPLE stuff now: IC is defined\n");
>         if (find_codec (ic, & cinfo, & vcinfo))
>         {
>             tuple.set_filename (filename);
> 
>             tuple.set_int (Tuple::Length, ic->duration / 1000);
>             tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
>             if (cinfo.codec->long_name)
>                 tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
>             if (ic->metadata)
>                 read_metadata_dict (tuple, ic->metadata);
>             if (cinfo.stream->metadata)
>                 read_metadata_dict (tuple, cinfo.stream->metadata);
>             if (play_video && vcinfo.stream->metadata)
>                 read_metadata_dict (tuple, vcinfo.stream->metadata);
>             set_playback_tuple (tuple.ref ());
>         }
>         else
>         {
>             AUDERR ("No codec found for %s.\n", filename);
>             goto error_exit;
>         }
>     }
>     else
>     {
>         if (! find_codec (ic, & cinfo, & vcinfo))
>         {
>             AUDERR ("No codec found for %s.\n", filename);
>             goto error_exit;
>         }
423c753
<     AUDDBG("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx);
---
>     AUDDBG ("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx);
425c755
<     if (avcodec_open2 (cinfo.context, cinfo.codec, nullptr) < 0)
---
>     if (avcodec_open2 (cinfo.context, cinfo.codec, NULL) < 0)
429a760,906
>     /* JWT: IF abUSER ALSO WANTS TO PLAY VIDEO THEN WE SET UP POP-UP VIDEO SCREEN: */
>     if (play_video)
>     {
>         int vx, vy, vw, vh;
>         String video_windowtitle;
>         int video_sws_scale;
>         int video_xmove = 0;
> 
>         vx = vy = vw = vh = 0;
>         video_xmove = aud_get_int ("ffaudio", "video_xmove");
>         /*  -1:always let windowmanager place (random); 0(default):place window via
>             SDL_putenv() - may work with Windows?; 1:relocate window via XMoveWindow
>             (X-specific); 2:both (0, then 1).  This is sometimes useful for multiple X
>             desktops where the default of placing the window via SDL_putenv will ALWAYS
>             place the window in the same desktop that Audacious is in.  By setting to 1,
>             the window will be moved to the proper location relative to the current
>             desktop, and Audacious is treated as "sticky" by the window manager.  Setting
>             to 2 MAY be useful IF for some reason, none of the other choices work properly.
>         */
>         video_window_x = video_window_y = video_window_w = video_window_h = 0;
>         video_sws_scale = 0;
>         /* GET SAVED PREV. VIDEO WINDOW LOCN. AND SIZE AND TRY TO PLACE NEW WINDOW ACCORDINGLY: */
>         /* JWT: I ADDED THIS TO AVOID NEW VID. WINDOW RANDOMLY POPPING UP IN NEW LOCN., IE. WHEN REPEATING A VIDEO. */
>         video_window_x = aud_get_int ("ffaudio", "video_window_x");
>         video_window_y = aud_get_int ("ffaudio", "video_window_y");
>         video_window_w = aud_get_int ("ffaudio", "video_window_w");
>         video_window_h = aud_get_int ("ffaudio", "video_window_h");
>         /* FIXME?:*MIGHT?* NEED DIFFERENT CODE TO ADD THIS FEATURE TO WINDOWS! */
>         if (video_xmove >= 0 && video_xmove != 1)
>         {
>             char video_windowpos[40];
>             sprintf (video_windowpos, "SDL_VIDEO_WINDOW_POS=%d,%d", video_window_x, video_window_y);
>             putenv (video_windowpos);
>         }
>         if (avcodec_open2 (vcinfo.context, vcinfo.codec, NULL) < 0)
>             goto error_exit;
> 
>         vcodec_opened = true;
> 
>         /* NOW CALCULATE THE WIDTH, HEIGHT, & ASPECT BASED ON VIDEO'S SIZE & AND ANY USER PARAMATERS GIVEN:
>             IDEALLY, ONE SHOULD ONLY SET X OR Y AND LET Audacious CALCULATE THE OTHER DIMENSION,
>             SO THAT THE ASPECT RATIO IS MAINTAINED, THOUGH ONE CAN SPECIFY BOTH AND FORCE
>             THE ASPECT TO BE ADJUSTED TO FIT.  IF A SINGLE ONE IS SPECIFIED AS "-1", THEN
>             THE NEW WINDOW WILL KEEP THE SAME VALUE FOR THAT DIMENSION AS THE PREV. WINDOW,
>             AND ADJUST THE OTHER DIMENTION ACCORDINGLY TO FIT THE NEW VIDEO'S ASPECT RATIO.
>         */        
>         video_aspect_ratio = vcinfo.context->height
>             ? (float)vcinfo.context->width / (float)vcinfo.context->height : 1.0;
>         vx = aud_get_int ("ffaudio", "video_xsize");
>         vy = aud_get_int ("ffaudio", "video_ysize");
>         if (vx && !vy)   /* User specified (or saved) width only, calc. height based on aspect: */
>         {
>             video_width = (vx == -1) ? (video_window_w ? video_window_w : vcinfo.context->width) : vx;
>             video_height = (int)((float)video_width / video_aspect_ratio);
>         }
>         else if (!vx && vy)   /* User specified (or saved) height only, calc. height based on aspect: */
>         {
>             video_height = (vy == -1) ? (video_window_h ? video_window_h : vcinfo.context->height) : vy;
>             video_width = (int)((float)video_height * video_aspect_ratio);
>             
>         }
>         else if (vx && vy)   /* User specified fixed width and height: */
>         {
>             if (vx == -1 && vy == -1)  /* Use saved settings or video's settings (SCREW THE ASPECT)! */
>             {
>                 video_width = video_window_w ? video_window_w : vcinfo.context->width;
>                 video_height = video_window_h ? video_window_h : vcinfo.context->height;
>             }
>             else if (vx == -1)  /* Use specified height & calculate new width based on aspect: */
>             {
>                 video_height = vy;
>                 video_width = (int)((float)video_height * video_aspect_ratio);
>             }
>             else if (vy == -1)  /* Use specified width & calculate new height based on aspect: */
>             {
>                 video_width = vx;
>                 video_height = (int)((float)video_width / video_aspect_ratio);
>             }
>             else  /* User specified window size (SCREW THE ASPECT)! */
>             {
>                 video_width = vx;
>                 video_height = vy;
>             }
>         }
>         else   /* User specified nothing, use the video's desired wXh (& ignore saved settings!): */
>         {
>             video_width = vcinfo.context->width;
>             video_height = vcinfo.context->height;
>         }
>         video_aspect_ratio = video_height
>             ? (float)video_width / (float)video_height : 1.0;   /* Fall thru to square to avoid possibliity of "/0"! */
> 
>         /* NOW "RESIZE" screen to user's wXh, if user set something: */
> #ifndef __DARWIN__
>         screen = SDL_SetVideoMode (video_width, video_height, 0, SDL_RESIZABLE);
> #else
>         screen = SDL_SetVideoMode (video_width, video_height, 24, SDL_RESIZABLE);
> #endif
>         if (!screen) {
>             AUDERR ("SDL: could not re-set video mode - exiting\n");
>             goto error_exit;
>         }
>         if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER))
>         {
>             AUDERR ("Could not initialize SDL - %s\n", SDL_GetError());
>             goto error_exit;
>         }
>         /* JWT:FIXME:IF *nix THEN MOVE (POPUP) WINDOW (AGAIN) TO WHERE IT WAS LEFT LAST TIME (ONLY IF USER SAYS WE NEED THIS (ie. ALT. DESKTOP) */
> #ifndef _WINDOWS
>         if (video_xmove > 0)
>         {
>             SDL_SysWMinfo info;
>             SDL_VERSION (&info.version);
>             if (SDL_GetWMInfo (&info) > 0 ) {
>                 SDL_Delay(50);
>                 XMoveWindow (info.info.x11.gfxdisplay, info.info.x11.wmwindow, video_window_x, video_window_y);
>             }
>         }
> #endif
>         video_windowtitle = aud_get_str ("ffaudio", "video_windowtitle");
>         if (video_windowtitle)
>             SDL_WM_SetCaption(video_windowtitle, NULL);
>         if (aud_get_int ("ffaudio", "video_sws_scale"))   /* USER CAN CHOOSE SWS_SCALE VALUE. */
>             video_sws_scale = aud_get_int ("ffaudio", "video_sws_scale");
>         else
>             video_sws_scale = SWS_BICUBIC;  /* default=4 (SWS_BICUBIC). */
> 
>         bmp = SDL_CreateYUVOverlay(
>             vcinfo.context->width,
>             vcinfo.context->height,
>             SDL_YV12_OVERLAY,
>             screen
>         );
>         sws_ctx = sws_getContext (
>           	 vcinfo.context->width,
>           	 vcinfo.context->height,
>           	 vcinfo.context->pix_fmt,
>           	 vcinfo.context->width,
>         	   vcinfo.context->height,
>           	 PIX_FMT_YUV420P,
>           	 video_sws_scale,
>           	 NULL,
>           	 NULL,
>         	   NULL
>         );
>     }
> 
448c925
<     AUDDBG("opening audio output\n");
---
>     AUDDBG("opening audio output - bitrate=%d=\n", ic->bit_rate);
450,451c927,928
<     set_stream_bitrate(ic->bit_rate);
<     open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels);
---
>     set_stream_bitrate (ic->bit_rate);
>     open_audio (out_fmt, cinfo.context->sample_rate, cinfo.context->channels);
454a932,963
>     int seek_value, ret, decoded, len, size, video_qsize, acount, vcount;
>     bool knit1perl2;
>     acount = 0; vcount = 0;  /* JWT:LET'S COUNT PACKETS OF EACH SIZE FOR DEBUGGING. */
>     AVFrame * frame;
>     AVFrame * vframe;
>     /* JWT:video_qsize:  MAX # VIDEO PACKETS TO QUEUE UP FOR INTERLACING TO SMOOTH VIDEO 
>         PLAYBACK - GOOD RANGE IS 8-56, NOT ENOUGH=JITTERY VIDEO, 
>         TOO MANY=AUDIO/VIDEO BECOME NOTICABLY OUT OF SYNC!
>     */
>     video_qsize = (aud_get_int ("ffaudio", "video_qsize"))
>         ? aud_get_int ("ffaudio", "video_qsize") : 16;
>     if (video_qsize < 1)
>         video_qsize = 1;
> 
>     pktQueue *pktQ;
>     pktQ = createQueue (video_qsize);
>     /* 
>         JWT: THIS FLAG FORCES THE VIDEO QUEUE TO BE POPPED ONCE FOR EVERY *TWO* AUDIO 
>         PACKETS - MOST VIDEOS SEEM TO HAVE A/B 2-1 RATIO OF AUDIO TO VIDEO PACKETS & 
>         THIS PRETTY MUCH *ELIMINATED* THE VIDEO JITTER!!!
>     */
>     knit1perl2 = true;  /* ALTERNATES BETWEEN ON AND OFF EVERY OTHER AUDIO PACKET */
> 
>     AUDDBG ("video queue size %d\n", video_qsize);
> #if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
>     frame = av_frame_alloc ();
>     vframe = av_frame_alloc ();
> #else
>     frame = avcodec_alloc_frame ();
>     vframe = avcodec_alloc_frame ();
> #endif
> 
457c966
<         int seek_value = check_seek ();
---
>         seek_value = check_seek ();
460a970,975
>             /* JWT:FIRST, FLUSH ANY VIDEO PACKETS SITTING IN THE QUEUE TO CLEAR THE QUEUE! */
>             QFlush (pktQ);
>             knit1perl2 = true;
> 
>             /* JWT: HAD TO CHANGE THIS FROM "AVSEEK_FLAG_ANY" TO AVSEEK_FLAG_BACKWARD 
>                 TO GET SEEK TO NOT RANDOMLY BRICK?! */
462c977
<              1000, AVSEEK_FLAG_ANY) < 0)
---
>                 1000, AVSEEK_FLAG_BACKWARD) < 0)
472d986
<         int ret;
475c989
<         if ((ret = av_read_frame(ic, &pkt)) < 0)
---
>         if ((ret = av_read_frame (ic, &pkt)) < 0)
479c993
<                 AUDDBG("eof reached\n");
---
>                 AUDDBG ("eof reached\n");
497,498c1011,1015
<             av_free_packet(&pkt);
<             continue;
---
>             if (!play_video || pkt.stream_index != vcinfo.stream_idx)
>             {
>                 av_free_packet (&pkt);
>                 continue;
>             }
502c1019
<         memcpy(&tmp, &pkt, sizeof(tmp));
---
>         memcpy (&tmp, &pkt, sizeof(tmp));
512,518c1029,1066
< #if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
<             AVFrame * frame = av_frame_alloc ();
< #else
<             AVFrame * frame = avcodec_alloc_frame ();
< #endif
<             int decoded = 0;
<             int len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);
---
>             decoded = 0;
>             if (pkt.stream_index == cinfo.stream_idx)  /* WE READ AN AUDIO PACKET: */
>             {
>                 ++acount;
>                 AUDDBG("-read audio frame\n");
>                 /* JWT:IF PLAYING VIDEO, CHECK VIDEO QUEUE. */
>                 if (play_video)
>                 {
>                     if (knit1perl2)
>                     {
>                         /* CHECK VIDEO QUEUE FIRST EVERY OTHER AUDIO PACKET AND POP AND
>                             PROCESS ONE VIDEO PACKET (BEFORE EVERY OTHER AUDIO PACKET)
>                         */
>                         AVPacket * pktRef;
> 
>                         if (!isQueueFull (pktQ))
>                             knit1perl2 = false;
>                         if ((pktRef = QFront (pktQ)))
>                         {
>                             write_videoframe (sws_ctx, & cinfo, & vcinfo, vframe, bmp, pktRef, 
>                                 video_width, video_height);
>                             if (!Dequeue (pktQ))
>                                 AUDDBG ("Queue is Empty\n");
>                         }
>                     }
>                     else
>                         knit1perl2 = true;  /* JWT:WE'RE ASSUMING LIKELY NEAR 2x AUDIO TO VIDEO FRAMES: */
>                 }
>                 /* NOW PROCESS THE AUDIO PACKET: */
>                 len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);
>                 if (len < 0)
>                 {
>                     AUDERR ("decode_audio() failed, code %d\n", len);
>                     break;
>                 }
> 
>                 tmp.size -= len;
>                 tmp.data += len;
520c1068,1087
<             if (len < 0)
---
>                 if (! decoded)
>                     /* continue;  // JWT:NOT SURE WHY THIS WAS A CONTINUE INSTEAD OF A BREAK?! */
>                     break;
> 
>                 size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples;
> 
>                 AUDDBG ("+++++Process AUDIO packet\n");
>                 if (planar)
>                 {
>                     if (size > buf.len ())
>                         buf.resize (size);
> 
>                     audio_interlace ((const void * *) frame->data, out_fmt,
>                      cinfo.context->channels, buf.begin (), frame->nb_samples);
>                     write_audio (buf.begin (), size);
>                 }
>                 else
>                     write_audio (frame->data[0], size);
>             }
>             else    /* WE READ A VIDEO PACKET: */
522c1089,1111
<                 AUDERR ("decode_audio() failed, code %d\n", len);
---
>                 ++vcount;
>                 /* JWT: IF QUEUE IS FULL, PROCESS NEXT VIDEO PACKET FROM QUEUE. */
>                 AUDDBG ("+read video frame\n");
>                 if (isQueueFull (pktQ))
>                 {
>                     AVPacket * pktRef;
> 
>                     if ((pktRef = QFront (pktQ)))
>                     {
>                         write_videoframe (sws_ctx, & cinfo, & vcinfo, vframe, bmp, pktRef, 
>                             video_width, video_height);
>                         if (!Dequeue (pktQ))
>                             AUDERR ("Queue is Empty\n");
>                     }
>                     AUDDBG ("Queue filled.\n");
>                 }
>                 /* JWT: VIDEO PACKETS TAKE A NUMBER & GET IN LINE! */
>                 if (Enqueue (pktQ, pkt))
>                 {
>                     knit1perl2 = true;
>                     break;
>                 }
>                 AUDERR ("Could not enqueue packet, refuses to wait in line, so shoot it!!\n");
526,527c1115,1125
<             tmp.size -= len;
<             tmp.data += len;
---
>             /* JWT: NOW HANDLE VIDEO UI EVENTS SUCH AS RESIZE OR KILL SCREEN: */
>             if (play_video)
>             {
>                 SDL_Rect rect;
>                 SDL_PollEvent (&event);
>                 switch (event.type) {
>                 case SDL_QUIT:
>                     save_window_xy();
>                     SDL_Quit ();
>                     play_video = false;
>                     break;
529,530c1127,1142
<             if (! decoded)
<                 continue;
---
>                 case SDL_VIDEORESIZE:
>                     /* Resize the screen. */
>                     float new_aspect_ratio;
> 
>                     new_aspect_ratio = event.resize.h
>                         ? (float)event.resize.w / (float)event.resize.h : 1.0;
>                     if (new_aspect_ratio > video_aspect_ratio)
>                     {
>                         video_height = event.resize.h;
>                         video_width = (int)(video_aspect_ratio * (float)video_height);
>                     }
>                     else
>                     {
>                         video_width = event.resize.w;
>                         video_height = (int)((float)video_width / video_aspect_ratio);
>                     }
532c1144,1148
<             int size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples;
---
> #ifndef __DARWIN__
>                     screen = SDL_SetVideoMode (video_width, video_height, 0, SDL_RESIZABLE);
> #else
>                     screen = SDL_SetVideoMode (video_width, video_height, 24, SDL_RESIZABLE);
> #endif
534,537c1150,1164
<             if (planar)
<             {
<                 if (size > buf.len ())
<                     buf.resize (size);
---
>                     /* If there's an error, punt! */
>                     if (video_resizedelay > 0)
>                         SDL_Delay(video_resizedelay);
>                     if (screen == NULL)
>                     {
>                         AUDERR ("Could not recreate screen after resizing!");
>                         break;
>                     }
>                 case SDL_VIDEOEXPOSE:
>                     rect.x = 0;
>                     rect.y = 0;
>                     rect.w = video_width;
>                     rect.h = video_height;
>                     SDL_DisplayYUVOverlay (bmp, &rect);
>                     break;
539,541c1166,1168
<                 audio_interlace ((const void * *) frame->data, out_fmt,
<                  cinfo.context->channels, buf.begin (), frame->nb_samples);
<                 write_audio (buf.begin (), size);
---
>                 default:
>                     break;
>                 }
543,544c1170,1179
<             else
<                 write_audio (frame->data[0], size);
---
>         }
>     }
> 
> error_exit:
>     AUDDBG("end of playback - % audio frames, % video frames processed.", acount, vcount);
>     if (play_video)
>     {
>         save_window_xy ();
>         SDL_Quit();
>     }
547c1182,1183
<             av_frame_free (& frame);
---
>     av_frame_free (& vframe);
>     av_frame_free (& frame);
549c1185,1186
<             avcodec_free_frame (& frame);
---
>     avcodec_free_frame (& vframe);
>     avcodec_free_frame (& frame);
551c1188,1189
<             av_free (frame);
---
>     av_free (vframe);
>     av_free (frame);
553d1190
<         }
555,559d1191
<         if (pkt.data)
<             av_free_packet(&pkt);
<     }
< 
< error_exit:
561c1193,1195
<         av_free_packet(&pkt);
---
>         av_free_packet (&pkt);
>     if (vcodec_opened)
>         avcodec_close(vcinfo.context);
565c1199
<         close_input_file(ic);
---
>         close_input_file (ic, fromstdin);
576c1210,1213
<     "Matti Hämäläinen <ccr@tnsp.org>");
---
>     "Matti Hämäläinen <ccr@tnsp.org>\n"
>     "\n"
>     "Video-playing capability (added 2015) by:\n"
>     "Jim Turner <turnerjw784@yahoo.com>");
619a1257,1262
> 
>     /* AVI  // JWT:ADDED */
>     "avi",
> 
>     /* FLV  // JWT:ADDED */
>     "flv",
