]> git.sesse.net Git - vlc/blobdiff - modules/hw/mmal/vout.c
vout: remove no longer used display size event parameter
[vlc] / modules / hw / mmal / vout.c
index a79ba33e9e998672c89cb2d21d2a142860388d2e..2b7ee671125ec1d8f58105ed6d92edac26d701ef 100644 (file)
 #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;