Added flag and out params to MVDSTD_ProcessNALUnit(). Added mvdstdSetupOutputBuffers() and mvdstdOverrideOutputBuffers(). Updated mvdstdInit() to use an initstruct, and clear the workbuf. In mvdstdInit(), use a seperate retval for MVDSTD_ControlFrameRendering() so that the actual retval is returned correctly. Updated mvdstdGenerateDefaultConfig(). Updated mvdstdProcessVideoFrame(). Updated mvd.h.

This commit is contained in:
yellows8 2016-04-25 12:21:16 -04:00
parent 030393a753
commit a65a2e0def
2 changed files with 120 additions and 25 deletions

View File

@ -8,7 +8,17 @@
///These values are the data returned as "result-codes" by MVDSTD. ///These values are the data returned as "result-codes" by MVDSTD.
#define MVD_STATUS_OK 0x17000 #define MVD_STATUS_OK 0x17000
#define MVD_STATUS_PARAMSET 0x17001 ///"Returned after processing NAL-unit parameter-sets."
#define MVD_STATUS_BUSY 0x17002 #define MVD_STATUS_BUSY 0x17002
#define MVD_STATUS_FRAMEREADY 0x17003
#define MVD_STATUS_INCOMPLETEPROCESSING 0x17004 ///"Returned when not all of the input NAL-unit buffer was processed."
#define MVD_STATUS_NALUPROCFLAG 0x17007 ///See here: https://www.3dbrew.org/wiki/MVDSTD:ProcessNALUnit
///This can be used to check whether mvdstdProcessVideoFrame() was successful.
#define MVD_CHECKNALUPROC_SUCCESS(x) (x==MVD_STATUS_OK || x==MVD_STATUS_PARAMSET || x==MVD_STATUS_FRAMEREADY || x==MVD_STATUS_INCOMPLETEPROCESSING || x==MVD_STATUS_NALUPROCFLAG)
/// Default input size for mvdstdInit(). This is what the New3DS Internet Browser uses, from the MVDSTD:CalculateWorkBufSize output.
#define MVD_DEFAULT_WORKBUF_SIZE 0x9006C8
/// Processing mode. /// Processing mode.
typedef enum { typedef enum {
@ -24,15 +34,16 @@ typedef enum {
/// Output format. /// Output format.
typedef enum { typedef enum {
MVD_OUTPUT_BGR565 = 0x00040002, ///< BGR565 MVD_OUTPUT_YUYV422 = 0x00010001, ///< YUYV422
MVD_OUTPUT_RGB565 = 0x00040004 ///< RGB565 MVD_OUTPUT_BGR565 = 0x00040002, ///< BGR565
MVD_OUTPUT_RGB565 = 0x00040004 ///< RGB565
} MVDSTD_OutputFormat; } MVDSTD_OutputFormat;
/// Processing configuration. /// Processing configuration.
typedef struct { typedef struct {
MVDSTD_InputFormat input_type; ///< Input type. MVDSTD_InputFormat input_type; ///< Input type.
u32 unk_x04; ///< Unknown. u32 unk_x04; ///< Unknown.
u32 unk_x08; ///< Unknown. u32 unk_x08; ///< Unknown. Referred to as "H264 range" in SKATER.
u32 inwidth; ///< Input width. u32 inwidth; ///< Input width.
u32 inheight; ///< Input height. u32 inheight; ///< Input height.
u32 physaddr_colorconv_indata; ///< Physical address of color conversion input data. u32 physaddr_colorconv_indata; ///< Physical address of color conversion input data.
@ -47,11 +58,11 @@ typedef struct {
u32 input_crop_height; u32 input_crop_height;
u32 input_crop_width; u32 input_crop_width;
u32 unk_x54; ///< Unknown. u32 unk_x54; ///< Unknown.
MVDSTD_OutputFormat output_type; ///< Output type. MVDSTD_OutputFormat output_type; ///< Output type.
u32 outwidth; ///< Output width. u32 outwidth; ///< Output width.
u32 outheight; ///< Output height. u32 outheight; ///< Output height.
u32 physaddr_outdata0; ///< Physical address of output data. u32 physaddr_outdata0; ///< Physical address of output data.
u32 physaddr_outdata1_colorconv; ///< Physical address of color conversion output data. u32 physaddr_outdata1; ///< Additional physical address for output data, only used when the output format type is value 0x00020001.
u32 unk_x6c[0x98>>2]; ///< Unknown. u32 unk_x6c[0x98>>2]; ///< Unknown.
u32 flag_x104; ///< This enables using the following 4 words when non-zero. u32 flag_x104; ///< This enables using the following 4 words when non-zero.
u32 output_x_pos; ///< Output X position in the output buffer. u32 output_x_pos; ///< Output X position in the output buffer.
@ -61,14 +72,39 @@ typedef struct {
u32 unk_x118; u32 unk_x118;
} MVDSTD_Config; } MVDSTD_Config;
typedef struct {
u32 end_vaddr;//"End-address of the processed NAL-unit(internal MVD heap vaddr)."
u32 end_physaddr;//"End-address of the processed NAL-unit(physaddr following the input physaddr)."
u32 remaining_size;//"Total remaining unprocessed input data. Buffer_end_pos=bufsize-<this value>."
} MVDSTD_ProcessNALUnitOut;
typedef struct {
void* outdata0;//Linearmem vaddr equivalent to config *_outdata0.
void* outdata1;//Linearmem vaddr equivalent to config *_outdata1.
} MVDSTD_OutputBuffersEntry;
typedef struct {
u32 total_entries;//Total actual used entries below.
MVDSTD_OutputBuffersEntry entries[17];
} MVDSTD_OutputBuffersEntryList;
/// This can be used to override the default input values for MVDSTD commands during initialization with video-processing. The default for these fields are all-zero, except for cmd1b_inval which is 1. See also here: https://www.3dbrew.org/wiki/MVD_Services
typedef struct {
s8 cmd5_inval0, cmd5_inval1, cmd5_inval2;
u32 cmd5_inval3;
u8 cmd1b_inval;
} MVDSTD_InitStruct;
/** /**
* @brief Initializes MVDSTD. Video processing / H.264 currently isn't supported. * @brief Initializes MVDSTD.
* @param mode Mode to initialize MVDSTD to. * @param mode Mode to initialize MVDSTD to.
* @param input_type Type of input to process. * @param input_type Type of input to process.
* @param output_type Type of output to produce. * @param output_type Type of output to produce.
* @param size Size of data to process. Not used when type == MVDTYPE_COLORFORMATCONV. * @param size Size of the work buffer, MVD_DEFAULT_WORKBUF_SIZE can be used for this. Only used when type == MVDMODE_VIDEOPROCESSING.
* @param initstruct Optional MVDSTD_InitStruct, this should be NULL normally.
*/ */
Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_OutputFormat output_type, u32 size); Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_OutputFormat output_type, u32 size, MVDSTD_InitStruct *initstruct);
/// Shuts down MVDSTD. /// Shuts down MVDSTD.
void mvdstdExit(void); void mvdstdExit(void);
@ -82,9 +118,9 @@ void mvdstdExit(void);
* @param output_height Output height. * @param output_height Output height.
* @param vaddr_colorconv_indata Virtual address of the color conversion input data. * @param vaddr_colorconv_indata Virtual address of the color conversion input data.
* @param vaddr_outdata0 Virtual address of the output data. * @param vaddr_outdata0 Virtual address of the output data.
* @param vaddr_outdata1_colorconv Virtual address of the color conversion output data. * @param vaddr_outdata1 Additional virtual address for output data, only used when the output format type is value 0x00020001.
*/ */
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); 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);
/** /**
* @brief Run color-format-conversion. * @brief Run color-format-conversion.
@ -96,8 +132,10 @@ Result mvdstdConvertImage(MVDSTD_Config* config);
* @brief Processes a video frame(specifically a NAL-unit). * @brief Processes a video frame(specifically a NAL-unit).
* @param inbuf_vaddr Input NAL-unit starting with the 3-byte "00 00 01" prefix. Must be located in linearmem. * @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. * @param size Size of the input buffer.
* @param flag See here regarding this input flag: https://www.3dbrew.org/wiki/MVDSTD:ProcessNALUnit
* @param out Optional output MVDSTD_ProcessNALUnitOut structure.
*/ */
Result mvdstdProcessVideoFrame(void* inbuf_vaddr, size_t size); Result mvdstdProcessVideoFrame(void* inbuf_vaddr, size_t size, u32 flag, MVDSTD_ProcessNALUnitOut *out);
/** /**
* @brief Renders the video frame. * @brief Renders the video frame.
@ -112,3 +150,19 @@ Result mvdstdRenderVideoFrame(MVDSTD_Config* config, bool wait);
*/ */
Result MVDSTD_SetConfig(MVDSTD_Config* config); Result MVDSTD_SetConfig(MVDSTD_Config* config);
/**
* @brief New3DS Internet Browser doesn't use this. Once done, rendered frames will be written to the output buffers specified by the entrylist instead of the output specified by configuration. See here: https://www.3dbrew.org/wiki/MVDSTD:SetupOutputBuffers
* @param entrylist Input entrylist.
* @param bufsize Size of each buffer from the entrylist.
*/
Result mvdstdSetupOutputBuffers(MVDSTD_OutputBuffersEntryList *entrylist, u32 bufsize);
/**
* @brief New3DS Internet Browser doesn't use this. This overrides the entry0 output buffers originally setup by mvdstdSetupOutputBuffers(). See also here: https://www.3dbrew.org/wiki/MVDSTD:OverrideOutputBuffers
* @param cur_outdata0 Linearmem vaddr. The current outdata0 for this entry must match this value.
* @param cur_outdata1 Linearmem vaddr. The current outdata1 for this entry must match this value.
* @param new_outdata0 Linearmem vaddr. This is the new address to use for outaddr0.
* @param new_outdata1 Linearmem vaddr. This is the new address to use for outaddr1.
*/
Result mvdstdOverrideOutputBuffers(void* cur_outdata0, void* cur_outdata1, void* new_outdata0, void* new_outdata1);

View File

@ -76,7 +76,7 @@ static Result MVDSTD_cmd7(void)
return cmdbuf[1]; return cmdbuf[1];
} }
static Result MVDSTD_ProcessNALUnit(u32 vaddr_buf, u32 physaddr_buf, u32 size, u32 frameid) static Result MVDSTD_ProcessNALUnit(u32 vaddr_buf, u32 physaddr_buf, u32 size, u32 frameid, u32 flag, MVDSTD_ProcessNALUnitOut *out)
{ {
u32* cmdbuf = getThreadCommandBuffer(); u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x8,5,2); // 0x80142 cmdbuf[0] = IPC_MakeHeader(0x8,5,2); // 0x80142
@ -84,13 +84,15 @@ static Result MVDSTD_ProcessNALUnit(u32 vaddr_buf, u32 physaddr_buf, u32 size, u
cmdbuf[2] = physaddr_buf; cmdbuf[2] = physaddr_buf;
cmdbuf[3] = size; cmdbuf[3] = size;
cmdbuf[4] = frameid; cmdbuf[4] = frameid;
cmdbuf[5] = 0;//Unknown cmdbuf[5] = flag;
cmdbuf[6] = IPC_Desc_SharedHandles(1); cmdbuf[6] = IPC_Desc_SharedHandles(1);
cmdbuf[7] = CUR_PROCESS_HANDLE; cmdbuf[7] = CUR_PROCESS_HANDLE;
Result ret=0; Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret; if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
if(out)memcpy(out, &cmdbuf[2], sizeof(MVDSTD_ProcessNALUnitOut));
return cmdbuf[1]; return cmdbuf[1];
} }
@ -181,9 +183,41 @@ Result MVDSTD_SetConfig(MVDSTD_Config* config)
return cmdbuf[1]; return cmdbuf[1];
} }
Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_OutputFormat output_type, u32 size) Result mvdstdSetupOutputBuffers(MVDSTD_OutputBuffersEntryList *entrylist, u32 bufsize)
{ {
Result ret=0; Result ret=0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x1F,36,2); // 0x1F0902
memcpy(&cmdbuf[1], entrylist, sizeof(MVDSTD_OutputBuffersEntryList));
cmdbuf[36] = bufsize;
cmdbuf[37] = IPC_Desc_SharedHandles(1);
cmdbuf[38] = CUR_PROCESS_HANDLE;
if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
return cmdbuf[1];
}
Result mvdstdOverrideOutputBuffers(void* cur_outdata0, void* cur_outdata1, void* new_outdata0, void* new_outdata1)
{
Result ret=0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x21,4,0); // 0x210100
cmdbuf[1] = (u32)cur_outdata0;
cmdbuf[2] = (u32)cur_outdata1;
cmdbuf[3] = (u32)new_outdata0;
cmdbuf[4] = (u32)new_outdata1;
if(R_FAILED(ret=svcSendSyncRequest(mvdstdHandle)))return ret;
return cmdbuf[1];
}
Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_OutputFormat output_type, u32 size, MVDSTD_InitStruct *initstruct)
{
Result ret=0, ret2=0;
mvdstd_workbufsize = size; mvdstd_workbufsize = size;
mvdstd_mode = mode; mvdstd_mode = mode;
@ -192,10 +226,16 @@ Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_Output
mvdstd_videoproc_frameid = 0; mvdstd_videoproc_frameid = 0;
MVDSTD_InitStruct tmpinitstruct;
if(mvdstd_mode==MVDMODE_COLORFORMATCONV)mvdstd_workbufsize = 1; if(mvdstd_mode==MVDMODE_COLORFORMATCONV)mvdstd_workbufsize = 1;
if (AtomicPostIncrement(&mvdstdRefCount)) return 0; if (AtomicPostIncrement(&mvdstdRefCount)) return 0;
memset(&tmpinitstruct, 0, sizeof(MVDSTD_InitStruct));
tmpinitstruct.cmd1b_inval = 1;
if(initstruct)memcpy(&tmpinitstruct, initstruct, sizeof(MVDSTD_InitStruct));
if(R_FAILED(ret=srvGetServiceHandle(&mvdstdHandle, "mvd:STD"))) goto cleanup0; if(R_FAILED(ret=srvGetServiceHandle(&mvdstdHandle, "mvd:STD"))) goto cleanup0;
mvdstd_workbuf = linearAlloc(mvdstd_workbufsize); mvdstd_workbuf = linearAlloc(mvdstd_workbufsize);
@ -204,13 +244,14 @@ Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_Output
ret = -1; ret = -1;
goto cleanup1; goto cleanup1;
} }
memset(mvdstd_workbuf, 0, mvdstd_workbufsize);
ret = MVDSTD_Initialize((u32*) osConvertOldLINEARMemToNew(mvdstd_workbuf), mvdstd_workbufsize); ret = MVDSTD_Initialize((u32*) osConvertOldLINEARMemToNew(mvdstd_workbuf), mvdstd_workbufsize);
if(R_FAILED(ret)) goto cleanup2; if(R_FAILED(ret)) goto cleanup2;
if(mvdstd_mode==MVDMODE_VIDEOPROCESSING) if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)
{ {
ret = MVDSTD_cmd5(0, 0, 0, 0); ret = MVDSTD_cmd5(tmpinitstruct.cmd5_inval0, tmpinitstruct.cmd5_inval1, tmpinitstruct.cmd5_inval2, tmpinitstruct.cmd5_inval3);
if(ret!=MVD_STATUS_OK) goto cleanup3; if(ret!=MVD_STATUS_OK) goto cleanup3;
} }
@ -219,15 +260,15 @@ Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_Output
if(mvdstd_mode==MVDMODE_VIDEOPROCESSING) if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)
{ {
ret = MVDSTD_cmd1b(1); ret = MVDSTD_cmd1b(tmpinitstruct.cmd1b_inval);
if(ret!=MVD_STATUS_OK) goto cleanup3; if(ret!=MVD_STATUS_OK) goto cleanup3;
} }
return 0; return 0;
cleanup3: cleanup3:
ret = MVD_STATUS_BUSY; ret2 = MVD_STATUS_BUSY;
while(ret==MVD_STATUS_BUSY)ret = MVDSTD_ControlFrameRendering(1); while(ret2==MVD_STATUS_BUSY)ret2 = MVDSTD_ControlFrameRendering(1);
if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd1c(); if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)MVDSTD_cmd1c();
@ -267,7 +308,7 @@ void mvdstdExit(void)
linearFree(mvdstd_workbuf); linearFree(mvdstd_workbuf);
} }
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) 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)
{ {
memset(config, 0, sizeof(MVDSTD_Config)); memset(config, 0, sizeof(MVDSTD_Config));
@ -284,7 +325,7 @@ void mvdstdGenerateDefaultConfig(MVDSTD_Config*config, u32 input_width, u32 inpu
config->outheight = output_height; config->outheight = output_height;
config->physaddr_outdata0 = osConvertVirtToPhys(vaddr_outdata0); config->physaddr_outdata0 = osConvertVirtToPhys(vaddr_outdata0);
if(mvdstd_mode==MVDMODE_COLORFORMATCONV)config->physaddr_outdata1_colorconv = osConvertVirtToPhys(vaddr_outdata1_colorconv); if(config->output_type==0x00020001)config->physaddr_outdata1 = osConvertVirtToPhys(vaddr_outdata1);
config->unk_x6c[0] = 0x1; config->unk_x6c[0] = 0x1;
config->unk_x6c[(0x84-0x6c)>>2] = 0x12a; config->unk_x6c[(0x84-0x6c)>>2] = 0x12a;
@ -309,14 +350,14 @@ Result mvdstdConvertImage(MVDSTD_Config* config)
return MVDSTD_cmd1a(); return MVDSTD_cmd1a();
} }
Result mvdstdProcessVideoFrame(void* inbuf_vaddr, size_t size) Result mvdstdProcessVideoFrame(void* inbuf_vaddr, size_t size, u32 flag, MVDSTD_ProcessNALUnitOut *out)
{ {
Result ret; Result ret;
if(mvdstdRefCount==0)return -3; if(mvdstdRefCount==0)return -3;
if(mvdstd_mode!=MVDMODE_VIDEOPROCESSING)return -2; if(mvdstd_mode!=MVDMODE_VIDEOPROCESSING)return -2;
ret = MVDSTD_ProcessNALUnit((u32)inbuf_vaddr, (u32)osConvertVirtToPhys(inbuf_vaddr), size, mvdstd_videoproc_frameid); ret = MVDSTD_ProcessNALUnit((u32)inbuf_vaddr, (u32)osConvertVirtToPhys(inbuf_vaddr), size, mvdstd_videoproc_frameid, flag, out);
mvdstd_videoproc_frameid++; mvdstd_videoproc_frameid++;
if(mvdstd_videoproc_frameid>=0x12)mvdstd_videoproc_frameid = 0; if(mvdstd_videoproc_frameid>=0x12)mvdstd_videoproc_frameid = 0;