123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #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();
- }
|