Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions
+490
View File
@@ -0,0 +1,490 @@
#include "main.h"
#include "api.h"
#include "ASXLoader.h"
#include <stdio.h>
#include "../nu/AutoWide.h"
#include "../xml/ifc_xmlreadercallback.h"
#include "../xml/obj_xml.h"
#include "api.h"
#include <api/service/waservicefactory.h>
#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
#include "../nu/AutoChar.h"
#include "../Winamp/strutil.h"
#include <strsafe.h>
#include "XMLString.h"
void SetUserAgent(api_httpreceiver *http)
{
char agent[256] = {0};
StringCchPrintfA(agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString());
http->addheader(agent);
}
class ASXInfo : public ifc_plentryinfo
{
public:
ASXInfo()
{
memset( returnTemp, 0, sizeof( returnTemp ) );
}
const wchar_t *GetExtendedInfo( const wchar_t *parameter )
{
if ( !_wcsicmp( parameter, L"context" ) )
{
if ( isRadio )
return L"radio";
}
else if ( !_wcsicmp( parameter, L"repeat" ) )
{
if ( repeat )
{
StringCchPrintfW( returnTemp, 20, L"%d", repeat );
return returnTemp;
}
}
return 0;
}
bool isRadio = false;
int repeat = 0;
protected:
RECVS_DISPATCH;
wchar_t returnTemp[ 20 ];
};
#define CBCLASS ASXInfo
START_DISPATCH;
CB( IFC_PLENTRYINFO_GETEXTENDEDINFO, GetExtendedInfo )
END_DISPATCH;
#undef CBCLASS
class ASXXML : public ifc_xmlreadercallback
{
public:
ASXXML(ifc_playlistloadercallback *_playlist, const wchar_t *_root, obj_xml *_parser) : playlist(_playlist), rootPath(_root), parser(_parser)
{
}
void OnFileHelper(ifc_playlistloadercallback *playlist, const wchar_t *filename, const wchar_t *title, int length, ifc_plentryinfo *extraInfo)
{
if (wcsstr(filename, L"://") || PathIsRootW(filename))
{
playlist->OnFile(filename, title, length, extraInfo);
}
else
{
wchar_t fullPath[MAX_PATH] = {0}, canonicalizedPath[MAX_PATH] = {0};
PathCombineW(fullPath, rootPath, filename);
PathCanonicalizeW(canonicalizedPath, fullPath);
playlist->OnFile(canonicalizedPath, title, length, extraInfo);
}
}
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
{
if (!_wcsicmp(xmltag, L"ENTRYREF"))
{
const wchar_t *url = params->getItemValue(L"HREF");
const wchar_t *titleHack = params->getItemValue(L"CLIENTBIND");
int lengthHack = -1;
wchar_t titleBuf[256] = L"";
if (titleHack)
{
// get the length out of the parantheses
StringCchCopyW(titleBuf, 256, titleHack);
wchar_t *end = titleBuf + lstrlenW(titleBuf);
while (end && *end && *end != '(' && end != titleBuf)
end = CharPrevW(titleBuf, end);
*end = 0;
end++;
lengthHack = _wtoi(end);
}
wchar_t filename[FILENAME_SIZE] = {0};
if (wcschr(url, L'?'))
StringCchPrintfW(filename, FILENAME_SIZE, L"%s&=.asx", url);
else
StringCchPrintfW(filename, FILENAME_SIZE, L"%s?.asx", url);
OnFileHelper(playlist, filename, titleBuf, lengthHack*1000, &info);
}
else if (!_wcsicmp(xmlpath, L"ASX\fENTRY\fREF") || !_wcsicmp(xmlpath, L"ASX\fREPEAT\fENTRY\fREF"))
{
const wchar_t *track = params->getItemValue(L"HREF");
wchar_t fullTitle[128] = {0}, fullFilename[FILENAME_SIZE] = {0};
// if there is no extension given, we need to add ?.wma or &=.wma to the end of the URL
// this could be 2 lines of code if that wasn't the case :(
if (track)
{
const wchar_t *trackTitle = 0;
if (title.GetString()[0] && artist.GetString()[0])
{
StringCchPrintfW(fullTitle, 128, L"%s - %s", artist.GetString(), title.GetString());
trackTitle = fullTitle;
}
if (!_wcsnicmp(track, L"http://", 7))
{
const wchar_t *end = scanstr_backcW(track, L"/.", 0);
if (!end || *end == L'/')
{
if (wcschr(track, L'?'))
StringCchPrintfW(fullFilename, FILENAME_SIZE, L"%s&=.wma", track);
else
StringCchPrintfW(fullFilename, FILENAME_SIZE, L"%s?.wma", track);
track = fullFilename;
}
}
OnFileHelper(playlist, track, trackTitle, -1, &info);
}
}
else if (!_wcsicmp(xmltag, L"REPEAT"))
{
const wchar_t *param;
if (param = params->getItemValue(L"count"))
{
info.repeat = _wtoi(param);
}
else
info.repeat = -1;
}
else if (!_wcsicmp(xmltag, L"PARAM"))
{
const wchar_t *param;
if (param = params->getItemValue(L"name"))
{
if (!_wcsicmp(param, L"context"))
{
const wchar_t * value = params->getItemValue(L"value");
if (!_wcsicmp(value, L"station"))
info.isRadio = true;
}
else if (!_wcsicmp(param, L"encoding"))
{
const wchar_t *value=params->getItemValue(L"value");
if (value)
parser->xmlreader_setEncoding(value); // I hope we can set it on the fly like this!
}
}
}
}
void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag)
{
if (!_wcsicmp(xmltag, L"REPEAT"))
{
info.repeat = 0;
}
}
ifc_playlistloadercallback *playlist;
XMLString title, artist;
ASXInfo info;
const wchar_t *rootPath;
obj_xml *parser;
protected:
RECVS_DISPATCH;
};
#define CBCLASS ASXXML
START_DISPATCH;
VCB(ONSTARTELEMENT, StartTag)
VCB(ONENDELEMENT, EndTag)
END_DISPATCH;
#undef CBCLASS
/*
TODO:
don't add tracks until all parts of the "ENTRY" tag are processed. There are some ASX playlists where the title comes AFTER the ref's
maybe have separate XML callbacks for metadata (title, author, shit like that) so that logic can be separated from the main ASX logic
*/
// ASX isn't really XML. That means we need to URL-encode the text so our XML parser doesn't choke
// if microsoft followed standards, the world would be a better place.
int ASXLoader::GayASX_to_XML_converter(obj_xml *parser, char *buffer, int len)
{
// benski> I have no idea if ASX is always ASCII, or if it's UTF-8 or what.
// but really I can't be bothered with Microsoft's lameness right now, so we'll assume it's local code page for the time being
char *start = buffer;
int sofar = 0;
for (int i = 0;i < len;i++)
{
if (buffer[i] == '&')
{
if (sofar)
{
if (parser->xmlreader_feed(start, sofar) != API_XML_SUCCESS)
return API_XML_FAILURE;
}
if (parser->xmlreader_feed("&amp;", 5) != API_XML_SUCCESS) // no null terminator
return API_XML_FAILURE;
start = &buffer[i + 1];
sofar = 0;
}
else
{
/**
* ok, this might look really weird
* but ASX doesn't have case sensitivity
* so lots of playlists have things like
* <title>This is the title</Title>
* and so we have to accomodate
* for this nonsense
*/
if (inTag && !inQuotes)
buffer[i] = toupper(buffer[i]);
if (buffer[i] == '>')
{
inTag=false;
}
else if (buffer[i] == '<')
{
inTag=true;
}
// dro> only do uppercase handling on parts of the tag not inbetween quotes
// (some servers just don't like having the urls case messed with, the swines)
if (buffer[i] == '"')
{
if(!inQuotes)
inQuotes=true;
else
inQuotes=false;
}
sofar++;
}
}
if (sofar && parser->xmlreader_feed(start, sofar) != API_XML_SUCCESS)
return API_XML_FAILURE;
OutputDebugStringA(buffer);
return API_XML_SUCCESS;
}
#define HTTP_BUFFER_SIZE 16384
int ASXLoader::FeedXMLHTTP(api_httpreceiver *http, obj_xml *parser, bool *noData)
{
char downloadedData[HTTP_BUFFER_SIZE] = {0};
int xmlResult = API_XML_SUCCESS;
int downloadSize = http->get_bytes(downloadedData, HTTP_BUFFER_SIZE);
if (downloadSize)
{
xmlResult = GayASX_to_XML_converter(parser, downloadedData, downloadSize);
*noData=false;
}
else
*noData = true;
return xmlResult;
}
void ASXLoader::RunXMLDownload(api_httpreceiver *http, obj_xml *parser)
{
int ret;
bool noData;
do
{
Sleep(50);
ret = http->run();
if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
return ;
}
while (ret == HTTPRECEIVER_RUN_OK);
// finish off the data
do
{
if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
return ;
} while (!noData);
parser->xmlreader_feed(0, 0);
}
int ASXLoader::LoadFile(obj_xml *parser, const wchar_t *filename)
{
HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (file == INVALID_HANDLE_VALUE)
return IFC_PLAYLISTLOADER_FAILED;
while (true)
{
char data[1024] = {0};
DWORD bytesRead = 0;
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
{
if (GayASX_to_XML_converter(parser, data, bytesRead) != API_XML_SUCCESS)
{
CloseHandle(file);
return IFC_PLAYLISTLOADER_FAILED;
}
}
else
break;
}
CloseHandle(file);
if (parser->xmlreader_feed(0, 0) != API_XML_SUCCESS)
return IFC_PLAYLISTLOADER_FAILED;
return IFC_PLAYLISTLOADER_SUCCESS;
}
int ASXLoader::LoadURL(obj_xml *parser, const wchar_t *url)
{
api_httpreceiver *http = 0;
waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
if (sf) http = (api_httpreceiver *)sf->getInterface();
if (!http)
return IFC_PLAYLISTLOADER_FAILED;
http->AllowCompression();
http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, winamp.GetProxy());
SetUserAgent(http);
http->connect(AutoChar(url));
int ret;
do
{
Sleep(10);
ret = http->run();
if (ret == -1) // connection failed
break;
// ---- check our reply code ----
int replycode = http->getreplycode();
switch (replycode)
{
case 0:
case 100:
break;
case 200:
{
RunXMLDownload(http, parser);
sf->releaseInterface(http);
return IFC_PLAYLISTLOADER_SUCCESS;
}
break;
default:
sf->releaseInterface(http);
return IFC_PLAYLISTLOADER_FAILED;
}
}
while (ret == HTTPRECEIVER_RUN_OK);
//const char *er = http->geterrorstr();
sf->releaseInterface(http);
return IFC_PLAYLISTLOADER_FAILED;
}
static int loadasxv2fn(const wchar_t *filename, ifc_playlistloadercallback *playlist)
{
int i=1;
wchar_t ref[FILENAME_SIZE] = {0};
wchar_t key[100] = {0};
while (1)
{
StringCchPrintfW(key, 100, L"Ref%d", i++);
GetPrivateProfileStringW(L"Reference", key, L"?", ref, FILENAME_SIZE, filename);
if (!lstrcmpiW(ref, L"?"))
break;
else
{
if (!_wcsnicmp(ref, L"http://", 7))
{
const wchar_t *end = scanstr_backcW(ref, L"/.", 0);
if (!end || *end == L'/')
{
if (wcschr(ref, L'?'))
StringCchCatW(ref, FILENAME_SIZE, L"&=.wma");
else
StringCchCatW(ref, FILENAME_SIZE, L"?.wma");
}
}
playlist->OnFile(ref, 0, 0, 0);
}
}
return IFC_PLAYLISTLOADER_SUCCESS;
}
int ASXLoader::Load(const wchar_t *filename, ifc_playlistloadercallback *playlist)
{
obj_xml *parser = 0;
waServiceFactory *parserFactory = 0;
HANDLE quickTest = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (quickTest != INVALID_HANDLE_VALUE)
{
char reference[11] = {0};
DWORD bytesRead=0;
ReadFile(quickTest, reference, 11, &bytesRead, 0);
CloseHandle(quickTest);
if (bytesRead == 11 && !_strnicmp(reference, "[Reference]", 11))
return loadasxv2fn(filename, playlist);
}
parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
if (parserFactory)
parser = (obj_xml *)parserFactory->getInterface();
if (parser)
{
wchar_t rootPath[MAX_PATH] = {0};
const wchar_t *callbackPath = playlist->GetBasePath();
if (callbackPath)
lstrcpynW(rootPath, callbackPath, MAX_PATH);
else
{
lstrcpynW(rootPath, filename, MAX_PATH);
PathRemoveFileSpecW(rootPath);
}
ASXXML asxXml(playlist, rootPath, parser);
parser->xmlreader_registerCallback(L"ASX\f*", &asxXml);
parser->xmlreader_registerCallback(L"ASX\fENTRY\fTITLE", &asxXml.title);
parser->xmlreader_registerCallback(L"ASX\fENTRY\fAUTHOR", &asxXml.artist);
parser->xmlreader_open();
parser->xmlreader_setEncoding(L"windows-1252");
int ret;
if (wcsstr(filename, L"://"))
ret = LoadURL(parser, filename);
else
ret = LoadFile(parser, filename);
parser->xmlreader_unregisterCallback(&asxXml);
parser->xmlreader_unregisterCallback(&asxXml.title);
parser->xmlreader_unregisterCallback(&asxXml.artist);
parser->xmlreader_close();
parserFactory->releaseInterface(parser);
return ret;
}
return IFC_PLAYLISTLOADER_FAILED;
}
#define CBCLASS ASXLoader
START_DISPATCH;
CB(IFC_PLAYLISTLOADER_LOAD, Load)
END_DISPATCH;
#undef CBCLASS
+29
View File
@@ -0,0 +1,29 @@
#ifndef NULLSOFT_PLAYLIST_ASX_LOADER_H
#define NULLSOFT_PLAYLIST_ASX_LOADER_H
#include "../playlist/ifc_playlistloader.h"
#include "../playlist/ifc_playlistloadercallback.h"
#include <stdio.h>
class obj_xml;
class api_httpreceiver;
class ASXLoader : public ifc_playlistloader
{
public:
ASXLoader() : inTag(false), inQuotes(false) {}
int Load(const wchar_t *filename, ifc_playlistloadercallback *playlist);
private:
int LoadURL(obj_xml *parser, const wchar_t *url);
int LoadFile(obj_xml *parser, const wchar_t *filename);
void RunXMLDownload(api_httpreceiver *http, obj_xml *parser);
int FeedXMLHTTP(api_httpreceiver *http, obj_xml *parser, bool *noData);
int GayASX_to_XML_converter(obj_xml *parser, char *buffer, int len);
protected:
bool inTag;
bool inQuotes;
RECVS_DISPATCH;
};
#endif
+202
View File
@@ -0,0 +1,202 @@
#include "main.h"
#include "../nu/AutoWide.h"
#include "AlbumArt.h"
#include "util.h"
#include <shlwapi.h>
#include <strsafe.h>
bool ASF_AlbumArtProvider::IsMine(const wchar_t *filename)
{
const wchar_t *ext = PathFindExtension(filename);
if (ext && *ext)
{
ext++;
return fileTypes.GetAVType(ext) != -1;
}
return false;
}
int ASF_AlbumArtProvider::ProviderType()
{
return ALBUMARTPROVIDER_TYPE_EMBEDDED;
}
bool NameToAPICType(const wchar_t *name, int &num)
{
if (!name || !*name) // default to cover
num=0x3;
else if (!_wcsicmp(name, L"fileicon")) // 32x32 pixels 'file icon' (PNG only)
num=0x1;
else if (!_wcsicmp(name, L"icon")) // Other file icon
num=0x2;
else if (!_wcsicmp(name, L"cover")) // Cover (front)
num=0x3;
else if (!_wcsicmp(name, L"back")) // Cover (back)
num=0x4;
else if (!_wcsicmp(name, L"leaflet")) // Leaflet page
num=0x5;
else if (!_wcsicmp(name, L"media")) // Media (e.g. lable side of CD)
num=0x6;
else if (!_wcsicmp(name, L"leadartist")) //Lead artist/lead performer/soloist
num=0x7;
else if (!_wcsicmp(name, L"artist")) // Artist/performer
num=0x8;
else if (!_wcsicmp(name, L"conductor")) // Conductor
num=0x9;
else if (!_wcsicmp(name, L"band")) // Band/Orchestra
num=0xA;
else if (!_wcsicmp(name, L"composer")) // Composer
num=0xB;
else if (!_wcsicmp(name, L"lyricist")) // Lyricist/text writer
num=0xC;
else if (!_wcsicmp(name, L"location")) // Recording Location
num=0xD;
else if (!_wcsicmp(name, L"recording")) // During recording
num=0xE;
else if (!_wcsicmp(name, L"performance")) // During performance
num=0xF;
else if (!_wcsicmp(name, L"preview")) // Movie/video screen capture
num=0x10;
else if (!_wcsicmp(name, L"fish")) // A bright coloured fish
num=0x11;
else if (!_wcsicmp(name, L"illustration")) // Illustration
num=0x12;
else if (!_wcsicmp(name, L"artistlogo")) // Band/artist logotype
num=0x13;
else if (!_wcsicmp(name, L"publisherlogo")) // Publisher/Studio logotype
num=0x14;
else
return false;
return true;
}
int ASF_AlbumArtProvider::GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
{
int pictype;
if (NameToAPICType(type, pictype))
{
WMInformation wm(filename);
if (wm.GetPicture(bits, len, mimeType, pictype))
return ALBUMARTPROVIDER_SUCCESS;
}
return ALBUMARTPROVIDER_FAILURE;
}
int ASF_AlbumArtProvider::SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType)
{
int pictype;
if (NameToAPICType(type, pictype))
{
WMInformation wm(filename);
if (!wm.MakeWritable(filename))
return ALBUMARTPROVIDER_READONLY; // can't write
if (wm.SetPicture(bits, len, mimeType, pictype))
{
wm.Flush();
return ALBUMARTPROVIDER_SUCCESS;
}
}
return ALBUMARTPROVIDER_FAILURE;
}
int ASF_AlbumArtProvider::DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
{
int pictype;
if (NameToAPICType(type, pictype))
{
WMInformation wm(filename);
if (!wm.MakeWritable(filename))
{
if (wm.HasPicture(pictype))
return ALBUMARTPROVIDER_READONLY; // can't write
else
return ALBUMARTPROVIDER_FAILURE;
}
if (wm.DeletePicture(pictype))
{
wm.Flush();
return ALBUMARTPROVIDER_SUCCESS;
}
}
return ALBUMARTPROVIDER_FAILURE;
}
#define CBCLASS ASF_AlbumArtProvider
START_DISPATCH;
CB(SVC_ALBUMARTPROVIDER_PROVIDERTYPE, ProviderType);
CB(SVC_ALBUMARTPROVIDER_GETALBUMARTDATA, GetAlbumArtData);
CB(SVC_ALBUMARTPROVIDER_SETALBUMARTDATA, SetAlbumArtData);
CB(SVC_ALBUMARTPROVIDER_DELETEALBUMART, DeleteAlbumArt);
CB(SVC_ALBUMARTPROVIDER_ISMINE, IsMine);
END_DISPATCH;
#undef CBCLASS
static ASF_AlbumArtProvider albumArtProvider;
// {B4184902-EE79-4015-B9A4-76209C6153FA}
static const GUID asf_albumartproviderGUID =
{ 0xb4184902, 0xee79, 0x4015, { 0xb9, 0xa4, 0x76, 0x20, 0x9c, 0x61, 0x53, 0xfa } };
FOURCC AlbumArtFactory::GetServiceType()
{
return svc_albumArtProvider::SERVICETYPE;
}
const char *AlbumArtFactory::GetServiceName()
{
return "ASF Album Art Provider";
}
GUID AlbumArtFactory::GetGUID()
{
return asf_albumartproviderGUID;
}
void *AlbumArtFactory::GetInterface(int global_lock)
{
return &albumArtProvider;
}
int AlbumArtFactory::SupportNonLockingInterface()
{
return 1;
}
int AlbumArtFactory::ReleaseInterface(void *ifc)
{
//plugin.service->service_unlock(ifc);
return 1;
}
const char *AlbumArtFactory::GetTestString()
{
return 0;
}
int AlbumArtFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS AlbumArtFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
+39
View File
@@ -0,0 +1,39 @@
#ifndef NULLSOFT_IN_MP3_ALBUMART_H
#define NULLSOFT_IN_MP3_ALBUMART_H
#include "../Agave/AlbumArt/svc_albumArtProvider.h"
class ASF_AlbumArtProvider : public svc_albumArtProvider
{
public:
bool IsMine(const wchar_t *filename);
int ProviderType();
// implementation note: use WASABI_API_MEMMGR to alloc bits and mimetype, so that the recipient can free through that
int GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType);
int SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType);
int DeleteAlbumArt(const wchar_t *filename, const wchar_t *type);
protected:
RECVS_DISPATCH;
};
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class AlbumArtFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
const char *GetServiceName();
GUID GetGUID();
void *GetInterface(int global_lock);
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
protected:
RECVS_DISPATCH;
};
#endif
@@ -0,0 +1 @@
#include "AllocLayer.h"
+80
View File
@@ -0,0 +1,80 @@
#ifndef NULLSOFT_ALLOCLAYERH
#define NULLSOFT_ALLOCLAYERH
#include "WMHandler.h"
#include "BufferPool.h"
#include <cassert>
class AllocLayer : public WMHandler
{
public:
AllocLayer(IWMReader *reader)
: readerAdvanced(0),
listenOutput( -1),
maxSize(0)
{
reader->QueryInterface(&readerAdvanced);
}
~AllocLayer()
{
if (readerAdvanced)
{
readerAdvanced->Release();
readerAdvanced = 0;
}
}
void Listen(long output)
{
listenOutput = output;
if (output != -1)
{
readerAdvanced->SetAllocateForOutput(listenOutput, TRUE);
readerAdvanced->GetMaxOutputSampleSize(listenOutput, &maxSize);
assert(maxSize>0);
pool.SetAllocSize(maxSize);
}
}
void Listen(long output, long numBuffers)
{
listenOutput = output;
if (output != -1)
{
readerAdvanced->SetAllocateForOutput(listenOutput, TRUE);
readerAdvanced->GetMaxOutputSampleSize(listenOutput, &maxSize);
assert(maxSize>0);
pool.SetAllocSize(maxSize);
pool.PreAllocate(numBuffers);
pool.limit=numBuffers;
}
}
void FreeBuffers()
{
pool.FreeBuffers();
}
BufferPool pool;
private:
void AllocateOutput(long outputNum, long bufferSize, INSSBuffer *&buffer)
{
if (outputNum == listenOutput)
{
assert(maxSize >= bufferSize);
buffer = pool.GetBuffer(bufferSize);
}
else
WMHandler::AllocateOutput(outputNum, bufferSize, buffer); // let other handlers have a shot at it first.
}
// WMHandler
long listenOutput;
DWORD maxSize;
IWMReaderAdvanced *readerAdvanced;
};
#endif
@@ -0,0 +1,61 @@
#include "main.h"
#include "AudioLayer.h"
unsigned long AudioFormat::AudioSamplesToMilliseconds(unsigned long samples)
{
return MulDiv(samples, 1000, SampleRate());
}
unsigned long AudioFormat::AudioBytesToMilliseconds(unsigned long bytes)
{
return MulDiv(AudioBytesToSamples(bytes), 1000, SampleRate());
}
unsigned long AudioFormat::AudioMillisecondsToBytes(DWORD milliseconds)
{
return AudioSamplesToBytes(MulDiv(milliseconds, SampleRate(), 1000));
}
unsigned long AudioFormat::AudioDurationToBytes(QWORD duration)
{
// TODO: potential integer overflow
return AudioSamplesToBytes(MulDiv((int)duration, SampleRate(), 1000*10000));
}
unsigned long AudioFormat::AudioBytesToSamples(unsigned long bytes)
{
return bytes / waveFormat->Format.nBlockAlign;
}
unsigned long AudioFormat::AudioSamplesToBytes(unsigned long samples)
{
return samples * waveFormat->Format.nBlockAlign;
}
long AudioFormat::Channels()
{
return waveFormat->Format.nChannels;
}
long AudioFormat::ValidBits()
{
if (waveFormat->Format.wFormatTag == WAVE_FORMAT_PCM)
{
return waveFormat->Format.wBitsPerSample;
}
if (waveFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
{
return waveFormat->Samples.wValidBitsPerSample;
}
return 0;
}
long AudioFormat::BitSize()
{
return waveFormat->Format.wBitsPerSample;
}
long AudioFormat::SampleRate()
{
return waveFormat->Format.nSamplesPerSec;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef NULLSOFT_IN_WMVDRM_AUDIOFORMAT_H
#define NULLSOFT_IN_WMVDRM_AUDIOFORMAT_H
#include <mmreg.h>
#include <wmsdk.h>
class AudioFormat
{
public:
AudioFormat() : waveFormat(0)
{
}
~AudioFormat()
{
delete [] waveFormat;
}
unsigned long AudioBytesToSamples(unsigned long bytes);
unsigned long AudioSamplesToBytes(unsigned long samples);
unsigned long AudioBytesToMilliseconds(unsigned long bytes);
unsigned long AudioMillisecondsToBytes(DWORD milliseconds);
unsigned long AudioDurationToBytes(QWORD duration);
unsigned long AudioSamplesToMilliseconds(unsigned long samples);
long Channels();
long ValidBits();
long BitSize();
long SampleRate();
//protected:
void Open(WM_MEDIA_TYPE *mediaType)
{
delete[] waveFormat;
waveFormat = (WAVEFORMATEXTENSIBLE *) new unsigned char[mediaType->cbFormat];
memcpy(waveFormat, mediaType->pbFormat, mediaType->cbFormat);
}
void Close()
{
delete [] waveFormat;
waveFormat=0;
}
private:
WAVEFORMATEXTENSIBLE *waveFormat;
};
#endif
+253
View File
@@ -0,0 +1,253 @@
#include "Main.h"
#include "AudioLayer.h"
#include "VideoLayer.h"
#include <Mmreg.h>
#include <cassert>
#include "util.h"
#include "config.h"
#include "AudioThread.h"
#include "api.h"
#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list
AudioLayer::AudioLayer(IWMReader *_reader)
: reader(_reader), audioOutputNum( -1),
reader2(0), offset(0), new_offset(0),
startPosition(0), videoCatchup(0),
opened(false), killSwitch(0),
audioThread(this), latency(0)
{
reader->AddRef();
if (FAILED(reader->QueryInterface(&reader2)))
reader2 = 0;
killSwitch = CreateEvent(NULL, TRUE, FALSE, NULL);
}
void AudioLayer::Opened()
{
ResetEvent(killSwitch);
if (AudioLayer::OpenAudio())
{
ResetEvent(killSwitch);
BOOL dedicatedThread = config_audio_dedicated_thread ? TRUE : FALSE;
reader2->SetOutputSetting(audioOutputNum, g_wszDedicatedDeliveryThread, WMT_TYPE_BOOL, (BYTE *) & dedicatedThread, sizeof(dedicatedThread));
BOOL outOfOrder = config_audio_outoforder ? TRUE : FALSE;
reader2->SetOutputSetting(audioOutputNum, g_wszDeliverOnReceive, WMT_TYPE_BOOL, (BYTE *) & outOfOrder, sizeof(outOfOrder));
BOOL justInTime = config_lowmemory ? TRUE : FALSE;
reader2->SetOutputSetting(audioOutputNum, g_wszJustInTimeDecode, WMT_TYPE_BOOL, (BYTE *) & justInTime, sizeof(justInTime));
opened = true;
offset = ((QWORD)latency) * 10000;
new_offset = config_audio_early ? (latency + config_audio_early_pad) : 0;
reader2->SetOutputSetting(audioOutputNum, g_wszEarlyDataDelivery, WMT_TYPE_DWORD, (BYTE *) & new_offset , sizeof(new_offset));
winamp.OpenViz(latency, SampleRate());
}
WMHandler::Opened();
}
void AudioLayer::Started()
{
ResetEvent(killSwitch);
if (opened)
{
audioThread.Start(&First());
}
WMHandler::Started();
}
void AudioLayer::Stopped()
{
if (opened)
audioThread.Stop();
WMHandler::Stopped();
}
WM_MEDIA_TYPE *NewMediaType(IWMOutputMediaProps *props)
{
DWORD mediaTypeSize;
props->GetMediaType(0, &mediaTypeSize);
WM_MEDIA_TYPE *mediaType = (WM_MEDIA_TYPE *)new unsigned char[mediaTypeSize];
props->GetMediaType(mediaType, &mediaTypeSize);
return mediaType;
}
bool AudioLayer::OpenAudio()
{
audioOutputNum = -1;
DWORD numOutputs, output, format, numFormats;
IWMOutputMediaProps *formatProperties;
GUID mediaType;
if (FAILED((reader->GetOutputCount(&numOutputs))))
return false;
for (output = 0;output < numOutputs;output++)
{
HRESULT hr;
DWORD speakerConfig = config_audio_num_channels;
if (AGAVE_API_CONFIG && AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false)) // force mono?
speakerConfig = DSSPEAKER_MONO;
else if (AGAVE_API_CONFIG && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true)) // is surround disallowed?
speakerConfig = DSSPEAKER_STEREO;
hr = reader2->SetOutputSetting(output, g_wszSpeakerConfig, WMT_TYPE_DWORD, (BYTE *) & speakerConfig, sizeof(speakerConfig));
assert(hr == S_OK);
BOOL discreteChannels = TRUE;
hr = reader2->SetOutputSetting(output, g_wszEnableDiscreteOutput, WMT_TYPE_BOOL, (BYTE *) & discreteChannels , sizeof(discreteChannels ));
assert(hr == S_OK);
if (FAILED(reader->GetOutputFormatCount(output, &numFormats)))
continue;
for (format = 0;format < numFormats;format++)
{
reader->GetOutputFormat(output, format, &formatProperties);
formatProperties->GetType(&mediaType);
if (mediaType == WMMEDIATYPE_Audio)
{
WM_MEDIA_TYPE *mediaType = NewMediaType(formatProperties);
if (mediaType->subtype == WMMEDIASUBTYPE_PCM)
{
if (AGAVE_API_CONFIG)
{
unsigned int bits = AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16);
WAVEFORMATEXTENSIBLE *waveFormat = (WAVEFORMATEXTENSIBLE *) mediaType->pbFormat;
if (waveFormat->Format.cbSize >= 22)
waveFormat->Samples.wValidBitsPerSample=bits;
waveFormat->Format.wBitsPerSample=bits;
waveFormat->Format.nBlockAlign = (waveFormat->Format.wBitsPerSample / 8) * waveFormat->Format.nChannels;
waveFormat->Format.nAvgBytesPerSec=waveFormat->Format.nSamplesPerSec * waveFormat->Format.nBlockAlign;
if (FAILED(formatProperties->SetMediaType(mediaType)))
{
// blah, just use the default settings then
delete[] mediaType;
mediaType = NewMediaType(formatProperties);
}
}
AudioFormat::Open(mediaType);
delete mediaType;
bool video = false;
First().HasVideo(video);
// this is needed to prevent an audio glitch on first playback
if (out)
{
extern WMDRM mod;
out->SetVolume(mod.GetVolume());
out->SetPan(mod.GetPan());
}
latency = out->Open(SampleRate(), Channels(), ValidBits(), (video ? -666 : -1), -1);
if (latency >= 0)
{
audioOutputNum = output;
reader->SetOutputProps(audioOutputNum, formatProperties);
formatProperties->Release();
return true;
}
else
{
formatProperties->Release();
AudioFormat::Close();
continue;
}
}
delete mediaType;
formatProperties->Release();
}
}
}
return false;
}
void AudioLayer::SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample)
{
if (outputNum == audioOutputNum)
{
if (WaitForSingleObject(killSwitch, 0) == WAIT_OBJECT_0)
return ;
if (videoCatchup)
{
videoCatchup = videoCatchup / 20000;
videoCatchup = min(videoCatchup, offset / 40000);
unsigned int num = (unsigned int) (videoCatchup / VIDEO_ACCEPTABLE_JITTER_MS);
while (num--)
{
if (WaitForSingleObject(killSwitch, VIDEO_ACCEPTABLE_JITTER_MS) == WAIT_OBJECT_0)
return ;
}
videoCatchup = 0;
}
while (!audioThread.AddBuffer(sample, timeStamp, flags, false))
{
if (WaitForSingleObject(killSwitch, VIDEO_ACCEPTABLE_JITTER_MS) == WAIT_OBJECT_0)
break;
}
}
else
WMHandler::SampleReceived(timeStamp, duration, outputNum, flags, sample);
}
void AudioLayer::VideoCatchup(QWORD time)
{
videoCatchup = time;
WMHandler::VideoCatchup(time);
}
void AudioLayer::Closed()
{
if (opened)
{
out->Close();
winamp.CloseViz();
}
opened = false;
//AudioFormat::Close();
WMHandler::Closed();
}
AudioLayer::~AudioLayer()
{
audioThread.Kill();
if (reader2)
reader2->Release();
if (reader)
reader->Release();
CloseHandle(killSwitch);
}
void AudioLayer::Kill()
{
SetEvent(killSwitch);
if (opened)
audioThread.SignalStop();
WMHandler::Kill();
if (opened)
audioThread.WaitForStop();
}
void AudioLayer::EndOfFile()
{
if (!opened || audioThread.EndOfFile())
WMHandler::EndOfFile();
}
+51
View File
@@ -0,0 +1,51 @@
#ifndef NULLSOFT_AUDIOLAYERH
#define NULLSOFT_AUDIOLAYERH
#include "WMHandler.h"
#include <mmreg.h>
#include "AudioThread.h"
#include "AudioFormat.h"
class AudioLayer : public WMHandler, public AudioFormat
{
public:
AudioLayer(IWMReader *_reader);
~AudioLayer();
bool IsOpen()
{
return opened;
}
void Kill();
bool OpenAudio();
void StartAudioThread();
private:
// WMHandler events
void Opened();
void SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample);
void VideoCatchup(QWORD time);
void Closed();
void EndOfFile();
void Started();
void Stopped();
// other people's data
IWMReader *reader;
// our data
QWORD startPosition;
int audioOutputNum;
IWMReaderAdvanced2 *reader2;
QWORD offset;
DWORD new_offset;
QWORD videoCatchup;
bool opened;
HANDLE killSwitch;
int latency;
AudioThread audioThread;
};
#endif
+129
View File
@@ -0,0 +1,129 @@
#include "Main.h"
#include "AudioThread.h"
#include "AudioLayer.h"
#include <assert.h>
extern unsigned long endTime;
DWORD WINAPI AudThread_stub(void *ptr)
{
((AudioThread *)ptr)->AudThread();
return 0;
}
void AudioThread::Start(WMHandler *_output)
{
assert(_output);
output = _output;
eof=0;
ResetEvent(stopped);
QueueUserAPC(MediaThread_StartAPC, thread, reinterpret_cast<ULONG_PTR>(static_cast<MediaThread *>(this)));
}
AudioThread::AudioThread(AudioLayer *audio) : output(0), audioLayer(audio)
{
DWORD id;
thread = CreateThread(NULL, 256*1024, AudThread_stub, (void *)this, NULL, &id);
SetThreadPriority(thread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
}
void AudioThread::AudThread()
{
int endbreak=0;
while (true)
{
switch (WaitForSingleObjectEx(killEvent, wait, TRUE))
{
case WAIT_OBJECT_0:
//StopAPC();
return;
case WAIT_TIMEOUT:
{
if (buffers.empty() || endbreak)
{
SetEvent(bufferFreed);
if (eof==1)
{
eof=2;
output->EndOfFile();
}
endbreak = 0;
continue;
}
MediaBuffer *buffer = buffers.front();
DWORD length;
void *data;
buffer->buffer->GetBufferAndLength((BYTE **)&data, &length);
//if (out->CanWrite() >= length)
{
QWORD timestamptemp = buffer->timestamp/10000LL;
DWORD timestamp = static_cast<DWORD>(timestamptemp);
if (buffer->flags & WM_SF_DISCONTINUITY)
{
// fill with silence!
int msToFill = timestamp - out->GetWrittenTime(); // TODO: maybe use microsoft's time resolution?
if (msToFill > 0 && msToFill < 2000)
{
int bytes = audioLayer->AudioMillisecondsToBytes(msToFill);
__int8 *zeroes = (__int8 *)calloc(bytes, 1);
if (zeroes)
{
output->AudioDataReceived(zeroes, bytes, timestamp);
free(zeroes);
}
else
{
out->Flush(timestamp);
}
}
else if (msToFill > 0)
{
out->Flush(timestamp);
}
}
output->AudioDataReceived(data, length, timestamp);
// TODO seen a few crash reports failing around here
// might be the cause of the random wma fails
// but crash dump doesn't help too much afaict
try {
buffer->buffer->Release();
delete buffer;
} catch (...) {}
//buffers.pop_front();
if (buffers.size())
{
buffers.erase(buffers.begin());
}
unsigned long x = endTime;
if (x && timestamp > x)
{
eof = 1; // reached the end baby....
endbreak = 1;
}
}
if (buffers.size() < config_audio_cache_frames)
SetEvent(bufferFreed);
}
continue;
default:
continue;
}
}
}
void AudioThread::AddAPC(MediaBuffer *buffer)
{
OrderedInsert(buffer);
if (buffers.size() >= config_audio_cache_frames)
ResetEvent(bufferFreed);
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef NULLSOFT_AUDIOTHREADH
#define NULLSOFT_AUDIOTHREADH
#include "WMHandler.h"
#include "MediaThread.h"
#include <wmsdk.h>
class AudioLayer;
class AudioThread : public MediaThread
{
public:
AudioThread(AudioLayer *audio);
void Start(WMHandler *output);
/* AddBuffers put an audio buffer in the queue
it returns true if it was added
it returns false if it was NOT added. it is up to YOU (the caller) to sleep for a while and call again
*/
void AudThread();
bool EndOfFile()
{
if (buffers.empty()) // if the buffers are empty, then our thread might never get a chance to signal EOF
return true;
if (eof)
return true;
eof=1;
return false;
}
private:
void AddAPC(MediaBuffer *);
int eof;
WMHandler *output;
AudioLayer *audioLayer;
};
#endif
+43
View File
@@ -0,0 +1,43 @@
#ifndef NULLSOFT_AUTOCHARH
#define NULLSOFT_AUTOCHARH
class AutoChar
{
public:
AutoChar(const wchar_t *convert) : allocated(false), narrow(0)
{
// review maybe CP_UTF8?
int size = WideCharToMultiByte(CP_ACP, 0, convert, -1, 0, 0, NULL, NULL);
if (!size)
return;
narrow = new char[size];
allocated=true;
if (!WideCharToMultiByte(CP_ACP, 0, convert, -1, narrow, size, NULL, NULL))
{
delete [] narrow;
narrow=0;
allocated=false;
}
}
~AutoChar()
{
if (allocated)
{
delete [] narrow;
narrow=0;
allocated=false;
}
}
operator char *()
{
return narrow;
}
private:
bool allocated;
char *narrow;
};
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef AUTOWIDEH
#define AUTOWIDEH
class AutoWide
{
public:
AutoWide(const char *convert) : allocated(false), wide(0)
{
// review maybe CP_UTF8?
int size = MultiByteToWideChar(CP_ACP, 0, convert, -1, 0,0);
if (!size)
return;
wide = new unsigned short[size];
allocated=true;
if (!MultiByteToWideChar(CP_ACP, 0, convert, -1, wide,size))
{
delete wide;
wide=0;
allocated=false;
}
}
~AutoWide()
{
if (allocated)
{
delete wide;
wide=0;
allocated=false;
}
}
operator unsigned short *()
{
return wide;
}
private:
bool allocated;
unsigned short *wide;
};
#endif
@@ -0,0 +1,95 @@
#include "BufferLayer.h"
#include "Main.h"
#include "resource.h"
#define killEvent events[0]
#define startEvent events[1]
enum
{
KILL_EVENT = 0,
START_EVENT = 1,
};
DWORD WINAPI BufferLayer::BufThread_stub(void *ptr)
{
((BufferLayer *)ptr)->BufThread();
return 0;
}
BufferLayer::BufferLayer(IWMReader *reader) : reader2(0), buffering(false)
{
if (FAILED(reader->QueryInterface(&reader2)))
reader2 = 0;
startEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
killEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
DWORD id;
thread = CreateThread(NULL, 128*1024, BufThread_stub, (void *)this, NULL, &id);
}
BufferLayer::~BufferLayer()
{
SetEvent(killEvent);
ResetEvent(startEvent);
WaitForSingleObject(thread, INFINITE);
if (reader2) reader2->Release(); reader2 = 0;
}
void BufferLayer::BufferingStarted()
{
winamp.SetStatus(WASABI_API_LNGSTRINGW(IDS_BUFFERING));
buffering=true;
SetEvent(startEvent);
WMHandler::BufferingStarted();
}
void BufferLayer::BufferingStopped()
{
winamp.SetStatus(L"");
buffering=false;
ResetEvent(startEvent);
WMHandler::BufferingStopped();
}
int BufferLayer::Wait()
{
if (WaitForSingleObject(killEvent, 0) == WAIT_OBJECT_0)
return KILL_EVENT;
return WaitForMultipleObjects(2, events, FALSE, INFINITE) - WAIT_OBJECT_0;
}
void BufferLayer::BufThread()
{
do
{
switch (Wait())
{
case KILL_EVENT:
return ;
case START_EVENT:
{
if (reader2)
{
DWORD percent;
QWORD throwAway;
if (SUCCEEDED(reader2->GetBufferProgress(&percent, &throwAway)))
winamp.Buffering(percent, WASABI_API_LNGSTRINGW(IDS_BUFFERING));
}
Sleep(10);
}
continue;
}
}
while (true);
}
void BufferLayer::OpenFailed()
{
ResetEvent(startEvent);
WMHandler::OpenFailed();
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef NULLSOFT_BUFFERLAYERH
#define NULLSOFT_BUFFERLAYERH
#include "WMHandler.h"
class BufferLayer : public WMHandler
{
public:
BufferLayer(IWMReader *reader);
~BufferLayer();
protected:
void BufferingStarted();
void BufferingStopped();
void OpenFailed();
private:
static DWORD WINAPI BufThread_stub(void *ptr);
void BufThread();
int Wait();
HANDLE events[2];
IWMReaderAdvanced2 *reader2;
HANDLE thread;
volatile bool buffering;
};
#endif
+203
View File
@@ -0,0 +1,203 @@
#ifndef NULLSOFT_BUFFERPOOLH
#define NULLSOFT_BUFFERPOOLH
#include <wmsdk.h>
#include "../nu/AutoLock.h"
#include <deque>
#include <iostream>
#include <cassert>
using namespace Nullsoft::Utility;
class Buffer;
class Pool
{
public:
virtual void ReturnBuffer(Buffer *buffer) = 0;
};
class Buffer : public INSSBuffer
{
public:
Buffer(size_t _size, Pool *_pool)
: size(_size),
length(0),
pool(_pool),
refCount(1)
{
buffer = new unsigned char[size];
}
~Buffer()
{
delete[] buffer;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return ++refCount;
}
ULONG STDMETHODCALLTYPE Release()
{
assert(refCount > 0);
if (--refCount == 0)
{
length = 0;
pool->ReturnBuffer(this);
}
return refCount;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
if (IID_INSSBuffer == iid)
{
*ppvObject = static_cast<INSSBuffer *>(this);
AddRef();
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
}
HRESULT STDMETHODCALLTYPE GetBuffer(BYTE **ppdwBuffer)
{
*ppdwBuffer = (BYTE *)buffer;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetBufferAndLength(BYTE **ppdwBuffer, DWORD *pdwLength)
{
*ppdwBuffer = (BYTE *)buffer;
*pdwLength = length;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetLength(DWORD *pdwLength)
{
*pdwLength = length;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetMaxLength(DWORD *pdwLength)
{
*pdwLength = size;
return S_OK;
}
HRESULT STDMETHODCALLTYPE SetLength(DWORD dwLength)
{
length = dwLength;
return S_OK;
}
bool CanFit(size_t sizeCompare)
{
return (sizeCompare <= size);
}
size_t size, length;
Pool *pool;
int refCount;
unsigned char *buffer;
};
class BufferPool : public Pool
{
typedef std::deque<Buffer *> PoolList;
public:
long limit;
BufferPool() : allocSize(0),
poolSize(0),
limit(0)
{}
~BufferPool()
{
FreeBuffers();
}
void FreeBuffers()
{
AutoLock lock (bufferGuard);
while (!pool.empty())
{
Buffer *buff = pool.front();
delete buff;
pool.pop_front();
poolSize = 0;
}
}
void ReturnBuffer(Buffer *buffer)
{
AutoLock lock (bufferGuard);
pool.push_back(buffer);
}
Buffer *SearchForBuffer(size_t size)
{
PoolList::iterator itr;
AutoLock lock (bufferGuard);
for (itr = pool.begin();itr != pool.end();itr++)
{
if ((*itr)->CanFit(size))
{
Buffer *buff = *itr;
pool.erase(itr);
buff->AddRef();
return buff;
}
}
return 0;
}
void PreAllocate(size_t count)
{
if (!allocSize)
return ;
for (size_t i = 0;i != count;i++)
{
AutoLock lock (bufferGuard);
pool.push_back( new Buffer(allocSize , this));
}
}
INSSBuffer *GetBuffer(size_t size)
{
Buffer *buff = SearchForBuffer(size);
/*
while (!buff && poolSize>=limit && limit)
{
Sleep(1);
buff = SearchForBuffer(size);
}*/
if (!buff)
{
poolSize++;
std::cerr << "poolsize = " << poolSize << std::endl;
buff = new Buffer(allocSize ? allocSize : size, this);
}
return buff;
}
void test()
{
std::cerr << "pool.size() == " << pool.size();
std::cerr << " and poolsize == " << poolSize << std::endl;
}
void SetAllocSize(long size)
{
allocSize = size;
}
PoolList pool;
LockGuard bufferGuard;
size_t allocSize;
size_t poolSize;
};
#endif
+48
View File
@@ -0,0 +1,48 @@
#ifndef CACHEDDATAH
#define CACHEDDATAH
template <class DataType>
class CachedData
{
public:
CachedData() : cached(false)
{
}
CachedData(DataType _data) : cached(true), data(_data)
{
}
operator DataType()
{
return data;
}
bool IsCached()
{
return cached;
}
void ClearCache()
{
cached=false;
}
DataType *operator &()
{
if (cached)
return &data;
else
return 0;
}
template <class FromType>
bool operator =(FromType from)
{
data = from;
cached=true;
return cached;
}
private:
bool cached;
DataType data;
};
#endif
+101
View File
@@ -0,0 +1,101 @@
#include "Main.h"
#include "ClockLayer.h"
#include "config.h"
ClockLayer::ClockLayer(IWMReader *reader)
: clock(0), startTime(0),
clockTick(2500000), curTime(0),
startTimeMilliseconds(0),
realTime(false),
lastOutputTime(0)
{
if (FAILED(reader->QueryInterface(&clock)))
clock=0;
}
void ClockLayer::Opened()
{
realTime=!config_clock;
WMHandler::Opened();
if (!realTime)
{
HRESULT hr = clock->SetUserProvidedClock(TRUE);
if (FAILED(hr))
{
realTime=false;
}
}
else
clock->SetUserProvidedClock(FALSE);
curTime = startTime;
}
void ClockLayer::Started()
{
if (!realTime && config_clock)
clock->DeliverTime((QWORD) - 1);
if (startTimeMilliseconds != 0)
out->Flush(startTimeMilliseconds);
SetLastOutputTime(startTimeMilliseconds);
WMHandler::Started();
}
void ClockLayer::Clock()
{
if (!realTime && config_clock)
clock->DeliverTime((QWORD) - 1);
}
void ClockLayer::SetStartTimeMilliseconds(long time)
{
startTimeMilliseconds=time;
startTime = time;
startTime *= 10000;
}
void ClockLayer::TimeReached(QWORD &timeReached)
{
curTime = timeReached;
}
QWORD ClockLayer::GetStartTime()
{
return startTime;
}
void ClockLayer::GoRealTime()
{
realTime = true;
}
int ClockLayer::GetOutputTime()
{
if (realTime)
return (int) (curTime / 10000LL);
else
return lastOutputTime + (out->GetOutputTime() - out->GetWrittenTime());
}
void ClockLayer::TimeToSync(QWORD timeStamp, __int64 &diff)
{
if (realTime)
diff = 0;
else
{
QWORD outputTime = this->GetOutputTime();
outputTime *= 10000LL;
diff = timeStamp - outputTime;
}
}
void ClockLayer::SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample)
{
if (realTime)
curTime = timeStamp;
WMHandler::SampleReceived(timeStamp, duration, outputNum, flags, sample);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef NULLSOFT_CLOCKLAYERH
#define NULLSOFT_CLOCKLAYERH
#include "WMHandler.h"
class ClockLayer : public WMHandler
{
public:
ClockLayer(IWMReader *reader);
void SetStartTimeMilliseconds(long time);
QWORD GetStartTime();
void GoRealTime();
int GetOutputTime();
void SetLastOutputTime(int _outputTime)
{
lastOutputTime = _outputTime;
}
void Clock();
private:
// WMHandler
void Opened();
void Started();
void TimeReached(QWORD &timeReached);
void TimeToSync(QWORD timeStamp, __int64 &diff);
void SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample);
IWMReaderAdvanced *clock;
QWORD startTime, clockTick, curTime;
DWORD startTimeMilliseconds;
bool realTime;
int lastOutputTime;
};
#endif
@@ -0,0 +1,398 @@
#include "Main.h"
#include "resource.h"
#include "../nu/ListView.h"
#include "FileTypes.h"
#include "AutoChar.h"
W_ListView typeList;
FileTypes::TypeList types;
#define CFGSET(hwnd, code, boolval) CheckDlgButton(hwnd, code, ((boolval)?BST_CHECKED:BST_UNCHECKED))
struct SpeakerSetup
{
int description;
DWORD value;
};
SpeakerSetup speakerList[] =
{
{IDS_STEREO,DSSPEAKER_STEREO},
{IDS_QUADROPHONIC,DSSPEAKER_QUAD},
{IDS_SURROUND,DSSPEAKER_SURROUND},
{IDS_5_1,DSSPEAKER_5POINT1},
{IDS_7_1,DSSPEAKER_7POINT1},
};
void FillFileTypes()
{
typeList.Clear();
long attrCount = types.size();
int pos=0;
for (long i = 0;i < attrCount;i++)
{
typeList.InsertItem(pos, types[i].wtype, 0);
typeList.SetItemText(pos, 1, types[i].description);
pos++;
}
}
void ResetTypes()
{
{
Nullsoft::Utility::AutoLock lock (fileTypes.typeGuard);
types=fileTypes.types;
}
FillFileTypes();
}
void Preferences_Populate(HWND hwndDlg)
{
CFGSET(hwndDlg, IDC_HTTPMETA, config_http_metadata);
/* CFGSET(hwndDlg, IDC_SILENT, !config_no_silent);
CFGSET(hwndDlg, IDC_UNTRUSTED, config_untrusted_ok);
*/
CFGSET(hwndDlg, IDC_EXTRA_ASX, config_extra_asx_extensions);
SetDlgItemInt(hwndDlg,IDC_BUFFER_TIME, config_buffer_time, FALSE/*unsigned*/);
SendMessage(GetDlgItem(hwndDlg, IDC_AUDIO_SPEAKER_COUNT), CB_RESETCONTENT, 0, 0);
for (int i = 0;i < sizeof(speakerList)/sizeof(speakerList[0]) ;i++)
{
SendMessage(GetDlgItem(hwndDlg, IDC_AUDIO_SPEAKER_COUNT), CB_ADDSTRING, 0, (LPARAM) WASABI_API_LNGSTRINGW(speakerList[i].description));
if (speakerList[i].value == config_audio_num_channels)
SendMessage(GetDlgItem(hwndDlg, IDC_AUDIO_SPEAKER_COUNT), CB_SETCURSEL, i, 0);
}
ResetTypes();
}
void Preferences_Init(HWND hwndDlg)
{
typeList.setwnd(GetDlgItem(hwndDlg, IDC_TYPELIST));
typeList.AddCol(WASABI_API_LNGSTRINGW(IDS_EXT), 75);
typeList.AddCol(WASABI_API_LNGSTRINGW(IDS_DESCRIPTION), 250);
Preferences_Populate(hwndDlg);
if(config_col1 == -1)
typeList.AutoSizeColumn(0);
else
typeList.SetColumnWidth(0, config_col1);
if(config_col2 == -1)
typeList.AutoSizeColumn(1);
else
typeList.SetColumnWidth(1, config_col2);
if (NULL != WASABI_API_APP)
WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(typeList.getwnd(), TRUE);
}
void Preferences_TypeRemove(HWND hwndDlg)
{
int next = -1;
do
{
next = typeList.GetNextSelected(next);
if (next != -1)
{
free(types[next].wtype);
types[next].wtype=0;
}
} while (next != -1);
for (FileTypes::TypeList::iterator itr = types.begin(); itr != types.end(); )
{
if (!itr->wtype || !itr->wtype[0])
types.erase(itr);
else
itr++;
}
}
void OnOk(HWND hwndDlg)
{
config_http_metadata=IsDlgButtonChecked(hwndDlg, IDC_HTTPMETA)== BST_CHECKED;
// config_no_silent=IsDlgButtonChecked(hwndDlg, IDC_SILENT) != BST_CHECKED;
// config_untrusted_ok=IsDlgButtonChecked(hwndDlg, IDC_UNTRUSTED)== BST_CHECKED;
config_extra_asx_extensions=IsDlgButtonChecked(hwndDlg, IDC_EXTRA_ASX)== BST_CHECKED;
wchar_t temp[64] = {0};
GetDlgItemText(hwndDlg,IDC_BUFFER_TIME, temp, 64);
int newBufferTime= _wtoi(temp);
if (newBufferTime<1000)
newBufferTime=1000;
if (newBufferTime>60000)
newBufferTime=60000;
config_buffer_time=newBufferTime;
int numChannels=SendMessage(GetDlgItem(hwndDlg, IDC_AUDIO_SPEAKER_COUNT), CB_GETCURSEL, 0, 0);
if (numChannels!=CB_ERR)
config_audio_num_channels = speakerList[numChannels].value;
fileTypes.SetTypes(types);
}
static INT_PTR CALLBACK AddTypeProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
CFGSET(hwndDlg, IDC_FILEEXTENSION, true);
CFGSET(hwndDlg, IDC_TYPE_AUDIO, true);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PROTOCOL:
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_PROTOCOL));
break;
case IDC_FILEEXTENSION:
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_EXTENSION));
break;
case IDOK:
{
wchar_t type[MAX_PATH] = {0}, description[1024] = {0};
GetDlgItemText(hwndDlg,IDC_TYPE,type,MAX_PATH);
GetDlgItemText(hwndDlg,IDC_DESCRIPTION,description,1024);
bool isProtocol = IsDlgButtonChecked(hwndDlg, IDC_PROTOCOL)== BST_CHECKED;
int avType = IsDlgButtonChecked(hwndDlg, IDC_TYPE_VIDEO)== BST_CHECKED;
types.push_back(FileType(type, description, isProtocol, avType));
EndDialog(hwndDlg, 0);
}
break;
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
}
break;
}
return FALSE;
}
void AddType(HWND hwndDlg)
{
WASABI_API_DIALOGBOXW(IDD_ADDTYPE, hwndDlg, AddTypeProc);
}
static size_t editIndex=0;
static INT_PTR CALLBACK EditTypeProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
SetWindowText(hwndDlg, WASABI_API_LNGSTRINGW(IDS_EDIT_FILE_TYPE));
CFGSET(hwndDlg, IDC_TYPE_AUDIO, (types[editIndex].avType==FileType::AUDIO));
CFGSET(hwndDlg, IDC_TYPE_VIDEO, (types[editIndex].avType==FileType::VIDEO));
CFGSET(hwndDlg, IDC_PROTOCOL, types[editIndex].isProtocol);
CFGSET(hwndDlg, IDC_FILEEXTENSION, !types[editIndex].isProtocol);
SetDlgItemText(hwndDlg,IDC_TYPE, types[editIndex].wtype);
SetDlgItemText(hwndDlg,IDC_DESCRIPTION, types[editIndex].description);
if (types[editIndex].isProtocol)
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_PROTOCOL));
else
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_EXTENSION));
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PROTOCOL:
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_PROTOCOL));
break;
case IDC_FILEEXTENSION:
SetDlgItemText(hwndDlg, IDC_STATIC_TYPE, WASABI_API_LNGSTRINGW(IDS_EXTENSION));
break;
case IDOK:
{
wchar_t type[MAX_PATH] = {0}, description[1024] = {0};
GetDlgItemText(hwndDlg,IDC_TYPE,type,MAX_PATH);
GetDlgItemText(hwndDlg,IDC_DESCRIPTION,description,1024);
bool isProtocol = IsDlgButtonChecked(hwndDlg, IDC_PROTOCOL)== BST_CHECKED;
types[editIndex].avType = (IsDlgButtonChecked(hwndDlg, IDC_TYPE_VIDEO)== BST_CHECKED);
if(types[editIndex].wtype)free(types[editIndex].wtype);
types[editIndex].wtype = _wcsdup(type);
types[editIndex].isProtocol = isProtocol;
if(types[editIndex].description)free(types[editIndex].description);
types[editIndex].description = _wcsdup(description);
EndDialog(hwndDlg, 0);
}
break;
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
}
break;
}
return FALSE;
}
void EditType(HWND hwndDlg)
{
editIndex=-1;
do
{
editIndex=typeList.GetNextSelected(editIndex);
if (editIndex != -1)
{
WASABI_API_DIALOGBOXW(IDD_ADDTYPE, hwndDlg, EditTypeProc);
}
else
return;
} while (true);
}
void Advanced_Init(HWND hwndDlg)
{
CFGSET(hwndDlg, IDC_AUDIO_THREAD, config_audio_dedicated_thread);
CFGSET(hwndDlg, IDC_AUDIO_EARLY, config_audio_early);
CFGSET(hwndDlg, IDC_AUDIO_OUTOFORDER, config_audio_outoforder);
CFGSET(hwndDlg, IDC_AUDIO_DROP, config_video_catchup);
CFGSET(hwndDlg, IDC_VIDEO_THREAD, config_video_dedicated_thread);
CFGSET(hwndDlg, IDC_VIDEO_EARLY, config_video_early);
CFGSET(hwndDlg, IDC_VIDEO_OUTOFORDER, config_video_outoforder);
CFGSET(hwndDlg, IDC_VIDEO_NOTIFY, config_video_notifylate);
CFGSET(hwndDlg, IDC_REALTIME, !config_clock);
CFGSET(hwndDlg, IDC_LOWMEMORY, config_lowmemory);
SetDlgItemInt(hwndDlg,IDC_AUDIO_CACHE_FRAMES, config_audio_cache_frames, TRUE/*signed*/);
SetDlgItemInt(hwndDlg,IDC_VIDEO_CACHE_FRAMES, config_video_cache_frames, TRUE);
SetDlgItemInt(hwndDlg,IDC_VIDEO_DROP_THRESHOLD, config_video_drop_threshold, TRUE);
SetDlgItemInt(hwndDlg,IDC_VIDEO_JITTER, config_video_jitter, TRUE);
SetDlgItemInt(hwndDlg,IDC_AUDIO_EARLYPAD, config_audio_early_pad, TRUE);
SetDlgItemInt(hwndDlg,IDC_VIDEO_EARLYPAD, config_video_early_pad,TRUE);
}
void Advanced_OnOK(HWND hwndDlg)
{
config_audio_dedicated_thread=IsDlgButtonChecked(hwndDlg, IDC_AUDIO_THREAD)== BST_CHECKED;
config_audio_early=IsDlgButtonChecked(hwndDlg, IDC_AUDIO_EARLY)== BST_CHECKED;
config_audio_outoforder=IsDlgButtonChecked(hwndDlg, IDC_AUDIO_OUTOFORDER)== BST_CHECKED;
config_video_catchup=IsDlgButtonChecked(hwndDlg, IDC_AUDIO_DROP)== BST_CHECKED;
config_video_dedicated_thread=IsDlgButtonChecked(hwndDlg, IDC_VIDEO_THREAD)== BST_CHECKED;
config_video_early=IsDlgButtonChecked(hwndDlg, IDC_VIDEO_EARLY)== BST_CHECKED;
config_video_outoforder=IsDlgButtonChecked(hwndDlg, IDC_VIDEO_OUTOFORDER)== BST_CHECKED;
config_video_notifylate=IsDlgButtonChecked(hwndDlg, IDC_VIDEO_NOTIFY)== BST_CHECKED;
config_clock=IsDlgButtonChecked(hwndDlg, IDC_REALTIME)!= BST_CHECKED;
config_lowmemory=IsDlgButtonChecked(hwndDlg, IDC_LOWMEMORY)== BST_CHECKED;
wchar_t temp[64] = {0};
GetDlgItemText(hwndDlg,IDC_AUDIO_CACHE_FRAMES, temp, 64);
config_audio_cache_frames = _wtoi(temp);
GetDlgItemText(hwndDlg,IDC_VIDEO_CACHE_FRAMES, temp, 64);
config_video_cache_frames= _wtoi(temp);
GetDlgItemText(hwndDlg,IDC_VIDEO_DROP_THRESHOLD, temp, 64);
config_video_drop_threshold= _wtoi(temp);
GetDlgItemText(hwndDlg,IDC_VIDEO_JITTER, temp, 64);
config_video_jitter= _wtoi(temp);
GetDlgItemText(hwndDlg,IDC_AUDIO_EARLYPAD, temp, 64);
config_audio_early_pad= _wtoi(temp);
GetDlgItemText(hwndDlg,IDC_VIDEO_EARLYPAD, temp, 64);
config_video_early_pad= _wtoi(temp);
}
static INT_PTR CALLBACK AdvancedDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
Advanced_Init(hwndDlg);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
Advanced_OnOK(hwndDlg);
EndDialog(hwndDlg, 0);
break;
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
}
break;
}
return 0;
}
void Advanced(HWND hwndDlg)
{
WASABI_API_DIALOGBOXW(IDD_ADVANCED, hwndDlg, AdvancedDialogProc);
}
void Preferences_Default(HWND hwndDlg)
{
if (config_no_video)
{
// TODO: ask the user if they want to enable video support
}
DefaultConfig();
fileTypes.LoadDefaults();
Preferences_Populate(hwndDlg);
}
INT_PTR CALLBACK PreferencesDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
Preferences_Init(hwndDlg);
break;
case WM_DESTROY:
config_col1 = typeList.GetColumnWidth(0);
config_col2 = typeList.GetColumnWidth(1);
if (NULL != WASABI_API_APP)
WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(typeList.getwnd(), FALSE);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_ADVANCED:
Advanced(hwndDlg);
break;
case IDC_DEFAULTTYPE:
Preferences_Default(hwndDlg);
break;
case IDC_ADDTYPE:
AddType(hwndDlg);
FillFileTypes();
break;
case IDC_EDITTYPE:
EditType(hwndDlg);
if(typeList.GetNextSelected(editIndex)!=-1)
FillFileTypes();
break;
case IDC_REMOVETYPE:
Preferences_TypeRemove(hwndDlg);
FillFileTypes();
break;
case IDOK:
OnOk(hwndDlg);
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
}
break;
}
return 0;
}
@@ -0,0 +1,4 @@
#ifndef NULLSOFT_CONFIGDIALOGH
#define NULLSOFT_CONFIGDIALOGH
INT_PTR CALLBACK PreferencesDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
+34
View File
@@ -0,0 +1,34 @@
Windows Media works in an asynchronous manner.
The WM Decompressor (IWMReader) requires that you provide a class
deriving from IWMReader (and, optionally, IWMReaderAdvanced) to receive information
Each delivery of uncompressed media arrives in an OnSample method
Status messages arrive in an OnStatus method.
The main difficulty that arrives from this approach is that ALL messages funnel through
a single function. Audio data and Video data arrive in the same function.
Even worse, status messages for file opened, clock error, http buffering, and DRM requirements all arrive in the same function!
In order to handle this properly, a "chain of event handlers" class was developed (WMHandler)
Any object wishing to receive data or status messages can derive from the WMHandler. All unhandled
messages are automatically passed to the next handler in the chain. Messages that are handled can be
passed or not passed based on programming requirements.
The main object sets up the chain. The >> operator has been convienently defined to faciliate the chaining.
The left side of the >> line must be the source (WMCallback)
(e.g. callback >> clock >> drm >> video >> audio >> wait >> this;)
Handlers may create their own mini-chains (which will get added in-whole) using the WMHandler::Inject() method.
Threading
------
7 basic threads
1. Main (Windows) thread
2. Callback/OnStatus thread
3. Audio Decoder thread
4. Video Decoder thread
5. Audio buffering thread (ours)
6. Video buffering thread (ours)
7. Buffering-percent status thread (ours)
There might be additional threads (created in another module) calling in, for functions like getextendedfileinfo
@@ -0,0 +1,597 @@
#include "main.h"
#include "../nu/AutoWide.h"
#include "WMPlaylist.h"
#include "resource.h"
#include <math.h>
#include <strsafe.h>
WMInformation *setFileInfo = 0;
static wchar_t *setFileInfoName=0;
static bool forcedStop = false;
static int outTime = 0;
float GetGain(WMInformation *info, bool allowDefault);
static const wchar_t *extension(const wchar_t *fn)
{
const wchar_t *x = PathFindExtension(fn);
if (*x)
return CharNext(x);
else
return x;
}
static bool KeywordMatch(const char *mainString, const char *keyword)
{
return !_stricmp(mainString, keyword);
}
static bool KeywordMatch(const wchar_t *mainString, const wchar_t *keyword)
{
return !lstrcmpiW(mainString, keyword);
}
static bool StartsWith(const wchar_t *mainString, const wchar_t *substring)
{
return !_wcsnicmp(mainString, substring, lstrlenW(substring));
}
static int Width(int dec)
{
// there's probably a better way
int width=3;
while (width && (dec % 10) == 0)
{
dec/=10;
width--;
}
return width;
}
int GetExtendedInformation(WMInformation *getExtendedFileInfo, const wchar_t *fn, const char *data, wchar_t *dest, int destlen)
{
AutoWide tagNameW(data);
const wchar_t *tagName = GetAlias(tagNameW);
if (KeywordMatch(tagName, L"streammetadata"))
{
if (config_http_metadata)
{
lstrcpyn(dest, L"1", destlen);
return 1;
}
return 0;
}
else if (KeywordMatch(tagName, L"type"))
{
if (!fn || !fn[0])
lstrcpyn(dest, (config_no_video ? L"0" : L"1"), destlen);
else if (getExtendedFileInfo->IsAttribute(g_wszWMHasVideo))
lstrcpyn(dest, L"1", destlen);
else if (getExtendedFileInfo->IsAttribute(g_wszWMHasAudio))
lstrcpyn(dest, L"0", destlen);
else
{
switch (fileTypes.GetAVType(extension(fn)))
{
case FileType::AUDIO:
lstrcpyn(dest, L"0", destlen);
break;
case FileType::VIDEO:
lstrcpyn(dest, L"1", destlen);
break;
default:
return 0;
}
}
return 1;
}
else if (KeywordMatch(tagName, L"rateable"))
{
dest[0] = '1';
dest[1] = 0;
return 1;
}
else if (StartsWith(tagName, L"WM/"))
{
getExtendedFileInfo->GetAttribute(tagName, dest, destlen);
return 1;
}
/*else if (KeywordMatch(data, "burnable")) // note: this isn't supposed to be any kind of protection - just keeps the burner from misbehaving on protected tracks
{
if (getExtendedFileInfo->IsAttribute(g_wszWMProtected))
lstrcpyn(dest, L"0", destlen);
else
lstrcpyn(dest, L"1", destlen);
return 1;
}*/
else if (KeywordMatch(data, "noburnreason")) // note: this isn't supposed to be any kind of protection - just keeps the burner from misbehaving on protected tracks
{
if (getExtendedFileInfo->IsAttribute(g_wszWMProtected))
{
lstrcpyn(dest, L"DRM (copy protected) file", destlen);
return 1;
}
}
else if ((const wchar_t *)tagNameW != tagName) // if the tag was in the tag list
{
getExtendedFileInfo->GetAttribute(tagName, dest, destlen);
return 1;
}
else if (KeywordMatch(data, "bitrate"))
{
StringCchPrintfW(dest, destlen, L"%u", getExtendedFileInfo->GetBitrate() / 1000);
return 1;
}
else if (KeywordMatch(data, "vbr"))
{
if (getExtendedFileInfo->IsAttribute(g_wszWMIsVBR))
StringCchCopyW(dest, destlen, L"1");
else if (getExtendedFileInfo->IsNotAttribute(g_wszWMIsVBR))
StringCchCopyW(dest, destlen, L"0");
return 1;
}
//else if (KeywordMatch(data, "srate"))
else if (KeywordMatch(data, "length"))
{
long length = getExtendedFileInfo->GetLengthMilliseconds();
if (length == -1000)
return 0;
_itow(length, dest, 10);
return 1;
}
else if (KeywordMatch(data, "rating"))
{
wchar_t rating_string[128] = {0};
getExtendedFileInfo->GetAttribute(L"WM/SharedUserRating", rating_string, 128);
int rating = _wtoi(rating_string);
if (rating == 0)
dest[0]=0;
else if (rating >= 1 && rating <= 12)
dest[0]=L'1';
else if (rating >= 13 && rating <= 37)
dest[0]=L'2';
else if (rating >= 38 && rating <= 62)
dest[0]=L'3';
else if (rating >= 63 && rating <= 86)
dest[0]=L'4';
else
dest[0]=L'5';
dest[1]=0;
return 1;
}
else if (KeywordMatch(data, "replaygain_track_gain")
|| KeywordMatch(data, "replaygain_track_peak")
|| KeywordMatch(data, "replaygain_album_gain")
|| KeywordMatch(data, "replaygain_album_peak"))
{
getExtendedFileInfo->GetAttribute(tagName, dest, destlen);
return 1;
}
else if (KeywordMatch(data, "gain"))
{
StringCchPrintfW(dest, destlen, L"%-+.2f dB", (float)log10f(GetGain(getExtendedFileInfo, false))*20.0f);
return 1;
}
else if (KeywordMatch(data, "audiocodec"))
{
if (!getExtendedFileInfo->GetCodecName(dest, destlen))
dest[0]=0;
return 1;
}
else if (KeywordMatch(data, "lossless"))
{
wchar_t codecname[1024] = {0};
if (!getExtendedFileInfo->GetCodecName(codecname, 1024))
dest[0]=0;
else
{
dest[0] = wcsstr(codecname, L"Lossless")?'1':'0';
dest[1]=0;
}
return 1;
}
else if (KeywordMatch(data, "GracenoteFileID"))
{
getExtendedFileInfo->GetAttribute_BinString(L"GN/UniqueFileIdentifier", dest, destlen);
return 1;
}
else if (KeywordMatch(data, "GracenoteExtData"))
{
getExtendedFileInfo->GetAttribute_BinString(L"GN/ExtData", dest, destlen);
return 1;
}
else if (KeywordMatch(data, "formatinformation"))
{
// this is a bit of a clusterfuck, but it's safe and (hopefully) logically laid out.
wchar_t codec[128]=L"", duration[64]=L"", bitrate[64]=L"", filesize[64]=L"", wmver[64]=L"", seekable[64]=L"";
wchar_t stridable[64]=L"", broadcast[64]=L"", protect[64]=L"", trusted[64]=L"", contents[64]=L"";
wchar_t buf[128]=L""; // temporary buffer
// get the codec name string
if (getExtendedFileInfo->GetCodecName(buf, 128) && buf[0])
StringCchPrintf(codec,128,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_CODEC),buf);
// get the length string formatted h:mm:ss.tttt
long t = getExtendedFileInfo->GetLengthMilliseconds();
if (t)
{
long h = t/36000000;
long m = (t/60000)%60;
long s = (t/1000)%60;
long ms = t%1000;
if (h)
StringCchPrintf(duration,64,L"%s: %u:%02u:%02u.%03u\n",WASABI_API_LNGSTRINGW(IDS_DURATION),h,m,s,ms);
else if (m)
StringCchPrintf(duration,64,L"%s: %u:%02u.%03u\n",WASABI_API_LNGSTRINGW(IDS_DURATION),m,s,ms);
else
StringCchPrintf(duration,64,L"%s: %u.%03u\n",WASABI_API_LNGSTRINGW(IDS_DURATION),s,ms);
}
// get the bitrate string formatted 128.235 kbps
long br = getExtendedFileInfo->GetBitrate();
wchar_t kbps[16] = {0};
StringCchPrintf(bitrate,64,L"%s: %.*f %s\n",
WASABI_API_LNGSTRINGW(IDS_BITRATE),
Width(br%1000),
br/1000.0,
WASABI_API_LNGSTRINGW_BUF(IDS_KBPS,kbps,16));
// get the filesize string, with commas grouping in threes
buf[0]=0;
getExtendedFileInfo->GetAttribute(L"FileSize",buf,64);
uint64_t fs = _wcstoui64(buf, 0, 10);
if (fs)
{
uint64_t fsgb = (fs/1000000000LL);
uint64_t fsmb = (fs/1000000LL)%1000LL;
uint64_t fskb = (fs/1000LL)%1000LL;
uint64_t fsb = fs%1000LL;
if (fsgb)
StringCchPrintf(filesize,64,L"%s: %I64u,%03I64u,%03I64u,%03I64u\n",WASABI_API_LNGSTRINGW(IDS_FILESIZE),fsgb,fsmb,fskb,fsb);
else if (fsmb)
StringCchPrintf(filesize,64,L"%s: %I64u,%03I64u,%03I64u\n",WASABI_API_LNGSTRINGW(IDS_FILESIZE),fsmb,fskb,fsb);
else if (fskb)
StringCchPrintf(filesize,64,L"%s: %I64u,%03I64u\n",WASABI_API_LNGSTRINGW(IDS_FILESIZE),fskb,fsb);
else
StringCchPrintf(filesize,64,L"%s: %I64u\n",WASABI_API_LNGSTRINGW(IDS_FILESIZE),fsb);
}
// 4 boolean flags, compose their strings
wchar_t yes[64] = {0}, no[64] = {0};
WASABI_API_LNGSTRINGW_BUF(IDS_YES,yes,64);
WASABI_API_LNGSTRINGW_BUF(IDS_NO,no,64);
buf[0]=0;
getExtendedFileInfo->GetAttribute(L"WMFSDKVersion",buf,128);
if (buf[0])
StringCchPrintf(wmver,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_WMVER),buf);
StringCchPrintf(seekable,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_SEEKABLE),getExtendedFileInfo->IsAttribute(L"Seekable")?yes:no);
StringCchPrintf(stridable,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_STRIDABLE),getExtendedFileInfo->IsAttribute(L"Stridable")?yes:no);
StringCchPrintf(broadcast,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_BROADCAST),getExtendedFileInfo->IsAttribute(L"Broadcast")?yes:no);
StringCchPrintf(protect,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_PROTECTED),getExtendedFileInfo->IsAttribute(L"Is_Protected")?yes:no);
StringCchPrintf(trusted,64,L"%s: %s\n",WASABI_API_LNGSTRINGW(IDS_TRUSTED),getExtendedFileInfo->IsAttribute(L"Is_Trusted")?yes:no);
// file contents. bit gross i know.
wchar_t cont[4][16]={L"",L"",L"",L""};
int i=0;
if (getExtendedFileInfo->IsAttribute(L"HasAudio"))
WASABI_API_LNGSTRINGW_BUF(IDS_AUDIO,cont[i++],16);
if (getExtendedFileInfo->IsAttribute(L"HasVideo"))
WASABI_API_LNGSTRINGW_BUF(IDS_VIDEO,cont[i++],16);
if (getExtendedFileInfo->IsAttribute(L"HasImage"))
WASABI_API_LNGSTRINGW_BUF(IDS_IMAGE,cont[i++],16);
if (getExtendedFileInfo->IsAttribute(L"HasScript"))
WASABI_API_LNGSTRINGW_BUF(IDS_SCRIPT,cont[i++],16);
WASABI_API_LNGSTRINGW_BUF(IDS_NONE,buf,64);
if (i == 0)
StringCchPrintf(contents,64,L"%s: %s",WASABI_API_LNGSTRINGW(IDS_CONTAINS), buf);
else if (i == 1)
StringCchPrintf(contents,64,L"%s: %s",WASABI_API_LNGSTRINGW(IDS_CONTAINS), cont[0]);
else if (i == 2)
StringCchPrintf(contents,64,L"%s: %s, %s",WASABI_API_LNGSTRINGW(IDS_CONTAINS), cont[0], cont[1]);
else if (i == 3)
StringCchPrintf(contents,64,L"%s: %s, %s, %s",WASABI_API_LNGSTRINGW(IDS_CONTAINS), cont[0], cont[1], cont[2]);
else if (i == 4)
StringCchPrintf(contents,64,L"%s: %s, %s, %s, %s",WASABI_API_LNGSTRINGW(IDS_CONTAINS), cont[0], cont[1], cont[2], cont[3]);
// compose our string together!
StringCchPrintf(dest,destlen,L"%s%s%s%s%s%s%s%s%s%s%s",codec, duration, bitrate, filesize, wmver, seekable, stridable, broadcast, protect, trusted, contents);
}
else
return 0;
return 1;
}
#if 0 // had to disable this because it was locking the file from being deleted
WMInformation *lastGetInfo = 0;
wchar_t *lastGetInfoFn;
#endif
extern "C" __declspec(dllexport)
int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, int destlen)
{
/* Check if there's a status message for this filename
doing this forces Winamp to hit plugin.getfileinfo, which gives us better control
over adding things like [Individualizing] to the playlist title for local files
*/
if (winamp.HasStatus(fn))
return 0;
if ((!fn || !*fn) && KeywordMatch(data, "type"))
{
if (config_no_video)
lstrcpyn(dest, L"0", destlen);
else
lstrcpyn(dest, L"1", destlen);
return 1;
}
if (KeywordMatch(data, "mime"))
{
int len;
const wchar_t *p;
if (!fn || !fn[0]) return 0;
len = lstrlenW(fn);
if (len < 4 || L'.' != fn[len - 4]) return 0;
p = &fn[len - 3];
if (!_wcsicmp(p, L"WMA")) { StringCchCopyW(dest, destlen, L"audio/x-ms-wma"); return 1; }
if (!_wcsicmp(p, L"WMV")) { StringCchCopyW(dest, destlen, L"video/x-ms-wmv"); return 1; }
if (!_wcsicmp(p, L"ASF")) { StringCchCopyW(dest, destlen, L"video/x-ms-asf"); return 1; }
return 0;
}
if (KeywordMatch(data, "family"))
{
LPCWSTR e, p(NULL);
DWORD lcid;
size_t i;
int len2(0);
if (!fn || !*fn) return 0;
e = PathFindExtensionW(fn);
if (L'.' != *e) return 0;
e++;
if (!*e) return 0;
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
for (i = 0; i < fileTypes.types.size() && !p; i++)
{
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, e, -1, fileTypes.types.at(i).wtype, -1))
p = fileTypes.types.at(i).description;
}
if (p)
{
wchar_t szTest[16];
if (S_OK == StringCchPrintfW(szTest, sizeof(szTest)/sizeof(wchar_t), L" (*.%s)", e))
{
int len1 = lstrlenW(szTest);
len2 = lstrlenW(p);
if (len2 > len1 && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, szTest, -1, (p + len2 - len1), -1))
len2 -= len1;
}
}
return (p && S_OK == StringCchCopyNW(dest, destlen, p, len2));
}
if (!config_http_metadata && PathIsURL(fn))
return 0;
if (KeywordMatch(data, "type") && !PathFileExistsW(fn))
{
switch (fileTypes.GetAVType(extension(fn)))
{
case FileType::AUDIO:
lstrcpyn(dest, L"0", destlen);
return 1;
case FileType::VIDEO:
lstrcpyn(dest, L"1", destlen);
return 1;
default:
return 0;
}
}
if (activePlaylist.IsMe(fn))
{
WMInformation getExtendedFileInfo(activePlaylist.GetFileName());
return GetExtendedInformation(&getExtendedFileInfo, fn, data, dest, destlen);
}
else
{
WMInformation getExtendedFileInfo(fn);
return GetExtendedInformation(&getExtendedFileInfo, fn, data, dest, destlen);
}
#if 0 // had to disable this because it was locking the file from being deleted
if (lastGetInfo && lastGetInfoFn && !_wcsicmp(fn, lastGetInfoFn))
{
return GetExtendedInformation(lastGetInfo, fn, data, dest, destlen);
}
delete lastGetInfo;
lastGetInfo=0;
free(lastGetInfoFn);
lastGetInfoFn=0;
if (activePlaylist.IsMe(fn))
lastGetInfoFn = _wcsdup(activePlaylist.GetFileName());
else
lastGetInfoFn = _wcsdup(fn);
lastGetInfo = new WMInformation(lastGetInfoFn);
if (lastGetInfo->ErrorOpening())
{
if (KeywordMatch(data, "type"))
{
switch (fileTypes.GetAVType(extension(fn)))
{
case FileType::AUDIO:
lstrcpyn(dest, L"0", destlen);
return 1;
case FileType::VIDEO:
lstrcpyn(dest, L"1", destlen);
return 1;
default:
return 0;
}
}
delete lastGetInfo;
lastGetInfo=0;
free(lastGetInfoFn);
lastGetInfoFn=0;
return 0;
}
return GetExtendedInformation(lastGetInfo, fn, data, dest, destlen);
#endif
}
extern "C" __declspec(dllexport) int winampClearExtendedFileInfoW(const wchar_t *fn)
{
// TODO: press stop if it's the currently playing file
WMInformation wmInfo(fn);
wmInfo.ClearAllAttributes();
wmInfo.Flush();
return 1;
}
extern "C" __declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *val)
{
// if (!lastSetInfoFilename.empty() && lastSetInfoFilename != fn)
// dosomething();
#if 0 // had to disable this because it was locking the file from being deleted
if (lastGetInfoFn && !_wcsicmp(lastGetInfoFn,fn))
{
delete lastGetInfo;
lastGetInfo=0;
free(lastGetInfoFn);
lastGetInfoFn=0;
}
#endif
if (!setFileInfo)
{
if (activePlaylist.IsMe(fn) && mod.playing)
{
forcedStop = true;
outTime = mod.GetOutputTime();
winamp.PressStop();
}
free(setFileInfoName);
setFileInfoName = _wcsdup(fn);
setFileInfo = new WMInformation(fn);
if (!setFileInfo->MakeWritable(fn))
return 0; // can't write
}
AutoWide tagNameW(data);
const wchar_t *tagName = GetAlias(tagNameW);
if (StartsWith(tagName, L"WM/"))
{
setFileInfo->SetAttribute(tagName, val);
return 1;
}
else if ((const wchar_t *)tagNameW != tagName) // if the tag was in the tag list
{
setFileInfo->SetAttribute(tagName, val);
return 1;
}
else if (KeywordMatch(data, "rating"))
{
int rating = _wtoi(val);
if (rating == 0)
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"",WMT_TYPE_DWORD);
else
{
switch(rating)
{
case 1:
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"1",WMT_TYPE_DWORD);
break;
case 2:
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"25",WMT_TYPE_DWORD);
break;
case 3:
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"50",WMT_TYPE_DWORD);
break;
case 4:
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"75",WMT_TYPE_DWORD);
break;
default:
setFileInfo->SetAttribute(L"WM/SharedUserRating", L"99",WMT_TYPE_DWORD);
break;
}
}
}
else if (KeywordMatch(data, "replaygain_track_gain")
|| KeywordMatch(data, "replaygain_track_peak")
|| KeywordMatch(data, "replaygain_album_gain")
|| KeywordMatch(data, "replaygain_album_peak"))
{
setFileInfo->SetAttribute(tagName, val);
return 1;
}
else if (KeywordMatch(data, "GracenoteFileID"))
{
setFileInfo->SetAttribute_BinString(L"GN/UniqueFileIdentifier", val);
return 1;
}
else if (KeywordMatch(data, "GracenoteExtData"))
{
setFileInfo->SetAttribute_BinString(L"GN/ExtData", val);
return 1;
}
// else if (KeywordMatch(data, "bitrate"))
//else if (KeywordMatch(data, "disc"))
// else if (KeywordMatch(data, "vbr"))
//else if (KeywordMatch(data, "srate"))
// else if (KeywordMatch(data, "length"))
return 0;
}
extern "C" __declspec(dllexport) int winampWriteExtendedFileInfo()
{
if (setFileInfo)
{
bool flushOK = setFileInfo->Flush();
delete setFileInfo;
setFileInfo = 0;
if (forcedStop)
{
mod.startAtMilliseconds = outTime;
winamp.PressPlay();
}
forcedStop=false;
if (flushOK)
return 1;
else
return 0;
}
return 0;
}
@@ -0,0 +1,240 @@
#include "main.h"
#include "ExtendedRead.h"
extern WM_MEDIA_TYPE *NewMediaType(IWMOutputMediaProps *props);
ExtendedReadStruct::ExtendedReadStruct() : buffer(0), reader(0), streamNum(0), bufferUsed(0), endOfFile(false), length(0)
{}
ExtendedReadStruct::ExtendedReadStruct(IWMSyncReader *_reader) : buffer(0), reader(0), streamNum(0), bufferUsed(0), endOfFile(false), length(0)
{
reader = _reader;
reader->AddRef();
}
#define CBCLASS ExtendedReadStruct
START_DISPATCH;
CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
END_DISPATCH;
ExtendedReadStruct::~ExtendedReadStruct()
{
if (reader)
{
reader->Close();
reader->Release();
}
if (buffer)
buffer->Release();
}
size_t ExtendedReadStruct::ReadAudio(void *_buffer, size_t len)
{
__int8 *dest = reinterpret_cast<__int8 *>(_buffer);
int bytesCopied = 0;
/*
while we still have bytes left
{
read a buffer
copy buffer to user passed buffer
if we have stuff left in the buffer, save it and return
if we hit EOF, return
}
*/
size_t frameSize = (BitSize()/8)*Channels();
len -= (len % frameSize); // only do whole frames
while (len)
{
if (buffer)
{
BYTE *bufferBytes;
DWORD bufferTotal;
buffer->GetBufferAndLength(&bufferBytes, &bufferTotal);
if (bufferUsed < bufferTotal)
{
size_t toCopy = min(bufferTotal - bufferUsed, len);
memcpy(dest, bufferBytes + bufferUsed, toCopy);
bufferUsed += toCopy;
len -= toCopy;
dest += toCopy;
bytesCopied += toCopy;
if (bufferUsed == bufferTotal)
{
bufferUsed = 0;
buffer->Release();
buffer = 0;
}
}
}
else if (!endOfFile)
{
QWORD sampleTime, duration;
DWORD flags;
DWORD outputNum;
WORD streamNum2;
HRESULT hr;
hr = reader->GetNextSample(streamNum, &buffer, &sampleTime, &duration, &flags, & outputNum, &streamNum2);
if (hr == NS_E_NO_MORE_SAMPLES)
endOfFile = true;
}
else
return bytesCopied;
}
return bytesCopied;
}
bool ExtendedReadStruct::Open(const wchar_t *filename)
{
//mod.InitWM();
if (!reader)
{
if (!SUCCEEDED(WMCreateSyncReader(NULL, 0, &reader)))
{
reader = 0;
return false;
}
}
if (SUCCEEDED(reader->Open(filename)))
{
return true;
}
else
{
reader->Release();
reader = 0;
return false;
}
}
bool ExtendedReadStruct::FindOutput(int bits, int channels)
{
DWORD numOutputs, output, format, numFormats;
IWMOutputMediaProps *formatProperties;
GUID mediaType;
DWORD audioOutputNum;
if (FAILED((reader->GetOutputCount(&numOutputs))))
return false;
for (output = 0;output < numOutputs;output++)
{
HRESULT hr;
DWORD speakerConfig;
switch (channels)
{
case 1:
speakerConfig = DSSPEAKER_MONO;
break;
case 2:
speakerConfig = DSSPEAKER_STEREO;
break;
case 0:
default:
speakerConfig = config_audio_num_channels; // TODO: force max channels?
}
hr = reader->SetOutputSetting(output, g_wszSpeakerConfig, WMT_TYPE_DWORD, (BYTE *) & speakerConfig, sizeof(speakerConfig));
assert(hr == S_OK);
BOOL discreteChannels = TRUE;
hr = reader->SetOutputSetting(output, g_wszEnableDiscreteOutput, WMT_TYPE_BOOL, (BYTE *) & discreteChannels , sizeof(discreteChannels));
assert(hr == S_OK);
if (FAILED(reader->GetOutputFormatCount(output, &numFormats)))
continue;
for (format = 0;format < numFormats;format++)
{
reader->GetOutputFormat(output, format, &formatProperties);
formatProperties->GetType(&mediaType);
if (mediaType != WMMEDIATYPE_Audio)
continue;
WM_MEDIA_TYPE *mediaType = NewMediaType(formatProperties);
if (mediaType->subtype == WMMEDIASUBTYPE_PCM)
{
if (bits)
{
WAVEFORMATEXTENSIBLE *waveFormat = (WAVEFORMATEXTENSIBLE *) mediaType->pbFormat;
if (waveFormat->Format.cbSize >= 22)
waveFormat->Samples.wValidBitsPerSample = bits;
waveFormat->Format.wBitsPerSample = bits;
waveFormat->Format.nBlockAlign = (waveFormat->Format.wBitsPerSample / 8) * waveFormat->Format.nChannels;
waveFormat->Format.nAvgBytesPerSec = waveFormat->Format.nSamplesPerSec * waveFormat->Format.nBlockAlign;
if (FAILED(formatProperties->SetMediaType(mediaType)))
{
// blah, just use the default settings then
delete[] mediaType;
mediaType = NewMediaType(formatProperties);
}
}
AudioFormat::Open(mediaType);
delete[] mediaType;
audioOutputNum = output;
reader->SetOutputProps(audioOutputNum, formatProperties);
reader->GetStreamNumberForOutput(audioOutputNum, &streamNum);
formatProperties->Release();
reader->SetReadStreamSamples(streamNum, FALSE);
IWMHeaderInfo *headerInfo = 0;
reader->QueryInterface(&headerInfo);
WMT_ATTR_DATATYPE type = WMT_TYPE_QWORD;
WORD byteLength = sizeof(QWORD);
WORD blah = 0;
headerInfo->GetAttributeByName(&blah, g_wszWMDuration, &type, (BYTE *)&length, &byteLength);
headerInfo->Release();
return true;
}
delete[] mediaType;
formatProperties->Release();
}
}
return false;
}
extern "C"
__declspec(dllexport) intptr_t winampGetExtendedRead_openW(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
{
ExtendedReadStruct *read = new ExtendedReadStruct;
if (read->Open(fn)
&& read->FindOutput(*bps, *nch))
{
*nch = read->Channels();
*bps = read->BitSize();
*srate = read->SampleRate();
__int64 bytespersec = ((*nch) * (*bps / 8) * (*srate));
__int64 s = (bytespersec * ((__int64)read->length)) / (__int64)(1000 * 10000);
*size = (int)s;
return reinterpret_cast<intptr_t>(read);
}
else
{
delete read;
return 0;
}
}
extern "C"
__declspec(dllexport) intptr_t winampGetExtendedRead_getData(intptr_t handle, char *dest, int len, int *killswitch)
{
ExtendedReadStruct *read = reinterpret_cast<ExtendedReadStruct *>(handle);
return read->ReadAudio(dest, len);
}
extern "C"
__declspec(dllexport) void winampGetExtendedRead_close(intptr_t handle)
{
ExtendedReadStruct *read = reinterpret_cast<ExtendedReadStruct *>(handle);
delete read;
}
@@ -0,0 +1,30 @@
#ifndef NULLSOFT_IN_WMVDRM_EXTENDEDREAD_H
#define NULLSOFT_IN_WMVDRM_EXTENDEDREAD_H
#include "AudioFormat.h"
#include "../Agave/DecodeFile/ifc_audiostream.h"
#include "main.h"
struct ExtendedReadStruct : public AudioFormat, public ifc_audiostream
{
public:
ExtendedReadStruct();
ExtendedReadStruct(IWMSyncReader *_reader);
~ExtendedReadStruct();
bool Open(const wchar_t *filename);
bool FindOutput(int bits, int channels);
size_t ReadAudio(void *buffer, size_t sizeBytes);
IWMSyncReader *reader;
WORD streamNum;
INSSBuffer *buffer;
size_t bufferUsed;
bool endOfFile;
QWORD length;
protected:
RECVS_DISPATCH;
};
#endif
@@ -0,0 +1,24 @@
#include "api.h"
#include <api/service/waservicefactory.h>
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if (plugin.service)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
api_t = (api_T *)factory->getInterface();
}
}
template <class api_T>
void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
{
if (plugin.service)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
factory->releaseInterface(api_t);
}
}
@@ -0,0 +1,831 @@
#include "Main.h"
#include "FileInfoDialog.h"
#include "WMInformation.h"
#include "resource.h"
#include "../nu/AutoChar.h"
#include "WMDRMModule.h"
#include "WMPlaylist.h"
// blah! commented out a load of shit because we can't have the advanced pane edit data cause wma sucks.
class Info
{
public:
Info(const wchar_t *filename);
~Info();
//bool Save(HWND parent);
int Error();
int GetNumMetadataItems();
void EnumMetadata(int n,wchar_t *key,int keylen, wchar_t *val, int vallen);
//void RemoveMetadata(wchar_t * key);
//void RemoveMetadata(int n);
//void SetMetadata(wchar_t *key, wchar_t *val);
//void SetMetadata(int n, wchar_t *key, wchar_t *val);
//void SetTag(int n,wchar_t *key); // changes the key name
private:
WMInformation wminfo;
const wchar_t *filename;
};
Info::Info(const wchar_t *filename) : wminfo(filename), filename(filename)
{
}
Info::~Info()
{
}
/*
bool Info::Save(HWND parent)
{
if (!wminfo.MakeWritable(filename))
{
wchar_t title[64] = {0};
if (activePlaylist.IsMe(filename) && mod.playing)
{
// TODO: this is a race condition. we might have stopped in between the above if () and now...
int outTime = mod.GetOutputTime();
winamp.PressStop();
wminfo.MakeWritable(filename);
SendMessage(parent,WM_USER+1,0,0);
//WriteEditBoxes();
wminfo.Flush();
wminfo.MakeReadOnly(filename);
mod.startAtMilliseconds=outTime;
winamp.PressPlay();
return true;
}
else if (!wminfo.MakeReadOnly(filename))
MessageBox(parent, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_WRITE_TO_FILE_DOES_FILE_EXIST),
WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_WRITE_TO_FILE,title,64), MB_OK);
else
MessageBox(parent, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_WRITE_TO_FILE_MAY_NOT_HAVE_ACCESS),
WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_WRITE_TO_FILE,title,64), MB_OK);
return false;
}
SendMessage(parent,WM_USER+1,0,0);
//WriteEditBoxes();
if (!wminfo.Flush())
{
wchar_t* title = WASABI_API_LNGSTRINGW(IDS_SAVE_FAILED);
MessageBox(NULL, title, title, MB_OK);
}
wminfo.MakeReadOnly(filename);
return true;
}
*/
int Info::Error()
{
return wminfo.ErrorOpening();
}
int Info::GetNumMetadataItems()
{
return wminfo.GetNumberAttributes();
}
void Info::EnumMetadata(int n,wchar_t *key,int keylen, wchar_t *val, int vallen)
{
if(keylen) key[0]=0;
if(vallen) val[0]=0;
wminfo.GetAttribute(n, key, keylen, val, vallen);
}
/*
void Info::RemoveMetadata(wchar_t * key)
{
wminfo.DeleteAttribute(key);
}
void Info::RemoveMetadata(int n)
{
wchar_t key[256] = {0};
EnumMetadata(n,key,256,NULL,0);
if(key[0])
RemoveMetadata(key);
}
void Info::SetMetadata(wchar_t *key, wchar_t *val)
{
wminfo.SetAttribute(key,val);
}
void Info::SetTag(int n, wchar_t *key)
{ // changes the key name
wchar_t val[2048]=L"";
wchar_t oldkey[256]=L"";
EnumMetadata(n,oldkey,256,val,2048);
RemoveMetadata(oldkey);
wminfo.SetAttribute(key,val);
}
*/
bool WMTagToWinampTag(wchar_t * tag, int len)
{
const wchar_t *f = GetAlias_rev(tag);
if(f)
{
lstrcpyn(tag,f,len);
return true;
}
return false;
}
bool WinampTagToWMTag(wchar_t * tag, int len)
{
const wchar_t *f = GetAlias(tag);
if(f)
{
lstrcpyn(tag,f,len);
return true;
}
return false;
}
static INT_PTR CALLBACK ChildProc_Advanced(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
static int ismychange=0;
switch(msg)
{
case WM_NOTIFYFORMAT:
return NFR_UNICODE;
case WM_INITDIALOG:
{
//SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
ListView_SetExtendedListViewStyle(hwndlist, LVS_EX_FULLROWSELECT);
LVCOLUMN lvc = {0, };
lvc.mask = LVCF_TEXT|LVCF_WIDTH;
lvc.pszText = WASABI_API_LNGSTRINGW(IDS_NAME);
lvc.cx = 82;
ListView_InsertColumn(hwndlist, 0, &lvc);
lvc.pszText = WASABI_API_LNGSTRINGW(IDS_VALUE);
lvc.cx = 160;
ListView_InsertColumn(hwndlist, 1, &lvc);
Info *info = (Info *)lParam;
int n = info->GetNumMetadataItems();
for(int i=0; i<n; i++) {
wchar_t key[512] = {0};
wchar_t value[2048] = {0};
info->EnumMetadata(i,key,512,value,2048);
if(key[0]) {
LVITEMW lvi={LVIF_TEXT,i,0};
lvi.pszText = key;
SendMessage(hwndlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
lvi.iSubItem=1;
lvi.pszText = value;
SendMessage(hwndlist,LVM_SETITEMW,0,(LPARAM)&lvi);
}
}
ListView_SetColumnWidth(hwndlist,0,LVSCW_AUTOSIZE);
ListView_SetColumnWidth(hwndlist,1,LVSCW_AUTOSIZE);
//SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
//SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
//EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
//EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
//EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
delete info;
}
break;
case WM_DESTROY:
{
HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
ListView_DeleteAllItems(hwndlist);
while(ListView_DeleteColumn(hwndlist,0));
Info * info = (Info*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
if(info) delete info;
}
break;
/*
case WM_USER+1:
{
Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
info->wminfo.ClearAllAttributes();
wchar_t key[100] = {0}, value[2048] = {0};
HWND hlist = GetDlgItem(hwndDlg,IDC_LIST);
int n = ListView_GetItemCount(hlist);
for(int i=0; i<n; i++)
{
key[0]=value[0]=0;
LVITEMW lvi={LVIF_TEXT,i,0};
lvi.pszText=key;
lvi.cchTextMax=100;
SendMessage(hlist,LVM_GETITEMW,0,(LPARAM)&lvi);
lvi.iSubItem = 1;
lvi.pszText = value;
lvi.cchTextMax=2048;
SendMessage(hlist,LVM_GETITEMW,0,(LPARAM)&lvi);
if(key[0])
info->SetMetadata(key,value);
}
}
break;
*/
case WM_USER:
if(wParam && lParam && !ismychange)
{
wchar_t * value = (wchar_t*)lParam;
wchar_t tag[100] = {0};
lstrcpynW(tag,(wchar_t*)wParam,100);
WinampTagToWMTag(tag,100);
/*
Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
if(!*value) info->RemoveMetadata(tag);
else info->SetMetadata(tag,value);
*/
HWND hlist = GetDlgItem(hwndDlg,IDC_LIST);
int n = ListView_GetItemCount(hlist);
for(int i=0; i<n; i++)
{
wchar_t key[100]=L"";
LVITEMW lvi={LVIF_TEXT,i,0};
lvi.pszText=key;
lvi.cchTextMax=100;
SendMessage(hlist,LVM_GETITEMW,0,(LPARAM)&lvi);
if(!_wcsicmp(key,tag))
{
lvi.iSubItem = 1;
lvi.pszText = value;
SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
if(!*value)
ListView_DeleteItem(hlist,i);
/*
else if(ListView_GetItemState(hlist,i,LVIS_SELECTED))
SetDlgItemTextW(hwndDlg,IDC_VALUE,value);
*/
return 0;
}
}
// bew hew, not found
LVITEMW lvi={0,0x7FFFFFF0,0};
n = SendMessage(hlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
lvi.mask = LVIF_TEXT;
lvi.iItem = n;
lvi.iSubItem = 0;
lvi.pszText = tag;
SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
lvi.iSubItem = 1;
lvi.pszText = value;
SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
}
break;
/*
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if(l->idFrom==IDC_LIST && l->code == LVN_ITEMCHANGED) {
LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam;
if(lv->uNewState & LVIS_SELECTED) {
int n = lv->iItem;
LVITEMW lvi={LVIF_TEXT,lv->iItem,0};
wchar_t key[100] = {0};
wchar_t value[1024] = {0};
lvi.pszText=key;
lvi.cchTextMax=100;
SendMessage(l->hwndFrom,LVM_GETITEMW,0,(LPARAM)&lvi);
lvi.pszText=value;
lvi.cchTextMax=1024;
lvi.iSubItem=1;
SendMessage(l->hwndFrom,LVM_GETITEMW,0,(LPARAM)&lvi);
SetDlgItemTextW(hwndDlg,IDC_NAME,key);
SetDlgItemTextW(hwndDlg,IDC_VALUE,value);
sel = n;
EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),TRUE);
EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),TRUE);
EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),TRUE);
}
if(lv->uOldState & LVIS_SELECTED) {
int n = lv->iItem;
sel = -1;
SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
}
}
}
break;
*/
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDOK:
{
//Info * info = (Info*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
//info->Save(hwndDlg);
}
break;
/*
case IDC_NAME:
case IDC_VALUE:
if(HIWORD(wParam) == EN_CHANGE && sel>=0) {
wchar_t key[100] = {0};
wchar_t value[1024] = {0};
LVITEMW lvi={LVIF_TEXT,sel,0};
GetDlgItemTextW(hwndDlg,IDC_NAME,key,100);
GetDlgItemTextW(hwndDlg,IDC_VALUE,value,1024);
lvi.pszText=key;
lvi.cchTextMax=100;
SendMessage(GetDlgItem(hwndDlg,IDC_LIST),LVM_SETITEMW,0,(LPARAM)&lvi);
lvi.pszText=value;
lvi.cchTextMax=1024;
lvi.iSubItem=1;
SendMessage(GetDlgItem(hwndDlg,IDC_LIST),LVM_SETITEMW,0,(LPARAM)&lvi);
WMTagToWinampTag(key,100);
ismychange=1;
SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)key,(WPARAM)value);
ismychange=0;
}
else if(HIWORD(wParam) == EN_KILLFOCUS && sel>=0) {
wchar_t key[100] = {0};
wchar_t value[1024] = {0};
GetDlgItemTextW(hwndDlg,IDC_NAME,key,100);
GetDlgItemTextW(hwndDlg,IDC_VALUE,value,1024);
Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
wchar_t oldkey[100]=L"";
bool newitem=true;
if(sel < info->GetNumMetadataItems()) {
info->EnumMetadata(sel,oldkey,100,0,0);
newitem=false;
}
if(!newitem && wcscmp(oldkey,key)) { // key changed
info->SetTag(sel,key);
} else {
info->SetMetadata(key,value);
}
WMTagToWinampTag(key,100);
ismychange=1;
SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)key,(WPARAM)value);
ismychange=0;
}
break;
case IDC_BUTTON_DEL:
if(sel >= 0) {
wchar_t tag[100] = {0};
GetDlgItemTextW(hwndDlg,IDC_NAME,tag,100);
SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
if(sel < info->GetNumMetadataItems())
info->RemoveMetadata(sel);
ListView_DeleteItem(GetDlgItem(hwndDlg,IDC_LIST),sel);
sel=-1;
WMTagToWinampTag(tag,100);
ismychange=1;
SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)tag,(WPARAM)L"");
ismychange=0;
}
break;
case IDC_BUTTON_DELALL:
ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_LIST));
SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
sel=-1;
{
Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
int n = info->GetNumMetadataItems();
while(n>0) {
--n;
wchar_t tag[100] = {0};
info->EnumMetadata(n,tag,100,0,0);
WMTagToWinampTag(tag,100);
ismychange=0;
SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)tag,(WPARAM)L"");
ismychange=1;
info->RemoveMetadata(n);
}
}
break;
case IDC_BUTTON_ADD:
{
HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
LVITEMW lvi={0,0x7FFFFFF0,0};
int n = SendMessage(hwndlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
ListView_SetItemState(hwndlist,n,LVIS_SELECTED,LVIS_SELECTED);
}
break;
*/
}
break;
}
return 0;
}
extern "C"
{
// return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
// if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")!
__declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn)
{
return 1;
}
// should return a child window of 513x271 pixels (341x164 in msvc dlg units), or return NULL for no tab.
// Fill in name (a buffer of namelen characters), this is the title of the tab (defaults to "Advanced").
// filename will be valid for the life of your window. n is the tab number. This function will first be
// called with n == 0, then n == 1 and so on until you return NULL (so you can add as many tabs as you like).
// The window you return will recieve WM_COMMAND, IDOK/IDCANCEL messages when the user clicks OK or Cancel.
// when the user edits a field which is duplicated in another pane, do a SendMessage(GetParent(hwnd),WM_USER,(WPARAM)L"fieldname",(LPARAM)L"newvalue");
// this will be broadcast to all panes (including yours) as a WM_USER.
__declspec(dllexport) HWND winampAddUnifiedFileInfoPane(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen)
{
if(n == 0) { // add first pane
//SetPropW(parent,L"INBUILT_NOWRITEINFO", (HANDLE)1);
Info *info = new Info(filename);
if(info->Error())
{
delete info;
return NULL;
}
return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO,parent,ChildProc_Advanced,(LPARAM)info);
}
return NULL;
}
};
/* CUT> we're now using the unified file info dlg. I'll leave this commented out incase we want to do an advanced tab later on.
#define CREATEDIALOGBOX DialogBoxParam
#define CLOSEDIALOGBOX(x) EndDialog(x, 0)
extern WMDRM mod;
enum
{
AttributeColumn = 0,
ValueColumn = 1,
};
void FileInfoDialog::FillAttributeList()
{
attributeList.Clear();
WORD attrCount = wmInfo->GetNumberAttributes();
wchar_t attrName[32768] = {0}, value[32768] = {0};
int pos=0;
for (WORD i = 0;i != attrCount;i++)
{
wmInfo->GetAttribute(i, attrName, 32768, value, 32768);
// if (!AttributeInStandardEditor(attrName.c_str()))
attributeList.InsertItem(pos, (wchar_t *)attrName, 0);
attributeList.SetItemText(pos, 1, (wchar_t *)value);
pos++;
}
attributeList.AutoColumnWidth(1);
}
void FileInfoDialog::FillEditBoxes()
{
wchar_t temp[32768] = {0};
wmInfo->GetAttribute(g_wszWMAuthor, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_ARTIST), temp);
wmInfo->GetAttribute(g_wszWMTitle, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_TITLE), temp);
wmInfo->GetAttribute(g_wszWMAlbumTitle, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_ALBUM), temp);
wmInfo->GetAttribute(g_wszWMDescription, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_COMMENTS), temp);
wmInfo->GetAttribute(g_wszWMGenre, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_GENRE), temp);
wmInfo->GetAttribute(g_wszWMYear, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_YEAR), temp);
wmInfo->GetAttribute(g_wszWMTrackNumber, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_TRACK), temp);
wmInfo->GetAttribute(g_wszWMPublisher, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_PUBLISHER), temp);
wmInfo->GetAttribute(g_wszWMAlbumArtist, temp, 32768);
SetWindowText(GetDlgItem(fileInfoHWND, IDC_EDIT_ALBUMARTIST), temp);
}
void FileInfoDialog::Init(HWND _hwnd)
{
fileInfoHWND = _hwnd;
attributeList.setwnd(GetDlgItem(fileInfoHWND, IDC_METADATALIST));
attributeList.AddCol(WASABI_API_LNGSTRINGW(IDS_ATTRIBUTE), 150);
attributeList.AddCol(WASABI_API_LNGSTRINGW(IDS_VALUE), 1);
attributeList.AutoColumnWidth(1);
if (fileNameToShow)
SetWindowText(GetDlgItem(fileInfoHWND, IDC_FILENAME), fileNameToShow);
else
SetWindowText(GetDlgItem(fileInfoHWND, IDC_FILENAME), fileName);
FillEditBoxes();
FillAttributeList();
if (wmInfo->NonWritable())
{
EnableWindow(GetDlgItem(fileInfoHWND, IDC_APPLY), FALSE);
EnableWindow(GetDlgItem(fileInfoHWND, IDC_REVERT), FALSE);
EnableWindow(GetDlgItem(fileInfoHWND, IDOK), FALSE);
SetDlgItemText(fileInfoHWND, IDCANCEL, WASABI_API_LNGSTRINGW(IDS_CLOSE));
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_TITLE), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_ARTIST), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_ALBUM), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_COMMENTS), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_GENRE), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_YEAR), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_TRACK), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_PUBLISHER), EM_SETREADONLY, TRUE, 0);
SendMessage(GetDlgItem(fileInfoHWND, IDC_EDIT_ALBUMARTIST), EM_SETREADONLY, TRUE, 0);
}
SetFocus(GetDlgItem(fileInfoHWND, IDCANCEL));
SendMessage(fileInfoHWND, DM_SETDEFID, GetDlgCtrlID(GetDlgItem(fileInfoHWND, IDCANCEL)),0);
}
void FileInfoDialog::Revert()
{
FillEditBoxes();
FillAttributeList();
}
BOOL FileInfoDialog::MetadataList_Notify(NMHDR *header)
{
switch (header->code)
{
case LVN_ITEMCHANGED:
{
LPNMLISTVIEW lvNotif = (LPNMLISTVIEW)header;
if ((lvNotif->uOldState & LVIS_SELECTED)
&& !(lvNotif->uNewState & LVIS_SELECTED))
{
EnableWindow(GetDlgItem(fileInfoHWND, IDC_EDIT),0);
EnableWindow(GetDlgItem(fileInfoHWND, IDC_DELETE), 0);
}
if (lvNotif->uNewState & LVIS_SELECTED)
{
if (lvNotif->iItem != -1)
{
EnableWindow(GetDlgItem(fileInfoHWND, IDC_EDIT),1);
EnableWindow(GetDlgItem(fileInfoHWND, IDC_DELETE), 1);
}
}
}
break;
}
return 0;
}
bool FileInfoDialog::AttributeInStandardEditor(const wchar_t *attrName)
{
return (!wcscmp(attrName, g_wszWMTitle)
||!wcscmp(attrName, g_wszWMAuthor)
||!wcscmp(attrName, g_wszWMAlbumTitle)
||!wcscmp(attrName, g_wszWMDescription)
||!wcscmp(attrName, g_wszWMGenre)
||!wcscmp(attrName, g_wszWMYear)
||!wcscmp(attrName, g_wszWMTrackNumber)
||!wcscmp(attrName, g_wszWMPublisher)
|| !wcscmp(attrName, g_wszWMAlbumArtist));
}
void FileInfoDialog::WriteEditBoxHelper(const wchar_t attrName[], DWORD IDC, wchar_t *&temp, int &size)
{
int thisSize = GetWindowTextLength(GetDlgItem(fileInfoHWND, IDC))+1;
if (thisSize && thisSize>size)
{
if (temp)
delete[] temp;
temp = new wchar_t[thisSize];
size=thisSize;
}
GetWindowText(GetDlgItem(fileInfoHWND, IDC), temp, size);
wmInfo->SetAttribute(attrName, temp);
}
void FileInfoDialog::WriteEditBoxes()
{
wchar_t *temp=0;
int thisSize=0;
int size=0;
WriteEditBoxHelper(g_wszWMTitle, IDC_EDIT_TITLE, temp, size);
WriteEditBoxHelper(g_wszWMAuthor, IDC_EDIT_ARTIST, temp, size);
WriteEditBoxHelper(g_wszWMAlbumTitle, IDC_EDIT_ALBUM, temp, size);
WriteEditBoxHelper(g_wszWMDescription, IDC_EDIT_COMMENTS, temp, size);
WriteEditBoxHelper(g_wszWMGenre, IDC_EDIT_GENRE, temp, size);
WriteEditBoxHelper(g_wszWMYear, IDC_EDIT_YEAR, temp, size);
WriteEditBoxHelper(g_wszWMTrackNumber, IDC_EDIT_TRACK, temp, size);
WriteEditBoxHelper(g_wszWMPublisher, IDC_EDIT_PUBLISHER, temp, size);
WriteEditBoxHelper(g_wszWMAlbumArtist, IDC_EDIT_ALBUMARTIST, temp, size);
}
void FileInfoDialog::WriteAttributeListA()
{
int attributeTextLength=0, valueTextLength=0;
char *attribute=0, *value=0;
size_t numAttrs = attributeList.GetCount();
for (size_t i=0;i!=numAttrs;i++)
{
int textLength;
textLength = attributeList.GetTextLength(i, 0);
if (textLength>attributeTextLength)
{
if (attribute)
delete[] attribute;
attribute = new char[textLength];
attributeTextLength=textLength;
}
attributeList.GetText(i, 0, attribute, attributeTextLength);
textLength = attributeList.GetTextLength(i, 0);
if (textLength>valueTextLength)
{
if (value)
delete[] value;
value = new char[textLength];
valueTextLength=textLength;
}
attributeList.GetText(i, 0, value, valueTextLength);
}
}
void FileInfoDialog::WriteAttributeList()
{
int attributeTextLength=0, valueTextLength=0;
wchar_t *attribute=0, *value=0;
size_t numAttrs = attributeList.GetCount();
for (size_t i=0;i!=numAttrs;i++)
{
int textLength;
textLength = attributeList.GetTextLength(i, 0);
if (textLength>attributeTextLength)
{
if (attribute)
delete[] attribute;
attribute = new wchar_t[textLength];
attributeTextLength=textLength;
}
attributeList.GetText(i, 0, attribute, attributeTextLength);
textLength = attributeList.GetTextLength(i, 0);
if (textLength>valueTextLength)
{
if (value)
delete[] value;
value = new wchar_t[textLength];
valueTextLength=textLength;
}
attributeList.GetText(i, 0, value, valueTextLength);
}
}
bool FileInfoDialog::Apply()
{
edited=true;
if (!wmInfo->MakeWritable(fileName))
{
wchar_t title[64] = {0};
if (activePlaylist.IsMe(fileName) && mod.playing)
{
// TODO: this is a race condition. we might have stopped in between the above if () and now...
int outTime = mod.GetOutputTime();
winamp.PressStop();
wmInfo->MakeWritable(fileName);
WriteEditBoxes();
wmInfo->Flush();
wmInfo->MakeReadOnly(fileName);
mod.startAtMilliseconds=outTime;
winamp.PressPlay();
return true;
}
else if (!wmInfo->MakeReadOnly(fileName))
MessageBox(fileInfoHWND, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_WRITE_TO_FILE_DOES_FILE_EXIST),
WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_WRITE_TO_FILE,title,64), MB_OK);
else
MessageBox(fileInfoHWND, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_WRITE_TO_FILE_MAY_NOT_HAVE_ACCESS),
WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_WRITE_TO_FILE,title,64), MB_OK);
return false;
}
WriteEditBoxes();
if (!wmInfo->Flush())
{
wchar_t* title = WASABI_API_LNGSTRINGW(IDS_SAVE_FAILED);
MessageBox(NULL, title, title, MB_OK);
}
wmInfo->MakeReadOnly(fileName);
return true;
}
BOOL FileInfoDialog::OnOk()
{
if (Apply())
CLOSEDIALOGBOX(fileInfoHWND);
return 0;
}
BOOL FileInfoDialog::OnCancel()
{
CLOSEDIALOGBOX(fileInfoHWND);
return 0;
}
INT_PTR WINAPI FileInfoDialog::FileInfoProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
FileInfoDialog *fileInfoDialog = (FileInfoDialog *)GetWindowLongPtr(wnd, GWLP_USERDATA);
switch (msg)
{
case WM_NOTIFYFORMAT:
return NFR_UNICODE;
case WM_NOTIFY:
{
LPNMHDR l = (LPNMHDR)lp;
if (l->hwndFrom == GetDlgItem(wnd, IDC_METADATALIST))
return fileInfoDialog->MetadataList_Notify(l);
}
break;
case WM_INITDIALOG:
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)lp);
fileInfoDialog = (FileInfoDialog *)lp;
fileInfoDialog->Init(wnd);
return FALSE;
case WM_DESTROY:
if (fileInfoDialog)
{
//delete fileInfoDialog;
//fileInfoDialog=0;
SetWindowLongPtr(wnd, GWLP_USERDATA, 0);
}
break;
case WM_COMMAND:
switch (LOWORD(wp))
{
case IDC_REVERT:
fileInfoDialog->Revert();
break;
case IDCANCEL:
return fileInfoDialog->OnCancel();
break;
case IDOK:
return fileInfoDialog->OnOk();
break;
case IDC_APPLY:
fileInfoDialog->Apply();
break;
}
break;
}
return 0;
}
FileInfoDialog::FileInfoDialog(HINSTANCE _hInstance, HWND parent,const wchar_t *_fileName)
: wmInfo(0),hInstance(_hInstance),fileName(0),fileNameToShow(0), edited(false)
{
if (activePlaylist.IsMe(_fileName))
{
fileName = _wcsdup(activePlaylist.GetFileName());
fileNameToShow = _wcsdup(_fileName);
}
else
fileName = _wcsdup(_fileName);
wmInfo = new WMInformation(fileName);
CREATEDIALOGBOX(hInstance, MAKEINTRESOURCE(IDD_FILEINFO), parent, FileInfoProc, (LPARAM)this);
}
FileInfoDialog::~FileInfoDialog()
{
delete wmInfo;
wmInfo=0;
free(fileName);
free(fileNameToShow);
}
bool FileInfoDialog::WasEdited()
{
return edited;
}
*/
@@ -0,0 +1,41 @@
#ifndef NULLSOFT_FILEINFODIALOGH
#define NULLSOFT_FILEINFODIALOGH
#include "../nu/listview.h"
#include "WMInformation.h"
/* CUT> we're now using the unified file info dlg. I'll leave this commented out incase we want to do an advanced tab later on.
class FileInfoDialog
{
public:
FileInfoDialog(HINSTANCE _hInstance, HWND parent, const wchar_t *fileName);
~FileInfoDialog();
void Init(HWND _hwnd);
static INT_PTR WINAPI FileInfoProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
BOOL MetadataList_Notify(NMHDR *header);
BOOL Edit_Notify(NMHDR *header);
BOOL OnOk();
BOOL OnCancel();
bool WasEdited();
private:
void FillAttributeList();
void WriteAttributeList();
void WriteAttributeListA();
void FillEditBoxes();
void WriteEditBoxes();
bool Apply();
void Revert();
void FileInfoDialog::WriteEditBoxHelper(const wchar_t attrName[], DWORD IDC, wchar_t *&temp, int &size);
bool AttributeInStandardEditor(const wchar_t *attrName);
HWND fileInfoHWND;
WMInformation *wmInfo;
W_ListView attributeList;
HINSTANCE hInstance;
wchar_t *fileName;
wchar_t *fileNameToShow;
bool edited;
};
*/
#endif
+179
View File
@@ -0,0 +1,179 @@
#include "main.h"
#include "FileTypes.h"
#include "Config.h"
#include "../nu/Config.h"
#include "resource.h"
#include <strsafe.h>
FileTypes fileTypes;
extern Nullsoft::Utility::Config wmConfig;
bool FileTypes::IsSupportedURL(const wchar_t *fn)
{
Nullsoft::Utility::AutoLock lock(typeGuard);
TypeList::iterator itr;
for (itr=types.begin();itr!=types.end();itr++)
{
if (itr->isProtocol && !_wcsnicmp(fn, itr->type, wcslen(itr->type)))
return true;
}
return false;
}
bool FileTypes::IsDefault()
{
return true;
}
void FileTypes::LoadDefaults()
{
Nullsoft::Utility::AutoLock lock(typeGuard);
types.clear();
types.push_back(FileType(L"WMA", WASABI_API_LNGSTRINGW(IDS_WMA_AUDIO_FILE), false, FileType::AUDIO));
if (!config_no_video)
{
types.push_back(FileType(L"WMV", WASABI_API_LNGSTRINGW(IDS_WMA_VIDEO_FILE), false, FileType::VIDEO));
types.push_back(FileType(L"ASF", WASABI_API_LNGSTRINGW(IDS_ASF_STREAM), false, FileType::VIDEO));
}
types.push_back(FileType(L"MMS://", WASABI_API_LNGSTRINGW(IDS_WINDOWS_MEDIA_STREAM), true, FileType::VIDEO));
types.push_back(FileType(L"MMSU://", WASABI_API_LNGSTRINGW(IDS_WINDOWS_MEDIA_STREAM), true, FileType::VIDEO));
types.push_back(FileType(L"MMST://", WASABI_API_LNGSTRINGW(IDS_WINDOWS_MEDIA_STREAM), true, FileType::VIDEO));
}
void FileTypes::ReadConfig()
{
Nullsoft::Utility::AutoLock lock(typeGuard);
int numTypes = wmConfig.cfg_int(L"numtypes", -1);
if (numTypes!=-1)
{
for (size_t i=0;i!=numTypes;i++)
{
wchar_t type[1024] = {0}, description[1024] = {0}, temp[64] = {0};
StringCchPrintf(temp, 64, L"type%u", i);
wmConfig.cfg_str(temp).GetString(type, 1024);
StringCchPrintf(temp, 64, L"description%u", i);
wmConfig.cfg_str(temp).GetString(description, 1024);
StringCchPrintf(temp, 64, L"protocol%u", i);
bool protocol = !!wmConfig.cfg_int(temp, 0);
StringCchPrintf(temp, 64, L"avtype%u", i);
int avtype = !!wmConfig.cfg_int(temp, 0);
if (!(config_no_video && !protocol && avtype==FileType::VIDEO)) // if we havn't explicity disabled video support
types.push_back(FileType(type, description, protocol, avtype));
}
}
else
fileTypes.LoadDefaults();
ResetTypes();
numTypes=types.size();
for (size_t i=0;i!=numTypes;i++)
{
if (!types[i].isProtocol)
AddType(AutoChar(types[i].type), AutoChar(types[i].description));
}
CheckVideo();
}
void FileTypes::SetTypes(TypeList &newTypes)
{
Nullsoft::Utility::AutoLock lock(typeGuard);
types=newTypes;
ResetTypes();
int numTypes=types.size();
for (size_t i=0;i!=numTypes;i++)
{
if (!types[i].isProtocol)
AddType(AutoChar(types[i].type), AutoChar(types[i].description));
}
CheckVideo();
}
void FileTypes::SaveConfig()
{
Nullsoft::Utility::AutoLock lock(typeGuard);
wmConfig.cfg_int(L"numtypes", -1) = types.size();
for (size_t i=0;i!=types.size();i++)
{
wchar_t temp[64] = {0};
StringCchPrintf(temp, 64, L"type%u", i);
wmConfig.cfg_str(temp) = types[i].wtype;
StringCchPrintf(temp, 64, L"description%u", i);
wmConfig.cfg_str(temp) = types[i].description;
StringCchPrintf(temp, 64, L"protocol%u", i);
wmConfig.cfg_int(temp, 0) = types[i].isProtocol;
StringCchPrintf(temp, 64, L"avtype%u", i);
wmConfig.cfg_int(temp, 0) = types[i].avType;
}
}
void FileTypes::CheckVideo()
{
bool videoPresent=false;
Nullsoft::Utility::AutoLock lock(typeGuard);
//wmConfig.cfg_int(L"numtypes", -1) = types.size();
for (size_t i=0;i!=types.size();i++)
if (types[i].avType == FileType::VIDEO)
videoPresent=true;
config_no_video = !videoPresent;
}
void FileTypes::ResetTypes()
{
free(typesString);
typesString=0;
}
void FileTypes::AddType(const char *extension, const char *description)
{
size_t oldSize=0, size=0;
if (typesString)
{
char *temp=typesString;
while (temp && *temp++)
{
size++;
if (*temp == 0)
{
size++;
temp++;
}
} ;
oldSize=size;
}
size += lstrlenA(extension)+1;
size += lstrlenA(description)+1;
char *newTypes = (char *)calloc(size+1, sizeof(char));
if (newTypes)
{
memcpy(newTypes, typesString, oldSize);
free(typesString);
typesString=newTypes;
newTypes += oldSize;
size-=oldSize;
StringCchCopyA(newTypes, size, extension);
int extSize = lstrlenA(extension)+1;
newTypes+=extSize;
size-=extSize;
StringCchCopyA(newTypes, size, description);
newTypes+=lstrlenA(description)+1;
*newTypes=0;
plugin.FileExtensions = typesString;
}
}
int FileTypes::GetAVType(const wchar_t *ext)
{
Nullsoft::Utility::AutoLock lock(typeGuard);
for (size_t i=0;i!=types.size();i++)
{
if (!types[i].isProtocol && !lstrcmpi(types[i].type, ext))
return types[i].avType;
}
return -1;
}
+88
View File
@@ -0,0 +1,88 @@
#ifndef NULLSOFT_FILETYPESH
#define NULLSOFT_FILETYPESH
#include <vector>
#include "../nu/AutoLock.h"
#include "AutoChar.h"
class FileType
{
public:
enum
{
AUDIO = 0,
VIDEO = 1,
};
FileType() : wtype(0), type(0), description(0), isProtocol(false), avType(AUDIO)
{
}
FileType(wchar_t *_type, wchar_t *_description, bool _protocol, int _avType)
{
wtype=_wcsdup(_type);
type = _wcsdup(_type);
description = _wcsdup(_description);
isProtocol = _protocol;
avType = _avType;
}
~FileType()
{
free(type);
free(wtype);
free(description);
}
FileType(const FileType &copy) :wtype(0), type(0), description(0)
{
operator =(copy);
}
void operator =(const FileType &copy)
{
if (copy.wtype)
wtype=_wcsdup(copy.wtype);
if (copy.type)
type = _wcsdup(copy.type);
if (copy.description)
description = _wcsdup(copy.description);
isProtocol = copy.isProtocol;
avType = copy.avType;
}
wchar_t *type;
wchar_t *wtype;
wchar_t *description;
bool isProtocol;
int avType; // audio or video
};
class FileTypes
{
public:
FileTypes()
: typesString(0),
typeGuard(GUARDNAME("FileTypes::typeGuard"))
{}
~FileTypes()
{
free(typesString);
typesString=0;
}
int GetAVType(const wchar_t *ext);
bool IsSupportedURL(const wchar_t *fn);
bool IsDefault();
void LoadDefaults();
void ReadConfig();
void SaveConfig();
void CheckVideo();
typedef std::vector<FileType> TypeList;
void SetTypes(TypeList &newTypes);
TypeList types;
Nullsoft::Utility::LockGuard typeGuard;
private:
char *typesString;
void ResetTypes();
void AddType(const char *type, const char *description);
};
extern FileTypes fileTypes;
#endif
+232
View File
@@ -0,0 +1,232 @@
#include "main.h"
#include "GainLayer.h"
#include <malloc.h>
#include <math.h>
#include <locale.h>
#include "api.h"
static void FillFloat(float *floatBuf, void *samples, size_t bps, size_t numSamples, size_t numChannels, float preamp)
{
switch (bps)
{
case 8:
{
unsigned __int8 *samples8 = (unsigned __int8 *)samples;
size_t totalSamples = numSamples * numChannels;
for (size_t x = 0; x != totalSamples; x ++)
{
floatBuf[x] = (float)(samples8[x] - 128) * preamp;
}
}
break;
case 16:
{
short *samples16 = (short *)samples;
size_t totalSamples = numSamples * numChannels;
for (size_t x = 0; x != totalSamples; x ++)
{
floatBuf[x] = (float)samples16[x] * preamp;
}
}
break;
case 24:
{
unsigned __int8 *samples8 = (unsigned __int8 *)samples;
size_t totalSamples = numSamples * numChannels;
for (size_t x = 0; x != totalSamples; x ++)
{
long temp = (((long)samples8[0]) << 8);
temp = temp | (((long)samples8[1]) << 16);
temp = temp | (((long)samples8[2]) << 24);
floatBuf[x] = (float)temp * preamp;
samples8 += 3;
}
}
break;
}
}
inline static float fastclip(float x, const float a, const float b)
{
float x1 = (float)fabs (x - a);
float x2 = (float)fabs (x - b);
x = x1 + (a + b);
x -= x2;
x *= 0.5f;
return (x);
}
#define PA_CLIP_( val, min, max )\
{ val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
void Float32_To_Int16_Clip(
void *destinationBuffer, signed int destinationStride,
void *sourceBuffer, signed int sourceStride,
unsigned int count)
{
float *src = (float*)sourceBuffer;
signed short *dest = (signed short*)destinationBuffer;
while ( count-- )
{
long samp = lrint(*src);
PA_CLIP_( samp, -0x8000, 0x7FFF );
*dest = (signed short) samp;
src += sourceStride;
dest += destinationStride;
}
}
inline static void clip(double &x, double a, double b)
{
double x1 = fabs (x - a);
double x2 = fabs (x - b);
x = x1 + (a + b);
x -= x2;
x *= 0.5;
}
void Float32_To_Int24_Clip(
void *destinationBuffer, signed int destinationStride,
void *sourceBuffer, signed int sourceStride,
unsigned int count)
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
while ( count-- )
{
/* convert to 32 bit and drop the low 8 bits */
double scaled = *src;
clip( scaled, -2147483648., 2147483647. );
signed long temp = (signed long) scaled;
dest[0] = (unsigned char)(temp >> 8);
dest[1] = (unsigned char)(temp >> 16);
dest[2] = (unsigned char)(temp >> 24);
src += sourceStride;
dest += destinationStride * 3;
}
}
static void FillSamples(void *samples, float *floatBuf, size_t bps, size_t numSamples, size_t numChannels)
{
switch (bps)
{
case 16:
Float32_To_Int16_Clip(samples, 1, floatBuf, 1, numSamples*numChannels);
break;
case 24:
Float32_To_Int24_Clip(samples, 1, floatBuf, 1, numSamples*numChannels);
break;
}
}
float GetGain(WMInformation *info, bool allowDefault)
{
if (AGAVE_API_CONFIG && AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false))
{
float dB = 0, peak = 1.0f;
wchar_t gain[64]=L"", peakVal[64]=L"";
switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0))
{
case 0: // track
info->GetAttribute(L"replaygain_track_gain", gain, 64);
if (!gain[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
info->GetAttribute(L"replaygain_album_gain", gain, 64);
info->GetAttribute(L"replaygain_track_peak", peakVal, 64);
if (!peakVal[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
info->GetAttribute(L"replaygain_album_peak", peakVal, 64);
break;
case 1:
info->GetAttribute(L"replaygain_album_gain", gain, 64);
if (!gain[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
info->GetAttribute(L"replaygain_track_gain", gain, 64);
info->GetAttribute(L"replaygain_album_peak", peakVal, 64);
if (!peakVal[0] && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
info->GetAttribute(L"replaygain_track_peak", peakVal, 64);
break;
}
_locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
if (gain[0])
{
if (gain[0] == L'+')
dB = static_cast<float>(_wtof_l(&gain[1],C_locale));
else
dB = static_cast<float>(_wtof_l(gain,C_locale));
}
else if (allowDefault)
{
dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
return powf(10.0f, dB / 20.0f);
}
if (peakVal[0])
{
peak = static_cast<float>(_wtof_l(peakVal,C_locale));
}
switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_mode", 1))
{
case 0: // apply gain
return powf(10.0f, dB / 20.0f);
case 1: // apply gain, but don't clip
return min(powf(10.0f, dB / 20.0f), 1.0f / peak);
case 2: // normalize
return 1.0f / peak;
case 3: // prevent clipping
if (peak > 1.0f)
return 1.0f / peak;
else
return 1.0f;
}
}
return 1.0f; // no gain
}
void GainLayer::AudioDataReceived(void *_data, unsigned long sizeBytes, DWORD timestamp)
{
if (enabled)
{
size_t samples = audio->AudioBytesToSamples(sizeBytes);
int channels = audio->Channels();
if (floatSize < (samples * channels))
{
delete [] floatData;
floatSize = samples * channels;
floatData = new float[floatSize];
}
if (outSize < sizeBytes)
{
delete [] outData;
outSize=sizeBytes;
outData = (void *)new __int8[sizeBytes];
}
FillFloat(floatData, _data, audio->BitSize(), samples , channels, replayGain);
FillSamples(outData, floatData, audio->BitSize(), samples , channels);
WMHandler::AudioDataReceived(outData, sizeBytes, timestamp);
}
else
WMHandler::AudioDataReceived(_data, sizeBytes, timestamp);
}
void GainLayer::Opened()
{
enabled= (AGAVE_API_CONFIG && AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false));
if (enabled)
replayGain = GetGain(info, true);
WMHandler::Opened();
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef NULLSOFT_GAIN_LAYER_H
#define NULLSOFT_GAIN_LAYER_H
#include "WMHandler.h"
#include "AudioFormat.h"
#include "WMInformation.h"
class GainLayer : public WMHandler
{
public:
GainLayer(AudioFormat *_audio, WMInformation *_info)
: audio(_audio), info(_info), enabled(false), replayGain(1.0f),
floatData(0),floatSize(0), outData(0), outSize(0)
{}
~GainLayer()
{
delete[]floatData;
delete[]outData;
}
void AudioDataReceived(void *_data, unsigned long sizeBytes, DWORD timestamp);
void Opened();
AudioFormat *audio;
WMInformation *info;
bool enabled;
float replayGain;
float *floatData;
size_t floatSize;
void *outData;
size_t outSize;
};
#endif
+52
View File
@@ -0,0 +1,52 @@
#ifndef NULLSOFT_MAINH
#define NULLSOFT_MAINH
#define WMDRM_VERSION L"3.95"
#include "WinampInterface.h"
#include "../Winamp/in2.h"
#include <windows.h>
#include "WMDRMModule.h"
#include <shlwapi.h>
#include <wmsdk.h>
#include "config.h"
#include "WMHandler.h"
#include "util.h"
#include "FileTypes.h"
#include "TagAlias.h"
#include "WMInformation.h"
#include "../nu/AutoWide.h"
#include "../nu/AutoChar.h"
#include "vidutils.h"
#include "api.h"
extern WMInformation *setFileInfo;
struct IDispatch;
extern IDispatch *winampExternal;
extern WinampInterface winamp;
extern In_Module plugin;
extern WMDRM mod;
#ifdef _DEBUG
#define SHOW_CALLBACKS
#endif
//#define SHOW_CALLBACKS
#ifdef SHOW_CALLBACKS
#include <iostream>
#define WMTCASE(sw) case sw: std::cerr << #sw << std::endl;
#define WMT_SHOW_HR_CODE(hr) std::cerr << HRErrorCode(hr) << std::endl;
#else
#define WMTCASE(sw) case sw:
#define WMT_SHOW_HR_CODE(hr)
#endif
// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
static const GUID playbackConfigGroupGUID =
{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
#endif
+110
View File
@@ -0,0 +1,110 @@
#include "main.h"
#include "MediaThread.h"
#include "config.h"
MediaThread::MediaThread() : wait(INFINITE), thread(0)
{
killEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
stopped = CreateEvent(NULL, TRUE, TRUE, NULL);
bufferFreed = CreateEvent(NULL, TRUE, TRUE, NULL);
}
MediaThread::~MediaThread()
{
Kill();
if (thread)
CloseHandle(thread);
}
VOID CALLBACK MediaThread_StartAPC(ULONG_PTR param)
{
reinterpret_cast<MediaThread *>(param)->StartAPC();
}
void MediaThread::StartAPC()
{
wait=config_video_jitter;
}
void MediaThread::StopAPC()
{
BufferList::iterator itr;
for (itr = buffers.begin();itr != buffers.end();itr++)
{
(*itr)->buffer->Release();
delete (*itr);
}
buffers.clear();
SetEvent(stopped);
SetEvent(bufferFreed);
wait=INFINITE;
}
static VOID CALLBACK MediaThread_StopAPC(ULONG_PTR param)
{
reinterpret_cast<MediaThread *>(param)->StopAPC();
}
void MediaThread::Stop()
{
ResetEvent(stopped);
QueueUserAPC(MediaThread_StopAPC, thread, reinterpret_cast<ULONG_PTR>(this));
WaitForSingleObject(stopped, INFINITE);
}
void MediaThread::WaitForStop()
{
WaitForSingleObject(stopped, INFINITE);
}
void MediaThread::SignalStop()
{
ResetEvent(stopped);
QueueUserAPC(MediaThread_StopAPC, thread, reinterpret_cast<ULONG_PTR>(this));
}
void MediaThread::Kill()
{
SetEvent(killEvent);
WaitForSingleObject(stopped, INFINITE);
}
void MediaThread::OrderedInsert(MediaBuffer *buffer)
{
BufferList::iterator itr;
for (itr = buffers.begin();itr != buffers.end(); itr++)
{
if ((*itr)->timestamp > buffer->timestamp)
{
buffers.insert(itr, buffer);
break;
}
}
if (itr == buffers.end())
buffers.push_back(buffer);
}
VOID CALLBACK MediaThread_AddAPC(ULONG_PTR param)
{
MediaBufferAPC *apc = reinterpret_cast<MediaBufferAPC *>(param);
apc->thread->AddAPC(apc->buffer);
delete apc;
}
bool MediaThread::AddBuffer(INSSBuffer *buff, QWORD ts, unsigned long flags, bool drmProtected)
{
if (WaitForSingleObject(bufferFreed, 0) == WAIT_TIMEOUT)
return false;
buff->AddRef();
MediaBuffer *buffer = new MediaBuffer(buff, ts, flags, drmProtected);
MediaBufferAPC *apc = new MediaBufferAPC;
apc->buffer = buffer;
apc->thread = this;
QueueUserAPC(MediaThread_AddAPC, thread, reinterpret_cast<ULONG_PTR>(apc));
Sleep(config_video_jitter); // sleep for a bit to keep the thread from going nuts
return true; // added
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef NULLSOFT_MEDIATHREADH
#define NULLSOFT_MEDIATHREADH
#include <deque>
#include <wmsdk.h>
#include <vector>
VOID CALLBACK MediaThread_StartAPC(ULONG_PTR param);
VOID CALLBACK MediaThread_AddAPC(ULONG_PTR param);
struct MediaBuffer
{
MediaBuffer(INSSBuffer *b, QWORD t, unsigned long f, bool d) : buffer(b), timestamp(t), flags(f), drmProtected(d) {}
INSSBuffer *buffer;
QWORD timestamp;
unsigned long flags;
bool drmProtected;
};
struct MediaBufferAPC;
class MediaThread
{
public:
MediaThread();
~MediaThread();
bool AddBuffer(INSSBuffer *buff, QWORD ts, unsigned long flags, bool drmProtected);
void Stop();
void SignalStop();
void WaitForStop();
void Kill();
public:
void StopAPC();
void StartAPC();
virtual void AddAPC(MediaBuffer *buffer)=0;
protected:
void OrderedInsert(MediaBuffer *buffer);
protected:
int wait;
HANDLE thread;
HANDLE killEvent, stopped, bufferFreed;
typedef std::vector<MediaBuffer*> BufferList;
BufferList buffers;
};
struct MediaBufferAPC
{
MediaBuffer *buffer;
MediaThread *thread;
};
#endif
+96
View File
@@ -0,0 +1,96 @@
#include "main.h"
#include "MetaTag.h"
#include "FileTypes.h"
#include "TagAlias.h"
ASFMetaTag::~ASFMetaTag()
{
delete info;
}
const wchar_t *ASFMetaTag::getName()
{
return L"ASF Metadata";
}
GUID ASFMetaTag::getGUID()
{
return getServiceGuid();
}
int ASFMetaTag::getFlags()
{
return METATAG_FILE_INFO;
}
int ASFMetaTag::isOurFile(const wchar_t *filename)
{
const wchar_t *ext = PathFindExtension(filename);
return !lstrcmpiW(ext, L".WMA")
|| !lstrcmpiW(ext, L".WMV")
|| !lstrcmpiW(ext, L".ASF");
}
int ASFMetaTag::metaTag_open(const wchar_t *filename)
{
info = new WMInformation(filename);
return METATAG_SUCCESS; // TODO: can we verify this?
}
void ASFMetaTag::metaTag_close()
{
delete this;
}
const wchar_t *ASFMetaTag::enumSupportedTag(int n, int *datatype)
{
return 0;
}
int ASFMetaTag::getTagSize(const wchar_t *tag, size_t *sizeBytes)
{
size_t size;
const wchar_t *tagName = GetAlias(tag);
if (info && info->GetAttributeSize(tagName, size))
{
*sizeBytes = size;
return METATAG_SUCCESS;
}
else
{
return METATAG_UNKNOWN_TAG;
}
}
int ASFMetaTag::getMetaData(const wchar_t *tag, __int8 *buf, int buflenBytes, int datatype)
{
const wchar_t *tagName = GetAlias(tag);
info->GetAttribute(tagName, reinterpret_cast<wchar_t *>(buf), buflenBytes / sizeof(wchar_t));
return METATAG_SUCCESS;
//return METATAG_FAILED;
}
int ASFMetaTag::setMetaData(const wchar_t *tag, const __int8 *buf, int buflenBytes, int datatype )
{
return METATAG_FAILED;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS ASFMetaTag
START_DISPATCH;
CB(SVC_METATAG_GETNAME,getName)
CB(SVC_METATAG_GETGUID,getGUID)
CB(SVC_METATAG_GETFLAGS,getFlags)
CB(SVC_METATAG_ISOURFILE,isOurFile)
CB(SVC_METATAG_OPEN,metaTag_open)
VCB(SVC_METATAG_CLOSE,metaTag_close)
CB(SVC_METATAG_ENUMTAGS,enumSupportedTag)
CB(SVC_METATAG_GETTAGSIZE,getTagSize)
CB(SVC_METATAG_GETMETADATA,getMetaData)
CB(SVC_METATAG_SETMETADATA,setMetaData)
END_DISPATCH;
+42
View File
@@ -0,0 +1,42 @@
#ifndef NULLSOFT_IN_WMVDRM_METATAG_H
#define NULLSOFT_IN_WMVDRM_METATAG_H
#include "../Agave/Metadata/svc_metatag.h"
#include "WMInformation.h"
// {8FF721E1-2FF4-4721-A7D5-60FDB32FEB1F}
static const GUID asfMetaTagGUID =
{ 0x8ff721e1, 0x2ff4, 0x4721, { 0xa7, 0xd5, 0x60, 0xfd, 0xb3, 0x2f, 0xeb, 0x1f } };
class ASFMetaTag : public svc_metaTag
{
public:
static const GUID getServiceGuid() { return asfMetaTagGUID; }
static const char *getServiceName() { return "ASF Metadata"; }
public:
ASFMetaTag() : info(0)
{
}
~ASFMetaTag();
/* These methods are to be used by api_metadata */
const wchar_t *getName(); // i.e. "ID3v2" or something
GUID getGUID(); // this needs to be the same GUID that you use when registering your service factory
int getFlags(); // how this service gets its info
int isOurFile(const wchar_t *filename);
int metaTag_open(const wchar_t *filename);
void metaTag_close(); // self-destructs when this is called (you don't need to call serviceFactory->releaseInterface)
/* user API starts here */
const wchar_t *enumSupportedTag(int n, int *datatype); // returns a list of understood tags. might not be complete (see note [1])
int getTagSize(const wchar_t *tag, size_t *sizeBytes); // always gives you BYTES, not characters (be careful with your strings)
int getMetaData(const wchar_t *tag, __int8 *buf, int buflenBytes, int datatype); // buflen is BYTES, not characters (be careful with your strings)
int setMetaData(const wchar_t *tag, const __int8 *buf, int buflenBytes, int datatype);
private:
WMInformation *info;
RECVS_DISPATCH;
};
#endif
@@ -0,0 +1,67 @@
#include "main.h"
#include "MetaTag.h"
#include "api.h"
#include "MetaTagFactory.h"
FOURCC MetaTagFactory::GetServiceType()
{
return WaSvc::METATAG;
}
const char *MetaTagFactory::GetServiceName()
{
return ASFMetaTag::getServiceName();
}
GUID MetaTagFactory::GetGUID()
{
return ASFMetaTag::getServiceGuid();
}
void *MetaTagFactory::GetInterface(int global_lock)
{
svc_metaTag *ifc= new ASFMetaTag;
// if (global_lock)
// plugin.service->service_lock(this, (void *)ifc);
return ifc;
}
int MetaTagFactory::SupportNonLockingInterface()
{
return 1;
}
int MetaTagFactory::ReleaseInterface(void *ifc)
{
//plugin.service->service_unlock(ifc);
svc_metaTag *metaTag = static_cast<svc_metaTag *>(ifc);
ASFMetaTag *asfMetaTag = static_cast<ASFMetaTag *>(metaTag);
delete asfMetaTag;
return 1;
}
const char *MetaTagFactory::GetTestString()
{
return NULL;
}
int MetaTagFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS MetaTagFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
@@ -0,0 +1,24 @@
#ifndef NULLSOFT_IN_WMVDRM_METATAGFACTORY_H
#define NULLSOFT_IN_WMVDRM_METATAGFACTORY_H
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class MetaTagFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
const char *GetServiceName();
GUID GetGUID();
void *GetInterface(int global_lock);
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
protected:
RECVS_DISPATCH;
};
#endif
+169
View File
@@ -0,0 +1,169 @@
#ifndef NULLSOFT_OUTPUTSTREAMH
#define NULLSOFT_OUTPUTSTREAMH
#include <wmsdk.h>
#define NULLSOFT_INTERFACE_BEGIN(RIID, OBJ) void **&NULLSOFT_interfaceHolder = OBJ; REFIID NULLSOFT_IID = RIID;
#define NULLSOFT_VALID_INTERFACE(a) if (NULLSOFT_IID == IID_ ## a) { *NULLSOFT_interfaceHolder = static_cast<a *>(this); return S_OK; }
#define NULLSOFT_INTERFACE_END() *NULLSOFT_interfaceHolder = 0; return E_NOINTERFACE;
class OutputStream : public IWMOutputMediaProps
{
public:
OutputStream(IWMMediaProps *props) : mediaType(0)
{
DWORD mediaTypeSize;
props->GetMediaType(0, &mediaTypeSize);
if (mediaTypeSize)
{
mediaType = (WM_MEDIA_TYPE *)new unsigned char[mediaTypeSize];
props->GetMediaType(mediaType, &mediaTypeSize);
}
}
~OutputStream()
{
if (mediaType)
{
delete mediaType;
mediaType = 0;
}
}
GUID &GetSubType() const
{
return mediaType->subtype;
}
WM_MEDIA_TYPE *mediaType;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
NULLSOFT_INTERFACE_BEGIN(riid, ppvObject)
NULLSOFT_VALID_INTERFACE(IWMOutputMediaProps);
NULLSOFT_VALID_INTERFACE(IWMMediaProps);
NULLSOFT_INTERFACE_END()
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 0;
}
ULONG STDMETHODCALLTYPE Release()
{
return 0;
}
HRESULT STDMETHODCALLTYPE GetType(GUID *pguidType)
{
if (!mediaType) return E_FAIL;
*pguidType = mediaType->majortype;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetMediaType(WM_MEDIA_TYPE *pType, DWORD *pcbType)
{
if (!mediaType) return E_FAIL;
if (!pType)
{
if (!pcbType) return E_INVALIDARG;
*pcbType = sizeof(WM_MEDIA_TYPE);
}
else
{
if (*pcbType < sizeof(WM_MEDIA_TYPE)) ASF_E_BUFFERTOOSMALL;
memcpy(pType, mediaType, sizeof(WM_MEDIA_TYPE));
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE SetMediaType(WM_MEDIA_TYPE *pType)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetStreamGroupName(WCHAR *pwszName, WORD *pcchName)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetConnectionName(WCHAR *pwszName, WORD *pcchName)
{
return E_NOTIMPL;
}
};
#include <uuids.h>
class VideoOutputStream : public OutputStream
{
public:
VideoOutputStream(IWMMediaProps *props) : OutputStream(props)
{}
WMVIDEOINFOHEADER *VideoInfo() const
{
return (WMVIDEOINFOHEADER *)mediaType->pbFormat;
}
int SourceWidth() const
{
return VideoInfo()->rcSource.right - VideoInfo()->rcSource.left;
}
int DestinationWidth() const
{
return VideoInfo()->rcTarget.right - VideoInfo()->rcTarget.left;
}
int DestinationHeight() const
{
return VideoInfo()->rcTarget.bottom - VideoInfo()->rcTarget.top;
}
bool Flipped() const
{
BITMAPINFOHEADER &info = VideoInfo()->bmiHeader;
if (info.biHeight < 0 || info.biCompression == 0)
return true;
else
return false;
}
int bmiHeight()
{
return VideoInfo()->bmiHeader.biYPelsPerMeter;
}
int bmiWidth()
{
return VideoInfo()->bmiHeader.biXPelsPerMeter;
}
RGBQUAD *CreatePalette()
{
RGBQUAD *palette = (RGBQUAD *)calloc(1, 1024);
BITMAPINFOHEADER &info = VideoInfo()->bmiHeader;
memcpy(palette, (char *)(&info) + 40, info.biClrUsed * 4);
return palette;
}
int FourCC() const
{
BITMAPINFOHEADER &info = VideoInfo()->bmiHeader;
int fourcc = info.biCompression;
if (fourcc == BI_RGB)
{
switch(info.biBitCount)
{
case 32:
fourcc='23GR'; // RG32
break;
case 24:
fourcc='42GR'; // RG24
break;
case 8:
fourcc='8BGR'; // RGB8
break;
}
} else if (fourcc == BI_BITFIELDS)
fourcc = 0; // TODO: calc a CC that winamp likes
return fourcc;
}
bool IsVideo() const
{
return !!(mediaType->formattype == WMFORMAT_VideoInfo);
}
};
#endif
@@ -0,0 +1,167 @@
#include "main.h"
#include "config.h"
#include "PlaylistHandler.h"
#include "WPLLoader.h"
#include "ASXLoader.h"
#include <shlwapi.h>
#include "resource.h"
void GetExtension(const wchar_t *filename, wchar_t *ext, size_t extCch)
{
const wchar_t *s = PathFindExtensionW(filename);
if (!PathIsURLW(filename)
|| (!wcsstr(s, L"?") && !wcsstr(s, L"&") && !wcsstr(s, L"=") && *s))
{
lstrcpynW(ext, s, extCch);
return ;
}
// s is not a terribly good extension, let's try again
{
wchar_t *copy = _wcsdup(filename);
s = L"";
again:
{
wchar_t *p = StrRChrW(copy,NULL, L'?');
if (p)
{
*p = 0;
s = PathFindExtensionW(copy);
if (!*s) goto again;
}
lstrcpynW(ext, s, extCch);
}
free(copy);
}
}
/* ---------------------------------- WPL --------------------------------------- */
const wchar_t *WPLHandler::enumExtensions(size_t n)
{
switch(n)
{
case 0:
return L"WPL";
/*case 1:
return L"ZPL";*/
default:
return 0;
}
}
int WPLHandler::SupportedFilename(const wchar_t *filename)
{
wchar_t ext[16] = {0};
GetExtension(filename, ext, 16);
if (!lstrcmpiW(ext, L".WPL") || !lstrcmpiW(ext, L".ZPL"))
return SVC_PLAYLISTHANDLER_SUCCESS;
// TODO: open file and sniff it for file signature
return SVC_PLAYLISTHANDLER_FAILED;
}
ifc_playlistloader *WPLHandler::CreateLoader(const wchar_t *filename)
{
return new WPLLoader;
}
void WPLHandler::ReleaseLoader(ifc_playlistloader *loader)
{
WPLLoader *pls;
pls = static_cast<WPLLoader *>(loader);
delete pls;
}
const wchar_t *WPLHandler::GetName()
{
static wchar_t wplpl[64];
// no point re-loading this all of the time since it won't change once we've been loaded
return (!wplpl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_WINDOWS_MEDIA_PLAYLIST,wplpl,64):wplpl);
}
/* --- ASX --- */
const wchar_t *ASXHandler::enumExtensions(size_t n)
{
switch(n)
{
case 0:
return L"ASX";
case 1:
if (config_extra_asx_extensions)
return L"WAX";
else
return 0;
case 2:
if (config_extra_asx_extensions)
return L"WMX";
else
return 0;
case 3:
if (config_extra_asx_extensions)
return L"WVX";
else
return 0;
default:
return 0;
}
}
int ASXHandler::SupportedFilename(const wchar_t *filename)
{
wchar_t ext[16] = {0};
GetExtension(filename, ext, 16);
if (!lstrcmpiW(ext, L".ASX"))
return SVC_PLAYLISTHANDLER_SUCCESS;
if (!lstrcmpiW(ext, L".WAX"))
return SVC_PLAYLISTHANDLER_SUCCESS;
if (!lstrcmpiW(ext, L".WMX"))
return SVC_PLAYLISTHANDLER_SUCCESS;
if (!lstrcmpiW(ext, L".WVX"))
return SVC_PLAYLISTHANDLER_SUCCESS;
// TODO: open file and sniff it for file signature
return SVC_PLAYLISTHANDLER_FAILED;
}
ifc_playlistloader *ASXHandler::CreateLoader(const wchar_t *filename)
{
return new ASXLoader;
}
void ASXHandler::ReleaseLoader(ifc_playlistloader *loader)
{
ASXLoader *pls;
pls = static_cast<ASXLoader *>(loader);
delete pls;
}
const wchar_t *ASXHandler::GetName()
{
static wchar_t asxpl[64];
// no point re-loading this all of the time since it won't change once we've been loaded
return (!asxpl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_ASX_PLAYLIST,asxpl,64):asxpl);
}
#define CBCLASS WPLHandler
START_DISPATCH;
CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, enumExtensions)
CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename)
CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader)
VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader)
CB(SVC_PLAYLISTHANDLER_GETNAME, GetName)
END_DISPATCH;
#undef CBCLASS
#define CBCLASS ASXHandler
START_DISPATCH;
CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, enumExtensions)
CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename)
CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader)
VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader)
CB(SVC_PLAYLISTHANDLER_GETNAME, GetName)
END_DISPATCH;
#undef CBCLASS
@@ -0,0 +1,28 @@
#ifndef NULLSOFT_PLAYLISTS_HANDLER_H
#define NULLSOFT_PLAYLISTS_HANDLER_H
#include "../playlist/svc_playlisthandler.h"
#include <bfc/platform/types.h>
#define DECLARE_HANDLER(className) class className ## Handler : public svc_playlisthandler {\
public:\
const wchar_t *enumExtensions(size_t n); \
int SupportedFilename(const wchar_t *filename); \
ifc_playlistloader *CreateLoader(const wchar_t *filename);\
void ReleaseLoader(ifc_playlistloader *loader);\
const wchar_t *GetName(); \
protected: RECVS_DISPATCH;}
DECLARE_HANDLER(WPL);
DECLARE_HANDLER(ASX);
// {DC13A85D-7C61-4462-8CB4-9EBBBD86FA7C}
static const GUID wplHandlerGUID =
{ 0xdc13a85d, 0x7c61, 0x4462, { 0x8c, 0xb4, 0x9e, 0xbb, 0xbd, 0x86, 0xfa, 0x7c } };
// {8909A743-6F00-43ef-B3F6-365000347DE3}
static const GUID asxHandlerGUID =
{ 0x8909a743, 0x6f00, 0x43ef, { 0xb3, 0xf6, 0x36, 0x50, 0x0, 0x34, 0x7d, 0xe3 } };
// {6F62CBB8-7E1F-43eb-B3F6-01C2601029A3}
#endif
+173
View File
@@ -0,0 +1,173 @@
#include "main.h"
#include "RawReader.h"
#include "FileTypes.h"
#include <shlwapi.h>
#define NS_E_FILE_IS_CORRUPTED _HRESULT_TYPEDEF_(0xC00D080DL)
bool IsMyExtension(const wchar_t *filename)
{
const wchar_t *ext = PathFindExtension(filename);
if (ext && *ext)
{
ext++;
return fileTypes.GetAVType(ext) != -1;
}
return false;
}
int RawMediaReaderService::CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **out_reader)
{
if (IsMyExtension(filename))
{
IWMSyncReader *reader = 0;
if (!SUCCEEDED(WMCreateSyncReader(NULL, 0, &reader)))
{
return NErr_FailedCreate;
}
if (FAILED(reader->Open(filename)))
{
reader->Release();
reader = 0;
return NErr_FileNotFound; // TODO: check HRESULT
}
RawMediaReader *raw_reader = new RawMediaReader();
if (!raw_reader)
{
reader->Close();
reader->Release();
return NErr_OutOfMemory;
}
int ret = raw_reader->Initialize(reader);
if (ret != NErr_Success)
{
delete raw_reader;
return ret;
}
*out_reader = raw_reader;
return NErr_Success;
}
else
{
return NErr_False;
}
}
#define CBCLASS RawMediaReaderService
START_DISPATCH;
CB(CREATERAWMEDIAREADER, CreateRawMediaReader);
END_DISPATCH;
#undef CBCLASS
RawMediaReader::RawMediaReader()
{
reader=0;
stream_num=0;
buffer_used=0;
end_of_file=false;
length=0;
buffer=0;
next_output=0;
}
RawMediaReader::~RawMediaReader()
{
if (reader)
{
reader->Close();
reader->Release();
}
if (buffer)
{
buffer->Release();
}
}
int RawMediaReader::Initialize(IWMSyncReader *reader)
{
this->reader=reader;
return NErr_Success;
}
int RawMediaReader::Read(void *out_buffer, size_t buffer_size, size_t *bytes_read)
{
/* we don't care about these, but the API does not allows NULL */
QWORD sample_time = 0, duration = 0;
size_t bytesCopied = 0;
uint8_t *dest = (uint8_t *)out_buffer;
for (;;)
{
if (buffer)
{
BYTE *bufferBytes = 0;
DWORD bufferTotal = 0;
buffer->GetBufferAndLength(&bufferBytes, &bufferTotal);
if (buffer_used < bufferTotal)
{
size_t toCopy = min(bufferTotal - buffer_used, buffer_size);
memcpy(dest, bufferBytes + buffer_used, toCopy);
buffer_used += toCopy;
buffer_size -= toCopy;
dest += toCopy;
bytesCopied += toCopy;
if (buffer_used == bufferTotal)
{
buffer_used = 0;
buffer->Release();
buffer = 0;
}
}
if (buffer_size == 0)
{
*bytes_read = bytesCopied;
return NErr_Success;
}
}
if (stream_num == 0)
{
DWORD outputs = 0;
HRESULT hr=reader->GetOutputCount(&outputs);
if (FAILED(hr))
return NErr_Error;
if (next_output >= outputs)
return NErr_EndOfFile;
hr=reader->GetStreamNumberForOutput(next_output, &stream_num);
if (FAILED(hr))
return NErr_Error;
hr=reader->SetReadStreamSamples(stream_num, TRUE);
if (FAILED(hr))
return NErr_Error;
next_output++;
}
DWORD flags = 0;
HRESULT r = reader->GetNextSample(stream_num, &buffer, &sample_time, &duration, &flags, 0, 0);
if (r == NS_E_NO_MORE_SAMPLES || r == NS_E_FILE_IS_CORRUPTED)
{
stream_num=0;
}
}
return NErr_Error;
}
size_t RawMediaReader::Release()
{
delete this;
return 0;
}
#define CBCLASS RawMediaReader
START_DISPATCH;
CB(RELEASE, Release);
CB(RAW_READ, Read);
END_DISPATCH;
#undef CBCLASS
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "../Agave/DecodeFile/svc_raw_media_reader.h"
#include "../Agave/DecodeFile/ifc_raw_media_reader.h"
#include <mmreg.h>
#include <wmsdk.h>
// {9AF5FD89-DC41-4F2A-A156-8D1399FDE57B}
static const GUID wm_raw_reader_guid =
{ 0x9af5fd89, 0xdc41, 0x4f2a, { 0xa1, 0x56, 0x8d, 0x13, 0x99, 0xfd, 0xe5, 0x7b } };
class RawMediaReaderService : public svc_raw_media_reader
{
public:
static const char *getServiceName() { return "Windows Media Audio Raw Reader"; }
static GUID getServiceGuid() { return wm_raw_reader_guid; }
int CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **reader);
protected:
RECVS_DISPATCH;
};
class RawMediaReader : public ifc_raw_media_reader
{
public:
RawMediaReader();
~RawMediaReader();
int Initialize(IWMSyncReader *reader);
int Read(void *buffer, size_t buffer_size, size_t *bytes_read);
size_t Release();
protected:
RECVS_DISPATCH;
private:
IWMSyncReader *reader;
WORD stream_num;
INSSBuffer *buffer;
size_t buffer_used;
bool end_of_file;
QWORD length;
DWORD next_output;
};
+68
View File
@@ -0,0 +1,68 @@
#ifndef NULLSOFT_REMAININGH
#define NULLSOFT_REMAININGH
#include <assert.h>
#include <memory.h>
/* this class is used to store leftover samples */
class Remaining
{
public:
Remaining()
: store(0), size(0), used(0)
{}
void Allocate(unsigned long _size)
{
assert(_size);
used=0;
size=_size;
if (store)
delete [] store;
store = new unsigned char [size];
}
/* Saves the incoming data and updates the pointer positions */
template <class storage_t>
void UpdatingWrite(storage_t *&data, unsigned long &bytes)
{
unsigned long bytesToWrite = min(bytes, SizeRemaining());
Write(data, bytesToWrite);
assert(bytesToWrite);
data = (storage_t *)((char *)data + bytesToWrite);
bytes -= bytesToWrite;
}
void Write(void *data, unsigned long bytes)
{
unsigned char *copy = (unsigned char *)store;
copy+=used;
memcpy(copy, data, bytes);
used+=bytes;
}
unsigned long SizeRemaining()
{
return size-used;
}
bool Empty()
{
return !used;
}
bool Full()
{
return size == used;
}
void *GetData()
{
return (void *)store;
}
void Flush()
{
used=0;
}
unsigned char *store;
long size, used;
};
#endif
+376
View File
@@ -0,0 +1,376 @@
#include "SeekLayer.h"
#include "Main.h"
#include "output/AudioOut.h"
#include "util.h"
#include <assert.h>
using namespace Nullsoft::Utility;
struct OpenThreadData
{
IWMReaderCallback *callback;
wchar_t *url;
IWMReader *reader;
void open()
{
reader->Open(url, callback, 0);
}
OpenThreadData(IWMReader *_reader, const wchar_t *_url, IWMReaderCallback *_callback)
{
reader = _reader;
reader->AddRef();
callback = _callback;
callback->AddRef();
url = _wcsdup(_url);
}
~OpenThreadData()
{
free(url);
reader->Release();
callback->Release();
}
};
DWORD WINAPI OpenThread(void *param)
{
OpenThreadData *data = (OpenThreadData *)param;
data->open();
delete data;
return 0;
}
#define NEW_SEEK
SeekLayer::SeekLayer(IWMReader *_reader, ClockLayer *_clock)
: seekPos(0), reader(_reader), playState(PLAYSTATE_CLOSED), metadata(NULL), clock(_clock),
needPause(false), paused(false), needStop(false),
seekGuard(GUARDNAME("Seek Guard")),
oldState_buffer(PLAYSTATE_NONE)
{
reader->AddRef();
reader->QueryInterface(&reader2);
}
void SeekLayer::DoStop()
{
if (paused)
reader->Resume();
reader->Stop();
First().Stopping();
First().Kill();
if (paused)
{
paused = false;
out->Pause(0);
}
needStop = false;
}
void SeekLayer::SeekTo(long position)
{
AutoLock lock (seekGuard LOCKNAME("SeekTo"));
if (paused)
{
reader->Resume();
}
First().Stopping();
First().Kill();
seekPos = position;
clock->SetLastOutputTime(position);
clock->SetStartTimeMilliseconds(position);
out->Flush(position);
QWORD qSeekPos = position;
qSeekPos *= 10000;
reader->Start(qSeekPos, 0, 1.0f, NULL);
if (paused)
{
reader->Pause();
}
}
void SeekLayer::Pause()
{
AutoLock lock (seekGuard LOCKNAME("Pause"));
if (playState == PLAYSTATE_STARTED)
{
paused = true;
reader->Pause();
out->Pause(1);
}
else
{
needPause = true;
}
}
int SeekLayer::Open(const wchar_t *filename, IWMReaderCallback *callback)
{
AutoLock lock (seekGuard LOCKNAME("Open"));
assert(playState == PLAYSTATE_CLOSED);
needStop = false;
playState = PLAYSTATE_OPENING;
DWORD dummyId;
CreateThread(NULL, 0, OpenThread, new OpenThreadData(reader, filename, callback), 0, &dummyId);
return 0;
}
void SeekLayer::Stop()
{
AutoLock lock (seekGuard LOCKNAME("Stop"));
needStop = true;
switch (playState)
{
case PLAYSTATE_BUFFERING:
// needStop=false;
reader2->StopBuffering();
// reader->Stop();
break;
case PLAYSTATE_OPENING:
// wait for it to open (or connect) and then we'll kill it there
break;
case PLAYSTATE_NONE:
case PLAYSTATE_STOPPED:
if (FAILED(reader->Close())) // reader->Close() is sometimes synchronous, and sometimes not valid here
{
playState = PLAYSTATE_CLOSED;
return ;
}
break;
case PLAYSTATE_OPENED:
case PLAYSTATE_STARTED:
reader->Stop();
First().Stopping();
First().Kill();
break;
case PLAYSTATE_CLOSED:
needStop = false;
break;
/*
case PLAYSTATE_BUFFERING:
reader2->StopBuffering();
reader->Stop();
break;*/
case PLAYSTATE_SEEK:
break;
}
while (playState != PLAYSTATE_CLOSED)
{
lock.ManualUnlock();
Sleep(55);
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]Stop"));
}
needStop = false;
}
void SeekLayer::Unpause()
{
AutoLock lock (seekGuard LOCKNAME("Unpause"));
if (playState == PLAYSTATE_STARTED)
{
paused = false;
out->Pause(0);
reader->Resume();
clock->Clock();
}
else
{
needPause = false;
}
}
void SeekLayer::Opened()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Opened"));
if (needStop)
{
playState = PLAYSTATE_OPENED;
lock.ManualUnlock();
reader->Close();
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Opened"));
return ;
}
playState = PLAYSTATE_OPENED;
}
WMHandler::Opened();
}
void SeekLayer::Stopped()
{
{
AutoLock lock (seekGuard LOCKNAME("Stopped"));
if (needStop)
{
playState = PLAYSTATE_STOPPED;
lock.ManualUnlock();
reader->Close();
lock.ManualLock(MANUALLOCKNAME("Stopped"));
}
else
{
playState = PLAYSTATE_STOPPED;
}
WMHandler::Stopped();
}
}
void SeekLayer::Started()
{
{
AutoLock lock (seekGuard LOCKNAME("Started"));
playState = PLAYSTATE_STARTED;
if (needStop)
{
reader->Stop();
First().Stopping();
First().Kill();
return ;
}
else if (needPause)
{
Pause();
needPause = false;
}
}
WMHandler::Started();
}
void SeekLayer::Closed()
{
playState = PLAYSTATE_CLOSED;
paused = false;
needPause = false;
needStop = false;
seekPos = 0;
WMHandler::Closed();
}
void SeekLayer::BufferingStarted()
{
{
AutoLock lock (seekGuard LOCKNAME("BufferingStarted"));
if (playState == PLAYSTATE_OPENED)
oldState_buffer = PLAYSTATE_NONE;
else
oldState_buffer = playState;
if (playState != PLAYSTATE_STARTED)
playState = PLAYSTATE_BUFFERING;
if (needStop)
reader2->StopBuffering();
}
WMHandler::BufferingStarted();
}
void SeekLayer::BufferingStopped()
{
{
AutoLock lock (seekGuard LOCKNAME("BufferingStopped"));
if (needStop)
reader->Stop();
playState = oldState_buffer;
}
WMHandler::BufferingStopped();
}
void SeekLayer::EndOfFile()
{
{
AutoLock lock (seekGuard LOCKNAME("EndOfFile"));
if (needStop)
return ;
}
WMHandler::EndOfFile();
}
void SeekLayer::Connecting()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Connecting"));
if (needStop)
{
playState = PLAYSTATE_NONE;
lock.ManualUnlock();
reader->Close();
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Connecting"));
return ;
}
playState = PLAYSTATE_NONE;
}
WMHandler::Connecting();
}
void SeekLayer::Locating()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Locating"));
if (needStop)
{
playState = PLAYSTATE_NONE;
lock.ManualUnlock();
reader->Close();
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Locating"));
return ;
}
playState = PLAYSTATE_NONE;
}
WMHandler::Locating();
}
void SeekLayer::OpenCalled()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::OpenCalled"));
if (needStop)
{
playState = PLAYSTATE_NONE;
lock.ManualUnlock();
reader->Close();
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::OpenCalled"));
return ;
}
playState = PLAYSTATE_NONE;
}
WMHandler::OpenCalled();
}
void SeekLayer::OpenFailed()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::OpenFailed"));
if (playState == PLAYSTATE_OPENING)
playState = PLAYSTATE_NONE;
}
WMHandler::OpenFailed();
}
void SeekLayer::Error()
{
{
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Error"));
/*if (playState == PLAYSTATE_OPENING)
playState = PLAYSTATE_CLOSED;
else */if (playState != PLAYSTATE_CLOSED)
playState = PLAYSTATE_NONE;
}
WMHandler::Error();
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef NULLSOFT_SEEKLAYERH
#define NULLSOFT_SEEKLAYERH
#include "WMHandler.h"
#include "../nu/AutoLock.h"
#include "ClockLayer.h"
class SeekLayer : public WMHandler
{
enum PlayState
{
PLAYSTATE_NONE,
PLAYSTATE_OPENING,
PLAYSTATE_OPENED,
PLAYSTATE_BUFFERING,
PLAYSTATE_STARTED,
PLAYSTATE_STOPPED,
PLAYSTATE_CLOSED,
PLAYSTATE_SEEK,
};
public:
SeekLayer(IWMReader *_reader, ClockLayer *_clock);
void SeekTo(long position);
void Pause();
void Unpause();
void Stop();
int Open(const wchar_t *filename, IWMReaderCallback *callback);
private:
void BufferingStarted();
void BufferingStopped();
void Started();
void Stopped();
void Closed();
void Opened();
void OpenCalled();
void Connecting();
void Locating();
void EndOfFile();
void OpenFailed();
void Error();
private:
void DoStop();
bool needPause, paused, needStop;
long seekPos;
Nullsoft::Utility::LockGuard seekGuard;
IWMReader *reader;
IWMReaderAdvanced2 *reader2;
IWMMetadataEditor *metadata;
ClockLayer *clock;
PlayState playState, oldState_buffer;
};
#endif
@@ -0,0 +1,54 @@
#if 0
#include <windows.h>
#include "../Winamp/wa_ipc.h"
#include "Main.h"
#include <shlwapi.h>
static WNDPROC waProc=0;
static bool winampisUnicode=false;
static LRESULT WINAPI StatusHookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_WA_IPC && lParam == IPC_HOOK_TITLESW)
{
LRESULT downTheLine = winampisUnicode?CallWindowProcW(waProc, hwnd, msg, wParam, lParam):CallWindowProcA(waProc, hwnd, msg, wParam, lParam);
waHookTitleStructW *hook = (waHookTitleStructW *)wParam;
if (!PathIsURLW(hook->filename) && winamp.GetStatusHook(hook->title, 2048, hook->filename))
{
return TRUE;
}
else
return downTheLine;
}
if (waProc)
{
if (winampisUnicode)
return CallWindowProcW(waProc, hwnd, msg, wParam, lParam);
else
return CallWindowProcA(waProc, hwnd, msg, wParam, lParam);
}
else
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void Hook(HWND winamp)
{
if (winamp)
{
winampisUnicode = !!IsWindowUnicode(winamp);
if (winampisUnicode)
waProc = (WNDPROC)SetWindowLongPtrW(winamp, GWLP_WNDPROC, (LONG_PTR)StatusHookProc);
else
waProc = (WNDPROC)SetWindowLongPtrA(winamp, GWLP_WNDPROC, (LONG_PTR)StatusHookProc);
}
}
void Unhook(HWND winamp)
{
// if (winamp && GetWindowLongA(winamp,GWL_WNDPROC) == (LONG)StatusHookProc)
//SetWindowLong(winamp, GWL_WNDPROC, (LONG)waProc);
//waProc=0;
}
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef NULLSOFT_STATUSHOOKH
#define NULLSOFT_STATUSHOOKH
#include <windows.h>
void Hook(HWND winamp);
void Unhook(HWND winamp);
#endif
+8
View File
@@ -0,0 +1,8 @@
advanced preferences:
defaults button
why do some videos not end properly?
potential race condition over WMDRM::fn
make the messagebox for 'do you want to acquire this shit' have its own message loop so we can killswitch it
+64
View File
@@ -0,0 +1,64 @@
#include "main.h"
#include "TagAlias.h"
struct TagAliases
{
const wchar_t *winampTag;
const wchar_t *wmaTag;
};
const TagAliases aliases[] =
{
{L"comment", g_wszWMDescription},
{L"album", g_wszWMAlbumTitle},
{L"genre", g_wszWMGenre},
{L"year", g_wszWMYear},
{L"track", g_wszWMTrackNumber},
{L"artist", g_wszWMAuthor},
{L"title", g_wszWMTitle},
{L"copyright", g_wszWMCopyright},
{L"composer", g_wszWMComposer},
{L"albumartist", g_wszWMAlbumArtist},
{L"bpm", g_wszWMBeatsPerMinute},
{L"publisher", g_wszWMPublisher},
{L"ISRC", g_wszWMISRC},
{L"lyricist", g_wszWMWriter},
{L"conductor", g_wszWMConductor},
{L"tool", g_wszWMToolName},
{L"encoder", g_wszWMEncodingSettings},
{L"key", g_wszWMInitialKey},
{L"mood", g_wszWMMood},
{L"disc", g_wszWMPartOfSet},
{L"height", g_wszWMVideoHeight},
{L"width", g_wszWMVideoWidth},
{L"category", g_wszWMCategory},
{L"producer", g_wszWMProducer},
{L"director", g_wszWMDirector},
{L"fps", g_wszWMVideoFrameRate},
{0, 0},
};
const wchar_t *GetAlias(const wchar_t *tag)
{
int i = 0;
while (aliases[i].winampTag)
{
if (!lstrcmpiW(tag, aliases[i].winampTag))
return aliases[i].wmaTag;
i++;
}
return tag;
}
const wchar_t *GetAlias_rev(const wchar_t *tag)
{
int i = 0;
while (aliases[i].wmaTag)
{
if (!lstrcmpiW(tag, aliases[i].wmaTag))
return aliases[i].winampTag;
i++;
}
return tag;
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef NULLSOFT_IN_WMVDRM_TAGALIAS_H
#define NULLSOFT_IN_WMVDRM_TAGALIAS_H
#include <wchar.h>
const wchar_t *GetAlias(const wchar_t *tag);
const wchar_t *GetAlias_rev(const wchar_t *tag);
#endif
@@ -0,0 +1,41 @@
#include "main.h"
#include "VideoDataConverter.h"
#include <cassert>
class YV12Converter : public VideoDataConverter
{
public:
YV12Converter(int w, int h)
: width(w), height(h)
{
yv12.y.rowBytes = width;
yv12.v.rowBytes = width / 2;
yv12.u.rowBytes = width / 2;
vOffset = width*height;
uOffset = width*height/4;
}
void *Convert(void *videoData)
{
yv12.y.baseAddr = (unsigned char*)videoData;
yv12.v.baseAddr = yv12.y.baseAddr + vOffset;
yv12.u.baseAddr = yv12.v.baseAddr + uOffset;
return (void *)&yv12;
}
int width, height;
int vOffset, uOffset;
YV12_PLANES yv12;
};
VideoDataConverter *MakeConverter(VideoOutputStream *stream)
{
switch (stream->FourCC())
{
case '21VY':
return new YV12Converter(stream->DestinationWidth(), stream->DestinationHeight());
default:
return new VideoDataConverter;
}
}
@@ -0,0 +1,18 @@
#ifndef NULLSOFT_VIDEODATACONVERTERH
#define NULLSOFT_VIDEODATACONVERTERH
#include "OutputStream.h"
class VideoDataConverter
{
public:
virtual void *Convert(void *videoData)
{
return videoData;
}
};
VideoDataConverter *MakeConverter(VideoOutputStream *stream);
#endif
+300
View 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();
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef NULLSOFT_VIDEOLAYERH
#define NULLSOFT_VIDEOLAYERH
#include "WMHandler.h"
#include "OutputStream.h"
#include <wmsdk.h>
#include "VideoDataConverter.h"
#include "Config.h"
#include "VideoThread.h"
#define VIDEO_ACCEPTABLE_JITTER (config_video_jitter*10000)
#define VIDEO_ACCEPTABLE_JITTER_MS (config_video_jitter)
class VideoLayer : public WMHandler
{
public:
VideoLayer(IWMReader *_reader);
~VideoLayer();
bool IsOpen();
void Kill();
private:
// WMHandler
void VideoFrameDrop(DWORD lateness);
void SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample);
void Opened();
void AudioBufferMilliseconds(long ms);
void Closed();
void Started();
void Stopped();
void HasVideo(bool &video);
// utility methods
bool AttemptOpenVideo(VideoOutputStream *attempt);
bool OpenVideo();
// other people's data
IWMReader *reader;
// our data
IWMReaderAdvanced2 *reader2;
IWMHeaderInfo *header;
int videoOutputNum;
DWORD offset;
long nextRest;
VideoDataConverter *converter;
VideoOutputStream *videoStream;
bool videoOpened;
QWORD catchupTime;
double aspect;
int fourcc;
bool flip;
int videoWidth, videoHeight;
HANDLE killSwitch;
DWORD earlyDelivery;
bool drmProtected;
bool video_output_opened;
VideoThread videoThread;
};
#endif
@@ -0,0 +1,80 @@
#include "main.h"
#include "VideoOutputChildDDraw.h"
#include <multimon.h>
#include <ddraw.h>
class MonitorFinder
{
public:
MonitorFinder(HMONITOR hm) : m_monitor_to_find(hm), m_found_devguid(0)
{}
HMONITOR m_monitor_to_find;
int m_found_devguid;
GUID m_devguid;
};
static BOOL WINAPI DDEnumCallbackEx(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
{
MonitorFinder *ovo = (MonitorFinder *)lpContext;
if (ovo->m_found_devguid) return 1;
if (hm == ovo->m_monitor_to_find)
{
ovo->m_devguid = *lpGUID;
ovo->m_found_devguid = 1;
}
return 1;
}
void VideoOutputChildDDraw::update_monitor_coords()
{
//find the correct monitor if multiple monitor support is present
m_mon_x = 0;
m_mon_y = 0;
HINSTANCE h = LoadLibrary(L"user32.dll");
if (h)
{
HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT, DWORD)) GetProcAddress(h, "MonitorFromPoint");
HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(h, "MonitorFromRect");
HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags) = (HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(h, "MonitorFromWindow");
BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = (BOOL (WINAPI *)(HMONITOR, LPMONITORINFO)) GetProcAddress(h, "GetMonitorInfoA");
if (Mfp && Mfr && Mfw && Gmi)
{
HMONITOR hm = Mfw(parent, 0);
if (hm)
{
HINSTANCE hdd = LoadLibrary(L"ddraw.dll");
if (hdd)
{
typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKEXA)(GUID FAR *, LPSTR, LPSTR, LPVOID, HMONITOR);
typedef HRESULT (WINAPI * LPDIRECTDRAWENUMERATEEX)( LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags);
LPDIRECTDRAWENUMERATEEX lpDDEnumEx;
lpDDEnumEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hdd, "DirectDrawEnumerateExW");
if (lpDDEnumEx)
{
MonitorFinder finder(hm);
lpDDEnumEx(&DDEnumCallbackEx, &finder, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES);
foundGUID=!!finder.m_found_devguid;
if (foundGUID)
{
m_devguid=finder.m_devguid;
MONITORINFOEXW mi;
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
if (Gmi(hm, &mi))
{
m_mon_x = mi.rcMonitor.left;
m_mon_y = mi.rcMonitor.top;
}
}
}
FreeLibrary(hdd);
}
}
}
FreeLibrary(h);
}
}
@@ -0,0 +1,17 @@
#ifndef NULLSOFT_VIDEOOUTPUTCHILDDDRAWH
#define NULLSOFT_VIDEOOUTPUTCHILDDDRAWH
#include "../Winamp/VideoOutputChild.h"
class VideoOutputChildDDraw : public VideoRenderer
{
public:
VideoOutputChildDDraw() : m_mon_x(0), m_mon_y(0), foundGUID(false), parent(0), adjuster(0) {}
VideoAspectAdjuster *adjuster;
void update_monitor_coords();
int m_mon_x, m_mon_y;
bool foundGUID;
GUID m_devguid;
HWND parent;
};
#endif
+166
View File
@@ -0,0 +1,166 @@
#include "Main.h"
#include "VideoThread.h"
#include "VideoLayer.h"
#include "config.h"
#include <windows.h>
DWORD WINAPI VidThread_stub(void *ptr)
{
((VideoThread *)ptr)->VidThread();
return 0;
}
VideoThread::VideoThread() : converter(0), clock(0)
{
drm = false;
DWORD id;
thread = CreateThread(NULL, 256*1024, VidThread_stub, (void *)this, NULL, &id);
SetThreadPriority(thread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
}
void VideoThread::Start(VideoDataConverter *_converter, WMHandler *_clock)
{
clock = _clock;
if (converter != _converter)
{
if (converter)
delete converter;
converter = _converter;
}
ResetEvent(stopped);
QueueUserAPC(MediaThread_StartAPC, thread, reinterpret_cast<ULONG_PTR>(this));
}
void VideoThread::VidThread()
{
while (true)
{
switch (WaitForSingleObjectEx(killEvent, wait, TRUE))
{
case WAIT_OBJECT_0:
//StopAPC();
return;
case WAIT_TIMEOUT:
{
if (buffers.empty())
{
SetEvent(bufferFreed);
continue;
}
MediaBuffer *buffer = buffers.front();
__int64 diff;
clock->TimeToSync(buffer->timestamp, diff);
if (diff < VIDEO_ACCEPTABLE_JITTER)
{
void *data;
DWORD size;
buffer->buffer->GetBufferAndLength((BYTE **)&data, &size);
if (buffer->drmProtected)
winamp.EncryptedDrawFrame(converter->Convert(data));
else
winamp.DrawFrame(converter->Convert(data));
try {
buffer->buffer->Release();
delete buffer;
} catch (...) {}
//buffers.pop_front();
if (buffers.size())
{
buffers.erase(buffers.begin());
}
}
if (buffers.size() < config_video_cache_frames)
SetEvent(bufferFreed);
}
continue;
default:
continue;
}
}
}
void VideoThread::AddAPC(MediaBuffer *buffer)
{
if (buffers.empty())
{
__int64 diff;
clock->TimeToSync(buffer->timestamp, diff);
if (diff < VIDEO_ACCEPTABLE_JITTER)
{
void *data;
DWORD size;
buffer->buffer->GetBufferAndLength((BYTE **)&data, &size);
if (buffer->drmProtected)
winamp.EncryptedDrawFrame(converter->Convert(data));
else
winamp.DrawFrame(converter->Convert(data));
buffer->buffer->Release();
if (buffers.size() >= config_video_cache_frames)
ResetEvent(bufferFreed);
return;
}
}
OrderedInsert(buffer);
if (buffers.size() >= config_video_cache_frames)
ResetEvent(bufferFreed);
}
struct VideoOpenParameters
{
int width;
int height;
int color_format;
double aspect;
int flip;
bool drm;
};
VOID CALLBACK VideoThread::VideoThread_VideoOpenAPC(ULONG_PTR params)
{
VideoOpenParameters *p = (VideoOpenParameters *)params;
if (p->drm)
{
winamp.OpenEncryptedVideo(p->width, p->height, !!p->flip, p->aspect, p->color_format);
}
else
{
winamp.OpenVideo(p->width, p->height, !!p->flip, p->aspect, p->color_format);
}
}
void VideoThread::OpenVideo(bool drm, int width, int height, bool flip, double aspect, int fourcc)
{
VideoOpenParameters *p = new VideoOpenParameters;
p->width = width;
p->height = height;
p->color_format = fourcc;
p->aspect = aspect;
p->flip = flip;
p->drm = drm;
this->drm = drm;
QueueUserAPC(VideoThread_VideoOpenAPC, thread, reinterpret_cast<ULONG_PTR>(p));
}
VOID CALLBACK VideoThread::VideoThread_VideoCloseAPC(ULONG_PTR params)
{
if (params)
winamp.CloseEncryptedVideo();
else
winamp.CloseVideo();
}
void VideoThread::CloseVideo(bool drm)
{
QueueUserAPC(VideoThread_VideoCloseAPC, thread, static_cast<ULONG_PTR>(drm));
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef NULLSOFTVIDEOTHREADH
#define NULLSOFTVIDEOTHREADH
#include "VideoDataConverter.h"
#include "WMHandler.h"
#include <deque>
#include <wmsdk.h>
#include "MediaThread.h"
class VideoThread : public MediaThread
{
public:
VideoThread();
void Start(VideoDataConverter *_converter, WMHandler *_clock);
/* AddBuffers put a video buffer in the queue
it returns true if it was added
it returns false if it was NOT added. it is up to YOU (the caller) to sleep for a while and call again
*/
void VidThread();
void OpenVideo(bool drm, int width, int height, bool flip, double aspect, int fourcc);
void CloseVideo(bool drm);
private:
static VOID CALLBACK VideoThread_VideoOpenAPC(ULONG_PTR params);
static VOID CALLBACK VideoThread_VideoCloseAPC(ULONG_PTR params);
void AddAPC(MediaBuffer *);
VideoDataConverter *converter;
WMHandler *clock;
bool drm;
};
#endif
+294
View File
@@ -0,0 +1,294 @@
#include "Main.h"
#include "WMCallback.h"
#include <algorithm>
#include "WMHandler.h"
#include "util.h"
#include <cassert>
#define CAST_TO(x) if (riid== IID_##x) { *ppvObject=static_cast<x *>(this); AddRef(); return S_OK; }
#define CAST_TO_VIA(x,y) if (riid== IID_##x) { *ppvObject=static_cast<y *>(this); AddRef(); return S_OK; }
HRESULT WMCallback::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
{
CAST_TO(IWMReaderCallback);
CAST_TO_VIA(IUnknown, IWMReaderCallback);
CAST_TO(IWMReaderCallbackAdvanced);
#ifdef _DEBUG
CAST_TO(IWMCredentialCallback);
#endif
*ppvObject = NULL;
return E_NOINTERFACE;
}
ULONG WMCallback::AddRef()
{
return InterlockedIncrement(&refCount);
}
ULONG WMCallback::Release()
{
if (InterlockedDecrement(&refCount) == 0)
{
delete this;
return 0;
}
return refCount;
}
HRESULT WMCallback::OnStatus(WMT_STATUS Status, HRESULT hr, WMT_ATTR_DATATYPE dwType,
BYTE __RPC_FAR *pValue, void __RPC_FAR *pvContext)
{
if (!handler)
return S_OK;
switch (Status)
{
WMTCASE(WMT_INIT_PLAYLIST_BURN)
handler->InitPlaylistBurn();
break;
WMTCASE(WMT_NO_RIGHTS)
handler->NoRights((wchar_t *)pValue);
break;
WMTCASE(WMT_NO_RIGHTS_EX)
handler->NoRightsEx((WM_GET_LICENSE_DATA *&)pValue);
break;
WMTCASE(WMT_NEEDS_INDIVIDUALIZATION)
handler->Individualize();
break;
WMTCASE(WMT_END_OF_STREAMING)
break;
WMTCASE(WMT_LICENSEURL_SIGNATURE_STATE)
handler->SignatureState((WMT_DRMLA_TRUST *&)pValue);
break;
WMTCASE(WMT_ACQUIRE_LICENSE)
WMT_SHOW_HR_CODE(hr)
switch (hr)
{
case NS_S_DRM_LICENSE_ACQUIRED:
handler->LicenseAcquired();
break;
case NS_S_DRM_MONITOR_CANCELLED:
handler->MonitorCancelled();
break;
case NS_S_DRM_ACQUIRE_CANCELLED:
handler->SilentCancelled();
break;
default:
handler->AcquireLicense((WM_GET_LICENSE_DATA *&)pValue);
}
break;
WMTCASE(WMT_INDIVIDUALIZE)
handler->IndividualizeStatus((WM_INDIVIDUALIZE_STATUS *)pValue);
break;
//the file has been opened
WMTCASE(WMT_OPENED)
if (SUCCEEDED(hr))
handler->Opened();
else
{
switch (hr)
{
WMTCASE(NS_E_DRM_APPCERT_REVOKED)
WMTCASE(NS_E_DRM_LICENSE_APP_NOTALLOWED)
handler->DRMExpired();
WMTCASE(NS_E_LICENSE_REQUIRED)
handler->LicenseRequired();
break;
WMTCASE(NS_E_DRM_NEEDS_INDIVIDUALIZATION)
handler->NeedsIndividualization();
break;
WMTCASE(E_ACCESSDENIED)
handler->AccessDenied();
break;
default:
WMT_SHOW_HR_CODE(hr);
handler->Error();
return S_OK;
}
handler->OpenCalled();
}
break;
// Playback of the opened file has begun.
WMTCASE( WMT_STARTED)
if (SUCCEEDED(hr))
handler->Started();
else
{
switch (hr)
{
WMTCASE(E_ABORT)
//handler->OpenFailed();
break;
WMTCASE(NS_E_DRM_REOPEN_CONTENT)
handler->Error();
break;
default:
WMT_SHOW_HR_CODE(hr);
handler->Error();
break;
}
}
break;
WMTCASE( WMT_NEW_METADATA)
if (SUCCEEDED(hr))
handler->NewMetadata();
break;
// The previously playing reader has stopped.
WMTCASE( WMT_STOPPED)
if (SUCCEEDED(hr))
handler->Stopped();
else
{
WMT_SHOW_HR_CODE(hr);
handler->Error();
}
break;
// The previously playing reader has stopped.
WMTCASE( WMT_CLOSED)
if (SUCCEEDED(hr))
handler->Closed();
else
{
WMT_SHOW_HR_CODE(hr);
handler->Error();
}
break;
WMTCASE(WMT_ERROR)
WMT_SHOW_HR_CODE(hr);
//handler->Error();
break;
WMTCASE( WMT_BUFFERING_START)
if (SUCCEEDED(hr))
handler->BufferingStarted();
break;
WMTCASE( WMT_BUFFERING_STOP)
if (SUCCEEDED(hr))
handler->BufferingStopped();
break;
WMTCASE( WMT_EOF)
WMT_SHOW_HR_CODE(hr);
handler->EndOfFile();
break;
WMTCASE( WMT_LOCATING)
handler->Locating();
break;
WMTCASE( WMT_CONNECTING)
handler->Connecting();
break;
WMTCASE( WMT_PREROLL_READY)
break;
WMTCASE( WMT_PREROLL_COMPLETE)
break;
WMTCASE(WMT_NEW_SOURCEFLAGS)
break;
WMTCASE(WMT_MISSING_CODEC)
WMT_SHOW_HR_CODE(hr);
#ifdef DEBUG
std::cerr << dwType << std::endl;
std::wcerr << GuidString(*(GUID *)pValue) << std::endl;
#endif
break;
default:
#ifdef DEBUG
std::cerr << "unknown message = " << Status << std::endl;
#endif
break;
};
return S_OK;
}
HRESULT WMCallback::OnStreamSelection(WORD wStreamCount, WORD *pStreamNumbers, WMT_STREAM_SELECTION *pSelections, void *pvContext)
{
#ifdef DEBUG
std::cerr << "OnStreamSelection" << std::endl;
#endif
return E_NOTIMPL;
}
HRESULT WMCallback::OnOutputPropsChanged(DWORD dwOutputNum, WM_MEDIA_TYPE *pMediaType, void *pvContext)
{
#ifdef DEBUG
std::cerr << "OnOutputPropsChanged" << std::endl;
#endif
return E_NOTIMPL;
}
HRESULT WMCallback::AllocateForStream(WORD wStreamNum, DWORD cbBuffer, INSSBuffer **ppBuffer, void *pvContext)
{
return E_NOTIMPL;
}
HRESULT WMCallback::AllocateForOutput(DWORD dwOutputNum, DWORD cbBuffer, INSSBuffer **ppBuffer, void *pvContext)
{
return E_NOTIMPL;
}
HRESULT WMCallback::OnStreamSample(WORD wStreamNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer *pSample, void *pvContext)
{
return E_NOTIMPL;
}
// 0x5A, 0xA5, 0x00, 0x03, 0x74, 0x00, 0x01, 0x01, 0x77,
//------------------------------------------------------------------------------
// Name: CWAPlugin::OnSample()
// Desc: IWMReaderCallback method to process samples.
//------------------------------------------------------------------------------
HRESULT WMCallback::OnSample(DWORD dwOutputNum, QWORD cnsSampleTime,
QWORD cnsSampleDuration, DWORD dwFlags,
INSSBuffer __RPC_FAR *pSample, void __RPC_FAR *pvContext)
{
if (!handler)
return S_OK;
handler->SampleReceived(cnsSampleTime, cnsSampleDuration, dwOutputNum, dwFlags, pSample);
return S_OK;
}
HRESULT WMCallback::OnTime(QWORD cnsCurrentTime, void *pvContext)
{
if (!handler)
return S_OK;
handler->TimeReached(cnsCurrentTime);
return S_OK;
}
HRESULT WMCallback::AcquireCredentials(WCHAR* pwszRealm, WCHAR* pwszSite,
WCHAR* pwszUser, DWORD cchUser,
WCHAR* pwszPassword, DWORD cchPassword,
HRESULT hrStatus, DWORD* pdwFlags)
{
#ifdef _DEBUG
std::cout << "WMCallback::AcquireCredentials" << std::endl;
std::wcout << pwszRealm << std::endl;
std::wcout << pwszSite << std::endl;
std::wcout << HRErrorCode(hrStatus) << std::endl;
return S_OK;
#endif
return E_NOTIMPL;
}
+52
View File
@@ -0,0 +1,52 @@
#ifndef NULLSOFT_WMCALLBACK
#define NULLSOFT_WMCALLBACK
#include <wmsdk.h>
#include <deque>
#include "WMHandler.h"
class WMCallback : public IWMReaderCallback, public IWMReaderCallbackAdvanced, public IWMCredentialCallback
{
public:
WMCallback() : refCount(0), handler(0)
{
AddRef();
}
~WMCallback()
{
}
WMHandler &operator >> (WMHandler *_handler)
{
handler = _handler;
return *handler;
}
private:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE OnStatus(WMT_STATUS Status, HRESULT hr, WMT_ATTR_DATATYPE dwType, BYTE __RPC_FAR *pValue, void __RPC_FAR *pvContext);
virtual HRESULT STDMETHODCALLTYPE OnSample(DWORD dwOutputNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer __RPC_FAR *pSample, void __RPC_FAR *pvContext);
/* IWMReaderCallbackAdvanced */
HRESULT STDMETHODCALLTYPE OnStreamSample(WORD wStreamNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer *pSample, void *pvContext);
HRESULT STDMETHODCALLTYPE OnTime(QWORD cnsCurrentTime, void *pvContext);
HRESULT STDMETHODCALLTYPE OnStreamSelection(WORD wStreamCount, WORD *pStreamNumbers, WMT_STREAM_SELECTION *pSelections, void *pvContext);
HRESULT STDMETHODCALLTYPE OnOutputPropsChanged(DWORD dwOutputNum, WM_MEDIA_TYPE *pMediaType, void *pvContext);
HRESULT STDMETHODCALLTYPE AllocateForStream(WORD wStreamNum, DWORD cbBuffer, INSSBuffer **ppBuffer, void *pvContext);
HRESULT STDMETHODCALLTYPE AllocateForOutput(DWORD dwOutputNum, DWORD cbBuffer, INSSBuffer **ppBuffer, void *pvContext);
/* IWMCredentialCallback */
HRESULT STDMETHODCALLTYPE AcquireCredentials(WCHAR* pwszRealm, WCHAR* pwszSite, WCHAR* pwszUser, DWORD cchUser, WCHAR* pwszPassword, DWORD cchPassword, HRESULT hrStatus, DWORD* pdwFlags);
long refCount;
WMHandler *handler;
};
#endif
+649
View File
@@ -0,0 +1,649 @@
#include "Main.h"
#include "WMDRMModule.h"
#include "AutoWide.h"
#include "WMInformation.h"
#include "AutoChar.h"
#include "FileInfoDialog.h"
#include "ConfigDialog.h"
#include "resource.h"
#include "StatusHook.h"
#include "../nu/Config.h"
#include "util.h"
#include "WMPlaylist.h"
#include "api.h"
#include "output/OutPlugin.h"
#include "output/AudioOut.h"
#include <strsafe.h>
extern Nullsoft::Utility::Config wmConfig;
#define SAMPLES_PER_BLOCK 576
AudioOut *out = 0;
unsigned long endTime = 0;
unsigned long startTime = 0;
void InitOutputs(HWND hMainWindow, HMODULE hDllInstance)
{}
void WMDRM::AssignOutput()
{
out = &pluginOut;
}
WMDRM::WMDRM()
: paused(false),
clock(0), audio(0), video(0), wait(0), info(0), buffer(0), seek(0), reader(NULL), gain(0),
killswitch(0), opened(false),
drmProtected(false),
volume(-666), pan(0),
reader2(0), network(0), playing(false),
startAtMilliseconds(0),
dspBuffer(0),
vizBuffer(0),
reader1(0),
flushed(false)
{
killswitch = CreateEvent(NULL, TRUE, TRUE, NULL);
}
WMDRM::~WMDRM()
{
DeleteObject(killswitch);
delete [] dspBuffer;
delete [] vizBuffer;
}
static int winampVersion=0;
#define WINAMP_VERSION_MINOR1(winampVersion) ((winampVersion & 0x000000F0)>>4) // returns, i.e. 0x01 for 5.12 and 0x02 for 5.2...
#define WINAMP_VERSION_MINOR2(winampVersion) ((winampVersion & 0x0000000F)) // returns, i.e. 0x02 for 5.12 and 0x00 for 5.2...
static void MakeVersionString(QWORD *ver)
{
if (!winampVersion)
winampVersion = (int)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION);
LARGE_INTEGER temp;
temp.HighPart = MAKELONG(WINAMP_VERSION_MINOR1(winampVersion), WINAMP_VERSION_MAJOR(winampVersion));
temp.LowPart = MAKELONG(WASABI_API_APP->main_getBuildNumber(), WINAMP_VERSION_MINOR2(winampVersion));
*ver = temp.QuadPart;
}
static void MakeUserAgentString(wchar_t str[256])
{
if (!winampVersion)
winampVersion = (int)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION);
StringCchPrintfW(str, 256, L"WinampASF/%01x.%02x",
WINAMP_VERSION_MAJOR(winampVersion),
WINAMP_VERSION_MINOR(winampVersion));
}
void WMDRM::InitWM()
{
static int triedInit = 0;
if (!triedInit)
{
if (FAILED(WMCreateReader(0, WMT_RIGHT_PLAYBACK, &reader)) || !reader)
{
reader = 0;
plugin.FileExtensions = "\0";
return ;
}
if (FAILED(reader->QueryInterface(&reader1)))
reader1 = 0;
if (FAILED(reader->QueryInterface(&reader2)))
reader2 = 0;
if (FAILED(reader->QueryInterface(&network)))
network = 0;
if (reader1)
{
QWORD verStr;
wchar_t userAgent[256] = {0};
MakeVersionString(&verStr);
MakeUserAgentString(userAgent);
WM_READER_CLIENTINFO info;
ZeroMemory(&info, sizeof(WM_READER_CLIENTINFO));
info.cbSize = sizeof(WM_READER_CLIENTINFO);
info.wszHostExe = L"winamp.exe";
info.qwHostVersion = verStr;
info.wszPlayerUserAgent = userAgent;
info.wszBrowserWebPage = L"http://www.winamp.com";
reader1->SetClientInfo(&info);
}
clock = new ClockLayer(reader);
audio = new AudioLayer(reader);
video = new VideoLayer(reader);
wait = new WaitLayer(reader);
info = new WMInformation(reader);
buffer = new BufferLayer(reader);
seek = new SeekLayer(reader, clock);
gain = new GainLayer(audio, info);
callback >> seek >> buffer >> clock >> video >> audio >> wait >> gain >> this;
triedInit = 1;
}
}
void WMDRM::Init()
{
winampVersion = (int)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION);
InitOutputs(plugin.hMainWindow, plugin.hDllInstance);
//Hook(plugin.hMainWindow);
}
void WMDRM::Config(HWND hwndParent)
{
WASABI_API_DIALOGBOXW(IDD_CONFIG, hwndParent, PreferencesDialogProc);
}
void WMDRM::Quit()
{
activePlaylist.Clear();
delete setFileInfo; setFileInfo = 0;
delete clock; clock = 0;
delete audio; audio = 0;
delete video; video = 0;
delete wait; wait = 0;
delete info; info = 0;
delete buffer; buffer = 0;
delete seek; seek = 0;
if (network) network->Release(); network = 0;
if (reader2) reader2->Release(); reader2 = 0;
if (reader1) reader1->Release(); reader1 = 0;
if (reader) reader->Release(); reader = 0;
// Unhook(plugin.hMainWindow);
}
static void BuildTitle(WMInformation *info, const wchar_t *file, wchar_t *str, size_t len)
{
if (info)
{
wchar_t artist[256] = L"", title[256] = L"";
info->GetAttribute(g_wszWMAuthor, artist, 256);
info->GetAttribute(g_wszWMTitle, title, 256);
if (!artist[0] && !title[0])
{
if (file && *file)
{
StringCchCopy(str, len, file);
}
}
else if (artist[0] && title[0])
StringCchPrintf(str, len, L"%s - %s", artist, title);
else if (artist[0])
StringCchCopy(str, len, artist);
else if (title[0])
StringCchCopy(str, len, title);
}
else if (file)
StringCchCopy(str, len, file);
}
void WMDRM::GetFileInfo(const wchar_t *file, wchar_t *title, int *length_in_ms)
{
InitWM();
if (length_in_ms) *length_in_ms = -1000;
if (file && file[0])
{
bool isURL = !!PathIsURL(file);
if (config_http_metadata || !isURL)
{
WMInformation getFileInfo(file, true);
if (title)
{
BuildTitle(&getFileInfo, file, title, GETFILEINFO_TITLE_LENGTH);
}
if (length_in_ms) *length_in_ms = getFileInfo.GetLengthMilliseconds();
}
else
{
if (title)
StringCchCopy(title, GETFILEINFO_TITLE_LENGTH, file);
}
winamp.GetStatus(title, 256, file);
}
else if (activePlaylist.GetFileName())
{
//isURL = !!wcsstr(activePlaylist.GetFileName(), L"://");
if (wait && !wait->IsOpen()) // if it's not open, fill in with some default data... WMDRM::Opened() will refresh the title ...
{
StringCchCopy(title, GETFILEINFO_TITLE_LENGTH, activePlaylist.GetOriginalFileName());
if (length_in_ms) *length_in_ms = -1000;
//if (isURL)
winamp.GetStatus(title, 256, activePlaylist.GetOriginalFileName());
return ;
}
if (title)
{
BuildTitle(info, activePlaylist.GetOriginalFileName(), title, GETFILEINFO_TITLE_LENGTH);
}
if (info)
if (length_in_ms) *length_in_ms = info->GetLengthMilliseconds();
else
if (length_in_ms) *length_in_ms = -1000;
//if (isURL)
winamp.GetStatus(title, 256, activePlaylist.GetOriginalFileName());
}
}
int WMDRM::InfoBox(const wchar_t *fn, HWND hwndParent)
{
/* CUT> we're now using the unified file info dialogue
FileInfoDialog dialog(WASABI_API_LNG_HINST, hwndParent, fn);
if (dialog.WasEdited())
return 0;
else
return 1;
*/
return 0;
}
int WMDRM::IsOurFile(const in_char *fn)
{
// if (!reader)
// return 0;
if (wcsstr(fn, L".asx")) // TODO: need something WAY better than this
return 1;
return fileTypes.IsSupportedURL(fn);
}
int WMDRM::Play(const wchar_t * fn)
{
InitWM();
if (!reader)
return -1;
if (network)
network->SetBufferingTime((QWORD)config_buffer_time*10000LL);
ResetEvent(killswitch);
wait->ResetForOpen();
activePlaylist.Clear();
activePlaylist.playlistFilename = _wcsdup(fn);
if (playlistManager->Load(fn, &activePlaylist) != PLAYLISTMANAGER_SUCCESS)
activePlaylist.OnFile(fn, 0, -1, 0); // add it manually (TODO: need a better way to do this)
winamp.GetVideoOutput();
playing = true;
startTime = winamp.GetStart() * 1000;
if (!startAtMilliseconds)
startAtMilliseconds = startTime;
endTime = winamp.GetEnd() * 1000;
clock->SetLastOutputTime(startAtMilliseconds); // normally 0, but set when metadata editor needs to stop / restart a file
AssignOutput();
clock->SetStartTimeMilliseconds(startAtMilliseconds); // normally 0, but set when metadata editor needs to stop / restart a file
startAtMilliseconds = 0;
return seek->Open(activePlaylist.GetFileName(), &callback);
}
void WMDRM::ReOpen()
{
if (opened)
seek->Stop();
seek->Open(activePlaylist.GetFileName(), &callback);
}
void WMDRM::Pause()
{
paused = true;
if (seek)
seek->Pause();
}
void WMDRM::UnPause()
{
paused = false;
if (seek)
seek->Unpause();
}
int WMDRM::IsPaused()
{
return (int)paused;
}
void WMDRM::Stop()
{
if (!playing)
return ;
playing = false;
SetEvent(killswitch);
if (paused)
UnPause();
if (seek)
seek->Stop();
}
void WMDRM::Closed()
{
opened = false;
WMHandler::Closed();
}
int WMDRM::GetLength()
{
if (info)
return info->GetLengthMilliseconds();
else
return 0;
}
int WMDRM::GetOutputTime()
{
if (!opened)
{
//if (winamp.bufferCount)
return winamp.bufferCount;
//return 0;
}
return clock->GetOutputTime();
}
void WMDRM::SetOutputTime(int time_in_ms)
{
if (startTime || endTime)
{
unsigned int seektime = time_in_ms;
if (endTime && seektime > endTime)
seektime = endTime;
if (startTime && seektime < startTime)
seektime = startTime;
seek->SeekTo(seektime);
return ;
}
seek->SeekTo(time_in_ms);
}
void WMDRM::SetVolume(int volume)
{
this->volume = volume;
if (out)
out->SetVolume(volume);
}
void WMDRM::SetPan(int pan)
{
this->pan = pan;
if (out)
out->SetPan(pan);
}
void WMDRM::EQSet(int on, char data[10], int preamp)
{}
void WMDRM::BuildBuffers()
{
remaining.Allocate(audio->AudioSamplesToBytes(SAMPLES_PER_BLOCK));
// TODO: check against old size
delete [] dspBuffer;
delete [] vizBuffer;
dspBuffer = new unsigned char[audio->AudioSamplesToBytes(SAMPLES_PER_BLOCK) * 2];
vizBuffer = new unsigned char[audio->AudioSamplesToBytes(SAMPLES_PER_BLOCK) * 2];
}
void WMDRM::AudioDataReceived(void *_data, unsigned long sizeBytes, DWORD timestamp)
{
// TODO: apply replaygain first
// but if we change bitdepth, we'll have to be careful about calling audio->AudioSamplesToBytes() and similiar functions
unsigned char *data = (unsigned char *)_data;
if (!remaining.Empty())
{
if (WaitForSingleObject(killswitch, 0) == WAIT_OBJECT_0)
{
remaining.Flush();
return ;
}
remaining.UpdatingWrite(data, sizeBytes);
if (remaining.Full())
{
OutputAudioSamples(remaining.GetData(), SAMPLES_PER_BLOCK, timestamp);
remaining.Flush();
}
}
long samplesLeft = audio->AudioBytesToSamples(sizeBytes);
while (samplesLeft)
{
if (WaitForSingleObject(killswitch, 0) == WAIT_OBJECT_0)
{
remaining.Flush();
return ;
}
if (samplesLeft >= SAMPLES_PER_BLOCK)
{
OutputAudioSamples(data, SAMPLES_PER_BLOCK, timestamp);
data += audio->AudioSamplesToBytes(SAMPLES_PER_BLOCK);
samplesLeft -= SAMPLES_PER_BLOCK;
}
else
{
unsigned long bytesLeft = audio->AudioSamplesToBytes(samplesLeft);
remaining.UpdatingWrite(data, bytesLeft);
samplesLeft = audio->AudioBytesToSamples(bytesLeft); // should always be 0
assert(samplesLeft == 0);
}
}
}
void WMDRM::QuantizedViz(void *data, long sizeBytes, DWORD timestamp)
{
if (drmProtected)
{
assert(sizeBytes == audio->Channels() *(audio->BitSize() / 8) * SAMPLES_PER_BLOCK);
memset(vizBuffer, 0, sizeBytes);
ptrdiff_t stride = audio->BitSize() / 8;
size_t position = stride - 1;
unsigned char *origData = (unsigned char *)data;
for (int i = 0;i < SAMPLES_PER_BLOCK*audio->Channels();i++) // winamp hardcodes this ...
{
vizBuffer[position] = (origData[position] & 0xFC); // 6 bits of precision, enough for viz.
position += stride;
}
plugin.SAAddPCMData((char *) vizBuffer, audio->Channels(), audio->ValidBits(), timestamp);
plugin.VSAAddPCMData((char *) vizBuffer, audio->Channels(), audio->ValidBits(), timestamp);
}
else
{
plugin.SAAddPCMData((char *) data, audio->Channels(), audio->ValidBits(), timestamp);
plugin.VSAAddPCMData((char *) data, audio->Channels(), audio->ValidBits(), timestamp);
}
}
long WMDRM::GetPosition()
{
if (!opened)
return 0;
return out->GetWrittenTime();
}
void WMDRM::OutputAudioSamples(void *data, long samples)
{
DWORD timestamp = out->GetWrittenTime();
OutputAudioSamples(data, samples, timestamp);
}
void WMDRM::OutputAudioSamples(void *data, long samples, DWORD &timestamp)
{
clock->SetLastOutputTime(timestamp);
timestamp += audio->AudioSamplesToMilliseconds(samples);
//clock->SetLastOutputTime(winamp.GetWrittenTime());
//in theory, we could check mod->dsp_isactive(), but that opens up a potential race condition ...
memcpy(dspBuffer, data, audio->AudioSamplesToBytes(samples));
int dspSize = samples;
if (!drmProtected)
dspSize = plugin.dsp_dosamples((short *)dspBuffer, samples, audio->BitSize(), audio->Channels(), audio->SampleRate());
dspSize = audio->AudioSamplesToBytes(dspSize);
if (samples == SAMPLES_PER_BLOCK)
QuantizedViz(dspBuffer, dspSize, timestamp);
while (out->CanWrite() <= dspSize)
{
if (WaitForSingleObject(killswitch, 10) == WAIT_OBJECT_0)
{
remaining.Flush();
return ;
}
}
out->Write((char *)dspBuffer, dspSize);
/*long bytesAvail = */out->CanWrite();
}
void WMDRM::Opened()
{
//winamp.ResetBuffering();
drmProtected = info->IsAttribute(g_wszWMProtected);
ResetEvent(killswitch);
if (!audio->IsOpen())
{
if (video->IsOpen())
{
winamp.SetStatus(WASABI_API_LNGSTRINGW(IDS_REALTIME));
clock->GoRealTime();
plugin.is_seekable = info->IsSeekable() ? 1 : 0;
winamp.SetAudioInfo(info->GetBitrate() / 1000, 0, 0);
//out->SetVolume( -666); // set default volume
}
else
{
// no audio or video!!
seek->Stop();
First().OpenFailed();
return ;
}
}
else
{
BuildBuffers();
plugin.is_seekable = info->IsSeekable() ? 1 : 0;
winamp.SetAudioInfo(info->GetBitrate() / 1000, audio->SampleRate() / 1000, audio->Channels());
out->SetVolume(volume); // set default volume
out->SetPan(pan);
winamp.SetVizInfo(audio->SampleRate(), audio->Channels());
}
opened = true;
winamp.ClearStatus();
reader->Start(clock->GetStartTime(), 0, 1.0f, NULL);
WMHandler::Opened();
}
void WMDRM::Started()
{
ResetEvent(killswitch);
winamp.ResetBuffering();
winamp.ClearStatus();
WMHandler::Started();
}
void WMDRM::EndOfFile()
{
if (audio->IsOpen())
{
if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0)
{
if (remaining.used)
{
OutputAudioSamples(remaining.GetData(), audio->AudioBytesToSamples(remaining.used));
remaining.Flush();
}
out->Write(0, 0);
while (out->IsPlaying())
{
if (WaitForSingleObject(killswitch, 10) == WAIT_OBJECT_0)
{
break;
}
}
}
}
// TODO: if we have a playlist, start the next track instead of telling winamp to go to the next track
if (playing)
winamp.EndOfFile();
WMHandler::EndOfFile();
}
void WMDRM::NewMetadata()
{
winamp.RefreshTitle();
WMHandler::NewMetadata();
}
void WMDRM::Error()
{
// wait 200 ms for the killswitch (aka hitting stop)
// this allows the user to hit "stop" and not have to continue cycling through songs if there are a whole bunch of bad/missing WMAs in the playlist
if (playing && WaitForSingleObject(killswitch, 200) != WAIT_OBJECT_0)
winamp.EndOfFile();
}
void WMDRM::OpenFailed()
{
if (playing && WaitForSingleObject(killswitch, 200) != WAIT_OBJECT_0) // wait 200 ms for the killswitch (see above notes)
winamp.EndOfFile();
}
void WMDRM::Stopped()
{
remaining.Flush();
WMHandler::Stopped();
}
void WMDRM::Kill()
{
SetEvent(killswitch);
WMHandler::Kill();
}
void WMDRM::NewSourceFlags()
{
plugin.is_seekable = info->IsSeekable() ? 1 : 0;
}
void WMDRM::Connecting()
{
winamp.SetStatus(WASABI_API_LNGSTRINGW(IDS_CONNECTING));
WMHandler::Connecting();
}
void WMDRM::Locating()
{
winamp.SetStatus(WASABI_API_LNGSTRINGW(IDS_LOCATING));
WMHandler::Locating();
}
void WMDRM::AccessDenied()
{
winamp.SetStatus(WASABI_API_LNGSTRINGW(IDS_ACCESS_DENIED));
if (playing && WaitForSingleObject(killswitch, 200) != WAIT_OBJECT_0) // wait 200 ms for the killswitch (see above notes)
winamp.PressStop();
}
+100
View File
@@ -0,0 +1,100 @@
#ifndef NULLSOFT_WMDRMMODULEH
#define NULLSOFT_WMDRMMODULEH
#include "Remaining.h"
#include <wmsdk.h>
// layers
#include "AudioLayer.h"
#include "VideoLayer.h"
#include "ClockLayer.h"
#include "WaitLayer.h"
#include "BufferLayer.h"
#include "SeekLayer.h"
#include "GainLayer.h"
#include "WMHandler.h"
#include "WMCallback.h"
#include "WMInformation.h"
class WMDRM : public WMHandler
{
public:
WMDRM();
~WMDRM();
void Config(HWND hwndParent);
void Init();
void Quit();
void GetFileInfo(const wchar_t *file, wchar_t *title, int *length_in_ms);
int InfoBox(const wchar_t *file, HWND hwndParent);
int IsOurFile(const wchar_t *fn);
int Play(const wchar_t *fn);
void Pause();
void UnPause();
int IsPaused();
void Stop();
int GetLength();
int GetOutputTime();
void SetOutputTime(int time_in_ms);
void SetVolume(int volume);
void SetPan(int pan);
int GetVolume() { return volume; }
int GetPan() { return pan; }
void EQSet(int on, char data[10], int preamp);
void BuildBuffers();
void OutputAudioSamples(void *data, long samples, DWORD&);
void OutputAudioSamples(void *data, long samples);
void QuantizedViz(void *data, long sizeBytes, DWORD);
long GetPosition();
void EndOfFile();
bool OpenVideo(int fourcc, int width, int height, bool flipped);
void ReOpen();
void NewSourceFlags();
// const char *GetFile() { return fn.c_str();}
bool playing;
int startAtMilliseconds;
void InitWM();
protected:
//WMHandler
void AudioDataReceived(void *_data, unsigned long sizeBytes, DWORD timestamp);
void Opened();
void NewMetadata();
void Closed();
void Started();
void Error();
void OpenFailed();
void Stopped();
void Kill();
BufferLayer *buffer;
ClockLayer *clock;
#ifndef NO_DRM
DRMLayer *drm;
#endif
AudioLayer *audio;
VideoLayer *video;
WaitLayer *wait;
SeekLayer *seek;
GainLayer *gain;
WMCallback callback;
IWMReader *reader;
IWMReaderAdvanced *reader1;
IWMReaderAdvanced2 *reader2;
IWMReaderNetworkConfig *network;
WMInformation *info;
Remaining remaining;
unsigned char *dspBuffer, *vizBuffer;
int volume, pan;
bool flushed, paused;
HANDLE killswitch;
bool opened;
bool drmProtected;
void Connecting();
void Locating();
void AssignOutput();
void AccessDenied();
};
#endif
+181
View File
@@ -0,0 +1,181 @@
#include "main.h"
#include <assert.h>
void WMHandler::OpenFailed()
{
if (next)
next->OpenFailed();
}
void WMHandler::ReOpen()
{
if (next)
next->ReOpen();
}
void WMHandler::Started()
{
if (next)
next->Started();
}
void WMHandler::Stopped()
{
if (next)
next->Stopped();
}
void WMHandler::PreRollComplete()
{
if (next)
next->PreRollComplete();
}
void WMHandler::EndOfFile()
{
if (next)
next->EndOfFile();
}
void WMHandler::Closed()
{
if (next)
next->Closed();
}
void WMHandler::BufferingStarted()
{
if (next)
next->BufferingStarted();
}
void WMHandler::BufferingStopped()
{
if (next)
next->BufferingStopped();
}
void WMHandler::NewMetadata()
{
if (next)
next->NewMetadata();
}
void WMHandler::Individualize()
{
if (next)
next->Individualize();
}
void WMHandler::SignatureState(WMT_DRMLA_TRUST *&state)
{
if (next)
next->SignatureState(state);
}
void WMHandler::NoRightsEx(WM_GET_LICENSE_DATA *&licenseData)
{
if (next)
next->NoRightsEx(licenseData);
}
void WMHandler::AcquireLicense(WM_GET_LICENSE_DATA *&licenseData)
{
if (next)
next->AcquireLicense(licenseData);
}
void WMHandler::AllocateOutput(long outputNum, long bufferSize, INSSBuffer *&buffer)
{
if (next)
next->AllocateOutput(outputNum, bufferSize, buffer);
}
void WMHandler::VideoCatchup(QWORD time)
{
if (next)
next->VideoCatchup(time);
}
void WMHandler::TimeToSync(QWORD timeStamp,__int64 &diff)
{
if (next)
next->TimeToSync(timeStamp, diff);
}
void WMHandler::Error()
{
if (next)
next->Error();
}
void WMHandler::LicenseRequired()
{
if (next)
next->LicenseRequired();
}
void WMHandler::NoRights(wchar_t *licenseData)
{
if (next)
next->NoRights(licenseData);
}
WMHandler::WMHandler() : next(0), prev(0)
{}
WMHandler::~WMHandler()
{
if (next)
next->prev = prev;
if (prev)
prev->next = next;
}
WMHandler &WMHandler::operator << (WMHandler &chain)
{
assert(chain.next == 0);
assert(prev == 0);
prev = &chain;
chain.next = this;
return chain;
}
WMHandler &WMHandler::operator >> (WMHandler &chain)
{
if (chain.prev)
{
operator >>(chain.prev);
return chain;
}
assert (next == 0);
assert (chain.prev == 0);
next = &chain;
chain.prev = this;
return chain;
}
WMHandler&WMHandler::operator << (WMHandler *chain)
{
return operator <<(*chain);
}
WMHandler &WMHandler::operator >> (WMHandler *chain)
{
return operator >>(*chain);
}
WMHandler &WMHandler::First()
{
if (prev)
return prev->First();
else
return *this;
}
+113
View File
@@ -0,0 +1,113 @@
#ifndef NULLSOFT_WMHANDLERH
#define NULLSOFT_WMHANDLERH
#include <wmsdk.h>
#define NEXT(x) { if (next) next->x; }
enum DRM_INDIVIDUALIZATION_STATUS {
INDI_UNDEFINED = 0x0000,
INDI_BEGIN = 0x0001,
INDI_SUCCEED = 0x0002,
INDI_FAIL = 0x0004,
INDI_CANCEL = 0x0008,
INDI_DOWNLOAD = 0x0010,
INDI_INSTALL = 0x0020
};
enum DRM_HTTP_STATUS {
HTTP_NOTINITIATED = 0,
HTTP_CONNECTING = 1,
HTTP_REQUESTING = 2,
HTTP_RECEIVING = 3,
HTTP_COMPLETED = 4
};
typedef struct _WMGetLicenseData {
DWORD dwSize;
HRESULT hr;
WCHAR* wszURL;
WCHAR* wszLocalFilename;
BYTE* pbPostData;
DWORD dwPostDataSize;
} WM_GET_LICENSE_DATA;
typedef struct _WMIndividualizeStatus {
HRESULT hr;
DRM_INDIVIDUALIZATION_STATUS enIndiStatus;
LPSTR pszIndiRespUrl;
DWORD dwHTTPRequest;
DRM_HTTP_STATUS enHTTPStatus;
DWORD dwHTTPReadProgress;
DWORD dwHTTPReadTotal;
} WM_INDIVIDUALIZE_STATUS;
class WMHandler //: public Chainable<WMHandler>
{
public:
WMHandler();
~WMHandler();
WMHandler &operator << (WMHandler &chain);
WMHandler &operator >> (WMHandler &chain);
WMHandler&operator << (WMHandler *chain);
WMHandler &operator >> (WMHandler *chain);
WMHandler &First();
virtual void Opened() NEXT(Opened())
virtual void OpenFailed();
virtual void ReOpen();
virtual void SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample)
NEXT(SampleReceived(timeStamp, duration, outputNum, flags, sample))
virtual void AudioDataReceived(void *data, unsigned long sizeBytes, DWORD timestamp)
NEXT(AudioDataReceived(data, sizeBytes, timestamp))
virtual void TimeReached(QWORD &timeReached) NEXT(TimeReached(timeReached))
virtual void NewSourceFlags() NEXT(NewSourceFlags())
virtual void HasVideo(bool &video) NEXT(HasVideo(video))
virtual void Started();
virtual void Stopped();
virtual void Stopping() NEXT(Stopping())
virtual void DRMExpired() NEXT(DRMExpired())
virtual void Error();
virtual void Kill() NEXT(Kill())
virtual void PreRollComplete();
virtual void EndOfFile();
virtual void Closed();
virtual void BufferingStarted();
virtual void BufferingStopped();
virtual void NewMetadata();
virtual void Connecting() NEXT(Connecting())
virtual void Locating() NEXT(Locating())
virtual void Individualize();
virtual void NeedsIndividualization() NEXT(NeedsIndividualization())
virtual void IndividualizeStatus(WM_INDIVIDUALIZE_STATUS *status) NEXT(IndividualizeStatus(status))
virtual void SignatureState(WMT_DRMLA_TRUST *&state);
virtual void NoRights(wchar_t *licenseData);
virtual void NoRightsEx(WM_GET_LICENSE_DATA *&licenseData);
virtual void AcquireLicense(WM_GET_LICENSE_DATA *&licenseData);
virtual void LicenseRequired();
virtual void BrowserClosed() NEXT(BrowserClosed())
virtual void LicenseAcquired() NEXT(LicenseAcquired())
virtual void AllocateOutput(long outputNum, long bufferSize, INSSBuffer *&buffer);
virtual void MonitorCancelled() NEXT(MonitorCancelled())
virtual void SilentCancelled() NEXT(SilentCancelled())
virtual void VideoCatchup(QWORD time);
virtual void TimeToSync(QWORD timeStamp, __int64 &diff);
virtual void OpenCalled() NEXT(OpenCalled())
virtual void InitPlaylistBurn() NEXT(InitPlaylistBurn())
virtual void AccessDenied() NEXT(AccessDenied())
private:
WMHandler *next, *prev;
};
#undef NEXT
#endif
@@ -0,0 +1,880 @@
#include "main.h"
#include "WMInformation.h"
#include "resource.h"
#include <exception>
#include <strsafe.h>
class AutoByte
{
public:
AutoByte(size_t bytes)
: data(0)
{
data = new BYTE[bytes];
}
~AutoByte()
{
if (data)
delete[] data;
data = 0;
}
operator void *()
{
return (void *)data;
}
BYTE *data;
};
static void StoreData(WMT_ATTR_DATATYPE type, BYTE *value, DWORD length, wchar_t *valueStr, size_t len)
{
switch (type)
{
case WMT_TYPE_DWORD:
StringCchPrintf(valueStr, len, L"%lu", *(DWORD *)value);
break;
case WMT_TYPE_STRING:
lstrcpyn(valueStr, (wchar_t *)value, len);
break;
case -1: // hack // if (attrName == L"WM/Text")
StringCchPrintf(valueStr, len, L"%s/%s", UserTextDescription(value, length), UserTextString(value, length));
break;
case WMT_TYPE_BINARY:
BinaryString(value, length, valueStr, len);
break;
case WMT_TYPE_BOOL:
if (*(BOOL *)value)
{
lstrcpyn(valueStr, L"True", len);
}
else
{
lstrcpyn(valueStr, L"False", len);
}
break;
case WMT_TYPE_QWORD:
StringCchPrintf(valueStr, len, L"%I64u", *(QWORD *)value);
break;
case WMT_TYPE_WORD:
StringCchPrintf(valueStr, len, L"%hu", *(WORD *)value);
break;
case WMT_TYPE_GUID:
GuidString(*(GUID *)value, valueStr, len);
break;
default:
WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,valueStr,len);
break;
}
}
WMInformation::WMInformation(const wchar_t *fileName, bool noBlock)
: editor(0), editor2(0), header(0), header3(0), reader(0), header2(0), openError(false)
{
if (fileName && fileName[0]
&& WMCreateEditor(&editor) == S_OK)
{
if (SUCCEEDED(editor->QueryInterface(&editor2)))
{
if (SUCCEEDED(editor2->OpenEx(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE)))
{
// good to go
editor2->QueryInterface(&header);
editor->QueryInterface(&header2);
editor2->QueryInterface(&header3);
return ;
}
}
else
{
editor2 = 0;
if (SUCCEEDED(editor->Open(fileName)))
{
// good to go
editor->QueryInterface(&header);
editor->QueryInterface(&header2);
editor->QueryInterface(&header3);
return ;
}
}
// can't open it through the metadata editor interface, let's open a reader
if (editor)
editor->Release();
editor = 0;
if (editor2)
editor2->Release();
editor2 = 0;
if (FAILED(WMCreateReader(0, WMT_RIGHT_PLAYBACK, &reader)))
{
reader = 0;
return ;
}
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
callback >> this;
if (FAILED(reader->Open(fileName, &callback, 0)))
{
reader->Release();
reader = 0;
return ;
}
if (noBlock)
WaitForEvent(hEvent, INFINITE);
else
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hEvent);
if (openError)
{
reader->Release();
reader = 0;
}
else
{
reader->QueryInterface(&header);
reader->QueryInterface(&header2);
reader->QueryInterface(&header3);
}
}
}
WMInformation::WMInformation(IWMReader *_reader)
: reader(0), // reader is if we create an internal reader, we don't want to save the passed one (so we don't close it on someone else :)
editor(0), editor2(0), header(0),
header3(0), header2(0),
openError(false), hEvent(NULL)
{
if (FAILED(_reader->QueryInterface(&header)))
header = 0;
if (FAILED(_reader->QueryInterface(&header2)))
header2 = 0;
if (FAILED(_reader->QueryInterface(&header3)))
header3 = 0; // this error is OK, we can deal with it.
}
/*
WMInformation::WMInformation(IWMSyncReader *reader)
: editor(0), editor2(0), header(0), header3(0)
{
reader->QueryInterface(&header);
reader->QueryInterface(&header3);
}*/
WMInformation::WMInformation(IWMMetadataEditor *_editor)
: editor(_editor), editor2(0), header(0),
header3(0), reader(0), header2(0),
openError(false), hEvent(NULL)
{
editor->AddRef();
editor->QueryInterface(&editor2);
editor->QueryInterface(&header);
editor->QueryInterface(&header2);
editor->QueryInterface(&header3);
}
WMInformation::~WMInformation()
{
if (editor)
{
editor->Close();
editor->Release();
editor = 0;
}
if (editor2)
editor2->Release();
editor2 = 0;
if (header)
header->Release();
header = 0;
if (header2)
header2->Release();
header2 = 0;
if (header3)
header3->Release();
header3 = 0;
if (reader)
{
reader->Close();
reader->Release();
reader = 0;
}
}
bool WMInformation::GetDataType(const wchar_t *name, WMT_ATTR_DATATYPE &type)
{
if (!name)
return false;
WORD stream = 0;
WORD dataLen = 0;
if (header && SUCCEEDED(header->GetAttributeByName(&stream, name, &type, 0, &dataLen)))
return true;
else
return false;
}
void WMInformation::DeleteAttribute(const wchar_t *attrName)
{
WORD indexCount = 0;
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, attrName, NULL, 0, &indexCount)))
{
WORD *indices = new WORD[indexCount];
if (SUCCEEDED(header3->GetAttributeIndices(0, attrName, NULL, indices, &indexCount)))
{
for (size_t i = 0;i != indexCount;i++)
{
header3->DeleteAttribute(0, indices[i]);
}
}
}
}
void WMInformation::SetAttribute_BinString(const wchar_t *attrName, wchar_t *value)
{
if (!header || !attrName || !value)
return ;
if (!*value)
{
DeleteAttribute(attrName);
return ;
}
AutoChar data(value);
header->SetAttribute(0, attrName, WMT_TYPE_BINARY, (BYTE *)(char *)data, (WORD)strlen(data));
}
void WMInformation::GetAttribute_BinString(const wchar_t attrName[], wchar_t *valueStr, size_t len)
{
if (!header)
{
valueStr[0]=0;
return ;
}
WMT_ATTR_DATATYPE type;
WORD length = 0;
HRESULT hr;
WORD streamNum = 0;
if (!header || FAILED(header->GetAttributeByName(&streamNum,
attrName,
&type,
0,
&length)))
{
valueStr[0]=0;
return ;
}
AutoByte v(length);
BYTE *value = v.data;
hr = header->GetAttributeByName(&streamNum,
attrName,
&type,
value,
&length);
if (FAILED(hr))
{
valueStr[0]=0;
return ;
}
int converted = MultiByteToWideChar(CP_ACP, 0, (const char *)value, length, valueStr, len-1);
valueStr[converted]=0;
}
void WMInformation::SetAttribute(const wchar_t *attrName, wchar_t *value, WMT_ATTR_DATATYPE defaultType)
{
if (!header || !attrName || !value)
return ;
if (!*value)
{
DeleteAttribute(attrName);
return ;
}
WMT_ATTR_DATATYPE type;
if (!GetDataType(attrName, type))
type = defaultType;
switch (type)
{
case WMT_TYPE_DWORD:
{
DWORD dwordValue = wcstoul(value, 0, 10);
header->SetAttribute(0, attrName, WMT_TYPE_DWORD, (BYTE *) &dwordValue, sizeof(dwordValue));
}
break;
case WMT_TYPE_STRING:
{
WORD size = static_cast<WORD>((lstrlen(value) + 1) * sizeof(wchar_t));
header->SetAttribute(0, attrName, WMT_TYPE_STRING, (BYTE *)value, size);
}
break;
case WMT_TYPE_BINARY:
{
// TODO
}
break;
case WMT_TYPE_BOOL:
{
BOOL boolValue;
if (!_wcsicmp(L"true", value))
boolValue = TRUE;
else
boolValue = FALSE;
header->SetAttribute(0, attrName, WMT_TYPE_BOOL, (BYTE *)&boolValue, sizeof(boolValue));
}
break;
case WMT_TYPE_QWORD:
{
{
QWORD qwordValue = _wcstoui64(value, 0, 10);
header->SetAttribute(0, attrName, WMT_TYPE_QWORD, (BYTE *) &qwordValue, sizeof(qwordValue));
}
}
break;
case WMT_TYPE_WORD:
{
{
WORD wordValue = static_cast<WORD>(wcstoul(value, 0, 10));
header->SetAttribute(0, attrName, WMT_TYPE_WORD, (BYTE *) &wordValue, sizeof(wordValue));
}
}
break;
case WMT_TYPE_GUID:
{
GUID guidValue = StringGUID(value);
header->SetAttribute(0, attrName, WMT_TYPE_GUID, (BYTE *) &guidValue, sizeof(guidValue));
}
break;
}
}
bool WMInformation::GetAttributeSize(const wchar_t *name, size_t &size)
{
WORD stream = 0;
WORD resultSize;
WMT_ATTR_DATATYPE type;
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, 0, &resultSize)))
{
return false;
}
size = resultSize;
return true;
}
DWORD WMInformation::GetDWORDAttr(const wchar_t name[])
{
WORD stream = 0;
DWORD result;
WORD resultSizeWord = sizeof(result);
DWORD resultSize = sizeof(result);
WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD;
WORD count = 1;
WORD indices[1] = {0};
if ((!header3
|| FAILED(header3->GetAttributeIndices(0, name, NULL, indices, &count))
|| FAILED(header3->GetAttributeByIndexEx(0, indices[0], 0, 0, &type, NULL, (BYTE *) &result, &resultSize)))
&&
(!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSizeWord))))
return 0;
else
return result;
}
long WMInformation::GetLongAttr(const wchar_t name[])
{
WORD stream = 0;
long result;
WORD resultSize = sizeof(result);
WMT_ATTR_DATATYPE type;
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSize)))
{
return 0;
}
return result;
}
bool WMInformation::GetBoolAttr(const wchar_t name[])
{
WORD stream = 0;
BOOL result;
WORD resultSize = sizeof(result);
WMT_ATTR_DATATYPE type;
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSize)))
{
return false;
}
return !!result;
}
bool WMInformation::IsSeekable()
{
return GetBoolAttr(g_wszWMSeekable);
}
long WMInformation::GetLengthMilliseconds()
{
WORD stream = 0;
long long duration = 0;
WORD resultSize = sizeof(duration);
WMT_ATTR_DATATYPE type;
if (!header || FAILED(header->GetAttributeByName(&stream, g_wszWMDuration, &type, (BYTE *)&duration, &resultSize)))
{
return -1000;
}
duration /= 10000LL;
return (long)duration;
}
long WMInformation::GetBitrate()
{
return GetDWORDAttr(g_wszWMCurrentBitrate);
}
WORD WMInformation::GetNumberAttributes()
{
WORD numAttr = 0;
if ((!header3 || FAILED(header3->GetAttributeCountEx(0, &numAttr)))
&& (!header || FAILED(header->GetAttributeCount(0, &numAttr))))
return 0;
else
return numAttr;
}
void WMInformation::GetAttribute(WORD index, wchar_t *attrName, size_t attrLen, wchar_t *valueStr, size_t valueStrLen)
{
wchar_t _attrName[1025] = {0};
WORD nameLen = sizeof(_attrName) / sizeof(_attrName[0]);
WMT_ATTR_DATATYPE type;
WORD lang;
WORD stream = 0;
DWORD length = 0;
WORD lengthWord = 0;
if ((!header3 || FAILED(header3->GetAttributeByIndexEx(0, index, _attrName, &nameLen, &type, &lang, 0, &length)))
&& (!header || FAILED(header->GetAttributeByIndex(index, &stream, _attrName, &nameLen, &type, 0, &lengthWord))))
{
attrName[0]=0;
valueStr[0]=0;
return ;
}
if (lengthWord)
length = lengthWord;
AutoByte v(length);
BYTE *value = v.data;
lstrcpyn(attrName, _attrName, attrLen);
if ((!header3 || FAILED(header3->GetAttributeByIndexEx(0, index, _attrName, &nameLen, &type, &lang, value, &length)))
&& (!header || FAILED(header->GetAttributeByIndex(index, &stream, _attrName, &nameLen, &type, value, &lengthWord))))
{
attrName[0]=0;
valueStr[0]=0;
return ;
}
if (attrName == L"WM/Text")
{
type = (WMT_ATTR_DATATYPE)-1; // hack
StringCchCat(attrName, attrLen, L":");
StringCchCat(attrName, attrLen, UserTextDescription(value, length));
}
StoreData(type, value, length, valueStr, valueStrLen);
}
void WMInformation::GetAttribute(const wchar_t attrName[], wchar_t *valueStr, size_t len)
{
if (!header)
{
valueStr[0]=0;
return ;
}
WMT_ATTR_DATATYPE type;
WORD length = 0;
HRESULT hr;
WORD streamNum = 0;
if (!header || FAILED(header->GetAttributeByName(&streamNum,
attrName,
&type,
0,
&length)))
{
valueStr[0]=0;
return ;
}
AutoByte v(length);
BYTE *value = v.data;
hr = header->GetAttributeByName(&streamNum,
attrName,
&type,
value,
&length);
if (FAILED(hr))
{
valueStr[0]=0;
return ;
}
if (attrName == L"WM/Text")
type = (WMT_ATTR_DATATYPE)-1; // hack
StoreData(type, value, length, valueStr, len);
}
bool WMInformation::MakeWritable(const wchar_t *fileName)
{
if (!editor || !editor2)
return false;
if (FAILED(editor2->OpenEx(fileName, GENERIC_READ | GENERIC_WRITE, 0)))
{
return false;
}
return true;
}
bool WMInformation::Flush()
{
if (!editor2 || FAILED(editor->Flush()))
return false;
return true;
}
bool WMInformation::IsAttribute(const wchar_t attrName[])
{
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
WORD length = sizeof(BOOL);
WORD streamNum = 0;
BOOL value;
if (!header || FAILED(header->GetAttributeByName(&streamNum,
attrName,
&type,
(BYTE *)&value,
&length)))
{
return false;
}
else
{
return !!value;
}
}
bool WMInformation::IsNotAttribute(const wchar_t attrName[])
{
if (!header)
{
return false;
}
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
WORD length = sizeof(BOOL);
WORD streamNum = 0;
BOOL value;
if (!header || FAILED(header->GetAttributeByName(&streamNum,
attrName,
&type,
(BYTE *)&value,
&length)))
{
return false;
}
else
{
return !value;
}
}
bool WMInformation::MakeReadOnly(const wchar_t *fileName)
{
if (!editor || !editor2)
return false;
//editor->Close();
if (FAILED(editor2->OpenEx(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE)))
{
return false;
}
return true;
}
bool WMInformation::NonWritable()
{
if (!editor2)
return true;
else
return false;
}
void WMInformation::DeleteUserText(const wchar_t *description)
{
WORD indexCount = 0;
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
WORD nameLen = 128;
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, L"WM/Text", NULL, 0, &indexCount)))
{
WORD *indices = new WORD[indexCount];
if (SUCCEEDED(header3->GetAttributeIndices(0, L"WM/Text", NULL, indices, &indexCount)))
{
for (size_t index = 0;index != indexCount;index++)
{
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD lang = 0;
DWORD length = 0;
wchar_t _attrName[128] = L"WM/Text";
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
{
AutoByte v(length);
BYTE *value = v.data;
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
{
if (UserTextDescription(value, length) == description)
{
header3->DeleteAttribute(0, indices[index]);
}
}
}
}
}
}
}
void WMInformation::SetUserText(const wchar_t *description, const wchar_t *valueStr)
{
if (!header3 || !description || !valueStr)
return;
WM_USER_TEXT userText;
userText.pwszDescription = (LPWSTR)description;
userText.pwszText = (LPWSTR) valueStr;
WORD index;
header3->AddAttribute(0, L"WM/Text", &index, WMT_TYPE_BINARY, 0, (BYTE *) &userText, sizeof(userText));
}
void WMInformation::ClearAllAttributes()
{
WORD numAttrs;
header3->GetAttributeCountEx(0xFFFF, &numAttrs);
while (numAttrs--)
{
header3->DeleteAttribute(0xFFFF, numAttrs);
}
}
bool WMInformation::GetCodecName(wchar_t *storage, size_t len)
{
if (!header2)
return false;
DWORD codecs=0;
header2->GetCodecInfoCount(&codecs);
for (DWORD i=0;i!=codecs;i++)
{
WORD nameLen=0, descriptionLen=0, infoLen = 0;
WMT_CODEC_INFO_TYPE type;
header2->GetCodecInfo(i, &nameLen, 0, &descriptionLen, 0, &type, &infoLen, 0);
if (type == WMT_CODECINFO_AUDIO)
{
wchar_t *name = new wchar_t[nameLen];
wchar_t *description = new wchar_t[descriptionLen];
BYTE *info = new BYTE[infoLen];
header2->GetCodecInfo(i, &nameLen, name, &descriptionLen, description, &type, &infoLen, info);
lstrcpynW(storage, name, len);
delete[] name;
delete[]description;
delete[] info;
return true;
}
}
return false;
}
bool WMInformation::GetPicture(void **data, size_t *len, wchar_t **mimeType, int pictype)
{
WORD indexCount = 0;
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD nameLen = 128;
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
{
WORD *indices = new WORD[indexCount];
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
{
for (size_t index = 0;index != indexCount;index++)
{
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD lang = 0;
DWORD length = 0;
wchar_t _attrName[128] = {0};
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
{
AutoByte v(length);
BYTE *value = v.data;
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
{
WM_PICTURE *picture = (WM_PICTURE *)value;
if (picture->bPictureType == pictype)
{
*len = picture->dwDataLen;
*data = WASABI_API_MEMMGR->sysMalloc(*len);
memcpy(*data, picture->pbData, *len);
wchar_t *type=0;
if (picture->pwszMIMEType)
type = wcschr(picture->pwszMIMEType, L'/');
if (type && *type)
{
type++;
wchar_t *type2 = wcschr(type, L'/');
if (type2 && *type2) type2++;
else type2 = type;
size_t mimelen = wcslen(type2)+1;
*mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(mimelen*sizeof(wchar_t));
StringCchCopyW(*mimeType, mimelen, type2);
}
else
*mimeType = 0; // unknown!
delete[] indices;
return true;
}
}
}
}
}
delete[] indices;
}
return false;
}
bool WMInformation::SetPicture(void *data, size_t len, const wchar_t *mimeType, int type)
{
WM_PICTURE picture;
picture.bPictureType = type;
picture.dwDataLen = len;
picture.pbData = (BYTE *)data;
picture.pwszDescription=L"";
wchar_t mt[32] = {0};
if (wcsstr(mimeType, L"/") != 0)
{
StringCchCopyW(mt, 32, mimeType);
}
else
{
StringCchPrintfW(mt, 32, L"image/%s", mimeType);
}
picture.pwszMIMEType = mt;
return SUCCEEDED(header->SetAttribute(0, g_wszWMPicture, WMT_TYPE_BINARY, (const BYTE *)&picture, sizeof(picture)));
}
bool WMInformation::HasPicture(int pictype)
{
WORD indexCount = 0;
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD nameLen = 128;
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
{
WORD *indices = new WORD[indexCount];
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
{
for (size_t index = 0;index != indexCount;index++)
{
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD lang = 0;
DWORD length = 0;
wchar_t _attrName[128] = {0};
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
{
AutoByte v(length);
BYTE *value = v.data;
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
{
WM_PICTURE *picture = (WM_PICTURE *)value;
if (picture->bPictureType == pictype)
{
delete[] indices;
return true;
}
}
}
}
}
delete[] indices;
}
return false;
}
bool WMInformation::DeletePicture(int pictype)
{
WORD indexCount = 0;
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD nameLen = 128;
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
{
WORD *indices = new WORD[indexCount];
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
{
for (size_t index = 0;index != indexCount;index++)
{
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
WORD lang = 0;
DWORD length = 0;
wchar_t _attrName[128] = {0};
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
{
AutoByte v(length);
BYTE *value = v.data;
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
{
WM_PICTURE *picture = (WM_PICTURE *)value;
if (picture->bPictureType == pictype)
{
header3->DeleteAttribute(0, indices[index]);
delete[] indices;
return true;
}
}
}
}
}
delete[] indices;
}
return false;
}
@@ -0,0 +1,89 @@
#ifndef NULLSOFT_WMINFORMATIONH
#define NULLSOFT_WMINFORMATIONH
#include <wmsdk.h>
#include "WMCallback.h"
class WMInformation : public WMHandler
{
public:
WMInformation(const wchar_t *fileName, bool noBlock=false);
WMInformation(IWMReader *reader);
//WMInformation(IWMSyncReader *reader);
WMInformation(IWMMetadataEditor *_editor);
//WMInformation();
bool ErrorOpening()
{
return openError;
} // TODO: benski> this is only valid for WMInformation(const wchar_t *fileName, bool noBlock=false)!!!
virtual ~WMInformation();
bool MakeWritable(const wchar_t *fileName);
bool NonWritable();
bool MakeReadOnly(const wchar_t *fileName);
bool Flush();
bool IsSeekable();
long GetLengthMilliseconds();
long GetBitrate();
WORD GetNumberAttributes();
void ClearAllAttributes();
bool IsAttribute(const wchar_t attrName[]); // false might mean "attribute not found", see IsNotAttribute
bool IsNotAttribute(const wchar_t attrName[]); // false might mean "attribute not found", see IsAttribute
void GetAttribute(WORD index, wchar_t *attrName, size_t attrLen, wchar_t *valueStr, size_t valueStrLen);
void GetAttribute(const wchar_t attrName[], wchar_t *valueStr, size_t len);
void SetAttribute(const wchar_t *attrName, wchar_t *value, WMT_ATTR_DATATYPE defaultType = WMT_TYPE_STRING);
void DeleteAttribute(const wchar_t *attrName);
bool GetAttributeSize(const wchar_t *attrName, size_t &size);
void LicenseRequired()
{
First().OpenFailed();
}
void SetAttribute_BinString(const wchar_t *attrName, wchar_t *value);
void GetAttribute_BinString(const wchar_t attrName[], wchar_t *valueStr, size_t len);
void DeleteUserText(const wchar_t *description);
void SetUserText(const wchar_t *description, const wchar_t *valueStr);
bool GetCodecName(wchar_t *storage, size_t len);
bool GetPicture(void **data, size_t *len, wchar_t **mimeType, int type);
bool SetPicture(void *data, size_t len, const wchar_t *mimeType, int type);
bool DeletePicture(int type);
bool HasPicture(int type);
private:
bool GetDataType(const wchar_t *name, WMT_ATTR_DATATYPE &type);
long GetLongAttr(const wchar_t name[]);
bool GetBoolAttr(const wchar_t name[]);
DWORD GetDWORDAttr(const wchar_t name[]);
struct IWMMetadataEditor *editor;
struct IWMMetadataEditor2 *editor2;
struct IWMHeaderInfo *header;
struct IWMHeaderInfo2 *header2;
struct IWMHeaderInfo3 *header3;
struct IWMReader *reader;
WMCallback callback;
HANDLE hEvent;
bool openError;
void NeedsIndividualization()
{
First().OpenFailed();
}
void Opened()
{
openError=false;
SetEvent(hEvent);
}
void OpenFailed()
{
openError=true;
SetEvent(hEvent);
}
void Error()
{
openError=true;
SetEvent(hEvent);
}
};
#endif
@@ -0,0 +1,45 @@
#include "main.h"
#include "WMPlaylist.h"
WMPlaylist activePlaylist;
void WMPlaylist::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
{
//if (playstring.empty())
if ( playstring )
free( playstring );
playstring = _wcsdup( filename );
}
const wchar_t *WMPlaylist::GetFileName()
{
return ( playstring ? playstring : L"" );
}
const wchar_t *WMPlaylist::GetOriginalFileName()
{
return ( playlistFilename ? playlistFilename : L"" );
}
bool WMPlaylist::IsMe( const char *filename )
{
return IsMe( (const wchar_t *)AutoWide( filename ) );
}
bool WMPlaylist::IsMe( const wchar_t *filename )
{
if ( playlistFilename && !_wcsicmp( playlistFilename, filename ) )
return true;
if ( playstring && !_wcsicmp( playstring, filename ) )
return true;
return false;
}
#define CBCLASS WMPlaylist
START_DISPATCH;
VCB( IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile )
END_DISPATCH;
#undef CBCLASS
+56
View File
@@ -0,0 +1,56 @@
#ifndef NULLSOFT_IN_WMVDRM_WMPLAYLIST_H
#define NULLSOFT_IN_WMVDRM_WMPLAYLIST_H
#include "../playlist/ifc_playlistloadercallback.h"
class WMPlaylist : public ifc_playlistloadercallback
{
public:
WMPlaylist() {}
~WMPlaylist()
{
if ( playstring )
free( playstring );
if ( playlistFilename )
free( playlistFilename );
}
void Clear()
{
if ( playstring )
free( playstring );
playstring = 0;
if ( playlistFilename )
free( playlistFilename );
playlistFilename = 0;
}
void OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
const wchar_t *GetFileName();
const wchar_t *GetOriginalFileName();
/* TODO: need something like these, just not sure exact what yet
bool ForceStartTime(int &);
bool ForceLength(int &);
bool ForceNoSeek();
*/
bool IsMe( const char *filename );
bool IsMe( const wchar_t *filename );
protected:
RECVS_DISPATCH;
public:
wchar_t *playstring = 0;
wchar_t *playlistFilename = 0;
};
extern WMPlaylist activePlaylist;
#endif // !NULLSOFT_IN_WMVDRM_WMPLAYLIST_H
+128
View File
@@ -0,0 +1,128 @@
#include "main.h"
#include "WPLLoader.h"
#include <stdio.h>
#include "../nu/AutoWide.h"
#include "../xml/ifc_xmlreadercallback.h"
#include "../xml/obj_xml.h"
#include "api.h"
#include <api/service/waservicefactory.h>
#include <shlwapi.h>
#include <strsafe.h>
class WPLXML : public ifc_xmlreadercallback
{
public:
WPLXML(ifc_playlistloadercallback *_playlist, const wchar_t *wplFilename) : playlist(_playlist)
{
lstrcpynW(rootPath, wplFilename, MAX_PATH);
PathRemoveFileSpecW(rootPath);
}
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
{
//not necessary YET, it will be if we register for more things: if (!_wcsicmp(xmlpath, L"smil\fbody\fseq\fmedia"))
{
const wchar_t *track = params->getItemValue(L"src");
if (track)
{
if (PathIsRootW(track) || PathIsURLW(track))
{
playlist->OnFile(track, 0, -1, 0); // TODO: more info!!!
}
else
{
wchar_t fullPath[MAX_PATH] = {0}, canonicalizedPath[MAX_PATH] = {0};
PathCombineW(fullPath, rootPath, track);
PathCanonicalizeW(canonicalizedPath, fullPath);
playlist->OnFile(canonicalizedPath, 0, -1, 0); // TODO: more info!!!
}
}
}
}
ifc_playlistloadercallback *playlist;
wchar_t rootPath[MAX_PATH];
protected:
RECVS_DISPATCH;
};
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS WPLXML
START_DISPATCH;
VCB(ONSTARTELEMENT, StartTag)
END_DISPATCH;
WPLLoader::WPLLoader()
{
}
WPLLoader::~WPLLoader(void)
{
//Close();
}
int WPLLoader::Load(const wchar_t *filename, ifc_playlistloadercallback *playlist)
{
HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (file == INVALID_HANDLE_VALUE)
return IFC_PLAYLISTLOADER_FAILED;
obj_xml *parser=0;
waServiceFactory *parserFactory=0;
parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
if (parserFactory)
parser = (obj_xml *)parserFactory->getInterface();
if (parser)
{
WPLXML wplXml(playlist, filename);
parser->xmlreader_registerCallback(L"smil\fbody\fseq\fmedia", &wplXml);
parser->xmlreader_open();
parser->xmlreader_setEncoding(L"UTF-8"); // WPL is always UTF-8, but doesn't explicitly have it
while (true)
{
char data[1024] = {0};
DWORD bytesRead = 0;
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
{
if (parser->xmlreader_feed(data, bytesRead) != API_XML_SUCCESS)
{
CloseHandle(file);
parser->xmlreader_unregisterCallback(&wplXml);
parser->xmlreader_close();
parserFactory->releaseInterface(parser);
return IFC_PLAYLISTLOADER_FAILED;
}
}
else
break;
}
CloseHandle(file);
parser->xmlreader_feed(0, 0);
parser->xmlreader_unregisterCallback(&wplXml);
parser->xmlreader_close();
parserFactory->releaseInterface(parser);
return IFC_PLAYLISTLOADER_SUCCESS;
}
CloseHandle(file);
return IFC_PLAYLISTLOADER_FAILED;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS WPLLoader
START_DISPATCH;
CB(IFC_PLAYLISTLOADER_LOAD, Load)
END_DISPATCH;
+19
View File
@@ -0,0 +1,19 @@
#ifndef NULLSOFT_PLAYLIST_WPL_LOADER_H
#define NULLSOFT_PLAYLIST_WPL_LOADER_H
#include "../playlist/ifc_playlistloader.h"
#include "../playlist/ifc_playlistloadercallback.h"
#include <stdio.h>
class WPLLoader : public ifc_playlistloader
{
public:
int Load(const wchar_t *filename, ifc_playlistloadercallback *playlist);
public:
WPLLoader();
virtual ~WPLLoader(void);
protected:
RECVS_DISPATCH;
};
#endif
+49
View File
@@ -0,0 +1,49 @@
#include "main.h"
#include "WaitLayer.h"
#include "util.h"
WaitLayer::WaitLayer(IWMReader *_reader)
: reader(_reader), stopEvent(0)
{
reader->AddRef();
openEvent = CreateEvent(0, TRUE, FALSE, 0);
}
WaitLayer::~WaitLayer()
{
reader->Release();
reader=0;
}
void WaitLayer::Opened()
{
SetEvent(openEvent);
WMHandler::Opened();
}
bool WaitLayer::IsOpen()
{
return WaitForSingleObject(openEvent, 0) == WAIT_OBJECT_0;
}
void WaitLayer::OpenCalled()
{
SetEvent(openEvent);
WMHandler::OpenCalled();
}
void WaitLayer::OpenFailed()
{
SetEvent(openEvent);
WMHandler::OpenFailed();
}
bool WaitLayer::WaitForOpen(int time_ms)
{
return WaitForSingleObject(openEvent, time_ms) == WAIT_OBJECT_0;
}
void WaitLayer::ResetForOpen()
{
ResetEvent(openEvent);
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef NULLSOFT_WAITLAYERH
#define NULLSOFT_WAITLAYERH
#include "WMHandler.h"
class WaitLayer : public WMHandler
{
public:
WaitLayer(IWMReader *_reader);
~WaitLayer();
void ResetForOpen();
bool WaitForOpen(int time_ms);
bool IsOpen();
protected:
/* inherited from WMCallback */
void OpenCalled();
void OpenFailed();
void Opened();
IWMReader *reader; // not ours
HANDLE stopEvent, openEvent;
};
#endif
@@ -0,0 +1,183 @@
#include "Main.h"
#include "WinampInterface.h"
#include "../Winamp/wa_ipc.h"
#include <cassert>
#include "WMDRMModule.h"
#include <strsafe.h>
#include "WMPlaylist.h"
#include "../nu/AutoChar.h"
WinampInterface winamp;
extern WMDRM mod;
using namespace Nullsoft::Utility;
#ifndef NO_DRM
#include "vid_overlay.h"
#include "vid_ddraw.h"
OverlayVideoOutput overlay;
DDrawVideoOutput ddraw;
#endif
WinampInterface::WinampInterface()
: videoWindow(0), bufferCount(0),
statusGuard(GUARDNAME("WinampInterface::statusGuard"))
{
statusFilename[0] = 0;
status[0] = 0;
}
/*
@returns winamp's video window handle
*/
HWND WinampInterface::GetVideoWindow()
{
return (HWND)GetVideoOutput()->extended(VIDUSER_GET_VIDEOHWND, 0, 0); // ask for the video hwnd
}
IVideoOutput *WinampInterface::GetVideoOutput()
{
if (!videoWindow)
videoWindow = (IVideoOutput *)SendMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_GET_IVIDEOOUTPUT); // ask winamp for an interface to the video output
return videoWindow;
}
void WinampInterface::EndOfFile()
{
PostMessage(GetWinampWindow(), WM_WA_MPEG_EOF, 0, 0);
}
HWND WinampInterface::GetWinampWindow()
{
return plugin.hMainWindow;
}
void WinampInterface::SetStatus(wchar_t *_status)
{
{
AutoLock lock (statusGuard);
StringCchCopy(status, 1024, _status);
StringCchCopy(statusFilename, FILENAME_SIZE, activePlaylist.GetFileName());
}
PostMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_UPDTITLE);
}
bool WinampInterface::GetStatus(wchar_t *title, size_t titleLen, const wchar_t *filename)
{
AutoLock lock (statusGuard);
if (status[0] && title && filename && !lstrcmpi(statusFilename, filename))
{
StringCchPrintf(title, titleLen, L"[%s]%s", status, filename);
return true;
}
else
return false;
}
bool WinampInterface::GetStatusHook(wchar_t *title, size_t titleLen, const wchar_t *filename)
{
AutoLock lock (statusGuard);
if (status[0] && title && filename && !lstrcmpi(statusFilename, filename))
{
wchar_t *oldTitle = _wcsdup(title);
StringCchPrintf(title, titleLen, L"[%s]%s", status, oldTitle);
free(oldTitle);
return true;
}
else
return false;
}
bool WinampInterface::HasStatus(const wchar_t *filename)
{
AutoLock lock (statusGuard);
if (status[0] && filename && !lstrcmpi(statusFilename, filename))
return true;
return false;
}
void WinampInterface::ClearStatus()
{
{
//AutoLock lock (statusGuard); // should be safe not to lock here
status[0] = 0;
statusFilename[0]=0;
}
PostMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_UPDTITLE);
}
void WinampInterface::EncryptedDrawFrame(void *frame)
{
#ifndef NO_DRM
overlay.SetFrame(frame);
ddraw.SetFrame(frame);
SecureZeroMemory(&frame, sizeof(void *));
GetVideoOutput()->draw((void *)1);
#endif
}
bool WinampInterface::OpenEncryptedVideo(int width, int height, bool flip, double aspect, int fourcc)
{
#ifndef NO_DRM
VideoOpenStruct openVideo = {width, height, flip, aspect, fourcc};
bool openedOK = false;
if (config_video.overlays())
{
openedOK = !!GetVideoOutput()->extended(VIDUSER_OPENVIDEORENDERER, (intptr_t)(VideoRenderer *)&overlay, (intptr_t)&openVideo);
if (openedOK)
return true;
}
openedOK = !!GetVideoOutput()->extended(VIDUSER_OPENVIDEORENDERER, (intptr_t)(VideoRenderer *)&ddraw, (intptr_t)&openVideo);
if (openedOK)
return true;
#endif
return false;
}
void WinampInterface::CloseEncryptedVideo()
{
GetVideoOutput()->extended(VIDUSER_CLOSEVIDEORENDERER, 0, 0);
}
void WinampInterface::Buffering(int bufStatus, const wchar_t *displayString)
{
char tempdata[75*2] = {0, };
int csa = plugin.SAGetMode();
if (csa & 1)
{
for (int x = 0; x < bufStatus*75 / 100; x ++)
tempdata[x] = x * 16 / 75;
}
else if (csa&2)
{
int offs = (csa & 1) ? 75 : 0;
int x = 0;
while (x < bufStatus*75 / 100)
{
tempdata[offs + x++] = -6 + x * 14 / 75;
}
while (x < 75)
{
tempdata[offs + x++] = 0;
}
}
else if (csa == 4)
{
tempdata[0] = tempdata[1] = (bufStatus * 127 / 100);
}
if (csa) plugin.SAAdd(tempdata, ++bufferCount, (csa == 3) ? 0x80000003 : csa);
wchar_t temp[64] = {0};
StringCchPrintf(temp, 64, L"%s: %d%%",displayString, bufStatus);
SetStatus(temp);
//SetVideoStatusText(temp); // TODO: find a way to set the old status back
GetVideoOutput()->notifyBufferState(static_cast<int>(bufStatus*2.55f));
}
@@ -0,0 +1,121 @@
#ifndef NULLSOFT_WINAMPINTERFACEH
#define NULLSOFT_WINAMPINTERFACEH
#include "Main.h"
#include <windows.h>
#include "../Winamp/wa_ipc.h"
#include "../Winamp/In2.h"
#include "../Winamp/strutil.h"
#include "output/AudioOut.h"
#include "../nu/AutoLock.h"
extern AudioOut *out;
extern In_Module plugin;
class WinampInterface
{
public:
WinampInterface();
HWND GetVideoWindow();
IVideoOutput *GetVideoOutput();
void EndOfFile();
HWND GetWinampWindow();
void RefreshTitle()
{
PostMessage(plugin.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
}
const char *GetProxy()
{
return (const char *)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_PROXY_STRING);
}
void ResetBuffering() { bufferCount=0;}
void Buffering(int bufStatus, const wchar_t *displayString);
bool OpenEncryptedVideo(int width, int height, bool flip, double aspect, int fourcc);
bool OpenVideo(int width, int height, bool flip, double aspect, int fourcc)
{
GetVideoOutput()->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
bool video = (GetVideoOutput()->open(width, height, flip ? 1 : 0, aspect, fourcc) == 0);
return video;
}
ULONG_PTR GetStart()
{
return SendMessage(plugin.hMainWindow, WM_WA_IPC,0,IPC_GETPLAYITEM_START);
}
ULONG_PTR GetEnd()
{
return SendMessage(plugin.hMainWindow, WM_WA_IPC,0,IPC_GETPLAYITEM_END);
}
void PressStop()
{
SendMessage(plugin.hMainWindow, WM_COMMAND, 40047, 0);
}
void PressPlay()
{
SendMessage(plugin.hMainWindow, WM_COMMAND,40045, 0);
}
void DrawFrame(void *frame)
{
GetVideoOutput()->draw(frame);
}
void EncryptedDrawFrame(void *frame);
void SetVideoStatusText(char *text)
{
GetVideoOutput()->extended(VIDUSER_SET_INFOSTRING,(INT_PTR)text,0);
}
void SetVideoPalette(RGBQUAD *palette)
{
GetVideoOutput()->extended(VIDUSER_SET_PALETTE,(INT_PTR)palette,0);
}
void CloseViz()
{
plugin.SAVSADeInit();
}
void CloseEncryptedVideo();
void CloseVideo()
{
GetVideoOutput()->close();
}
void SetAudioInfo(int bitRateKiloBits, int sampleRateKiloHertz, int channels)
{
plugin.SetInfo(bitRateKiloBits, sampleRateKiloHertz, channels, 1);
}
void OpenViz(int maxLatency, int sampleRate)
{
plugin.SAVSAInit(maxLatency, sampleRate);
}
void SetVizInfo(int sampleRate, int channels)
{
plugin.VSASetInfo(sampleRate, channels);
}
bool GetStatusHook(wchar_t *title, size_t titleLen, const wchar_t *filename);
bool HasStatus(const wchar_t *filename);
void SetStatus(wchar_t *_status);
bool GetStatus(wchar_t *title, size_t titleLen, const wchar_t *filename);
void ClearStatus();
Nullsoft::Utility::LockGuard statusGuard;
int bufferCount;
private:
wchar_t status[1024];
wchar_t statusFilename[FILENAME_SIZE];
IVideoOutput *videoWindow;
};
#endif
+45
View File
@@ -0,0 +1,45 @@
#include "main.h"
#include "XMLString.h"
#include <strsafe.h>
XMLString::XMLString()
{
data[0]=0;
}
void XMLString::Reset()
{
data[0]=0;
}
const wchar_t *XMLString::GetString()
{
return data;
}
void XMLString::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
{
data[0]=0;
}
void XMLString::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
{
StringCchCatW(data, 256, str);
}
void XMLString::ManualSet(const wchar_t *string)
{
StringCchCatW(data, 256, string);
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS XMLString
START_DISPATCH;
VCB(ONSTARTELEMENT, StartTag)
VCB(ONCHARDATA, TextHandler)
END_DISPATCH;
+29
View File
@@ -0,0 +1,29 @@
#ifndef NULLSOFT_WINAMP_XMLSTRING_H
#define NULLSOFT_WINAMP_XMLSTRING_H
#include "../xml/ifc_xmlreadercallback.h"
/*
this one is an xml callback that just saves the last encountered string
*/
class XMLString : public ifc_xmlreadercallback
{
public:
XMLString();
void Reset();
const wchar_t *GetString();
void ManualSet(const wchar_t *string);
private:
/* XML callbacks */
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag);
void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
wchar_t data[256]; // for now, we'll make it dynamic later
RECVS_DISPATCH;
};
#endif
+56
View File
@@ -0,0 +1,56 @@
#include "main.h"
#include "api.h"
#include <windows.h>
#include "../Winamp/wa_ipc.h"
#include "FactoryHelper.h"
#include "MetaTagFactory.h"
#include "factory_Handler.h"
#include "AlbumArt.h"
#include "RawReader.h"
#include "../nu/Singleton.h"
MetaTagFactory metaTagFactory;
api_service *serviceManager = 0;
api_playlistmanager *playlistManager=0;
api_config *AGAVE_API_CONFIG=0;
api_application *applicationApi=0;
// wasabi based services for localisation support
api_language *WASABI_API_LNG = 0;
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
api_memmgr *WASABI_API_MEMMGR = 0;
WPLHandlerFactory wplHandlerFactory;
ASXHandlerFactory asxHandlerFactory;
AlbumArtFactory albumArtFactory;
static RawMediaReaderService raw_media_reader_service;
static SingletonServiceFactory<svc_raw_media_reader, RawMediaReaderService> raw_factory;
int LoadWasabi()
{
ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
ServiceBuild(playlistManager, api_playlistmanagerGUID);
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
ServiceBuild(WASABI_API_LNG, languageApiGUID);
ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
plugin.service->service_register(&metaTagFactory);
plugin.service->service_register(&wplHandlerFactory);
plugin.service->service_register(&asxHandlerFactory);
plugin.service->service_register(&albumArtFactory);
raw_factory.Register(plugin.service, &raw_media_reader_service);
return TRUE;
}
void UnloadWasabi()
{
plugin.service->service_deregister(&metaTagFactory);
plugin.service->service_deregister(&wplHandlerFactory);
plugin.service->service_deregister(&asxHandlerFactory);
plugin.service->service_deregister(&albumArtFactory);
plugin.service->service_deregister(&raw_factory);
ServiceRelease(playlistManager, api_playlistmanagerGUID);
ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
ServiceRelease(WASABI_API_LNG, languageApiGUID);
ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef NULLSOFT_API_H
#define NULLSOFT_API_H
#include <windows.h>
int LoadWasabi();
void UnloadWasabi();
#include "../playlist/api_playlistmanager.h"
extern api_playlistmanager *playlistManager;
#define AGAVE_API_PLAYLISTMANAGER playlistManager
#include "../Agave/Config/api_config.h"
extern api_config *config;
#define AGAVE_API_CONFIG config
#include <api/application/api_application.h>
extern api_application *applicationApi;
#define WASABI_API_APP applicationApi
#include <api/memmgr/api_memmgr.h>
extern api_memmgr *memmgr;
#define WASABI_API_MEMMGR memmgr
#include "../Agave/Language/api_language.h"
// these are custom defines for the out_wave and out_ds embedded implementations
extern HINSTANCE WASABI_API_LNG_HINST_WAV, WASABI_API_LNG_HINST_WAV_ORIG;
extern HINSTANCE WASABI_API_LNG_HINST_DS, WASABI_API_LNG_HINST_DS_ORIG;
#define WASABI_API_LNGSTRING_WAV(uID) WASABI_API_LNGSTR(WASABI_API_LNG_HINST_WAV,WASABI_API_LNG_HINST_WAV_ORIG,uID)
#define WASABI_API_LNGSTRING_BUF_WAV(uID,buf,len) WASABI_API_LNGSTR(WASABI_API_LNG_HINST_WAV,WASABI_API_LNG_HINST_WAV_ORIG,uID,buf,len)
#define WASABI_API_LNGSTRINGW_WAV(uID) WASABI_API_LNGSTRW(WASABI_API_LNG_HINST_WAV,WASABI_API_LNG_HINST_WAV_ORIG,uID)
#define WASABI_API_LNGSTRINGW_BUF_WAV(uID,buf,len) WASABI_API_LNGSTRW(WASABI_API_LNG_HINST_WAV,WASABI_API_LNG_HINST_WAV_ORIG,uID,buf,len)
#define WASABI_API_LNGSTRING_DS(uID) WASABI_API_LNGSTR(WASABI_API_LNG_HINST_DS,WASABI_API_LNG_HINST_DS_ORIG,uID)
#define WASABI_API_LNGSTRING_BUF_DS(uID,buf,len) WASABI_API_LNGSTR(WASABI_API_LNG_HINST_DS,WASABI_API_LNG_HINST_DS_ORIG,uID,buf,len)
#define WASABI_API_LNGSTRINGW_DS(uID) WASABI_API_LNGSTRW(WASABI_API_LNG_HINST_DS,WASABI_API_LNG_HINST_DS_ORIG,uID)
#define WASABI_API_LNGSTRINGW_BUF_DS(uID,buf,len) WASABI_API_LNGSTRW(WASABI_API_LNG_HINST_DS,WASABI_API_LNG_HINST_DS_ORIG,uID,buf,len)
#endif
+118
View File
@@ -0,0 +1,118 @@
#define WM_DEFINE_CONFIG 1
#include "config.h"
#include "loadini.h"
#include "main.h"
#include "../nu/Config.h"
bool config_no_video = false;
extern Nullsoft::Utility::Config wmConfig;
#pragma warning(disable:4800)
#define READ(type, name) config_##name = (type)wmConfig.cfg_int(TEXT("config_") TEXT(#name), default_##name)
#define WRITE(type, name) wmConfig.cfg_int(TEXT("config_") TEXT(#name), default_##name) = (int)config_##name
#define DEFAULT(name) config_##name = default_##name
void ReadConfig()
{
READ(bool, lowmemory);
READ(bool, clock);
READ(bool, video_dedicated_thread);
READ(bool, video_early);
READ(int, video_early_pad);
READ(bool, video_outoforder);
READ(bool, video_catchup);
READ(int, video_jitter);
READ(int, video_drop_threshold);
READ(size_t, video_cache_frames);
READ(bool, video_notifylate);
READ(bool, video_framedropoffset);
READ(bool, audio_outoforder);
READ(bool, audio_dedicated_thread);
READ(int, audio_early_pad);
READ(bool, audio_early);
READ(size_t, audio_cache_frames);
READ(size_t, audio_num_channels);
// READ(bool, no_silent);
// READ(bool, untrusted_ok);
READ(bool, http_metadata);
READ(size_t, buffer_time);
READ(bool, extra_asx_extensions);
READ(int, col1);
READ(int, col2);
}
void WriteConfig()
{
WRITE(bool, lowmemory);
WRITE(bool, clock);
WRITE(bool, video_dedicated_thread);
WRITE(bool, video_early);
WRITE(int, video_early_pad);
WRITE(bool, video_outoforder);
WRITE(bool, video_catchup);
WRITE(int, video_jitter);
WRITE(int, video_drop_threshold);
WRITE(size_t, video_cache_frames);
WRITE(bool, video_notifylate);
WRITE(bool, video_framedropoffset);
WRITE(bool, audio_outoforder);
WRITE(bool, audio_dedicated_thread);
WRITE(int, audio_early_pad);
WRITE(bool, audio_early);
WRITE(size_t, audio_cache_frames);
WRITE(size_t, audio_num_channels);
// WRITE(bool, no_silent);
// WRITE(bool, untrusted_ok);
WRITE(bool, http_metadata);
WRITE(size_t, buffer_time);
WRITE(bool, extra_asx_extensions);
WRITE(int, col1);
WRITE(int, col2);
}
void DefaultConfig()
{
DEFAULT(http_metadata);
// DEFAULT(no_silent);
// DEFAULT(untrusted_ok);
DEFAULT(buffer_time);
DEFAULT(audio_num_channels);
DEFAULT(audio_outoforder);
DEFAULT(audio_dedicated_thread);
DEFAULT(audio_early_pad);
DEFAULT(audio_early);
DEFAULT(audio_cache_frames);
DEFAULT(lowmemory);
DEFAULT(clock);
DEFAULT(video_dedicated_thread);
DEFAULT(video_early);
DEFAULT(video_early_pad);
DEFAULT(video_outoforder);
DEFAULT(video_catchup);
DEFAULT(video_jitter);
DEFAULT(video_drop_threshold);
DEFAULT(video_cache_frames);
DEFAULT(video_notifylate);
DEFAULT(video_framedropoffset);
DEFAULT(extra_asx_extensions);
DEFAULT(col1);
DEFAULT(col2);
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef NULLSOFT_CONFIGH
#define NULLSOFT_CONFIGH
#include "dsound.h"
#ifdef WM_DEFINE_CONFIG
#define DEFVAL(x) =x
#define CFGEXTERN
#else
#define DEFVAL(x)
#define CFGEXTERN extern
#endif
#define CFG(type, name, defval) CFGEXTERN type config_##name DEFVAL(defval); CFGEXTERN type default_##name DEFVAL(defval);
CFG(bool, lowmemory, true);
CFG(bool, clock, true);
CFG(bool, video_dedicated_thread, true);
CFG(bool, video_early, false);
CFG(int, video_early_pad, 500);
CFG(bool, video_outoforder, true);
CFG(bool, video_catchup, true);
CFG(int, video_jitter, 5);
CFG(int, video_drop_threshold, 15);
CFG(size_t, video_cache_frames, 16);
CFG(bool, video_notifylate, true);
CFG(bool, video_framedropoffset, false);
//CFG(bool, video_flip, false);
CFG(bool, audio_outoforder, false);
CFG(bool, audio_dedicated_thread, true);
CFG(int, audio_early_pad, 0);
CFG(bool, audio_early, false);
CFG(size_t, audio_cache_frames, 12);
CFG(DWORD, audio_num_channels, DSSPEAKER_5POINT1);
CFG(bool, no_silent, false);
CFG(bool, untrusted_ok, false);
CFG(bool, http_metadata, false);
CFG(size_t, buffer_time, 5000);
CFG(int, col1, -1);
CFG(int, col2, -1);
extern bool config_no_video;
CFG(bool, extra_asx_extensions, false);
void ReadConfig(), WriteConfig(), DefaultConfig();
#endif
@@ -0,0 +1,23 @@
#include "main.h"
#include "directdraw.h"
HRESULT (WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter) = 0;
HRESULT DDrawCreate(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter)
{
static int a = 0;
if (!_DirectDrawCreate && !a)
{
a++;
HINSTANCE h = LoadLibrary(L"ddraw.dll");
if (h)
{
*(void**)&_DirectDrawCreate = (void*)GetProcAddress(h, "DirectDrawCreate");
}
}
if (_DirectDrawCreate)
return _DirectDrawCreate(lpGUID, lplpDD, pUnkOuter);
else
return S_OK; // TODO: uhhh no this should be an error :)
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef NULLSOFT_DDRAWH
#define NULLSOFT_DDRAWH
#include <ddraw.h>
extern HRESULT (WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
HRESULT DDrawCreate(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
#endif
@@ -0,0 +1,80 @@
#include "main.h"
#include "api.h"
#include "factory_Handler.h"
#include "PlaylistHandler.h"
#include <api/service/services.h>
WPLHandler wplHandler;
ASXHandler asxHandler;
#define DEFINE_HANDLER_FACTORY(CLASSNAME, className) const char *CLASSNAME ## HandlerFactory::GetServiceName() { return #CLASSNAME ## "Playlist Handler"; }\
GUID CLASSNAME ## HandlerFactory::GetGUID(){ return className ## HandlerGUID;}\
void *CLASSNAME ## HandlerFactory::GetInterface(int global_lock){ return &className ## Handler;}
DEFINE_HANDLER_FACTORY(WPL, wpl);
DEFINE_HANDLER_FACTORY(ASX, asx);
/* --------------------------------------------------------------------- */
FOURCC CommonHandlerFactory::GetServiceType()
{
return WaSvc::PLAYLISTHANDLER;
}
int CommonHandlerFactory::SupportNonLockingInterface()
{
return 1;
}
int CommonHandlerFactory::ReleaseInterface(void *ifc)
{
return 1;
}
const char *CommonHandlerFactory::GetTestString()
{
return NULL;
}
int CommonHandlerFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#undef CBCLASS
#define CBCLASS WPLHandlerFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
#undef CBCLASS
#define CBCLASS CommonHandlerFactory
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
#undef CBCLASS
#define CBCLASS ASXHandlerFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
#undef CBCLASS
#define CBCLASS CommonHandlerFactory
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
@@ -0,0 +1,30 @@
#ifndef NULLSOFT_FACTORY_HANDLER_H
#define NULLSOFT_FACTORY_HANDLER_H
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class CommonHandlerFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
};
#define DECLARE_HANDLER_FACTORY(CLASSNAME) class CLASSNAME : public CommonHandlerFactory {\
public:\
const char *GetServiceName();\
GUID GetGUID();\
void *GetInterface(int global_lock);\
protected:\
RECVS_DISPATCH;}
DECLARE_HANDLER_FACTORY(ASXHandlerFactory);
DECLARE_HANDLER_FACTORY(WPLHandlerFactory);
#endif
+331
View File
@@ -0,0 +1,331 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 0, 0, 344, 142
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Windows Media Decoder Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "General",IDC_STATIC,4,4,156,59
CONTROL "Retrieve metadata for HTTP streams",IDC_HTTPMETA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,16,133,10
LTEXT "Streaming prebuffer: ",IDC_STATIC,10,30,70,8
EDITTEXT IDC_BUFFER_TIME,81,28,41,12,ES_AUTOHSCROLL
LTEXT "ms",IDC_STATIC,126,30,10,8
LTEXT "Speaker Configuration:",IDC_STATIC,10,43,75,12,SS_CENTERIMAGE
COMBOBOX IDC_AUDIO_SPEAKER_COUNT,88,43,66,83,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Advanced Settings",IDC_STATIC,4,67,156,52
LTEXT "Warning: For advanced users only!",IDC_STATIC,10,83,128,10
PUSHBUTTON "Advanced ...",IDC_ADVANCED,52,98,50,13
/* GROUPBOX "Protected Media",IDC_STATIC,4,80,156,42
CONTROL "Try to acquire licenses silently",IDC_SILENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,93,111,10
CONTROL "Always accept untrusted certificates",IDC_UNTRUSTED,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,106,133,10
*/
GROUPBOX "Filetypes",IDC_STATIC,164,4,176,134
CONTROL "",IDC_TYPELIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,172,17,161,85
PUSHBUTTON "Add ...",IDC_ADDTYPE,172,107,51,13
PUSHBUTTON "Edit ...",IDC_EDITTYPE,227,107,50,13
PUSHBUTTON "Remove",IDC_REMOVETYPE,281,107,52,13
CONTROL "Enable WAX/WMX/WVX playlist extensions",IDC_EXTRA_ASX,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,124,151,10
PUSHBUTTON "Save",IDOK,4,125,46,13
PUSHBUTTON "Cancel",IDCANCEL,54,125,48,13
PUSHBUTTON "Defaults",IDC_DEFAULTTYPE,110,125,50,13
END
IDD_ADDTYPE DIALOGEX 0, 0, 168, 124
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Add File Type"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Type",IDC_STATIC_TYPE,4,9,36,8,NOT WS_GROUP
EDITTEXT IDC_TYPE,44,7,120,12,ES_AUTOHSCROLL
LTEXT "Description",IDC_STATIC,4,25,36,8,NOT WS_GROUP
EDITTEXT IDC_DESCRIPTION,44,23,120,12,ES_AUTOHSCROLL
GROUPBOX "Extension Type",IDC_STATIC,4,40,160,30
CONTROL "File Extension",IDC_FILEEXTENSION,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,53,60,10
CONTROL "Protocol",IDC_PROTOCOL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,84,53,42,10
GROUPBOX "Media Type",IDC_STATIC,4,73,160,30
CONTROL "Audio Only",IDC_TYPE_AUDIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,86,51,10
CONTROL "Audio/Video",IDC_TYPE_VIDEO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,84,86,54,10
DEFPUSHBUTTON "OK",IDOK,60,107,50,13
PUSHBUTTON "Cancel",IDCANCEL,114,107,50,13
END
IDD_ADVANCED DIALOGEX 0, 0, 190, 214
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Windows Media Decoder Advanced Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Audio",IDC_STATIC,4,4,182,60
CONTROL "Dedicated Delivery Thread",IDC_AUDIO_THREAD,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,204,15,101,10
CONTROL "Deliver samples early",IDC_AUDIO_EARLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,18,80,10
LTEXT "and add",IDC_STATIC,96,18,30,10,SS_CENTERIMAGE
EDITTEXT IDC_AUDIO_EARLYPAD,126,17,40,12,ES_AUTOHSCROLL
LTEXT "ms",IDC_STATIC,168,18,11,10,SS_CENTERIMAGE
CONTROL "Allow out-of-order frames",IDC_AUDIO_OUTOFORDER,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,204,25,99,10
LTEXT "cache",IDC_STATIC,12,32,21,12,SS_CENTERIMAGE
EDITTEXT IDC_AUDIO_CACHE_FRAMES,37,32,40,12,ES_AUTOHSCROLL
LTEXT "frames",IDC_STATIC,81,32,30,12,SS_CENTERIMAGE
CONTROL "Drop audio frames instead of video frames",IDC_AUDIO_DROP,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,48,152,10
GROUPBOX "General",IDC_STATIC,4,164,182,28
CONTROL "Low Memory",IDC_LOWMEMORY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,175,56,10
CONTROL "Real Time",IDC_REALTIME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,108,175,47,10
GROUPBOX "Video",IDC_STATIC,4,68,182,93
CONTROL "Dedicated Delivery Thread",IDC_VIDEO_THREAD,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,205,113,101,10
CONTROL "Deliver samples early",IDC_VIDEO_EARLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,81,80,10
LTEXT "by",IDC_STATIC,96,81,10,10,SS_CENTERIMAGE
EDITTEXT IDC_VIDEO_EARLYPAD,108,81,40,12,ES_AUTOHSCROLL
LTEXT "ms",IDC_STATIC,150,81,11,10,SS_CENTERIMAGE
CONTROL "Allow out-of-order frames",IDC_VIDEO_OUTOFORDER,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,205,126,99,10
LTEXT "Cache",IDC_STATIC,14,97,21,12,SS_CENTERIMAGE
EDITTEXT IDC_VIDEO_CACHE_FRAMES,42,97,40,12,ES_AUTOHSCROLL
LTEXT "frames",IDC_STATIC,88,97,30,12,SS_CENTERIMAGE
LTEXT "Jitter:",IDC_STATIC,14,113,20,12,SS_CENTERIMAGE
EDITTEXT IDC_VIDEO_JITTER,42,113,40,12,ES_AUTOHSCROLL
LTEXT "ms",IDC_STATIC,88,113,10,12,SS_CENTERIMAGE
LTEXT "Frame drop threshold:",IDC_STATIC,12,131,72,10,SS_CENTERIMAGE
EDITTEXT IDC_VIDEO_DROP_THRESHOLD,88,129,40,12,ES_AUTOHSCROLL
LTEXT "ms",IDC_STATIC,132,131,10,10,SS_CENTERIMAGE
CONTROL "Report dropped frames to decoder",IDC_VIDEO_NOTIFY,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,145,127,10
DEFPUSHBUTTON "OK",IDOK,82,197,50,13
PUSHBUTTON "Cancel",IDCANCEL,136,197,50,13
END
IDD_INFO DIALOGEX 0, 0, 341, 164
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Advanced",-1,0,0,341,164
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,13,327,143
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 340
TOPMARGIN, 4
BOTTOMMARGIN, 138
END
IDD_ADDTYPE, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 164
TOPMARGIN, 7
BOTTOMMARGIN, 120
END
IDD_ADVANCED, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 186
TOPMARGIN, 4
BOTTOMMARGIN, 210
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_NULLSOFT_WINDOWS_MEDIA_DECODER "Nullsoft Windows Media Decoder v%s"
65535 "{C5B78F09-3222-4a64-AA98-F1ABC5A9E355}"
END
STRINGTABLE
BEGIN
IDS_NULLSOFT_WINDOWS_MEDIA_DECODER_OLD "Nullsoft Windows Media Decoder"
IDS_REALTIME "Realtime"
IDS_CONNECTING "Connecting"
IDS_LOCATING "Locating"
IDS_ACCESS_DENIED "Access Denied"
IDS_STEREO "Stereo"
IDS_QUADROPHONIC "Quadrophonic"
IDS_SURROUND "Surround"
IDS_5_1 "5.1"
IDS_7_1 "7.1"
IDS_EXT "Ext"
IDS_DESCRIPTION "Description"
IDS_PROTOCOL "Protocol"
IDS_EXTENSION "Extension"
END
STRINGTABLE
BEGIN
IDS_EDIT_FILE_TYPE "Edit File Type"
IDS_WMA_AUDIO_FILE "Windows Media Audio File (*.WMA)"
IDS_WMA_VIDEO_FILE "Windows Media Video File (*.WMV)"
IDS_ASF_STREAM "Advanced Streaming Format (*.ASF)"
IDS_WINDOWS_MEDIA_STREAM "Windows Media Stream"
IDS_UNKNOWN_ERROR "unknown error: %x"
IDS_ATTRIBUTE "Attribute"
IDS_VALUE "Value"
IDS_CLOSE "Close"
IDS_UNABLE_TO_WRITE_TO_FILE_DOES_FILE_EXIST
"Unable to write to file\nDoes the file still exist?"
IDS_UNABLE_TO_WRITE_TO_FILE "Unable to write to file"
IDS_UNABLE_TO_WRITE_TO_FILE_MAY_NOT_HAVE_ACCESS
"Unable to write to file\nYou may not have access to modify this file."
IDS_SAVE_FAILED "Save failed"
IDS_TRUE "True"
IDS_FALSE "False"
IDS_UNKNOWN "Unknown"
END
STRINGTABLE
BEGIN
IDS_WINDOWS_MEDIA_XXX "Windows Media: %dx%d %c%c%c%c"
IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_NEED_LICENSE
"Windows Media Protected Content\n\nIn order to play this file, you must acquire a license.\nA website will launch to perform this process.\n\nProceed?"
IDS_LICENSE_REQUIRED "License required"
IDS_BEGINNING_UPDATE "Beginning Update"
IDS_UPDATE_FAILED "Update Failed"
IDS_UPDATE_CANCELLED "Update Cancelled"
IDS_IDLE "Idle"
IDS_REQUESTING "Requesting"
IDS_RECEIVING_DATA "Receiving Data"
IDS_COMPLETED "Completed"
IDS_INSTALLING "Installing"
IDS_FILE_PROTECTED_CANNOT_PLAY_IN_WINAMP
"This file is protected, but cannot be played in Winamp."
IDS_LICENSE_ACQUIRED "License Acquired"
IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_UNTRUSTED_SOURCE
"Windows Media Protected Content\n\nThe license for this license is from an untrusted source.\n\nProceed?"
IDS_UNTRUSTED_LICENSE "Untrusted License"
IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_TAMPERED_LICENSE
"Windows Media Protected Content\n\nThe license for this license appeared to have been tampered.\nIt is recommended that you answer ""No"".\n\nProceed?"
END
STRINGTABLE
BEGIN
IDS_TAMPERED_LICENSE "Tampered License"
IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_SECURITY_UPDATE
"Windows Media Protected Content\n\nIn order to play this file, a security update is required.\n\nProceed?"
IDS_SECURITY_UPDATE_REQUIRED "Security Update Required"
IDS_UPDATING "Updating"
IDS_ENCRYPTED_IN_OP_LEVEL_HIGHER_THAN_SUPPORTED
"This file is encrypted with an Output Protection Level higher than supported in Winamp."
IDS_WINDOWS_MEDIA_PLAYBACK_FAILURE "Windows Media Playback Failure"
IDS_UPDATE_REQUIRED "Update required"
IDS_ACQUIRING_LICENSE "Acquiring License"
IDS_DRM_LICENSE_EXPIRED_VISIT_WINAMP_COM
"DRM License has expired! Please visit Winamp.com"
IDS_ERROR "Error"
IDS_BUFFERING "Buffering"
IDS_UNKNOWN_ERROR_WAV "Unknown Error."
IDS_CODEC "Codec"
IDS_DURATION "Duration"
IDS_BITRATE "Bitrate"
IDS_FILESIZE "File Size"
END
STRINGTABLE
BEGIN
IDS_YES "Yes"
IDS_NO "No"
IDS_WMVER "WM Version"
IDS_SEEKABLE "Seekable"
IDS_STRIDABLE "Stridable"
IDS_BROADCAST "Broadcast"
IDS_PROTECTED "Protected"
IDS_TRUSTED "Trusted"
IDS_CONTAINS "Contains"
IDS_NAME "Name"
IDS_KBPS "kbps"
IDS_ABOUT_TEXT "%s\n© 2005-2023 Winamp SA\nWritten by: Ben Allison\nBuild date: %s\n\nWindows Media is a trademark\nof Microsoft Corporation."
END
STRINGTABLE
BEGIN
IDS_AUDIO "Audio"
IDS_VIDEO "Video"
IDS_IMAGE "Image"
IDS_SCRIPT "Script"
IDS_NONE "None"
IDS_WINDOWS_MEDIA_PLAYLIST "Windows Media Playlist"
IDS_ASX_PLAYLIST "Advanced Streaming Redirector (ASX)"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+30
View File
@@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_wm", "in_wmvdrm.vcxproj", "{9362E6C2-EFCC-4104-8671-78222E0A5FCC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Debug|Win32.ActiveCfg = Debug|Win32
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Debug|Win32.Build.0 = Debug|Win32
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Debug|x64.ActiveCfg = Debug|x64
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Debug|x64.Build.0 = Debug|x64
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Release|Win32.ActiveCfg = Release|Win32
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Release|Win32.Build.0 = Release|Win32
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Release|x64.ActiveCfg = Release|x64
{9362E6C2-EFCC-4104-8671-78222E0A5FCC}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3A0E00EA-C715-4273-A005-BCCCC6158254}
EndGlobalSection
EndGlobal
@@ -0,0 +1,361 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>in_wm</ProjectName>
<ProjectGuid>{9362E6C2-EFCC-4104-8671-78222E0A5FCC}</ProjectGuid>
<RootNamespace>in_wmvdrm</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>false</VcpkgEnabled>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_USRDLL;IN_WMVDRM_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_DRM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalOptions>/ignore:4253 /ignore:4254 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>wmvcore.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_USRDLL;IN_WMVDRM_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_DRM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalOptions>/ignore:4253 /ignore:4254 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>wmvcore.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_USRDLL;IN_WMVDRM_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_DRM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<ObjectFileName>$(IntDir)</ObjectFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<DisableSpecificWarnings>4005;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalOptions>/ignore:4253 /ignore:4254 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>wmvcore.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_USRDLL;IN_WMVDRM_EXPORTS;UNICODE_INPUT_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_DRM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<ObjectFileName>$(IntDir)</ObjectFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<DisableSpecificWarnings>4005;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalOptions>/ignore:4253 /ignore:4254 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>wmvcore.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\nu\CCVersion.cpp" />
<ClCompile Include="..\..\..\nu\listview.cpp" />
<ClCompile Include="..\..\..\Winamp\strutil.cpp" />
<ClCompile Include="AlbumArt.cpp" />
<ClCompile Include="api.cpp" />
<ClCompile Include="ASXLoader.cpp" />
<ClCompile Include="AudioFormat.cpp" />
<ClCompile Include="AudioLayer.cpp" />
<ClCompile Include="AudioThread.cpp" />
<ClCompile Include="BufferLayer.cpp" />
<ClCompile Include="ClockLayer.cpp" />
<ClCompile Include="config.cpp">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">WM_DEFINE_CONFIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">WM_DEFINE_CONFIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="ConfigDialog.cpp" />
<ClCompile Include="directdraw.cpp" />
<ClCompile Include="ExtendedFileInfo.cpp" />
<ClCompile Include="ExtendedRead.cpp" />
<ClCompile Include="factory_Handler.cpp" />
<ClCompile Include="FileInfoDialog.cpp" />
<ClCompile Include="FileTypes.cpp" />
<ClCompile Include="GainLayer.cpp" />
<ClCompile Include="loadini.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MediaThread.cpp" />
<ClCompile Include="MetaTag.cpp" />
<ClCompile Include="MetaTagFactory.cpp" />
<ClCompile Include="output\OutPlugin.cpp" />
<ClCompile Include="PlaylistHandler.cpp" />
<ClCompile Include="RawReader.cpp" />
<ClCompile Include="SeekLayer.cpp" />
<ClCompile Include="StatusHook.cpp" />
<ClCompile Include="TagAlias.cpp" />
<ClCompile Include="util.cpp" />
<ClCompile Include="VideoDataConverter.cpp" />
<ClCompile Include="VideoLayer.cpp" />
<ClCompile Include="VideoOutputChildDDraw.cpp" />
<ClCompile Include="VideoThread.cpp" />
<ClCompile Include="vidutils.cpp" />
<ClCompile Include="vid_ddraw.cpp" />
<ClCompile Include="vid_overlay.cpp" />
<ClCompile Include="WaitLayer.cpp" />
<ClCompile Include="WinampInterface.cpp" />
<ClCompile Include="WMCallback.cpp" />
<ClCompile Include="WMDRMModule.cpp" />
<ClCompile Include="WMHandler.cpp" />
<ClCompile Include="WMInformation.cpp" />
<ClCompile Include="WMPlaylist.cpp" />
<ClCompile Include="WPLLoader.cpp" />
<ClCompile Include="XMLString.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\nu\listview.h" />
<ClInclude Include="..\..\Output\out_ds\res_wa2\resource.h" />
<ClInclude Include="..\..\..\Winamp\strutil.h" />
<ClInclude Include="AlbumArt.h" />
<ClInclude Include="api.h" />
<ClInclude Include="ASXLoader.h" />
<ClInclude Include="AudioFormat.h" />
<ClInclude Include="AudioLayer.h" />
<ClInclude Include="AudioThread.h" />
<ClInclude Include="AutoChar.h" />
<ClInclude Include="AutoWide.h" />
<ClInclude Include="BufferLayer.h" />
<ClInclude Include="ClockLayer.h" />
<ClInclude Include="config.h" />
<ClInclude Include="ConfigDialog.h" />
<ClInclude Include="directdraw.h" />
<ClInclude Include="ExtendedRead.h" />
<ClInclude Include="factory_Handler.h" />
<ClInclude Include="FileInfoDialog.h" />
<ClInclude Include="FileTypes.h" />
<ClInclude Include="GainLayer.h" />
<ClInclude Include="loadini.h" />
<ClInclude Include="Main.h" />
<ClInclude Include="MediaThread.h" />
<ClInclude Include="MetaTag.h" />
<ClInclude Include="MetaTagFactory.h" />
<ClInclude Include="OutputStream.h" />
<ClInclude Include="output\AudioOut.h" />
<ClInclude Include="output\OutPlugin.h" />
<ClInclude Include="PlaylistHandler.h" />
<ClInclude Include="RawReader.h" />
<ClInclude Include="Remaining.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SeekLayer.h" />
<ClInclude Include="StatusHook.h" />
<ClInclude Include="TagAlias.h" />
<ClInclude Include="util.h" />
<ClInclude Include="VideoDataConverter.h" />
<ClInclude Include="VideoLayer.h" />
<ClInclude Include="VideoOutputChildDDraw.h" />
<ClInclude Include="VideoThread.h" />
<ClInclude Include="vidutils.h" />
<ClInclude Include="vid_ddraw.h" />
<ClInclude Include="vid_overlay.h" />
<ClInclude Include="WaitLayer.h" />
<ClInclude Include="WinampInterface.h" />
<ClInclude Include="WMCallback.h" />
<ClInclude Include="WMDRMModule.h" />
<ClInclude Include="WMHandler.h" />
<ClInclude Include="WMInformation.h" />
<ClInclude Include="WMPlaylist.h" />
<ClInclude Include="WPLLoader.h" />
<ClInclude Include="XMLString.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_wm.rc" />
</ItemGroup>
<ItemGroup>
<Text Include="DESIGN.txt" />
<Text Include="TODO.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,330 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="AlbumArt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="api.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ASXLoader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioFormat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BufferLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClockLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ConfigDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="directdraw.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ExtendedFileInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ExtendedRead.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="factory_Handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FileInfoDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FileTypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GainLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="loadini.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MediaThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MetaTag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MetaTagFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="output\OutPlugin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PlaylistHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RawReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SeekLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StatusHook.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TagAlias.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vid_ddraw.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vid_overlay.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VideoDataConverter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VideoLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VideoOutputChildDDraw.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VideoThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vidutils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WaitLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WinampInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WMCallback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WMDRMModule.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WMHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WMInformation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WMPlaylist.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WPLLoader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XMLString.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\nu\CCVersion.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\nu\listview.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\Winamp\strutil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlbumArt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="api.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ASXLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioFormat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="output\AudioOut.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioThread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AutoChar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AutoWide.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BufferLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ClockLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ConfigDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="directdraw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ExtendedRead.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="factory_Handler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FileInfoDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FileTypes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GainLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="loadini.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MediaThread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MetaTagFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MetaTag.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="output\OutPlugin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="OutputStream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PlaylistHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RawReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Remaining.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SeekLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StatusHook.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TagAlias.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vid_ddraw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vid_overlay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VideoDataConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VideoLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VideoOutputChildDDraw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VideoThread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vidutils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WaitLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WinampInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WMCallback.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WMDRMModule.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WMHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WMInformation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WMPlaylist.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WPLLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="XMLString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\nu\listview.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\Output\out_ds\res_wa2\resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\Winamp\strutil.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="DESIGN.txt" />
<Text Include="TODO.txt" />
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{c26aaf40-61a0-4d01-b985-d9da875ad265}</UniqueIdentifier>
</Filter>
<Filter Include="Ressource Files">
<UniqueIdentifier>{e22165b9-a669-4451-bca6-7d77a42f2d99}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{375a8628-880b-412e-b643-d12761afdc4b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_wm.rc">
<Filter>Ressource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+12
View File
@@ -0,0 +1,12 @@
#include "main.h"
#include "loadini.h"
#include "AutoWide.h"
#include "../Winamp/wa_ipc.h"
extern wchar_t INI_FILE[MAX_PATH];
void IniFile(HWND hMainWindow)
{
if (!INI_FILE[0])
{
lstrcpyn(INI_FILE, (wchar_t *)SendMessage(hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILEW), MAX_PATH);
}
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef NULLSOFT_LOADINIH
#define NULLSOFT_LOADINIH
#include <windows.h>
extern wchar_t INI_FILE[MAX_PATH];
void IniFile(HWND hMainWindow);
#endif
+136
View File
@@ -0,0 +1,136 @@
#include "Main.h"
#include "api.h"
#include "loadini.h"
#include "FileTypes.h"
#include <commctrl.h>
#include "../nu/Config.h"
#include "../nu/CCVersion.h"
#include "resource.h"
wchar_t INI_FILE[MAX_PATH] = L"";
IDispatch *winampExternal = 0;
Nullsoft::Utility::Config wmConfig;
WMDRM mod;
HINSTANCE WASABI_API_LNG_HINST_WAV = 0;
HINSTANCE WASABI_API_LNG_HINST_DS = 0;
int Init()
{
if (!IsWindow(plugin.hMainWindow))
return IN_INIT_FAILURE;
if (!LoadWasabi())
return IN_INIT_FAILURE;
plugin.UsesOutputPlug |= 8;
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG(plugin.hDllInstance,InWmLangGUID);
static wchar_t szDescription[256];
swprintf(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_WINDOWS_MEDIA_DECODER),WMDRM_VERSION);
plugin.description = (char*)szDescription;
IniFile(plugin.hMainWindow);
wmConfig.SetFile(INI_FILE, L"in_wm");
ReadConfig();
fileTypes.ReadConfig();
if (NULL == winampExternal)
{
winampExternal = (IDispatch *)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_DISPATCH_OBJECT); // ask for winamp's
if (winampExternal == (IDispatch *)1)
winampExternal = 0;
}
mod.Init();
return IN_INIT_SUCCESS;
}
void Quit()
{
mod.Quit();
UnloadWasabi();
fileTypes.types.clear();
if (NULL != winampExternal)
{
winampExternal->Release();
winampExternal = NULL;
}
}
void Config(HWND parent)
{
mod.Config(parent);
fileTypes.SaveConfig();
WriteConfig();
}
void About(HWND parent)
{
wchar_t message[1024] = {0}, text[1024] = {0};
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_WINDOWS_MEDIA_DECODER_OLD,text,1024);
wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
plugin.description, TEXT(__DATE__));
DoAboutMessageBox(parent,text,message);
}
void GetFileInfo(const in_char *file, wchar_t *title, int *length_in_ms) { mod.GetFileInfo(file, title, length_in_ms); }
int InfoDialog(const in_char *file, HWND parent) { return mod.InfoBox(file, parent); }
int IsOurFile(const in_char *fn) { return mod.IsOurFile(fn); }
int Play(const in_char *fn) {return mod.Play(fn); }
void Pause() { mod.Pause(); }
void Resume() { mod.UnPause(); }
int IsPaused() { return mod.IsPaused(); }
void Stop() { mod.Stop(); }
int GetLength() { return mod.GetLength(); }
int GetOutputTime() { return mod.GetOutputTime(); }
void SetOutputTime(int time_in_ms) { return mod.SetOutputTime(time_in_ms); }
void SetVolume(int volume) { mod.SetVolume(volume); }
void SetPan(int pan) { mod.SetPan(pan); }
void EQSet(int on, char data[10], int preamp) { mod.EQSet(on, data, preamp); }
In_Module plugin =
{
IN_VER_RET, // defined in IN2.H
"nullsoft(in_wm.dll)",
0, // hMainWindow (filled in by winamp)
0, // hDllInstance (filled in by winamp)
0, // this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc.
0, // is_seekable
1, // uses output plug-in system
Config,
About,
Init,
Quit,
GetFileInfo,
InfoDialog,
IsOurFile,
Play,
Pause,
Resume,
IsPaused,
Stop,
GetLength,
GetOutputTime,
SetOutputTime,
SetVolume,
SetPan,
0,0,0,0,0,0,0,0,0, // visualization calls filled in by winamp
0,0, // dsp calls filled in by winamp
EQSet,
NULL, // setinfo call filled in by winamp
0, // out_mod filled in by winamp
};
extern "C" __declspec( dllexport ) In_Module * winampGetInModule2()
{
return &plugin;
}
@@ -0,0 +1,38 @@
#ifndef NULLSOFT_AUDIOOUTH
#define NULLSOFT_AUDIOOUTH
#include <windows.h>
#include "../../../../Winamp/out.h"
enum InitState
{
StatusNone = 0,
StatusInit,
StatusQuit
};
class AudioOut
{
public:
AudioOut() : dllInstance(0), winampWnd(NULL) {}
virtual void Init() = 0;
virtual void Quit() = 0;
virtual int CanWrite() = 0;
virtual int GetWrittenTime() = 0;
virtual int IsPlaying() = 0;
virtual int Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms) = 0;
virtual void Close() = 0;
virtual int Write(char *buf, int len) = 0;
virtual void Flush(int t) = 0;
virtual void SetVolume(int _volume) = 0;
virtual int Pause(int new_state) = 0;
virtual int GetOutputTime() = 0;
virtual void SetPan(int _pan) = 0;
virtual void About(HWND p) = 0;
virtual void Config(HWND w) = 0;
HINSTANCE dllInstance;
HWND winampWnd;
};
#endif
@@ -0,0 +1,70 @@
#include "OutPlugin.h"
#include "../Winamp/In2.h"
#include "WMDRMModule.h"
extern In_Module plugin;
OutPlugin pluginOut;
OutPlugin::OutPlugin()
{}
void OutPlugin::Init()
{
plugin.outMod->Init();
}
void OutPlugin::Quit()
{
plugin.outMod->Quit();
}
int OutPlugin::CanWrite()
{
return plugin.outMod->CanWrite();
}
int OutPlugin::GetWrittenTime()
{
return plugin.outMod->GetWrittenTime();
}
int OutPlugin::IsPlaying()
{
return plugin.outMod->IsPlaying();
}
int OutPlugin::Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
{
return plugin.outMod->Open(samplerate, numchannels, bitspersamp, bufferlenms, prebufferms);
}
void OutPlugin::Close()
{
plugin.outMod->Close();
}
int OutPlugin::Write(char *buf, int len)
{
return plugin.outMod->Write(buf, len);
}
void OutPlugin::Flush(int t)
{
plugin.outMod->Flush(t);
}
void OutPlugin::SetVolume(int _volume)
{
plugin.outMod->SetVolume(_volume);
}
int OutPlugin::Pause(int new_state)
{
return plugin.outMod->Pause(new_state);
}
int OutPlugin::GetOutputTime()
{
return plugin.outMod->GetOutputTime();
}
void OutPlugin::SetPan(int _pan)
{
plugin.outMod->SetPan(_pan);
}
void OutPlugin::About(HWND p)
{
plugin.outMod->About(p);
}
void OutPlugin::Config(HWND w)
{
plugin.outMod->Config(w);
}
@@ -0,0 +1,28 @@
#ifndef NULLSOFT_OUTPLUGINH
#define NULLSOFT_OUTPLUGINH
#include "AudioOut.h"
class OutPlugin : public AudioOut
{
public:
OutPlugin();
void Init();
void Quit();
int CanWrite();
int GetWrittenTime();
int IsPlaying();
int Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
void Close();
int Write(char *buf, int len);
void Flush(int t);
void SetVolume(int _volume);
int Pause(int new_state);
int GetOutputTime();
void SetPan(int _pan);
void About(HWND p);
void Config(HWND w);
};
extern OutPlugin pluginOut;
#endif
@@ -0,0 +1,60 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by out_wave.rc
//
#define IDS_NULLSOFT_WAVEOUT_OLD 0
#define IDS_NOT_ACTIVE 1
#define IDS_UNKNOWN_MMSYSTEM_ERROR 2
#define IDC_RESET 3
#define IDS_UNSUPPORTED_PCM_FORMAT 3
#define IDS_ANOTHER_PROGRAM_IS_USING_THE_SOUNDCARD 4
#define IDS_NO_SOUND_DEVICES_FOUND 5
#define IDS_INTERNAL_DRIVER_ERROR 6
#define IDS_REINSTALL_SOUNDCARD_DRIVERS 7
#define IDS_ERROR_CODE_WINDOWS_ERROR_MESSAGE 8
#define IDS_ERROR_CODE 9
#define IDS_DATA_FORMAT 10
#define IDS_BUFFER_STATUS 11
#define IDS_LATENCY 12
#define IDS_ABOUT 13
#define IDS_PREFS_TITLE 15
#define IDS_ERROR 16
#define IDS_WAVE_U_MS 17
#define IDS_ABOUT_STRING 18
#define IDS_ABOUT_TEXT 18
#define IDD_CONFIG 300
#define IDD_WAVE_CONFIG 300
#define IDC_GAPLESS 1000
#define IDC_BUF_SIZE 1001
#define IDC_SPIN1 1002
#define IDC_PRIMARY 1003
#define IDC_PREBUF_SIZE 1003
#define IDC_DEV 1004
#define IDC_HACK 1005
#define IDC_EXCLUSIVE 1006
#define IDC_PREBUFFER 1007
#define IDC_SPIN2 1008
#define IDC_VOL_ENABLE 1009
#define IDC_ALT_VOL 1010
#define IDC_VOL_RESET 1011
#define IDC_PREB_TEXT 1012
#define IDC_STATE 1013
#define IDC_PREBUFFER_1 1014
#define IDC_PREBUFFER_2 1015
#define IDC_PREBUF_DISP_1 1016
#define IDC_PREBUF_DISP_2 1017
#define IDC_BLAH 1018
#define IDC_BUFFER 1020
#define IDC_BUF_DISP 1021
#define IDS_NULLSOFT_WAVEOUT 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 301
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1019
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+266
View File
@@ -0,0 +1,266 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by fileinfo.rc
//
#define IDS_NULLSOFT_WINDOWS_MEDIA_DECODER_OLD 0
#define IDS_WMDRM_ABOUT 1
#define IDS_ABOUT 2
#define IDS_REALTIME 3
#define IDS_CONNECTING 4
#define IDS_LOCATING 5
#define IDS_ACCESS_DENIED 6
#define IDS_STEREO 7
#define IDS_QUADROPHONIC 8
#define IDS_SURROUND 9
#define IDS_5_1 10
#define IDS_7_1 11
#define IDS_EXT 12
#define IDS_DESCRIPTION 13
#define IDS_PROTOCOL 14
#define IDS_EXTENSION 15
#define IDS_EDIT_FILE_TYPE 16
#define IDS_WMA_AUDIO_FILE 17
#define IDS_WMA_VIDEO_FILE 18
#define IDS_ASF_STREAM 19
#define IDS_WINDOWS_MEDIA_STREAM 20
#define IDS_UNKNOWN_ERROR 21
#define IDS_ATTRIBUTE 22
#define IDS_VALUE 23
#define IDS_CLOSE 24
#define IDS_UNABLE_TO_WRITE_TO_FILE_DOES_FILE_EXIST 25
#define IDS_UNABLE_TO_WRITE_TO_FILE 26
#define IDS_UNABLE_TO_WRITE_TO_FILE_MAY_NOT_HAVE_ACCESS 27
#define IDS_SAVE_FAILED 28
#define IDS_TRUE 29
#define IDS_FALSE 30
#define IDS_UNKNOWN 31
#define IDS_WINDOWS_MEDIA_XXX 32
#define IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_NEED_LICENSE 33
#define IDS_LICENSE_REQUIRED 34
#define IDS_BEGINNING_UPDATE 35
#define IDS_UPDATE_FAILED 36
#define IDS_UPDATE_CANCELLED 37
#define IDS_IDLE 38
#define IDS_REQUESTING 39
#define IDS_RECEIVING_DATA 40
#define IDS_COMPLETED 41
#define IDS_INSTALLING 42
#define IDS_FILE_PROTECTED_CANNOT_PLAY_IN_WINAMP 43
#define IDS_LICENSE_ACQUIRED 44
#define IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_UNTRUSTED_SOURCE 45
#define IDS_UNTRUSTED_LICENSE 46
#define IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_TAMPERED_LICENSE 47
#define IDS_TAMPERED_LICENSE 48
#define IDS_WINDOWS_MEDIA_PROTECTED_CONTENT_SECURITY_UPDATE 49
#define IDS_SECURITY_UPDATE_REQUIRED 50
#define IDS_UPDATING 51
#define IDS_ENCRYPTED_IN_OP_LEVEL_HIGHER_THAN_SUPPORTED 52
#define IDS_WINDOWS_MEDIA_PLAYBACK_FAILURE 53
#define IDS_UPDATE_REQUIRED 54
#define IDS_ACQUIRING_LICENSE 55
#define IDS_DRM_LICENSE_EXPIRED_VISIT_WINAMP_COM 56
#define IDS_ERROR 57
#define IDS_STRING58 58
#define IDS_BUFFERING 58
#define IDS_STRING59 59
#define IDS_UNKNOWN_ERROR_WAV 59
#define IDS_CODEC 60
#define IDS_DURATION 61
#define IDS_BITRATE 62
#define IDS_FILESIZE 63
#define IDS_YES 64
#define IDS_NO 65
#define IDS_WMVER 66
#define IDS_SEEKABLE 67
#define IDS_STRIDABLE 68
#define IDS_BROADCAST 69
#define IDS_PROTECTED 70
#define IDS_TRUSTED 71
#define IDS_CONTAINS 72
#define IDS_NAME 73
#define IDS_STRING74 74
#define IDS_KBPS 74
#define IDS_ABOUT_TEXT 75
#define IDD_CONFIG 105
#define IDD_CONFIG_STATUS 112
#define IDD_ADDTYPE 113
#define IDD_ADVANCED 114
#define IDS_AUDIO 117
#define IDS_VIDEO 118
#define IDS_IMAGE 119
#define IDS_SCRIPT 120
#define IDS_NONE 121
#define IDS_WINDOWS_MEDIA_PLAYLIST 122
#define IDS_STRING124 123
#define IDS_ASX_PLAYLIST 123
#define IDD_INFO 131
#define IDC_EDIT 1003
#define IDC_DEV 1004
#define IDC_REVERT 1006
#define IDC_BUTTON5 1007
#define IDC_DELETE 1007
#define IDC_REMOVETYPE 1007
#define IDC_ADD 1008
#define IDC_APPLY 1009
#define IDC_TEMP 1009
#define IDC_VOL_ENABLE 1009
#define IDC_METADATALIST 1010
#define IDC_ALT_VOL 1010
#define IDC_VOL_RESET 1011
#define IDC_EDIT1 1011
#define IDC_AUDIO_EARLY_PAD 1011
#define IDC_VIDEO_EARLYPAD 1011
#define IDC_BUFFER_TIME 1011
#define IDC_VIDEO_EARLY_PAD 1012
#define IDC_EDIT2 1012
#define IDC_AUDIO_EARLYPAD 1012
#define IDC_STATE 1013
#define IDC_FILENAME 1014
#define IDC_STATIC_TITLE 1015
#define IDC_STATIC_ARTIST 1016
#define IDC_STATIC_ALBUM 1017
#define IDC_STATIC_TRACK 1018
#define IDC_BLAH 1018
#define IDC_STATIC_YEAR 1019
#define IDC_STATIC_GENRE 1020
#define IDC_STATIC_COMMENTS 1021
#define IDC_EDIT_TITLE 1022
#define IDC_EDIT_ARTIST 1023
#define IDC_EDIT_ALBUM 1024
#define IDC_EDIT_COMMENTS 1025
#define IDC_EDIT_GENRE 1026
#define IDC_EDIT_YEAR 1027
#define IDC_EDIT_TRACK 1028
#define IDC_BUTTON_DELALL 1028
#define IDC_LOWMEMORY 1029
#define IDC_EDIT_GENRE2 1029
#define IDC_EDIT_PUBLISHER 1029
#define IDC_STATIC_GENRE2 1030
#define IDC_AUDIO_OUTOFORDER 1031
#define IDC_EDIT_GENRE3 1031
#define IDC_EDIT_ALBUMARTIST 1031
#define IDC_AUDIO_DEDICATED_THREAD 1032
#define IDC_VIDEO_OUTOFORDER 1033
#define IDC_AUDIO_EARLY 1034
#define IDC_VIDEO_DEDICATED_THREAD 1035
#define IDC_VIDEO_EARLY 1036
#define IDC_VIDEO_JITTER 1039
#define IDC_VIDEO_CACHE_FRAMES 1040
#define IDC_VIDEO_CATCHUP 1042
#define IDC_VIDEO_NOTIFYLATE 1043
#define IDC_CHECK3 1044
#define IDC_VIDEO_FRAMEDROPOFFSET 1044
#define IDC_SILENT 1044
#define IDC_REALTIME 1044
#define IDC_BROWSER 1045
#define IDC_EDIT5 1049
#define IDC_RESET 1052
#define IDC_GLOBAL_FADES 1053
#define IDC_CUSTOM_FADE_SPIN 1054
#define IDC_LOGVOL_SPIN 1055
#define IDC_REFRESH_SPIN 1056
#define IDC_FADE 1057
#define IDC_FADE_SPIN 1058
#define IDC_CREATE_PRIMARY 1059
#define IDC_PAUSEFADE2 1060
#define IDC_DEVICE 1061
#define IDC_WAITx 1062
#define IDC_PREBUFFER_2 1063
#define IDC_KILLSIL 1064
#define IDC_DB 1065
#define IDC_DB_DISPLAY 1066
#define IDC_PREBUFFER_1 1067
#define IDC_LIST 1068
#define IDC_PREBUF_DISP_1 1069
#define IDC_CUSTOM_FADE 1070
#define IDC_PREBUF_DISP_2 1071
#define IDC_USE_CUSTOM_FADE 1072
#define IDC_BUFFER 1073
#define IDC_BUF_DISP 1074
#define IDC_STATIC_MS 1075
#define IDC_BUF_RESET 1076
#define IDC_VOLUME 1077
#define IDC_TAB1 1078
#define IDC_TAB 1079
#define IDC_DEVICE_INFO 1080
#define IDC_PDS_FAQ 1081
#define IDC_FADE_GROUP 1082
#define IDC_FADE_ENABLED 1083
#define IDC_REFRESH 1084
#define IDC_STAT_COPY 1085
#define IDC_LOGVOL_MIN 1086
#define IDC_LOGVOL_STATIC 1087
#define IDC_LOGVOL_STATIC2 1088
#define IDC_FADEVOL 1089
#define IDC_PREBUF_AUTO 1090
#define IDC_STATIC_BLEH 1091
#define IDC_WAVE_GAPLESS 1092
#define IDC_WAVE_RESET 1093
#define IDC_WAVE_BUF_SIZE 1093
#define IDC_WAVE_SPIN1 1094
#define IDC_WAVE_PRIMARY 1095
#define IDC_WAVE_PREBUF_SIZE 1095
#define IDC_WAVE_DEV 1096
#define IDC_WAVE_HACK 1097
#define IDC_WAVE_EXCLUSIVE 1098
#define IDC_WAVE_PREBUFFER 1099
#define IDC_WAVE_SPIN2 1100
#define IDC_WAVE_VOL_ENABLE 1101
#define IDC_WAVE_ALT_VOL 1102
#define IDC_WAVE_VOL_RESET 1103
#define IDC_WAVE_PREB_TEXT 1104
#define IDC_WAVE_STATE 1105
#define IDC_WAVE_PREBUFFER_1 1106
#define IDC_WAVE_PREBUFFER_2 1107
#define IDC_WAVE_PREBUF_DISP_1 1108
#define IDC_WAVE_PREBUF_DISP_2 1109
#define IDC_WAVE_BLAH 1110
#define IDC_WAVE_BUFFER 1111
#define IDC_WAVE_BUF_DISP 1112
#define IDC_VOLMODE 1113
#define IDC_LOGFADES 1114
#define IDC_TEXT1 1115
#define IDC_HW_MIX 1116
#define IDC_VER 1117
#define IDC_LIST2 1119
#define IDC_FLIP 1120
#define IDC_HTTPMETA 1121
#define IDC_ADVANCED 1122
#define IDC_DEFAULTTYPE 1123
#define IDC_ADDTYPE 1124
#define IDC_EDITTYPE 1125
#define IDC_TYPELIST 1126
#define IDC_UNTRUSTED 1127
#define IDC_TYPE 1129
#define IDC_DESCRIPTION 1130
#define IDC_FILEEXTENSION 1131
#define IDC_PROTOCOL 1132
#define IDC_VIDEO_THREAD 1135
#define IDC_AUDIO_DROP 1138
#define IDC_CHECK8 1139
#define IDC_VIDEO_NOTIFY 1139
#define IDC_AUDIO_THREAD 1140
#define IDC_EDIT4 1145
#define IDC_EDIT7 1146
#define IDC_AUDIO_CACHE_FRAMES 1146
#define IDC_EDIT6 1148
#define IDC_VIDEO_DROP_THRESHOLD 1148
#define IDC_EDIT9 1149
#define IDC_TYPE_AUDIO 1151
#define IDC_TYPE_VIDEO 1152
#define IDC_STATIC_TYPE 1153
#define IDC_TYPE_AUDIO2 1154
#define IDC_EXTRA_ASX 1154
#define IDC_AUDIO_SPEAKER_COUNT 10000
#define IDS_NULLSOFT_WINDOWS_MEDIA_DECODER 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 127
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1155
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+169
View File
@@ -0,0 +1,169 @@
#include "main.h"
#include "resource.h"
#include <stdio.h>
#include <strsafe.h>
//static const GUID INVALID_GUID =
//{ 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
void WaitForEvent(HANDLE hEvent, DWORD msMaxWaitTime)
{
// DWORD i;
MSG msg;
const unsigned long eachWait = 10;
unsigned long totalWait = 0;
while (WaitForSingleObject(hEvent, eachWait) == WAIT_TIMEOUT)
{
while (PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE))
{
//TranslateMessage(&msg);
DispatchMessage(&msg);
}
totalWait += eachWait;
if (totalWait >= msMaxWaitTime)
break;
}
}
char *HRErrorCode(HRESULT hr)
{
#define HR_ERROR_CODE(x) case x: return #x
switch (hr)
{
HR_ERROR_CODE(E_OUTOFMEMORY);
HR_ERROR_CODE(E_UNEXPECTED);
HR_ERROR_CODE(S_OK);
HR_ERROR_CODE(S_FALSE);
HR_ERROR_CODE(E_NOINTERFACE);
HR_ERROR_CODE(NS_E_PROTECTED_CONTENT);
HR_ERROR_CODE(E_INVALIDARG);
HR_ERROR_CODE(NS_E_DRM_NO_RIGHTS);
HR_ERROR_CODE(NS_E_DRM_LICENSE_NOTACQUIRED);
HR_ERROR_CODE(NS_E_DRM_ACQUIRING_LICENSE);
HR_ERROR_CODE(NS_S_DRM_ACQUIRE_CANCELLED);
HR_ERROR_CODE(NS_E_LICENSE_OUTOFDATE);
HR_ERROR_CODE(NS_E_LICENSE_INCORRECT_RIGHTS);
HR_ERROR_CODE(NS_E_DRM_REOPEN_CONTENT);
HR_ERROR_CODE(NS_E_DRM_LICENSE_APPSECLOW);
HR_ERROR_CODE(E_ABORT);
HR_ERROR_CODE(NS_E_INVALID_REQUEST);
HR_ERROR_CODE(NS_S_DRM_LICENSE_ACQUIRED);
HR_ERROR_CODE(NS_S_DRM_MONITOR_CANCELLED);
HR_ERROR_CODE(NS_E_FILE_NOT_FOUND);
HR_ERROR_CODE(NS_E_FILE_OPEN_FAILED);
HR_ERROR_CODE(NS_E_SERVER_NOT_FOUND);
HR_ERROR_CODE(NS_E_UNRECOGNIZED_STREAM_TYPE);
HR_ERROR_CODE(NS_E_NO_STREAM);
HR_ERROR_CODE(E_ACCESSDENIED);
HR_ERROR_CODE(NS_S_DRM_BURNABLE_TRACK);
HR_ERROR_CODE(NS_S_DRM_BURNABLE_TRACK_WITH_PLAYLIST_RESTRICTION);
HR_ERROR_CODE(NS_E_DRM_TRACK_EXCEEDED_PLAYLIST_RESTICTION);
HR_ERROR_CODE(NS_E_DRM_TRACK_EXCEEDED_TRACKBURN_RESTRICTION);
}
static char temp[50];
StringCchPrintfA(temp, 50, WASABI_API_LNGSTRING(IDS_UNKNOWN_ERROR), hr);
return temp;
}
void GuidString(GUID guid, wchar_t *target, size_t len)
{
StringCchPrintf( target, len, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
(int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
(int)guid.Data4[0], (int)guid.Data4[1],
(int)guid.Data4[2], (int)guid.Data4[3],
(int)guid.Data4[4], (int)guid.Data4[5],
(int)guid.Data4[6], (int)guid.Data4[7] );
}
const wchar_t *UserTextDescription(unsigned char *binary, size_t size)
{
WM_USER_TEXT *userText = (WM_USER_TEXT *)binary;
return userText->pwszDescription;
}
const wchar_t *UserTextString(unsigned char *binary, size_t size)
{
WM_USER_TEXT *userText = (WM_USER_TEXT *)binary;
return userText->pwszText;
}
void BinaryString(unsigned char *binary, size_t size, wchar_t *final, size_t len)
{
wchar_t * const start = new wchar_t[2 + size*2 + 1]; // 0x + 2 hex per byte + null terminator
wchar_t *target = start;
*target++='0';
*target++='x';
size_t i;
for (i = 0;i!=size;i++)
{
wchar_t temp[3] = {0};
_itow(binary[i], temp, 16);
if (!temp[0])
{
*target++ = '0';
*target++ = '0';
}
else if (!temp[1])
{
*target++ = '0';
*target++ = temp[0];
}
else
{
*target++ = temp[0];
*target++ = temp[1];
}
}
*target = 0;
lstrcpyn(final, start, len);
delete [] start;
}
GUID StringGUID(const wchar_t *source)
{
if (source == NULL) return INVALID_GUID;
GUID guid = GUID_NULL;
int Data1, Data2, Data3;
int Data4[8] = {0};
// {1B3CA60C-DA98-4826-B4A9-D79748A5FD73}
int n = swscanf(source, L" { %08x - %04x - %04x - %02x%02x - %02x%02x%02x%02x%02x%02x } ",
&Data1, &Data2, &Data3, Data4 + 0, Data4 + 1,
Data4 + 2, Data4 + 3, Data4 + 4, Data4 + 5, Data4 + 6, Data4 + 7 );
if (n != 11) return INVALID_GUID;
// Cross assign all the values
guid.Data1 = Data1;
guid.Data2 = Data2;
guid.Data3 = Data3;
guid.Data4[0] = Data4[0];
guid.Data4[1] = Data4[1];
guid.Data4[2] = Data4[2];
guid.Data4[3] = Data4[3];
guid.Data4[4] = Data4[4];
guid.Data4[5] = Data4[5];
guid.Data4[6] = Data4[6];
guid.Data4[7] = Data4[7];
return guid;
}
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
{
MSGBOXPARAMS msgbx = {sizeof(MSGBOXPARAMS),0};
msgbx.lpszText = message;
msgbx.lpszCaption = title;
msgbx.lpszIcon = MAKEINTRESOURCE(102);
msgbx.hInstance = GetModuleHandle(0);
msgbx.dwStyle = MB_USERICON;
msgbx.hwndOwner = parent;
return MessageBoxIndirect(&msgbx);
}

Some files were not shown because too many files have changed in this diff Show More