]> Chaos Git - corbenik/ctrulib.git/commitdiff
Updated the MVD implementation to support video processing. Fixed some issues, etc.
authoryellows8 <yellows8@users.noreply.github.com>
Thu, 21 Apr 2016 23:22:14 +0000 (19:22 -0400)
committeryellows8 <yellows8@users.noreply.github.com>
Thu, 21 Apr 2016 23:22:14 +0000 (19:22 -0400)
libctru/include/3ds/services/mvd.h
libctru/source/services/mvd.c

index cfc464433b075929e918f7af9ef2ad9b1cb08fd7..530fa98e8bd326bb8344d256f76017034aa346cc 100644 (file)
@@ -6,6 +6,10 @@
 
 //New3DS-only, see also: http://3dbrew.org/wiki/MVD_Services
 
+///These values are the data returned as "result-codes" by MVDSTD.
+#define MVD_STATUS_OK 0x17000
+#define MVD_STATUS_BUSY 0x17002
+
 /// Processing mode.
 typedef enum {
        MVDMODE_COLORFORMATCONV, ///< Converting color formats.
@@ -20,7 +24,8 @@ typedef enum {
 
 /// Output format.
 typedef enum {
-       MVD_OUTPUT_RGB565 = 0x00040002 ///< RGB565
+       MVD_OUTPUT_BGR565 = 0x00040002, ///< BGR565
+       MVD_OUTPUT_RGB565 = 0x00040004 ///< RGB565
 } MVDSTD_OutputFormat;
 
 /// Processing configuration.
@@ -43,7 +48,10 @@ typedef struct {
        u32 outheight1;                  ///< Second output height.
        u32 physaddr_outdata0;           ///< Physical address of output data.
        u32 physaddr_outdata1_colorconv; ///< Physical address of color conversion output data.
-       u32 unk_x6c[0xb0>>2];            ///< Unknown.
+       u32 unk_x6c[0xa4>>2];            ///< Unknown.
+       u32 output_width_override;       ///< Used for aligning the output width when larger than the output width. Overrides the output width when smaller than the output width.
+       u32 output_height_override;      ///< Same as output_width_override except for the output height.
+       u32 unk_x118;
 } MVDSTD_Config;
 
 /**
@@ -72,13 +80,19 @@ void mvdstdExit(void);
 void mvdstdGenerateDefaultConfig(MVDSTD_Config*config, u32 input_width, u32 input_height, u32 output_width, u32 output_height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv);
 
 /**
- * @brief Processes a frame.
+ * @brief Run color-format-conversion.
+ * @param config Pointer to the configuration to use.
+ */
+Result mvdstdConvertImage(MVDSTD_Config* config);
+
+/**
+ * @brief Processes a video frame(specifically a NAL-unit).
  * @param config Pointer to the configuration to use.
- * @param h264_vaddr_inframe Input H264 frame.
- * @param h264_inframesize Size of the input frame.
- * @param h264_frameid ID of the input frame.
+ * @parameter_set Must be true for the initial NAL-unit parameter sets("Sequence Parameter Set" and "Picture Parameter Set"), false otherwise.
+ * @param inbuf_vaddr Input NAL-unit starting with the 3-byte "00 00 01" prefix. Must be located in linearmem.
+ * @param size Size of the input buffer.
  */
-Result mvdstdProcessFrame(MVDSTD_Config*config, u32 *h264_vaddr_inframe, u32 h264_inframesize, u32 h264_frameid);
+Result mvdstdProcessVideoFrame(MVDSTD_Config* config, bool parameter_set, void* inbuf_vaddr, size_t size);
 
 /**
  * @brief Sets the current configuration of MVDSTD.
index 06f0d311c067628bef80c52df87ecee7c3a8f33d..1c6415764a6a1e0c87a393e107195cdd461d77e1 100644 (file)
@@ -22,6 +22,8 @@ static MVDSTD_OutputFormat mvdstd_output_type;
 static u32 *mvdstd_workbuf;
 static size_t mvdstd_workbufsize;
 
+static u32 mvdstd_videoproc_frameid;
+
 static Result MVDSTD_Initialize(u32* buf, u32 bufsize)
 {
        u32* cmdbuf = getThreadCommandBuffer();
@@ -48,6 +50,64 @@ static Result MVDSTD_Shutdown(void)
        return cmdbuf[1];
 }
 
+static Result MVDSTD_cmd5(s8 unk0, s8 unk1, s8 unk2, u32 unk3)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100
+       cmdbuf[1] = unk0;
+       cmdbuf[2] = unk1;
+       cmdbuf[3] = unk2;
+       cmdbuf[4] = unk3;
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
+static Result MVDSTD_cmd7(void)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x7,0,0); // 0x70000
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
+static Result MVDSTD_ProcessNALUnit(u32 vaddr_buf, u32 physaddr_buf, u32 size, u32 frameid)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x8,5,2); // 0x80142
+       cmdbuf[1] = vaddr_buf;
+       cmdbuf[2] = physaddr_buf;
+       cmdbuf[3] = size;
+       cmdbuf[4] = frameid;
+       cmdbuf[5] = 0;//Unknown
+       cmdbuf[6] = IPC_Desc_SharedHandles(1);
+       cmdbuf[7] = CUR_PROCESS_HANDLE;
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
+static Result MVDSTD_ControlFrameRendering(s8 type)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x9,1,2); // 0x90042
+       cmdbuf[1] = type;
+       cmdbuf[2] = IPC_Desc_SharedHandles(1);
+       cmdbuf[3] = CUR_PROCESS_HANDLE;
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
 static Result MVDSTD_cmd18(void)
 {
        u32* cmdbuf = getThreadCommandBuffer();
@@ -81,6 +141,29 @@ static Result MVDSTD_cmd1a(void)
        return cmdbuf[1];
 }
 
+static Result MVDSTD_cmd1b(u8 unk)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x1B,1,0); // 0x1B0040
+       cmdbuf[1] = unk;
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
+static Result MVDSTD_cmd1c(void)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x1C,0,0); // 0x1C0000
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
+
+       return cmdbuf[1];
+}
+
 Result MVDSTD_SetConfig(MVDSTD_Config* config)
 {
        Result ret=0;
@@ -107,25 +190,51 @@ Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_Output
        mvdstd_input_type = input_type;
        mvdstd_output_type = output_type;
 
+       mvdstd_videoproc_frameid = 0;
+
        if(mvdstd_mode==MVDMODE_COLORFORMATCONV)mvdstd_workbufsize = 1;
-       if(mvdstd_mode!=MVDMODE_COLORFORMATCONV)return -2;//Video processing / H.264 isn't supported atm.
 
        if (AtomicPostIncrement(&mvdstdRefCount)) return 0;
 
        if(R_FAILED(ret=srvGetServiceHandle(&mvdstdHandle, "mvd:STD"))) goto cleanup0;
 
        mvdstd_workbuf = linearAlloc(mvdstd_workbufsize);
-       if(mvdstd_workbuf==NULL) goto cleanup1;
+       if(mvdstd_workbuf==NULL)
+       {
+               ret = -1;
+               goto cleanup1;
+       }
 
        ret = MVDSTD_Initialize((u32*) osConvertOldLINEARMemToNew(mvdstd_workbuf), mvdstd_workbufsize);
        if(R_FAILED(ret)) goto cleanup2;
 
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)
+       {
+               ret = MVDSTD_cmd5(0, 0, 0, 0);
+               if(ret!=MVD_STATUS_OK) goto cleanup3; 
+       }
+
        ret = MVDSTD_cmd18();
-       if(R_FAILED(ret)) goto cleanup3;
+       if(ret!=MVD_STATUS_OK) goto cleanup3;
 
-       return ret;
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)
+       {
+               ret = MVDSTD_cmd1b(1);
+               if(ret!=MVD_STATUS_OK) goto cleanup3; 
+       }
+
+       return 0;
 
 cleanup3:
+       ret = MVD_STATUS_BUSY;
+       while(ret==MVD_STATUS_BUSY)ret = MVDSTD_ControlFrameRendering(1);
+
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd1c();
+
+       MVDSTD_cmd19();
+
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd7();
+
        MVDSTD_Shutdown();
 cleanup2:
        linearFree(mvdstd_workbuf);
@@ -138,12 +247,18 @@ cleanup0:
 
 void mvdstdExit(void)
 {
+       Result ret=0;
+
        if (AtomicDecrement(&mvdstdRefCount)) return;
 
-       if(mvdstd_mode==MVDMODE_COLORFORMATCONV)
-       {
-               MVDSTD_cmd19();
-       }
+       ret = MVD_STATUS_BUSY;
+       while(ret==MVD_STATUS_BUSY)ret = MVDSTD_ControlFrameRendering(1);
+
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd1c();
+
+       MVDSTD_cmd19();
+
+       if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd7();
 
        MVDSTD_Shutdown();
 
@@ -186,21 +301,45 @@ void mvdstdGenerateDefaultConfig(MVDSTD_Config*config, u32 input_width, u32 inpu
        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;
+       config->output_width_override = 0x200;
+       config->output_height_override = 0x100;
 }
 
-Result mvdstdProcessFrame(MVDSTD_Config*config, u32 *h264_vaddr_inframe, u32 h264_inframesize, u32 h264_frameid)
+Result mvdstdConvertImage(MVDSTD_Config* config)
 {
        Result ret;
 
-       if(mvdstdRefCount==0)return 0;
+       if(mvdstdRefCount==0)return -3;
        if(config==NULL)return -1;
        if(mvdstd_mode!=MVDMODE_COLORFORMATCONV)return -2;
 
        ret = MVDSTD_SetConfig(config);
-       if(R_FAILED(ret))return ret;
+       if(ret!=MVD_STATUS_OK)return ret;
 
        return MVDSTD_cmd1a();
 }
 
+Result mvdstdProcessVideoFrame(MVDSTD_Config* config, bool parameter_set, void* inbuf_vaddr, size_t size)
+{
+       Result ret;
+
+       if(mvdstdRefCount==0)return -3;
+       if(config==NULL)return -1;
+       if(mvdstd_mode!=MVDMODE_VIDEOPROCESSING)return -2;
+
+       ret = MVDSTD_ProcessNALUnit((u32)inbuf_vaddr, (u32)osConvertVirtToPhys(inbuf_vaddr), size, mvdstd_videoproc_frameid);
+       mvdstd_videoproc_frameid++;
+       if(mvdstd_videoproc_frameid>=0x12)mvdstd_videoproc_frameid = 0;
+       //if(ret!=MVD_STATUS_OK)return ret;
+
+       if(parameter_set)return ret;
+
+       ret = MVDSTD_SetConfig(config);
+       if(ret!=MVD_STATUS_OK)return ret;
+
+       ret = MVD_STATUS_BUSY;
+       while(ret==MVD_STATUS_BUSY)ret = MVDSTD_ControlFrameRendering(0);
+
+       return ret;
+}
+