mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2025-02-03 23:59:31 +00:00
seprated 608 dependency from spupng encoder
This commit is contained in:
parent
9c1e23cc9f
commit
32b86d5d58
19
src/608.c
19
src/608.c
@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "608_spupng.h"
|
||||
|
||||
static const 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
|
||||
@ -282,7 +283,7 @@ void handle_text_attr(const unsigned char c1, const unsigned char c2, struct s_c
|
||||
}
|
||||
|
||||
|
||||
void write_subtitle_file_footer(struct s_context_cc608 *context)
|
||||
void write_subtitle_file_footer(struct ccx_s_write *out)
|
||||
{
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
@ -293,7 +294,7 @@ void write_subtitle_file_footer(struct s_context_cc608 *context)
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
write(out->fh, enc_buffer, enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
sprintf ((char *) str,"</div></body></tt>\n");
|
||||
@ -302,10 +303,10 @@ void write_subtitle_file_footer(struct s_context_cc608 *context)
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
write (out->fh, enc_buffer,enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_footer(context);
|
||||
write_spumux_footer(out);
|
||||
break;
|
||||
default: // Nothing to do, no footer on this format
|
||||
break;
|
||||
@ -313,7 +314,7 @@ void write_subtitle_file_footer(struct s_context_cc608 *context)
|
||||
}
|
||||
|
||||
|
||||
void write_subtitle_file_header(struct s_context_cc608 *context)
|
||||
void write_subtitle_file_header(struct ccx_s_write *out)
|
||||
{
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
@ -323,19 +324,19 @@ void write_subtitle_file_header(struct s_context_cc608 *context)
|
||||
//fprintf_encoded (wb->fh, sami_header);
|
||||
REQUEST_BUFFER_CAPACITY(strlen (sami_header)*3);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) sami_header);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
write (out->fh, enc_buffer,enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI
|
||||
//fprintf_encoded (wb->fh, sami_header);
|
||||
REQUEST_BUFFER_CAPACITY(strlen (smptett_header)*3);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) smptett_header);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
write(out->fh, enc_buffer, enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_RCWT: // Write header
|
||||
write(context->out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_header(context);
|
||||
write_spumux_header(out);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT: // No header. Fall thru
|
||||
default:
|
||||
|
@ -42,7 +42,6 @@ struct s_context_cc608
|
||||
int new_channel; // The new channel after a channel change
|
||||
int my_field; // Used for sanity checks
|
||||
long bytes_processed_608; // To be written ONLY by process_608
|
||||
void* spupng_data;
|
||||
struct ccx_s_write *out;
|
||||
};
|
||||
|
||||
@ -91,10 +90,6 @@ unsigned char cctoupper (unsigned char c);
|
||||
int general_608_init (void);
|
||||
LLONG get_visible_end (void);
|
||||
|
||||
void write_spumux_header(struct s_context_cc608 *context);
|
||||
void write_spumux_footer(struct s_context_cc608 *context);
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen* data, struct s_context_cc608 *context);
|
||||
|
||||
#define CC608_SCREEN_WIDTH 32
|
||||
|
||||
#define REQUEST_BUFFER_CAPACITY(length) if (length>enc_buffer_capacity) \
|
||||
|
531
src/608_spupng.c
531
src/608_spupng.c
@ -1,435 +1,7 @@
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
#endif
|
||||
|
||||
#include "608_spupng.h"
|
||||
|
||||
// #include "wstfont2.xbm" // Teletext font, not used
|
||||
#include "ccfont2.xbm" // CC font from libzvbi
|
||||
|
||||
// CC page dimensions
|
||||
#define ROWS 15
|
||||
#define COLUMNS 32
|
||||
|
||||
/* Closed Caption character cell dimensions */
|
||||
#define CCW 16
|
||||
#define CCH 26 /* line doubled */
|
||||
#define CCPL (ccfont2_width / CCW * ccfont2_height / CCH)
|
||||
|
||||
void
|
||||
write_spumux_header(struct s_context_cc608 *context)
|
||||
{
|
||||
if (0 == context->spupng_data)
|
||||
context->spupng_data = spunpg_init(context);
|
||||
|
||||
spupng_write_header((struct spupng_t*)context->spupng_data);
|
||||
}
|
||||
|
||||
void
|
||||
write_spumux_footer(struct s_context_cc608 *context)
|
||||
{
|
||||
if (0 != context->spupng_data)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->spupng_data;
|
||||
|
||||
spupng_write_footer(sp);
|
||||
spunpg_free(sp);
|
||||
|
||||
context->spupng_data = 0;
|
||||
context->out->fh = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
write_cc_buffer_as_spupng(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
if (0 != context->spupng_data)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->spupng_data;
|
||||
return spupng_write_ccbuffer(sp, data, context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
struct spupng_t *spunpg_init(struct s_context_cc608 *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) malloc(sizeof(struct spupng_t));
|
||||
if (NULL == sp)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = 1;
|
||||
spupng_init_font();
|
||||
}
|
||||
|
||||
if ((sp->fpxml = fdopen(context->out->fh, "w")) == NULL)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
context->out->filename, strerror(errno));
|
||||
}
|
||||
sp->dirname = (char *) malloc(
|
||||
sizeof(char) * (strlen(context->out->filename) + 3));
|
||||
if (NULL == sp->dirname)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
strcpy(sp->dirname, context->out->filename);
|
||||
char* p = strrchr(sp->dirname, '.');
|
||||
if (NULL == p)
|
||||
p = sp->dirname + strlen(sp->dirname);
|
||||
*p = '\0';
|
||||
strcat(sp->dirname, ".d");
|
||||
if (0 != mkdir(sp->dirname, 0777))
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot create %s: %s\n",
|
||||
sp->dirname, strerror(errno));
|
||||
}
|
||||
// If dirname isn't a directory or if we don't have write permission,
|
||||
// the first attempt to create a .png file will fail and we'll XXxit.
|
||||
}
|
||||
|
||||
// enough to append /subNNNN.png
|
||||
sp->pngfile = (char *) malloc(sizeof(char) * (strlen(sp->dirname) + 13));
|
||||
if (NULL == sp->pngfile)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
sp->fileIndex = 0;
|
||||
|
||||
// For NTSC closed captions and 720x480 DVD subtitle resolution:
|
||||
// Each character is 16x26.
|
||||
// 15 rows by 32 columns, plus 2 columns for left & right padding
|
||||
// So each .png image will be 16*34 wide and 26*15 high, or 544x390
|
||||
// To center image in 720x480 DVD screen, offset image by 88 and 45
|
||||
// Need to keep yOffset even to prevent flicker on interlaced displays
|
||||
// Would need to do something different for PAL format and teletext.
|
||||
sp->xOffset = 88;
|
||||
sp->yOffset = 46;
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
void
|
||||
spunpg_free(struct spupng_t *sp)
|
||||
{
|
||||
free(sp->dirname);
|
||||
free(sp->pngfile);
|
||||
free(sp);
|
||||
}
|
||||
|
||||
void
|
||||
spupng_write_header(struct spupng_t *sp)
|
||||
{
|
||||
fprintf(sp->fpxml, "<subpictures>\n<stream>\n");
|
||||
if (num_input_files > 0)
|
||||
fprintf(sp->fpxml, "<!-- %s -->\n", inputfile[0]);
|
||||
}
|
||||
|
||||
void
|
||||
spupng_write_footer(struct spupng_t *sp)
|
||||
{
|
||||
fprintf(sp->fpxml, "</stream>\n</subpictures>\n");
|
||||
fflush(sp->fpxml);
|
||||
fclose(sp->fpxml);
|
||||
}
|
||||
|
||||
int
|
||||
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG ms_start = context->current_visible_start_ms + subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int row;
|
||||
int empty_buf = 1;
|
||||
for (row = 0; row < 15; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
empty_buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Blank page\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLONG ms_end = get_visible_end() + subs_delay;
|
||||
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
|
||||
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
if (!spupng_export_png(sp, data))
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
fclose(sp->fppng);
|
||||
|
||||
fprintf(sp->fpxml, "<spu start=\"%.3f\"", ((double)ms_start) / 1000);
|
||||
dbg_print(CCX_DMT_608, "<spu start=\"%.3f\"", ((double)ms_start) / 1000);
|
||||
fprintf(sp->fpxml, " end=\"%.3f\"", ((double)ms_end) / 1000);
|
||||
dbg_print(CCX_DMT_608, " end=\"%.3f\"", ((double)ms_end) / 1000);
|
||||
fprintf(sp->fpxml, " image=\"%s\"", sp->pngfile);
|
||||
dbg_print(CCX_DMT_608, " image=\"%s\"", sp->pngfile);
|
||||
fprintf(sp->fpxml, " xoffset=\"%d\"", sp->xOffset);
|
||||
dbg_print(CCX_DMT_608, " xoffset=\"%d\"", sp->xOffset);
|
||||
fprintf(sp->fpxml, " yoffset=\"%d\"", sp->yOffset);
|
||||
dbg_print(CCX_DMT_608, " yoffset=\"%d\"", sp->yOffset);
|
||||
fprintf(sp->fpxml, ">\n<!--\n");
|
||||
dbg_print(CCX_DMT_608, ">\n<!--\n");
|
||||
for (row = 0; row < ROWS; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
int len = get_decoder_line_encoded(subline, row, data);
|
||||
// Check for characters that spumux won't parse
|
||||
// null chars will be changed to space
|
||||
// pairs of dashes will be changed to underscores
|
||||
for (unsigned char* ptr = subline; ptr < subline+len; ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case 0:
|
||||
*ptr = ' ';
|
||||
break;
|
||||
case '-':
|
||||
if (*(ptr+1) == '-')
|
||||
{
|
||||
*ptr++ = '_';
|
||||
*ptr = '_';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(sp->fpxml, "%s\n", subline);
|
||||
dbg_print(CCX_DMT_608, "%s\n", subline);
|
||||
}
|
||||
}
|
||||
fprintf(sp->fpxml, "--></spu>\n");
|
||||
dbg_print(CCX_DMT_608, "--></spu>\n");
|
||||
|
||||
fflush(sp->fpxml);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Begin copy from http://zapping.cvs.sourceforge.net/viewvc/zapping/vbi/src/exp-gfx.c?view=markup&pathrev=zvbi-0-2-33
|
||||
//
|
||||
|
||||
void
|
||||
spupng_init_font()
|
||||
{
|
||||
uint8_t *t, *p;
|
||||
int i, j;
|
||||
|
||||
/* de-interleave font image (puts all chars in row 0) */
|
||||
#if 0
|
||||
if (!(t = malloc(wstfont2_width * wstfont2_height / 8)))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
for (p = t, i = 0; i < TCH; i++)
|
||||
for (j = 0; j < wstfont2_height; p += wstfont2_width / 8, j += TCH)
|
||||
memcpy(p, wstfont2_bits + (j + i) * wstfont2_width / 8,
|
||||
wstfont2_width / 8);
|
||||
|
||||
memcpy(wstfont2_bits, t, wstfont2_width * wstfont2_height / 8);
|
||||
free (t);
|
||||
#endif
|
||||
if (!(t = (uint8_t*)malloc(ccfont2_width * ccfont2_height / 8)))
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
for (p = t, i = 0; i < CCH; i++)
|
||||
for (j = 0; j < ccfont2_height; p += ccfont2_width / 8, j += CCH)
|
||||
memcpy(p, ccfont2_bits + (j + i) * ccfont2_width / 8,
|
||||
ccfont2_width / 8);
|
||||
|
||||
memcpy(ccfont2_bits, t, ccfont2_width * ccfont2_height / 8);
|
||||
free(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param c Unicode.
|
||||
* @param italic @c TRUE to switch to slanted character set.
|
||||
*
|
||||
* Translate Unicode character to glyph number in ccfont2 image.
|
||||
*
|
||||
* @return
|
||||
* Glyph number.
|
||||
*/
|
||||
static unsigned int
|
||||
unicode_ccfont2(unsigned int c, int italic)
|
||||
{
|
||||
static const unsigned short specials[] = {
|
||||
0x00E1, 0x00E9,
|
||||
0x00ED, 0x00F3, 0x00FA, 0x00E7, 0x00F7, 0x00D1, 0x00F1, 0x25A0,
|
||||
0x00AE, 0x00B0, 0x00BD, 0x00BF, 0x2122, 0x00A2, 0x00A3, 0x266A,
|
||||
0x00E0, 0x0020, 0x00E8, 0x00E2, 0x00EA, 0x00EE, 0x00F4, 0x00FB };
|
||||
unsigned int i;
|
||||
|
||||
if (c < 0x0020)
|
||||
c = 15; /* invalid */
|
||||
else if (c < 0x0080)
|
||||
c = c;
|
||||
else {
|
||||
for (i = 0; i < sizeof(specials) / sizeof(specials[0]); i++)
|
||||
if (specials[i] == c) {
|
||||
c = i + 6;
|
||||
goto slant;
|
||||
}
|
||||
|
||||
c = 15; /* invalid */
|
||||
}
|
||||
|
||||
slant:
|
||||
if (italic)
|
||||
c += 4 * 32;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param p Plane of @a canvas_type char, short, int.
|
||||
* @param i Index.
|
||||
*
|
||||
* @return
|
||||
* Pixel @a i in plane @a p.
|
||||
*/
|
||||
#define peek(p, i) \
|
||||
((canvas_type == sizeof(uint8_t)) ? ((uint8_t *)(p))[i] : \
|
||||
((canvas_type == sizeof(uint16_t)) ? ((uint16_t *)(p))[i] : \
|
||||
((uint32_t *)(p))[i]))
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param p Plane of @a canvas_type char, short, int.
|
||||
* @param i Index.
|
||||
* @param v Value.
|
||||
*
|
||||
* Set pixel @a i in plane @a p to value @a v.
|
||||
*/
|
||||
#define poke(p, i, v) \
|
||||
((canvas_type == sizeof(uint8_t)) ? (((uint8_t *)(p))[i] = (v)) : \
|
||||
((canvas_type == sizeof(uint16_t)) ? (((uint16_t *)(p))[i] = (v)) : \
|
||||
(((uint32_t *)(p))[i] = (v))))
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param canvas_type sizeof(char, short, int).
|
||||
* @param canvas Pointer to image plane where the character is to be drawn.
|
||||
* @param rowstride @a canvas <em>byte</em> distance from line to line.
|
||||
* @param pen Pointer to color palette of @a canvas_type (index 0 background
|
||||
* pixels, index 1 foreground pixels).
|
||||
* @param font Pointer to font image with width @a cpl x @a cw pixels, height
|
||||
* @a ch pixels, depth one bit, bit '1' is foreground.
|
||||
* @param cpl Chars per line (number of characters in @a font image).
|
||||
* @param cw Character cell width in pixels.
|
||||
* @param ch Character cell height in pixels.
|
||||
* @param glyph Glyph number in font image, 0 ... @a cpl - 1.
|
||||
* @param underline Bit mask of character rows. For each bit
|
||||
* 1 << (n = 0 ... @a ch - 1) set all of character row n to
|
||||
* foreground color.
|
||||
* @param size Size of character, either NORMAL, DOUBLE_WIDTH (draws left
|
||||
* and right half), DOUBLE_HEIGHT (draws upper half only),
|
||||
* DOUBLE_SIZE (left and right upper half), DOUBLE_HEIGHT2
|
||||
* (lower half), DOUBLE_SIZE2 (left and right lower half).
|
||||
*
|
||||
* Draw one character (function template - define a static version with
|
||||
* constant @a canvas_type, @a font, @a cpl, @a cw, @a ch).
|
||||
*/
|
||||
static void
|
||||
draw_char(int canvas_type, uint8_t *canvas, int rowstride,
|
||||
uint8_t *pen, uint8_t *font, int cpl, int cw, int ch,
|
||||
int glyph, unsigned int underline)
|
||||
{
|
||||
uint8_t *src;
|
||||
int shift, x, y;
|
||||
|
||||
assert(cw >= 8 && cw <= 16);
|
||||
assert(ch >= 1 && ch <= 31);
|
||||
|
||||
x = glyph * cw;
|
||||
shift = x & 7;
|
||||
src = font + (x >> 3);
|
||||
|
||||
for (y = 0; y < ch; underline >>= 1, y++) {
|
||||
int bits = ~0;
|
||||
|
||||
if (!(underline & 1)) {
|
||||
#ifdef __i386__
|
||||
bits = (*((uint16_t *) src) >> shift);
|
||||
#else
|
||||
/* unaligned/little endian */
|
||||
bits = ((src[1] * 256 + src[0]) >> shift);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (x = 0; x < cw; bits >>= 1, x++)
|
||||
poke(canvas, x, peek(pen, bits & 1));
|
||||
|
||||
canvas += rowstride;
|
||||
|
||||
src += cpl * cw / 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param canvas_type sizeof(char, short, int).
|
||||
* @param canvas Pointer to image plane where the character is to be drawn.
|
||||
* @param rowstride @a canvas <em>byte</em> distance from line to line.
|
||||
* @param color Color value of @a canvas_type.
|
||||
* @param cw Character width in pixels.
|
||||
* @param ch Character height in pixels.
|
||||
*
|
||||
* Draw blank character.
|
||||
*/
|
||||
static void
|
||||
draw_blank(int canvas_type, uint8_t *canvas, unsigned int rowstride,
|
||||
unsigned int color, int cw, int ch)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < ch; y++) {
|
||||
for (x = 0; x < cw; x++)
|
||||
poke(canvas, x, color);
|
||||
|
||||
canvas += rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PNG and XPM drawing functions (palette-based)
|
||||
*/
|
||||
static void
|
||||
draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
|
||||
int unicode, int italic, int underline)
|
||||
{
|
||||
draw_char(sizeof(*canvas), canvas, rowstride,
|
||||
pen, (uint8_t *) ccfont2_bits, CCPL, CCW, CCH,
|
||||
unicode_ccfont2(unicode, italic),
|
||||
underline * (3 << 24) /* cell row 24, 25 */);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
draw_row(struct eia608_screen* data, int row, uint8_t * canvas, int rowstride)
|
||||
{
|
||||
@ -503,7 +75,7 @@ static png_byte alpha[10] =
|
||||
0
|
||||
};
|
||||
|
||||
int
|
||||
int
|
||||
spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
|
||||
png_structp png_ptr, png_infop info_ptr,
|
||||
png_bytep image,
|
||||
@ -620,7 +192,102 @@ unknown_error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// End copy from http://zapping.cvs.sourceforge.net/viewvc/zapping/vbi/src/exp-gfx.c?view=markup&pathrev=zvbi-0-2-33
|
||||
//
|
||||
int
|
||||
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG ms_start = context->current_visible_start_ms + subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int row;
|
||||
int empty_buf = 1;
|
||||
for (row = 0; row < 15; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
empty_buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Blank page\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLONG ms_end = get_visible_end() + subs_delay;
|
||||
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
|
||||
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
if (!spupng_export_png(sp, data))
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
fclose(sp->fppng);
|
||||
|
||||
fprintf(sp->fpxml, "<spu start=\"%.3f\"", ((double)ms_start) / 1000);
|
||||
dbg_print(CCX_DMT_608, "<spu start=\"%.3f\"", ((double)ms_start) / 1000);
|
||||
fprintf(sp->fpxml, " end=\"%.3f\"", ((double)ms_end) / 1000);
|
||||
dbg_print(CCX_DMT_608, " end=\"%.3f\"", ((double)ms_end) / 1000);
|
||||
fprintf(sp->fpxml, " image=\"%s\"", sp->pngfile);
|
||||
dbg_print(CCX_DMT_608, " image=\"%s\"", sp->pngfile);
|
||||
fprintf(sp->fpxml, " xoffset=\"%d\"", sp->xOffset);
|
||||
dbg_print(CCX_DMT_608, " xoffset=\"%d\"", sp->xOffset);
|
||||
fprintf(sp->fpxml, " yoffset=\"%d\"", sp->yOffset);
|
||||
dbg_print(CCX_DMT_608, " yoffset=\"%d\"", sp->yOffset);
|
||||
fprintf(sp->fpxml, ">\n<!--\n");
|
||||
dbg_print(CCX_DMT_608, ">\n<!--\n");
|
||||
for (row = 0; row < ROWS; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
int len = get_decoder_line_encoded(subline, row, data);
|
||||
// Check for characters that spumux won't parse
|
||||
// null chars will be changed to space
|
||||
// pairs of dashes will be changed to underscores
|
||||
for (unsigned char* ptr = subline; ptr < subline+len; ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case 0:
|
||||
*ptr = ' ';
|
||||
break;
|
||||
case '-':
|
||||
if (*(ptr+1) == '-')
|
||||
{
|
||||
*ptr++ = '_';
|
||||
*ptr = '_';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(sp->fpxml, "%s\n", subline);
|
||||
dbg_print(CCX_DMT_608, "%s\n", subline);
|
||||
}
|
||||
}
|
||||
fprintf(sp->fpxml, "--></spu>\n");
|
||||
dbg_print(CCX_DMT_608, "--></spu>\n");
|
||||
|
||||
fflush(sp->fpxml);
|
||||
|
||||
return 1;
|
||||
}
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context)
|
||||
{
|
||||
if (0 != context->out->spupng_data)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
|
||||
return spupng_write_ccbuffer(sp, data, context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,9 @@
|
||||
#ifndef __608_SPUPNG_H__
|
||||
|
||||
#include "png.h"
|
||||
#include "ccextractor.h"
|
||||
#include "spupng_encoder.h"
|
||||
|
||||
struct spupng_t
|
||||
{
|
||||
FILE* fpxml;
|
||||
FILE* fppng;
|
||||
char* dirname;
|
||||
char* pngfile;
|
||||
int fileIndex;
|
||||
int xOffset;
|
||||
int yOffset;
|
||||
};
|
||||
|
||||
struct spupng_t *spunpg_init(struct s_context_cc608 *context);
|
||||
void spunpg_free(struct spupng_t *spupng);
|
||||
|
||||
void spupng_write_header(struct spupng_t *spupng);
|
||||
void spupng_write_footer(struct spupng_t *spupng);
|
||||
|
||||
int spupng_write_ccbuffer(struct spupng_t *spupng, struct eia608_screen* data,
|
||||
struct s_context_cc608 *context);
|
||||
|
||||
void spupng_init_font();
|
||||
|
||||
int spupng_write_png(struct spupng_t *spupng,
|
||||
struct eia608_screen* data,
|
||||
png_structp png_ptr, png_infop info_ptr,
|
||||
png_bytep image,
|
||||
png_bytep* row_pointer,
|
||||
unsigned int ww, unsigned int wh);
|
||||
|
||||
int spupng_export_png(struct spupng_t *spupng, struct eia608_screen* data);
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context);
|
||||
|
||||
#endif /* __608_SPUPNG_H__ */
|
||||
|
@ -470,7 +470,7 @@ int main(int argc, char *argv[])
|
||||
writeraw (UTF8_BOM, sizeof (UTF8_BOM), &wbout1);
|
||||
if (ccx_options.encoding==CCX_ENC_UNICODE) // Write BOM
|
||||
writeraw (LITTLE_ENDIAN_BOM, sizeof (LITTLE_ENDIAN_BOM), &wbout1);
|
||||
write_subtitle_file_header(&context_cc608_field_1);
|
||||
write_subtitle_file_header(context_cc608_field_1.out);
|
||||
}
|
||||
}
|
||||
if (ccx_options.extract == 12)
|
||||
@ -510,7 +510,7 @@ int main(int argc, char *argv[])
|
||||
writeraw (UTF8_BOM, sizeof (UTF8_BOM), &wbout2);
|
||||
if (ccx_options.encoding==CCX_ENC_UNICODE) // Write BOM
|
||||
writeraw (LITTLE_ENDIAN_BOM, sizeof (LITTLE_ENDIAN_BOM), &wbout2);
|
||||
write_subtitle_file_header(&context_cc608_field_2);
|
||||
write_subtitle_file_header(context_cc608_field_2.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -825,7 +825,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (ccx_options.end_credits_text!=NULL)
|
||||
try_to_add_end_credits(&context_cc608_field_1);
|
||||
write_subtitle_file_footer(&context_cc608_field_1);
|
||||
write_subtitle_file_footer(context_cc608_field_1.out);
|
||||
}
|
||||
if (wbout2.fh!=-1)
|
||||
{
|
||||
@ -840,7 +840,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (ccx_options.end_credits_text!=NULL)
|
||||
try_to_add_end_credits(&context_cc608_field_2);
|
||||
write_subtitle_file_footer(&context_cc608_field_2);
|
||||
write_subtitle_file_footer(context_cc608_field_2.out);
|
||||
}
|
||||
telxcc_close();
|
||||
flushbuffer (&wbout1,true);
|
||||
|
@ -139,6 +139,7 @@ struct ccx_s_write
|
||||
{
|
||||
int fh;
|
||||
char *filename;
|
||||
void* spupng_data;
|
||||
};
|
||||
|
||||
|
||||
@ -369,8 +370,8 @@ int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, un
|
||||
void init_context_cc608(struct s_context_cc608 *data, int field);
|
||||
unsigned encode_line (unsigned char *buffer, unsigned char *text);
|
||||
void buffered_seek (int offset);
|
||||
void write_subtitle_file_header(struct s_context_cc608 *context);
|
||||
void write_subtitle_file_footer(struct s_context_cc608 *context);
|
||||
void write_subtitle_file_header(struct ccx_s_write *out);
|
||||
void write_subtitle_file_footer(struct ccx_s_write *out);
|
||||
extern void build_parity_table(void);
|
||||
|
||||
void tlt_process_pes_packet(uint8_t *buffer, uint16_t size) ;
|
||||
|
@ -16,6 +16,8 @@ typedef int socklen_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
#define IN_CLASSD(i) (((INT32)(i) & 0xf0000000) == 0xe0000000)
|
||||
#define IN_MULTICAST(i) IN_CLASSD(i)
|
||||
#include <direct.h>
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
@ -27,6 +29,8 @@ typedef uint32_t in_addr_t;
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
294
src/spupng_encoder.c
Normal file
294
src/spupng_encoder.c
Normal file
@ -0,0 +1,294 @@
|
||||
#include "ccfont2.xbm" // CC font from libzvbi
|
||||
#include "platform.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define CCPL (ccfont2_width / CCW * ccfont2_height / CCH)
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
void
|
||||
spupng_init_font()
|
||||
{
|
||||
uint8_t *t, *p;
|
||||
int i, j;
|
||||
|
||||
/* de-interleave font image (puts all chars in row 0) */
|
||||
if (!(t = (uint8_t*)malloc(ccfont2_width * ccfont2_height / 8)))
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
for (p = t, i = 0; i < CCH; i++)
|
||||
for (j = 0; j < ccfont2_height; p += ccfont2_width / 8, j += CCH)
|
||||
memcpy(p, ccfont2_bits + (j + i) * ccfont2_width / 8,
|
||||
ccfont2_width / 8);
|
||||
|
||||
memcpy(ccfont2_bits, t, ccfont2_width * ccfont2_height / 8);
|
||||
free(t);
|
||||
}
|
||||
|
||||
struct spupng_t *spunpg_init(struct ccx_s_write *out)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) malloc(sizeof(struct spupng_t));
|
||||
if (NULL == sp)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = 1;
|
||||
spupng_init_font();
|
||||
}
|
||||
|
||||
if ((sp->fpxml = fdopen(out->fh, "w")) == NULL)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
out->filename, strerror(errno));
|
||||
}
|
||||
sp->dirname = (char *) malloc(
|
||||
sizeof(char) * (strlen(out->filename) + 3));
|
||||
if (NULL == sp->dirname)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
|
||||
strcpy(sp->dirname, out->filename);
|
||||
char* p = strrchr(sp->dirname, '.');
|
||||
if (NULL == p)
|
||||
p = sp->dirname + strlen(sp->dirname);
|
||||
*p = '\0';
|
||||
strcat(sp->dirname, ".d");
|
||||
if (0 != mkdir(sp->dirname, 0777))
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot create %s: %s\n",
|
||||
sp->dirname, strerror(errno));
|
||||
}
|
||||
// If dirname isn't a directory or if we don't have write permission,
|
||||
// the first attempt to create a .png file will fail and we'll XXxit.
|
||||
}
|
||||
|
||||
// enough to append /subNNNN.png
|
||||
sp->pngfile = (char *) malloc(sizeof(char) * (strlen(sp->dirname) + 13));
|
||||
if (NULL == sp->pngfile)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
sp->fileIndex = 0;
|
||||
|
||||
// For NTSC closed captions and 720x480 DVD subtitle resolution:
|
||||
// Each character is 16x26.
|
||||
// 15 rows by 32 columns, plus 2 columns for left & right padding
|
||||
// So each .png image will be 16*34 wide and 26*15 high, or 544x390
|
||||
// To center image in 720x480 DVD screen, offset image by 88 and 45
|
||||
// Need to keep yOffset even to prevent flicker on interlaced displays
|
||||
// Would need to do something different for PAL format and teletext.
|
||||
sp->xOffset = 88;
|
||||
sp->yOffset = 46;
|
||||
|
||||
return sp;
|
||||
}
|
||||
void
|
||||
spunpg_free(struct spupng_t *sp)
|
||||
{
|
||||
free(sp->dirname);
|
||||
free(sp->pngfile);
|
||||
free(sp);
|
||||
}
|
||||
|
||||
void
|
||||
spupng_write_header(struct spupng_t *sp)
|
||||
{
|
||||
fprintf(sp->fpxml, "<subpictures>\n<stream>\n");
|
||||
if (num_input_files > 0)
|
||||
fprintf(sp->fpxml, "<!-- %s -->\n", inputfile[0]);
|
||||
}
|
||||
|
||||
void
|
||||
spupng_write_footer(struct spupng_t *sp)
|
||||
{
|
||||
fprintf(sp->fpxml, "</stream>\n</subpictures>\n");
|
||||
fflush(sp->fpxml);
|
||||
fclose(sp->fpxml);
|
||||
}
|
||||
|
||||
void write_spumux_header(struct ccx_s_write *out)
|
||||
{
|
||||
if (0 == out->spupng_data)
|
||||
out->spupng_data = spunpg_init(out);
|
||||
|
||||
spupng_write_header((struct spupng_t*)out->spupng_data);
|
||||
}
|
||||
|
||||
void write_spumux_footer(struct ccx_s_write *out)
|
||||
{
|
||||
if (0 != out->spupng_data)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) out->spupng_data;
|
||||
|
||||
spupng_write_footer(sp);
|
||||
spunpg_free(sp);
|
||||
|
||||
out->spupng_data = 0;
|
||||
out->fh = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param p Plane of @a canvas_type char, short, int.
|
||||
* @param i Index.
|
||||
*
|
||||
* @return
|
||||
* Pixel @a i in plane @a p.
|
||||
*/
|
||||
#define peek(p, i) \
|
||||
((canvas_type == sizeof(uint8_t)) ? ((uint8_t *)(p))[i] : \
|
||||
((canvas_type == sizeof(uint16_t)) ? ((uint16_t *)(p))[i] : \
|
||||
((uint32_t *)(p))[i]))
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param p Plane of @a canvas_type char, short, int.
|
||||
* @param i Index.
|
||||
* @param v Value.
|
||||
*
|
||||
* Set pixel @a i in plane @a p to value @a v.
|
||||
*/
|
||||
#define poke(p, i, v) \
|
||||
((canvas_type == sizeof(uint8_t)) ? (((uint8_t *)(p))[i] = (v)) : \
|
||||
((canvas_type == sizeof(uint16_t)) ? (((uint16_t *)(p))[i] = (v)) : \
|
||||
(((uint32_t *)(p))[i] = (v))))
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param c Unicode.
|
||||
* @param italic @c TRUE to switch to slanted character set.
|
||||
*
|
||||
* Translate Unicode character to glyph number in ccfont2 image.
|
||||
*
|
||||
* @return
|
||||
* Glyph number.
|
||||
*/
|
||||
static unsigned int
|
||||
unicode_ccfont2(unsigned int c, int italic)
|
||||
{
|
||||
static const unsigned short specials[] = {
|
||||
0x00E1, 0x00E9,
|
||||
0x00ED, 0x00F3, 0x00FA, 0x00E7, 0x00F7, 0x00D1, 0x00F1, 0x25A0,
|
||||
0x00AE, 0x00B0, 0x00BD, 0x00BF, 0x2122, 0x00A2, 0x00A3, 0x266A,
|
||||
0x00E0, 0x0020, 0x00E8, 0x00E2, 0x00EA, 0x00EE, 0x00F4, 0x00FB };
|
||||
unsigned int i;
|
||||
|
||||
if (c < 0x0020)
|
||||
c = 15; /* invalid */
|
||||
else if (c < 0x0080)
|
||||
/*c = c */;
|
||||
else {
|
||||
for (i = 0; i < sizeof(specials) / sizeof(specials[0]); i++)
|
||||
if (specials[i] == c) {
|
||||
c = i + 6;
|
||||
goto slant;
|
||||
}
|
||||
|
||||
c = 15; /* invalid */
|
||||
}
|
||||
|
||||
slant:
|
||||
if (italic)
|
||||
c += 4 * 32;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param canvas_type sizeof(char, short, int).
|
||||
* @param canvas Pointer to image plane where the character is to be drawn.
|
||||
* @param rowstride @a canvas <em>byte</em> distance from line to line.
|
||||
* @param color Color value of @a canvas_type.
|
||||
* @param cw Character width in pixels.
|
||||
* @param ch Character height in pixels.
|
||||
*
|
||||
* Draw blank character.
|
||||
*/
|
||||
static void
|
||||
draw_blank(int canvas_type, uint8_t *canvas, unsigned int rowstride,
|
||||
unsigned int color, int cw, int ch)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < ch; y++) {
|
||||
for (x = 0; x < cw; x++)
|
||||
poke(canvas, x, color);
|
||||
|
||||
canvas += rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param canvas_type sizeof(char, short, int).
|
||||
* @param canvas Pointer to image plane where the character is to be drawn.
|
||||
* @param rowstride @a canvas <em>byte</em> distance from line to line.
|
||||
* @param pen Pointer to color palette of @a canvas_type (index 0 background
|
||||
* pixels, index 1 foreground pixels).
|
||||
* @param font Pointer to font image with width @a cpl x @a cw pixels, height
|
||||
* @a ch pixels, depth one bit, bit '1' is foreground.
|
||||
* @param cpl Chars per line (number of characters in @a font image).
|
||||
* @param cw Character cell width in pixels.
|
||||
* @param ch Character cell height in pixels.
|
||||
* @param glyph Glyph number in font image, 0 ... @a cpl - 1.
|
||||
* @param underline Bit mask of character rows. For each bit
|
||||
* 1 << (n = 0 ... @a ch - 1) set all of character row n to
|
||||
* foreground color.
|
||||
* @param size Size of character, either NORMAL, DOUBLE_WIDTH (draws left
|
||||
* and right half), DOUBLE_HEIGHT (draws upper half only),
|
||||
* DOUBLE_SIZE (left and right upper half), DOUBLE_HEIGHT2
|
||||
* (lower half), DOUBLE_SIZE2 (left and right lower half).
|
||||
*
|
||||
* Draw one character (function template - define a static version with
|
||||
* constant @a canvas_type, @a font, @a cpl, @a cw, @a ch).
|
||||
*/
|
||||
static void
|
||||
draw_char(int canvas_type, uint8_t *canvas, int rowstride,
|
||||
uint8_t *pen, uint8_t *font, int cpl, int cw, int ch,
|
||||
int glyph, unsigned int underline)
|
||||
{
|
||||
uint8_t *src;
|
||||
int shift, x, y;
|
||||
|
||||
assert(cw >= 8 && cw <= 16);
|
||||
assert(ch >= 1 && ch <= 31);
|
||||
|
||||
x = glyph * cw;
|
||||
shift = x & 7;
|
||||
src = font + (x >> 3);
|
||||
|
||||
for (y = 0; y < ch; underline >>= 1, y++) {
|
||||
int bits = ~0;
|
||||
|
||||
if (!(underline & 1)) {
|
||||
#ifdef __i386__
|
||||
bits = (*((uint16_t *) src) >> shift);
|
||||
#else
|
||||
/* unaligned/little endian */
|
||||
bits = ((src[1] * 256 + src[0]) >> shift);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (x = 0; x < cw; bits >>= 1, x++)
|
||||
poke(canvas, x, peek(pen, bits & 1));
|
||||
|
||||
canvas += rowstride;
|
||||
|
||||
src += cpl * cw / 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PNG and XPM drawing functions (palette-based)
|
||||
*/
|
||||
void draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
|
||||
int unicode, int italic, int underline)
|
||||
{
|
||||
draw_char(sizeof(*canvas), canvas, rowstride,
|
||||
pen, (uint8_t *) ccfont2_bits, CCPL, CCW, CCH,
|
||||
unicode_ccfont2(unicode, italic),
|
||||
underline * (3 << 24) /* cell row 24, 25 */);
|
||||
}
|
30
src/spupng_encoder.h
Normal file
30
src/spupng_encoder.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _SPUPNG_ENCODER_H
|
||||
#define _SPUPNG_ENCODER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "png.h"
|
||||
#include "ccextractor.h"
|
||||
|
||||
// CC page dimensions
|
||||
#define ROWS 15
|
||||
#define COLUMNS 32
|
||||
/* Closed Caption character cell dimensions */
|
||||
#define CCW 16
|
||||
#define CCH 26 /* line doubled */
|
||||
|
||||
struct spupng_t
|
||||
{
|
||||
FILE* fpxml;
|
||||
FILE* fppng;
|
||||
char* dirname;
|
||||
char* pngfile;
|
||||
int fileIndex;
|
||||
int xOffset;
|
||||
int yOffset;
|
||||
};
|
||||
|
||||
void write_spumux_header(struct ccx_s_write *out);
|
||||
void write_spumux_footer(struct ccx_s_write *out);
|
||||
void draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
|
||||
int unicode, int italic, int underline);
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user