]> git.sesse.net Git - vlc/blobdiff - src/video_output/video_output.c
LGPL
[vlc] / src / video_output / video_output.c
index 2721caabb36709355c4569860abf103406082586..a8e4e24c98add3c71d1fcfd694889ced2fb2079f 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.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -75,7 +75,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 +120,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,9 +144,6 @@ 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);
 
@@ -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,
@@ -901,10 +904,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
      *
@@ -912,43 +969,41 @@ 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) {
+        todisplay = picture_pool_Get(vout->p->private_pool);
+        if (todisplay) {
+            VideoFormatCopyCropAr(&todisplay->format, &filtered->format);
+            picture_Copy(todisplay, filtered);
+            if (vout->p->spu_blend)
+                picture_BlendSubpicture(todisplay, vout->p->spu_blend, subpic);
         }
-        if (vout->p->is_decoder_pool_slow) {
-            direct = picture_pool_Get(vout->p->display_pool);
-            if (direct)
-                picture_Copy(direct, render);
-            picture_Release(render);
+        picture_Release(filtered);
+        subpicture_Delete(subpic);
+        subpic = NULL;
 
-        } else {
-            direct = render;
+        if (!todisplay)
+            return VLC_EGENERIC;
+    }
+
+    picture_t *direct;
+    if (!is_direct && todisplay) {
+        direct = picture_pool_Get(vout->p->display_pool);
+        if (direct) {
+            VideoFormatCopyCropAr(&direct->format, &todisplay->format);
+            picture_Copy(direct, todisplay);
         }
-        VideoFormatCopyCropAr(&direct->format, &filtered->format);
-        picture_Release(filtered);
-        filtered = NULL;
+        picture_Release(todisplay);
     } else {
-        direct = filtered;
+        direct = todisplay;
     }
-    if (subpic)
-        subpicture_Delete(subpic);
 
-    if (!direct)
+    if (!direct) {
+        if (subpic)
+            subpicture_Delete(subpic);
         return VLC_EGENERIC;
+    }
 
     /*
      * Take a snapshot if requested
@@ -960,11 +1015,18 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
     assert(vout_IsDisplayFiltered(vd) == !sys->display.use_dr);
     vout_UpdateDisplaySourceProperties(vd, &direct->format);
     if (sys->display.use_dr) {
-        vout_display_Prepare(vd, direct, NULL);
+        vout_display_Prepare(vd, direct, subpic);
     } else {
         sys->display.filtered = vout_FilterDisplay(vd, direct);
-        if (sys->display.filtered)
-            vout_display_Prepare(vd, sys->display.filtered, NULL);
+        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);
+        if (!sys->display.filtered)
+            return VLC_EGENERIC;
     }
 
     vout_chrono_Stop(&vout->p->render);
@@ -991,7 +1053,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
     vout_display_Display(vd,
                          sys->display.filtered ? sys->display.filtered
                                                 : direct,
-                         NULL);
+                         subpic);
     sys->display.filtered = NULL;
 
     vout_statistic_Update(&vout->p->statistic, 1, 0);
@@ -1112,10 +1174,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);
@@ -1304,10 +1372,8 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
     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;
@@ -1457,6 +1523,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;