static void omx_clk_init(omx_clk_t *clk, int has_audio) { OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; clk->has_audio = has_audio; clk->seek_in_progress = 0; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateStopped; omxchk(OMX_SetParameter(clk->c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); omx_set_state(clk->c, OMX_StateIdle); OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; cstate.nWaitMask = has_audio ? 1 : 2; omxchk(OMX_SetParameter(clk->c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock; OMX_INIT_STRUCTURE(refClock); refClock.eClock = has_audio ? OMX_TIME_RefClockAudio : OMX_TIME_RefClockVideo; omxchk(OMX_SetConfig(clk->c->oc_handle, OMX_IndexConfigTimeActiveRefClock, &refClock)); omx_set_state(clk->c, OMX_StateExecuting); }
omx_tunnel_t * omx_tunnel_create(omx_component_t *src, int srcport, omx_component_t *dst, int dstport, const char *name) { OMX_STATETYPE state; omxchk(OMX_GetState(src->oc_handle, &state)); if(state == OMX_StateLoaded) omx_set_state(src, OMX_StateIdle); omxdbg("Creating tunnel %s from %s:%d to %s:%d\n", name, src->oc_name, srcport, dst->oc_name, dstport); omx_send_command(src, OMX_CommandPortDisable, srcport, NULL, 1); omx_send_command(dst, OMX_CommandPortDisable, dstport, NULL, 1); omxchk(OMX_SetupTunnel(src->oc_handle, srcport, dst->oc_handle, dstport)); omx_send_command(src, OMX_CommandPortEnable, srcport, NULL, 0); omx_send_command(dst, OMX_CommandPortEnable, dstport, NULL, 0); omxchk(OMX_GetState(dst->oc_handle, &state)); if(state == OMX_StateLoaded) omx_set_state(dst, OMX_StateIdle); omx_tunnel_t *ot = malloc(sizeof(omx_tunnel_t)); ot->ot_src = src; ot->ot_srcport = srcport; ot->ot_dst = dst; ot->ot_dstport = dstport; ot->ot_name = name; return ot; }
static void omx_mp_init(media_pipe_t *mp) { if(!(mp->mp_flags & MP_VIDEO)) return; omx_component_t *c; c = omx_component_create("OMX.broadcom.clock", &mp->mp_mutex, NULL); mp->mp_extra = c; omx_set_state(c, OMX_StateIdle); OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; cstate.nWaitMask = 1; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock; OMX_INIT_STRUCTURE(refClock); refClock.eClock = OMX_TIME_RefClockAudio; // refClock.eClock = OMX_TIME_RefClockVideo; // refClock.eClock = OMX_TIME_RefClockNone; omxchk(OMX_SetConfig(c->oc_handle, OMX_IndexConfigTimeActiveRefClock, &refClock)); omx_set_state(c, OMX_StateExecuting); }
void omx_alloc_buffers(omx_component_t *oc, int port) { OMX_PARAM_PORTDEFINITIONTYPE portdef; memset(&portdef, 0, sizeof(portdef)); portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); portdef.nVersion.nVersion = OMX_VERSION; portdef.nPortIndex = port; omxchk(OMX_GetParameter(oc->oc_handle, OMX_IndexParamPortDefinition, &portdef)); if(portdef.bEnabled != OMX_FALSE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0) exit(3); omxdbg("Allocating buffers for %s:%d\n", oc->oc_name, port); omxdbg(" buffer count = %d\n", (int)portdef.nBufferCountActual); omxdbg(" buffer size = %d\n", (int)portdef.nBufferSize); omx_send_command(oc, OMX_CommandPortEnable, port, NULL, 0); int i; for(i = 0; i < portdef.nBufferCountActual; i++) { OMX_BUFFERHEADERTYPE *buf; omxchk(OMX_AllocateBuffer(oc->oc_handle, &buf, port, NULL, portdef.nBufferSize)); omxdbg("buf=%p\n", buf); buf->pAppPrivate = oc->oc_avail; oc->oc_avail = buf; oc->oc_avail_bytes += buf->nAllocLen; } omx_wait_command(oc); // Waits for the OMX_CommandPortEnable command }
static void omx_mp_init(media_pipe_t *mp) { if(!(mp->mp_flags & MP_VIDEO)) return; #if 0 if(0) { mp->mp_seek_initiate = omx_mp_begin_seek; mp->mp_seek_audio_done = omx_mp_seek_audio_done; mp->mp_seek_video_done = omx_mp_seek_video_done; } #endif mp->mp_hold_changed = omx_mp_hold_changed; omx_clk_t *clk = calloc(1, sizeof(omx_clk_t)); TAILQ_INIT(&clk->q); clk->mp = mp; clk->c = omx_component_create("OMX.broadcom.clock", &mp->mp_mutex, NULL); hts_cond_init(&clk->cond, &mp->mp_mutex); mp->mp_extra = clk; omx_set_state(clk->c, OMX_StateIdle); #if 0 OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; cstate.nWaitMask = 1; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock; OMX_INIT_STRUCTURE(refClock); refClock.eClock = OMX_TIME_RefClockAudio; // refClock.eClock = OMX_TIME_RefClockVideo; // refClock.eClock = OMX_TIME_RefClockNone; #else OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateRunning; omxchk(OMX_SetParameter(clk->c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock; OMX_INIT_STRUCTURE(refClock); refClock.eClock = OMX_TIME_RefClockAudio; #endif omxchk(OMX_SetConfig(clk->c->oc_handle, OMX_IndexConfigTimeActiveRefClock, &refClock)); omx_set_state(clk->c, OMX_StateExecuting); hts_thread_create_joinable("omxclkctrl", &clk->tid, omx_clk_thread, clk, THREAD_PRIO_DEMUXER); }
omx_component_t * omx_component_create(const char *name, hts_mutex_t *mtx, hts_cond_t *avail_cond) { omx_component_t *oc = calloc(1, sizeof(omx_component_t)); OMX_CALLBACKTYPE cb; const OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit}; assert(mtx != NULL); oc->oc_mtx = mtx; oc->oc_avail_cond = avail_cond; hts_cond_init(&oc->oc_event_cond, oc->oc_mtx); oc->oc_name = strdup(name); cb.EventHandler = oc_event_handler; cb.EmptyBufferDone = oc_empty_buffer_done; cb.FillBufferDone = oc_fill_buffer_done; // omxdbg("Creating %s\n", oc->oc_name); omxchk(OMX_GetHandle(&oc->oc_handle, oc->oc_name, oc, &cb)); // Initially disable ports int i; for(i = 0; i < 4; i++) { OMX_PORT_PARAM_TYPE ports; ports.nSize = sizeof(OMX_PORT_PARAM_TYPE); ports.nVersion.nVersion = OMX_VERSION; omxchk(OMX_GetParameter(oc->oc_handle, types[i], &ports)); omxdbg("%s: type:%d: ports: %d +%d\n", name, i, ports.nStartPortNumber, ports.nPorts); if(ports.nPorts > 0) { oc->oc_inport = ports.nStartPortNumber; oc->oc_outport = ports.nStartPortNumber + 1; } for(int j = 0; j < ports.nPorts; j++) omx_send_command(oc, OMX_CommandPortDisable, ports.nStartPortNumber + j, NULL, 1); } return oc; }
void omx_set_state(omx_component_t *oc, OMX_STATETYPE reqstate) { OMX_STATETYPE state; int attempts = 20; omxchk(OMX_GetState(oc->oc_handle, &state)); omxdbg("Telling component '%s' to go from state %d -> to state %d\n", oc->oc_name, state, reqstate); while(1) { oc->oc_cmd_done = 0; int r = OMX_SendCommand(oc->oc_handle, OMX_CommandStateSet, reqstate, NULL); if(r == OMX_ErrorInsufficientResources && attempts) { usleep(10000); attempts--; continue; } if(r != 0) { panic("OMX Setstate %s from %d to %d error 0x%x", oc->oc_name, state, reqstate, r); } if(reqstate == OMX_StateExecuting) omx_wait_command(oc); return; } }
static int64_t rvd_newframe(glw_video_t *gv, video_decoder_t *vd, int flags) { rpi_video_display_t *rvd = gv->gv_aux; if(rvd->rvd_vsched && rvd->rvd_reconfigure) { rvd->rvd_reconfigure = 0; if(rvd->rvd_tun_vsched_vrender) omx_tunnel_destroy(rvd->rvd_tun_vsched_vrender); rvd->rvd_tun_vsched_vrender = omx_tunnel_create(rvd->rvd_vsched, 11, rvd->rvd_vrender, 90, "vsched -> vrender"); omx_set_state(rvd->rvd_vrender, OMX_StateExecuting); OMX_CONFIG_DISPLAYREGIONTYPE dr; OMX_INIT_STRUCTURE(dr); dr.nPortIndex = 90; dr.set = OMX_DISPLAY_SET_LAYER; dr.layer = 3; omxchk(OMX_SetConfig(rvd->rvd_vrender->oc_handle, OMX_IndexConfigDisplayRegion, &dr)); } return rvd->rvd_pts; }
static rpi_pixmap_decoder_t * pixmap_decoder_create(int cfmt) { rpi_pixmap_decoder_t *rpd = calloc(1, sizeof(rpi_pixmap_decoder_t)); hts_mutex_init(&rpd->rpd_mtx); hts_cond_init(&rpd->rpd_cond, &rpd->rpd_mtx); rpd->rpd_decoder = omx_component_create("OMX.broadcom.image_decode", &rpd->rpd_mtx, &rpd->rpd_cond); rpd->rpd_decoder->oc_port_settings_changed_cb = decoder_port_settings_changed; rpd->rpd_decoder->oc_opaque = rpd; rpd->rpd_resizer = omx_component_create("OMX.broadcom.resize", &rpd->rpd_mtx, &rpd->rpd_cond); omx_set_state(rpd->rpd_decoder, OMX_StateIdle); OMX_IMAGE_PARAM_PORTFORMATTYPE fmt; OMX_INIT_STRUCTURE(fmt); fmt.nPortIndex = rpd->rpd_decoder->oc_inport; fmt.eCompressionFormat = cfmt; omxchk(OMX_SetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamImagePortFormat, &fmt)); #ifndef NOCOPY omx_alloc_buffers(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_set_state(rpd->rpd_decoder, OMX_StateExecuting); #endif return rpd; }
static void rvd_render(glw_video_t *gv, glw_rctx_t *rc) { rpi_video_display_t *rvd = gv->gv_aux; if(!memcmp(&rvd->rvd_pos, &gv->gv_rect, sizeof(glw_rect_t))) return; rvd->rvd_pos = gv->gv_rect; OMX_CONFIG_DISPLAYREGIONTYPE conf; OMX_INIT_STRUCTURE(conf); conf.nPortIndex = 90; conf.fullscreen = OMX_FALSE; conf.noaspect = OMX_TRUE; conf.set = OMX_DISPLAY_SET_DEST_RECT | OMX_DISPLAY_SET_FULLSCREEN | OMX_DISPLAY_SET_NOASPECT; conf.dest_rect.x_offset = rvd->rvd_pos.x1; conf.dest_rect.y_offset = rvd->rvd_pos.y1; conf.dest_rect.width = rvd->rvd_pos.x2 - rvd->rvd_pos.x1; conf.dest_rect.height = rvd->rvd_pos.y2 - rvd->rvd_pos.y1; omxchk(OMX_SetConfig(rvd->rvd_vrender->oc_handle, OMX_IndexConfigDisplayRegion, &conf)); }
static void rpi_codec_decode(struct media_codec *mc, struct video_decoder *vd, struct media_queue *mq, struct media_buf *mb, int reqsize) { media_pipe_t *mp = vd->vd_mp; rpi_video_codec_t *rvc = mc->opaque; const void *data = mb->mb_data; size_t len = mb->mb_size; while(len > 0) { OMX_BUFFERHEADERTYPE *buf = omx_get_buffer(rvc->rvc_decoder); buf->nOffset = 0; buf->nFilledLen = MIN(len, buf->nAllocLen); memcpy(buf->pBuffer, data, buf->nFilledLen); buf->nFlags = 0; if(rvc->rvc_last_epoch != mb->mb_epoch) { buf->nFlags |= OMX_BUFFERFLAG_DISCONTINUITY; rvc->rvc_last_epoch = mb->mb_epoch; } if(len <= buf->nAllocLen) buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; data += buf->nFilledLen; len -= buf->nFilledLen; if(mb->mb_pts != PTS_UNSET) buf->nTimeStamp = omx_ticks_from_s64(mb->mb_pts); else { buf->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; buf->nTimeStamp = omx_ticks_from_s64(0); } if(mb->mb_skip) buf->nFlags |= OMX_BUFFERFLAG_DECODEONLY; if(rvc->rvc_decoder->oc_port_settings_changed) { rvc->rvc_decoder->oc_port_settings_changed = 0; frame_info_t fi; memset(&fi, 0, sizeof(fi)); fi.fi_type = 'omx'; fi.fi_data[0] = (void *)rvc->rvc_decoder; mp->mp_video_frame_deliver(&fi, mp->mp_video_frame_opaque); } omxchk(OMX_EmptyThisBuffer(rvc->rvc_decoder->oc_handle, buf)); } frame_info_t fi; memset(&fi, 0, sizeof(fi)); fi.fi_drive_clock = mb->mb_drive_clock; fi.fi_epoch = mb->mb_epoch; fi.fi_pts = PTS_UNSET; fi.fi_delta = mb->mb_delta; fi.fi_type = 'omx'; mp->mp_video_frame_deliver(&fi, mp->mp_video_frame_opaque); }
void omx_enable_buffer_marks(omx_component_t *oc) { OMX_CONFIG_BOOLEANTYPE t; OMX_INIT_STRUCTURE(t); t.bEnabled = 1; omxchk(OMX_SetParameter(oc->oc_handle, OMX_IndexParamPassBufferMarks, &t)); }
void omx_tunnel_destroy(omx_tunnel_t *ot) { omxdbg("Destroying tunnel\n"); omx_send_command(ot->ot_src, OMX_CommandPortDisable, ot->ot_srcport, NULL, 0); omx_send_command(ot->ot_dst, OMX_CommandPortDisable, ot->ot_dstport, NULL, 0); omxchk(OMX_SetupTunnel(ot->ot_src->oc_handle, ot->ot_srcport, NULL, 0)); free(ot); }
void omx_set_state(omx_component_t *oc, OMX_STATETYPE reqstate) { OMX_STATETYPE state; omxchk(OMX_GetState(oc->oc_handle, &state)); omxdbg("Telling component '%s' to go from state %d -> to state %d\n", oc->oc_name, state, reqstate); omx_send_command(oc, OMX_CommandStateSet, reqstate, NULL, reqstate != OMX_StateLoaded); }
void omx_component_destroy(omx_component_t *oc) { omxchk(OMX_FreeHandle(oc->oc_handle)); free(oc->oc_name); hts_cond_destroy(&oc->oc_event_cond); free(oc); }
static void omx_clk_begin_seek(omx_clk_t *clk) { omx_component_t *c = clk->c; OMX_TIME_CONFIG_CLOCKSTATETYPE cs; OMX_INIT_STRUCTURE(cs); cs.eState = OMX_TIME_ClockStateStopped; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cs)); clk->seek_in_progress = 2; }
static void omx_mp_begin_seek(media_pipe_t *mp) { omx_component_t *c = mp->mp_extra; OMX_TIME_CONFIG_CLOCKSTATETYPE cs; OMX_INIT_STRUCTURE(cs); cs.eState = OMX_TIME_ClockStateStopped; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cs)); cnt = 2; }
static void omx_clk_set_speed(omx_clk_t *clk, int v) { omx_component_t *c = clk->c; OMX_TIME_CONFIG_SCALETYPE scale; OMX_INIT_STRUCTURE(scale); scale.xScale = v; omxchk(OMX_SetConfig(c->oc_handle, OMX_IndexConfigTimeScale, &scale)); }
int64_t omx_get_media_time(omx_component_t *oc) { OMX_TIME_CONFIG_TIMESTAMPTYPE ts; OMX_INIT_STRUCTURE(ts); omxchk(OMX_GetConfig(oc->oc_handle, OMX_IndexConfigTimeCurrentMediaTime, &ts)); return omx_ticks_to_s64(ts.nTimestamp); }
void omx_send_command(omx_component_t *oc, OMX_COMMANDTYPE cmd, int v, void *p, int wait) { oc->oc_cmd_done = 0; omxdbg("%s: CMD(0x%x, 0x%x, %p)\n", oc->oc_name, cmd, v, p); omxchk(OMX_SendCommand(oc->oc_handle, cmd, v, p)); if(wait) omx_wait_command(oc); }
static void omx_mp_seek_audio_done(media_pipe_t *mp) { cnt--; if(cnt == 0) { omx_component_t *c = mp->mp_extra; OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; cstate.nWaitMask = 1; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); } }
static void omx_clk_seek_done(omx_clk_t *clk) { if(clk->seek_in_progress == 0) return; clk->seek_in_progress--; if(clk->seek_in_progress) return; omx_component_t *c = clk->c; OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; OMX_INIT_STRUCTURE(cstate); cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; cstate.nWaitMask = clk->has_audio ? 1 : 2; omxchk(OMX_SetParameter(c->oc_handle, OMX_IndexConfigTimeClockState, &cstate)); }
static void setup_tunnel(rpi_pixmap_decoder_t *rpd) { int dst_width, dst_height; OMX_PARAM_PORTDEFINITIONTYPE portdef; if(rpd->rpd_tunnel != NULL) return; OMX_INIT_STRUCTURE(portdef); portdef.nPortIndex = rpd->rpd_decoder->oc_outport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); pixmap_compute_rescale_dim(rpd->rpd_im, portdef.format.image.nFrameWidth, portdef.format.image.nFrameHeight, &dst_width, &dst_height); portdef.nPortIndex = rpd->rpd_resizer->oc_inport; omxchk(OMX_SetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); rpd->rpd_tunnel = omx_tunnel_create(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport, rpd->rpd_resizer, rpd->rpd_resizer->oc_inport, "decoder -> resizer"); OMX_INIT_STRUCTURE(portdef); portdef.nPortIndex = rpd->rpd_resizer->oc_outport; omxchk(OMX_GetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); int stride = (dst_width * 4 + PIXMAP_ROW_ALIGN - 1) & ~(PIXMAP_ROW_ALIGN - 1); portdef.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; portdef.format.image.eColorFormat = OMX_COLOR_Format32bitABGR8888; portdef.format.image.nFrameWidth = dst_width; portdef.format.image.nFrameHeight = dst_height; portdef.format.image.nStride = stride; portdef.format.image.nSliceHeight = 0; portdef.format.image.bFlagErrorConcealment = OMX_FALSE; omxchk(OMX_SetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omxchk(OMX_GetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_set_state(rpd->rpd_resizer, OMX_StateExecuting); omx_port_enable(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); pixmap_t *pm = rpd->rpd_pm = calloc(1, sizeof(pixmap_t)); pm->pm_refcount = 1; pm->pm_width = portdef.format.image.nFrameWidth; pm->pm_height = portdef.format.image.nFrameHeight; pm->pm_linesize = portdef.format.image.nStride; pm->pm_type = PIXMAP_BGR32; pm->pm_data = mymemalign(portdef.nBufferAlignment, portdef.nBufferSize); pm->pm_aspect = (float)pm->pm_width / (float)pm->pm_height; omxchk(OMX_UseBuffer(rpd->rpd_resizer->oc_handle, &rpd->rpd_buf, rpd->rpd_resizer->oc_outport, NULL, portdef.nBufferSize, pm->pm_data)); omx_wait_command(rpd->rpd_resizer); omxchk(OMX_FillThisBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_buf)); }
static int rpi_codec_create(media_codec_t *mc, const media_codec_params_t *mcp, media_pipe_t *mp) { int fmt; switch(mc->codec_id) { case CODEC_ID_H264: fmt = OMX_VIDEO_CodingAVC; break; case CODEC_ID_MPEG2VIDEO: if(!omx_enable_mpg2) return 1; fmt = OMX_VIDEO_CodingMPEG2; break; #if 0 case CODEC_ID_VC1: case CODEC_ID_WMV3: if(mcp->extradata_size == 0) return 1; mc->decode = vc1_pt_decode; return 0; #endif default: return 1; } rpi_video_codec_t *rvc = calloc(1, sizeof(rpi_video_codec_t)); hts_cond_init(&rvc->rvc_avail_cond, &mp->mp_mutex); omx_component_t *d = omx_component_create("OMX.broadcom.video_decode", &mp->mp_mutex, &rvc->rvc_avail_cond); if(d == NULL) { hts_cond_destroy(&rvc->rvc_avail_cond); free(rvc); return 1; } rvc->rvc_decoder = d; omx_set_state(d, OMX_StateIdle); OMX_VIDEO_PARAM_PORTFORMATTYPE format; OMX_INIT_STRUCTURE(format); format.nPortIndex = 130; format.eCompressionFormat = fmt; omxchk(OMX_SetParameter(d->oc_handle, OMX_IndexParamVideoPortFormat, &format)); OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ec; OMX_INIT_STRUCTURE(ec); ec.bStartWithValidFrame = OMX_FALSE; omxchk(OMX_SetParameter(d->oc_handle, OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ec)); OMX_CONFIG_BOOLEANTYPE bt; OMX_INIT_STRUCTURE(bt); bt.bEnabled = 1; omxchk(OMX_SetConfig(d->oc_handle, OMX_IndexParamBrcmInterpolateMissingTimestamps, &bt)); omx_alloc_buffers(d, 130); omx_set_state(d, OMX_StateExecuting); if(mcp->extradata_size) { hts_mutex_lock(&mp->mp_mutex); OMX_BUFFERHEADERTYPE *buf = omx_get_buffer_locked(rvc->rvc_decoder); hts_mutex_unlock(&mp->mp_mutex); buf->nOffset = 0; buf->nFilledLen = mcp->extradata_size; memcpy(buf->pBuffer, mcp->extradata, buf->nFilledLen); buf->nFlags = OMX_BUFFERFLAG_CODECCONFIG; omxchk(OMX_EmptyThisBuffer(rvc->rvc_decoder->oc_handle, buf)); } mc->opaque = rvc; mc->close = rpi_codec_close; mc->decode = rpi_codec_decode; mc->flush = rpi_codec_flush; return 0; }
static pixmap_t * rpi_pixmap_decode(pixmap_t *pm, const image_meta_t *im, char *errbuf, size_t errlen) { if(pm->pm_type != PIXMAP_JPEG) return NULL; #ifdef TIMING int64_t ts = showtime_get_ts(), ts2; #endif rpi_pixmap_decoder_t *rpd = pixmap_decoder_create(OMX_IMAGE_CodingJPEG); if(rpd == NULL) return NULL; rpd->rpd_im = im; #ifdef NOCOPY #error check rpd->rpd_decoder->oc_stream_corrupt OMX_PARAM_PORTDEFINITIONTYPE portdef; memset(&portdef, 0, sizeof(portdef)); portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); portdef.nVersion.nVersion = OMX_VERSION; portdef.nPortIndex = rpd->rpd_decoder->oc_inport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_send_command(rpd->rpd_decoder, OMX_CommandPortEnable, rpd->rpd_decoder->oc_inport, NULL, 0); OMX_BUFFERHEADERTYPE *buf; for(int i = 0; i < portdef.nBufferCountActual; i++) { omxchk(OMX_UseBuffer(rpd->rpd_decoder->oc_handle, &buf, rpd->rpd_decoder->oc_inport, NULL, pm->pm_size, pm->pm_data)); } // Waits for the OMX_CommandPortEnable command omx_wait_command(rpd->rpd_decoder); omx_set_state(rpd->rpd_decoder, OMX_StateExecuting); CHECKPOINT("Initialized"); buf->nOffset = 0; buf->nFilledLen = pm->pm_size; buf->nFlags |= OMX_BUFFERFLAG_EOS; rpd->rpd_decoder->oc_inflight_buffers++; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); while(rpd->rpd_change == 0) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); CHECKPOINT("Setup tunnel"); setup_tunnel(rpd); #else const void *data = pm->pm_data; size_t len = pm->pm_size; hts_mutex_lock(&rpd->rpd_mtx); while(len > 0) { OMX_BUFFERHEADERTYPE *buf; if(rpd->rpd_decoder->oc_stream_corrupt) break; if(rpd->rpd_change == 1) { rpd->rpd_change = 2; hts_mutex_unlock(&rpd->rpd_mtx); setup_tunnel(rpd); hts_mutex_lock(&rpd->rpd_mtx); continue; } if(rpd->rpd_decoder->oc_avail == NULL) { hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); continue; } buf = rpd->rpd_decoder->oc_avail; rpd->rpd_decoder->oc_avail = buf->pAppPrivate; rpd->rpd_decoder->oc_inflight_buffers++; hts_mutex_unlock(&rpd->rpd_mtx); buf->nOffset = 0; buf->nFilledLen = MIN(len, buf->nAllocLen); memcpy(buf->pBuffer, data, buf->nFilledLen); buf->nFlags = 0; if(len <= buf->nAllocLen) buf->nFlags |= OMX_BUFFERFLAG_EOS; data += buf->nFilledLen; len -= buf->nFilledLen; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); } if(rpd->rpd_decoder->oc_stream_corrupt) { hts_mutex_unlock(&rpd->rpd_mtx); goto err; } if(rpd->rpd_change != 2) { while(rpd->rpd_change == 0 && !rpd->rpd_decoder->oc_stream_corrupt) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); if(rpd->rpd_decoder->oc_stream_corrupt) goto err; setup_tunnel(rpd); } else { hts_mutex_unlock(&rpd->rpd_mtx); } #endif omx_wait_fill_buffer(rpd->rpd_resizer, rpd->rpd_buf); CHECKPOINT("Got buffer"); err: omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_inport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); if(rpd->rpd_tunnel != NULL) { omx_tunnel_destroy(rpd->rpd_tunnel); rpd->rpd_tunnel = NULL; } omx_set_state(rpd->rpd_decoder, OMX_StateIdle); omx_set_state(rpd->rpd_resizer, OMX_StateIdle); if(rpd->rpd_buf != NULL) { omxchk(OMX_FreeBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_resizer->oc_outport, rpd->rpd_buf)); } omx_release_buffers(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_set_state(rpd->rpd_resizer, OMX_StateLoaded); omx_set_state(rpd->rpd_decoder, OMX_StateLoaded); omx_component_destroy(rpd->rpd_resizer); omx_component_destroy(rpd->rpd_decoder); hts_cond_destroy(&rpd->rpd_cond); hts_mutex_destroy(&rpd->rpd_mtx); pixmap_t *out = rpd->rpd_pm; if(out) { pixmap_release(pm); } else { snprintf(errbuf, errlen, "Load error"); } free(rpd); CHECKPOINT("All done"); return out; }