diff -Nru showtime-4.3~git201303030928.de886c7/Makefile showtime-4.3~git201303112047.200884e/Makefile --- showtime-4.3~git201303030928.de886c7/Makefile 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/Makefile 2013-03-11 18:47:52.000000000 +0000 @@ -224,7 +224,7 @@ src/video/video_settings.c \ SRCS-$(CONFIG_VDPAU) += src/video/vdpau.c -SRCS-$(CONFIG_PS3_VDEC) += src/video/ps3_vdec.c +SRCS-$(CONFIG_PS3_VDEC) += src/video/ps3_vdec.c src/video/h264_annexb.c SRCS-$(CONFIG_VDA) += src/video/vda.c ############################################################## diff -Nru showtime-4.3~git201303030928.de886c7/configure.rpi showtime-4.3~git201303112047.200884e/configure.rpi --- showtime-4.3~git201303030928.de886c7/configure.rpi 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/configure.rpi 2013-03-11 18:47:52.000000000 +0000 @@ -58,7 +58,8 @@ STRIP=${TOOLCHAIN}strip OBJDUMP=${TOOLCHAIN}objdump OBJCOPY=${TOOLCHAIN}objcopy -CFLAGS_cfg += -mfpu=vfp -mcpu=arm1176jzf-s +CFLAGS_cfg += -mfpu=vfp -mcpu=arm1176jzf-s -funwind-tables +CFLAGS_cfg += -DOMX_SKIP64BIT CFLAGS_cfg += -I${VCROOT}/include CFLAGS_cfg += -I${VCROOT}/include/IL diff -Nru showtime-4.3~git201303030928.de886c7/debian/changelog showtime-4.3~git201303112047.200884e/debian/changelog --- showtime-4.3~git201303030928.de886c7/debian/changelog 2013-03-03 07:31:28.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/debian/changelog 2013-03-11 18:50:47.000000000 +0000 @@ -1,8 +1,8 @@ -showtime (4.3~git201303030928.de886c7-0ubuntu1~ppa1~quantal1) quantal; urgency=low +showtime (4.3~git201303112047.200884e-0ubuntu1~ppa1~quantal1) quantal; urgency=low * Auto build - -- Johan Abbors Sun, 03 Mar 2013 09:28:39 +0200 + -- Johan Abbors Mon, 11 Mar 2013 20:47:53 +0200 showtime (4.2-0ubuntu1~ppa1) precise; urgency=low diff -Nru showtime-4.3~git201303030928.de886c7/glwskins/default/universe.view showtime-4.3~git201303112047.200884e/glwskins/default/universe.view --- showtime-4.3~git201303030928.de886c7/glwskins/default/universe.view 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/glwskins/default/universe.view 2013-03-11 18:47:52.000000000 +0000 @@ -2,7 +2,7 @@ $ui.monofont = "dataroot://resources/fonts/UbuntuMono-Regular.ttf"; $ui.condensedfont = $global.fonts.condensed ?? "skin://fonts/OpenSans-CondBold.ttf"; -$ui.background = "graphics/background.jpg"; +$ui.background = "skin://graphics/background.jpg"; onEvent(logwindow, { $ui.logwindow = !$ui.logwindow; diff -Nru showtime-4.3~git201303030928.de886c7/src/arch/rpi/omx.c showtime-4.3~git201303112047.200884e/src/arch/rpi/omx.c --- showtime-4.3~git201303030928.de886c7/src/arch/rpi/omx.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/arch/rpi/omx.c 2013-03-11 18:47:52.000000000 +0000 @@ -1,6 +1,7 @@ #include #include +#include "media.h" #include "omx.h" /** @@ -15,7 +16,7 @@ omxdbg("%s: event 0x%x 0x%x 0x%x %p\n", oc->oc_name, event, (int)data1, (int)data2, eventdata); - hts_mutex_lock(oc->oc_mtx); + hts_mutex_lock(&oc->oc_event_mtx); switch(event) { case OMX_EventCmdComplete: @@ -36,11 +37,16 @@ printf("%s: ERROR 0x%x\n", oc->oc_name, (int)data1); exit(1); + + case OMX_EventPortSettingsChanged: + oc->oc_port_settings_changed = 1; + break; + default: break; } - hts_mutex_unlock(oc->oc_mtx); + hts_mutex_unlock(&oc->oc_event_mtx); return 0; } @@ -54,24 +60,36 @@ OMX_BUFFERHEADERTYPE* buf) { omx_component_t *oc = opaque; - - hts_mutex_lock(oc->oc_mtx); - + hts_mutex_lock(oc->oc_avail_mtx); oc->oc_inflight_buffers--; buf->pAppPrivate = oc->oc_avail; oc->oc_avail = buf; hts_cond_signal(oc->oc_avail_cond); - hts_mutex_unlock(oc->oc_mtx); - + hts_mutex_unlock(oc->oc_avail_mtx); return 0; } + +/** + * + */ +static void +omx_wait_command(omx_component_t *oc) +{ + hts_mutex_lock(&oc->oc_event_mtx); + while(!oc->oc_cmd_done) + hts_cond_wait(&oc->oc_event_cond, &oc->oc_event_mtx); + hts_mutex_unlock(&oc->oc_event_mtx); +} + + /** * */ static void -omx_send_command(omx_component_t *oc, OMX_COMMANDTYPE cmd, int v, void *p, int wait) +omx_send_command(omx_component_t *oc, OMX_COMMANDTYPE cmd, int v, void *p, + int wait) { oc->oc_cmd_done = 0; @@ -79,13 +97,8 @@ omxchk(OMX_SendCommand(oc->oc_handle, cmd, v, p)); - if(!wait) - return; - - hts_mutex_lock(oc->oc_mtx); - while(!oc->oc_cmd_done) - hts_cond_wait(&oc->oc_event_cond, oc->oc_mtx); - hts_mutex_unlock(oc->oc_mtx); + if(wait) + omx_wait_command(oc); } @@ -102,9 +115,10 @@ OMX_IndexParamImageInit, OMX_IndexParamOtherInit}; - oc->oc_mtx = mtx; + oc->oc_avail_mtx = mtx; oc->oc_avail_cond = avail; - hts_cond_init(&oc->oc_event_cond, oc->oc_mtx); + hts_mutex_init(&oc->oc_event_mtx); + hts_cond_init(&oc->oc_event_cond, &oc->oc_event_mtx); oc->oc_name = strdup(name); @@ -196,6 +210,8 @@ buf->pAppPrivate = oc->oc_avail; oc->oc_avail = buf; } + omx_wait_command(oc); // Waits for the OMX_CommandPortEnable command + } @@ -203,16 +219,26 @@ * */ OMX_BUFFERHEADERTYPE * -omx_get_buffer(omx_component_t *oc) +omx_get_buffer_locked(omx_component_t *oc) { OMX_BUFFERHEADERTYPE *buf; - hts_mutex_lock(oc->oc_mtx); while((buf = oc->oc_avail) == NULL) - hts_cond_wait(oc->oc_avail_cond, oc->oc_mtx); + hts_cond_wait(oc->oc_avail_cond, oc->oc_avail_mtx); oc->oc_avail = buf->pAppPrivate; oc->oc_inflight_buffers++; - hts_mutex_unlock(oc->oc_mtx); + return buf; +} + +/** + * + */ +OMX_BUFFERHEADERTYPE * +omx_get_buffer(omx_component_t *oc) +{ + hts_mutex_lock(oc->oc_avail_mtx); + OMX_BUFFERHEADERTYPE *buf = omx_get_buffer_locked(oc); + hts_mutex_unlock(oc->oc_avail_mtx); return buf; } @@ -224,10 +250,10 @@ void omx_wait_buffers(omx_component_t *oc) { - hts_mutex_lock(oc->oc_mtx); + hts_mutex_lock(oc->oc_avail_mtx); while(oc->oc_inflight_buffers) - hts_cond_wait(oc->oc_avail_cond, oc->oc_mtx); - hts_mutex_unlock(oc->oc_mtx); + hts_cond_wait(oc->oc_avail_cond, oc->oc_avail_mtx); + hts_mutex_unlock(oc->oc_avail_mtx); } @@ -253,7 +279,7 @@ */ omx_tunnel_t * omx_tunnel_create(omx_component_t *src, int srcport, omx_component_t *dst, - int dstport, int portstream) + int dstport) { OMX_STATETYPE state; omxchk(OMX_GetState(src->oc_handle, &state)); @@ -292,3 +318,92 @@ omxchk(OMX_SetupTunnel(ot->ot_src->oc_handle, ot->ot_srcport, NULL, 0)); free(ot); } + + +/** + * + */ +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_flush_port(omx_component_t *oc, int port) +{ + printf("Flushing %s %d\n", oc->oc_name, port); + omx_send_command(oc, OMX_CommandFlush, port, NULL, 1); +} + + +/** + * + */ +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); +} + + +/** + * + */ +static void +omx_mp_fini(media_pipe_t *mp) +{ + if(mp->mp_extra != NULL) + omx_component_destroy(mp->mp_extra); +} + + +/** + * + */ +void +omx_init(void) +{ + OMX_Init(); + + media_pipe_init_extra = omx_mp_init; + media_pipe_fini_extra = omx_mp_fini; +} + diff -Nru showtime-4.3~git201303030928.de886c7/src/arch/rpi/omx.h showtime-4.3~git201303112047.200884e/src/arch/rpi/omx.h --- showtime-4.3~git201303030928.de886c7/src/arch/rpi/omx.h 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/arch/rpi/omx.h 2013-03-11 18:47:52.000000000 +0000 @@ -16,12 +16,17 @@ typedef struct omx_component { OMX_HANDLETYPE oc_handle; char *oc_name; - hts_mutex_t *oc_mtx; - hts_cond_t oc_event_cond; + hts_mutex_t *oc_avail_mtx; hts_cond_t *oc_avail_cond; + + hts_mutex_t oc_event_mtx; + hts_cond_t oc_event_cond; + OMX_BUFFERHEADERTYPE *oc_avail; int oc_inflight_buffers; int oc_cmd_done; + int oc_port_settings_changed; + } omx_component_t; typedef struct omx_tunnel { @@ -53,15 +58,19 @@ #endif +void omx_init(void); omx_component_t *omx_component_create(const char *name, hts_mutex_t *mtx, hts_cond_t *avail); void omx_component_destroy(omx_component_t *oc); void omx_set_state(omx_component_t *oc, OMX_STATETYPE reqstate); void omx_alloc_buffers(omx_component_t *oc, int port); +OMX_BUFFERHEADERTYPE *omx_get_buffer_locked(omx_component_t *oc); OMX_BUFFERHEADERTYPE *omx_get_buffer(omx_component_t *oc); void omx_wait_buffers(omx_component_t *oc); void omx_release_buffers(omx_component_t *oc, int port); omx_tunnel_t *omx_tunnel_create(omx_component_t *src, int srcport, - omx_component_t *dst, int dstport, - int portstream); + omx_component_t *dst, int dstport); void omx_tunnel_destroy(omx_tunnel_t *ot); +int64_t omx_get_media_time(omx_component_t *oc); +void omx_flush_port(omx_component_t *oc, int port); + diff -Nru showtime-4.3~git201303030928.de886c7/src/arch/rpi/rpi_audio.c showtime-4.3~git201303112047.200884e/src/arch/rpi/rpi_audio.c --- showtime-4.3~git201303030928.de886c7/src/arch/rpi/rpi_audio.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/arch/rpi/rpi_audio.c 2013-03-11 18:47:52.000000000 +0000 @@ -7,7 +7,9 @@ typedef struct decoder { audio_decoder_t ad; omx_component_t *d_render; + omx_tunnel_t *d_clock_tun; int d_bpf; // Bytes per frame + int d_first_sent; } decoder_t; @@ -25,6 +27,10 @@ omx_wait_buffers(d->d_render); omx_set_state(d->d_render, OMX_StateIdle); omx_release_buffers(d->d_render, 100); + + if(d->d_clock_tun) + omx_tunnel_destroy(d->d_clock_tun); + omx_set_state(d->d_render, OMX_StateLoaded); omx_component_destroy(d->d_render); } @@ -36,6 +42,7 @@ static int rpi_audio_reconfig(audio_decoder_t *ad) { + media_pipe_t *mp = ad->ad_mp; decoder_t *d = (decoder_t *)ad; rpi_audio_fini(ad); @@ -54,6 +61,9 @@ OMX_IndexConfigBrcmAudioDestination, &audioDest)); + if(mp->mp_extra) + d->d_clock_tun = omx_tunnel_create(mp->mp_extra, 80, d->d_render, 101); + // Initialize audio render OMX_PARAM_PORTDEFINITIONTYPE param; OMX_AUDIO_PARAM_PCMMODETYPE pcm; @@ -126,6 +136,7 @@ omx_component_t *oc = d->d_render; OMX_BUFFERHEADERTYPE *buf; + if((buf = oc->oc_avail) == NULL) return 1; @@ -136,8 +147,14 @@ data[0] = (uint8_t *)buf->pBuffer; int r = avresample_read(ad->ad_avr, data, samples); + if(!d->d_first_sent) { + buf->nFlags |= OMX_BUFFERFLAG_STARTTIME; + d->d_first_sent = 1; + } + buf->nOffset = 0; buf->nFilledLen = r * d->d_bpf; + buf->nTimeStamp = omx_ticks_from_s64(pts); hts_mutex_unlock(&ad->ad_mp->mp_mutex); omxchk(OMX_EmptyThisBuffer(oc->oc_handle, buf)); hts_mutex_lock(&ad->ad_mp->mp_mutex); diff -Nru showtime-4.3~git201303030928.de886c7/src/arch/rpi/rpi_main.c showtime-4.3~git201303112047.200884e/src/arch/rpi/rpi_main.c --- showtime-4.3~git201303030928.de886c7/src/arch/rpi/rpi_main.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/arch/rpi/rpi_main.c 2013-03-11 18:47:52.000000000 +0000 @@ -38,13 +38,17 @@ #include "arch/linux/linux.h" #include "prop/prop.h" #include "ui/glw/glw.h" +#include "ui/background.h" #include "navigator.h" +#include "omx.h" +#include "backend/backend.h" static uint32_t screen_width, screen_height; static EGLDisplay display; static EGLContext context; static EGLSurface surface; +static DISPMANX_DISPLAY_HANDLE_T dispman_display; /** * @@ -71,7 +75,6 @@ EGL_DISPMANX_WINDOW_T nw; DISPMANX_ELEMENT_HANDLE_T de; - DISPMANX_DISPLAY_HANDLE_T dd; DISPMANX_UPDATE_HANDLE_T u; VC_RECT_T dst_rect; VC_RECT_T src_rect; @@ -125,19 +128,21 @@ success = graphics_get_display_size(0, &screen_width, &screen_height); assert(success >= 0); - dd = vc_dispmanx_display_open(0); + dispman_display = vc_dispmanx_display_open(0); + + u = vc_dispmanx_update_start(0); DISPMANX_RESOURCE_HANDLE_T r; uint32_t ip; - + int rw = 32; int rh = 32; r = vc_dispmanx_resource_create(VC_IMAGE_RGB565, rw, rh, &ip); void *zero = calloc(1, rw * rh * 2); - + memset(zero, 0xcc, rw * rh * 2); VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, rw, rh); @@ -153,10 +158,12 @@ src_rect.x = 0; src_rect.y = 0; src_rect.width = rw << 16; - src_rect.height = rh << 16; - vc_dispmanx_element_add(u, dd, 0, &dst_rect, r, + src_rect.height = rh << 16; +#if 0 + vc_dispmanx_element_add(u, dd, 1, &dst_rect, r, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, 0); +#endif dst_rect.x = 0; dst_rect.y = 0; @@ -168,7 +175,7 @@ src_rect.width = screen_width << 16; src_rect.height = screen_height << 16; - de = vc_dispmanx_element_add(u, dd, 10, &dst_rect, 0, + de = vc_dispmanx_element_add(u, dispman_display, 10, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, 0); @@ -191,6 +198,119 @@ } +static DISPMANX_ELEMENT_HANDLE_T bg_element; +static int bg_resource; +static float bg_current_alpha; +static VC_RECT_T bg_src_rect; +static VC_RECT_T bg_dst_rect; + +/** + * + */ +static void +bg_refresh_element(void) +{ + DISPMANX_UPDATE_HANDLE_T u = vc_dispmanx_update_start(0); + + VC_DISPMANX_ALPHA_T alpha; + alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; + alpha.opacity = bg_current_alpha * 255; + alpha.mask = 0; + + if(alpha.opacity == 0) { + if(bg_element) { + vc_dispmanx_element_remove(u, bg_element); + bg_element = 0; + } + } else if(!bg_element) { + if(bg_resource) { + bg_element = vc_dispmanx_element_add(u, dispman_display, -10, + &bg_dst_rect, bg_resource, + &bg_src_rect, + DISPMANX_PROTECTION_NONE, + &alpha, NULL, 0); + } + } else { + vc_dispmanx_element_change_attributes(u, bg_element, + 1 << 1, + 0, + alpha.opacity, + NULL, NULL, 0, 0); + } + vc_dispmanx_update_submit_sync(u); +} + + + + +/** + * + */ +static void +set_bg_image(rstr_t *url, const char **vpaths, void *opaque) +{ + char errbuf[256]; + image_meta_t im = {0}; + im.im_req_width = screen_width; + im.im_req_height = screen_height; + + pixmap_t *pm; + pm = backend_imageloader(url, &im, vpaths, errbuf, sizeof(errbuf), + NULL, NULL, NULL); + + if(pm == NULL) { + TRACE(TRACE_ERROR, "BG", "Unable to load %s -- %s", rstr_get(url), errbuf); + return; + } + + uint32_t ip; + VC_IMAGE_TYPE_T it; + + switch(pm->pm_type) { + case PIXMAP_BGR32: + it = VC_IMAGE_ARGB8888; + break; + case PIXMAP_RGB24: + it = VC_IMAGE_RGB888; + break; + default: + pixmap_release(pm); + return; + } + + if(bg_resource) + vc_dispmanx_resource_delete(bg_resource); + + + bg_resource = + vc_dispmanx_resource_create(it, pm->pm_width, pm->pm_height, &ip); + + vc_dispmanx_rect_set(&bg_src_rect, 0, 0, + pm->pm_width << 16, pm->pm_height << 16); + vc_dispmanx_rect_set(&bg_dst_rect, 0, 0, + pm->pm_width, pm->pm_height); + + vc_dispmanx_resource_write_data(bg_resource, it, pm->pm_linesize, + pm->pm_pixels, &bg_dst_rect); + + pixmap_release(pm); + + bg_refresh_element(); +} + +/** + * + */ +static void +set_bg_alpha(float alpha, void *opaque) +{ + bg_current_alpha = alpha; + bg_refresh_element(); +} + + + + /** * */ @@ -200,6 +320,11 @@ glw_root_t *gr = calloc(1, sizeof(glw_root_t)); gr->gr_prop_ui = prop_create_root("ui"); gr->gr_prop_nav = nav_spawn(); + prop_set(gr->gr_prop_ui, "nobackground", PROP_SET_INT, 1); + + background_init(gr->gr_prop_ui, gr->gr_prop_nav, + set_bg_image, set_bg_alpha, NULL); + gr->gr_width = screen_width; gr->gr_height = screen_height; @@ -243,7 +368,7 @@ { bcm_host_init(); - OMX_Init(); + omx_init(); gconf.binary = argv[0]; diff -Nru showtime-4.3~git201303030928.de886c7/src/media.c showtime-4.3~git201303112047.200884e/src/media.c --- showtime-4.3~git201303030928.de886c7/src/media.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/media.c 2013-03-11 18:47:52.000000000 +0000 @@ -57,6 +57,9 @@ static struct media_pipe_list media_pipe_stack; media_pipe_t *media_primary; +void (*media_pipe_init_extra)(media_pipe_t *mp); +void (*media_pipe_fini_extra)(media_pipe_t *mp); + static int mp_seek_in_queues(media_pipe_t *mp, int64_t pos); static void seek_by_propchange(void *opaque, prop_event_t event, ...); @@ -469,7 +472,8 @@ mp->mp_pc, NULL, NULL); - + if(media_pipe_init_extra != NULL) + media_pipe_init_extra(mp); return mp; } @@ -531,13 +535,15 @@ { event_t *e; - /* Make sure a clean shutdown has been made */ assert(mp->mp_audio_decoder == NULL); assert(mp != media_primary); assert(!(mp->mp_flags & MP_ON_STACK)); + if(media_pipe_fini_extra != NULL) + media_pipe_fini_extra(mp); + setting_destroy(mp->mp_setting_av_delta); setting_destroy(mp->mp_setting_sv_delta); setting_destroy(mp->mp_setting_sub_scale); diff -Nru showtime-4.3~git201303030928.de886c7/src/media.h showtime-4.3~git201303112047.200884e/src/media.h --- showtime-4.3~git201303030928.de886c7/src/media.h 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/media.h 2013-03-11 18:47:52.000000000 +0000 @@ -426,8 +426,17 @@ struct setting *mp_setting_fstretch; // Fullscreen stretch struct setting *mp_setting_vdpau_deinterlace; // Deinterlace interlaced content + /** + * Extra (created by media_pipe_init_extra) + */ + void *mp_extra; + } media_pipe_t; +extern void (*media_pipe_init_extra)(media_pipe_t *mp); +extern void (*media_pipe_fini_extra)(media_pipe_t *mp); + + struct AVFormatContext; struct AVCodecContext; struct media_format; diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/background.c showtime-4.3~git201303112047.200884e/src/ui/background.c --- showtime-4.3~git201303030928.de886c7/src/ui/background.c 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/background.c 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,257 @@ +/* + * Showtime mediacenter + * Copyright (C) 2007-2013 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "showtime.h" +#include "prop/prop.h" +#include "background.h" + + +typedef struct bg_helper { + void (*set_image)(rstr_t *url, const char **vpaths, void *opaque); + void (*set_alpha)(float alpha, void *opaque); + void *opaque; + prop_courier_t *pc; + + int fullwindow; + int screensaver; + + rstr_t *skin_path; + rstr_t *bg_url[3]; + float bg_alpha[2]; +} bg_helper_t; + + +/** + * + */ +static void +set_in_fullwindow(bg_helper_t *bgh, int v) +{ + bgh->fullwindow = v; +} + + +/** + * + */ +static void +set_in_screensaver(bg_helper_t *bgh, int v) +{ + bgh->screensaver = v; +} + + +/** + * + */ +static void +set_skin_path(bg_helper_t *bgh, rstr_t *r) +{ + rstr_set(&bgh->skin_path, r); +} + + +/** + * + */ +static void +set_bg0(bg_helper_t *bgh, rstr_t *r) +{ + rstr_set(&bgh->bg_url[0], r); +} + + +/** + * + */ +static void +set_bg1(bg_helper_t *bgh, rstr_t *r) +{ + rstr_set(&bgh->bg_url[1], r); +} + + +/** + * + */ +static void +set_bg2(bg_helper_t *bgh, rstr_t *r) +{ + rstr_set(&bgh->bg_url[2], r); +} + + +/** + * + */ +static void +set_alpha0(bg_helper_t *bgh, float a) +{ + bgh->bg_alpha[0] = a; +} + + +/** + * + */ +static void +set_alpha1(bg_helper_t *bgh, float a) +{ + bgh->bg_alpha[1] = a; +} + + +/** + * + */ +static void * +bgloader_thread(void *aux) +{ + bg_helper_t *bgh = aux; + + rstr_t *current_bg = NULL; + float current_alpha = 0; + + while(1) { + struct prop_notify_queue exp, nor; + + float alpha = 1.0f; + int timo = alpha != current_alpha ? 50 : 0; + + prop_courier_wait(bgh->pc, &nor, &exp, timo); + prop_notify_dispatch(&exp); + prop_notify_dispatch(&nor); + + rstr_t *bg; + if(bgh->bg_url[0]) { + bg = bgh->bg_url[0]; + + if(bgh->bg_alpha[0]) + alpha = bgh->bg_alpha[0]; + } else if(bgh->bg_url[1]) { + bg = bgh->bg_url[1]; + + if(bgh->bg_alpha[1]) + alpha = bgh->bg_alpha[1]; + } else { + bg = bgh->bg_url[2]; + } + + if(bgh->fullwindow || bgh->screensaver) + alpha = 0; + + if(alpha != current_alpha) { + if(current_alpha < alpha) + current_alpha = MIN(alpha, current_alpha + 0.1); + else if(current_alpha > alpha) + current_alpha = MAX(alpha, current_alpha - 0.1); + + bgh->set_alpha(current_alpha, bgh->opaque); + } + + if(!rstr_eq(current_bg, bg)) { + rstr_set(¤t_bg, bg); + const char *v[3]; + + v[0] = "skin"; + v[1] = rstr_get(bgh->skin_path); + v[2] = NULL; + + bgh->set_image(bg, v, bgh->opaque); + } + + } + return NULL; +} + +/** + * + */ +void +background_init(prop_t *ui, prop_t *nav, + void (*set_image)(rstr_t *url, const char **vpaths, + void *opaque), + void (*set_alpha)(float alpha, void *opaque), + void *opaque) +{ + bg_helper_t *bgh = calloc(1, sizeof(bg_helper_t)); + bgh->pc = prop_courier_create_waitable(); + bgh->set_image = set_image; + bgh->set_alpha = set_alpha; + + prop_subscribe(0, + PROP_TAG_NAME("ui","fullwindow"), + PROP_TAG_CALLBACK_INT, set_in_fullwindow, bgh, + PROP_TAG_ROOT, ui, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("ui","screensaverActive"), + PROP_TAG_CALLBACK_INT, set_in_screensaver, bgh, + PROP_TAG_ROOT, ui, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("ui","skin", "path"), + PROP_TAG_CALLBACK_RSTR, set_skin_path, bgh, + PROP_TAG_ROOT, ui, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("ui","background"), + PROP_TAG_CALLBACK_RSTR, set_bg2, bgh, + PROP_TAG_ROOT, ui, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("nav","currentpage","glw", "background"), + PROP_TAG_CALLBACK_RSTR, set_bg1, bgh, + PROP_TAG_ROOT, nav, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("nav","currentpage", "model", "metadata", + "background"), + PROP_TAG_CALLBACK_RSTR, set_bg0, bgh, + PROP_TAG_ROOT, nav, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("nav","currentpage","glw", "backgroundAlpha"), + PROP_TAG_CALLBACK_FLOAT, set_alpha1, bgh, + PROP_TAG_ROOT, nav, + PROP_TAG_COURIER, bgh->pc, + NULL); + + prop_subscribe(0, + PROP_TAG_NAME("nav","currentpage", "model", "metadata", + "backgroundAlpha"), + PROP_TAG_CALLBACK_FLOAT, set_alpha0, bgh, + PROP_TAG_ROOT, nav, + PROP_TAG_COURIER, bgh->pc, + NULL); + + hts_thread_create_detached("bgloader", bgloader_thread, bgh, + THREAD_PRIO_LOW); +} diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/background.h showtime-4.3~git201303112047.200884e/src/ui/background.h --- showtime-4.3~git201303030928.de886c7/src/ui/background.h 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/background.h 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,7 @@ +#pragma once + +void background_init(prop_t *ui, prop_t *nav, + void (*set_image)(rstr_t *url, const char **vpaths, + void *opaque), + void (*set_alpha)(float alpha, void *opaque), + void *opaque); diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/glw/glw.c showtime-4.3~git201303112047.200884e/src/ui/glw/glw.c --- showtime-4.3~git201303030928.de886c7/src/ui/glw/glw.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/glw/glw.c 2013-03-11 18:47:52.000000000 +0000 @@ -194,6 +194,9 @@ glw_text_bitmap_init(gr); + prop_setv(gr->gr_prop_ui, "skin", "path", NULL, + PROP_SET_STRING, gr->gr_skin); + gr->gr_pointer_visible = prop_create(gr->gr_prop_ui, "pointerVisible"); gr->gr_is_fullscreen = prop_create(gr->gr_prop_ui, "fullscreen"); gr->gr_screensaver_active = prop_create(gr->gr_prop_ui, "screensaverActive"); diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_common.c showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_common.c --- showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_common.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_common.c 2013-03-11 18:47:52.000000000 +0000 @@ -317,6 +317,9 @@ hts_cond_destroy(&gv->gv_avail_queue_cond); hts_cond_destroy(&gv->gv_reconf_cond); hts_mutex_destroy(&gv->gv_surface_mutex); + + mp_ref_dec(gv->gv_mp); + gv->gv_mp = NULL; } @@ -374,8 +377,6 @@ hts_mutex_unlock(&gv->gv_surface_mutex); video_playback_destroy(gv->gv_mp); video_decoder_stop(vd); - mp_ref_dec(gv->gv_mp); - gv->gv_mp = NULL; return 0; case GLW_SIGNAL_POINTER_EVENT: @@ -741,23 +742,21 @@ glw_video_t *gv = opaque; glw_video_engine_t *gve; - if(fi) { - gv->gv_dar_num = fi->fi_dar_num; - gv->gv_dar_den = fi->fi_dar_den; - gv->gv_vheight = fi->fi_height; - } hts_mutex_lock(&gv->gv_surface_mutex); if(fi == NULL) { // Blackout glw_video_configure(gv, &glw_video_blank, NULL, NULL, 0, 0, 0); - hts_mutex_unlock(&gv->gv_surface_mutex); - return; - } + } else { + + gv->gv_dar_num = fi->fi_dar_num; + gv->gv_dar_den = fi->fi_dar_den; + gv->gv_vheight = fi->fi_height; - LIST_FOREACH(gve, &engines, gve_link) - if(gve->gve_type == fi->fi_type) - gve->gve_deliver(fi, gv); + LIST_FOREACH(gve, &engines, gve_link) + if(gve->gve_type == fi->fi_type) + gve->gve_deliver(fi, gv); + } hts_mutex_unlock(&gv->gv_surface_mutex); } diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_common.h showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_common.h --- showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_common.h 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_common.h 2013-03-11 18:47:52.000000000 +0000 @@ -184,6 +184,8 @@ int64_t gv_nextpts; + void *gv_aux; + /** * VDPAU specifics */ diff -Nru showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_rpi.c showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_rpi.c --- showtime-4.3~git201303030928.de886c7/src/ui/glw/glw_video_rpi.c 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/ui/glw/glw_video_rpi.c 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * VDPAU accelerated OpenGL video engine + * Copyright (C) 2010 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "showtime.h" +#include "glw_video_common.h" + +#include "video/video_settings.h" +#include "arch/rpi/omx.h" + + +typedef struct rpi_video { + omx_component_t *rv_vdecoder; + omx_component_t *rv_vrender; + omx_component_t *rv_vsched; + + omx_tunnel_t *rv_tun_clock_vsched; + omx_tunnel_t *rv_tun_vdecoder_vsched; + omx_tunnel_t *rv_tun_vsched_vrender; + +} rpi_video_t; + + +/** + * + */ +static int +rpi_video_init(glw_video_t *gv, rpi_video_t *rv, media_pipe_t *mp) +{ + + rv->rv_vdecoder = omx_component_create("OMX.broadcom.video_decode", + &gv->gv_surface_mutex, + &gv->gv_avail_queue_cond); + rv->rv_vrender = omx_component_create("OMX.broadcom.video_render", + NULL, NULL); + rv->rv_vsched = omx_component_create("OMX.broadcom.video_scheduler", + NULL, NULL); + + if(rv->rv_vdecoder == NULL || + rv->rv_vrender == NULL || + rv->rv_vsched == NULL) { + return 1; + } + + rv->rv_tun_clock_vsched = + omx_tunnel_create(mp->mp_extra, 81, rv->rv_vsched, 12); + + + omx_set_state(rv->rv_vdecoder, OMX_StateIdle); + + OMX_VIDEO_PARAM_PORTFORMATTYPE format; + OMX_INIT_STRUCTURE(format); + format.nPortIndex = 130; + format.eCompressionFormat = OMX_VIDEO_CodingAVC; + + omxchk(OMX_SetParameter(rv->rv_vdecoder->oc_handle, + OMX_IndexParamVideoPortFormat, &format)); + + + omx_alloc_buffers(rv->rv_vdecoder, 130); + omx_set_state(rv->rv_vdecoder, OMX_StateExecuting); + return 0; +} + + +/** + * + */ +static int64_t +rpi_video_newframe(glw_video_t *gv, video_decoder_t *vd0, int flags) +{ + int64_t pts = PTS_UNSET; + return pts; +} + + + +/** + * + */ +static void +rpi_h264_reset(glw_video_t *gv) +{ + rpi_video_t *rv = gv->gv_aux; + + omx_flush_port(rv->rv_vdecoder, 130); + omx_flush_port(rv->rv_vdecoder, 131); + + omx_flush_port(rv->rv_vsched, 10); + omx_flush_port(rv->rv_vsched, 11); + + omx_flush_port(rv->rv_vrender, 90); + + omx_wait_buffers(rv->rv_vdecoder); + + if(rv->rv_tun_vsched_vrender != NULL) + omx_tunnel_destroy(rv->rv_tun_vsched_vrender); + + if(rv->rv_tun_vdecoder_vsched != NULL) + omx_tunnel_destroy(rv->rv_tun_vdecoder_vsched); + + omx_tunnel_destroy(rv->rv_tun_clock_vsched); + + omx_set_state(rv->rv_vrender, OMX_StateIdle); + omx_set_state(rv->rv_vsched, OMX_StateIdle); + omx_set_state(rv->rv_vdecoder, OMX_StateIdle); + + omx_release_buffers(rv->rv_vdecoder, 130); + + omx_set_state(rv->rv_vrender, OMX_StateLoaded); + omx_set_state(rv->rv_vsched, OMX_StateLoaded); + omx_set_state(rv->rv_vdecoder, OMX_StateLoaded); + + omx_component_destroy(rv->rv_vrender); + omx_component_destroy(rv->rv_vsched); + omx_component_destroy(rv->rv_vdecoder); + free(rv); +} + + +/** + * + */ +static int +rpi_h264_init(glw_video_t *gv) +{ + rpi_video_t *rv = calloc(1, sizeof(rpi_video_t)); + gv->gv_aux = rv; + rpi_video_init(gv, rv, gv->gv_mp); + + + return 0; +} + +/** + * + */ +static void +rpi_video_render(glw_video_t *gv, glw_rctx_t *rc) +{ + +} + +static void h264_deliver(const frame_info_t *fi, glw_video_t *gv); + +/** + * Raw h264 packets + */ +static glw_video_engine_t glw_video_h264 = { + .gve_type = 'h264', + .gve_newframe = rpi_video_newframe, + .gve_render = rpi_video_render, + .gve_reset = rpi_h264_reset, + .gve_init = rpi_h264_init, + .gve_deliver = h264_deliver, +}; + +GLW_REGISTER_GVE(glw_video_h264); + +/** + * + */ +static void +h264_deliver(const frame_info_t *fi, glw_video_t *gv) +{ + + if(glw_video_configure(gv, &glw_video_h264, NULL, NULL, 0, 0, 0)) + return; + + rpi_video_t *rv = gv->gv_aux; + + const void *data = fi->fi_data[0]; + size_t len = fi->fi_pitch[0]; + + while(len > 0) { + OMX_BUFFERHEADERTYPE *buf = omx_get_buffer_locked(rv->rv_vdecoder); + pthread_mutex_unlock(&gv->gv_surface_mutex); + buf->nOffset = 0; + buf->nFilledLen = MIN(len, buf->nAllocLen); + memcpy(buf->pBuffer, data, buf->nFilledLen); + + + if(len <= buf->nAllocLen) { + buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + } + + data += buf->nFilledLen; + len -= buf->nFilledLen; + buf->nTimeStamp = omx_ticks_from_s64(fi->fi_pts); + + if(fi->fi_pitch[1]) + buf->nFlags |= OMX_BUFFERFLAG_DECODEONLY; + + if(rv->rv_vdecoder->oc_port_settings_changed) { + rv->rv_vdecoder->oc_port_settings_changed = 0; + rv->rv_tun_vdecoder_vsched = + omx_tunnel_create(rv->rv_vdecoder, 131, rv->rv_vsched, 10); + omx_set_state(rv->rv_vsched, OMX_StateExecuting); + omx_set_state(rv->rv_vrender, OMX_StateIdle); + } + + if(rv->rv_vsched->oc_port_settings_changed) { + rv->rv_vsched->oc_port_settings_changed = 0; + rv->rv_tun_vsched_vrender = + omx_tunnel_create(rv->rv_vsched, 11, rv->rv_vrender, 90); + omx_set_state(rv->rv_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(rv->rv_vrender->oc_handle, + OMX_IndexConfigDisplayRegion, &dr)); + } + omxchk(OMX_EmptyThisBuffer(rv->rv_vdecoder->oc_handle, buf)); + pthread_mutex_lock(&gv->gv_surface_mutex); + } +} diff -Nru showtime-4.3~git201303030928.de886c7/src/video/h264_annexb.c showtime-4.3~git201303112047.200884e/src/video/h264_annexb.c --- showtime-4.3~git201303030928.de886c7/src/video/h264_annexb.c 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/video/h264_annexb.c 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,173 @@ +/* + * h264 annex.b helpers + * Copyright (C) 2013 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "h264_annexb.h" + +/** + * + */ +static void +h264_to_annexb_inplace(uint8_t *b, size_t fsize) +{ + uint8_t *p = b; + while(p < b + fsize) { + if(p[0]) + break; // Avoid overflows with this simple check + int len = (p[1] << 16) + (p[2] << 8) + p[3]; + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = 1; + p += len + 4; + } +} + + +/** + * + */ +static int +h264_to_annexb_buffered(uint8_t *dst, const uint8_t *b, size_t fsize, int lsize) +{ + const uint8_t *p = b; + int i; + int ol = 0; + while(p < b + fsize) { + + int len = 0; + for(i = 0; i < lsize; i++) + len = len << 8 | *p++; + + if(dst) { + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + dst[3] = 1; + memcpy(dst + 4, p, len); + dst += 4 + len; + } + ol += 4 + len; + p += len; + } + return ol; +} + + +/** + * + */ +int +h264_to_annexb(h264_annexb_ctx_t *ctx, uint8_t **datap, size_t *sizep) +{ + int l; + + switch(ctx->lsize) { + case 4: + h264_to_annexb_inplace(*datap, *sizep); + case 0: + + + // submit_au(vdd, &au, mb->mb_data, mb->mb_size, mb->mb_skip == 1, vd); + break; + case 3: + case 2: + case 1: + l = h264_to_annexb_buffered(NULL, *datap, *sizep, ctx->lsize); + if(l > ctx->tmpbufsize) { + ctx->tmpbuf = realloc(ctx->tmpbuf, l); + ctx->tmpbufsize = l; + } + if(ctx->tmpbuf == NULL) + return -1; + h264_to_annexb_buffered(ctx->tmpbuf, *datap, *sizep, ctx->lsize); + *datap = ctx->tmpbuf; + *sizep = l; + break; + } + + // submit_au(vdd, &au, vdd->tmpbuf, l, mb->mb_skip == 1, vd); + + return 0; +} + + +/** + * + */ +static void +append_extradata(h264_annexb_ctx_t *ctx, const uint8_t *data, int len) +{ + ctx->extradata = realloc(ctx->extradata, ctx->extradata_size + len); + memcpy(ctx->extradata + ctx->extradata_size, data, len); + ctx->extradata_size += len; +} + +/** + * + */ +void +h264_to_annexb_init(h264_annexb_ctx_t *ctx, const uint8_t *data, int len) +{ + int i, n, s; + + uint8_t buf[4] = {0,0,0,1}; + + if(len < 7 || data[0] != 1) + return; + + int lsize = (data[4] & 0x3) + 1; + if(lsize == 3) + return; + + n = data[5] & 0x1f; + data += 6; + len -= 6; + + for(i = 0; i < n && len >= 2; i++) { + s = ((data[0] << 8) | data[1]) + 2; + if(len < s) + break; + + append_extradata(ctx, buf, 4); + append_extradata(ctx, data + 2, s - 2); + data += s; + len -= s; + } + + if(len < 1) + return; + n = *data++; + len--; + + for(i = 0; i < n && len >= 2; i++) { + s = ((data[0] << 8) | data[1]) + 2; + if(len < s) + break; + + append_extradata(ctx, buf, 4); + append_extradata(ctx, data + 2, s - 2); + data += s; + len -= s; + } + + ctx->lsize = lsize; +} diff -Nru showtime-4.3~git201303030928.de886c7/src/video/h264_annexb.h showtime-4.3~git201303112047.200884e/src/video/h264_annexb.h --- showtime-4.3~git201303030928.de886c7/src/video/h264_annexb.h 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/video/h264_annexb.h 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +typedef struct h264_annexb_ctx { + int lsize; + uint8_t *tmpbuf; + int tmpbufsize; + size_t extradata_size; + uint8_t *extradata; + int extradata_injected; +} h264_annexb_ctx_t; + +void h264_to_annexb_init(h264_annexb_ctx_t *ctx, + const uint8_t *data, int len); + +int h264_to_annexb(h264_annexb_ctx_t *ctx, uint8_t **datap, size_t *sizep); + +static inline void h264_to_annexb_cleanup(h264_annexb_ctx_t *ctx) +{ + free(ctx->tmpbuf); + free(ctx->extradata); + +} diff -Nru showtime-4.3~git201303030928.de886c7/src/video/h264_passthru.c showtime-4.3~git201303112047.200884e/src/video/h264_passthru.c --- showtime-4.3~git201303030928.de886c7/src/video/h264_passthru.c 1970-01-01 00:00:00.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/video/h264_passthru.c 2013-03-11 18:47:52.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * h264 passthrough decoder + * Copyright (C) 2013 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "showtime.h" +#include "video_decoder.h" +#include "h264_annexb.h" + +/** + * + */ +static void +h264_pt_decode(struct media_codec *mc, struct video_decoder *vd, + struct media_queue *mq, struct media_buf *mb, int reqsize) +{ + h264_annexb_ctx_t *annexb = mc->opaque; + + + frame_info_t fi; + memset(&fi, 0, sizeof(fi)); + fi.fi_pts = mb->mb_pts; + fi.fi_epoch = mb->mb_epoch; + fi.fi_delta = mb->mb_delta; + fi.fi_drive_clock = mb->mb_drive_clock; + fi.fi_type = 'h264'; + + if(annexb->extradata != NULL && !annexb->extradata_injected) { + + fi.fi_data[0] = annexb->extradata; + fi.fi_pitch[0] = annexb->extradata_size; + video_deliver_frame(vd, &fi); + annexb->extradata_injected = 1; + } + + uint8_t *data = mb->mb_data; + size_t size = mb->mb_size; + h264_to_annexb(annexb, &data, &size); + + fi.fi_data[0] = data; + fi.fi_pitch[0] = size; + fi.fi_pitch[1] = mb->mb_skip == 1; + video_deliver_frame(vd, &fi); +} + + +/** + * + */ +static void +h264_pt_close(struct media_codec *mc) +{ + h264_to_annexb_cleanup(mc->opaque); + free(mc->opaque); +} + + +/** + * + */ +static int +h264_pt_codec_create(media_codec_t *mc, int id, + const media_codec_params_t *mcp, + media_pipe_t *mp) +{ + if(id != CODEC_ID_H264) + return 1; + + if(mc->codec_ctx == NULL) { + // this is lame + mc->codec_ctx = avcodec_alloc_context3(NULL); + mc->codec_ctx->codec_id = id; + mc->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + } + + mc->opaque = calloc(1, sizeof(h264_annexb_ctx_t)); + + if(mcp->extradata_size) + h264_to_annexb_init(mc->opaque, mcp->extradata, mcp->extradata_size); + + mc->decode = h264_pt_decode; + mc->close = h264_pt_close; + return 0; +} + +REGISTER_CODEC(NULL, h264_pt_codec_create, 100); diff -Nru showtime-4.3~git201303030928.de886c7/src/video/ps3_vdec.c showtime-4.3~git201303112047.200884e/src/video/ps3_vdec.c --- showtime-4.3~git201303030928.de886c7/src/video/ps3_vdec.c 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/src/video/ps3_vdec.c 2013-03-11 18:47:52.000000000 +0000 @@ -29,6 +29,7 @@ #include "video_settings.h" #include "arch/halloc.h" #include "notifications.h" +#include "h264_annexb.h" static int vdec_mpeg2_loaded; static int vdec_h264_loaded; @@ -95,10 +96,6 @@ int sequence_done; - size_t extradata_size; - uint8_t *extradata; - int extradata_injected; - struct vdec_pic_list pictures; @@ -118,10 +115,8 @@ pktmeta_t pktmeta[64]; int pktmeta_cur; - int lsize; - uint8_t *tmpbuf; - int tmpbufsize; + h264_annexb_ctx_t annexb; } vdec_decoder_t; @@ -536,57 +531,6 @@ /** - * - */ -static void -h264_to_annexb_inplace(uint8_t *b, size_t fsize) -{ - uint8_t *p = b; - while(p < b + fsize) { - if(p[0]) - break; // Avoid overflows with this simple check - int len = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; - p[0] = 0; - p[1] = 0; - p[2] = 0; - p[3] = 1; - p += len + 4; - } -} - - -/** - * - */ -static int -h264_to_annexb(uint8_t *dst, uint8_t *b, size_t fsize, int lsize) -{ - uint8_t *p = b; - int i; - int ol = 0; - while(p < b + fsize) { - - int len = 0; - for(i = 0; i < lsize; i++) - len = len << 8 | *p++; - - if(dst) { - dst[0] = 0; - dst[1] = 0; - dst[2] = 0; - dst[3] = 1; - memcpy(dst + 4, p, len); - dst += 4 + len; - } - ol += 4 + len; - p += len; - } - return ol; -} - - - -/** * Return 0 if ownership of 'data' has been transfered from caller */ static void @@ -641,7 +585,7 @@ if(vd->vd_do_flush) { end_sequence_and_wait(vdd); vdec_start_sequence(vdd->handle); - vdd->extradata_injected = 0; + vdd->annexb.extradata_injected = 0; vd->vd_nextpts = AV_NOPTS_VALUE; vdd->flush_to = -1; } @@ -683,33 +627,17 @@ au.dts.low = dts; au.dts.hi = dts >> 32; - if(vdd->extradata != NULL && vdd->extradata_injected == 0) { - submit_au(vdd, &au, vdd->extradata, vdd->extradata_size, 0, vd); - vdd->extradata_injected = 1; + if(vdd->annexb.extradata != NULL && vdd->annexb.extradata_injected == 0) { + submit_au(vdd, &au, vdd->annexb.extradata, + vdd->annexb.extradata_size, 0, vd); + vdd->annexb.extradata_injected = 1; } - int l; - - switch(vdd->lsize) { - case 4: - h264_to_annexb_inplace(mb->mb_data, mb->mb_size); - case 0: - submit_au(vdd, &au, mb->mb_data, mb->mb_size, mb->mb_skip == 1, vd); - break; - case 3: - case 2: - case 1: - l = h264_to_annexb(NULL, mb->mb_data, mb->mb_size, vdd->lsize); - if(l > vdd->tmpbufsize) { - vdd->tmpbuf = realloc(vdd->tmpbuf, l); - vdd->tmpbufsize = l; - } - if(vdd->tmpbuf == NULL) - return; - h264_to_annexb(vdd->tmpbuf, mb->mb_data, mb->mb_size, vdd->lsize); - submit_au(vdd, &au, vdd->tmpbuf, l, mb->mb_skip == 1, vd); - break; - } + uint8_t *data = mb->mb_data; + size_t size = mb->mb_size; + + h264_to_annexb(&vdd->annexb, &data, &size); + submit_au(vdd, &au, data, size, mb->mb_skip == 1, vd); vd->vd_do_flush = 0; } @@ -733,8 +661,7 @@ hts_mutex_destroy(&vdd->mtx); prop_ref_dec(vdd->metainfo); - free(vdd->extradata); - free(vdd->tmpbuf); + h264_to_annexb_cleanup(&vdd->annexb); free(vdd); TRACE(TRACE_DEBUG, "VDEC", "Cell decoder closed"); } @@ -743,69 +670,6 @@ /** * */ -static void -vdd_append_extradata(vdec_decoder_t *vdd, const uint8_t *data, int len) -{ - vdd->extradata = realloc(vdd->extradata, vdd->extradata_size + len); - memcpy(vdd->extradata + vdd->extradata_size, data, len); - vdd->extradata_size += len; -} - -/** - * - */ -static void -h264_load_extradata(vdec_decoder_t *vdd, const uint8_t *data, int len) -{ - int i, n, s; - - uint8_t buf[4] = {0,0,0,1}; - - if(len < 7 || data[0] != 1) - return; - - int lsize = (data[4] & 0x3) + 1; - if(lsize == 3) - return; - - n = data[5] & 0x1f; - data += 6; - len -= 6; - - for(i = 0; i < n && len >= 2; i++) { - s = ((data[0] << 8) | data[1]) + 2; - if(len < s) - break; - - vdd_append_extradata(vdd, buf, 4); - vdd_append_extradata(vdd, data + 2, s - 2); - data += s; - len -= s; - } - - if(len < 1) - return; - n = *data++; - len--; - - for(i = 0; i < n && len >= 2; i++) { - s = ((data[0] << 8) | data[1]) + 2; - if(len < s) - break; - - vdd_append_extradata(vdd, buf, 4); - vdd_append_extradata(vdd, data + 2, s - 2); - data += s; - len -= s; - } - - vdd->lsize = lsize; -} - - -/** - * - */ static int no_lib(media_pipe_t *mp, const char *codec) { @@ -924,7 +788,7 @@ vdd->level_minor = mcp->level % 10; if(id == CODEC_ID_H264 && mcp->extradata_size) - h264_load_extradata(vdd, mcp->extradata, mcp->extradata_size); + h264_to_annexb_init(&vdd->annexb, mcp->extradata, mcp->extradata_size); vdd->max_order = -1; diff -Nru showtime-4.3~git201303030928.de886c7/support/rpi.mk showtime-4.3~git201303112047.200884e/support/rpi.mk --- showtime-4.3~git201303030928.de886c7/support/rpi.mk 2013-03-03 07:28:38.000000000 +0000 +++ showtime-4.3~git201303112047.200884e/support/rpi.mk 2013-03-11 18:47:52.000000000 +0000 @@ -3,6 +3,10 @@ SRCS += src/arch/rpi/rpi_main.c \ src/arch/rpi/omx.c \ src/arch/rpi/rpi_audio.c \ + src/video/h264_passthru.c \ + src/video/h264_annexb.c \ + src/ui/glw/glw_video_rpi.c \ + src/ui/background.c \ SRCS += src/arch/linux/linux_misc.c \ src/arch/linux/linux_trap.c \