seprated 608 dependency from spupng encoder

This commit is contained in:
Anshul Maheshwari 2014-05-21 17:36:51 +05:30
parent 9c1e23cc9f
commit 32b86d5d58
9 changed files with 446 additions and 482 deletions

View File

@ -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:

View File

@ -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) \

View File

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

View File

@ -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__ */

View File

@ -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);

View File

@ -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) ;

View File

@ -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
View 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
View 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