Hi,
I'm pleased to announce bugfix release 0.7.1:
http://home.vr-web.de/~rnissl/vdr-xine-0.7.1.tgz
2005-02-13: Version 0.7.1
*** NO NEED TO RECOMPILE XINE THIS TIME ***
- Updated finish translation (thanks to Rolf Ahrensberg for supplying the update). - Fixed a typo in checking for VDR versions before 1.3.18. This broke successful compilation for versions between 1.3.8 and 1.3.18 (thanks to Andreas Urban for reporting this issue). - Fixed processing of cDevice::SetDigitalAudio() as it skipped displaying of NO SIGNAL when switching channels.
For this release I suggest the following xine sources:
http://home.vr-web.de/~rnissl/xine-lib-cvs-20050127201000.tar.bz2 http://home.vr-web.de/~rnissl/xine-ui-cvs-20050127201000.tar.bz2
Enjoy.
Bye.
On Sun, Feb 13, 2005 at 09:47:56AM +0100, Reinhard Nissl wrote:
Hi,
I'm pleased to announce bugfix release 0.7.1:
http://home.vr-web.de/~rnissl/vdr-xine-0.7.1.tgz
2005-02-13: Version 0.7.1
*** NO NEED TO RECOMPILE XINE THIS TIME ***
hooraaay! :)
... anyone doing .debs?
I demand that Luke Kenneth Casson Leighton may or may not have written...
On Sun, Feb 13, 2005 at 09:47:56AM +0100, Reinhard Nissl wrote:
I'm pleased to announce bugfix release 0.7.1: http://home.vr-web.de/~rnissl/vdr-xine-0.7.1.tgz 2005-02-13: Version 0.7.1 *** NO NEED TO RECOMPILE XINE THIS TIME ***
hooraaay! :)
... anyone doing .debs?
Me, soon...
On Sun, 13 Feb 2005, Anssi Hannula wrote:
Are you planning to add support for socket connections as proposed by Patrick Boettcher anytime soon?
I volunteered to try to implement this thing to vdr-xine (and remove fifo handling completely if speed allows it). I have to say I underestimated the complexity of the vdr-xine Plugin (especially the full-featured-device emulation). Implementing would be not so hard, but it should be maintainable afterwards and thus one has to pay attention to good code style and reusability.
On the other hand developing an open source project without a public version control system is very uncomfortable, at least for me.
Currently I stuck in another project (besides work), when it can be understand as completed, I plan to invest time to have a deeper look into vdr-xine (and maybe we have a vdr-xine CVS then :) ).
best regards, Patrick.
-- Mail: patrick.boettcher@desy.de WWW: http://www.wi-bw.tfh-wildau.de/~pboettch/
Hi,
Reinhard Nissl wrote:
I'm pleased to announce bugfix release 0.7.1:
http://home.vr-web.de/~rnissl/vdr-xine-0.7.1.tgz
2005-02-13: Version 0.7.1
*** NO NEED TO RECOMPILE XINE THIS TIME ***
For current cvs xine you'll need to change my plugin's version from 15 to 16:
xine-lib-cvs/src/vdr/input_vdr.c:1584: { PLUGIN_INPUT, 16, "VDR", XINE_VERSION_CODE, NULL, init_class },
Bye.
On Sun, Feb 13, 2005 at 02:08:07PM +0100, Reinhard Nissl wrote:
For current cvs xine you'll need to change my plugin's version from 15 to 16:
xine-lib-cvs/src/vdr/input_vdr.c:1584: { PLUGIN_INPUT, 16, "VDR", XINE_VERSION_CODE, NULL, init_class },
Thank you very much, unfortunately even with the recommended xine-lib and xine-ui, xine keeps crashing all the time (and then vdr took 100% of my CPU during about 1 minute and then everything comes to normal).
Right now, I use xine to programm my timer, and mplayer to actually watch the recordings (and it even take much lower CPU).
Thank for the so quick fix :-)
On Sun, Feb 13, 2005 at 02:32:01PM +0100, Grégoire Favre wrote:
Thank you very much, unfortunately even with the recommended xine-lib and xine-ui, xine keeps crashing all the time (and then vdr took 100% of my CPU during about 1 minute and then everything comes to normal).
Right now, I use xine to programm my timer, and mplayer to actually watch the recordings (and it even take much lower CPU).
I have to appologize : xine is not in cause, in fact I got lots of crashes in vdr without even launching the xine-plugin, but I have a lots of patches in my VDR (AIO and configurable sharing patch in fact, and vdr-1.3.21 source dependent new channel insertation) which mean I should take more time to test with a vanilla vdr first.
Disabling the EPG scan seems to reduce the crashes...
Thank you very much for this tremendous plugin :-)
Reinhard,
Excellant! centre cut out mode is great! great great great!!!
But, can I help to make it better? I noticed when whatching the simpsons last night forsomereason it took a minute or two to start (this only happened once).. Then, once it had "sensed" the picture change, when some add break came up and the menu was on, the menu was "zoomed" also. I think maybe what is hapening is there is a delay from when the scene change is noted as zoomed, say 1 second? Then the menu will change to the correct size, but if the scenes keep on cutting the menu never gets a chance to catch up.
Also, I'd really love to be able to use lirc or something (like vdr) to send commands to the post plugin, like on/off, or "aspect 1/2/3/4". That way this plugin can take care of the zooming in other cases for xine usage, likewatching movies etc. through freevo, What is your opinion on this? Is it possible to send status like on/off though sdctrl method?
In any case, great!
Mick
mike lewis wrote:
Also, I'd really love to be able to use lirc or something (like vdr) to send commands to the post plugin, like on/off, or "aspect 1/2/3/4". That way this plugin can take care of the zooming in other cases for xine usage, likewatching movies etc. through freevo, What is your opinion on this? Is it possible to send status like on/off though sdctrl method?
Hi, I haven't tried this version yet, or even looked at the code, but...
The post plugin could, or may already, listen for an internal xine event for changing the aspect. I suspect the vdr input plugin converts vdr events into xine events and posts them. If that's the case any xine ui could post the same event, even through the stdcrtl that Freevo uses - we'd just have to add the stdctrl part and the event passing in Freevo.
-Rob
I demand that mike lewis may or may not have written...
[snip]
Also, I'd really love to be able to use lirc or something (like vdr) to send commands to the post plugin, like on/off, or "aspect 1/2/3/4".
Controlling the plugin's configuration - yes, that seems reasonable, but I think that it's something for the xine-lib front end. I don't see any need for changing the aspect ratio unless the plugin needs to be able to handle displays other than 4:3, and even then you're likely to want to set it once and to forget about it.
Windowed mode is a different matter, but that's likely to be a dynamically-alterable aspect ratio anyway. Given this, aspect ratio information should come from the output window, rather than being a user-configurable option.
That way this plugin can take care of the zooming in other cases for xine usage, like watching movies etc. through freevo,
AFD support aside (Reinhard - anything to test?), shouldn't that Just Happen anyway?
Hi,
Darren Salt wrote:
Also, I'd really love to be able to use lirc or something (like vdr) to send commands to the post plugin, like on/off, or "aspect 1/2/3/4".
Controlling the plugin's configuration - yes, that seems reasonable, but I think that it's something for the xine-lib front end. I don't see any need for changing the aspect ratio unless the plugin needs to be able to handle displays other than 4:3, and even then you're likely to want to set it once and to forget about it.
Windowed mode is a different matter, but that's likely to be a dynamically-alterable aspect ratio anyway. Given this, aspect ratio information should come from the output window, rather than being a user-configurable option.
That way this plugin can take care of the zooming in other cases for xine usage, like watching movies etc. through freevo,
AFD support aside (Reinhard - anything to test?), shouldn't that Just Happen anyway?
I've had a look into your samples and extracted AFD information. But I won't find some time before March until I can start creating this "magic" post plugin.
Bye.
Also, I'd really love to be able to use lirc or something (like vdr) to send commands to the post plugin, like on/off, or "aspect 1/2/3/4".
Controlling the plugin's configuration - yes, that seems reasonable, but I think that it's something for the xine-lib front end. I don't see any need for changing the aspect ratio unless the plugin needs to be able to handle displays other than 4:3, and even then you're likely to want to set it once and to forget about it.
Windowed mode is a different matter, but that's likely to be a dynamically-alterable aspect ratio anyway. Given this, aspect ratio information should come from the output window, rather than being a user-configurable option.
OK, i think i'm using the wrong teminology again. The display aspect will always stay the same; but say on a 16:9 dvd, some times they still have some black bars on the top and bottom (i'm not sure of the term for this). In some cases it would be nice to be able to zoom the picture in so that you cut off some of the sides, but not all. In mplayer, zoom has about 6 stages from full 16:9 content, to looking at what would be the 4:3 picture with the tops and sites cut off like in centre_cutout_mode.
What I'm proposing is really just a copy of this feature, to be able to stage-zoom from full screen to centre_cut_full in xine. No, this now has nothing to do with vdr.. It about extending what Reinhard did for 4:3 AFD style content to be used on other media in xine...
That way this plugin can take care of the zooming in other cases for xine usage, like watching movies etc. through freevo,
AFD support aside (Reinhard - anything to test?), shouldn't that Just Happen anyway?
Well, AFD style does just work. But as per above it would be nice to use this feaure when watching a dvd to zoom. For example fight club is very dark.. So instead of having to use the tv remote to adjust the brighness, you could just zoom one or two stages. so it doesn't matter so much.
I'd be happy to play with the code a little to see If I can do this, as i think its very simply an extension of what Reinhard has done. But I have no idea how to tell if a post plugin can listen to an input event. I can't see any examples of an post plugin listening to input events.
And before you ask, the only reason for this is because vidixfb doesn't seem to zoom, as I think has been discussed on the xine list recently.
Mick
I'd be happy to play with the code a little to see If I can do this, as i think its very simply an extension of what Reinhard has done. But I have no idea how to tell if a post plugin can listen to an input event. I can't see any examples of an post plugin listening to input events.
OK,I think I bit off more that I can chew here ;-). I'mno coder lets face it. I've read through the expand plugin and it does not have an existing event structure. So I'mnot sure where exactly or what type of queue to use.
From xine.h, the options for queue's are:
i) A callback: this is what the vdr plugin uses to send key events to vdr from xine. ii) a non-blocking wait. this is what the also sound plugin uses.
OK cool, so I can read code, that was pretty hard ;-) (no really, I had to get out my '12 easy lessons of C' book from 10 years ago).
So where too from here? Can anyone offer some psudo code ideas on how it couldwork?
From what I can see in event.c, "static post_plugin_t
*expand_open_plugin" (what does static mean refer to?) is the function which makes call draw (function expand_draw): {{{ ... 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; ... }}}
So, what I'm thinking, in the spirit of KISS (this is a necessity for me, because the last S is me *wink*) is to simply: i) initiate the event_function with zoom setting of 0 (expected range 0-6) if event = zoom in, zoom+=1 if event = zoom out, zoom-=1
ii) create a callback on an event_function.
iii) in expand_draw, modify centre_cut_out_mode code to "levels" of zoom, 0-6 (where 0 is no zoom and 6 is zoom as is). Then do zoom as per zoom level. If center_cut_out_mode=1 then do zoom 6 where appropriate.
OK wow, i hope the above make sense.
Comments PLEASE ;-)
Mick
OK,I think I bit off more that I can chew here ;-). I'mno coder lets face it. I've read through the expand plugin and it does not have an existing event structure. So I'mnot sure where exactly or what type of queue to use.
From xine.h, the options for queue's are: i) A callback: this is what the vdr plugin uses to send key events to vdr from xine. ii) a non-blocking wait. this is what the also sound plugin uses.
OK cool, so I can read code, that was pretty hard ;-) (no really, I had to get out my '12 easy lessons of C' book from 10 years ago).
So where too from here? Can anyone offer some psudo code ideas on how it couldwork?
From what I can see in event.c, "static post_plugin_t *expand_open_plugin" (what does static mean refer to?) is the function which makes call draw (function expand_draw): {{{ ... 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; ... }}}
So, what I'm thinking, in the spirit of KISS (this is a necessity for me, because the last S is me *wink*) is to simply: i) initiate the event_function with zoom setting of 0 (expected range 0-6) if event = zoom in, zoom+=1 if event = zoom out, zoom-=1
ii) create a callback on an event_function.
iii) in expand_draw, modify centre_cut_out_mode code to "levels" of zoom, 0-6 (where 0 is no zoom and 6 is zoom as is). Then do zoom as per zoom level. If center_cut_out_mode=1 then do zoom 6 where appropriate.
OK wow, i hope the above make sense.
Comments PLEASE ;-)
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 ? ... ---
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
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
Hi,
mike lewis wrote:
Excellant! centre cut out mode is great! great great great!!!
But, can I help to make it better? I noticed when whatching the simpsons last night forsomereason it took a minute or two to start (this only happened once).. Then, once it had "sensed" the picture change, when some add break came up and the menu was on, the menu was "zoomed" also. I think maybe what is hapening is there is a delay from when the scene change is noted as zoomed, say 1 second? Then the menu will change to the correct size, but if the scenes keep on cutting the menu never gets a chance to catch up.
I've realized such a behaviour recently and I recall that Darren Salt has mentioned something like that on the xine ML. But still no time to spend work on it.
Feel free to supply further samples meanwhile. Your ftp-account is still active ;-)
Bye.
I've realized such a behaviour recently and I recall that Darren Salt has mentioned something like that on the xine ML. But still no time to spend work on it.
Feel free to supply further samples meanwhile. Your ftp-account is still active ;-)
So you'd like for me to send a smple of a file where I can repeat the action? I'll keep my eye on it.
Mick