X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fhw%2Fmmal%2Fvout.c;h=2b7ee671125ec1d8f58105ed6d92edac26d701ef;hb=fad21f3c668db1df9d85e950d17a7d23c99a1c0b;hp=a79ba33e9e998672c89cb2d21d2a142860388d2e;hpb=9ccd69b27f431d6f0600e09dab1f78b0aad26e1e;p=vlc diff --git a/modules/hw/mmal/vout.c b/modules/hw/mmal/vout.c index a79ba33e9e..2b7ee67112 100644 --- a/modules/hw/mmal/vout.c +++ b/modules/hw/mmal/vout.c @@ -53,6 +53,11 @@ #define MMAL_ADJUST_REFRESHRATE_TEXT N_("Adjust HDMI refresh rate to the video.") #define MMAL_ADJUST_REFRESHRATE_LONGTEXT N_("Adjust HDMI refresh rate to the video.") +#define MMAL_NATIVE_INTERLACED "mmal-native-interlaced" +#define MMAL_NATIVE_INTERLACE_TEXT N_("Force interlaced video mode.") +#define MMAL_NATIVE_INTERLACE_LONGTEXT N_("Force the HDMI output into an " \ + "interlaced video mode for interlaced video content.") + /* Ideal rendering phase target is at rough 25% of frame duration */ #define PHASE_OFFSET_TARGET ((double)0.25) #define PHASE_CHECK_INTERVAL 100 @@ -68,6 +73,8 @@ vlc_module_begin() add_integer(MMAL_LAYER_NAME, 1, MMAL_LAYER_TEXT, MMAL_LAYER_LONGTEXT, false) add_bool(MMAL_ADJUST_REFRESHRATE_NAME, false, MMAL_ADJUST_REFRESHRATE_TEXT, MMAL_ADJUST_REFRESHRATE_LONGTEXT, false) + add_bool(MMAL_NATIVE_INTERLACED, false, MMAL_NATIVE_INTERLACE_TEXT, + MMAL_NATIVE_INTERLACE_LONGTEXT, false) set_callbacks(Open, Close) vlc_module_end() @@ -85,6 +92,11 @@ struct dmx_region_t { }; struct vout_display_sys_t { + vlc_cond_t buffer_cond; + vlc_mutex_t buffer_mutex; + vlc_mutex_t manage_mutex; + + plane_t planes[3]; picture_t **pictures; picture_pool_t *picture_pool; @@ -92,12 +104,8 @@ struct vout_display_sys_t { MMAL_PORT_T *input; MMAL_POOL_T *pool; struct dmx_region_t *dmx_region; - plane_t planes[3]; int i_planes; - vlc_mutex_t buffer_mutex; - vlc_mutex_t manage_mutex; - vlc_cond_t buffer_cond; uint32_t buffer_size; int buffers_in_transit; unsigned num_buffers; @@ -107,13 +115,19 @@ struct vout_display_sys_t { DISPMANX_RESOURCE_HANDLE_T bkg_resource; unsigned display_width; unsigned display_height; - bool need_configure_display; - bool adjust_refresh_rate; + int i_frame_rate_base; + int i_frame_rate; + int next_phase_check; int phase_offset; - int layer; + + bool need_configure_display; + bool adjust_refresh_rate; + bool native_interlaced; + bool b_top_field_first; + bool b_progressive; bool opaque; }; @@ -182,9 +196,6 @@ static int Open(vlc_object_t *object) vd->info.has_hide_mouse = true; sys->opaque = vd->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE; - vd->fmt.i_sar_num = vd->source.i_sar_num; - vd->fmt.i_sar_den = vd->source.i_sar_den; - status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to create MMAL component %s (status=%"PRIx32" %s)", @@ -290,8 +301,7 @@ static int Open(vlc_object_t *object) vc_tv_register_callback(tvservice_cb, vd); if (query_resolution(vd, &sys->display_width, &sys->display_height) >= 0) { - vout_display_SendEventDisplaySize(vd, sys->display_width, sys->display_height, - vd->cfg->is_fullscreen); + vout_display_SendEventDisplaySize(vd, sys->display_width, sys->display_height); } else { sys->display_width = vd->cfg->display.width; sys->display_height = vd->cfg->display.height; @@ -311,6 +321,7 @@ static void Close(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys = vd->sys; + char response[20]; /* answer is hvs_update_fields=%1d */ unsigned i; vc_tv_unregister_callback_full(tvservice_cb, vd); @@ -344,6 +355,12 @@ static void Close(vlc_object_t *object) vlc_cond_destroy(&sys->buffer_cond); vlc_mutex_destroy(&sys->manage_mutex); + if (sys->native_interlaced) { + if (vc_gencmd(response, sizeof(response), "hvs_update_fields 0") < 0 || + response[18] != '0') + msg_Warn(vd, "Could not reset hvs field mode"); + } + free(sys->pictures); free(sys); @@ -380,7 +397,7 @@ static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg, return -EINVAL; } } else { - fmt = &vd->fmt; + fmt = &vd->source; } if (!cfg) @@ -411,14 +428,12 @@ static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg, show_background(vd, cfg->is_fullscreen); sys->adjust_refresh_rate = var_InheritBool(vd, MMAL_ADJUST_REFRESHRATE_NAME); + sys->native_interlaced = var_InheritBool(vd, MMAL_NATIVE_INTERLACED); if (sys->adjust_refresh_rate) { adjust_refresh_rate(vd, fmt); set_latency_target(vd, true); } - if (fmt != &vd->fmt) - memcpy(&vd->fmt, fmt, sizeof(video_format_t)); - return 0; } @@ -530,6 +545,17 @@ static void vd_display(vout_display_t *vd, picture_t *picture, MMAL_BUFFER_HEADER_T *buffer = pic_sys->buffer; MMAL_STATUS_T status; + if (picture->format.i_frame_rate != sys->i_frame_rate || + picture->format.i_frame_rate_base != sys->i_frame_rate_base || + picture->b_progressive != sys->b_progressive || + picture->b_top_field_first != sys->b_top_field_first) { + sys->b_top_field_first = picture->b_top_field_first; + sys->b_progressive = picture->b_progressive; + sys->i_frame_rate = picture->format.i_frame_rate; + sys->i_frame_rate_base = picture->format.i_frame_rate_base; + configure_display(vd, NULL, &picture->format); + } + if (!pic_sys->displayed || !sys->opaque) { buffer->cmd = 0; buffer->length = sys->input->buffer_size; @@ -568,7 +594,6 @@ static int vd_control(vout_display_t *vd, int query, va_list args) vout_display_sys_t *sys = vd->sys; vout_display_cfg_t cfg; const vout_display_cfg_t *tmp_cfg; - video_format_t fmt; const video_format_t *tmp_fmt; int ret = VLC_EGENERIC; @@ -581,7 +606,7 @@ static int vd_control(vout_display_t *vd, int query, va_list args) case VOUT_DISPLAY_CHANGE_FULLSCREEN: tmp_cfg = va_arg(args, const vout_display_cfg_t *); vout_display_SendEventDisplaySize(vd, sys->display_width, - sys->display_height, tmp_cfg->is_fullscreen); + sys->display_height); ret = VLC_SUCCESS; break; @@ -597,31 +622,10 @@ static int vd_control(vout_display_t *vd, int query, va_list args) } break; - case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: - cfg = *vd->cfg; - tmp_cfg = va_arg(args, const vout_display_cfg_t *); - cfg.is_display_filled = tmp_cfg->is_display_filled; - if (configure_display(vd, &cfg, NULL) >= 0) - ret = VLC_SUCCESS; - break; - case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: - fmt = vd->fmt; - tmp_fmt = va_arg(args, const video_format_t *); - fmt.i_sar_num = tmp_fmt->i_sar_num; - fmt.i_sar_den = tmp_fmt->i_sar_den; - if (configure_display(vd, NULL, &fmt) >= 0) - ret = VLC_SUCCESS; - break; - case VOUT_DISPLAY_CHANGE_SOURCE_CROP: - fmt = vd->fmt; tmp_fmt = va_arg(args, const video_format_t *); - fmt.i_x_offset = tmp_fmt->i_x_offset; - fmt.i_y_offset = tmp_fmt->i_y_offset; - fmt.i_visible_width = tmp_fmt->i_visible_width; - fmt.i_visible_height = tmp_fmt->i_visible_height; - if (configure_display(vd, NULL, &fmt) >= 0) + if (configure_display(vd, NULL, tmp_fmt) >= 0) ret = VLC_SUCCESS; break; @@ -653,7 +657,7 @@ static void vd_manage(vout_display_t *vd) if (query_resolution(vd, &width, &height) >= 0) { sys->display_width = width; sys->display_height = height; - vout_display_SendEventDisplaySize(vd, width, height, vd->cfg->is_fullscreen); + vout_display_SendEventDisplaySize(vd, width, height); } sys->need_configure_display = false; @@ -756,8 +760,10 @@ static int set_latency_target(vout_display_t *vd, bool enable) static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt) { + vout_display_sys_t *sys = vd->sys; TV_DISPLAY_STATE_T display_state; TV_SUPPORTED_MODE_NEW_T supported_modes[VC_TV_MAX_MODE_IDS]; + char response[20]; /* answer is hvs_update_fields=%1d */ int num_modes; double frame_rate = (double)fmt->i_frame_rate / fmt->i_frame_rate_base; int best_id = -1; @@ -769,11 +775,20 @@ static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt) num_modes = vc_tv_hdmi_get_supported_modes_new(display_state.display.hdmi.group, supported_modes, VC_TV_MAX_MODE_IDS, NULL, NULL); - for(i = 0; i < num_modes; ++i) { - if(supported_modes[i].width != display_state.display.hdmi.width || - supported_modes[i].height != display_state.display.hdmi.height || - supported_modes[i].scan_mode != display_state.display.hdmi.scan_mode) - continue; + for (i = 0; i < num_modes; ++i) { + TV_SUPPORTED_MODE_NEW_T *mode = &supported_modes[i]; + if (!sys->native_interlaced) { + if (mode->width != display_state.display.hdmi.width || + mode->height != display_state.display.hdmi.height || + mode->scan_mode == HDMI_INTERLACED) + continue; + } else { + if (mode->width != vd->fmt.i_visible_width || + mode->height != vd->fmt.i_visible_height) + continue; + if (mode->scan_mode != sys->b_progressive ? HDMI_NONINTERLACED : HDMI_INTERLACED) + continue; + } score = fmod(supported_modes[i].frame_rate, frame_rate); if((best_id < 0) || (score < best_score)) { @@ -782,13 +797,24 @@ static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt) } } - if((best_id >= 0) && (display_state.display.hdmi.frame_rate != supported_modes[best_id].frame_rate)) { + if((best_id >= 0) && (display_state.display.hdmi.mode != supported_modes[best_id].code)) { msg_Info(vd, "Setting HDMI refresh rate to %"PRIu32, supported_modes[best_id].frame_rate); vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, supported_modes[best_id].group, supported_modes[best_id].code); } + + if (sys->native_interlaced && + supported_modes[best_id].scan_mode == HDMI_INTERLACED) { + char hvs_mode = sys->b_top_field_first ? '1' : '2'; + if (vc_gencmd(response, sizeof(response), "hvs_update_fields %c", + hvs_mode) != 0 || response[18] != hvs_mode) + msg_Warn(vd, "Could not set hvs field mode"); + else + msg_Info(vd, "Configured hvs field mode for interlaced %s playback", + sys->b_top_field_first ? "tff" : "bff"); + } } } @@ -934,8 +960,8 @@ static void maintain_phase_sync(vout_display_t *vd) .hdr = { MMAL_PARAMETER_VIDEO_RENDER_STATS, sizeof(render_stats) }, }; int32_t frame_duration = 1000000 / - ((double)vd->fmt.i_frame_rate / - vd->fmt.i_frame_rate_base); + ((double)vd->source.i_frame_rate / + vd->source.i_frame_rate_base); vout_display_sys_t *sys = vd->sys; int32_t phase_offset; MMAL_STATUS_T status;