libctru  v2.3.1
mvd/source/main.c
#include <stdio.h>
#include <string.h>
#include <3ds.h>
u8* inaddr;
u8* outaddr;
void mvd_colorconvert()
{
Result ret;
FILE *f = NULL;
u8* bufAdr = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);
u8* gfxtopadr = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
MVDSTD_Config config;
printf("mvd color-format-conversion example.\n");
f = fopen("sdmc:/mvd_indata.bin", "r");
if(f)
{
fread(inaddr, 1, 0x46500, f);
fclose(f);
}
else
{
memcpy(inaddr, bufAdr, 320*240*3);
}
memset(gfxtopadr, 0, 0x46500);
GSPGPU_FlushDataCache(inaddr, 0x46500);
GSPGPU_FlushDataCache(gfxtopadr, 0x46500);
printf("mvdstdInit(): 0x%08x\n", (unsigned int)ret);
if(ret==0)
{
mvdstdGenerateDefaultConfig(&config, 320, 240, 320, 240, (u32*)inaddr, (u32*)outaddr, (u32*)&outaddr[0x12c00]);
ret = mvdstdConvertImage(&config);
printf("mvdstdConvertImage(): 0x%08x\n", (unsigned int)ret);
}
f = fopen("sdmc:/mvd_outdata.bin", "w");
if(f)
{
fwrite(outaddr, 1, 0x100000, f);
fclose(f);
}
memcpy(gfxtopadr, outaddr, 0x46500);
}
void mvd_video()
{
Result ret;
size_t video_size, nalunitsize;
u32 video_pos=0;
u32 cur_nalunit_pos=0, prev_nalunit_pos=0;
u32 nalcount=0;
u8 *video;
u32 flagval=0;
FILE *f = NULL;
u8* gfxtopadr=NULL;
MVDSTD_Config config;
u32 prefix_offset;
u8 prefix[4] = {0x00, 0x00, 0x00, 0x01};
printf("Loading video...\n");
//This loads the entire video into memory, normally you'd use a library to stream it.
f = fopen("romfs:/video.h264", "r");
if(f==NULL)
{
printf("Faile to open the video in romfs.\n");
return;
}
video = &inaddr[0x100000];
video_size = fread(video, 1, 0xF00000, f);
fclose(f);
if(video_size==0 || video_size>=0xF00000)
{
printf("Failed to read video / video is too large.\n");
return;
}
printf("mvdstdInit(): 0x%08x\n", (unsigned int)ret);
if(ret!=0)return;
printf("Processing 0x%08x-byte video...\n", (unsigned int)video_size);
mvdstdGenerateDefaultConfig(&config, 240, 400, 240, 400, NULL, (u32*)outaddr, (u32*)outaddr);//Normally you'd set the input dimensions here to dimensions loaded from the actual video.
//Normally you'd use a library to load each NAL-unit, this example just parses the data manually.
while(video_pos < video_size+1)
{
cur_nalunit_pos = video_pos;
video_pos++;
prefix_offset = 1;
if(cur_nalunit_pos<video_size)
{
/*
{
if(memcmp(&video[cur_nalunit_pos], &prefix[1], 3)==0 && cur_nalunit_pos==0x2dd)
{
prefix_offset = 0;
}
}
if(prefix_offset)*/
//else
{
if(memcmp(&video[cur_nalunit_pos], prefix, 4))
{
continue;
}
else
{
video_pos++;
}
}
}
if(nalcount && prev_nalunit_pos!=cur_nalunit_pos)
{
nalunitsize = cur_nalunit_pos - prev_nalunit_pos - prefix_offset;
if(nalunitsize > 0x100000)
{
printf("The NAL-unit at offset 0x%08x is too large.\n", (unsigned int)nalunitsize);
break;
}
memcpy(inaddr, &video[prev_nalunit_pos+prefix_offset], nalunitsize);
GSPGPU_FlushDataCache(inaddr, nalunitsize);
MVDSTD_ProcessNALUnitOut tmpout;//Normally you don't really need to use this.
//printf("Processing NAL-unit at offset 0x%08x size 0x%08x...\n", (unsigned int)prev_nalunit_pos, (unsigned int)nalunitsize);
ret = mvdstdProcessVideoFrame(inaddr, nalunitsize, flagval, &tmpout);
{
printf("mvdstdProcessVideoFrame() at NAL-unit offset 0x%08x size 0x%08x returned: 0x%08x. remaining_size=0x%08x.\n", (unsigned int)prev_nalunit_pos, (unsigned int)nalunitsize, (unsigned int)ret, (unsigned int)tmpout.remaining_size);
break;
}
if(ret!=MVD_STATUS_PARAMSET && ret!=MVD_STATUS_INCOMPLETEPROCESSING)
{
gfxtopadr = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
//This sets the MVD output to the framebuffer directly. This is to avoid doing the video->framebuffer image rotation on the ARM11.
//Normally you'd use a seperate MVD output buffer, then transfer that to the framebuffer(such as with GPU rendering).
ret = mvdstdRenderVideoFrame(&config, true);
if(ret!=MVD_STATUS_OK)
{
printf("mvdstdRenderVideoFrame() at NAL-unit offset 0x%08x returned: 0x%08x\n", (unsigned int)prev_nalunit_pos, (unsigned int)ret);
break;
}
if(hidKeysDown() & KEY_B)break;
//Enable/disable the flag passed to mvdstdProcessVideoFrame().
{
flagval-= 0x1;
printf("0x%08x\n", (unsigned int)flagval);
}
{
flagval+= 0x1;
printf("0x%08x\n", (unsigned int)flagval);
}
//gspWaitForVBlank();//Can't use this under this example without a major slowdown. This is due to this example not doing any buffering for the frames.
}
}
nalcount++;
prev_nalunit_pos = cur_nalunit_pos;
}
}
int main()
{
Result ret=0;
int draw=1;
int ready=0;
int type=0;
ret = romfsInit();
if(R_FAILED(ret))
{
printf("romfsInit() failed: 0x%08x\n", (unsigned int)ret);
ready = -1;
}
if(ready==0)
{
inaddr = linearMemAlign(0x1000000, 0x40);
outaddr = linearMemAlign(0x100000, 0x40);
if(!(inaddr && outaddr))
{
ready = -2;
printf("Failed to allocate memory.\n");
}
}
// Main loop
while (aptMainLoop())
{
if(draw && type==0)
{
draw = 0;
if(ready==0)printf("mvd example\n");
printf("Press START to exit.\n");
if(ready==0)
{
printf("Press A for color-format-conversion.\n");
printf("Press B for video(no sound).\n");
}
}
u32 kDown = hidKeysDown();
if(type)
{
if(kDown & KEY_A)
{
type = 0;
continue;
}
}
if(type)continue;
if (kDown & KEY_START)
break; // break in order to return to hbmenu
if(ready==0)
{
type = 0;
if (kDown & KEY_A)type = 1;
if (kDown & KEY_B)type = 2;
if(type)
{
memset(inaddr, 0, 0x100000);
memset(outaddr, 0, 0x100000);
if(type==1)mvd_colorconvert();
if(type==2)mvd_video();
draw = 1;
printf("Press A to continue.\n");
}
}
}
if(inaddr)linearFree(inaddr);
if(outaddr)linearFree(outaddr);
if(ready!=-1)romfsExit();
return 0;
}
Central 3DS header.
bool aptMainLoop(void)
Main function which handles sleep mode and HOME/power buttons - call this at the beginning of every f...
PrintConsole * consoleInit(gfxScreen_t screen, PrintConsole *console)
Initialise the console.
void consoleClear(void)
Clears the screen by using iprintf("\x1b[2J");.
void gfxInit(GSPGPU_FramebufferFormat topFormat, GSPGPU_FramebufferFormat bottomFormat, bool vrambuffers)
Initializes the LCD framebuffers.
void gfxSwapBuffersGpu(void)
Same as gfxSwapBuffers (formerly different).
u8 * gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height)
Retrieves the framebuffer of the specified screen to which graphics should be rendered.
@ GFX_BOTTOM
Bottom screen.
Definition: gfx.h:27
@ GFX_TOP
Top screen.
Definition: gfx.h:26
void gfxExit(void)
Deinitializes and frees the LCD framebuffers.
@ GFX_LEFT
Left eye framebuffer.
Definition: gfx.h:37
void gfxFlushBuffers(void)
Flushes the data cache for the current framebuffers.
Result GSPGPU_FlushDataCache(const void *adr, u32 size)
Flushes memory from the data cache.
#define gspWaitForVBlank()
Waits for VBlank.
Definition: gspgpu.h:151
@ GSP_BGR8_OES
BGR8. (3 bytes)
Definition: gspgpu.h:30
@ GSP_RGB565_OES
RGB565. (2 bytes)
Definition: gspgpu.h:31
@ KEY_UP
D-Pad Up or Circle Pad Up.
Definition: hid.h:37
@ KEY_B
B.
Definition: hid.h:13
@ KEY_START
Start.
Definition: hid.h:15
@ KEY_A
A.
Definition: hid.h:12
@ KEY_DOWN
D-Pad Down or Circle Pad Down.
Definition: hid.h:38
u32 hidKeysDown(void)
Returns a bitmask of newly pressed buttons, this frame.
void hidScanInput(void)
Scans HID for input data.
void * linearMemAlign(size_t size, size_t alignment)
Allocates a buffer aligned to the given size.
void linearFree(void *mem)
Frees a buffer.
void mvdstdExit(void)
Shuts down MVDSTD.
@ MVDMODE_VIDEOPROCESSING
Processing video.
Definition: mvd.h:26
@ MVDMODE_COLORFORMATCONV
Converting color formats.
Definition: mvd.h:25
#define MVD_DEFAULT_WORKBUF_SIZE
Default input size for mvdstdInit(). This is what the New3DS Internet Browser uses,...
Definition: mvd.h:21
Result mvdstdRenderVideoFrame(MVDSTD_Config *config, bool wait)
Renders the video frame.
#define MVD_STATUS_OK
These values are the data returned as "result-codes" by MVDSTD.
Definition: mvd.h:10
#define MVD_CHECKNALUPROC_SUCCESS(x)
This can be used to check whether mvdstdProcessVideoFrame() was successful.
Definition: mvd.h:18
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)
Generates a default MVDSTD configuration.
Result mvdstdInit(MVDSTD_Mode mode, MVDSTD_InputFormat input_type, MVDSTD_OutputFormat output_type, u32 size, MVDSTD_InitStruct *initstruct)
Initializes MVDSTD.
@ MVD_INPUT_H264
H264.
Definition: mvd.h:32
@ MVD_INPUT_YUYV422
YUYV422.
Definition: mvd.h:31
@ MVD_OUTPUT_BGR565
BGR565.
Definition: mvd.h:38
Result mvdstdConvertImage(MVDSTD_Config *config)
Run color-format-conversion.
Result mvdstdProcessVideoFrame(void *inbuf_vaddr, size_t size, u32 flag, MVDSTD_ProcessNALUnitOut *out)
Processes a video frame(specifically a NAL-unit).
u32 osConvertVirtToPhys(const void *vaddr)
Converts an address from virtual (process) memory to physical memory.
#define R_FAILED(res)
Checks whether a result code indicates failure.
Definition: result.h:11
static Result romfsInit(void)
Wrapper for romfsMountSelf with the default "romfs" device name.
Definition: romfs.h:84
static Result romfsExit(void)
Wrapper for romfsUnmount with the default "romfs" device name.
Definition: romfs.h:90
Processing configuration.
Definition: mvd.h:43
u32 physaddr_outdata0
Physical address of output data.
Definition: mvd.h:64
Definition: mvd.h:75
uint8_t u8
would be nice if newlib had this already
Definition: types.h:21
s32 Result
Function result.
Definition: types.h:42
uint32_t u32
32-bit unsigned integer
Definition: types.h:23