summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2019-12-10 16:27:23 -0800
committerJohn Stebbins <[email protected]>2020-03-29 08:23:20 -0600
commit494a548865e20767076f2caaa4f23522ee750687 (patch)
tree536bea5373e6c2c4180e85c60b30f4db8a682697 /libhb
parent400e8d4784d67978061c059abf5cbe23b0271009 (diff)
decavsub: use libav to decode EIA 608 subtitles
simplifies code, eliminates deccc608sub.c
Diffstat (limited to 'libhb')
-rw-r--r--libhb/decavcodec.c50
-rw-r--r--libhb/decavsub.c47
-rw-r--r--libhb/deccc608sub.c1867
-rw-r--r--libhb/handbrake/common.h1
-rw-r--r--libhb/handbrake/internal.h1
-rw-r--r--libhb/hb.c1
-rw-r--r--libhb/stream.c11
7 files changed, 63 insertions, 1915 deletions
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index a0e4a2e26..97958fa09 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -935,39 +935,9 @@ static void cc_send_to_decoder(hb_work_private_t *pv, hb_buffer_t *buf)
static hb_buffer_t * cc_fill_buffer(hb_work_private_t *pv, uint8_t *cc, int size)
{
- int cc_count[4] = {0,};
- int ii;
- hb_buffer_t *buf = NULL;
+ hb_buffer_t * buf = hb_buffer_init(size);
- for (ii = 0; ii < size; ii += 3)
- {
- if ((cc[ii] & 0x04) == 0) // not valid
- continue;
- if ((cc[ii+1] & 0x7f) == 0 && (cc[ii+2] & 0x7f) == 0) // stuffing
- continue;
- int type = cc[ii] & 0x03;
- cc_count[type]++;
- }
-
- // Only handles CC1 for now.
- if (cc_count[0] > 0)
- {
- buf = hb_buffer_init(cc_count[0] * 2);
- int jj = 0;
- for (ii = 0; ii < size; ii += 3)
- {
- if ((cc[ii] & 0x04) == 0) // not valid
- continue;
- if ((cc[ii+1] & 0x7f) == 0 && (cc[ii+2] & 0x7f) == 0) // stuffing
- continue;
- int type = cc[ii] & 0x03;
- if (type == 0)
- {
- buf->data[jj++] = cc[ii+1];
- buf->data[jj++] = cc[ii+2];
- }
- }
- }
+ memcpy(buf->data, cc, size);
return buf;
}
@@ -1074,12 +1044,15 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv )
subtitle = calloc(sizeof( hb_subtitle_t ), 1);
subtitle->track = hb_list_count(pv->title->list_subtitle);
- subtitle->id = HB_SUBTITLE_EMBEDDED_CC_TAG;
- subtitle->format = TEXTSUB;
- subtitle->source = CC608SUB;
- subtitle->config.dest = PASSTHRUSUB;
- subtitle->codec = WORK_DECCC608;
- subtitle->attributes = HB_SUBTITLE_ATTR_CC;
+ subtitle->id = HB_SUBTITLE_EMBEDDED_CC_TAG;
+ subtitle->format = TEXTSUB;
+ subtitle->source = CC608SUB;
+ subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECAVSUB;
+ subtitle->codec_param = AV_CODEC_ID_EIA_608;
+ subtitle->attributes = HB_SUBTITLE_ATTR_CC;
+ subtitle->timebase.num = 1;
+ subtitle->timebase.den = 90000;
/*
* The language of the subtitles will be the same as the
@@ -1110,6 +1083,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv )
if (cc_buf != NULL)
{
cc_buf->s.start = out->s.start;
+ cc_buf->s.duration = (int64_t)AV_NOPTS_VALUE;
cc_buf->s.scr_sequence = out->s.scr_sequence;
}
cc_send_to_decoder(pv, cc_buf);
diff --git a/libhb/decavsub.c b/libhb/decavsub.c
index 3e57e8b69..71baaf3a3 100644
--- a/libhb/decavsub.c
+++ b/libhb/decavsub.c
@@ -65,6 +65,10 @@ hb_avsub_context_t * decavsubInit( hb_work_object_t * w, hb_job_t * job )
// Set decoder opts...
AVDictionary * av_opts = NULL;
av_dict_set( &av_opts, "sub_text_format", "ass", 0 );
+ if (ctx->subtitle->source == CC608SUB)
+ {
+ av_dict_set( &av_opts, "real_time", "1", 0 );
+ }
if (hb_avcodec_open(ctx->context, codec, &av_opts, 0))
{
@@ -90,7 +94,7 @@ hb_avsub_context_t * decavsubInit( hb_work_object_t * w, hb_job_t * job )
{
// Mono font for CC
hb_subtitle_add_ssa_header(ctx->subtitle, HB_FONT_MONO,
- .066 * job->title->geometry.height, width, height);
+ 30, 384, 288);
} break;
default:
@@ -223,6 +227,24 @@ static void make_empty_sub( int source, hb_buffer_list_t * list_pass )
}
}
+// Returns a pointer to the first character after the ASS preamble
+static const char * ssa_text(const char * ssa)
+{
+ int ii;
+ const char * text = ssa;
+
+ if (ssa == NULL)
+ return NULL;
+ for (ii = 0; ii < 8; ii++)
+ {
+ text = strchr(text, ',');
+ if (text == NULL)
+ break;
+ text++;
+ }
+ return text;
+}
+
int decavsubWork( hb_avsub_context_t * ctx,
hb_buffer_t ** buf_in,
hb_buffer_t ** buf_out )
@@ -291,6 +313,11 @@ int decavsubWork( hb_avsub_context_t * ctx,
{
usedBytes++;
}
+ // Another ugly hack, ffmpeg always returns 0 for CC decoder :(
+ if (ctx->subtitle->source == CC608SUB)
+ {
+ usedBytes = avp.size;
+ }
if (usedBytes <= avp.size)
{
avp.data += usedBytes;
@@ -424,11 +451,23 @@ int decavsubWork( hb_avsub_context_t * ctx,
// Text subtitles are treated the same regardless of
// whether we are burning or passing through. They
// get translated to SSA
- if (!clear_sub && subtitle.rects[0]->ass != NULL)
+ //
+ // When using the "real_time" option with CC608 subtitles,
+ // ffmpeg prepends an ASS rect that has only the preample
+ // to every list of returned rects. libass doesn't like this
+ // and logs a warning for every one of these. So strip these
+ // out by using only the last rect in the list.
+ //
+ // Also, when a CC needs to be removed from the screen, ffmpeg
+ // emits a single rect with only the preamble. Detect this
+ // and flag an "End Of Subtitle" EOS.
+ int ii = subtitle.num_rects - 1;
+ const char * text = ssa_text(subtitle.rects[ii]->ass);
+ if (!clear_sub && text != NULL && *text != 0)
{
- int size = strlen(subtitle.rects[0]->ass) + 1;
+ int size = strlen(subtitle.rects[ii]->ass) + 1;
out = hb_buffer_init(size);
- strcpy((char*)out->data, subtitle.rects[0]->ass);
+ strcpy((char*)out->data, subtitle.rects[ii]->ass);
}
else
{
diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c
deleted file mode 100644
index 3bbbce1e2..000000000
--- a/libhb/deccc608sub.c
+++ /dev/null
@@ -1,1867 +0,0 @@
-/* deccc608sub.c
-
- Copyright (c) 2003-2020 HandBrake Team
- This file is part of the HandBrake source code
- Homepage: <http://handbrake.fr/>.
- It may be used under the terms of the GNU General Public License v2.
- For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
- */
-
-/*
- * From ccextractor, leave this file as intact and close to the original as possible so that
- * it is easy to patch in fixes - even though this file contains code that we don't need.
- *
- * Note that the SRT sub generation from CC could be useful for mkv subs.
- */
-#include "handbrake/handbrake.h"
-#include "handbrake/deccc608sub.h"
-
-#define SSA_PREAMBLE_LEN 24
-/*
- * ccextractor static configuration variables.
- */
-static int debug_608 = 0;
-static int cc_channel = 1;
-static int subs_delay = 0;
-
-int rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
-// Relationship between the first PAC byte and the row number
-
-// The following enc_buffer is not used at the moment, if it does get used
-// we need to bring it into the swrite struct. Same for "str".
-#define INITIAL_ENC_BUFFER_CAPACITY 2048
-
-static const unsigned char pac2_attribs[][3]= // Color, font, ident
-{
- {COL_WHITE, FONT_REGULAR, 0}, // 0x40 || 0x60
- {COL_WHITE, FONT_UNDERLINED, 0}, // 0x41 || 0x61
- {COL_GREEN, FONT_REGULAR, 0}, // 0x42 || 0x62
- {COL_GREEN, FONT_UNDERLINED, 0}, // 0x43 || 0x63
- {COL_BLUE, FONT_REGULAR, 0}, // 0x44 || 0x64
- {COL_BLUE, FONT_UNDERLINED, 0}, // 0x45 || 0x65
- {COL_CYAN, FONT_REGULAR, 0}, // 0x46 || 0x66
- {COL_CYAN, FONT_UNDERLINED, 0}, // 0x47 || 0x67
- {COL_RED, FONT_REGULAR, 0}, // 0x48 || 0x68
- {COL_RED, FONT_UNDERLINED, 0}, // 0x49 || 0x69
- {COL_YELLOW, FONT_REGULAR, 0}, // 0x4a || 0x6a
- {COL_YELLOW, FONT_UNDERLINED, 0}, // 0x4b || 0x6b
- {COL_MAGENTA, FONT_REGULAR, 0}, // 0x4c || 0x6c
- {COL_MAGENTA, FONT_UNDERLINED, 0}, // 0x4d || 0x6d
- {COL_WHITE, FONT_ITALICS, 0}, // 0x4e || 0x6e
- {COL_WHITE, FONT_UNDERLINED_ITALICS, 0}, // 0x4f || 0x6f
- {COL_WHITE, FONT_REGULAR, 0}, // 0x50 || 0x70
- {COL_WHITE, FONT_UNDERLINED, 0}, // 0x51 || 0x71
- {COL_WHITE, FONT_REGULAR, 4}, // 0x52 || 0x72
- {COL_WHITE, FONT_UNDERLINED, 4}, // 0x53 || 0x73
- {COL_WHITE, FONT_REGULAR, 8}, // 0x54 || 0x74
- {COL_WHITE, FONT_UNDERLINED, 8}, // 0x55 || 0x75
- {COL_WHITE, FONT_REGULAR, 12}, // 0x56 || 0x76
- {COL_WHITE, FONT_UNDERLINED, 12}, // 0x57 || 0x77
- {COL_WHITE, FONT_REGULAR, 16}, // 0x58 || 0x78
- {COL_WHITE, FONT_UNDERLINED, 16}, // 0x59 || 0x79
- {COL_WHITE, FONT_REGULAR, 20}, // 0x5a || 0x7a
- {COL_WHITE, FONT_UNDERLINED, 20}, // 0x5b || 0x7b
- {COL_WHITE, FONT_REGULAR, 24}, // 0x5c || 0x7c
- {COL_WHITE, FONT_UNDERLINED, 24}, // 0x5d || 0x7d
- {COL_WHITE, FONT_REGULAR, 28}, // 0x5e || 0x7e
- {COL_WHITE, FONT_UNDERLINED, 28} // 0x5f || 0x7f
-};
-
-// Default color
-static enum color_code default_color=COL_WHITE;
-
-static const char *command_type[] =
-{
- "Unknown",
- "EDM - EraseDisplayedMemory",
- "RCL - ResumeCaptionLoading",
- "EOC - End Of Caption",
- "TO1 - Tab Offset, 1 column",
- "TO2 - Tab Offset, 2 column",
- "TO3 - Tab Offset, 3 column",
- "RU2 - Roll up 2 rows",
- "RU3 - Roll up 3 rows",
- "RU4 - Roll up 4 rows",
- "CR - Carriage Return",
- "ENM - Erase non-displayed memory",
- "BS - Backspace",
- "RTD - Resume Text Display"
-};
-
-static const char *font_text[]=
-{
- "regular",
- "italics",
- "underlined",
- "underlined italics"
-};
-
-static const char *color_text[][2]=
-{
- {"white", "&HFFFFFF&"},
- {"green", "&H00FF00&"},
- {"blue", "&HFF0000&"},
- {"cyan", "&HFFFF00&"},
- {"red", "&H0000FF&"},
- {"yellow", "&H00FFFF&"},
- {"magenta", "&HFF00FF&"},
- {"userdefined", "&HFFFFFF&"}
-};
-
-static int general_608_init (struct s_write *wb)
-{
- if( !wb->enc_buffer )
- {
- wb->enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY);
- if (wb->enc_buffer==NULL)
- return -1;
- wb->enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
- }
-
- if( !wb->subline) {
- wb->subline = malloc(2048);
-
- if (!wb->subline)
- {
- return -1;
- }
- }
-
- wb->new_sentence = 1;
- wb->new_channel = 1;
- wb->in_xds_mode = 0;
-
- hb_buffer_list_clear(&wb->list);
- wb->last_pts = 0;
- wb->last_scr_sequence = 0;
- return 0;
-}
-
-/*
- * Free up CC memory - don't call this from HB just yet since it will cause
- * parallel encodes to fail - to be honest they will be stuffed anyway since
- * the CC's may be overwriting the buffers.
- */
-static void general_608_close (struct s_write *wb)
-{
- if( wb->enc_buffer ) {
- free(wb->enc_buffer);
- wb->enc_buffer_capacity = 0;
- wb->enc_buffer_used = 0;
- }
- if( wb->subline ) {
- free(wb->subline);
- }
- hb_buffer_list_close(&wb->list);
-}
-
-
-#include <ctype.h>
-
-// Returns number of bytes used
-static int get_char_in_utf8(unsigned char *buffer, unsigned char c)
-{
- if (c == 0x00)
- return 0;
-
- // Regular line-21 character set, mostly ASCII except these exceptions
- if (c < 0x80)
- {
- switch (c)
- {
- case 0x2a: // lowercase a, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0xa1;
- return 2;
- case 0x5c: // lowercase e, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0xa9;
- return 2;
- case 0x5e: // lowercase i, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0xad;
- return 2;
- case 0x5f: // lowercase o, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0xb3;
- return 2;
- case 0x60: // lowercase u, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0xba;
- return 2;
- case 0x7b: // lowercase c with cedilla
- *buffer = 0xc3;
- *(buffer+1) = 0xa7;
- return 2;
- case 0x7c: // division symbol
- *buffer = 0xc3;
- *(buffer+1) = 0xb7;
- return 2;
- case 0x7d: // uppercase N tilde
- *buffer = 0xc3;
- *(buffer+1) = 0x91;
- return 2;
- case 0x7e: // lowercase n tilde
- *buffer = 0xc3;
- *(buffer+1) = 0xb1;
- return 2;
- default:
- *buffer = c;
- return 1;
- }
- }
- switch (c)
- {
- // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
- // THAT COME FROM HI BYTE = 0x11 AND LOW BETWEEN 0x30 AND 0x3F
- case 0x80: // Registered symbol (R)
- *buffer = 0xc2;
- *(buffer+1) = 0xae;
- return 2;
- case 0x81: // degree sign
- *buffer = 0xc2;
- *(buffer+1) = 0xb0;
- return 2;
- case 0x82: // 1/2 symbol
- *buffer = 0xc2;
- *(buffer+1) = 0xbd;
- return 2;
- case 0x83: // Inverted (open) question mark
- *buffer = 0xc2;
- *(buffer+1) = 0xbf;
- return 2;
- case 0x84: // Trademark symbol (TM)
- *buffer = 0xe2;
- *(buffer+1) = 0x84;
- *(buffer+2) = 0xa2;
- return 3;
- case 0x85: // Cents symbol
- *buffer = 0xc2;
- *(buffer+1) = 0xa2;
- return 2;
- case 0x86: // Pounds sterling
- *buffer = 0xc2;
- *(buffer+1) = 0xa3;
- return 2;
- case 0x87: // Music note
- *buffer = 0xe2;
- *(buffer+1) = 0x99;
- *(buffer+2) = 0xaa;
- return 3;
- case 0x88: // lowercase a, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0xa0;
- return 2;
- case 0x89: // transparent space, we make it regular
- *buffer = 0x20;
- return 1;
- case 0x8a: // lowercase e, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0xa8;
- return 2;
- case 0x8b: // lowercase a, circumflex accent
- *buffer = 0xc3;
- *(buffer+1) = 0xa2;
- return 2;
- case 0x8c: // lowercase e, circumflex accent
- *buffer = 0xc3;
- *(buffer+1) = 0xaa;
- return 2;
- case 0x8d: // lowercase i, circumflex accent
- *buffer = 0xc3;
- *(buffer+1) = 0xae;
- return 2;
- case 0x8e: // lowercase o, circumflex accent
- *buffer = 0xc3;
- *(buffer+1) = 0xb4;
- return 2;
- case 0x8f: // lowercase u, circumflex accent
- *buffer = 0xc3;
- *(buffer+1) = 0xbb;
- return 2;
- // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
- // THAT COME FROM HI BYTE = 0x12 AND LOW BETWEEN 0x20 AND 0x3F
- case 0x90: // capital letter A with acute
- *buffer = 0xc3;
- *(buffer+1) = 0x81;
- return 2;
- case 0x91: // capital letter E with acute
- *buffer = 0xc3;
- *(buffer+1) = 0x89;
- return 2;
- case 0x92: // capital letter O with acute
- *buffer = 0xc3;
- *(buffer+1) = 0x93;
- return 2;
- case 0x93: // capital letter U with acute
- *buffer = 0xc3;
- *(buffer+1) = 0x9a;
- return 2;
- case 0x94: // capital letter U with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0x9c;
- return 2;
- case 0x95: // lowercase letter U with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0xbc;
- return 2;
- case 0x96: // apostrophe
- *buffer = 0x27;
- return 1;
- case 0x97: // inverted exclamation mark
- *buffer = 0xc2;
- *(buffer+1) = 0xa1;
- return 2;
- case 0x98: // asterisk
- *buffer = 0x2a;
- return 1;
- case 0x99: // apostrophe (yes, duped). See CCADI source code.
- *buffer = 0x27;
- return 1;
- case 0x9a: // hyphen-minus
- *buffer = 0x2d;
- return 1;
- case 0x9b: // copyright sign
- *buffer = 0xc2;
- *(buffer+1) = 0xa9;
- return 2;
- case 0x9c: // Service mark
- *buffer = 0xe2;
- *(buffer+1) = 0x84;
- *(buffer+2) = 0xa0;
- return 3;
- case 0x9d: // Full stop (.)
- *buffer = 0x2e;
- return 1;
- case 0x9e: // Quotation mark
- *buffer = 0x22;
- return 1;
- case 0x9f: // Quotation mark
- *buffer = 0x22;
- return 1;
- case 0xa0: // uppercase A, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0x80;
- return 2;
- case 0xa1: // uppercase A, circumflex
- *buffer = 0xc3;
- *(buffer+1) = 0x82;
- return 2;
- case 0xa2: // uppercase C with cedilla
- *buffer = 0xc3;
- *(buffer+1) = 0x87;
- return 2;
- case 0xa3: // uppercase E, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0x88;
- return 2;
- case 0xa4: // uppercase E, circumflex
- *buffer = 0xc3;
- *(buffer+1) = 0x8a;
- return 2;
- case 0xa5: // capital letter E with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0x8b;
- return 2;
- case 0xa6: // lowercase letter e with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0xab;
- return 2;
- case 0xa7: // uppercase I, circumflex
- *buffer = 0xc3;
- *(buffer+1) = 0x8e;
- return 2;
- case 0xa8: // uppercase I, with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0x8f;
- return 2;
- case 0xa9: // lowercase i, with diaeresis
- *buffer = 0xc3;
- *(buffer+1) = 0xaf;
- return 2;
- case 0xaa: // uppercase O, circumflex
- *buffer = 0xc3;
- *(buffer+1) = 0x94;
- return 2;
- case 0xab: // uppercase U, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0x99;
- return 2;
- case 0xac: // lowercase u, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0xb9;
- return 2;
- case 0xad: // uppercase U, circumflex
- *buffer = 0xc3;
- *(buffer+1) = 0x9b;
- return 2;
- case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
- *buffer = 0xc2;
- *(buffer+1) = 0xab;
- return 2;
- case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- *buffer = 0xc2;
- *(buffer+1) = 0xbb;
- return 2;
- // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
- // THAT COME FROM HI BYTE = 0x13 AND LOW BETWEEN 0x20 AND 0x3F
- case 0xb0: // Uppercase A, tilde
- *buffer = 0xc3;
- *(buffer+1) = 0x83;
- return 2;
- case 0xb1: // Lowercase a, tilde
- *buffer = 0xc3;
- *(buffer+1) = 0xa3;
- return 2;
- case 0xb2: // Uppercase I, acute accent
- *buffer = 0xc3;
- *(buffer+1) = 0x8d;
- return 2;
- case 0xb3: // Uppercase I, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0x8c;
- return 2;
- case 0xb4: // Lowercase i, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0xac;
- return 2;
- case 0xb5: // Uppercase O, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0x92;
- return 2;
- case 0xb6: // Lowercase o, grave accent
- *buffer = 0xc3;
- *(buffer+1) = 0xb2;
- return 2;
- case 0xb7: // Uppercase O, tilde
- *buffer = 0xc3;
- *(buffer+1) = 0x95;
- return 2;
- case 0xb8: // Lowercase o, tilde
- *buffer = 0xc3;
- *(buffer+1) = 0xb5;
- return 2;
- case 0xb9: // Open curly brace
- *buffer = 0x7b;
- return 1;
- case 0xba: // Closing curly brace
- *buffer = 0x7d;
- return 1;
- case 0xbb: // Backslash
- *buffer = 0x5c;
- return 1;
- case 0xbc: // Caret
- *buffer = 0x5e;
- return 1;
- case 0xbd: // Underscore
- *buffer = 0x5f;
- return 1;
- case 0xbe: // Pipe (broken bar)
- *buffer = 0xc2;
- *(buffer+1) = 0xa6;
- return 1;
- case 0xbf: // Tilde
- *buffer = 0x7e; // Not sure
- return 1;
- case 0xc0: // Uppercase A, umlaut
- *buffer = 0xc3;
- *(buffer+1) = 0x84;
- return 2;
- case 0xc1: // Lowercase A, umlaut
- *buffer = 0xc3;
- *(buffer+1) = 0xa4;
- return 2;
- case 0xc2: // Uppercase O, umlaut
- *buffer = 0xc3;
- *(buffer+1) = 0x96;
- return 2;
- case 0xc3: // Lowercase o, umlaut
- *buffer = 0xc3;
- *(buffer+1) = 0xb6;
- return 2;
- case 0xc4: // Esszett (sharp S)
- *buffer = 0xc3;
- *(buffer+1) = 0x9f;
- return 2;
- case 0xc5: // Yen symbol
- *buffer = 0xc2;
- *(buffer+1) = 0xa5;
- return 2;
- case 0xc6: // Currency symbol
- *buffer = 0xc2;
- *(buffer+1) = 0xa4;
- return 2;
- case 0xc7: // Vertical bar
- *buffer = 0x7c;
- return 1;
- case 0xc8: // Uppercase A, ring
- *buffer = 0xc3;
- *(buffer+1) = 0x85;
- return 2;
- case 0xc9: // Lowercase A, ring
- *buffer = 0xc3;
- *(buffer+1) = 0xa5;
- return 2;
- case 0xca: // Uppercase O, slash
- *buffer = 0xc3;
- *(buffer+1) = 0x98;
- return 2;
- case 0xcb: // Lowercase o, slash
- *buffer = 0xc3;
- *(buffer+1) = 0xb8;
- return 2;
- case 0xcc: // Upper left corner
- *buffer = 0xe2;
- *(buffer+1) = 0x8c;
- *(buffer+2) = 0x9c;
- return 3;
- case 0xcd: // Upper right corner
- *buffer = 0xe2;
- *(buffer+1) = 0x8c;
- *(buffer+2) = 0x9d;
- return 3;
- case 0xce: // Lower left corner
- *buffer = 0xe2;
- *(buffer+1) = 0x8c;
- *(buffer+2) = 0x9e;
- return 3;
- case 0xcf: // Lower right corner
- *buffer = 0xe2;
- *(buffer+1) = 0x8c;
- *(buffer+2) = 0x9f;
- return 3;
- default: //
- *buffer = '?'; // I'll do it eventually, I promise
- return 1; // This are weird chars anyway
- }
-}
-
-// Encodes a generic string. Note that since we use the encoders for closed
-// caption data, text would have to be encoded as CCs... so using special
-// characters here it's a bad idea.
-static unsigned encode_line(unsigned char *buffer, unsigned char *text)
-{
- unsigned bytes = 0;
- while (*text)
- {
- *buffer++ = *text++;
- bytes++;
- }
- return bytes;
-}
-
-static unsigned stuff_space(unsigned char *buffer, int space)
-{
- int ii;
- for (ii = 0; ii < space; ii++)
- {
- *buffer++ = '\\';
- *buffer++ = 'h';
- }
- return space * 2;
-}
-
-static void find_limit_characters(unsigned char *line, int *first_non_blank,
- int *last_non_blank)
-{
- int i;
-
- *last_non_blank = -1;
- *first_non_blank = -1;
- for (i = 0; i < CC608_SCREEN_WIDTH; i++)
- {
- unsigned char c = line[i];
- if (c != ' ' && c != 0x89)
- {
- if (*first_non_blank == -1)
- *first_non_blank = i;
- *last_non_blank = i;
- }
- }
-}
-
-static unsigned get_decoder_line_encoded(struct s_write *wb,
- unsigned char *buffer, int line_num,
- struct eia608_screen *data)
-{
- uint8_t font_style;
- uint8_t font_color;
- int i;
-
- unsigned char *line = data->characters[line_num];
- unsigned char *orig = buffer; // Keep for debugging
- int first = 0, last = 31;
-
- find_limit_characters(line, &first, &last);
- for (i = first; i <= last; i++)
- {
- // Handle color
- font_color = data->colors[line_num][i];
- font_style = data->fonts[line_num][i];
-
- // Handle reset to defaults
- if ((font_style & FONT_STYLE_MASK) == 0 && font_color == COL_WHITE)
- {
- if (((font_style ^ wb->prev_font_style) & FONT_STYLE_MASK) ||
- (font_color != wb->prev_font_color))
- {
- buffer += encode_line(buffer, (uint8_t*)"{\\r}");
- }
- }
- else
- {
- // Open markup
- if (((font_style ^ wb->prev_font_style) & FONT_STYLE_MASK) ||
- (font_color != wb->prev_font_color))
- {
- // style changed
- buffer += encode_line(buffer, (uint8_t*)"{");
- }
-
- // Handle underlined
- if ((font_style ^ wb->prev_font_style) & FONT_UNDERLINED)
- {
- int enable = !!(font_style & FONT_UNDERLINED);
- buffer += encode_line(buffer, (uint8_t*)"\\u");
- *buffer++ = enable + 0x30;
- }
-
- // Handle italics
- if ((font_style ^ wb->prev_font_style) & FONT_ITALICS)
- {
- int enable = !!(font_style & FONT_ITALICS);
- buffer += encode_line(buffer, (uint8_t*)"\\i");
- *buffer++ = enable + 0x30;
- }
-
- // Handle color
- if (font_color != wb->prev_font_color)
- {
- buffer += encode_line(buffer, (uint8_t*)"\\1c");
- buffer += encode_line(buffer,
- (uint8_t*)color_text[font_color][1]);
- }
-
- // Close markup
- if (((font_style ^ wb->prev_font_style) & FONT_STYLE_MASK) ||
- (font_color != wb->prev_font_color))
- {
- // style changed
- buffer += encode_line(buffer, (uint8_t*)"}");
- }
- }
- wb->prev_font_style = font_style;
- wb->prev_font_color = font_color;
-
- int bytes = 0;
- bytes = get_char_in_utf8(buffer, line[i]);
- buffer += bytes;
- }
- *buffer = 0;
- return (unsigned) (buffer - orig); // Return length
-}
-
-
-static void clear_eia608_cc_buffer (struct eia608_screen *data)
-{
- int i;
-
- for (i=0;i<15;i++)
- {
- memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
- data->characters[i][CC608_SCREEN_WIDTH]=0;
- memset (data->colors[i],default_color,CC608_SCREEN_WIDTH+1);
- memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1);
- data->row_used[i]=0;
- }
- data->empty=1;
-}
-
-static void init_eia608 (struct eia608 *data)
-{
- data->cursor_column = 0;
- data->cursor_row = 0;
- clear_eia608_cc_buffer (&data->buffer1);
- clear_eia608_cc_buffer (&data->buffer2);
- data->visible_buffer = 1;
- data->last_c1 = 0;
- data->last_c2 = 0;
- data->mode = MODE_POPUP;
- data->current_visible_start_ms = 0;
- data->ssa_counter = 0;
- data->screenfuls_counter = 0;
- data->channel = 1;
- data->color = default_color;
- data->font = FONT_REGULAR;
- data->rollup_base_row = 14;
-}
-
-static struct eia608_screen *get_current_hidden_buffer(struct s_write *wb)
-{
- struct eia608_screen *data;
- if (wb->data608->visible_buffer == 1)
- data = &wb->data608->buffer2;
- else
- data = &wb->data608->buffer1;
- return data;
-}
-
-static struct eia608_screen *get_current_visible_buffer(struct s_write *wb)
-{
- struct eia608_screen *data;
- if (wb->data608->visible_buffer == 1)
- data = &wb->data608->buffer1;
- else
- data = &wb->data608->buffer2;
- return data;
-}
-
-static void swap_visible_buffer(struct s_write *wb)
-{
- wb->data608->visible_buffer = (wb->data608->visible_buffer == 1) ? 2 : 1;
-}
-
-static struct eia608_screen *get_writing_buffer(struct s_write *wb)
-{
- struct eia608_screen *use_buffer=NULL;
- switch (wb->data608->mode)
- {
- case MODE_POPUP: // Write on the non-visible buffer
- use_buffer = get_current_hidden_buffer(wb);
- break;
- case MODE_ROLLUP_2: // Write directly to screen
- case MODE_ROLLUP_3:
- case MODE_ROLLUP_4:
- case MODE_TEXT:
- use_buffer = get_current_visible_buffer(wb);
- break;
- default:
- hb_error("Caption mode has an illegal value at get_writing_buffer(), this is a bug.");
- }
- return use_buffer;
-}
-
-static void write_char(const unsigned char c, struct s_write *wb)
-{
- if (wb->data608->mode != MODE_TEXT)
- {
- struct eia608_screen * use_buffer = get_writing_buffer(wb);
- if (use_buffer != NULL)
- {
- /* hb_log ("\rWriting char [%c] at %s:%d:%d\n",c,
- use_buffer == &wb->data608->buffer1?"B1":"B2",
- wb->data608->cursor_row,wb->data608->cursor_column); */
- use_buffer->characters[wb->data608->cursor_row][wb->data608->cursor_column] = c;
- use_buffer->colors[wb->data608->cursor_row][wb->data608->cursor_column] = wb->data608->color;
- use_buffer->fonts[wb->data608->cursor_row][wb->data608->cursor_column] = wb->data608->font;
- use_buffer->row_used[wb->data608->cursor_row] = 1;
- use_buffer->empty = 0;
- if (wb->data608->cursor_column < 31)
- wb->data608->cursor_column++;
- use_buffer->dirty = 1;
- }
- }
-
-}
-
-/* Handle MID-ROW CODES. */
-static void handle_text_attr(const unsigned char c1, const unsigned char c2,
- struct s_write *wb)
-{
- // Handle channel change
- wb->data608->channel=wb->new_channel;
- if (wb->data608->channel!=cc_channel)
- return;
- if (debug_608)
- hb_log ("\r608: text_attr: %02X %02X",c1,c2);
- if ( ((c1!=0x11 && c1!=0x19) ||
- (c2<0x20 || c2>0x2f)) && debug_608)
- {
- hb_log ("\rThis is not a text attribute!\n");
- }
- else
- {
- int i = c2-0x20;
- wb->data608->color=pac2_attribs[i][0];
- wb->data608->font=pac2_attribs[i][1];
- if (debug_608)
- hb_log(" -- Color: %s, font: %s\n",
- color_text[wb->data608->color][0],
- font_text[wb->data608->font]);
- if (wb->data608->cursor_column<31)
- wb->data608->cursor_column++;
- }
-}
-
-static int write_cc_buffer_as_ssa(struct eia608_screen *data,
- struct s_write *wb)
-{
- int wrote_something = 0;
- int i;
- int64_t ms_start = wb->data608->current_visible_start_ms;
- //int64_t ms_end = wb->last_pts + subs_delay;
-
- ms_start += subs_delay;
- if (ms_start<0) // Drop screens that because of subs_delay start too early
- return 0;
-
- if (debug_608)
- {
- char timeline[128];
- wb->data608->ssa_counter++;
- sprintf (timeline,"%u\r\n",wb->data608->ssa_counter);
-
- hb_log ("\n- - - SSA caption - - -\n");
- hb_log ("%s", timeline);
- }
-
- /*
- * Write all the lines into enc_buffer, and then write that out at the end
- * ensure that we only have two lines, insert a newline after the first one,
- * and have a big bottom line (strip spaces from any joined lines).
- */
- int rows = 0, columns = 0;
- int min_row = 15, max_row = 0;
- int min_col = 41, max_col = 0;
- for (i = 0; i < 15; i++)
- {
- if (data->row_used[i])
- {
- int first, last;
-
- rows++;
- find_limit_characters(data->characters[i], &first, &last);
- if (last - first + 1 > columns)
- columns = last - first + 1;
- if (min_col > first)
- min_col = first;
- if (min_row > i)
- min_row = i;
- if (max_col < last)
- max_col = last;
- if (max_row < i)
- max_row = i;
- }
- }
-
- wb->prev_font_style = FONT_REGULAR;
- wb->prev_font_color = COL_WHITE;
- wb->enc_buffer_used = 0;
-
- int cropped_width, cropped_height, font_size;
- int cell_width, cell_height;
- int safe_x, safe_y;
- int min_safe_x, min_safe_y;
- double aspect;
-
- cropped_height = wb->height - wb->crop[0] - wb->crop[1];
- cropped_width = wb->width - wb->crop[2] - wb->crop[3];
- aspect = (double)wb->width * wb->par.num /
- (wb->height * wb->par.den);
-
- // CC grid is 16 rows by 32 columns (for 4:3 video)
- // Our SSA resolution is the title resolution
- // Translate CC grid to SSA coordinates
- // The numbers are tweaked to keep things off the very
- // edges of the screen and in the "safe" zone
- int screen_columns = 32;
- if (aspect >= 1.6)
- {
- // If the display aspect is close to or greater than 16:9
- // then width of screen is 42 columns (see CEA-708)
- screen_columns = 42;
- }
- font_size = wb->height * .8 * .08;
-
- safe_x = 0.1 * wb->width;
- safe_y = 0.1 * wb->height;
- min_safe_x = 0.025 * cropped_width;
- min_safe_y = 0.025 * cropped_height;
- cell_height = (wb->height - 2 * safe_y) / 16;
- cell_width = (wb->width - 2 * safe_x) / screen_columns;
-
- char *pos;
- int y, x, top;
- int col = min_col;
- if (aspect >= 1.6)
- {
- // If the display aspect is close to or greater than 16:9
- // center the CC in about a 4:3 region
- col += 5;
- }
- y = cell_height * (min_row + 1 + rows) + safe_y - wb->crop[0];
- x = cell_width * col + safe_x - wb->crop[2];
- top = y - rows * font_size;
-
- if (top < min_safe_y)
- y = (rows * font_size) + min_safe_y;
- if (y > cropped_height - min_safe_y)
- y = cropped_height - min_safe_y;
- if (x + columns * cell_width > cropped_width - min_safe_x)
- x = cropped_width - columns * cell_width - min_safe_x;
- if (x < min_safe_x)
- x = min_safe_x;
- pos = hb_strdup_printf("{\\an1\\pos(%d,%d)}", x, y);
-
- int line = 1;
- for (i = 0; i < 15; i++)
- {
- if (data->row_used[i])
- {
- int first, last;
- // Get position for this CC
- find_limit_characters(data->characters[i], &first, &last);
-
- /*
- * The intention was to use a newline but QT doesn't like it,
- * old code still here just in case..
- */
- int space = first - min_col;
- if (line == 1) {
- wb->enc_buffer_used += encode_line(
- wb->enc_buffer + wb->enc_buffer_used, (uint8_t*)pos);
- wb->enc_buffer_used += stuff_space(
- wb->enc_buffer + wb->enc_buffer_used, space);
- wb->enc_buffer_used += get_decoder_line_encoded(wb,
- wb->enc_buffer + wb->enc_buffer_used, i, data);
- line = 2;
- } else {
- wb->enc_buffer_used += encode_line(
- wb->enc_buffer + wb->enc_buffer_used, (uint8_t*)"\\N");
- wb->enc_buffer_used += stuff_space(
- wb->enc_buffer + wb->enc_buffer_used, space);
- wb->enc_buffer_used += get_decoder_line_encoded(wb,
- wb->enc_buffer + wb->enc_buffer_used, i, data);
- }
- }
- }
- free(pos);
- if (wb->enc_buffer_used && wb->enc_buffer[0] != 0 && data->dirty)
- {
- hb_buffer_t *buffer;
- int len;
-
- // bump past null terminator
- wb->enc_buffer_used++;
- buffer = hb_buffer_init(wb->enc_buffer_used + SSA_PREAMBLE_LEN);
- buffer->s.frametype = HB_FRAME_SUBTITLE;
- buffer->s.start = ms_start;
- buffer->s.stop = AV_NOPTS_VALUE;
- buffer->s.scr_sequence = wb->data608->current_visible_scr_sequence;
- sprintf((char*)buffer->data, "%d,,Default,,0,0,0,,", ++wb->line);
- len = strlen((char*)buffer->data);
- memcpy(buffer->data + len, wb->enc_buffer, wb->enc_buffer_used);
- hb_buffer_list_append(&wb->list, buffer);
- wrote_something=1;
- wb->clear_sub_needed = 1;
- }
- else if (wb->clear_sub_needed)
- {
- hb_buffer_t *buffer = hb_buffer_init(0);
- buffer->s.frametype = HB_FRAME_SUBTITLE;
- buffer->s.flags = HB_BUF_FLAG_EOS;
- buffer->s.start = ms_start;
- buffer->s.stop = ms_start;
- buffer->s.scr_sequence = wb->data608->current_visible_scr_sequence;
- hb_buffer_list_append(&wb->list, buffer);
- wb->clear_sub_needed = 0;
- }
- if (debug_608)
- {
- hb_log ("- - - - - - - - - - - -\r\n");
- }
- return wrote_something;
-}
-
-static int write_cc_buffer(struct s_write *wb)
-{
- struct eia608_screen *data;
- int wrote_something=0;
-
- data = get_current_visible_buffer(wb);
- if (!data->dirty)
- return 0;
- wb->new_sentence=1;
- wrote_something = write_cc_buffer_as_ssa(data, wb);
- data->dirty = 0;
- return wrote_something;
-}
-
-static void move_roll_up(struct s_write *wb, int row)
-{
- struct eia608_screen *use_buffer;
- int ii, src, dst, keep_lines;
-
- switch (wb->data608->mode)
- {
- case MODE_ROLLUP_2:
- keep_lines = 2;
- break;
- case MODE_ROLLUP_3:
- keep_lines = 3;
- break;
- case MODE_ROLLUP_4:
- keep_lines = 4;
- break;
- default:
- // Not rollup mode, nothing to do
- return;
- }
-
- if (row == wb->data608->rollup_base_row)
- {
- // base row didn't change, nothing to do
- return;
- }
-
- use_buffer = get_current_visible_buffer(wb);
- if (row < wb->data608->rollup_base_row)
- {
- src = wb->data608->rollup_base_row - keep_lines + 1;
- dst = row - keep_lines + 1;
- for (ii = 0; ii < keep_lines; ii++)
- {
- memcpy(use_buffer->characters[dst], use_buffer->characters[src], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->colors[dst], use_buffer->colors[src], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->fonts[dst], use_buffer->fonts[src], CC608_SCREEN_WIDTH+1);
- use_buffer->row_used[dst] = use_buffer->row_used[src];
-
- memset(use_buffer->characters[src], ' ', CC608_SCREEN_WIDTH);
- memset(use_buffer->colors[src], COL_WHITE, CC608_SCREEN_WIDTH);
- memset(use_buffer->fonts[src], FONT_REGULAR, CC608_SCREEN_WIDTH);
- use_buffer->characters[src][CC608_SCREEN_WIDTH] = 0;
- use_buffer->row_used[src] = 0;
-
- src++;
- dst++;
- }
- }
- else
- {
- src = wb->data608->rollup_base_row;
- dst = row;
- for (ii = 0; ii < keep_lines; ii++)
- {
- memcpy(use_buffer->characters[dst], use_buffer->characters[src], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->colors[dst], use_buffer->colors[src], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->fonts[dst], use_buffer->fonts[src], CC608_SCREEN_WIDTH+1);
- use_buffer->row_used[dst] = use_buffer->row_used[src];
-
- memset(use_buffer->characters[src], ' ', CC608_SCREEN_WIDTH);
- memset(use_buffer->colors[src], COL_WHITE, CC608_SCREEN_WIDTH);
- memset(use_buffer->fonts[src], FONT_REGULAR, CC608_SCREEN_WIDTH);
- use_buffer->characters[src][CC608_SCREEN_WIDTH] = 0;
- use_buffer->row_used[src] = 0;
-
- src--;
- dst--;
- }
- }
- use_buffer->dirty = 1;
-}
-
-static void roll_up(struct s_write *wb)
-{
- struct eia608_screen *use_buffer;
- int i, j;
-
- use_buffer = get_current_visible_buffer(wb);
- int keep_lines;
- switch (wb->data608->mode)
- {
- case MODE_ROLLUP_2:
- keep_lines = 2;
- break;
- case MODE_ROLLUP_3:
- keep_lines = 3;
- break;
- case MODE_ROLLUP_4:
- keep_lines = 4;
- break;
- default: // Shouldn't happen
- keep_lines = 0;
- break;
- }
- int firstrow = -1, lastrow = -1;
- // Look for the last line used
- int rows_now = 0; // Number of rows in use right now
- for (i = 0; i < 15; i++)
- {
- if (use_buffer->row_used[i])
- {
- rows_now++;
- if (firstrow == -1)
- firstrow = i;
- lastrow = i;
- }
- }
-
- if (debug_608)
- hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now, firstrow, lastrow);
-
- if (lastrow==-1) // Empty screen, nothing to rollup
- return;
-
- for (j = lastrow - keep_lines + 1; j < lastrow; j++)
- {
- if (j >= 0)
- {
- memcpy(use_buffer->characters[j], use_buffer->characters[j+1], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->colors[j], use_buffer->colors[j+1], CC608_SCREEN_WIDTH+1);
- memcpy(use_buffer->fonts[j], use_buffer->fonts[j+1], CC608_SCREEN_WIDTH+1);
- use_buffer->row_used[j] = use_buffer->row_used[j+1];
- }
- }
- for (j = 0; j < (1 + wb->data608->cursor_row - keep_lines); j++)
- {
- memset(use_buffer->characters[j], ' ', CC608_SCREEN_WIDTH);
- memset(use_buffer->colors[j], COL_WHITE, CC608_SCREEN_WIDTH);
- memset(use_buffer->fonts[j], FONT_REGULAR, CC608_SCREEN_WIDTH);
- use_buffer->characters[j][CC608_SCREEN_WIDTH] = 0;
- use_buffer->row_used[j] = 0;
- }
- memset(use_buffer->characters[lastrow], ' ', CC608_SCREEN_WIDTH);
- memset(use_buffer->colors[lastrow], COL_WHITE, CC608_SCREEN_WIDTH);
- memset(use_buffer->fonts[lastrow], FONT_REGULAR, CC608_SCREEN_WIDTH);
-
- use_buffer->characters[lastrow][CC608_SCREEN_WIDTH] = 0;
- use_buffer->row_used[lastrow] = 0;
-
- // Sanity check
- rows_now = 0;
- for (i = 0; i < 15; i++)
- if (use_buffer->row_used[i])
- rows_now++;
- if (rows_now > keep_lines)
- hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
- keep_lines, rows_now);
- use_buffer->dirty = 1;
-}
-
-void erase_memory (struct s_write *wb, int displayed)
-{
- struct eia608_screen *buf;
- if (displayed)
- {
- buf = get_current_visible_buffer(wb);
- }
- else
- {
- buf = get_current_hidden_buffer(wb);
- }
- clear_eia608_cc_buffer (buf);
-}
-
-static int is_current_row_empty (struct s_write *wb)
-{
- struct eia608_screen *use_buffer;
- int i;
-
- use_buffer = get_current_visible_buffer(wb);
- for (i=0;i<CC608_SCREEN_WIDTH;i++)
- {
- if (use_buffer->characters[wb->data608->rollup_base_row][i]!=' ')
- return 0;
- }
- return 1;
-}
-
-/* Process GLOBAL CODES */
-static void handle_command(unsigned char c1, const unsigned char c2,
- struct s_write *wb)
-{
- // Handle channel change
- wb->data608->channel=wb->new_channel;
- if (wb->data608->channel!=cc_channel)
- return;
-
- enum command_code command = COM_UNKNOWN;
- if (c1==0x15)
- c1=0x14;
- if ((c1==0x14 || c1==0x1C) && c2==0x2C)
- command = COM_ERASEDISPLAYEDMEMORY;
- if ((c1==0x14 || c1==0x1C) && c2==0x20)
- command = COM_RESUMECAPTIONLOADING;
- if ((c1==0x14 || c1==0x1C) && c2==0x2F)
- command = COM_ENDOFCAPTION;
- if ((c1==0x17 || c1==0x1F) && c2==0x21)
- command = COM_TABOFFSET1;
- if ((c1==0x17 || c1==0x1F) && c2==0x22)
- command = COM_TABOFFSET2;
- if ((c1==0x17 || c1==0x1F) && c2==0x23)
- command = COM_TABOFFSET3;
- if ((c1==0x14 || c1==0x1C) && c2==0x25)
- command = COM_ROLLUP2;
- if ((c1==0x14 || c1==0x1C) && c2==0x26)
- command = COM_ROLLUP3;
- if ((c1==0x14 || c1==0x1C) && c2==0x27)
- command = COM_ROLLUP4;
- if ((c1==0x14 || c1==0x1C) && c2==0x2D)
- command = COM_CARRIAGERETURN;
- if ((c1==0x14 || c1==0x1C) && c2==0x2E)
- command = COM_ERASENONDISPLAYEDMEMORY;
- if ((c1==0x14 || c1==0x1C) && c2==0x21)
- command = COM_BACKSPACE;
- if ((c1==0x14 || c1==0x1C) && c2==0x2b)
- command = COM_RESUMETEXTDISPLAY;
- if (debug_608)
- {
- hb_log ("\rCommand: %02X %02X (%s)\n",c1,c2,command_type[command]);
- }
- switch (command)
- {
- case COM_BACKSPACE:
- if (wb->data608->cursor_column>0)
- {
- struct eia608_screen *data;
- data = get_writing_buffer(wb);
- if (data != NULL)
- {
- wb->data608->cursor_column--;
- data->characters[wb->data608->cursor_row][wb->data608->cursor_column] = ' ';
- data->dirty = 1;
- }
- }
- break;
- case COM_TABOFFSET1:
- if (wb->data608->cursor_column<31)
- wb->data608->cursor_column++;
- break;
- case COM_TABOFFSET2:
- wb->data608->cursor_column+=2;
- if (wb->data608->cursor_column>31)
- wb->data608->cursor_column=31;
- break;
- case COM_TABOFFSET3:
- wb->data608->cursor_column+=3;
- if (wb->data608->cursor_column>31)
- wb->data608->cursor_column=31;
- break;
- case COM_RESUMECAPTIONLOADING:
- wb->data608->mode=MODE_POPUP;
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- break;
- case COM_RESUMETEXTDISPLAY:
- wb->data608->mode=MODE_TEXT;
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- break;
- case COM_ROLLUP2:
- if (wb->data608->rollup_base_row + 1 < 2)
- {
- move_roll_up(wb, 1);
- wb->data608->rollup_base_row = 1;
- }
- if (wb->data608->mode==MODE_POPUP)
- {
- swap_visible_buffer(wb);
- if (write_cc_buffer(wb))
- wb->data608->screenfuls_counter++;
- erase_memory (wb, 1);
- }
- wb->data608->color=default_color;
- wb->data608->font=FONT_REGULAR;
- if (wb->data608->mode==MODE_ROLLUP_2 && !is_current_row_empty(wb))
- {
- if (debug_608)
- hb_log ("Two RU2, current line not empty. Simulating a CR\n");
- handle_command(0x14, 0x2D, wb);
- wb->rollup_cr = 1;
- }
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- wb->data608->mode=MODE_ROLLUP_2;
- erase_memory (wb, 0);
- wb->data608->cursor_column = 0;
- wb->data608->cursor_row = wb->data608->rollup_base_row;
- break;
- case COM_ROLLUP3:
- if (wb->data608->rollup_base_row + 1 < 3)
- {
- move_roll_up(wb, 2);
- wb->data608->rollup_base_row = 2;
- }
- if (wb->data608->mode==MODE_POPUP)
- {
- if (write_cc_buffer(wb))
- wb->data608->screenfuls_counter++;
- erase_memory (wb, 1);
- }
- wb->data608->color=default_color;
- wb->data608->font=FONT_REGULAR;
- if (wb->data608->mode==MODE_ROLLUP_3 && !is_current_row_empty(wb))
- {
- if (debug_608)
- hb_log ("Two RU3, current line not empty. Simulating a CR\n");
- handle_command(0x14, 0x2D, wb);
- wb->rollup_cr = 1;
- }
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- wb->data608->mode=MODE_ROLLUP_3;
- erase_memory (wb, 0);
- wb->data608->cursor_column = 0;
- wb->data608->cursor_row = wb->data608->rollup_base_row;
- break;
- case COM_ROLLUP4:
- if (wb->data608->rollup_base_row + 1 < 4)
- {
- move_roll_up(wb, 3);
- wb->data608->rollup_base_row = 3;
- }
- if (wb->data608->mode==MODE_POPUP)
- {
- if (write_cc_buffer(wb))
- wb->data608->screenfuls_counter++;
- erase_memory (wb, 1);
- }
- wb->data608->color=default_color;
- wb->data608->font=FONT_REGULAR;
- if (wb->data608->mode==MODE_ROLLUP_4 && !is_current_row_empty(wb))
- {
- if (debug_608)
- hb_log ("Two RU4, current line not empty. Simulating a CR\n");
- handle_command(0x14, 0x2D, wb);
- wb->rollup_cr = 1;
- }
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- wb->data608->mode = MODE_ROLLUP_4;
- wb->data608->cursor_column = 0;
- wb->data608->cursor_row = wb->data608->rollup_base_row;
- erase_memory (wb, 0);
- break;
- case COM_CARRIAGERETURN:
- // In transcript mode, CR doesn't write the whole screen, to avoid
- // repeated lines.
-
- // Skip initial CR if rollup has already done it
- if (wb->rollup_cr && is_current_row_empty(wb))
- {
- wb->rollup_cr = 0;
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- break;
- }
- if (write_cc_buffer(wb))
- wb->data608->screenfuls_counter++;
- roll_up(wb);
- wb->data608->cursor_column = 0;
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- break;
- case COM_ERASENONDISPLAYEDMEMORY:
- erase_memory (wb,0);
- break;
- case COM_ERASEDISPLAYEDMEMORY:
- // There may be "displayed" rollup data that has not been
- // written to a buffer yet.
- if (wb->data608->mode == MODE_ROLLUP_2 ||
- wb->data608->mode == MODE_ROLLUP_3 ||
- wb->data608->mode == MODE_ROLLUP_4)
- {
- write_cc_buffer(wb);
- }
- erase_memory (wb,1);
-
- // the last pts is the time to remove the previously
- // displayed CC from the display
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
-
- // Write "clear" subtitle if necessary
- struct eia608_screen *data;
- data = get_current_visible_buffer(wb);
- data->dirty = 1;
- write_cc_buffer(wb);
- break;
- case COM_ENDOFCAPTION: // Switch buffers
- // The currently *visible* buffer is leaving, so now we know it's ending
- // time. Time to actually write it to file.
- if (wb->data608->mode == MODE_POPUP)
- {
- swap_visible_buffer(wb);
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- }
- if (write_cc_buffer(wb))
- wb->data608->screenfuls_counter++;
-
- if (wb->data608->mode != MODE_POPUP)
- swap_visible_buffer(wb);
- wb->data608->cursor_column = 0;
- wb->data608->cursor_row = 0;
- wb->data608->color=default_color;
- wb->data608->font=FONT_REGULAR;
- break;
- default:
- if (debug_608)
- {
- hb_log ("\rNot yet implemented.\n");
- }
- break;
- }
-}
-
-static void handle_end_of_data(struct s_write *wb)
-{
- // We issue a EraseDisplayedMemory here so if there's any captions pending
- // they get written to file.
- handle_command (0x14, 0x2c, wb); // EDM
-}
-
-static void handle_double(const unsigned char c1, const unsigned char c2,
- struct s_write *wb)
-{
- unsigned char c;
- if (wb->data608->channel!=cc_channel)
- return;
- if (c2>=0x30 && c2<=0x3f)
- {
- c=c2 + 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
- if (debug_608)
- hb_log ("\rDouble: %02X %02X --> %c\n",c1,c2,c);
- write_char(c,wb);
- }
-}
-
-/* Process EXTENDED CHARACTERS */
-static unsigned char handle_extended(unsigned char hi, unsigned char lo,
- struct s_write *wb)
-{
- // Handle channel change
- if (wb->new_channel > 2)
- {
- wb->new_channel -= 2;
- if (debug_608)
- hb_log ("\nChannel correction, now %d\n", wb->new_channel);
- }
- wb->data608->channel=wb->new_channel;
- if (wb->data608->channel!=cc_channel)
- return 0;
-
- // For lo values between 0x20-0x3f
- unsigned char c=0;
-
- if (debug_608)
- hb_log ("\rExtended: %02X %02X\n",hi,lo);
- if (lo>=0x20 && lo<=0x3f && (hi==0x12 || hi==0x13))
- {
- switch (hi)
- {
- case 0x12:
- c=lo+0x70; // So if c>=0x90 && c<=0xaf it comes from here
- break;
- case 0x13:
- c=lo+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
- break;
- }
- // This column change is because extended characters replace
- // the previous character (which is sent for basic decoders
- // to show something similar to the real char)
- if (wb->data608->cursor_column>0)
- wb->data608->cursor_column--;
-
- write_char (c,wb);
- }
- return 1;
-}
-
-/* Process PREAMBLE ACCESS CODES (PAC) */
-static void handle_pac(unsigned char c1, unsigned char c2, struct s_write *wb)
-{
- // Handle channel change
- if (wb->new_channel > 2)
- {
- wb->new_channel -= 2;
- if (debug_608)
- hb_log ("\nChannel correction, now %d\n", wb->new_channel);
- }
- wb->data608->channel=wb->new_channel;
- if (wb->data608->channel!=cc_channel)
- return;
-
- int row=rowdata[((c1<<1)&14)|((c2>>5)&1)];
-
- if (debug_608)
- hb_log ("\rPAC: %02X %02X",c1,c2);
-
- if (c2>=0x40 && c2<=0x5f)
- {
- c2=c2-0x40;
- }
- else
- {
- if (c2>=0x60 && c2<=0x7f)
- {
- c2=c2-0x60;
- }
- else
- {
- if (debug_608)
- hb_log ("\rThis is not a PAC!!!!!\n");
- return;
- }
- }
- wb->data608->color=pac2_attribs[c2][0];
- wb->data608->font=pac2_attribs[c2][1];
- int indent=pac2_attribs[c2][2];
- if (debug_608)
- hb_log (" -- Position: %d:%d, color: %s, font: %s\n", row, indent,
- color_text[wb->data608->color][0],
- font_text[wb->data608->font]);
-
- // CC spec says to the preferred method to handle a roll-up base row
- // that causes the display to scroll off the top of the screen is to
- // adjust the base row down.
- int keep_lines;
- switch (wb->data608->mode)
- {
- case MODE_ROLLUP_2:
- keep_lines = 2;
- break;
- case MODE_ROLLUP_3:
- keep_lines = 3;
- break;
- case MODE_ROLLUP_4:
- keep_lines = 4;
- break;
- default:
- // Not rollup mode, all rows ok
- keep_lines = 0;
- break;
- }
- if (row < keep_lines)
- {
- row = keep_lines;
- }
- if (wb->data608->mode != MODE_TEXT)
- {
- // According to Robson, row info is discarded in text mode
- // but column is accepted
- //
- // CC-608 spec says current rollup display must move to the
- // new position when the cursor row changes
- move_roll_up(wb, row - 1);
- wb->data608->cursor_row = row - 1 ; // Since the array is 0 based
- }
- wb->data608->rollup_base_row = row - 1;
- wb->data608->cursor_column = indent;
-}
-
-
-static void handle_single(const unsigned char c1, struct s_write *wb)
-{
- if (c1<0x20 || wb->data608->channel!=cc_channel)
- return; // We don't allow special stuff here
- if (debug_608)
- hb_log ("%c",c1);
-
- /*if (debug_608)
- hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
- write_char (c1,wb);
-}
-
-static int check_channel(unsigned char c1, struct s_write *wb)
-{
- if (c1==0x14)
- {
- if (debug_608 && wb->data608->channel!=1)
- hb_log ("\nChannel change, now 1\n");
- return 1;
- }
- if (c1==0x1c)
- {
- if (debug_608 && wb->data608->channel!=2)
- hb_log ("\nChannel change, now 2\n");
- return 2;
- }
- if (c1==0x15)
- {
- if (debug_608 && wb->data608->channel!=3)
- hb_log ("\nChannel change, now 3\n");
- return 3;
- }
- if (c1==0x1d)
- {
- if (debug_608 && wb->data608->channel!=4)
- hb_log ("\nChannel change, now 4\n");
- return 4;
- }
-
- // Otherwise keep the current channel
- return wb->data608->channel;
-}
-
-/* Handle Command, special char or attribute and also check for
-* channel changes.
-* Returns 1 if something was written to screen, 0 otherwise */
-static int disCommand(unsigned char hi, unsigned char lo, struct s_write *wb)
-{
- int wrote_to_screen=0;
-
- /* Full channel changes are only allowed for "GLOBAL CODES",
- * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
- * "MID-ROW CODES".
- * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
- * SPECIAL/SPECIAL CHARACTERS allow only switching
- * between 1&3 or 2&4. */
- wb->new_channel = check_channel (hi,wb);
- //if (wb->data608->channel!=cc_channel)
- // continue;
-
- if (hi>=0x18 && hi<=0x1f)
- hi=hi-8;
-
- switch (hi)
- {
- case 0x10:
- if (lo>=0x40 && lo<=0x5f)
- handle_pac (hi,lo,wb);
- break;
- case 0x11:
- if (lo>=0x20 && lo<=0x2f)
- handle_text_attr (hi,lo,wb);
- if (lo>=0x30 && lo<=0x3f)
- {
- wrote_to_screen=1;
- handle_double (hi,lo,wb);
- }
- if (lo>=0x40 && lo<=0x7f)
- handle_pac (hi,lo,wb);
- break;
- case 0x12:
- case 0x13:
- if (lo>=0x20 && lo<=0x3f)
- {
- wrote_to_screen=handle_extended (hi,lo,wb);
- }
- if (lo>=0x40 && lo<=0x7f)
- handle_pac (hi,lo,wb);
- break;
- case 0x14:
- case 0x15:
- if (lo>=0x20 && lo<=0x2f)
- handle_command (hi,lo,wb);
- if (lo>=0x40 && lo<=0x7f)
- handle_pac (hi,lo,wb);
- break;
- case 0x16:
- if (lo>=0x40 && lo<=0x7f)
- handle_pac (hi,lo,wb);
- break;
- case 0x17:
- if (lo>=0x21 && lo<=0x23)
- handle_command (hi,lo,wb);
- if (lo>=0x2e && lo<=0x2f)
- handle_text_attr (hi,lo,wb);
- if (lo>=0x40 && lo<=0x7f)
- handle_pac (hi,lo,wb);
- break;
- }
- return wrote_to_screen;
-}
-
-static void process608(const unsigned char *data, int length,
- struct s_write *wb)
-{
- static int textprinted = 0;
- int i;
-
- if (data!=NULL)
- {
- for (i=0;i<length;i=i+2)
- {
- unsigned char hi, lo;
- hi = data[i] & 0x7F; // Get rid of parity bit
- lo = data[i+1] & 0x7F; // Get rid of parity bit
-
- if (hi==0 && lo==0) // Just padding
- continue;
- if (hi>=0x01 && hi<=0x0E)
- {
- // XDS crap - mode. Would be nice to support it eventually
- // wb->data608->last_c1=0;
- // wb->data608->last_c2=0;
- wb->data608->channel=3; // Always channel 3
- wb->in_xds_mode=1;
- }
- if (hi==0x0F) // End of XDS block
- {
- wb->in_xds_mode=0;
- continue;
- }
- if (hi>=0x10 && hi<0x1F) // Non-character code or special/extended char
- // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
- // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
- {
- // We were writing characters before, start a new line for
- // diagnostic output from disCommand()
- if (debug_608 && textprinted == 1 )
- {
- hb_log("\n");
- textprinted = 0;
- }
-
- wb->in_xds_mode=0; // Back to normal
- if (wb->data608->last_c1==hi && wb->data608->last_c2==lo)
- {
- // Duplicate dual code, discard
- continue;
- }
- wb->data608->last_c1=hi;
- wb->data608->last_c2=lo;
- disCommand (hi,lo,wb);
- }
- if (hi>=0x20) // Standard characters (always in pairs)
- {
- // Only print if the channel is active
- if (wb->data608->channel!=cc_channel)
- continue;
-
- if (debug_608)
- {
- if( textprinted == 0 )
- {
- hb_log("\n");
- textprinted = 1;
- }
- }
-
- handle_single(hi,wb);
- handle_single(lo,wb);
- wb->data608->last_c1=0;
- wb->data608->last_c2=0;
- }
-
- if ( debug_608 && !textprinted && wb->data608->channel==cc_channel )
- { // Current FTS information after the characters are shown
- //hb_log("Current FTS: %s\n", print_mstime(wb->last_pts));
- }
-
- if ((wb->data608->mode == MODE_ROLLUP_2 ||
- wb->data608->mode == MODE_ROLLUP_3 ||
- wb->data608->mode == MODE_ROLLUP_4) &&
- wb->direct_rollup)
- {
- // If we are showing rollup on the fly (direct_rollup)
- // write a buffer now
- write_cc_buffer(wb);
- wb->data608->current_visible_start_ms = wb->last_pts;
- wb->data608->current_visible_scr_sequence = wb->last_scr_sequence;
- }
- }
- }
-}
-
-struct hb_work_private_s
-{
- hb_job_t * job;
- struct s_write * cc608;
-};
-
-static int decccInit( hb_work_object_t * w, hb_job_t * job )
-{
- int retval = 1;
- hb_work_private_t * pv;
-
- pv = calloc( 1, sizeof( hb_work_private_t ) );
- if( pv )
- {
- w->private_data = pv;
-
- pv->job = job;
-
- pv->cc608 = calloc(1, sizeof(struct s_write));
-
- if( pv->cc608 )
- {
- pv->cc608->width = job->title->geometry.width;
- pv->cc608->height = job->title->geometry.height;
- memcpy(pv->cc608->crop, job->crop, sizeof(int[4]));
- pv->cc608->par = job->title->geometry.par;
- retval = general_608_init(pv->cc608);
- if( !retval )
- {
- pv->cc608->data608 = calloc(1, sizeof(struct eia608));
- if( !pv->cc608->data608 )
- {
- retval = 1;
- }
- else
- {
- init_eia608(pv->cc608->data608);
- }
- }
-
- // When rendering subs, we need to push rollup subtitles out
- // asap (instead of waiting for a completed line) so that we
- // do not miss the frame that they should be rendered over.
- pv->cc608->direct_rollup = w->subtitle->config.dest == RENDERSUB;
- }
-
- if (!retval)
- {
- // Generate generic SSA Script Info.
- int height = job->title->geometry.height - job->crop[0] - job->crop[1];
- int width = job->title->geometry.width - job->crop[2] - job->crop[3];
- int safe_height = 0.8 * job->title->geometry.height;
- hb_subtitle_add_ssa_header(w->subtitle, HB_FONT_MONO,
- .08 * safe_height, width, height);
- }
- }
- return retval;
-}
-
-static int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
- hb_buffer_t ** buf_out )
-{
- hb_work_private_t * pv = w->private_data;
- hb_buffer_t * in = *buf_in;
-
- if (in->s.flags & HB_BUF_FLAG_EOF)
- {
- /* EOF on input stream - send it downstream & say that we're done */
- handle_end_of_data(pv->cc608);
- /*
- * Grab any pending buffer and output them with the EOF on the end
- */
- *buf_in = NULL;
- hb_buffer_list_append(&pv->cc608->list, in);
- *buf_out = hb_buffer_list_clear(&pv->cc608->list);
- return HB_WORK_DONE;
- }
-
- pv->cc608->last_pts = in->s.start;
- pv->cc608->last_scr_sequence = in->s.scr_sequence;
- process608(in->data, in->size, pv->cc608);
-
- /*
- * If there is one waiting then pass it on
- */
- *buf_out = hb_buffer_list_clear(&pv->cc608->list);
- return HB_WORK_OK;
-}
-
-static void decccClose( hb_work_object_t * w )
-{
- hb_work_private_t * pv = w->private_data;
-
- if (pv)
- {
- general_608_close( pv->cc608 );
- free( pv->cc608->data608 );
- free( pv->cc608 );
- }
- free( w->private_data );
-}
-
-hb_work_object_t hb_deccc608 =
-{
- WORK_DECCC608,
- "Closed Caption (608) decoder",
- decccInit,
- decccWork,
- decccClose
-};
diff --git a/libhb/handbrake/common.h b/libhb/handbrake/common.h
index 0576d5aa6..391e6e369 100644
--- a/libhb/handbrake/common.h
+++ b/libhb/handbrake/common.h
@@ -1263,7 +1263,6 @@ extern hb_work_object_t hb_sync_audio;
extern hb_work_object_t hb_sync_subtitle;
extern hb_work_object_t hb_decvobsub;
extern hb_work_object_t hb_encvobsub;
-extern hb_work_object_t hb_deccc608;
extern hb_work_object_t hb_decsrtsub;
extern hb_work_object_t hb_decutf8sub;
extern hb_work_object_t hb_dectx3gsub;
diff --git a/libhb/handbrake/internal.h b/libhb/handbrake/internal.h
index fe5690968..2f8fc0369 100644
--- a/libhb/handbrake/internal.h
+++ b/libhb/handbrake/internal.h
@@ -434,7 +434,6 @@ enum
WORK_SYNC_VIDEO,
WORK_SYNC_AUDIO,
WORK_SYNC_SUBTITLE,
- WORK_DECCC608,
WORK_DECVOBSUB,
WORK_DECSRTSUB,
WORK_DECTX3GSUB,
diff --git a/libhb/hb.c b/libhb/hb.c
index f28b7287c..a62052436 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -1709,7 +1709,6 @@ int hb_global_init()
hb_register(&hb_decavcodecv);
hb_register(&hb_decavcodeca);
hb_register(&hb_declpcm);
- hb_register(&hb_deccc608);
hb_register(&hb_decavsub);
hb_register(&hb_decsrtsub);
hb_register(&hb_decssasub);
diff --git a/libhb/stream.c b/libhb/stream.c
index aecffab10..bf96090bc 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -5558,10 +5558,11 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id
subtitle->codec_param = codecpar->codec_id;
break;
case AV_CODEC_ID_EIA_608:
- subtitle->format = TEXTSUB;
- subtitle->source = CC608SUB;
+ subtitle->format = TEXTSUB;
+ subtitle->source = CC608SUB;
subtitle->config.dest = PASSTHRUSUB;
- subtitle->codec = WORK_DECCC608;
+ subtitle->codec = WORK_DECAVSUB;
+ subtitle->codec_param = codecpar->codec_id;
subtitle->attributes = HB_SUBTITLE_ATTR_CC;
break;
default:
@@ -6124,6 +6125,10 @@ hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream )
buf->s.duration = av_to_hb_pts(pkt_duration, tsconv, 0);
buf->s.stop = buf->s.start + buf->s.duration;
}
+ else
+ {
+ buf->s.duration = (int64_t)AV_NOPTS_VALUE;
+ }
buf->s.type = SUBTITLE_BUF;
} break;