📄 baseclass.h
字号:
/* * Copyright (C) 2005-2007 gulikoza * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id$ */#ifndef BASECLASS_H#define BASECLASS_H#define MODULE "Thread"class Thread {private: MUTEX * th_mutex; SDL_Thread * thread; SDL_semaphore * ack; // 0 - exit, 1 - running bool thread_status;protected: // Entry point must be static static int EntryPoint(void * pthis) { Thread *pt = (Thread*)pthis; return pt->Start(); } // Start cannot be virtual (called from this-> pointer) int Start() { thread_status = true; SDL_SemPost(ack); DEBUG_MSG("Thread %u starting..", SDL_ThreadID()); int ret = Run(); DEBUG_MSG("Thread %u is finishing..", SDL_ThreadID()); thread_status = false; return ret; } // Function to override in derived class virtual int Run() = 0; // Call in main thread loop bool ThreadRun() { MUTEX_LOCK(th_mutex); bool status = thread_status; MUTEX_UNLOCK(th_mutex);#ifndef RELEASE if(status == false) { LOG_MSG("Thread %u is ending", SDL_ThreadID()); }#endif return status; } bool ThreadPause() {#ifdef SEM_SILENT SDL_SemWait(ack);#else while(SDL_SemWaitTimeout(ack, 1000) == SDL_MUTEX_TIMEDOUT) { ERROR_MSG("Semaphore timeout expired, line: %d, thread: %u", __LINE__, SDL_ThreadID()); }#endif MUTEX_LOCK(th_mutex); bool ret = thread_status; MUTEX_UNLOCK(th_mutex); return ret; } Thread():thread(NULL),thread_status(false) { th_mutex = MUTEX_CREATE(); if(th_mutex == NULL) throw "Thread: Failed to create mutex"; ack = SDL_CreateSemaphore(0); if(ack == NULL) { MUTEX_DESTROY(th_mutex); throw "Thread: Failed to create semaphore"; } } virtual ~Thread() { if(thread) TerminateThread(); MUTEX_DESTROY(th_mutex); SDL_DestroySemaphore(ack); }public: void ThreadCreate() { if(thread) { LOG_MSG("Thread %u already exists!?", SDL_GetThreadID(thread)); return; } DEBUG_MSG("Thread %u creating new worker thread", SDL_ThreadID()); MUTEX_LOCK(th_mutex); thread = SDL_CreateThread(EntryPoint, this); // Wait to get ack from the thread#ifdef SEM_SILENT SDL_SemWait(ack);#else while(SDL_SemWaitTimeout(ack, 1000) == SDL_MUTEX_TIMEDOUT) { ERROR_MSG("Semaphore timeout expired, line: %d, thread: %u", __LINE__, SDL_ThreadID()); }#endif MUTEX_UNLOCK(th_mutex); DEBUG_MSG("Worker thread %u created successfully", SDL_GetThreadID(thread)); } void TerminateThread(bool wait = true) { if(thread) { LOG_MSG("Thread %u is terminating thread %u", SDL_ThreadID(), SDL_GetThreadID(thread)); MUTEX_LOCK(th_mutex); thread_status = false; MUTEX_UNLOCK(th_mutex); SDL_SemPost(ack); if(wait) { SDL_WaitThread(thread, NULL); thread = NULL; } } } void ThreadUnpause() { if(!SDL_SemValue(ack)) SDL_SemPost(ack); } bool ThreadStatus() { if(!thread) return false; MUTEX_LOCK(th_mutex); bool ret = thread_status; MUTEX_UNLOCK(th_mutex); return ret; }};#undef MODULE// Renderer receives data from decoder in main thread and renders it in another#include "overlay.h"// Source class receives data in a seperate thread and feeds it directly to the splitter.// Open() and Close() should be called from main program. Run() should be overridden,// it runs in a seperate thread and is responsible for creating the splitter object#define MODULE "Source"class Source : public Thread {private:protected: virtual int Run() = 0;public: Source() { LOG_MSG("Created source in thread %u", SDL_ThreadID()); } virtual bool Open(CStr&) = 0; virtual void configure(const void *) = 0; virtual ~Source() { LOG_MSG("Destroyed source in thread %u", SDL_ThreadID()); }};#undef MODULE// Decoder receives data from Splitter in main thread and decodes it in a seperate thread// main program is responsible for connecting the renderer#define MODULE "Decoder"struct Packet { bool pes_flag; unsigned int pts; unsigned int size; unsigned char *data; Packet():pes_flag(false),pts(0),size(0),data(NULL) { }};class Decoder : public Thread {private: MUTEX * dlock;protected: unsigned char * buffer; SDL_semaphore * data; const bool wait; const unsigned int buffersize; unsigned int roffset, woffset; void * filterinfo; FIFO * fifo;private: int BufferOverrun(unsigned int pos) { LOG_MSG("Buffer overrun at pos: %d, roffset %d, data dropped", pos, roffset); return 0; }protected: int LockBuffer() { if(MUTEX_LOCK(dlock) == -1) { ERROR_MSG("Mutex lock failed!"); return 0; } return 1; } int UnlockBuffer() { if(MUTEX_UNLOCK(dlock) == -1) { ERROR_MSG("Mutex unlock failed!"); return 0; } return 1; } virtual int Run() = 0;public: Decoder(const bool w, const unsigned int buf = BUFFERSIZE): wait(w),buffersize(buf),roffset(0),woffset(0),filterinfo(NULL),fifo(NULL) { dlock = MUTEX_CREATE(); if(dlock == NULL) throw "Decoder: Failed to create mutex"; data = SDL_CreateSemaphore(0); if(data == NULL) { MUTEX_DESTROY(dlock); throw "Decoder: Failed to create semaphore"; } buffer = (unsigned char*)_aligned_malloc(sizeof(char)*buffersize, 64); if(buffer == NULL) { MUTEX_DESTROY(dlock); SDL_DestroySemaphore(data); throw "Decoder: Failed to allocate memory for buffer"; } SDL_memset(buffer, 0, buffersize); LOG_MSG("Created decoder in thread %u, buffer 0x%x-0x%x", SDL_ThreadID(), buffer, buffer+buffersize); } void SetFilterInfo(void * f) { filterinfo = f; } bool WriteData(Packet * packet) { if(!ThreadStatus() && !wait) { DEBUG_MSG("Decoder thread not running, data dropped"); return false; } if(LockBuffer()) { // Wrap buffer - leave some space at the end // (see FF_INPUT_BUFFER_PADDING_SIZE) if(woffset+packet->size > buffersize-8) { // Get last pes start position if(!packet->pes_flag) { unsigned int offset = fifo->GetCurrentPacket(); woffset = woffset - offset; DEBUG_MSG("Buffer wrap: Copying %d bytes to pos 0", woffset); // If roffset is between 0 and woffset declare buffer overrun if((roffset < woffset) && (!BufferOverrun(woffset))) { UnlockBuffer(); return false; } SDL_memcpy(buffer, buffer+offset, woffset); fifo->ResetCurrentPacket(0); } else { fifo->ResetCurrentPacket(woffset); woffset = 0; } } // Handle buffer overruns if((woffset < roffset) && (woffset + packet->size > roffset)) { if(!BufferOverrun(woffset+packet->size)) { UnlockBuffer(); return false; } } if(buffer) { // This is 184 bytes max void * pt = buffer+woffset; small_memcpy(pt, packet->data, packet->size); // Indicate new data is present at PES start if(packet->pes_flag) { // Add packet to fifo queue fifo->AddPacket(woffset, packet->pts); } // Advance pointers woffset += packet->size; DEBUG_MSG("Wrote %d bytes from %d to %d (read offset: %d)", packet->size, woffset - packet->size, woffset, roffset); } else { ERROR_MSG("Buffer error! Dropping %d bytes", packet->size); } UnlockBuffer(); } else { ERROR_MSG("Error locking buffer! Data lost."); return false; } return true; } virtual ~Decoder() { MUTEX_DESTROY(dlock); SDL_DestroySemaphore(data); if(buffer) _aligned_free(buffer); LOG_MSG("Destroyed decoder in thread %u", SDL_ThreadID()); }};#undef MODULE// Splitter class receives data from Source and feeds it to the decoders#define MODULE "Splitter"class Splitter {private:protected: // decoders Decoder * videodec; Decoder * audiodec;public: Splitter():videodec(NULL),audiodec(NULL) { LOG_MSG("Created splitter in thread %u", SDL_ThreadID()); } virtual int ProcessData(unsigned char*, int) = 0; virtual ~Splitter() { SAFE_DELETE(videodec); SAFE_DELETE(audiodec); LOG_MSG("Destroyed splitter in thread %u", SDL_ThreadID()); }};#undef MODULE#endif // BASECLASS_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -