Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
291
Src/Plugins/Input/in_flv/VideoThread.cpp
Normal file
291
Src/Plugins/Input/in_flv/VideoThread.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include "main.h"
|
||||
#include "VideoThread.h"
|
||||
#include "api__in_flv.h"
|
||||
#include "FLVVideoHeader.h"
|
||||
#include <shlwapi.h>
|
||||
#include <windows.h>
|
||||
#include "../nu/threadname.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "../nu/SampleQueue.h"
|
||||
|
||||
int width, height;
|
||||
IVideoOutput *videoOutput=0;
|
||||
static HANDLE videoThread=0;
|
||||
static volatile LONG video_flush=0;
|
||||
static ifc_flvvideodecoder *videoDecoder=0;
|
||||
bool video_opened=false;
|
||||
static HANDLE coded_frames_event=0;
|
||||
static HANDLE video_flush_event=0;
|
||||
static Nullsoft::Utility::LockGuard coded_frames_guard;
|
||||
extern bool video_only;
|
||||
|
||||
void Video_Init()
|
||||
{
|
||||
video_opened=false;
|
||||
videoDecoder=0;
|
||||
videoThread=0;
|
||||
width=0;
|
||||
height=0;
|
||||
|
||||
if (coded_frames_event == 0)
|
||||
coded_frames_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (video_flush_event == 0)
|
||||
video_flush_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
video_flush=0;
|
||||
}
|
||||
|
||||
struct FRAMEDATA
|
||||
{
|
||||
FRAMEDATA()
|
||||
{
|
||||
data=0;
|
||||
length=0;
|
||||
timestamp=0;
|
||||
}
|
||||
|
||||
~FRAMEDATA()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
void Reset()
|
||||
{
|
||||
free(data);
|
||||
data=0;
|
||||
length=0;
|
||||
timestamp=0;
|
||||
}
|
||||
void Set(void *_data, size_t _length, uint32_t ts)
|
||||
{
|
||||
data = _data;
|
||||
length = _length;
|
||||
timestamp = ts;
|
||||
}
|
||||
void *data;
|
||||
size_t length;
|
||||
uint32_t timestamp;
|
||||
};
|
||||
|
||||
static SampleQueue<FRAMEDATA> coded_frames;
|
||||
|
||||
extern int GetOutputTime();
|
||||
static void DecodeVideo(FRAMEDATA *framedata)
|
||||
{
|
||||
if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0)
|
||||
{
|
||||
int decodeResult = videoDecoder->DecodeSample(framedata->data, framedata->length, framedata->timestamp);
|
||||
|
||||
if (decodeResult == FLV_VIDEO_SUCCESS)
|
||||
{
|
||||
void *data, *decoder_data;
|
||||
uint64_t timestamp=framedata->timestamp;
|
||||
while (videoDecoder->GetPicture(&data, &decoder_data, ×tamp) == FLV_VIDEO_SUCCESS)
|
||||
{
|
||||
if (!video_opened)
|
||||
{
|
||||
int color_format;
|
||||
if (videoDecoder->GetOutputFormat(&width, &height, &color_format) == FLV_VIDEO_SUCCESS)
|
||||
{
|
||||
videoOutput->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
|
||||
videoOutput->open(width, height, 0, 1.0, color_format);
|
||||
video_opened=true;
|
||||
}
|
||||
}
|
||||
if (video_opened)
|
||||
{
|
||||
again:
|
||||
int realTime =(int)GetOutputTime();
|
||||
if (timestamp > (realTime+5))
|
||||
{
|
||||
HANDLE handles[] = {killswitch, video_flush_event};
|
||||
int ret=WaitForMultipleObjects(2, handles, FALSE, (DWORD)(timestamp-realTime));
|
||||
if (ret != WAIT_TIMEOUT)
|
||||
{
|
||||
videoDecoder->FreePicture(data, decoder_data);
|
||||
framedata->Reset();
|
||||
return ;
|
||||
}
|
||||
goto again; // TODO: handle paused state a little better than this
|
||||
}
|
||||
videoOutput->draw(data);
|
||||
}
|
||||
videoDecoder->FreePicture(data, decoder_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
framedata->Reset();
|
||||
}
|
||||
|
||||
DWORD CALLBACK VideoProcedure(LPVOID param)
|
||||
{
|
||||
SetThreadName(-1,"FLV_VideoProcedure");
|
||||
HANDLE wait_handles[] = { killswitch, video_flush_event, coded_frames_event};
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = WaitForMultipleObjects(3, wait_handles, FALSE, INFINITE);
|
||||
if (ret == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
if (video_flush)
|
||||
{
|
||||
InterlockedDecrement(&video_flush);
|
||||
if (videoDecoder)
|
||||
videoDecoder->Flush();
|
||||
}
|
||||
ResetEvent(video_flush_event);
|
||||
}
|
||||
else if (ret == WAIT_OBJECT_0 + 2)
|
||||
{
|
||||
FRAMEDATA *frame_data = 0;
|
||||
while (frame_data = coded_frames.PopProcessed())
|
||||
{
|
||||
DecodeVideo(frame_data);
|
||||
frame_data->Reset();
|
||||
coded_frames.PushFree(frame_data);
|
||||
}
|
||||
}
|
||||
} while (ret != WAIT_OBJECT_0);
|
||||
|
||||
if (video_opened && videoOutput)
|
||||
videoOutput->close();
|
||||
video_opened=false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Video_IsSupported(int type)
|
||||
{
|
||||
size_t n = 0;
|
||||
waServiceFactory *factory = NULL;
|
||||
while (factory = plugin.service->service_enumService(WaSvc::FLVDECODER, n++))
|
||||
{
|
||||
svc_flvdecoder *creator = (svc_flvdecoder *)factory->getInterface();
|
||||
if (creator)
|
||||
{
|
||||
int supported = creator->HandlesVideo(type);
|
||||
factory->releaseInterface(creator);
|
||||
if (supported == svc_flvdecoder::CREATEDECODER_SUCCESS)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static ifc_flvvideodecoder *CreateVideoDecoder(int type)
|
||||
{
|
||||
ifc_flvvideodecoder *video_decoder = 0;
|
||||
size_t n = 0;
|
||||
waServiceFactory *factory = NULL;
|
||||
while (factory = plugin.service->service_enumService(WaSvc::FLVDECODER, n++))
|
||||
{
|
||||
svc_flvdecoder *creator = (svc_flvdecoder *)factory->getInterface();
|
||||
if (creator)
|
||||
{
|
||||
if (creator->CreateVideoDecoder(type, width, height, &video_decoder) == FLV_VIDEO_SUCCESS)
|
||||
return video_decoder;
|
||||
|
||||
factory->releaseInterface(creator);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
|
||||
static const GUID playbackConfigGroupGUID =
|
||||
{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
|
||||
bool OnVideo(void *data, size_t length, int type, unsigned __int32 timestamp)
|
||||
{
|
||||
if (!videoDecoder)
|
||||
{
|
||||
videoDecoder = CreateVideoDecoder(type);
|
||||
}
|
||||
|
||||
if (videoDecoder)
|
||||
{
|
||||
if (!video_only && !videoThread)
|
||||
{
|
||||
DWORD threadId;
|
||||
videoThread = CreateThread(0, 0, VideoProcedure, 0, 0, &threadId);
|
||||
SetThreadPriority(videoThread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
|
||||
}
|
||||
|
||||
FRAMEDATA *new_frame = coded_frames.PopFree();
|
||||
if (new_frame)
|
||||
{
|
||||
new_frame->Set(data, length, timestamp);
|
||||
if (video_only)
|
||||
{
|
||||
DecodeVideo(new_frame);
|
||||
new_frame->Reset();
|
||||
coded_frames.PushFree(new_frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
coded_frames.PushProcessed(new_frame);
|
||||
SetEvent(coded_frames_event);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Video_Stop()
|
||||
{
|
||||
if (video_only)
|
||||
{
|
||||
ResetEvent(coded_frames_event);
|
||||
Nullsoft::Utility::AutoLock l(coded_frames_guard);
|
||||
coded_frames.Trim();
|
||||
if (video_opened && videoOutput)
|
||||
videoOutput->close();
|
||||
video_opened=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (videoThread)
|
||||
WaitForSingleObject(videoThread, INFINITE);
|
||||
videoThread=0;
|
||||
|
||||
InterlockedIncrement(&video_flush);
|
||||
ResetEvent(coded_frames_event);
|
||||
Nullsoft::Utility::AutoLock l(coded_frames_guard);
|
||||
coded_frames.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
void Video_Close()
|
||||
{
|
||||
video_opened=false;
|
||||
|
||||
if (videoDecoder)
|
||||
{
|
||||
videoDecoder->Close();
|
||||
videoDecoder=0;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoFlush()
|
||||
{
|
||||
if (video_only)
|
||||
{
|
||||
if (videoDecoder)
|
||||
videoDecoder->Flush();
|
||||
}
|
||||
else if (videoThread)
|
||||
{
|
||||
InterlockedIncrement(&video_flush);
|
||||
ResetEvent(coded_frames_event);
|
||||
coded_frames.Trim();
|
||||
SetEvent(video_flush_event);
|
||||
}
|
||||
}
|
||||
|
||||
bool Video_DecoderReady()
|
||||
{
|
||||
if (!videoDecoder)
|
||||
return true;
|
||||
|
||||
return !!videoDecoder->Ready();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue