> 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 > > >