📄 ppf_bridge.c
字号:
#define ALLOW_OS_CODE 1#include "../../../../emhwlib/include/emhwlib.h"/* it seems weird that this is not included from the emhwlib.h */#include "../../../../emhwlib/include/emhwlib_properties_1000.h"#include "../../../dock/include/filters.h"/* HACK this should not be here But ppf modules will need to access the gbus_xxx functions. */struct EMhwlib { struct gbus *pGBus;};#include "../include/ppf_bridge.h"#define PPFDBG DISABLE#define MAX_INPUT_SURFACES 1#define MAX_OUTPUT_SURFACES MAX_INPUT_SURFACESextern unsigned long module_id;extern unsigned long pE;extern unsigned long pEm;/* Let's avoid including any rua files by now. After cleanup, ppf modules should be EMhwlib-dependent only*/#ifndef WITH_RUAUSERMODEtypedef RMuint32 (*Event_callback) (void *pEm,RMuint32 ModuleID,RMuint32 mask);RMstatus krua_register_event_callback(void *pEm, RMuint32 ModuleID, RMuint32 mask, Event_callback callback);RMstatus krua_unregister_event_callback(void *pEm, RMuint32 ModuleID, Event_callback callback);#elsestruct RUA;typedef RMuint32 (*Event_callback) (void *pEm,RMuint32 ModuleID,RMuint32 mask);struct RUAEventCallback{ RMuint32 ModuleID; RMuint32 mask; Event_callback callback;};RMstatus RUARegisterEventCallback(struct RUA *pRua, struct RUAEventCallback* event_callback);RMstatus RUAUnregisterEventCallback(struct RUA *pRua, struct RUAEventCallback* event_callback);#endifenum ppf_bridge_state{ ppf_bridge_state_play, ppf_bridge_state_stop}; int ppf_schedule_filter(void *pE, RMuint32 ModuleID, RMuint32 mask);struct ppf_bridge_context{ struct EMhwlibSurfaceReader inputs[MAX_INPUT_SURFACES]; RMuint32 outputs[MAX_OUTPUT_SURFACES]; enum ppf_bridge_state state; RMuint32 on_display_pics;};static struct ppf_bridge_context context;RMstatus bridge_get_engine_mem(struct EMhwlibMemoryBlockList *requiredmemblocks);RMstatus bridge_set_engine_mem(struct EMhwlibMemoryBlockList *allocatedmemblocks);RMstatus bridge_get_output_mem(RMuint32 output_slot, struct EMhwlibMemoryBlockList *requiredmemblocks);RMstatus bridge_set_output_mem(RMuint32 output_slot, struct EMhwlibMemoryBlockList *allocatedmemblocks);RMstatus bridge_get_output(RMuint32 output_slot, RMuint32 *output_surface);RMstatus bridge_set_input(RMuint32 input_slot, RMuint32 input_surface);RMstatus bridge_set_command(void *command_param, RMuint32 param_size, void *command_result, RMuint32 result_size);/* these are not part of the handler */RMstatus bridge_run_filter(RMuint32 dummy);RMstatus bridge_init(void);RMstatus bridge_deinit(void);RMstatus (*ppf_init)(void) = bridge_init;RMstatus (*ppf_deinit)(void) = bridge_deinit;RMstatus (*ppf_run_filter)(RMuint32 dummy) = bridge_run_filter;RMstatus bridge_get_engine_mem(struct EMhwlibMemoryBlockList *requiredmemblocks){ /* this module does not require any DRAM memory */ RMDBGLOG((ENABLE, "came to get engine mem\n")); requiredmemblocks->BlockCount = 0; return RM_OK;}RMstatus bridge_set_engine_mem(struct EMhwlibMemoryBlockList *allocatedmemblocks){ /* we don't need any memory here */ if(allocatedmemblocks->BlockCount) RMDBGLOG((ENABLE, "WARNING: I did not ask for any engine memory!\n")); return RM_OK;}RMstatus bridge_get_output_mem(RMuint32 output_slot, struct EMhwlibMemoryBlockList *requiredmemblocks){ RMuint32 surface_size; RMuint32 picture_count = 6; RMstatus err; /* The pictures are allocated by the creator of the input surfaces (i.e.) no new pictures are needed for the output surfaces. We only need enough memory to create the surface structure. */ err = EMhwlibExchangeProperty((struct EMhwlib *)pEm,DisplayBlock, RMDisplayBlockPropertyID_MultiplePictureSurfaceSize, &picture_count, sizeof(picture_count), &surface_size, sizeof(surface_size)); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Cannot get the size of a surface\n")); return err; } requiredmemblocks->BlockCount = 1; requiredmemblocks->Blocks[0].Size = surface_size; RMDBGLOG((ENABLE, "asking for %ld bytes\n", surface_size)); /* the application is supposed to ignore Address Maybe in the future we can consider using it as a hint as to where the memory should be allocated? */ requiredmemblocks->Blocks[0].Address = 0; return RM_OK;}RMstatus bridge_set_output_mem(RMuint32 output_slot, struct EMhwlibMemoryBlockList *allocatedmemblocks){ struct DisplayBlock_InitMultiplePictureSurfaceX_type surface_init; RMstatus err; if(output_slot >= MAX_OUTPUT_SURFACES){ RMDBGLOG((ENABLE, "Invalid slot!\n")); return RM_ERROR; } if((allocatedmemblocks->BlockCount < 1) ||(allocatedmemblocks->Blocks[0].Address == 0)){ /* Let's say that this means that the application is going to free the memory and that we cannot use the surface anymore */ RMDBGLOG((PPFDBG, "Unsetting output slot %ld\n", output_slot)); context.outputs[output_slot] = 0; return RM_OK; } if(context.outputs[output_slot] != 0){ RMDBGLOG((ENABLE, "This slot is used already!\n")); return RM_ERROR; } /* TODO: CHECK THAT THE ALLOCATED SIZE IS CORRECT */ surface_init.Address = allocatedmemblocks->Blocks[0].Address; /* These should be unused by the display handler (scaler). The display handler should obtain this info from the picture structure. Until that part is made clear in the code, we just guess some reasonable values to make sure. */ surface_init.ColorMode = EMhwlibColorMode_VideoNonInterleaved; surface_init.ColorFormat = EMhwlibColorFormat_24BPP; surface_init.SamplingMode = EMhwlibSamplingMode_420; surface_init.ColorSpace = EMhwlibColorSpace_YUV_601; surface_init.PixelAspectRatio.X = 1; surface_init.PixelAspectRatio.Y = 1; surface_init.PictureCount = 6; surface_init.STCModuleId = 0xFFFF; surface_init.Tiled = 1; err = EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_InitMultiplePictureSurfaceX, &surface_init, sizeof(surface_init)); if (RMFAILED(err)) { RMDBGLOG((ENABLE, "Error Cannot initialize surface\n")); return err; } context.outputs[output_slot] = surface_init.Address; RMDBGLOG((PPFDBG, "Initialized output surface at 0x%08lx\n", context.outputs[output_slot])); return RM_OK;}RMstatus bridge_get_output(RMuint32 output_slot, RMuint32 *output_surface){ /* Not much room for elegance in this one */ if(output_slot >= MAX_OUTPUT_SURFACES){ RMDBGLOG((ENABLE, "Invalid slot!\n")); return RM_ERROR; } *output_surface = context.outputs[output_slot]; return RM_OK;}RMstatus bridge_set_input(RMuint32 input_slot, RMuint32 input_surface){ RMuint32 reader_id; RMstatus err = RM_OK; if(input_slot>=MAX_INPUT_SURFACES){ RMDBGLOG((ENABLE, "Invalid slot\n")); return RM_ERROR; } if(input_surface == 0){ RMDBGLOG((ENABLE, "Unseting input surface slot\n")); context.inputs[input_slot].SurfaceAddress = 0; return RM_OK; } if(context.inputs[input_slot].SurfaceAddress != 0){ RMDBGLOG((ENABLE, "Surface slot already used\n")); return RM_ERROR; } context.inputs[input_slot].SurfaceAddress = input_surface; /* The ConnectReader API says that we can put the "desired" reader id here but it may change during the call */ context.inputs[input_slot].ReaderID = input_slot; err = EMhwlibExchangeProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_ConnectReader, &(context.inputs[input_slot]), sizeof(context.inputs[input_slot]), &reader_id, sizeof(reader_id)); if(RMFAILED(err)){ RMDBGLOG((ENABLE, "Connect reader failed: unsetting input\n")); context.inputs[input_slot].SurfaceAddress = 0; return RM_ERROR; } /* This is the one to use */ context.inputs[input_slot].ReaderID = reader_id; RMDBGLOG((PPFDBG,"connected to surface 0x%08lx with reader_id %ld\n", input_surface, reader_id)); return RM_OK;}RMstatus bridge_set_command(void *command_param, RMuint32 param_size, void *command_result, RMuint32 result_size){ enum ppf_bridge_cmd cmd; RMDBGLOG((ENABLE, "at command param\n")); if(param_size != sizeof(enum ppf_bridge_cmd)){ RMDBGLOG((ENABLE, "Invalid param size!\n")); return RM_ERROR; } if(command_param == NULL){ RMDBGLOG((ENABLE, "Invalid param address!\n")); return RM_ERROR; } /* Most ppf modules will need to handle play/stop commands. We did not add a generic function for this because in the near future the aim is to pass those commands via the input surfaces. So temporarily this is implemented here as a custom command of each ppf module. */ cmd = *(enum ppf_bridge_cmd *)command_param; switch(cmd){ case ppf_bridge_cmd_play: context.state = ppf_bridge_state_play; break; case ppf_bridge_cmd_stop: context.state = ppf_bridge_state_stop; break; } return RM_OK;}RMstatus bridge_run_filter(RMuint32 dummy){ RMuint32 i; RMstatus err = RM_OK; for(i = 0; i < MAX_INPUT_SURFACES; i++){ /* get one picture from each surface and insert it on the output surface */ struct EMhwlibPictureInfo pic; struct DisplayBlock_InsertPictureInSurfaceFifo_type insert_pic; /* see if we can erase some pictures */ if(context.inputs[i].SurfaceAddress == 0){ RMDBGLOG((PPFDBG, "Not doing anything because no input\n")); continue; } if(context.outputs[i] == 0){ RMDBGLOG((PPFDBG, "Not doing anything because no output\n")); continue; }#ifdef WITH_MULTIPLE_READERS_DISPLAY_FIFO /* In single reader display fifo the pictures are released directly by the consumer (e.g. the scalers) so we don't need to implement erasing and releasing */ while((err = EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_ErasePicture, &(context.outputs[i]), sizeof(context.outputs[i]))) == RM_OK){ EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_ReleasePicture, &(context.inputs[i]), sizeof(context.inputs[i])); RMDBGLOG((PPFDBG, "release one input picture\n")); context.on_display_pics--; } if(context.on_display_pics > 1){ /* this can be removed, used here for testing */ RMDBGLOG((PPFDBG, "the dispay has enough pictures already wait until one can be erased\n")); continue; }#endif if(context.state == ppf_bridge_state_stop){ RMDBGLOG((PPFDBG, "Not doing anything because on stop mode\n")); continue; } err = EMhwlibExchangeProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_PeekNextPicture, &(context.inputs[i]), sizeof(context.inputs[i]), &pic, sizeof(pic)); if((err == RM_OK) && pic.PictureAddress){ insert_pic.Surface = context.outputs[i]; insert_pic.Picture = pic.PictureAddress; /* WARNING: THE PICTURE PTS IS OVERWRITTEN BY THE INSERT PROPERTY */ err = EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_InsertPictureInSurfaceFifo, &insert_pic, sizeof(insert_pic)); if(err==RM_OK){ RMDBGLOG((PPFDBG, "****************************************inserted picture 0x%08lx\n", pic.PictureAddress));#ifndef WITH_MULTIPLE_READERS_DISPLAY_FIFO context.inputs[i].emhwlibReserved = pic.PictureAddress;#endif err = EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMDisplayBlockPropertyID_AcquirePicture, &(context.inputs[i]), sizeof(context.inputs[i])); if(RMFAILED(err)){ RMDBGLOG((ENABLE, "Could not acquire picture...\n")); } else{ RMDBGLOG((PPFDBG, "acquired picture\n")); context.on_display_pics++; } } else RMDBGLOG((PPFDBG, "Could not insert picture (full output fifo most likely)\n")); }else RMDBGLOG((PPFDBG, "Empty input fifo\n")); } { /* hack, this function should get the actual mask that triggered its calling and clear it */ RMuint32 mask = EMHWLIB_DISPLAY_EVENT_ID(DispMainAnalogOut); err = EMhwlibSetProperty((struct EMhwlib *)pEm, DisplayBlock, RMGenericPropertyID_ClearEventMask, &(mask), sizeof(mask)); } return RM_OK;}RMstatus bridge_init(void){ RMuint32 i; struct PPFHandle handle = {NULL,}; /* for forward portability */ for(i = 0; i < MAX_INPUT_SURFACES; i++) context.inputs[i].SurfaceAddress = 0; for(i = 0; i < MAX_OUTPUT_SURFACES; i++) context.outputs[i] = 0; context.state = ppf_bridge_state_stop; context.on_display_pics = 0; handle.get_engine_mem = bridge_get_engine_mem; handle.set_engine_mem = bridge_set_engine_mem; handle.get_output_mem = bridge_get_output_mem; handle.set_output_mem = bridge_set_output_mem; handle.get_output = bridge_get_output; handle.set_input = bridge_set_input; handle.set_command = bridge_set_command;/* /\* register within the emhwlib *\/ *//* EMhwlibSetProperty((struct EMhwlib *)pEm, module_id, RMPPFPropertyID_RegisterFilter, *//* &handle, sizeof(handle)); */ RMDBGLOG((ENABLE, "calling register filter\n")); PPFDockRegisterFilter(0, &handle); /* this should probably not be done here but let's wait until we cleanup the regiset_event_callback mechanism */ #ifndef WITH_RUAUSERMODE/* krua_register_event_callback((void*)pE, DisplayBlock, EMHWLIB_DISPLAY_EVENT_ID(DispMainAnalogOut), bridge_run_filter); */ krua_register_event_callback((void*)pE, DisplayBlock, EMHWLIB_DISPLAY_EVENT_ID(DispMainAnalogOut), ppf_schedule_filter);#else { struct RUAEventCallback event_callback; event_callback.ModuleID = DisplayBlock; event_callback.mask = EMHWLIB_DISPLAY_EVENT_ID(DispMainAnalogOut); event_callback.callback = bridge_run_filter; RUARegisterEventCallback((struct RUA*)pE, &event_callback); }#endif return RM_OK;}RMstatus bridge_deinit(void){ /* register within the emhwlib *//* EMhwlibSetProperty((struct EMhwlib *)pEm, module_id, RMPPFPropertyID_RegisterFilter, *//* NULL, sizeof(struct EMhwlibPPFHandle)); */ #ifndef WITH_RUAUSERMODE krua_unregister_event_callback((void*)pE, DisplayBlock, ppf_schedule_filter);#else { struct RUAEventCallback event_callback; event_callback.ModuleID = DisplayBlock; event_callback.mask = EMHWLIB_DISPLAY_EVENT_ID(DispMainAnalogOut); event_callback.callback = bridge_run_filter; RUAUnregisterEventCallback((struct RUA*)pE, &event_callback); }#endif return RM_OK;}#ifndef WITH_RUAUSERMODE#elseRMstatus shared_init(RMuint32 pem, RMuint32 pe, RMuint32 moduleid);RMstatus shared_deinit(void);RMstatus shared_init(RMuint32 pem, RMuint32 pe, RMuint32 moduleid){ module_id = moduleid; pE = pe; pEm = pem; bridge_init(); return RM_OK;}RMstatus shared_deinit(){ bridge_deinit(); return RM_OK;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -