Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
300
Src/Plugins/Input/in_wmvdrm/VideoLayer.cpp
Normal file
300
Src/Plugins/Input/in_wmvdrm/VideoLayer.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "Main.h"
|
||||
#include "VideoLayer.h"
|
||||
#include <initguid.h>
|
||||
#include <wmsdkidl.h>
|
||||
#include <cassert>
|
||||
#include "util.h"
|
||||
#include "resource.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "config.h"
|
||||
#define VIDEO_ACCEPTABLE_DROP (config_video_drop_threshold*10000)
|
||||
|
||||
VideoLayer::VideoLayer(IWMReader *_reader)
|
||||
: reader(_reader), videoOutputNum(-1),
|
||||
reader2(0), offset(0), nextRest(0),
|
||||
converter(NULL), videoOpened(false),
|
||||
video_output_opened(false),
|
||||
killSwitch(0), aspect(0),
|
||||
earlyDelivery(0), fourcc(0),
|
||||
drmProtected(false),
|
||||
videoStream(0), flip(false),
|
||||
videoWidth(0), videoHeight(0)
|
||||
{
|
||||
reader->AddRef();
|
||||
if (FAILED(reader->QueryInterface(&reader2)))
|
||||
reader2 = 0;
|
||||
|
||||
if (FAILED(reader->QueryInterface(&header)))
|
||||
header = 0;
|
||||
|
||||
killSwitch = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
}
|
||||
|
||||
VideoLayer::~VideoLayer()
|
||||
{
|
||||
videoThread.Kill();
|
||||
if (reader2)
|
||||
reader2->Release();
|
||||
if (header)
|
||||
header->Release();
|
||||
reader->Release();
|
||||
CloseHandle(killSwitch);
|
||||
}
|
||||
|
||||
bool AcceptableFormat(GUID &subtype)
|
||||
{
|
||||
if (subtype == WMMEDIASUBTYPE_YV12
|
||||
|| subtype == WMMEDIASUBTYPE_YUY2
|
||||
|| subtype == WMMEDIASUBTYPE_UYVY
|
||||
//|| subtype == WMMEDIASUBTYPE_YVYU
|
||||
|| subtype == WMMEDIASUBTYPE_RGB24
|
||||
|| subtype == WMMEDIASUBTYPE_RGB32
|
||||
|| subtype == WMMEDIASUBTYPE_I420
|
||||
|| subtype == WMMEDIASUBTYPE_IYUV
|
||||
|| subtype == WMMEDIASUBTYPE_RGB1
|
||||
|| subtype == WMMEDIASUBTYPE_RGB4
|
||||
|| subtype == WMMEDIASUBTYPE_RGB8
|
||||
|| subtype == WMMEDIASUBTYPE_RGB565
|
||||
|| subtype == WMMEDIASUBTYPE_RGB555
|
||||
)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoLayer::AttemptOpenVideo(VideoOutputStream *attempt)
|
||||
{
|
||||
videoWidth = attempt->DestinationWidth();
|
||||
videoHeight = attempt->DestinationHeight();
|
||||
flip = attempt->Flipped();
|
||||
fourcc = attempt->FourCC();
|
||||
if (!fourcc)
|
||||
return false;
|
||||
|
||||
aspect = 1.0;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool VideoLayer::OpenVideo()
|
||||
{
|
||||
videoOutputNum = -1;
|
||||
DWORD numOutputs, numFormats;
|
||||
IWMOutputMediaProps *formatProperties;
|
||||
VideoOutputStream *stream;
|
||||
GUID mediaType;
|
||||
|
||||
reader->GetOutputCount(&numOutputs);
|
||||
|
||||
for (DWORD output = 0;output < numOutputs;output++)
|
||||
{
|
||||
// test the default format first, and if that fails, iterate through the rest
|
||||
const int defaultFormat = -1;
|
||||
HRESULT hr;
|
||||
if (FAILED(hr = reader->GetOutputFormatCount(output, &numFormats)))
|
||||
continue;
|
||||
|
||||
for (int format = 0/*defaultFormat*/;format != numFormats;format++)
|
||||
{
|
||||
if (format == defaultFormat)
|
||||
reader->GetOutputProps(output, &formatProperties);
|
||||
else
|
||||
reader->GetOutputFormat(output, format, &formatProperties);
|
||||
|
||||
formatProperties->GetType(&mediaType);
|
||||
|
||||
if (mediaType == WMMEDIATYPE_Video)
|
||||
{
|
||||
stream = new VideoOutputStream(formatProperties);
|
||||
|
||||
if (stream->IsVideo() // if it's video
|
||||
&& AcceptableFormat(stream->GetSubType()) // and a video format we like
|
||||
&& AttemptOpenVideo(stream)) // and winamp was able to open it
|
||||
{
|
||||
videoOpened = true;
|
||||
int fourcc = stream->FourCC();
|
||||
if (fourcc == '8BGR')
|
||||
{
|
||||
RGBQUAD *palette = stream->CreatePalette();
|
||||
winamp.SetVideoPalette(palette);
|
||||
|
||||
// TODO: don't leak the palette
|
||||
}
|
||||
char *cc = (char *) & fourcc;
|
||||
char status[512] = {0};
|
||||
StringCchPrintfA(status, 512, WASABI_API_LNGSTRING(IDS_WINDOWS_MEDIA_XXX),
|
||||
stream->DestinationWidth(), stream->DestinationHeight(), cc[0], cc[1], cc[2], cc[3]);
|
||||
winamp.SetVideoStatusText(status);
|
||||
converter = MakeConverter(stream);
|
||||
videoOutputNum = output;
|
||||
videoStream = stream;
|
||||
reader->SetOutputProps(output, formatProperties);
|
||||
formatProperties->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
stream = 0;
|
||||
|
||||
}
|
||||
formatProperties->Release();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VideoLayer::SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample)
|
||||
{
|
||||
if (outputNum == videoOutputNum)
|
||||
{
|
||||
if (WaitForSingleObject(killSwitch, 0) == WAIT_OBJECT_0)
|
||||
return ;
|
||||
|
||||
INSSBuffer3 *buff3;
|
||||
if (SUCCEEDED(sample->QueryInterface(&buff3)))
|
||||
{
|
||||
short aspectHex = 0;
|
||||
DWORD size = 2;
|
||||
buff3->GetProperty(WM_SampleExtensionGUID_PixelAspectRatio, &aspectHex, &size);
|
||||
if (aspectHex)
|
||||
{
|
||||
double newAspect = (double)((aspectHex & 0xFF00) >> 8) / (double)(aspectHex & 0xFF) ;
|
||||
|
||||
if (newAspect != aspect)
|
||||
{
|
||||
aspect = newAspect;
|
||||
videoThread.OpenVideo(drmProtected, videoWidth, videoHeight, flip, aspect, fourcc);
|
||||
video_output_opened=true;
|
||||
}
|
||||
}
|
||||
buff3->Release();
|
||||
}
|
||||
|
||||
if (!video_output_opened)
|
||||
{
|
||||
videoThread.OpenVideo(drmProtected, videoWidth, videoHeight, flip, aspect, fourcc);
|
||||
video_output_opened=true;
|
||||
}
|
||||
|
||||
__int64 timeDiff;
|
||||
First().TimeToSync(timeStamp, timeDiff);
|
||||
|
||||
if (timeDiff < -VIDEO_ACCEPTABLE_DROP) // late
|
||||
{
|
||||
timeDiff = -timeDiff;
|
||||
if (config_video_catchup) First().VideoCatchup(timeDiff);
|
||||
if (config_video_framedropoffset) this->VideoFrameDrop((DWORD)(timeDiff / 10000));
|
||||
if (config_video_notifylate) reader2->NotifyLateDelivery(timeDiff);
|
||||
|
||||
// drop the frame
|
||||
}
|
||||
else // early
|
||||
{
|
||||
while (!videoThread.AddBuffer(sample, timeStamp, flags, drmProtected))
|
||||
{
|
||||
if (WaitForSingleObject(killSwitch, VIDEO_ACCEPTABLE_JITTER_MS) == WAIT_OBJECT_0)
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
WMHandler::SampleReceived(timeStamp, duration, outputNum, flags, sample);
|
||||
}
|
||||
|
||||
void VideoLayer::Opened()
|
||||
{
|
||||
WORD stream = 0;
|
||||
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
|
||||
BOOL value;
|
||||
WORD valueLen = sizeof(value);
|
||||
header->GetAttributeByName(&stream, g_wszWMProtected, &type, (BYTE *)&value, &valueLen);
|
||||
drmProtected = !!value;
|
||||
|
||||
ResetEvent(killSwitch);
|
||||
if (OpenVideo())
|
||||
{
|
||||
ResetEvent(killSwitch);
|
||||
HRESULT hr;
|
||||
|
||||
BOOL dedicatedThread = config_video_dedicated_thread ? TRUE : FALSE;
|
||||
hr = reader2->SetOutputSetting(videoOutputNum, g_wszDedicatedDeliveryThread, WMT_TYPE_BOOL, (BYTE *) & dedicatedThread, sizeof(dedicatedThread));
|
||||
assert(hr == S_OK);
|
||||
|
||||
earlyDelivery = config_video_early ? config_video_early_pad : 0;
|
||||
hr = reader2->SetOutputSetting(videoOutputNum, g_wszEarlyDataDelivery, WMT_TYPE_DWORD, (BYTE *) & earlyDelivery , sizeof(earlyDelivery));
|
||||
assert(hr == S_OK);
|
||||
|
||||
BOOL outOfOrder = config_video_outoforder ? TRUE : FALSE;
|
||||
hr = reader2->SetOutputSetting(videoOutputNum, g_wszDeliverOnReceive, WMT_TYPE_BOOL, (BYTE *) & outOfOrder, sizeof(outOfOrder));
|
||||
assert(hr == S_OK);
|
||||
|
||||
BOOL justInTime = config_lowmemory ? TRUE : FALSE;
|
||||
hr = reader2->SetOutputSetting(videoOutputNum, g_wszJustInTimeDecode, WMT_TYPE_BOOL, (BYTE *) & justInTime, sizeof(justInTime));
|
||||
assert(hr == S_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
videoOpened = false;
|
||||
}
|
||||
|
||||
WMHandler::Opened();
|
||||
}
|
||||
|
||||
void VideoLayer::VideoFrameDrop(DWORD lateness)
|
||||
{
|
||||
//earlyDelivery+=lateness;
|
||||
lateness += earlyDelivery;
|
||||
HRESULT hr = reader2->SetOutputSetting(videoOutputNum, g_wszEarlyDataDelivery, WMT_TYPE_DWORD, (BYTE *) & lateness, sizeof(lateness));
|
||||
assert(hr == S_OK);
|
||||
}
|
||||
|
||||
void VideoLayer::Closed()
|
||||
{
|
||||
if (video_output_opened)
|
||||
{
|
||||
videoThread.CloseVideo(drmProtected);
|
||||
video_output_opened = false;
|
||||
}
|
||||
videoOpened = false;
|
||||
delete videoStream;
|
||||
videoStream=0;
|
||||
WMHandler::Closed();
|
||||
}
|
||||
|
||||
|
||||
bool VideoLayer::IsOpen()
|
||||
{
|
||||
return videoOpened;
|
||||
}
|
||||
|
||||
void VideoLayer::HasVideo(bool &video)
|
||||
{
|
||||
video=videoOpened;
|
||||
}
|
||||
|
||||
void VideoLayer::Kill()
|
||||
{
|
||||
SetEvent(killSwitch);
|
||||
if (videoOpened)
|
||||
videoThread.SignalStop();//SignalStop();
|
||||
|
||||
WMHandler::Kill();
|
||||
if (videoOpened)
|
||||
videoThread.WaitForStop();
|
||||
}
|
||||
|
||||
void VideoLayer::Started()
|
||||
{
|
||||
ResetEvent(killSwitch);
|
||||
if (videoOpened)
|
||||
videoThread.Start(converter, &First());
|
||||
WMHandler::Started();
|
||||
}
|
||||
|
||||
void VideoLayer::Stopped()
|
||||
{
|
||||
if (videoOpened)
|
||||
videoThread.Stop();
|
||||
WMHandler::Stopped();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue