Le patch originel se trouve ici : http://www.mail-archive.com/ffmpeg-soc@mplayerhq.hu/msg05705.html
(Aussi ça m'evitera de devoir tout refaire car j'avais oublié que j'avais modifié des choses à la main, de delete et de me retrouver comme un con lors d'une MàJ )
Libass (http://repo.or.cz/w/libass.git/) : 0.9.10
FFMPEG : r24796
- Code : Tout sélectionner
/*
* SSA/ASS subtitles rendering filter, using libssa.
* Based on vf_drawbox.c from libavfilter and vf_ass.c from mplayer.
*
* Copyright (c) 2006 Evgeniy Stepanov <eugeni.stepa...@gmail.com>
* Copyright (c) 2008 Affine Systems, Inc (Michael Sullivan, Bobby Impollonia)
* Copyright (c) 2009 Alexey Lebedeff <bina...@binarin.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
/*
* Usage: '-vfilters ass=filename:somefile.ass|margin:50|encoding:utf-8'
* Only 'filename' param is mandatory.
*/
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <ass/ass.h>
#include "avfilter.h"
typedef struct
{
ASS_Library *ass_library;
ASS_Renderer *ass_renderer;
ASS_Track *ass_track;
int margin;
char *filename;
char *encoding;
int frame_width, frame_height;
int vsub,hsub; //< chroma subsampling
} AssContext;
static int parse_args(AVFilterContext *ctx, AssContext *context, const char* args);
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
{
AssContext *context= ctx->priv;
/* defaults */
context->margin = 10;
context->encoding = "utf-8";
if ( parse_args(ctx, context, args) )
return 1;
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
enum PixelFormat pix_fmts[] = {10,
PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV420P,
PIX_FMT_YUV411P, PIX_FMT_YUV410P,
PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
PIX_FMT_YUV440P, PIX_FMT_YUVJ440P,
PIX_FMT_NONE };
avfilter_set_common_formats
(ctx,
avfilter_make_format_list(pix_fmts));
return 0;
}
static int config_input(AVFilterLink *link)
{
AssContext *context = link->dst->priv;
context->frame_width = link->w;
context->frame_height = link->h;
context->ass_library = ass_library_init();
if ( !context->ass_library ) {
av_log(0, AV_LOG_ERROR, "ass_library_init() failed!\n");
return 1;
}
ass_set_fonts_dir(context->ass_library, "");
ass_set_extract_fonts(context->ass_library, 1);
ass_set_style_overrides(context->ass_library, NULL);
context->ass_renderer = ass_renderer_init(context->ass_library);
if ( ! context->ass_renderer ) {
av_log(0, AV_LOG_ERROR, "ass_renderer_init() failed!\n");
return 1;
}
ass_set_frame_size(context->ass_renderer, link->w, link->h);
ass_set_margins(context->ass_renderer, context->margin, context->margin, context->margin, context->margin);
ass_set_use_margins(context->ass_renderer, 1);
ass_set_font_scale(context->ass_renderer, 1.);
ass_set_fonts(context->ass_renderer, NULL, "Sans", 1, NULL, 1);
context->ass_track = ass_read_file(context->ass_library, context->filename, context->encoding);
if ( !context->ass_track ) {
av_log(0, AV_LOG_ERROR, "Failed to read subtitle file with ass_read_file()!\n");
return 1;
}
avcodec_get_chroma_sub_sample(link->format,
&context->hsub, &context->vsub);
return 0;
}
static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
{
avfilter_start_frame(link->dst->outputs[0], picref);
}
#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 )
static void draw_ass_image(AVFilterBufferRef *pic, ASS_Image *img, AssContext *context)
{
unsigned char *row[4];
unsigned char c_y = rgba2y(img->color);
unsigned char c_u = rgba2u(img->color);
unsigned char c_v = rgba2v(img->color);
unsigned char opacity = 255 - _a(img->color);
unsigned char *src;
int i, j;
unsigned char *bitmap = img->bitmap;
int bitmap_w = img->w;
int bitmap_h = img->h;
int dst_x = img->dst_x;
int dst_y = img->dst_y;
int channel;
int x,y;
src = bitmap;
for (i = 0; i < bitmap_h; ++i) {
y = dst_y + i;
if ( y >= pic->video->h )
break;
row[0] = pic->data[0] + y * pic->linesize[0];
for (channel = 1; channel < 3; channel++)
row[channel] = pic->data[channel] +
pic->linesize[channel] * (y>> context->vsub);
for (j = 0; j < bitmap_w; ++j) {
unsigned k = ((unsigned)src[j]) * opacity / 255;
x = dst_x + j;
if ( y >= pic->video->w )
break;
row[0][x] = (k*c_y + (255-k)*row[0][x]) / 255;
row[1][x >> context->hsub] = (k*c_u + (255-k)*row[1][x >> context->hsub]) / 255;
row[2][x >> context->hsub] = (k*c_v + (255-k)*row[2][x >> context->hsub]) / 255;
}
src += img->stride;
}
}
static void end_frame(AVFilterLink *link)
{
AssContext *context = link->dst->priv;
AVFilterLink* output = link->dst->outputs[0];
AVFilterBufferRef *pic = link->cur_buf;
ASS_Image* img = ass_render_frame(context->ass_renderer,
context->ass_track,
pic->pts * 1000 / AV_TIME_BASE,
NULL);
while ( img ) {
draw_ass_image(pic, img, context);
img = img->next;
}
avfilter_draw_slice(output, 0, pic->video->h, 1);
avfilter_end_frame(output);
}
static int parse_args(AVFilterContext *ctx, AssContext *context, const char* args)
{
char *arg_copy = av_strdup(args);
char *strtok_arg = arg_copy;
char *param;
while ( param = strtok(strtok_arg, "|") ) {
char *tmp = param;
char *param_name;
char *param_value;
strtok_arg = NULL;
while ( *tmp && *tmp != ':' ) {
tmp++;
}
if ( param == tmp || ! *tmp ) {
av_log(ctx, AV_LOG_ERROR, "Error while parsing arguments - must be like 'param1:value1|param2:value2'\n");
return 1;
}
param_name = av_malloc(tmp - param + 1);
memset(param_name, 0, tmp - param + 1);
strncpy(param_name, param, tmp-param);
tmp++;
if ( ! *tmp ) {
av_log(ctx, AV_LOG_ERROR, "Error while parsing arguments - parameter value cannot be empty\n");
return 1;
}
param_value = av_strdup(tmp);
if ( !strcmp("margin", param_name ) ) {
context->margin = atoi(param_value);
} else if ( !strcmp("filename", param_name ) ) {
context->filename = av_strdup(param_value);
} else if ( !strcmp("encoding", param_name ) ) {
context->encoding = av_strdup(param_value);
} else {
av_log(ctx, AV_LOG_ERROR, "Error while parsing arguments - unsupported parameter '%s'\n", param_name);
return 1;
}
av_free(param_name);
av_free(param_value);
}
if ( ! context->filename ) {
av_log(ctx, AV_LOG_ERROR, "Error while parsing arguments - mandatory parameter 'filename' missing\n");
return 1;
}
return 0;
}
AVFilter avfilter_vf_ass=
{
.name = "ass",
.priv_size = sizeof(AssContext),
.init = init,
.query_formats = query_formats,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = CODEC_TYPE_VIDEO,
.start_frame = start_frame,
.end_frame = end_frame,
.config_props = config_input,
.min_perms = AV_PERM_WRITE |
AV_PERM_READ,
.rej_perms = AV_PERM_REUSE |
AV_PERM_REUSE2},
{ .name = NULL}},
.outputs = (AVFilterPad[]) {{ .name = "default",
.type = CODEC_TYPE_VIDEO, },
{ .name = NULL}},
};