diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 2111f04..116df41 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -25,6 +25,7 @@ extern "C" { #include <3ds/services/ptm.h> #include <3ds/services/soc.h> #include <3ds/services/mic.h> +#include <3ds/services/mvd.h> #include <3ds/gpu/gx.h> #include <3ds/gpu/gpu.h> diff --git a/libctru/include/3ds/os.h b/libctru/include/3ds/os.h index 92e6483..446677d 100644 --- a/libctru/include/3ds/os.h +++ b/libctru/include/3ds/os.h @@ -4,6 +4,7 @@ (((major)<<24)|((minor)<<16)|((revision)<<8)) u32 osConvertVirtToPhys(u32 vaddr); +u32 osConvertOldLINEARMemToNew(u32 addr);//Converts 0x14* vmem to 0x30*. Returns the input addr when it's already within the new vmem. Returns 0 when outside of either LINEAR mem areas. const char* osStrError(u32 error); u32 osGetFirmVersion(); u32 osGetKernelVersion(); diff --git a/libctru/include/3ds/services/mvd.h b/libctru/include/3ds/services/mvd.h new file mode 100644 index 0000000..800d6fb --- /dev/null +++ b/libctru/include/3ds/services/mvd.h @@ -0,0 +1,36 @@ +#pragma once + +//New3DS-only, see also: http://3dbrew.org/wiki/MVD_Services + +typedef enum { + MVDTYPE_COLORFORMATCONV = 0x00010001, + MVDTYPE_H264 = 0x00020001 +} mvdstdType; + +typedef struct { + mvdstdType type; + u32 unk_x04; + u32 unk_x08; + u32 width0, height0; + u32 physaddr_colorconv_indata; + u32 unk_x18[0x28>>2]; + u32 flag_x40;//0x0 for colorconv, 0x1 for H.264 + u32 unk_x44; + u32 unk_x48; + u32 height1, width1;//Only set for H.264. + u32 unk_x54; + u32 unk_x58; + u32 width2, height2; + u32 physaddr_outdata0; + u32 physaddr_outdata1_colorconv; + u32 unk_x6c[0xb0>>2]; +} mvdstdConfig; + +void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 width, u32 height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv); + +Result mvdstdInit(mvdstdType type, u32 size);//The input size isn't used when type==MVDTYPE_COLORFORMATCONV. H.264 isn't supported currently. +Result mvdstdShutdown(); + +Result mvdstdSetConfig(mvdstdConfig *config); +Result mvdstdProcessFrame(mvdstdConfig *config, u32 *h264_vaddr_inframe, u32 h264_inframesize, u32 h264_frameid); + diff --git a/libctru/source/os.c b/libctru/source/os.c index 6274b34..fb2bd97 100644 --- a/libctru/source/os.c +++ b/libctru/source/os.c @@ -29,6 +29,13 @@ u32 osConvertVirtToPhys(u32 vaddr) return 0; } +u32 osConvertOldLINEARMemToNew(u32 vaddr) +{ + if(vaddr >= 0x30000000 && vaddr < 0x40000000)return vaddr; + if(vaddr >= 0x14000000 && vaddr < 0x1c000000)return vaddr+=0x1c000000; + return 0; +} + // Returns number of milliseconds since 1st Jan 1900 00:00. u64 osGetTime() { volatile datetime_t* dt; diff --git a/libctru/source/services/mvd.c b/libctru/source/services/mvd.c new file mode 100644 index 0000000..ba55fd6 --- /dev/null +++ b/libctru/source/services/mvd.c @@ -0,0 +1,197 @@ +/* + mvd.c - code for using this: http://3dbrew.org/wiki/MVD_Services +*/ + +#include +#include +#include <3ds.h> + +Handle mvdstdHandle; +static u32 mvdstdInitialized = 0; +static mvdstdType mvdstd_type; +static u32 *mvdstd_workbuf = NULL; +static size_t mvdstd_workbufsize = 0; + +static Result mvdstdipc_Initialize(u32 *buf, u32 bufsize, Handle kprocess) +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00010082; //request header code + cmdbuf[1] = (u32)buf; + cmdbuf[2] = bufsize; + cmdbuf[3] = 0; + cmdbuf[4] = kprocess; + + Result ret=0; + if((ret=svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +static Result mvdstdipc_Shutdown() +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00020000; //request header code + + Result ret=0; + if((ret = svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +static Result mvdstdipc_cmd18() +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00180000; //request header code + + Result ret=0; + if((ret=svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +static Result mvdstdipc_cmd19() +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00190000; //request header code + + Result ret=0; + if((ret=svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +static Result mvdstdipc_cmd1a() +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001A0000; //request header code + + Result ret=0; + if((ret=svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +Result mvdstdSetConfig(mvdstdConfig *config) +{ + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001E0044; //request header code + cmdbuf[1] = sizeof(mvdstdConfig); + cmdbuf[2] = 0; + cmdbuf[3] = 0xffff8001; + cmdbuf[4] = (sizeof(mvdstdConfig)<<4) | 10; + cmdbuf[5] = (u32)config; + + Result ret=0; + if((ret=svcSendSyncRequest(mvdstdHandle)))return ret; + + return cmdbuf[1]; +} + +void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 width, u32 height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv) +{ + memset(config, 0, sizeof(mvdstdConfig)); + + config->type = mvdstd_type; + + config->width0 = width; + config->height0 = height; + + if(mvdstd_type==MVDTYPE_COLORFORMATCONV)config->physaddr_colorconv_indata = osConvertVirtToPhys((u32)vaddr_colorconv_indata); + + if(mvdstd_type==MVDTYPE_H264) + { + config->flag_x40 = 1; + config->height1 = height; + config->width1 = width; + } + + config->unk_x58 = 0x40002; + + config->width2 = width; + config->height2 = height; + + config->physaddr_outdata0 = osConvertVirtToPhys((u32)vaddr_outdata0); + if(mvdstd_type==MVDTYPE_COLORFORMATCONV)config->physaddr_outdata1_colorconv = osConvertVirtToPhys((u32)vaddr_outdata1_colorconv); + + config->unk_x6c[0] = 0x1; + config->unk_x6c[(0x84-0x6c)>>2] = 0x12a; + config->unk_x6c[(0x88-0x6c)>>2] = 0x199; + config->unk_x6c[(0x8c-0x6c)>>2] = 0xd0; + config->unk_x6c[(0x90-0x6c)>>2] = 0x64; + config->unk_x6c[(0x94-0x6c)>>2] = 0x204; + config->unk_x6c[(0xa8-0x6c)>>2] = 0x1; + config->unk_x6c[(0x104-0x6c)>>2] = 0x1; + config->unk_x6c[(0x110-0x6c)>>2] = 0x200; + config->unk_x6c[(0x114-0x6c)>>2] = 0x100; +} + +Result mvdstdInit(mvdstdType type, u32 size) +{ + Result ret=0; + + if(mvdstdInitialized)return 0; + + mvdstd_workbufsize = size; + mvdstd_type = type; + + if(type==MVDTYPE_COLORFORMATCONV)mvdstd_workbufsize = 1; + if(type!=MVDTYPE_COLORFORMATCONV)return -2;//H264 isn't supported atm. + + if((ret=srvGetServiceHandle(&mvdstdHandle, "mvd:STD")))return ret; + + mvdstd_workbuf = linearAlloc(mvdstd_workbufsize); + if(mvdstd_workbuf==NULL)return -1; + + ret = mvdstdipc_Initialize((u32*)osConvertOldLINEARMemToNew((u32)mvdstd_workbuf), mvdstd_workbufsize, 0xffff8001); + if(ret<0) + { + svcCloseHandle(mvdstdHandle); + linearFree(mvdstd_workbuf); + return ret; + } + + ret = mvdstdipc_cmd18(); + if(ret<0) + { + mvdstdipc_Shutdown(); + svcCloseHandle(mvdstdHandle); + linearFree(mvdstd_workbuf); + return ret; + } + + mvdstdInitialized = 1; + + return 0; +} + +Result mvdstdShutdown() +{ + if(!mvdstdInitialized)return 0; + + if(mvdstd_type==MVDTYPE_COLORFORMATCONV) + { + mvdstdipc_cmd19(); + } + + mvdstdipc_Shutdown(); + + svcCloseHandle(mvdstdHandle); + + linearFree(mvdstd_workbuf); + + return 0; +} + +Result mvdstdProcessFrame(mvdstdConfig *config, u32 *h264_vaddr_inframe, u32 h264_inframesize, u32 h264_frameid) +{ + Result ret; + + if(config==NULL)return -1; + if(mvdstd_type!=MVDTYPE_COLORFORMATCONV)return -2; + + ret = mvdstdSetConfig(config); + if(ret<0)return ret; + + return mvdstdipc_cmd1a(); +} +