The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
SDL Multithreading
madprogrammer24


Joined: 12 Jun 2015
Posts: 9
Location: South Dakota
Hello Everybody,

I am having issues with multithreading, currently I am trying to split up my decoding and networking into separate threads. I can get the networking thread to fill the buffer just fine, but the issue seems to crop up after the decode thread gets signaled. The fillBuffer() method just seems to hang, and I know it is because it is waiting on the condition signal. What I don't understand is that the queue_cond for which the fillBuffer() is waiting is signaled after the decode thread finishes, so it should fire just fine.

Should I make the fillBuffer() it's own thread?

Or should I move my condition check somewhere else?

Any advice offered would be appreciated.

Code:

#include <WinSock2.h>
#include <WS2tcpip.h>
#include "wsrm.h"
#include <Windows.h>
#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <list>
#include <mfapi.h>
#include <mfplay.h>
#include <mfreadwrite.h>
#include <Mferror.h>
#include <wmcodecdsp.h>
#include <mutex>
#include <thread>
#include <condition_variable>
#include "SDL.h"
#include "SDL_thread.h"
#include "concurrentqueue.h"
#include "LTimer.h"

#ifdef _WIN32
#undef main
#endif

extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/mathematics.h"
#include "libavutil/old_pix_fmts.h"
#include "libswscale/swscale.h"
}

#define CHUNK_SIZE 512

#define FF_ALLOC_EVENT (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
#define FF_QUIT_EVENT (SDL_USEREVENT + 2)

#define CHECK_HR(hr, msg) if(hr != S_OK){ printf(msg); printf("Error: %.2X.\n", hr); }

typedef struct madProto
{
   uint16_t frame_num;
   uint16_t nal_type;
   uint16_t nal_length;
   uint16_t frame_length;
   uint16_t num_of_nals;
   uint16_t frame_end;
   uint8_t payload[1300];
} MadProto;

static int decodeThread(void *arg);
static int receiveThread(void *arg);
int packetQueuePut(MadProto proto);

std::mutex mtx;
std::condition_variable cv;
std::thread thread;

HANDLE mutex;
HANDLE DecodeHandle = NULL;

SDL_Thread *receive;
SDL_Thread *decode;
SDL_mutex *queue_mutex;
SDL_cond *queue_cond;
SDL_cond *frame_end;

SDL_bool frameEndCond = SDL_FALSE;

SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *bmp = NULL;
SDL_Rect rect;

std::ofstream file;
FILE *f;
bool quit = false;

ULONG              localif;
SOCKET s;
SOCKET ns;
SOCKADDR_IN        multi, safrom;
int fromlen;

int totalSize = 0;
int horizontal = 0;
int vertical = 0;

std::vector<uint8_t> buffer;

AVCodec *codec;
AVCodecContext *codecContext;
int frame;
int got_picture;
AVFrame *picture;
AVFrame *pictureRGB;
AVPacket packet;
AVPicture myPicture;
SwsContext* convertContext;
AVCodecParserContext *parser;

//The frames per second timer
LTimer fpsTimer;

//The frames per second cap timer
LTimer capTimer;

//Start counting frames per second
int countedFrames = 0;

static void fillBuffer(MadProto proto)
{
   uint16_t nal_length = ntohs(proto.nal_length);
   
   SDL_LockMutex(queue_mutex);
   std::cout << "filling buffer, no mutex lock" << std::endl;

   while (frameEndCond)
   {
      std::cout << "fillBuffer()   waiting on condition frame_end" << std::endl;
      std::cout << "frameEndCond in fillBuffer(): " << frameEndCond << std::endl;
      int rc = SDL_CondWait(queue_cond, queue_mutex);

      if (rc < 0)
         std::cout << "SDL_CondWait failed: " << SDL_GetError() << std::endl;
   }

   std::cout << "filling buffer, locking queue_mutex" << std::endl;
   std::copy(proto.payload, proto.payload + nal_length, std::back_inserter(buffer));
   std::cout << "queue size: " << buffer.size() << std::endl;
   std::cout << "frameEndCond: " << frameEndCond << std::endl;
   std::cout << "unlocking queue_mutex" << std::endl;
   SDL_UnlockMutex(queue_mutex);
}

static int receiveThread(void *arg)
{
   fpsTimer.start();

   // This loop receives, decodes, and displays the frame.
   while (true)
   {
      //Uint32 startTime = SDL_GetTicks();
      //Start cap timer
      capTimer.start();

      MadProto proto;
      int result = recvfrom(ns, (char *)&proto, sizeof(MadProto), 0, (struct sockaddr *)&multi, &fromlen);

      //Calculate and correct fps
      float avgFPS = countedFrames / (fpsTimer.getTicks() / 1000.f);
      if (avgFPS > 2000000)
      {
         avgFPS = 0;
      }

      if (result < 0)
      {
         std::cout << "receive failed! error: " << WSAGetLastError() << std::endl;
         break;
      }
      else
      {
         std::cout << "receive successful, received " << result << " bytes" << std::endl;

         // Frame has ended, now decode and display
         if (ntohs(proto.frame_end) == 1)
         {
            std::cout << "we have a frame end" << std::endl;
            
            uint8_t *frameData = buffer.data();
            int dataSize = buffer.size();
            uint8_t *outbuffer = NULL;
            int outBufSize = 0;

            //// Loop while given a valid size
            //while (dataSize)
            //{
            //   // parse the stream out
            int rc = av_parser_parse2(parser, codecContext, &outbuffer, &outBufSize, frameData, dataSize, 0, 0, 0);

            if (outBufSize <= 0)
            {
               std::cout << "parsing failed!" << std::endl;
               std::cout << "outBufSize: " << outBufSize << std::endl;
            }
            else
            {
               frameEndCond = SDL_TRUE;
               SDL_CondSignal(frame_end);
               buffer.empty();
            }

            //   frameData += rc;
            //   dataSize -= rc;

            //   if (outBufSize)
            //   {
            //      ++countedFrames;

            //      std::cout << "rc: " << rc << std::endl;
            //      std::cout << "parsing successful!" << std::endl;
            //      //std::cin.get();

            //      av_init_packet(&packet);
            //      packet.size = outBufSize;
            //      packet.data = outbuffer;

            //      frame = avcodec_decode_video2(codecContext, picture, &got_picture, &packet);

            //      if (frame < 0)
            //      {
            //         std::cout << "decoding was unsuccessful!" << std::endl;
            //         break;
            //      }

            //      if (got_picture)
            //      {
            //         unsigned char *pixels = NULL;
            //         int pitch;

            //         std::cout << "decoding was successful!" << std::endl;
            //         std::cout << "decoded length was: " << frame << std::endl;
            //         buffer.empty();

            //         int code = 0;

            //         code = SDL_UpdateYUVTexture(bmp, NULL, picture->data[0], picture->linesize[0],
            //            picture->data[1], picture->linesize[1],
            //            picture->data[2], picture->linesize[2]);

            //         if (code < 0)
            //         {
            //            std::cout << "updating failed! " << SDL_GetError() << std::endl;
            //            std::cin.get();
            //         }

            //         //If frame finished early
            //         int frameTicks = capTimer.getTicks();
            //         if (frameTicks < SCREEN_TICKS_PER_FRAME)
            //         {
            //            //Wait remaining time
            //            SDL_Delay(SCREEN_TICKS_PER_FRAME - frameTicks);
            //         }
            //      }

            //      av_free_packet(&packet);
            //   }
            //}

            //SDL_RenderClear(renderer);
            //SDL_RenderCopy(renderer, bmp, NULL, NULL);
            //SDL_RenderPresent(renderer);
         }
         else
         {
            std::cout << "calling fill buffer" << std::endl;

            //while (frameEndCond)
               //SDL_CondWait(queue_cond, queue_mutex);

            fillBuffer(proto);
            //std::copy(proto.payload, proto.payload + ntohs(proto.nal_length), std::back_inserter(buffer));
            //std::cout << "frame is continuing!" << std::endl;
         }
      }
   }
   return 0;
}

static int decodeThread(void *arg)
{
   //Screen dimension constants
   const int SCREEN_WIDTH = horizontal;
   const int SCREEN_HEIGHT = vertical;
   const int SCREEN_FPS = 60;
   const int SCREEN_TICKS_PER_FRAME = 1000 / SCREEN_FPS;

   int rc = 0;
   int count = 10;
   
   if (SDL_LockMutex(queue_mutex) == 0)
   {
      std::cout << "entering decode thread" << std::endl;

      while (!frameEndCond)
      {
         rc = SDL_CondWait(frame_end, queue_mutex);
         std::cout << "decodeThread() waiting on condition frame_end" << std::endl;

         if (rc < 0)
            std::cout << "SDL_CondWait failed: " << SDL_GetError() << std::endl;
      }

      std::cout << "pulling data from buffer" << std::endl;

      // just a test
      while (count > 0)
      {
         std::cout << "decoding!" << std::endl;
         count--;
      }
      /*uint8_t *frameData = buffer.data();
      int dataSize = buffer.size();
      uint8_t *outbuffer = NULL;
      int outBufSize = 0;
      buffer.empty();*/

      // Loop while given a valid size
      //while (dataSize)
      //{
      //   // parse the stream out
      //   int rc = av_parser_parse2(parser, codecContext, &outbuffer, &outBufSize, frameData, dataSize, 0, 0, 0);

      //   if (outBufSize <= 0)
      //   {
      //      std::cout << "parsing failed!" << std::endl;
      //      std::cout << "outBufSize: " << outBufSize << std::endl;
      //   }

      //   frameData += rc;
      //   dataSize -= rc;

      //   if (outBufSize)
      //   {
      //      ++countedFrames;

      //      std::cout << "rc: " << rc << std::endl;
      //      std::cout << "parsing successful!" << std::endl;

      //      av_init_packet(&packet);
      //      packet.size = outBufSize;
      //      packet.data = outbuffer;

      //      frame = avcodec_decode_video2(codecContext, picture, &got_picture, &packet);

      //      if (frame < 0)
      //      {
      //         std::cout << "decoding was unsuccessful!" << std::endl;
      //         break;
      //      }

      //      if (got_picture)
      //      {
      //         unsigned char *pixels = NULL;
      //         int pitch;

      //         std::cout << "decoding was successful!" << std::endl;
      //         std::cout << "decoded length was: " << frame << std::endl;
      //         buffer.empty();

      //         int code = 0;

      //         code = SDL_UpdateYUVTexture(bmp, NULL, picture->data[0], picture->linesize[0],
      //            picture->data[1], picture->linesize[1],
      //            picture->data[2], picture->linesize[2]);

      //         if (code < 0)
      //         {
      //            std::cout << "updating failed! " << SDL_GetError() << std::endl;
      //         }

      //         //If frame finished early
      //         int frameTicks = capTimer.getTicks();
      //         if (frameTicks < SCREEN_TICKS_PER_FRAME)
      //         {
      //            //Wait remaining time
      //            SDL_Delay(SCREEN_TICKS_PER_FRAME - frameTicks);
      //         }
      //      }

      //      av_free_packet(&packet);
      //   }
      //}

      //SDL_RenderClear(renderer);
      //SDL_RenderCopy(renderer, bmp, NULL, NULL);
      //SDL_RenderPresent(renderer);

      frameEndCond = SDL_FALSE;
      std::cout << "frameEndCondition in decode thread: " << frameEndCond << std::endl;
      SDL_UnlockMutex(queue_mutex);
      rc = SDL_CondSignal(queue_cond);

      if (rc < 0)
         std::cout << "unable to signal condition" << std::endl;
   }
   else
   {
      std::cout << "Unable to lock queue_mutex in decodeThread" << std::endl;
   }
   
   return 0;
}

const static uint8_t* getData()
{
   std::cout << "getting buffer data" << std::endl;

   SDL_LockMutex(queue_mutex);

   uint8_t *data = buffer.data();

   std::cout << "emptying buffer, queue_mutex has been locked" << std::endl;

   buffer.empty();

   SDL_UnlockMutex(queue_mutex);

   return data;
}

// Get the horizontal and vertical screen sizes in pixel
void GetDesktopResolution(int& horizontal, int& vertical)
{
   RECT desktop;
   // Get a handle to the desktop window
   const HWND hDesktop = GetDesktopWindow();
   // Get the size of screen to the variable desktop
   GetWindowRect(hDesktop, &desktop);
   // The top left corner will have coordinates (0,0)
   // and the bottom right corner will have coordinates
   // (horizontal, vertical)
   horizontal = desktop.right;
   vertical = desktop.bottom;
}

int main()
{
   SDL_Event event;

   WORD wVersionRequested;
   WSADATA wsaData;
   int wsaerr;

   if (SDL_Init(SDL_INIT_EVERYTHING)) {
      fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
      exit(1);
   }
   
   // Using MAKEWORD macro, Winsock version request 2.2
   wVersionRequested = MAKEWORD(2, 2);

   wsaerr = WSAStartup(wVersionRequested, &wsaData);

   if (wsaerr != 0)
   {
      /* Tell the user that we could not find a usable */
      /* WinSock DLL.*/
      printf("The Winsock dll not found!\n");
      return 0;
   }
   else
   {
      printf("The Winsock dll found!\n");
      printf("The status: %s.\n", wsaData.szSystemStatus);
   }

   /* Confirm that the WinSock DLL supports 2.2.*/
   /* Note that if the DLL supports versions greater    */
   /* than 2.2 in addition to 2.2, it will still return */
   /* 2.2 in wVersion since that is the version we      */
   /* requested.                                        */
   if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
   {
      /* Tell the user that we could not find a usable */
      /* WinSock DLL.*/
      printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
      WSACleanup();
      return 0;
   }
   else
   {
      printf("The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
      printf("The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
   }

   
   /*INT Ret;
   HANDLE ThreadHandle;
   DWORD ThreadId;
   WSAEVENT AcceptEvent;
   char               buf[1024];
   int                buflen = 1024, rc, err;*/

   
   uint16_t i = 1;
   //std::queue<MadProto> queue;
   //std::list<MadProto> list;
   

   const int WEBCAM_DEVICE_INDEX = 1;   // <--- Set to 0 to use default system webcam.
   const int SAMPLE_COUNT = 50;

   //std::ofstream outputBuffer("rawframes.yuv", std::ios::out | std::ios::binary);

   // setup MediaFoundation decoder, eventually will use this for testing
   IMFMediaSource *videoSource = NULL;
   UINT32 videoDeviceCount = 0;
   IMFAttributes *videoConfig = NULL;
   IMFActivate **videoDevices = NULL;
   IMFSourceReader *videoReader = NULL;
   WCHAR *webcamFriendlyName;
   IMFMediaType *videoSourceOutputType = NULL, *pSrcOutMediaType = NULL;
   IUnknown *spTransformUnk = NULL;
   IMFTransform *pTransform = NULL; // This is H264 Encoder MFT.
   IWMResamplerProps *spResamplerProps = NULL;
   IMFMediaType *pMFTInputMediaType = NULL, *pMFTOutputMediaType = NULL;

   IUnknown *spDecTransformUnk = NULL;
   IMFTransform *pDecoderTransform = NULL; // This is H264 Decoder MFT.
   IMFMediaType *pDecInputMediaType = NULL, *pDecOutputMediaType = NULL;
   DWORD mftStatus = 0;

   CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
   MFStartup(MF_VERSION);

   CHECK_HR(CoCreateInstance(CLSID_CMSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&spDecTransformUnk), "Failed to create H264 decoder MFT.\n");

   CHECK_HR(spDecTransformUnk->QueryInterface(IID_PPV_ARGS(&pDecoderTransform)), "Failed to get IMFTransform interface from H264 MFT.\n");

   MFCreateMediaType(&pDecInputMediaType);
   pDecInputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   pDecInputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
   pDecInputMediaType->SetUINT32(MF_MT_AVG_BITRATE, 240000);
   CHECK_HR(MFSetAttributeSize(pDecInputMediaType, MF_MT_FRAME_SIZE, 1920, 1080), "Failed to set frame size on H264 MFT.\n");
   CHECK_HR(MFSetAttributeRatio(pDecInputMediaType, MF_MT_FRAME_RATE, 30, 1), "Failed to set frame rate on H264 MFT.\n");
   CHECK_HR(MFSetAttributeRatio(pDecInputMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set aspect ratio on H264 MFT.\n");
   pDecInputMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2);
   pDecInputMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

   CHECK_HR(pDecoderTransform->SetInputType(0, pDecInputMediaType, 0), "Failed to set input medai type on H264 decoder MFT.\n");

   MFCreateMediaType(&pDecOutputMediaType);
   pDecOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   pDecOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV);
   CHECK_HR(MFSetAttributeSize(pDecOutputMediaType, MF_MT_FRAME_SIZE, 1920, 1080), "Failed to set frame size on decoder output MFT.\n");
   CHECK_HR(MFSetAttributeRatio(pDecOutputMediaType, MF_MT_FRAME_RATE, 30, 1), "Failed to set frame rate on H264 MFT out type.\n");
   CHECK_HR(MFSetAttributeRatio(pDecOutputMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set pixel aspect ratio on H264 out type.\n");
   pDecOutputMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2);
   
   CHECK_HR(pDecoderTransform->SetOutputType(0, pDecOutputMediaType, 0), "Failed to set output media type on H.264 decoder MFT.\n");
   CHECK_HR(pDecoderTransform->GetInputStatus(0, &mftStatus), "Failed to get input status from H.264 decoder MFT.\n");
   if (MFT_INPUT_STATUS_ACCEPT_DATA != mftStatus)
   {
      std::cout << "H.264 decoder MFT is not accepting data.\n";
      std::cin.get();
   }

   //moodycamel::ConcurrentQueue<MadProto> protoQueue;

   

   file.open("log.txt");

   s = socket(AF_INET, SOCK_STREAM, IPPROTO_RM);

   multi.sin_family = AF_INET;
   multi.sin_port = htons(5150);
   multi.sin_addr.s_addr = inet_addr("234.5.6.7");
   int bindResult = bind(s, (PSOCKADDR)&multi, sizeof(multi));

   if (bindResult < 0)
   {
      std::cout << "bindResult: " << WSAGetLastError() << std::endl;
   }

   listen(s, 10);

   //if ((AcceptEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
   //{
   //   printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());
   //   return 1;
   //}
   //else
   //   printf("WSACreateEvent() is OK!\n");

   //// Create a worker thread to service completed I/O requests
   //if ((ThreadHandle = CreateThread(NULL, 0, WorkerThread, (LPVOID)AcceptEvent, 0, &ThreadId)) == NULL)
   //{
   //   printf("CreateThread() failed with error %d\n", GetLastError());
   //   return 1;
   //}
   //else
   //   printf("CreateThread() should be fine!\n");

   localif = inet_addr("10.0.1.46");
   setsockopt(s, IPPROTO_RM, RM_ADD_RECEIVE_IF, (char *)&localif, sizeof(localif));

   fromlen = sizeof(safrom);
   ns = accept(s, (SOCKADDR *)&safrom, &fromlen);

   closesocket(s);  // Don't need to listen anymore

   std::string received;

   av_register_all();
   
   GetDesktopResolution(horizontal, vertical);

   codec = avcodec_find_decoder(CODEC_ID_H264);
   if (!codec) {
      std::cout << "codec not found" << std::endl;
      std::cin.get();
   }

   codecContext = avcodec_alloc_context3(codec);

   /*if (codec->capabilities & CODEC_CAP_TRUNCATED)
      codecContext->flags |= CODEC_FLAG_TRUNCATED;*/

   //codecContext->flags |= CODEC_FLAG_LOW_DELAY;
   codecContext->flags2 |= CODEC_FLAG2_CHUNKS;

   codecContext->width = horizontal;
   codecContext->height = vertical;
   codecContext->codec_id = CODEC_ID_H264;
   codecContext->codec_type = AVMEDIA_TYPE_VIDEO;
   codecContext->pix_fmt = PIX_FMT_YUV420P;
   codecContext->thread_type = 0;

   if (avcodec_open2(codecContext, codec, NULL) < 0) {
      std::cout << "could not open codec" << std::endl;
      std::cin.get();
   }

   convertContext = sws_getContext(
      codecContext->width,
      codecContext->height,
      PIX_FMT_YUV420P,
      codecContext->width,
      codecContext->height,
      PIX_FMT_RGB24,
      SWS_BICUBIC,
      NULL,
      NULL,
      NULL
      );

   parser = av_parser_init(CODEC_ID_H264);

   picture = av_frame_alloc();

   if (ns == INVALID_SOCKET)
   {
      std::cout << "accept didn't work!" << std::endl;
      std::cin.get();
   }

   /*if (WSASetEvent(AcceptEvent) == FALSE)
   {
      printf("WSASetEvent() failed with error %d\n", WSAGetLastError());
      return 1;
   }
   else
      printf("WSASetEvent() should be working!\n");*/

   window = SDL_CreateWindow("YUV", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, codecContext->width, codecContext->height, SDL_WINDOW_SHOWN);

   if (window == NULL)
   {
      std::cout << "window creation failed!" << SDL_GetError() << std::endl;
      std::cin.get();
   }

   renderer = SDL_CreateRenderer(window, -1, 0);

   if (renderer == NULL)
   {
      std::cout << "unable to create renderer! " << SDL_GetError() << std::endl;
      std::cin.get();
   }

   bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STATIC, codecContext->width, codecContext->height);

   if (bmp == NULL)
   {
      std::cout << "texture creation failed! " << SDL_GetError() << std::endl;
      std::cin.get();
   }

   //receive = SDL_CreateThread(receiveThread, "ReceiveThread", (void *)NULL);
   bool quit = false;

   rect.x = 0;
   rect.y = 0;
   rect.w = codecContext->width;
   rect.h = codecContext->height;

   MFT_OUTPUT_DATA_BUFFER decDataBuffer;
   DWORD processOutputStatus = 0;
   LONGLONG llVideoTimeStamp, llSampleDuration;
   HRESULT mftDecProcessOutput = S_OK;
   MFT_OUTPUT_STREAM_INFO StreamInfo;
   IMFSample *mftEncSample = NULL, *mftDecSample = NULL;
   DWORD mftDecFlags;
   
   memset(&decDataBuffer, 0, sizeof(decDataBuffer));

   int FPS = 25;

   // Create the threads, conditions and mutexes
   queue_mutex = SDL_CreateMutex();
   queue_cond = SDL_CreateCond();

   frame_end = SDL_CreateCond();

   std::cout << "creating receive thread" << std::endl;
   decode = SDL_CreateThread(decodeThread, "Decode Thread", NULL);
   receive = SDL_CreateThread(receiveThread, "ReceiveThread", NULL);
   


   for (;;)
   {
      SDL_PollEvent(&event);
      switch (event.type)
      {
      case SDL_QUIT:
         SDL_Quit();
         break;
      }
   }

   std::cout << "closing everything!" << std::endl;
   av_frame_free(&picture);
   closesocket(ns);
   fclose(f);
   std::cin.get();
   return 0;
}
madprogrammer24


Joined: 12 Jun 2015
Posts: 9
Location: South Dakota
Any suggestions on this? If I posted too much code I can narrow it down to the thread functions.