]> git.sesse.net Git - vlc/blobdiff - src/video_output/video_output.c
ThreadDisplayPicture: simplify prototype
[vlc] / src / video_output / video_output.c
index fe4d95681cad47441449f6c4e037ba3281c717ba..3876ccd0afd852de79e614de3098951f305ba4ef 100644 (file)
@@ -5,26 +5,26 @@
  * It includes functions allowing to open a new thread, send pictures to a
  * thread, and destroy a previously oppened video output thread.
  *****************************************************************************
- * Copyright (C) 2000-2007 the VideoLAN team
+ * Copyright (C) 2000-2007 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Gildas Bazin <gbazin@videolan.org>
  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *
- * 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 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -49,7 +49,6 @@
 #include <libvlc.h>
 #include "vout_internal.h"
 #include "interlacing.h"
-#include "postprocessing.h"
 #include "display.h"
 
 /*****************************************************************************
@@ -75,7 +74,8 @@ static void VoutDestructor(vlc_object_t *);
 static int VoutValidateFormat(video_format_t *dst,
                               const video_format_t *src)
 {
-    if (src->i_width <= 0 || src->i_height <= 0)
+    if (src->i_width <= 0  || src->i_width  > 8192 ||
+        src->i_height <= 0 || src->i_height > 8192)
         return VLC_EGENERIC;
     if (src->i_sar_num <= 0 || src->i_sar_den <= 0)
         return VLC_EGENERIC;
@@ -119,7 +119,7 @@ static vout_thread_t *VoutCreate(vlc_object_t *object,
     /* Allocate descriptor */
     vout_thread_t *vout = vlc_custom_create(object,
                                             sizeof(*vout) + sizeof(*vout->p),
-                                            VLC_OBJECT_VOUT, "video output");
+                                            "video output");
     if (!vout) {
         video_format_Clean(&original);
         return NULL;
@@ -143,18 +143,15 @@ static vout_thread_t *VoutCreate(vlc_object_t *object,
     vlc_mutex_init(&vout->p->filter.lock);
     vlc_mutex_init(&vout->p->spu_lock);
 
-    /* Attach the new object now so we can use var inheritance below */
-    vlc_object_attach(vout, object);
-
     /* Initialize subpicture unit */
     vout->p->spu = spu_Create(vout);
 
     /* Take care of some "interface/control" related initialisations */
     vout_IntfInit(vout);
 
-    vout->p->title.show     = var_GetBool(vout, "video-title-show");
-    vout->p->title.timeout  = var_GetInteger(vout, "video-title-timeout");
-    vout->p->title.position = var_GetInteger(vout, "video-title-position");
+    vout->p->title.show     = var_InheritBool(vout, "video-title-show");
+    vout->p->title.timeout  = var_InheritInteger(vout, "video-title-timeout");
+    vout->p->title.position = var_InheritInteger(vout, "video-title-position");
 
     /* Get splitter name if present */
     char *splitter_name = var_InheritString(vout, "video-splitter");
@@ -224,6 +221,7 @@ vout_thread_t *(vout_Request)(vlc_object_t *object,
 
         if (!vout->p->dead) {
             msg_Dbg(object, "reusing provided vout");
+            vout_IntfReinit(vout);
             return vout;
         }
         vout_CloseAndRelease(vout);
@@ -472,8 +470,8 @@ int vout_GetSnapshot(vout_thread_t *vout,
         if (type && image_Type2Fourcc(type))
             codec = image_Type2Fourcc(type);
 
-        const int override_width  = var_GetInteger(vout, "snapshot-width");
-        const int override_height = var_GetInteger(vout, "snapshot-height");
+        const int override_width  = var_InheritInteger(vout, "snapshot-width");
+        const int override_height = var_InheritInteger(vout, "snapshot-height");
 
         if (picture_Export(VLC_OBJECT(vout), image_dst, fmt,
                            picture, codec, override_width, override_height)) {
@@ -551,6 +549,11 @@ void vout_ControlChangeFilters(vout_thread_t *vout, const char *filters)
     vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_FILTERS,
                             filters);
 }
+void vout_ControlChangeSubSources(vout_thread_t *vout, const char *filters)
+{
+    vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_SOURCES,
+                            filters);
+}
 void vout_ControlChangeSubFilters(vout_thread_t *vout, const char *filters)
 {
     vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_FILTERS,
@@ -852,14 +855,13 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_
         vout->p->displayed.decoded       = picture_Hold(decoded);
         vout->p->displayed.timestamp     = decoded->date;
         vout->p->displayed.is_interlaced = !decoded->b_progressive;
-        vout->p->displayed.qtype         = decoded->i_qtype;
 
         picture = filter_chain_VideoFilter(vout->p->filter.chain_static, decoded);
     }
 
     vlc_mutex_unlock(&vout->p->filter.lock);
 
-    vout_statistic_Update(&vout->p->statistic, 0, lost_count);
+    vout_statistic_AddLost(&vout->p->statistic, lost_count);
     if (!picture)
         return VLC_EGENERIC;
 
@@ -873,6 +875,7 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_
 
 static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
 {
+    vout_thread_sys_t *sys = vout->p;
     vout_display_t *vd = vout->p->display.vd;
 
     picture_t *torender = picture_Hold(vout->p->displayed.current);
@@ -900,10 +903,64 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
         render_subtitle_date = filtered->date > 1 ? filtered->date : mdate();
     mtime_t render_osd_date = mdate(); /* FIXME wrong */
 
-    subpicture_t *subpic = spu_Render(vout->p->spu, NULL, &vd->source, &vd->source,
+    /*
+     * Get the subpicture to be displayed
+     */
+    const bool do_dr_spu = !do_snapshot &&
+                           vd->info.subpicture_chromas &&
+                           *vd->info.subpicture_chromas != 0;
+    const bool do_early_spu = !do_dr_spu &&
+                              (vd->info.is_slow ||
+                               sys->display.use_dr ||
+                               do_snapshot ||
+                               !vout_IsDisplayFiltered(vd) ||
+                               vd->fmt.i_width * vd->fmt.i_height <= vd->source.i_width * vd->source.i_height);
+
+    const vlc_fourcc_t *subpicture_chromas;
+    video_format_t fmt_spu;
+    if (do_dr_spu) {
+        vout_display_place_t place;
+        vout_display_PlacePicture(&place, &vd->source, vd->cfg, false);
+
+        fmt_spu = vd->source;
+        if (fmt_spu.i_width * fmt_spu.i_height < place.width * place.height) {
+            fmt_spu.i_sar_num = vd->cfg->display.sar.num;
+            fmt_spu.i_sar_den = vd->cfg->display.sar.den;
+            fmt_spu.i_width          =
+            fmt_spu.i_visible_width  = place.width;
+            fmt_spu.i_height         =
+            fmt_spu.i_visible_height = place.height;
+        }
+        subpicture_chromas = vd->info.subpicture_chromas;
+    } else {
+        if (do_early_spu) {
+            fmt_spu = vd->source;
+        } else {
+            fmt_spu = vd->fmt;
+            fmt_spu.i_sar_num = vd->cfg->display.sar.num;
+            fmt_spu.i_sar_den = vd->cfg->display.sar.den;
+        }
+        subpicture_chromas = NULL;
+
+        if (vout->p->spu_blend &&
+            vout->p->spu_blend->fmt_out.video.i_chroma != fmt_spu.i_chroma) {
+            filter_DeleteBlend(vout->p->spu_blend);
+            vout->p->spu_blend = NULL;
+            vout->p->spu_blend_chroma = 0;
+        }
+        if (!vout->p->spu_blend && vout->p->spu_blend_chroma != fmt_spu.i_chroma) {
+            vout->p->spu_blend_chroma = fmt_spu.i_chroma;
+            vout->p->spu_blend = filter_NewBlend(VLC_OBJECT(vout), &fmt_spu);
+            if (!vout->p->spu_blend)
+                msg_Err(vout, "Failed to create blending filter, OSD/Subtitles will not work");
+        }
+    }
+
+    subpicture_t *subpic = spu_Render(vout->p->spu,
+                                      subpicture_chromas, &fmt_spu,
+                                      &vd->source,
                                       render_subtitle_date, render_osd_date,
                                       do_snapshot);
-
     /*
      * Perform rendering
      *
@@ -911,52 +968,69 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
      * - be sure to end up with a direct buffer.
      * - blend subtitles, and in a fast access buffer
      */
-    picture_t *direct = NULL;
-    if (filtered &&
-        (vout->p->decoder_pool != vout->p->display_pool || subpic)) {
-        picture_t *render;
-        if (vout->p->is_decoder_pool_slow)
-            render = picture_NewFromFormat(&vd->source);
-        else if (vout->p->decoder_pool != vout->p->display_pool)
-            render = picture_pool_Get(vout->p->display_pool);
-        else
-            render = picture_pool_Get(vout->p->private_pool);
-
-        if (render) {
-            picture_Copy(render, filtered);
-
-            if (vout->p->spu_blend && subpic)
-                picture_BlendSubpicture(render, vout->p->spu_blend, subpic);
+    bool is_direct = vout->p->decoder_pool == vout->p->display_pool;
+    picture_t *todisplay = filtered;
+    if (do_early_spu && subpic) {
+        picture_t *blent = picture_pool_Get(vout->p->private_pool);
+        if (blent) {
+            VideoFormatCopyCropAr(&blent->format, &filtered->format);
+            picture_Copy(blent, filtered);
+            if (vout->p->spu_blend
+             && picture_BlendSubpicture(blent, vout->p->spu_blend, subpic)) {
+                picture_Release(todisplay);
+                todisplay = blent;
+            } else
+                picture_Release(blent);
         }
-        if (vout->p->is_decoder_pool_slow) {
-            direct = picture_pool_Get(vout->p->display_pool);
-            if (direct)
-                picture_Copy(direct, render);
-            picture_Release(render);
+        subpicture_Delete(subpic);
+        subpic = NULL;
+    }
 
-        } else {
-            direct = render;
+    assert(vout_IsDisplayFiltered(vd) == !sys->display.use_dr);
+    if (sys->display.use_dr && !is_direct) {
+        picture_t *direct = picture_pool_Get(vout->p->display_pool);
+        if (!direct) {
+            picture_Release(todisplay);
+            if (subpic)
+                subpicture_Delete(subpic);
+            return VLC_EGENERIC;
         }
-        VideoFormatCopyCropAr(&direct->format, &filtered->format);
-        picture_Release(filtered);
-        filtered = NULL;
-    } else {
-        direct = filtered;
-    }
-    if (subpic)
-        subpicture_Delete(subpic);
 
-    if (!direct)
-        return VLC_EGENERIC;
+        /* The display uses direct rendering (no conversion), but its pool of
+         * pictures is not usable by the decoder (too few, too slow or
+         * subject to invalidation...). Since there are no filters, copying
+         * pictures from the decoder to the output is unavoidable. */
+        VideoFormatCopyCropAr(&direct->format, &todisplay->format);
+        picture_Copy(direct, todisplay);
+        picture_Release(todisplay);
+        todisplay = direct;
+    }
 
     /*
      * Take a snapshot if requested
      */
     if (do_snapshot)
-        vout_snapshot_Set(&vout->p->snapshot, &vd->source, direct);
+        vout_snapshot_Set(&vout->p->snapshot, &vd->source, todisplay);
 
-    /* Render the direct buffer returned by vout_RenderPicture */
-    vout_RenderWrapper(vout, direct);
+    /* Render the direct buffer */
+    vout_UpdateDisplaySourceProperties(vd, &todisplay->format);
+    if (sys->display.use_dr) {
+        vout_display_Prepare(vd, todisplay, subpic);
+    } else {
+        sys->display.filtered = vout_FilterDisplay(vd, todisplay);
+        if (sys->display.filtered) {
+            if (!do_dr_spu && !do_early_spu && vout->p->spu_blend && subpic)
+                picture_BlendSubpicture(sys->display.filtered, vout->p->spu_blend, subpic);
+            vout_display_Prepare(vd, sys->display.filtered, do_dr_spu ? subpic : NULL);
+        }
+        if (!do_dr_spu && subpic)
+        {
+            subpicture_Delete(subpic);
+            subpic = NULL;
+        }
+        if (!sys->display.filtered)
+            return VLC_EGENERIC;
+    }
 
     vout_chrono_Stop(&vout->p->render);
 #if 0
@@ -975,21 +1049,24 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
         msg_Warn(vout, "picture is late (%lld ms)", delay / 1000);
 #endif
     if (!is_forced)
-        mwait(direct->date);
+        mwait(todisplay->date);
 
     /* Display the direct buffer returned by vout_RenderPicture */
     vout->p->displayed.date = mdate();
+    vout_display_Display(vd,
+                         sys->display.filtered ? sys->display.filtered
+                                                : todisplay,
+                         subpic);
+    sys->display.filtered = NULL;
 
-    vout_DisplayWrapper(vout, direct);
-
-    vout_statistic_Update(&vout->p->statistic, 1, 0);
+    vout_statistic_AddDisplayed(&vout->p->statistic, 1);
 
     return VLC_SUCCESS;
 }
 
-static int ThreadDisplayPicture(vout_thread_t *vout,
-                                bool now, mtime_t *deadline)
+static int ThreadDisplayPicture(vout_thread_t *vout, mtime_t *deadline)
 {
+    bool now = !deadline;
     bool is_late_dropped = vout->p->is_late_dropped && !vout->p->pause.is_on && !now;
     bool first = !vout->p->displayed.current;
     if (first && ThreadDisplayPreparePicture(vout, true, is_late_dropped)) /* FIXME not sure it is ok */
@@ -1031,12 +1108,14 @@ static int ThreadDisplayPicture(vout_thread_t *vout,
         refresh = date_refresh <= date;
 
     if (!first && !refresh && !drop) {
-        if (date_next != VLC_TS_INVALID && date_refresh != VLC_TS_INVALID)
-            *deadline = __MIN(date_next, date_refresh);
-        else if (date_next != VLC_TS_INVALID)
-            *deadline = date_next;
-        else if (date_refresh != VLC_TS_INVALID)
-            *deadline = date_refresh;
+        if (!now) {
+            if (date_next != VLC_TS_INVALID && date_refresh != VLC_TS_INVALID)
+                *deadline = __MIN(date_next, date_refresh);
+            else if (date_next != VLC_TS_INVALID)
+                *deadline = date_next;
+            else if (date_refresh != VLC_TS_INVALID)
+                *deadline = date_refresh;
+        }
         return VLC_EGENERIC;
     }
 
@@ -1054,25 +1133,19 @@ static int ThreadDisplayPicture(vout_thread_t *vout,
 
 static void ThreadManage(vout_thread_t *vout,
                          mtime_t *deadline,
-                         vout_interlacing_support_t *interlacing,
-                         vout_postprocessing_support_t *postprocessing)
+                         vout_interlacing_support_t *interlacing)
 {
     vlc_mutex_lock(&vout->p->picture_lock);
 
     *deadline = VLC_TS_INVALID;
-    for (;;) {
-        if (ThreadDisplayPicture(vout, false, deadline))
+    for (;;)
+        if (ThreadDisplayPicture(vout, deadline))
             break;
-    }
 
-    const int  picture_qtype      = vout->p->displayed.qtype;
     const bool picture_interlaced = vout->p->displayed.is_interlaced;
 
     vlc_mutex_unlock(&vout->p->picture_lock);
 
-    /* Post processing */
-    vout_SetPostProcessingState(vout, postprocessing, picture_qtype);
-
     /* Deinterlacing */
     vout_SetInterlacingState(vout, interlacing, picture_interlaced);
 
@@ -1100,10 +1173,16 @@ static void ThreadDisplayOsdTitle(vout_thread_t *vout, const char *string)
                  string);
 }
 
+static void ThreadChangeSubSources(vout_thread_t *vout, const char *filters)
+{
+    spu_ChangeSources(vout->p->spu, filters);
+}
+
 static void ThreadChangeSubFilters(vout_thread_t *vout, const char *filters)
 {
     spu_ChangeFilters(vout->p->spu, filters);
 }
+
 static void ThreadChangeSubMargin(vout_thread_t *vout, int margin)
 {
     spu_ChangeMargin(vout->p->spu, margin);
@@ -1172,8 +1251,7 @@ static void ThreadStep(vout_thread_t *vout, mtime_t *duration)
     if (vout->p->step.last <= VLC_TS_INVALID)
         vout->p->step.last = vout->p->displayed.timestamp;
 
-    mtime_t dummy;
-    if (ThreadDisplayPicture(vout, true, &dummy))
+    if (ThreadDisplayPicture(vout, NULL))
         return;
 
     vout->p->step.timestamp = vout->p->displayed.timestamp;
@@ -1188,8 +1266,6 @@ static void ThreadStep(vout_thread_t *vout, mtime_t *duration)
 
 static void ThreadChangeFullscreen(vout_thread_t *vout, bool fullscreen)
 {
-    /* FIXME not sure setting "fullscreen" is good ... */
-    var_SetBool(vout, "fullscreen", fullscreen);
     vout_SetDisplayFullscreen(vout->p->display.vd, fullscreen);
 }
 
@@ -1286,16 +1362,13 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
     vout->p->displayed.decoded       = NULL;
     vout->p->displayed.date          = VLC_TS_INVALID;
     vout->p->displayed.timestamp     = VLC_TS_INVALID;
-    vout->p->displayed.qtype         = QTYPE_NONE;
     vout->p->displayed.is_interlaced = false;
 
     vout->p->step.last               = VLC_TS_INVALID;
     vout->p->step.timestamp          = VLC_TS_INVALID;
 
-
-    vout->p->spu_blend = filter_NewBlend(VLC_OBJECT(vout), &vout->p->original);
-    if (!vout->p->spu_blend)
-        msg_Err(vout, "Failed to create blending filter, OSD/Subtitles will not work");
+    vout->p->spu_blend_chroma        = 0;
+    vout->p->spu_blend               = NULL;
 
     video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original);
     return VLC_SUCCESS;
@@ -1404,9 +1477,6 @@ static void *Thread(void *object)
         .is_interlaced = false,
         .date = mdate(),
     };
-    vout_postprocessing_support_t postprocessing = {
-        .qtype = QTYPE_NONE,
-    };
 
     mtime_t deadline = VLC_TS_INVALID;
     for (;;) {
@@ -1445,6 +1515,9 @@ static void *Thread(void *object)
             case VOUT_CONTROL_CHANGE_FILTERS:
                 ThreadChangeFilters(vout, NULL, cmd.u.string, false);
                 break;
+            case VOUT_CONTROL_CHANGE_SUB_SOURCES:
+                ThreadChangeSubSources(vout, cmd.u.string);
+                break;
             case VOUT_CONTROL_CHANGE_SUB_FILTERS:
                 ThreadChangeSubFilters(vout, cmd.u.string);
                 break;
@@ -1497,7 +1570,7 @@ static void *Thread(void *object)
             vout_control_cmd_Clean(&cmd);
         }
 
-        ThreadManage(vout, &deadline, &interlacing, &postprocessing);
+        ThreadManage(vout, &deadline, &interlacing);
     }
 }