[vdr] [ANNOUNCE] vdr-xine-0.7.1 plugin

mike lewis lachlanlewis at gmail.com
Tue Mar 8 07:11:12 CET 2005


> I have tried to implement this, at least with a callback to spit a
> message to stdout when a particular type of event is seen.  However,
> fbxine just dies during execution.  Is there any way to debug the
> code?  Without expand on, fbxine launches.  With it on, I just get
> this:
> ---
> /usr/local/bin/fbxine -d --stdctl -V vidixfb -A alsa --no-lirc
> --post=expand:centre_cut_out=1 -D
> vdr://tmp/vdr-xine/stream#demux:mpeg_pes
> mga_crtc2_vid: Found MGA G400/G450
> mga_crtc2_vid: detected RAMSIZE is 16 MB
> mga_crtc2_vid: Set write-combining type of video memory
> mga_crtc2_vid: IRQ support disabled
> ---
> With the old expand plugin, i the above plus normal operation (video out ;-):
> ---
> ...
> 1
> time: 0
> libmpeg2: stream not demultiplexed ?
> libmpeg2: stream not demultiplexed ?
> mga_crtc2_vid: Saved colorkey (ON: 0  B9:72:32)
> libmpeg2: stream not demultiplexed ?
> ...
> ---
>
So from the above, its quite easy to see that the changes I made to
expand are causing it to crash..  But how? I have not touched the
functions of the code yet, just added an event handler..

Can someone please have a look at the code bellow or offer some tips
on how I can debug  when there seems to be no debug output for fbxine
output?  Please..

Mick 
> Here is the new expand plugin...
> freevo src # cat post/planar/expand.c
> /*
>  * Copyright (C) 2003 the xine project
>  *
>  * This file is part of xine, a free video player.
>  *
>  * xine 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
>  * (at your option) any later version.
>  *
>  * xine 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, write to the Free Software
>  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
>  *
>  * $Id:
>  *
>  * expand video filter by James Stembridge 24/05/2003
>  *            improved by Michael Roitzsch
>  *            centre_crop_out_mode by Reinhard Nissl
>  *
>  * based on invert.c
>  *
>  */
> 
> #include "xine_internal.h"
> #include "post.h"
> 
> /* The expand trick explained:
>  *
>  * The expand plugin is meant to take frames of arbitrary aspect ratio and
>  * converts them to 4:3 aspect by adding black bars on the top and bottom
>  * of the frame. This allows us to shift overlays down into the black area
>  * so they don't cover the image.
>  *
>  * How do we do that? The naive approach would be to intercept the frame's
>  * draw() function and simply copy the frame's content into a larger one.
>  * This is quite CPU intensive because of the huge memcpy()s involved.
>  *
>  * Therefore the better idea is to trick the decoder into rendering the
>  * image into a frame with pre-attached black borders. This is the way:
>  *  - when the decoder asks for a new frame, we allocate an enlarged
>  *    frame from the original port and prepare it with black borders
>  *  - we modify this frame's base pointers so that the decoder will only see
>  *    the area between the black bars
>  *  - this frame is given to the decoder, which paints its image inside
>  *  - when the decoder draws the frame, the post plugin architecture
>  *    will automatically restore the old pointers
>  * This way, the decoder (or any other post plugin up the tree) will only
>  * see the frame area between the black bars and by that modify the
>  * enlarged version directly. No need for later copying.
>  *
>  * When centre_crop_out_mode is enabled, the plugin will detect the black
>  * bars to the left and right of the image and will then set up cropping
>  * to efficiently remove the black border around the 4:3 image, which the
>  * plugin would produce otherwise for this case.
>  */
> 
> /* plugin class initialization function */
> void *expand_init_plugin(xine_t *xine, void *);
> 
> /* plugin structures */
> typedef struct expand_parameters_s {
>   int enable_automatic_shift;
>   int overlay_y_offset;
>   int centre_cut_out_mode;
> } expand_parameters_t;
> 
> START_PARAM_DESCR(expand_parameters_t)
> PARAM_ITEM(POST_PARAM_TYPE_BOOL, enable_automatic_shift, NULL, 0, 1, 0,
>   "enable automatic overlay shifting")
> PARAM_ITEM(POST_PARAM_TYPE_INT, overlay_y_offset, NULL, -500, 500, 0,
>   "manually shift the overlay vertically")
> PARAM_ITEM(POST_PARAM_TYPE_BOOL, centre_cut_out_mode, NULL, 0, 1, 0,
>   "cut out centered 4:3 image contained in 16:9 frame")
> END_PARAM_DESCR(expand_param_descr)
> 
> typedef struct post_expand_s {
> 
>   xine_stream_t      *stream;
> 
>   post_plugin_t            post;
> 
>   xine_post_in_t           parameter_input;
> 
>   int                      enable_automatic_shift;
>   int                      overlay_y_offset;
>   int                      top_bar_height;
>   int                      centre_cut_out_mode;
>   int                      cropping_active;
> 
>   xine_event_queue_t *event_queue;
>   xine_event_queue_t *event_queue_external;
> 
> } post_expand_t;
> 
> /* plugin class functions */
> static post_plugin_t *expand_open_plugin(post_class_t *class_gen, int inputs,
>                                          xine_audio_port_t **audio_target,
>                                          xine_video_port_t **video_target,
>                                          xine_stream_t *stream);
> 
> static char          *expand_get_identifier(post_class_t *class_gen);
> static char          *expand_get_description(post_class_t *class_gen);
> static void           expand_class_dispose(post_class_t *class_gen);
> 
> /* plugin instance functions */
> static void           expand_dispose(post_plugin_t *this_gen);
> 
> /* parameter functions */
> static xine_post_api_descr_t *expand_get_param_descr(void);
> static int            expand_set_parameters(xine_post_t *this_gen,
> void *param_gen);
> static int            expand_get_parameters(xine_post_t *this_gen,
> void *param_gen);
> static char          *expand_get_help (void);
> 
> /* replaced video port functions */
> static vo_frame_t    *expand_get_frame(xine_video_port_t *port_gen,
> uint32_t width,
>                                        uint32_t height, double ratio,
>                                        int format, int flags);
> 
> /* replaced vo_frame functions */
> static int            expand_draw(vo_frame_t *frame, xine_stream_t *stream);
> 
> /* event listener */
> static int            is_event_callback (void *user_data, const
> xine_event_t *event);
> 
> /* overlay manager intercept check */
> static int            expand_intercept_ovl(post_video_port_t *port);
> 
> /* replaced overlay manager functions */
> static int32_t        expand_overlay_add_event(video_overlay_manager_t
> *this_gen, void *event);
> 
> void *expand_init_plugin(xine_t *xine, void *data)
> {
>   post_class_t *class = (post_class_t *)malloc(sizeof(post_class_t));
> 
>   if (!class)
>     return NULL;
> 
>   class->open_plugin     = expand_open_plugin;
>   class->get_identifier  = expand_get_identifier;
>   class->get_description = expand_get_description;
>   class->dispose         = expand_class_dispose;
> 
>   return class;
> }
> 
> static post_plugin_t *expand_open_plugin(post_class_t *class_gen, int inputs,
>                                          xine_audio_port_t **audio_target,
>                                          xine_video_port_t **video_target,
>                                          xine_stream_t *stream)
> {
>   post_expand_t     *this        = (post_expand_t
> *)xine_xmalloc(sizeof(post_expand_t));
>   post_in_t         *input;
>   xine_post_in_t    *input_param;
>   post_out_t        *output;
>   post_video_port_t *port;
>   static xine_post_api_t post_api =
>     { expand_set_parameters, expand_get_parameters,
> expand_get_param_descr, expand_get_help };
> 
>   if (!this || !video_target || !video_target[0]) {
>     free(this);
>     return NULL;
>   }
> 
>   _x_post_init(&this->post, 0, 1);
> 
>   this->stream     = stream;
> 
>   this->enable_automatic_shift = 0;
>   this->overlay_y_offset       = 0;
>   this->centre_cut_out_mode    = 0;
>   this->cropping_active        = 0;
> 
>   this->event_queue = xine_event_new_queue (this->stream);
> 
>   xine_event_create_listener_thread (this->event_queue,
>                                      is_event_callback,
>                                      this);
> 
> 
>   port = _x_post_intercept_video_port(&this->post, video_target[0],
> &input, &output);
>   port->new_port.get_frame     = expand_get_frame;
>   port->intercept_ovl          = expand_intercept_ovl;
>   port->new_manager->add_event = expand_overlay_add_event;
>   port->new_frame->draw        = expand_draw;
> 
>   input_param       = &this->parameter_input;
>   input_param->name = "parameters";
>   input_param->type = XINE_POST_DATA_PARAMETERS;
>   input_param->data = &post_api;
>   xine_list_append_content(this->post.input, input_param);
> 
>   input->xine_in.name   = "video";
>   output->xine_out.name = "expanded video";
> 
>   this->post.xine_post.video_input[0] = &port->new_port;
> 
>   this->post.dispose = expand_dispose;
> 
>   return &this->post;
> }
> 
> static char *expand_get_identifier(post_class_t *class_gen)
> {
>   return "expand";
> }
> 
> static char *expand_get_description(post_class_t *class_gen)
> {
>   return "add black borders to top and bottom of video to expand it to
> 4:3 aspect ratio";
> }
> 
> static void expand_class_dispose(post_class_t *class_gen)
> {
>   free(class_gen);
> }
> 
> static void expand_dispose(post_plugin_t *this_gen)
> {
>   post_expand_t     *this = (post_expand_t *)this_gen;
> 
>   if (_x_post_dispose(this_gen))
>     free(this);
> }
> 
> static xine_post_api_descr_t *expand_get_param_descr(void)
> {
>   return &expand_param_descr;
> }
> 
> static int expand_set_parameters(xine_post_t *this_gen, void *param_gen)
> {
>   post_expand_t *this = (post_expand_t *)this_gen;
>   expand_parameters_t *param = (expand_parameters_t *)param_gen;
> 
>   this->enable_automatic_shift = param->enable_automatic_shift;
>   this->overlay_y_offset       = param->overlay_y_offset;
>   this->centre_cut_out_mode    = param->centre_cut_out_mode;
> 
>   return 1;
> }
> 
> static int expand_get_parameters(xine_post_t *this_gen, void *param_gen)
> {
>   post_expand_t *this = (post_expand_t *)this_gen;
>   expand_parameters_t *param = (expand_parameters_t *)param_gen;
> 
>   param->enable_automatic_shift = this->enable_automatic_shift;
>   param->overlay_y_offset       = this->overlay_y_offset;
>   param->centre_cut_out_mode    = this->centre_cut_out_mode;
> 
>   return 1;
> }
> 
> static char *expand_get_help(void) {
>   return _("The expand plugin is meant to take frames of arbitrary
> aspect ratio and "
>            "converts them to 4:3 aspect by adding black bars on the
> top and bottom "
>            "of the frame. This allows us to shift overlays down into
> the black area "
>            "so they don't cover the image.\n"
>            "\n"
>            "Parameters (FIXME: better help)\n"
>            "  Enable_automatic_shift: Enable automatic overlay shifting\n"
>            "  Overlay_y_offset: Manually shift the overlay vertically\n"
>            "  Centre_cut_out_mode: extracts 4:3 image contained in 16:9 frame\n"
>            "\n"
>          );
> }
> 
> static vo_frame_t *expand_get_frame(xine_video_port_t *port_gen, uint32_t width,
>                                     uint32_t height, double ratio,
>                                     int format, int flags)
> {
>   post_video_port_t *port = (post_video_port_t *)port_gen;
>   post_expand_t     *this = (post_expand_t *)port->post;
>   vo_frame_t        *frame;
>   uint32_t           new_height, top_bar_height;
>   int                i, end;
> 
>   _x_post_rewire(&this->post);
> 
>   if (ratio <= 0.0) ratio = (double)width / (double)height;
> 
>   /* Calculate height of expanded frame */
>   new_height = (double)height * ratio * 3.0 / 4.0;
>   new_height = (new_height + 1) & ~1;
>   top_bar_height = (new_height - height) / 2;
>   top_bar_height = (top_bar_height + 1) & ~1;
> 
>   this->top_bar_height = top_bar_height;
> 
>   if (new_height > height &&
>       (format == XINE_IMGFMT_YV12 || format == XINE_IMGFMT_YUY2)) {
>     frame = port->original_port->get_frame(port->original_port,
>       width, new_height, 4.0 / 3.0, format, flags);
> 
>     _x_post_inc_usage(port);
>     frame = _x_post_intercept_video_frame(frame, port);
> 
>     /* paint black bars in the top and bottom of the frame and hide these
>      * from the decoders by modifying the pointers to and
>      * the size of the drawing area */
>     frame->height = height;
>     frame->ratio  = ratio;
>     switch (format) {
>     case XINE_IMGFMT_YV12:
>       /* paint top bar */
>       memset(frame->base[0],   0, frame->pitches[0] * top_bar_height    );
>       memset(frame->base[1], 128, frame->pitches[1] * top_bar_height / 2);
>       memset(frame->base[2], 128, frame->pitches[2] * top_bar_height / 2);
>       /* paint bottom bar */
>       memset(frame->base[0] + frame->pitches[0] * (top_bar_height +
> height)    ,   0,
>         frame->pitches[0] * (new_height - top_bar_height - height)    );
>       memset(frame->base[1] + frame->pitches[1] * (top_bar_height +
> height) / 2, 128,
>         frame->pitches[1] * (new_height - top_bar_height - height) / 2);
>       memset(frame->base[2] + frame->pitches[2] * (top_bar_height +
> height) / 2, 128,
>         frame->pitches[2] * (new_height - top_bar_height - height) / 2);
>       /* modify drawing area */
>       frame->base[0] += frame->pitches[0] * top_bar_height;
>       frame->base[1] += frame->pitches[1] * top_bar_height / 2;
>       frame->base[2] += frame->pitches[2] * top_bar_height / 2;
>       break;
>     case XINE_IMGFMT_YUY2:
>       /* paint top bar */
>       end = frame->pitches[0] * top_bar_height;
>       for (i = 0; i < end; i += 2) {
>         frame->base[0][i]   = 0;
>         frame->base[0][i+1] = 128;
>       }
>       /* paint bottom bar */
>       end = frame->pitches[0] * new_height;
>       for (i = frame->pitches[0] * (top_bar_height + height); i < end; i += 2) {
>         frame->base[0][i]   = 0;
>         frame->base[0][i+1] = 128;
>       }
>       /* modify drawing area */
>       frame->base[0] += frame->pitches[0] * top_bar_height;
>     }
>   } else {
>     frame = port->original_port->get_frame(port->original_port,
>       width, height, ratio, format, flags);
>     /* no need to intercept this one, we are not going to do anything with it */
>   }
> 
>   return frame;
> }
> 
> static int expand_intercept_ovl(post_video_port_t *port)
> {
>   post_expand_t         *this = (post_expand_t *)port->post;
> 
>   if (this->centre_cut_out_mode && this->cropping_active) return 0;
> 
>   /* we always intercept overlay manager */
>   return 1;
> }
> 
> static int32_t expand_overlay_add_event(video_overlay_manager_t
> *this_gen, void *event_gen)
> {
>   video_overlay_event_t *event = (video_overlay_event_t *)event_gen;
>   post_video_port_t     *port = _x_post_ovl_manager_to_port(this_gen);
>   post_expand_t         *this = (post_expand_t *)port->post;
> 
>   if (event->event_type == OVERLAY_EVENT_SHOW) {
>     switch (event->object.object_type) {
>     case 0:
>       /* regular subtitle */
>       if (this->enable_automatic_shift)
>         event->object.overlay->y += 2 * this->top_bar_height;
>       else
>         event->object.overlay->y += this->overlay_y_offset;
>       break;
>     case 1:
>       /* menu overlay */
>       event->object.overlay->y += this->top_bar_height;
>     }
>   }
> 
>   return port->original_manager->add_event(port->original_manager, event_gen);
> }
> 
> static int is_pixel_black(vo_frame_t *frame, int x, int y)
> {
>   int Y = 0x00, Cr = 0x00, Cb = 0x00;
> 
>   if (x < 0)              x = 0;
>   if (x >= frame->width)  x = frame->width - 1;
>   if (y < 0)              y = 0;
>   if (y >= frame->height) y = frame->height - 1;
> 
>   switch (frame->format)
>   {
>   case XINE_IMGFMT_YV12:
>     Y  = *(frame->base[ 0 ] + frame->pitches[ 0 ] * y     + x);
>     Cr = *(frame->base[ 1 ] + frame->pitches[ 1 ] * y / 2 + x / 2);
>     Cb = *(frame->base[ 2 ] + frame->pitches[ 2 ] * y / 2 + x / 2);
>     break;
> 
>   case XINE_IMGFMT_YUY2:
>     Y  = *(frame->base[ 0 ] + frame->pitches[ 0 ] * y + x * 2 + 0);
>     x &= ~1;
>     Cr = *(frame->base[ 0 ] + frame->pitches[ 0 ] * y + x * 2 + 1);
>     Cb = *(frame->base[ 0 ] + frame->pitches[ 0 ] * y + x * 2 + 3);
>     break;
>   }
> 
>   return (Y == 0x10 && Cr == 0x80 && Cb == 0x80);
> }
> 
> static int is_event_callback (void *user_data, const xine_event_t *event)
> {
>   /* this doesn't do anything for now: it's a start at attempting to display
>    * CMML clips which occur at 0 seconds into the track.  see
>    *
>    *   http://marc.theaimsgroup.com/?l=xine-devel&m=109202443013890&w=2
>    *
>    * for a description of the problem. */
> 
>   switch (event->type) {
>     case XINE_EVENT_INPUT_MENU1:
>       lprintf("video_frame_format_change_callback called!\n");
>       break;
>     default:
>       lprintf("video_frame_format_change_callback called with unknown
> event %d\n", event->type);
>       break;
>   }
> }
> 
> static int expand_draw(vo_frame_t *frame, xine_stream_t *stream)
> {
>   post_video_port_t *port = (post_video_port_t *)frame->port;
>   post_expand_t     *this = (post_expand_t *)port->post;
>   int                skip;
> 
>   if (this->centre_cut_out_mode && !frame->bad_frame)
>   {
>     /* expected area of inner 4:3 image */
>     int centre_width = frame->width * (9 * 4) / (16 * 3);
>     int centre_left  = (frame->width - centre_width ) / 2;
> 
>     /* centre point for detecting a black frame */
>     int centre_x = frame->width  / 2;
>     int centre_y = frame->height / 2;
> 
>     /* ignore a black frame as it could lead to wrong results */
>     if (!is_pixel_black(frame, centre_x, centre_y))
>     {
>       /* coordinates for testing black border near the centre area */
>       int test_left  = centre_left - 16;
>       int test_right = centre_left + 16 + centre_width;
> 
>       /* enable cropping when these pixels are black */
>       this->cropping_active = is_pixel_black(frame, test_left, centre_y)
>         && is_pixel_black(frame, test_right, centre_y);
>     }
> 
>     /* crop frame */
>     if (this->centre_cut_out_mode && this->cropping_active) {
>       frame->crop_left  += centre_left;
>       frame->crop_right += centre_left;
> 
>       /* get_frame() allocated an extra high frame */
>       frame->crop_top    += (frame->next->height - frame->height) / 2;
>       frame->crop_bottom += (frame->next->height - frame->height) / 2;
>     }
>   }
> 
>   _x_post_frame_copy_down(frame, frame->next);
>   skip = frame->next->draw(frame->next, stream);
>   _x_post_frame_copy_up(frame, frame->next);
> 
>   return skip;
> }
> 
> > Mick
> >
>



More information about the vdr mailing list