Skip to content
Permalink
Browse files

WIP

  • Loading branch information
ubitux committed Nov 5, 2014
1 parent b477150 commit a73a19cfc5c5e27d06b6e0cdb4ec06b1c45c8240
@@ -25,6 +25,7 @@
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "libavutil/common.h"
#include "libavutil/subtitles.h"

int ff_ass_subtitle_header(AVCodecContext *avctx,
const char *font, int font_size,
@@ -88,99 +89,27 @@ int ff_ass_subtitle_header_default(AVCodecContext *avctx)
ASS_DEFAULT_ALIGNMENT);
}

static void insert_ts(AVBPrint *buf, int ts)
int ff_ass_fill_text_sub(AVTextSubtitle *sub, const AVBPrint *buf,
const AVPacket *pkt, int layer,
const char *style, const char *speaker)
{
if (ts == -1) {
av_bprintf(buf, "9:59:59.99,");
} else {
int h, m, s;

h = ts/360000; ts -= 360000*h;
m = ts/ 6000; ts -= 6000*m;
s = ts/ 100; ts -= 100*s;
av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts);
}
}

int ff_ass_bprint_dialog(AVBPrint *buf, const char *dialog,
int ts_start, int duration, int raw)
{
int dlen;

if (!raw || raw == 2) {
long int layer = 0;

if (raw == 2) {
/* skip ReadOrder */
dialog = strchr(dialog, ',');
if (!dialog)
return AVERROR_INVALIDDATA;
dialog++;

/* extract Layer or Marked */
layer = strtol(dialog, (char**)&dialog, 10);
if (*dialog != ',')
return AVERROR_INVALIDDATA;
dialog++;
}
av_bprintf(buf, "Dialogue: %ld,", layer);
insert_ts(buf, ts_start);
insert_ts(buf, duration == -1 ? -1 : ts_start + duration);
if (raw != 2)
av_bprintf(buf, "Default,,0,0,0,,");
}
int64_t readorder;

dlen = strcspn(dialog, "\n");
dlen += dialog[dlen] == '\n';
if (pkt->dts != AV_NOPTS_VALUE) readorder = pkt->dts;
else if (pkt->pos >= 0) readorder = pkt->pos;
else if (pkt->pts != AV_NOPTS_VALUE) readorder = pkt->pts;
else readorder = 0;

av_bprintf(buf, "%.*s", dlen, dialog);
if (raw == 2)
av_bprintf(buf, "\r\n");

return dlen;
}

int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
int ts_start, int duration, int raw)
{
AVBPrint buf;
int ret, dlen;
AVSubtitleRect **rects;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
if ((ret = ff_ass_bprint_dialog(&buf, dialog, ts_start, duration, raw)) < 0)
goto err;
dlen = ret;
if (!av_bprint_is_complete(&buf))
goto errnomem;

rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects));
if (!rects)
goto errnomem;
sub->rects = rects;
sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration);
rects[sub->num_rects] = av_mallocz(sizeof(*rects[0]));
rects[sub->num_rects]->type = SUBTITLE_ASS;
ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass);
if (ret < 0)
goto err;
sub->num_rects++;
return dlen;

errnomem:
ret = AVERROR(ENOMEM);
err:
av_bprint_finalize(&buf, NULL);
return ret;
}

int ff_ass_add_rect_bprint(AVSubtitle *sub, AVBPrint *buf,
int ts_start, int duration)
{
av_bprintf(buf, "\r\n");
if (!av_bprint_is_complete(buf))
return AVERROR(ENOMEM);
return ff_ass_add_rect(sub, buf->str, ts_start, duration, 0);
sub->dialog = av_asprintf("%"PRId64",%d,%s,%s,0,0,0,,%s",
readorder, layer, style ? style : "Default",
speaker ? speaker : "", buf->str);
if (!sub->dialog)
return AVERROR(ENOMEM);
sub->pts = pkt->pts;
sub->duration = pkt->duration;
return 0;
}

void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size,
@@ -24,6 +24,7 @@

#include "avcodec.h"
#include "libavutil/bprint.h"
#include "libavutil/subtitles.h"

/**
* @name Default values for ASS style
@@ -70,55 +71,11 @@ int ff_ass_subtitle_header(AVCodecContext *avctx,
int ff_ass_subtitle_header_default(AVCodecContext *avctx);

/**
* Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect.
*
* @param sub pointer to the AVSubtitle
* @param dialog ASS dialog to add to sub
* @param ts_start start timestamp for this dialog (in 1/100 second unit)
* @param duration duration for this dialog (in 1/100 second unit), can be -1
* to last until the end of the presentation
* @param raw when set to 2, it indicates that dialog contains an ASS
* dialog line as muxed in Matroska
* when set to 1, it indicates that dialog contains a whole SSA
* dialog line which should be copied as is.
* when set to 0, it indicates that dialog contains only the Text
* part of the ASS dialog line, the rest of the line
* will be generated.
* @return number of characters read from dialog. It can be less than the whole
* length of dialog, if dialog contains several lines of text.
* A negative value indicates an error.
*/
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
int ts_start, int duration, int raw);

/**
* Same as ff_ass_add_rect_bprint, but taking an AVBPrint buffer instead of a
* string, and assuming raw=0.
*/
int ff_ass_add_rect_bprint(AVSubtitle *sub, AVBPrint *buf,
int ts_start, int duration);

/**
* Add an ASS dialog line to an AVBPrint buffer.
*
* @param buf pointer to an initialized AVBPrint buffer
* @param dialog ASS dialog to add to sub
* @param ts_start start timestamp for this dialog (in 1/100 second unit)
* @param duration duration for this dialog (in 1/100 second unit), can be -1
* to last until the end of the presentation
* @param raw when set to 2, it indicates that dialog contains an ASS
* dialog line as muxed in Matroska
* when set to 1, it indicates that dialog contains a whole SSA
* dialog line which should be copied as is.
* when set to 0, it indicates that dialog contains only the Text
* part of the ASS dialog line, the rest of the line
* will be generated.
* @return number of characters read from dialog. It can be less than the whole
* length of dialog, if dialog contains several lines of text.
* A negative value indicates an error.
* XXX
*/
int ff_ass_bprint_dialog(AVBPrint *buf, const char *dialog,
int ts_start, int duration, int raw);
int ff_ass_fill_text_sub(AVTextSubtitle *sub, const AVBPrint *buf,
const AVPacket *pkt, int layer,
const char *style, const char *speaker);

/**
* Escape a text subtitle using ASS syntax into an AVBPrint buffer.
@@ -40,24 +40,19 @@ static av_cold int ass_decode_init(AVCodecContext *avctx)
static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
AVPacket *avpkt)
{
int ret;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
static const AVRational ass_tb = {1, 100};
const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, ass_tb);
const int ts_duration = av_rescale_q(avpkt->duration, avctx->time_base, ass_tb);
AVTextSubtitle *sub = data;

if (avpkt->size <= 0)
return avpkt->size;

ret = ff_ass_add_rect(sub, ptr, ts_start, ts_duration, 2);
if (ret < 0) {
if (ret == AVERROR_INVALIDDATA)
av_log(avctx, AV_LOG_ERROR, "Invalid ASS packet\n");
return ret;
}
sub->dialog = av_strdup(avpkt->data);
if (!sub->dialog)
return AVERROR(ENOMEM);

sub->pts = avpkt->pts;
sub->duration = avpkt->duration;

*got_sub_ptr = avpkt->size > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

@@ -39,6 +39,7 @@
#include "libavutil/log.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
#include "libavutil/subtitles.h"

#include "version.h"

@@ -4181,6 +4182,12 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt);

/**
* XXX
*/
int avcodec_decode_text_subtitle(AVCodecContext *avctx, AVTextSubtitle *sub,
int *got_sub_ptr, AVPacket *avpkt);

/**
* @defgroup lavc_parsing Frame parsing
* @{
@@ -168,7 +168,6 @@ static int jacosub_decode_frame(AVCodecContext *avctx,
void *data, int *got_sub_ptr, AVPacket *avpkt)
{
int ret;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;

if (avpkt->size <= 0)
@@ -184,14 +183,14 @@ static int jacosub_decode_frame(AVCodecContext *avctx,

av_bprint_init(&buffer, JSS_MAX_LINESIZE, JSS_MAX_LINESIZE);
jacosub_to_ass(avctx, &buffer, ptr);
ret = ff_ass_add_rect_bprint(sub, &buffer, avpkt->pts, avpkt->duration);
ret = ff_ass_fill_text_sub(data, &buffer, avpkt, 0, NULL, NULL);
av_bprint_finalize(&buffer, NULL);
if (ret < 0)
return ret;
}

end:
*got_sub_ptr = sub->num_rects > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

@@ -110,7 +110,7 @@ static int create_ass_text(TeletextContext *ctx, const char *text, char **ass)

/* Then we create the ass dialog line in buf2 from the escaped text in buf. */
av_bprint_init(&buf2, 0, AV_BPRINT_SIZE_UNLIMITED);
ff_ass_bprint_dialog(&buf2, buf.str, ts_start, ts_duration, 0);
//ff_ass_bprint_dialog(&buf2, buf.str, ts_start, ts_duration);
av_bprint_finalize(&buf, NULL);

if (!av_bprint_is_complete(&buf2)) {
@@ -258,7 +258,6 @@ static void microdvd_close_no_persistent_tags(AVBPrint *new_line,
static int microdvd_decode_frame(AVCodecContext *avctx,
void *data, int *got_sub_ptr, AVPacket *avpkt)
{
AVSubtitle *sub = data;
AVBPrint new_line;
char *line = avpkt->data;
char *end = avpkt->data + avpkt->size;
@@ -290,20 +289,13 @@ static int microdvd_decode_frame(AVCodecContext *avctx,
}
}
if (new_line.len) {
int ret;
int64_t start = avpkt->pts;
int64_t duration = avpkt->duration;
int ts_start = av_rescale_q(start, avctx->time_base, (AVRational){1,100});
int ts_duration = duration != -1 ?
av_rescale_q(duration, avctx->time_base, (AVRational){1,100}) : -1;

ret = ff_ass_add_rect_bprint(sub, &new_line, ts_start, ts_duration);
int ret = ff_ass_fill_text_sub(data, &new_line, avpkt, 0, NULL, NULL);
av_bprint_finalize(&new_line, NULL);
if (ret < 0)
return ret;
}

*got_sub_ptr = sub->num_rects > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

@@ -58,8 +58,7 @@ static int mov_text_init(AVCodecContext *avctx) {
static int mov_text_decode_frame(AVCodecContext *avctx,
void *data, int *got_sub_ptr, AVPacket *avpkt)
{
AVSubtitle *sub = data;
int ret, ts_start, ts_end;
int ret;
AVBPrint buf;
const char *ptr = avpkt->data;
const char *end;
@@ -85,21 +84,14 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
end = ptr + FFMIN(2 + AV_RB16(ptr), avpkt->size);
ptr += 2;

ts_start = av_rescale_q(avpkt->pts,
avctx->time_base,
(AVRational){1,100});
ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
avctx->time_base,
(AVRational){1,100});

// Note that the spec recommends lines be no longer than 2048 characters.
av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
text_to_ass(&buf, ptr, end);
ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_end-ts_start);
ret = ff_ass_fill_text_sub(data, &buf, avpkt, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
*got_sub_ptr = sub->num_rects > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

@@ -67,19 +67,15 @@ static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
{
int ret = 0;
AVBPrint buf;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
const int ts_duration = avpkt->duration != -1 ?
av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
if (ptr && avpkt->size > 0 && *ptr && !mpl2_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
ret = ff_ass_fill_text_sub(data, &buf, avpkt, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
*got_sub_ptr = sub->num_rects > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

@@ -59,19 +59,16 @@ static int realtext_decode_frame(AVCodecContext *avctx,
void *data, int *got_sub_ptr, AVPacket *avpkt)
{
int ret = 0;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
AVBPrint buf;

av_bprint_init(&buf, 0, 4096);
// note: no need to rescale pts & duration since they are in the same
// timebase as ASS (1/100)
if (ptr && avpkt->size > 0 && !rt_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration);
ret = ff_ass_fill_text_sub(data, &buf, avpkt, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
*got_sub_ptr = sub->num_rects > 0;
*got_sub_ptr = 1;
return avpkt->size;
}

0 comments on commit a73a19c

Please sign in to comment.