[MPlayer-dev-eng] Re: [PATCH] SSA/ASS subtitles support
Reimar Döffinger
Reimar.Doeffinger at stud.uni-karlsruhe.de
Sat Jun 17 21:27:16 CEST 2006
Hello,
On Wed, Jun 14, 2006 at 01:09:42PM +0400, Evgeniy Stepanov wrote:
> Several bugfixes.
Some reviewing and a question.
Maybe even those developers without the time to review themselves can
review my review...
> Index: libmpcodecs/vf.h
> ===================================================================
> --- libmpcodecs/vf.h (.../branches/upstream) (revision 503)
> +++ libmpcodecs/vf.h (.../trunk) (revision 503)
> @@ -75,6 +75,7 @@
> #define VFCTRL_SKIP_NEXT_FRAME 12 /* For encoding - drop the next frame that passes thru */
> #define VFCTRL_FLUSH_FRAMES 13 /* For encoding - flush delayed frames */
> #define VFCTRL_SCREENSHOT 14 /* Make a screenshot */
> +#define VFCTRL_EOSD 15 /* Select EOSD renderer */
The other values are aligned so they are in the same column, so it should
be done here, too
in configure:
> @@ -5387,6 +5391,35 @@
> fi
> echores "$_fontconfig"
>
> +echocheck "SSA/ASS support"
> +# libass depends on freetype
> +if test "$_freetype" = no ; then
> + _ass=no
> + _res_comment="FreeType support needed"
> +fi
IMHO this should go in the "auto" case, --enable should always be respected,
regardless of the consequences.
in mplayer.c:
> @@ -1845,6 +1861,20 @@
> return 1;
> }
> #endif
> +#ifdef USE_ASS
> + if (ass_track && ass_track->name) {
> + char *tmp,*tmp2;
> + tmp = ass_track->name;
> + if ((tmp2 = strrchr(tmp, '/')))
> + tmp = tmp2+1;
> +
> + snprintf(*(char**)arg, 63, "(%d) %s%s",
> + set_of_sub_pos + 1,
> + strlen(tmp) < 20 ? "" : "...",
> + strlen(tmp) < 20 ? tmp : tmp+strlen(tmp)-19);
> + return 1;
> + }
> +#endif
Please do not duplicate code. Either move it in a seperate function or just
use the existing code e.g. by changing
"if (subdata)" to "if (subdata || ass_track)"
and
"tmp = subdata->filename;" to "tmp = subdata ? subdata->filename : ass_track->name;"
You can check for tmp == NULL then and set some useful substitute...
> @@ -1925,15 +1955,25 @@
[...]
> - subdata = set_of_subtitles[set_of_sub_pos];
> - vo_osd_changed(OSDTYPE_SUBTITLE);
> +#ifdef USE_ASS
> + if (ass_enabled && set_of_ass_tracks[set_of_sub_pos])
> + ass_track = set_of_ass_tracks[set_of_sub_pos];
> + else
> #endif
> + {
> + subdata = set_of_subtitles[set_of_sub_pos];
> + vo_osd_changed(OSDTYPE_SUBTITLE);
For improved patch-readability, I'd say don't change then indentation of
these two lines.
> @@ -3459,11 +3505,37 @@
[...]
> +#ifdef USE_ASS
> +if (ass_enabled)
> + ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_EOSD, 0);
> +#endif
> +
What is the intended purpose of this?
> @@ -5084,9 +5160,15 @@
> current_module="sub_free";
> for (i = 0; i < set_of_sub_size; ++i)
> sub_free( set_of_subtitles[i] );
> - set_of_sub_size = 0;
> vo_sub_last = vo_sub=NULL;
> subdata=NULL;
> +#ifdef USE_ASS
> + for (i = 0; i < set_of_sub_size; ++i)
> + if ( set_of_ass_tracks[i] )
> + ass_free_track( set_of_ass_tracks[i] );
> + ass_track = NULL;
> +#endif
> + set_of_sub_size = 0;
Why not save some code and do both frees in the same loop?
> Index: libass/ass_mp.c
> ===================================================================
> --- libass/ass_mp.c (.../branches/upstream) (revision 0)
> +++ libass/ass_mp.c (.../trunk) (revision 503)
> @@ -0,0 +1,9 @@
> +#include "ass_mp.h"
> +
> +// libass-related command line options
> +float ass_font_scale = 1.;
> +float ass_line_spacing = 0.;
> +int ass_top_margin = 0;
> +int ass_bottom_margin = 0;
> +int extract_embedded_fonts = 0;
> +
A whole file for just nine lines seems a bit like overkill to me, but your decision.
in ass_render.c:
> +#define PI 3.1415926535897932384626433832795029L
why not just use M_PI? I think we already (e.g. in the audio filters) require
that to be defined properly in math.h
> +#define _r(c) ((c)>>24)
> +#define _g(c) (((c)>>16)&0xFF)
> +#define _b(c) (((c)>>8)&0xFF)
> +#define _a(c) ((c)&0xFF)
> +#define rgba2y(c) ( (( 263*_r(c) + 516*_g(c) + 100*_b(c)) >> 10) + 16 )
> +#define rgba2u(c) ( ((-152*_r(c) - 298*_g(c) + 450*_b(c)) >> 10) + 128 )
> +#define rgba2v(c) ( (( 450*_r(c) - 376*_g(c) - 73*_b(c)) >> 10) + 128 )
These seem to be unused??
> +/**
> + * \brief Parse color value from ass script.
> + */
> +static inline unsigned ampcolor(char* p, char** q) {
> +#define badcolor { mp_msg(MSGT_GLOBAL, MSGL_WARN, "bad color at %s:%d\n", __FILE__, __LINE__); *q = p; return 0; }
IMHO this is ugly and also bloats code. Normally I woud suggest using goto,
but here:
> + unsigned color = 0;
> + if (*p++ != '&') badcolor
> + if (*p++ != 'H') badcolor
why not just
if (*p++ != '&' || *p++ != 'H') {
mp_msg(...);
}
Ok, you can't make a difference between the '&' and 'H' expected cases then...
> +/**
> + * \brief Calculate a weighted average of two colors
> + * calculates c1*(1-a) + c2*a, but separately for each component
> + */
> +static unsigned color_avg(unsigned c1, unsigned c2, double a)
> +{
> + unsigned char* p1 = (unsigned char*)&c1;
> + unsigned char* p2 = (unsigned char*)&c2;
> + unsigned c3;
> + unsigned char* p3 = (unsigned char*)&c3;
> + int i;
> + for (i = 0; i < 4; ++i)
> + p3[i] = p1[i] * (1 - a) + p2[i] * a;
> + return c3;
If something absolutely needs to have 4 bytes size, please use uint32_t instead of
just unsigned. Also
> +static void change_alpha(unsigned* var, unsigned new_val, double pwr)
> +{
> + (*var) = color_avg(*var, ((*var) & 0xFFFFFF00) | new_val, pwr);
> +}
> +
> +static void change_color(unsigned* var, unsigned new_val, double pwr)
> +{
> + (*var) = color_avg(*var, ((*var) & 0x000000FF) | new_val, pwr);
> +}
Interpolating all four component when only one respectively three values
are different is a bit overkill...
Maybe it would be simpler to make c1, c2 and all internal color stuff
uin8_t c1[4] instead of unsigned and convert via the usual
(c1[0] << 24) | (c1[1] << 16) | (c1[2] << 8) | c1[3]
(see the BE_32 macro in libavcodec), though you might have to be more careful
to make sure it works with any endianness.
> +static void skip_spaces(char** str) {
> + char* p = *str;
> + while ((*p==' ') || (*p=='\t'))
> + ++p;
> + *str = p;
> +}
Is this what the specification defines as valid spaces? I think a comment
on this function would be nice, since e.g. UTF-8 sure specifies a lot more
as space...
> +static unsigned string2color(char* p) {
> +#define badcolor { mp_msg(MSGT_GLOBAL, MSGL_WARN, "bad color at %s:%d\n", __FILE__, __LINE__); return 0; }
Huh? What is the difference between this function and the previous one where
I complained about this macro?
> +#define NEXT(str,token) \
> + token = next_token(&str); \
> + if (!token) break;
> +
> +#define ANYVAL(name,func) \
> + } else if (strcasecmp(tname, #name) == 0) { \
> + target->name = func(token); \
> + mp_msg(MSGT_GLOBAL, MSGL_DBG2, "%s = %s\n", #name, token);
> +#define STRVAL(name) ANYVAL(name,strdup)
> +#define COLORVAL(name) ANYVAL(name,string2color)
> +#define INTVAL(name) ANYVAL(name,atoi)
> +#define FPVAL(name) ANYVAL(name,atof)
> +#define TIMEVAL(name) ANYVAL(name,string2timecode)
> +#define STYLEVAL(name) \
> + } else if (strcasecmp(tname, #name) == 0) { \
> + target->name = lookup_style(track, token); \
> + mp_msg(MSGT_GLOBAL, MSGL_DBG2, "%s = %s\n", #name, token);
> +
> +#define ALIAS(alias,name) \
> + if (strcasecmp(tname, #alias) == 0) {tname = #name;}
Hmmm... maybe you can convert some of these into functions, I think it might
help readability a bit (esp. when it comes to checking for possible
vulnerabilities - which I admit I am not doing).
> +static void* guess_cp(char* data, int size, char *preferred_language, char *fallback)
How does this function relate to the code in subreader.c? Can that one be
change to use this function, too?
> +static char* validate_fname(char* name)
I am not sure this is careful enough - though I think this feature is a
problem in itself.
> +/**
> + * \brief Process embedded matroska font. Saves it to ~/.mplayer/fonts.
I do not like this at all.
This feature might be misused in many ways, one I can think of is leaving
a track record of which films somebody has been watching.
The fact that it is disabled by default might make it acceptable though.
I prefer if there was a way to use embedded fonts with at most using
temporary files created via tmpfile instead (hopefully this function is
portable enough).
> Index: libass/ass_utils.c
> ===================================================================
> --- libass/ass_utils.c (.../branches/upstream) (revision 0)
> +++ libass/ass_utils.c (.../trunk) (revision 503)
> @@ -0,0 +1,39 @@
> +#include "config.h"
> +
> +#include <stdint.h>
> +#include <sys/time.h>
> +#include <time.h>
> +
> +#include "mp_msg.h"
> +#include "ass_utils.h"
> +
> +unsigned utf8_to_ucs4(char** str)
I give whoever commits the wonderful duty to find a place for this
function and the utf8_get_char in libvo/sub.c (they are the same).
> +#define MAX_FACE_CACHE_SIZE 100
> +
> +static face_cache_item_t face_cache[MAX_FACE_CACHE_SIZE];
How big is this? Might be better to allocate at runtime because
if I understand things correctly this will increase startup time
and memory consumption even if ass is not used at all...
> +static unsigned glyph_hash(glyph_hash_key_t* key) {
> + unsigned val = 0;
> + unsigned i;
> + for (i = 0; i < sizeof(key->face); ++i)
> + val += *(unsigned char *)(&(key->face) + i);
> + val <<= 21;
This does not look like the keys will be very unique. Can this be a problem?
Somebody please make Moritz review the changes to demux_mkv *g*
> Index: mencoder.c
> ===================================================================
> --- mencoder.c (.../branches/upstream) (revision 503)
> +++ mencoder.c (.../trunk) (revision 503)
> @@ -54,6 +54,7 @@
> #include "libmpdemux/stheader.h"
> #include "libmpdemux/mp3_hdr.h"
> #include "libmpdemux/muxer.h"
> +#include "libmpdemux/matroska.h"
Why is this needed? Can it be avoided? (if this is in mplayer.c as well,
same question there *g*)
And now for something completely different. What do you think would be needed
to support this in vo_gl.c? What would be the steps needed to get one or
several bitmaps containing the overlay data for the current frame?
Greetings,
Reimar Döffinger
P.S. I did not review any of the parts under #if 0, might be a good idea to
remove them before committing.
More information about the MPlayer-dev-eng
mailing list