aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_mp4/AlbumArt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Input/in_mp4/AlbumArt.cpp')
-rw-r--r--Src/Plugins/Input/in_mp4/AlbumArt.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_mp4/AlbumArt.cpp b/Src/Plugins/Input/in_mp4/AlbumArt.cpp
new file mode 100644
index 00000000..d990162d
--- /dev/null
+++ b/Src/Plugins/Input/in_mp4/AlbumArt.cpp
@@ -0,0 +1,232 @@
+#include "mp4.h"
+#include "AlbumArt.h"
+#include "api__in_mp4.h"
+#include "main.h"
+#include "../nu/AutoWide.h"
+#include "VirtualIO.h"
+#include "Stopper.h"
+#include <shlwapi.h>
+#include <strsafe.h>
+
+bool IsMyExtension(const wchar_t *filename)
+{
+ const wchar_t *extension = PathFindExtension(filename);
+ if (extension && *extension)
+ {
+ wchar_t exts[1024] = L"";
+ // TODO: build a copy of this at config load time so we don't have to run this every time
+ GetPrivateProfileStringW(L"in_mp4", L"extensionlist", defaultExtensions, exts, 1024, m_ini);
+
+ extension++;
+ wchar_t *b = exts;
+ wchar_t *c = 0;
+ do
+ {
+ wchar_t d[20] = {0};
+ StringCchCopyW(d, 15, b);
+ c = wcschr(b, L';');
+ if (c)
+ {
+ if ((c-b)<15)
+ d[c - b] = 0;
+ }
+
+ if (!_wcsicmp(extension, d))
+ return true;
+
+ b = c + 1;
+ }
+ while (c);
+ }
+ return false;
+}
+
+bool MP4_AlbumArtProvider::IsMine(const wchar_t *filename)
+{
+ return IsMyExtension(filename);
+}
+
+int MP4_AlbumArtProvider::ProviderType()
+{
+ return ALBUMARTPROVIDER_TYPE_EMBEDDED;
+}
+
+static int MimeTypeToFlags(const wchar_t *mime_type)
+{
+ if (!mime_type)
+ return 0;
+
+ if (!_wcsicmp(mime_type, L"jpeg")
+ || !_wcsicmp(mime_type, L"jpg")
+ || !_wcsicmp(mime_type, L"image/jpeg")
+ || !_wcsicmp(mime_type, L"image/jpg"))
+ return 13; /* JPEG */
+
+ if (!_wcsicmp(mime_type, L"png")
+ || !_wcsicmp(mime_type, L"image/png"))
+ return 14; /* PNG */
+
+ if (!_wcsicmp(mime_type, L"gif")
+ || !_wcsicmp(mime_type, L"image/gif"))
+ return 12; /* GIF */
+
+ if (!_wcsicmp(mime_type, L"bmp")
+ || !_wcsicmp(mime_type, L"image/bmp"))
+ return 27; /* BMP */
+
+ return 0; /* default to binary, I guess */
+}
+
+int MP4_AlbumArtProvider::GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
+{
+ void *reader = CreateUnicodeReader(filename);
+ if (!reader)
+ return ALBUMARTPROVIDER_FAILURE;
+
+ MP4FileHandle mp4 = MP4ReadEx(filename, reader, &UnicodeIO);
+ if (!mp4)
+ {
+ DestroyUnicodeReader(reader);
+ return ALBUMARTPROVIDER_FAILURE;
+ }
+ else
+ {
+ UnicodeClose(reader); // go ahead and close the file so we don't lock it
+ }
+
+ u_int8_t *art = 0;
+ u_int32_t artSize = 0;
+ int flags = 0;
+ if (MP4GetMetadataCoverArt(mp4, &art, &artSize, &flags))
+ {
+ *bits = WASABI_API_MEMMGR->sysMalloc(artSize);
+ memcpy(*bits, art, artSize);
+ *len=artSize;
+ /* TODO: use flags */
+ *mimeType = 0; // no idea what the mime type is :(
+ MP4Free(art);
+ MP4Close(mp4);
+ DestroyUnicodeReader(reader);
+ return ALBUMARTPROVIDER_SUCCESS;
+ }
+
+ MP4Close(mp4);
+ DestroyUnicodeReader(reader);
+ return ALBUMARTPROVIDER_FAILURE;
+}
+
+int MP4_AlbumArtProvider::SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType)
+{
+ MP4FileHandle mp4 = MP4Modify(filename, 0, 0);
+ if (!mp4)
+ {
+ return ALBUMARTPROVIDER_FAILURE;
+ }
+
+ int flags = MimeTypeToFlags(mimeType);
+ if (MP4SetMetadataCoverArt(mp4, (u_int8_t *)bits, len, flags))
+ {
+ MP4Close(mp4);
+ return ALBUMARTPROVIDER_SUCCESS;
+ }
+
+ MP4Close(mp4);
+ return ALBUMARTPROVIDER_FAILURE;
+}
+
+int MP4_AlbumArtProvider::DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
+{
+ MP4FileHandle mp4 = MP4Modify(filename, 0, 0);
+
+ if (!mp4)
+ {
+ return ALBUMARTPROVIDER_FAILURE;
+ }
+
+ if (MP4DeleteMetadataCoverArt(mp4))
+ {
+ Stopper stopper;
+ if (!_wcsicmp(filename, lastfn))
+ stopper.Stop();
+ MP4Close(mp4);
+ stopper.Play();
+ return ALBUMARTPROVIDER_SUCCESS;
+ }
+
+ MP4Close(mp4);
+ return ALBUMARTPROVIDER_FAILURE;
+}
+
+
+#define CBCLASS MP4_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 MP4_AlbumArtProvider albumArtProvider;
+
+// {315CA473-4A7B-43a9-BB1B-7E1C24B3BFE2}
+static const GUID mp4_albumartproviderGUID =
+ { 0x315ca473, 0x4a7b, 0x43a9, { 0xbb, 0x1b, 0x7e, 0x1c, 0x24, 0xb3, 0xbf, 0xe2 } };
+
+FOURCC AlbumArtFactory::GetServiceType()
+{
+ return svc_albumArtProvider::SERVICETYPE;
+}
+
+const char *AlbumArtFactory::GetServiceName()
+{
+ return "MP4 Album Art Provider";
+}
+
+GUID AlbumArtFactory::GetGUID()
+{
+ return mp4_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; \ No newline at end of file