AU Streaming : patch libass pour ffmpeg

Venez prendre connaissance des changements concernant la communauté d'Anime-Ultime

Modérateur: Modérateurs

AU Streaming : patch libass pour ffmpeg

Messagepar ryoku » 15 Août 2010, 17:52

Rien d'officiel et ça n'interessera pas grand monde, mais google étant ce qu'il est (et par grosse flemme de ma part de le faire ailleurs xD) voici les outils que j'ai utilisé pour le streaming et notamment un patch ass pour ffmpeg que j'ai du modifié pour compilé avec les dernières versions.

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

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}},
  };

Image
Avatar de l’utilisateur
ryoku
Divinité Ultime
 
Message(s) : 1689
Enregistré le: 13 Déc 2005, 22:51

Retour vers Communiqués officiels

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 5 invités

cron