mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-15 21:23:10 +00:00
Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fa59a14f7 | ||
|
|
4e6c0352b0 | ||
|
|
cc7ebbc4d7 | ||
|
|
7a74b815fa | ||
|
|
331038634d | ||
|
|
aa2c316093 | ||
|
|
3347f5d345 | ||
|
|
141792a299 | ||
|
|
183e613981 | ||
|
|
19e2912a71 | ||
|
|
dc82154a03 | ||
|
|
2029dab3bf | ||
|
|
405d808d0b | ||
|
|
783e889634 | ||
|
|
a32c8a3b7f | ||
|
|
5618df35c6 | ||
|
|
c054594383 | ||
|
|
c58f99378f | ||
|
|
45d1dfe425 | ||
|
|
a5dcf9242d | ||
|
|
ecc0714f48 | ||
|
|
26410b991d | ||
|
|
19b1bff7f4 | ||
|
|
bc1aff78d7 | ||
|
|
2df8931d00 | ||
|
|
b765198d53 | ||
|
|
22f620400a | ||
|
|
a68add78d0 | ||
|
|
14d866e8a2 | ||
|
|
335bca4507 | ||
|
|
f31425e9f0 | ||
|
|
3f54fab5f4 | ||
|
|
59c62d48b3 | ||
|
|
a926766478 | ||
|
|
cc233c61f2 | ||
|
|
e9fcdf392f | ||
|
|
c42f039297 | ||
|
|
8cbaf09b4f | ||
|
|
ee8d5dff66 | ||
|
|
ec0873f5a2 | ||
|
|
29515bfcd5 | ||
|
|
c85ebb0c1e | ||
|
|
d6e66d5c7f | ||
|
|
f65f2b229a | ||
|
|
5094351469 | ||
|
|
5d6a770ce8 | ||
|
|
010d7f9ce4 | ||
|
|
fb49e680a6 | ||
|
|
6b98856892 | ||
|
|
1a479a7199 | ||
|
|
2894bcd7ff | ||
|
|
1ae8040bd7 | ||
|
|
57a80084ce | ||
|
|
e35b4ea62c | ||
|
|
3546526177 | ||
|
|
12efb6166a | ||
|
|
9beee068ce | ||
|
|
9efcba5c02 | ||
|
|
947333ea64 | ||
|
|
7e527fc62a | ||
|
|
9f78c595b3 | ||
|
|
fa03442c85 | ||
|
|
e664c035a1 | ||
|
|
c522e3b054 | ||
|
|
b3c037ab21 | ||
|
|
097fdb643b | ||
|
|
43094a9897 | ||
|
|
aefa623cd4 | ||
|
|
1be11738eb | ||
|
|
5a09c116f6 | ||
|
|
bb700db08e | ||
|
|
2e8582b14c | ||
|
|
8d47dc2f82 | ||
|
|
6a3c736195 | ||
|
|
9463999325 | ||
|
|
e50c30eaaa | ||
|
|
45a3e21897 | ||
|
|
47dbcdff9c | ||
|
|
dc164f81e5 | ||
|
|
bab0ec8b60 | ||
|
|
f543e3f4e2 | ||
|
|
43d4b9abaa | ||
|
|
f5bbb6aef5 | ||
|
|
25b666c2ae | ||
|
|
78087073ac | ||
|
|
12c2ced497 | ||
|
|
87954419ba | ||
|
|
0add0bc2e9 | ||
|
|
7858afb837 | ||
|
|
69c0b2e223 | ||
|
|
855ca48220 | ||
|
|
02bee86397 | ||
|
|
315d466da8 | ||
|
|
d4597e0094 | ||
|
|
b8ff3414c0 | ||
|
|
2206cc1f78 | ||
|
|
00433467be | ||
|
|
1000e33e7f | ||
|
|
a64245fb5b | ||
|
|
2f784f00ff | ||
|
|
136012c558 | ||
|
|
874abf6442 | ||
|
|
20975957ee | ||
|
|
1fabae2870 | ||
|
|
abb3523ee3 | ||
|
|
ec63a06e25 | ||
|
|
8b4353f08c | ||
|
|
8bfb3b87c3 | ||
|
|
f1a493b999 | ||
|
|
3afcfa79e1 | ||
|
|
adaa436f6b | ||
|
|
37135762c5 | ||
|
|
e6aa7128df | ||
|
|
da8d4a290c | ||
|
|
4d11a727d9 | ||
|
|
3c232bfca0 | ||
|
|
b3fe96477a | ||
|
|
5f87544a0d | ||
|
|
f0c0ca4566 | ||
|
|
23719526cd | ||
|
|
67ffe22460 | ||
|
|
08996a3253 | ||
|
|
95e2f7665b | ||
|
|
a5ef2d1574 | ||
|
|
cc0a786004 | ||
|
|
4d6693d948 | ||
|
|
9c0792c5a0 | ||
|
|
0f06f47ab4 | ||
|
|
5371f854fc | ||
|
|
bd49f0f959 | ||
|
|
63d3071233 | ||
|
|
015a50bafd | ||
|
|
1ee4b9bd01 |
@@ -4,7 +4,7 @@ MAINTAINER = Marc Espie <espie@openbsd.org>
|
||||
CATEGORIES = multimedia
|
||||
COMMENT = closed caption subtitles extractor
|
||||
HOMEPAGE = http://ccextractor.sourceforge.net/
|
||||
V = 0.70
|
||||
V = 0.71
|
||||
DISTFILES = ccextractor.${V:S/.//}-src.zip
|
||||
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
|
||||
DISTNAME = ccextractor-$V
|
||||
|
||||
27
README.md
27
README.md
@@ -3,19 +3,18 @@ ccextractor
|
||||
|
||||
CCExtractor - Carlos' version (mainstream).
|
||||
|
||||
0.70 - GSOC
|
||||
GSOC - 0.72
|
||||
-----------
|
||||
This is the first release that is part of Google's Summer of Code.
|
||||
Anshul, Ruslan and Willem joined CCExtractor to work on a number of things
|
||||
over the summer, and their work is already reaching the mainstream
|
||||
version of CCExtractor.
|
||||
- Fix for WTV files with incorrect timing
|
||||
- Added support for fps change using data from AVC video track in a H264 TS file.
|
||||
|
||||
- Added a huge dictionary submitted by Matt Stockard.
|
||||
- Added DVB subtitles decoder, spupng in output
|
||||
- Added support for cdt2 media atoms in QT video files. Now multiple atoms in
|
||||
a single sample sequence are supported.
|
||||
- Changed Makefile.
|
||||
- Fixed some bugs.
|
||||
- Added feature to print info about file's subtitles and streams.
|
||||
- Support Long PMT.
|
||||
- Support Configuration file.
|
||||
GSOC - 0.71
|
||||
-----------
|
||||
- Added feature to receive captions in BIN format according to CCExtractor's own
|
||||
protocol over TCP (-tcp port [-tcppassword password])
|
||||
- Added ability to send captions to the server described above or to the
|
||||
online repository (-sendto host[:port])
|
||||
- Added -stdin parameter for reading input stream from standard input
|
||||
- Compilation in Cygwin using linux/Makefile
|
||||
- Code tested with coverity for defect density 0.42
|
||||
- Correction of mp4 timing, when one timestamp points timing of two atom
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
0.72 - GSOC
|
||||
-----------
|
||||
- Fix for WTV files with incorrect timing
|
||||
- Added support for fps change using data from AVC video track in a H264 TS file.
|
||||
|
||||
0.71 - GSOC
|
||||
-----------
|
||||
- Added feature to receive captions in BIN format according to CCExtractor's own
|
||||
protocol over TCP (-tcp port [-tcppassword password])
|
||||
- Added ability to send captions to the server described above or to the
|
||||
online repository (-sendto host[:port])
|
||||
- Added -stdin parameter for reading input stream from standard input
|
||||
- Compilation in Cygwin using linux/Makefile
|
||||
- Fix for .bin files when not using latin1 charset
|
||||
- Correction of mp4 timing, when one timestamp points timing of two atom
|
||||
|
||||
0.70 - GSOC
|
||||
-----------
|
||||
This is the first release that is part of Google's Summer of Code.
|
||||
@@ -37,6 +53,7 @@ version of CCExtractor.
|
||||
1111001 is the default setting for -ucla
|
||||
Make sure you use this parameter after others that might affect these
|
||||
settings (-out, -ucla, -xds, -txt, -ttxt, ...)
|
||||
- Fixed Negative timing Bug
|
||||
|
||||
0.69
|
||||
----
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ccextractor, 0.63
|
||||
ccextractor, 0.71
|
||||
-----------------
|
||||
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
|
||||
Maintainer: cfsmp3
|
||||
@@ -7,12 +7,17 @@ Lots of credit goes to other people, though:
|
||||
McPoodle (author of the original SCC_RIP), Neuron2, and others (see source
|
||||
code).
|
||||
|
||||
Home: http://ccextractor.sourceforge.net
|
||||
Home: http://www.ccextractor.org
|
||||
|
||||
You can subscribe to new releases notifications at freshmeat:
|
||||
|
||||
http://freshmeat.net/projects/ccextractor
|
||||
|
||||
Google Summer of Code 2014 students
|
||||
- Willem van iseghem
|
||||
- Ruslan KuchumoV
|
||||
- Anshul Maheshwari
|
||||
|
||||
License
|
||||
-------
|
||||
GPL 2.0.
|
||||
@@ -67,21 +72,18 @@ If there are Spanish subtitles, one of them should work.
|
||||
|
||||
McPoodle's page
|
||||
---------------
|
||||
http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
|
||||
http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
|
||||
|
||||
Essential CC related information and free (with source) tools.
|
||||
|
||||
Encoding
|
||||
--------
|
||||
This version, in both its Linux and Windows builds generates by
|
||||
default Latin-1 encoded files. You can use -unicode and -utf8
|
||||
if you prefer these encodings (usually it just depends on what
|
||||
your specific player likes).
|
||||
This has changed from the previous UTF-8 default which vobsub
|
||||
can't handle.
|
||||
default Unicode files. You can use -latin1 and -utf8 if you prefer
|
||||
these encodings (usually it just depends on what your specific
|
||||
player likes).
|
||||
|
||||
Future work
|
||||
-----------
|
||||
- Finish EIA-708 decoder
|
||||
- Network support
|
||||
- Please check www.ccextractor.org for news and future work.
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
SHELL = /bin/sh
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
||||
CFLAGS = -O3 -std=gnu99
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib
|
||||
ALL_FLAGS = -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm -zmuldefs
|
||||
ALL_FLAGS = -Wno-write-strings -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm
|
||||
|
||||
TARGET = ccextractor
|
||||
|
||||
@@ -49,7 +48,7 @@ objs_dir:
|
||||
mkdir -p $(OBJS_DIR)
|
||||
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB)
|
||||
$(CXX) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJS_DIR)/%.o: %.c
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@
|
||||
@@ -74,7 +73,7 @@ uninstall:
|
||||
|
||||
.PHONY: depend dep
|
||||
depend dep:
|
||||
$(CXX) $(CXXFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) \
|
||||
$(CC) $(CFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) \
|
||||
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
|
||||
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
g++ -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I../src/gpacmp4 -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c')
|
||||
gcc -std=gnu99 -Wno-write-strings -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I../src/gpacmp4 -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c')
|
||||
|
||||
633
src/608.c
633
src/608.c
@@ -1,16 +1,13 @@
|
||||
#include "ccextractor.h"
|
||||
#include "608_spupng.h"
|
||||
#include "cc_decoders_common.h"
|
||||
#include "utility.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
|
||||
int in_xds_mode=0;
|
||||
|
||||
#define INITIAL_ENC_BUFFER_CAPACITY 2048
|
||||
|
||||
unsigned char *enc_buffer=NULL; // Generic general purpose buffer
|
||||
unsigned char str[2048]; // Another generic general purpose buffer
|
||||
unsigned enc_buffer_used;
|
||||
unsigned enc_buffer_capacity;
|
||||
|
||||
LLONG minimum_fts=0; // No screen should start before this FTS
|
||||
const unsigned char pac2_attribs[][3] = // Color, font, ident
|
||||
@@ -48,16 +45,6 @@ const unsigned char pac2_attribs[][3] = // Color, font, ident
|
||||
{ COL_WHITE, FONT_REGULAR, 28 }, // 0x5e || 0x7e
|
||||
{ COL_WHITE, FONT_UNDERLINED, 28 } // 0x5f || 0x7f
|
||||
};
|
||||
|
||||
int general_608_init (void)
|
||||
{
|
||||
enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY);
|
||||
if (enc_buffer==NULL)
|
||||
return -1;
|
||||
enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
@@ -71,24 +58,6 @@ int new_sentence=1; // Capitalize next letter?
|
||||
unsigned char usercolor_rgb[8]="";
|
||||
|
||||
|
||||
static const char *sami_header= // TODO: Revise the <!-- comments
|
||||
"<SAMI>\n\
|
||||
<HEAD>\n\
|
||||
<STYLE TYPE=\"text/css\">\n\
|
||||
<!--\n\
|
||||
P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
|
||||
text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
|
||||
.UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
|
||||
-->\n\
|
||||
</STYLE>\n\
|
||||
</HEAD>\n\n\
|
||||
<BODY>\n";
|
||||
|
||||
static const char *smptett_header =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\
|
||||
<tt xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n\
|
||||
<body>\n<div>\n" ;
|
||||
|
||||
static const char *command_type[] =
|
||||
{
|
||||
"Unknown",
|
||||
@@ -166,7 +135,6 @@ void init_context_cc608(struct s_context_cc608 *data, int field)
|
||||
data->mode=MODE_POPON;
|
||||
// data->current_visible_start_cc=0;
|
||||
data->current_visible_start_ms=0;
|
||||
data->srt_counter=0;
|
||||
data->screenfuls_counter=0;
|
||||
data->channel=1;
|
||||
data->color=ccx_options.cc608_default_color;
|
||||
@@ -282,187 +250,6 @@ void handle_text_attr(const unsigned char c1, const unsigned char c2, struct s_c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void write_subtitle_file_footer(struct ccx_s_write *out)
|
||||
{
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SAMI:
|
||||
sprintf ((char *) str,"</BODY></SAMI>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(out->fh, enc_buffer, enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
sprintf ((char *) str,"</div></body></tt>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (out->fh, enc_buffer,enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_footer(out);
|
||||
break;
|
||||
default: // Nothing to do, no footer on this format
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void write_subtitle_file_header(struct ccx_s_write *out)
|
||||
{
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT: // Subrip subtitles have no header
|
||||
break;
|
||||
case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI
|
||||
//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 (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(out->fh, enc_buffer, enc_buffer_used);
|
||||
break;
|
||||
case CCX_OF_RCWT: // Write header
|
||||
write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_header(out);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT: // No header. Fall thru
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_cc_line_as_transcript(struct eia608_screen *data, struct s_context_cc608 *context, int line_number)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
if (ccx_options.sentence_cap)
|
||||
{
|
||||
capitalize (line_number,data);
|
||||
correct_case(line_number,data);
|
||||
}
|
||||
int length = get_decoder_line_basic (subline, line_number, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
if (length>0)
|
||||
{
|
||||
if (context->ts_start_of_current_line == -1)
|
||||
{
|
||||
// CFS: Means that the line has characters but we don't have a timestamp for the first one. Since the timestamp
|
||||
// is set for example by the write_char function, it possible that we don't have one in empty lines (unclear)
|
||||
// For now, let's not consider this a bug as before and just return.
|
||||
// fatal (EXIT_BUG_BUG, "Bug in timedtranscript (ts_start_of_current_line==-1). Please report.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showStartTime){
|
||||
char buf1[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
millis_to_date(context->ts_start_of_current_line + subs_delay, buf1);
|
||||
fdprintf(context->out->fh, "%s|", buf1);
|
||||
}
|
||||
else {
|
||||
mstotime(context->ts_start_of_current_line + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (context->ts_start_of_current_line + subs_delay) / 1000;
|
||||
int start_time_dec = (context->ts_start_of_current_line + subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showEndTime){
|
||||
char buf2[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
millis_to_date(get_fts() + subs_delay, buf2);
|
||||
fdprintf(context->out->fh, "%s|", buf2);
|
||||
}
|
||||
else {
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = (get_fts() + subs_delay) / 1000;
|
||||
int end_time_dec = (get_fts() + subs_delay) % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showCC){
|
||||
fdprintf(context->out->fh, "CC%d|", context->my_field == 1 ? context->channel : context->channel + 2); // Data from field 2 is CC3 or 4
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showMode){
|
||||
const char *mode = "???";
|
||||
switch (context->mode)
|
||||
{
|
||||
case MODE_POPON:
|
||||
mode = "POP";
|
||||
break;
|
||||
case MODE_FAKE_ROLLUP_1:
|
||||
mode = "RU1";
|
||||
break;
|
||||
case MODE_ROLLUP_2:
|
||||
mode = "RU2";
|
||||
break;
|
||||
case MODE_ROLLUP_3:
|
||||
mode = "RU3";
|
||||
break;
|
||||
case MODE_ROLLUP_4:
|
||||
mode = "RU4";
|
||||
break;
|
||||
case MODE_TEXT:
|
||||
mode = "TXT";
|
||||
break;
|
||||
case MODE_PAINTON:
|
||||
mode = "PAI";
|
||||
break;
|
||||
}
|
||||
|
||||
fdprintf(context->out->fh, "%s|", mode);
|
||||
}
|
||||
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_transcript(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
int wrote_something = 0;
|
||||
context->ts_start_of_current_line = context->current_visible_start_ms;
|
||||
dbg_print(CCX_DMT_608, "\n- - - TRANSCRIPT caption - - -\n");
|
||||
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
write_cc_line_as_transcript (data,context, i);
|
||||
}
|
||||
wrote_something=1;
|
||||
}
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
return wrote_something;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct eia608_screen *get_current_visible_buffer(struct s_context_cc608 *context)
|
||||
{
|
||||
struct eia608_screen *data;
|
||||
@@ -473,11 +260,14 @@ struct eia608_screen *get_current_visible_buffer(struct s_context_cc608 *context
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
int write_cc_buffer(struct s_context_cc608 *context)
|
||||
int write_cc_buffer(struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
struct eia608_screen *data;
|
||||
int wrote_something=0;
|
||||
LLONG start_time;
|
||||
LLONG end_time;
|
||||
|
||||
|
||||
if (ccx_options.screens_to_process!=-1 &&
|
||||
context->screenfuls_counter >= ccx_options.screens_to_process)
|
||||
{
|
||||
@@ -485,52 +275,124 @@ int write_cc_buffer(struct s_context_cc608 *context)
|
||||
processed_enough=1;
|
||||
return 0;
|
||||
}
|
||||
if (context->visible_buffer == 1)
|
||||
data = &context->buffer1;
|
||||
else
|
||||
data = &context->buffer2;
|
||||
|
||||
data = get_current_visible_buffer(context);
|
||||
|
||||
if (context->mode == MODE_FAKE_ROLLUP_1 && // Use the actual start of data instead of last buffer change
|
||||
context->ts_start_of_current_line != -1)
|
||||
context->current_visible_start_ms = context->ts_start_of_current_line;
|
||||
|
||||
start_time = context->current_visible_start_ms;
|
||||
end_time = get_visible_end() + subs_delay;
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_SCREEN;
|
||||
data->start_time = 0;
|
||||
data->end_time = 0;
|
||||
data->mode = context->mode;
|
||||
data->channel = context->channel;
|
||||
data->my_field = context->my_field;
|
||||
|
||||
if (!data->empty)
|
||||
{
|
||||
if (context->mode == MODE_FAKE_ROLLUP_1 && // Use the actual start of data instead of last buffer change
|
||||
context->ts_start_of_current_line != -1)
|
||||
context->current_visible_start_ms = context->ts_start_of_current_line;
|
||||
|
||||
new_sentence=1;
|
||||
switch (ccx_options.write_format)
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
|
||||
if (!sub->data)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context);
|
||||
wrote_something = write_cc_buffer_as_srt(data, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context);
|
||||
wrote_something = write_cc_buffer_as_sami(data, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context);
|
||||
wrote_something = write_cc_buffer_as_smptett(data, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_buffer_as_transcript(data, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_buffer_as_spupng(data, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
mprint("No Memory left");
|
||||
return 0;
|
||||
}
|
||||
if (wrote_something)
|
||||
last_displayed_subs_ms=get_fts()+subs_delay;
|
||||
|
||||
if (ccx_options.gui_mode_reports)
|
||||
write_cc_buffer_to_gui(data, context);
|
||||
memcpy(((struct eia608_screen *)sub->data) + sub->nb_data, data, sizeof(*data));
|
||||
sub->nb_data++;
|
||||
wrote_something = 1;
|
||||
if(start_time < end_time)
|
||||
{
|
||||
int i = 0;
|
||||
int nb_data = sub->nb_data;
|
||||
data = (struct eia608_screen *)sub->data;
|
||||
for(i = 0; i < sub->nb_data; i++)
|
||||
{
|
||||
if(!data->start_time)
|
||||
break;
|
||||
nb_data--;
|
||||
data++;
|
||||
}
|
||||
for(i = 0; i < nb_data; i++)
|
||||
{
|
||||
data->start_time = start_time + ( ( (end_time - start_time)/nb_data ) * i );
|
||||
data->end_time = start_time + ( ( (end_time - start_time)/nb_data ) * (i + 1) );
|
||||
data++;
|
||||
}
|
||||
sub->got_output = 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return wrote_something;
|
||||
}
|
||||
int write_cc_line(struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
struct eia608_screen *data;
|
||||
LLONG start_time;
|
||||
LLONG end_time;
|
||||
int i = 0;
|
||||
int wrote_something=0;
|
||||
int ret = 0;
|
||||
data = get_current_visible_buffer(context);
|
||||
|
||||
start_time = context->ts_start_of_current_line + subs_delay;
|
||||
end_time = get_fts() + subs_delay;
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_LINE;
|
||||
data->start_time = 0;
|
||||
data->end_time = 0;
|
||||
data->mode = context->mode;
|
||||
data->channel = context->channel;
|
||||
data->my_field = context->my_field;
|
||||
|
||||
ret = get_decoder_line_basic (subline, context->cursor_row, data);
|
||||
if( ret > 0 )
|
||||
{
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data,(sub->nb_data +1) * sizeof(*data));
|
||||
if (!sub->data)
|
||||
{
|
||||
mprint("No Memory left");
|
||||
return 0;
|
||||
}
|
||||
memcpy(((struct eia608_screen *)sub->data) + sub->nb_data, data, sizeof(*data));
|
||||
data = (struct eia608_screen *)sub->data + sub->nb_data;
|
||||
sub->nb_data++;
|
||||
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
if(i == context->cursor_row)
|
||||
data->row_used[i] = 1;
|
||||
else
|
||||
data->row_used[i] = 0;
|
||||
}
|
||||
wrote_something = 1;
|
||||
if(start_time < end_time)
|
||||
{
|
||||
int nb_data = sub->nb_data;
|
||||
data = (struct eia608_screen *)sub->data;
|
||||
for(i = 0; i < sub->nb_data; i++)
|
||||
{
|
||||
if(!data->start_time)
|
||||
break;
|
||||
nb_data--;
|
||||
data++;
|
||||
}
|
||||
for(i = 0; i < nb_data; i++)
|
||||
{
|
||||
data->start_time = start_time + ( ( (end_time - start_time)/nb_data ) * i );
|
||||
data->end_time = start_time + ( ( (end_time - start_time)/nb_data ) * (i + 1) );
|
||||
data++;
|
||||
}
|
||||
sub->got_output = 1;
|
||||
}
|
||||
}
|
||||
return wrote_something;
|
||||
|
||||
}
|
||||
|
||||
// Check if a rollup would cause a line to go off the visible area
|
||||
int check_roll_up(struct s_context_cc608 *context)
|
||||
@@ -715,7 +577,7 @@ int is_current_row_empty(struct s_context_cc608 *context)
|
||||
}
|
||||
|
||||
/* Process GLOBAL CODES */
|
||||
void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct s_context_cc608 *context)
|
||||
void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
int changes=0;
|
||||
|
||||
@@ -812,7 +674,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
/* CEA-608 C.10 Style Switching (regulatory)
|
||||
[...]if pop-up or paint-on captioning is already present in
|
||||
either memory it shall be erased[...] */
|
||||
if (write_cc_buffer(context))
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
erase_memory(context, true);
|
||||
}
|
||||
@@ -859,7 +721,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
}
|
||||
if (ccx_options.write_format==CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
write_cc_line_as_transcript(get_current_visible_buffer(context), context, context->cursor_row);
|
||||
write_cc_line(context,sub);
|
||||
}
|
||||
|
||||
// In transcript mode, CR doesn't write the whole screen, to avoid
|
||||
@@ -870,7 +732,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
// Only if the roll up would actually cause a line to disappear we write the buffer
|
||||
if (ccx_options.write_format!=CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
if (write_cc_buffer(context))
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
if (ccx_options.norollup)
|
||||
erase_memory(context, true); // Make sure the lines we just wrote aren't written again
|
||||
@@ -897,11 +759,13 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
// In transcript mode we just write the cursor line. The previous lines
|
||||
// should have been written already, so writing everything produces
|
||||
// duplicate lines.
|
||||
write_cc_line_as_transcript(get_current_visible_buffer(context), context, context->cursor_row);
|
||||
write_cc_line(context, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (write_cc_buffer(context))
|
||||
if (ccx_options.write_format==CCX_OF_TRANSCRIPT)
|
||||
context->ts_start_of_current_line = context->current_visible_start_ms;
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
}
|
||||
erase_memory(context, true);
|
||||
@@ -910,7 +774,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
case COM_ENDOFCAPTION: // Switch buffers
|
||||
// The currently *visible* buffer is leaving, so now we know its ending
|
||||
// time. Time to actually write it to file.
|
||||
if (write_cc_buffer(context))
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
context->visible_buffer = (context->visible_buffer == 1) ? 2 : 1;
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
@@ -942,11 +806,11 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, struct
|
||||
|
||||
}
|
||||
|
||||
void handle_end_of_data(struct s_context_cc608 *context)
|
||||
void handle_end_of_data(struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
// We issue a EraseDisplayedMemory here so if there's any captions pending
|
||||
// they get written to file.
|
||||
handle_command (0x14, 0x2c, context); // EDM
|
||||
// they get written to Subtitle.
|
||||
handle_command (0x14, 0x2c, context, sub); // EDM
|
||||
}
|
||||
|
||||
// CEA-608, Anex F 1.1.1. - Character Set Table / Special Characters
|
||||
@@ -1083,13 +947,13 @@ void handle_single(const unsigned char c1, struct s_context_cc608 *context)
|
||||
write_char (c1,context);
|
||||
}
|
||||
|
||||
void erase_both_memories(struct s_context_cc608 *context)
|
||||
void erase_both_memories(struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
erase_memory(context, false);
|
||||
// For the visible memory, we write the contents to disk
|
||||
// The currently *visible* buffer is leaving, so now we know its ending
|
||||
// time. Time to actually write it to file.
|
||||
if (write_cc_buffer(context))
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->cursor_column = 0;
|
||||
@@ -1123,7 +987,7 @@ int check_channel(unsigned char c1, struct s_context_cc608 *context)
|
||||
/* Handle Command, special char or attribute and also check for
|
||||
* channel changes.
|
||||
* Returns 1 if something was written to screen, 0 otherwise */
|
||||
int disCommand(unsigned char hi, unsigned char lo, struct s_context_cc608 *context)
|
||||
int disCommand(unsigned char hi, unsigned char lo, struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
int wrote_to_screen=0;
|
||||
|
||||
@@ -1169,7 +1033,7 @@ int disCommand(unsigned char hi, unsigned char lo, struct s_context_cc608 *conte
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
if (lo>=0x20 && lo<=0x2f)
|
||||
handle_command(hi, lo, context);
|
||||
handle_command(hi, lo, context, sub);
|
||||
if (lo>=0x40 && lo<=0x7f)
|
||||
handle_pac(hi, lo, context);
|
||||
break;
|
||||
@@ -1179,7 +1043,7 @@ int disCommand(unsigned char hi, unsigned char lo, struct s_context_cc608 *conte
|
||||
break;
|
||||
case 0x17:
|
||||
if (lo>=0x21 && lo<=0x23)
|
||||
handle_command(hi, lo, context);
|
||||
handle_command(hi, lo, context, sub);
|
||||
if (lo>=0x2e && lo<=0x2f)
|
||||
handle_text_attr(hi, lo, context);
|
||||
if (lo>=0x40 && lo<=0x7f)
|
||||
@@ -1190,139 +1054,144 @@ int disCommand(unsigned char hi, unsigned char lo, struct s_context_cc608 *conte
|
||||
}
|
||||
|
||||
/* If wb is NULL, then only XDS will be processed */
|
||||
void process608(const unsigned char *data, int length, struct s_context_cc608 *context)
|
||||
int process608(const unsigned char *data, int length, struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
static int textprinted = 0;
|
||||
int i;
|
||||
if (context)
|
||||
context->bytes_processed_608 += length;
|
||||
if (data!=NULL)
|
||||
if (!data)
|
||||
{
|
||||
for (int i=0;i<length;i=i+2)
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i < length; i=i+2)
|
||||
{
|
||||
unsigned char hi, lo;
|
||||
int wrote_to_screen=0;
|
||||
|
||||
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;
|
||||
|
||||
// printf ("\r[%02X:%02X]\n",hi,lo);
|
||||
|
||||
if (hi>=0x10 && hi<=0x1e) {
|
||||
int ch = (hi<=0x17)? 1 : 2;
|
||||
if (current_field == 2)
|
||||
ch+=2;
|
||||
|
||||
file_report.cc_channels_608[ch - 1] = 1;
|
||||
}
|
||||
|
||||
if (hi >= 0x01 && hi <= 0x0E && (context == NULL || context->my_field == 2)) // XDS can only exist in field 2.
|
||||
{
|
||||
unsigned char hi, lo;
|
||||
int wrote_to_screen=0;
|
||||
if (context)
|
||||
context->channel = 3;
|
||||
if (!in_xds_mode)
|
||||
{
|
||||
ts_start_of_xds=get_fts();
|
||||
in_xds_mode=1;
|
||||
}
|
||||
|
||||
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
|
||||
file_report.xds=1;
|
||||
}
|
||||
if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block
|
||||
{
|
||||
in_xds_mode=0;
|
||||
do_end_of_xds (sub, lo);
|
||||
if (context)
|
||||
context->channel = context->new_channel; // Switch from channel 3
|
||||
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 (textprinted == 1 )
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\n");
|
||||
textprinted = 0;
|
||||
}
|
||||
if (!context || context->my_field == 2)
|
||||
in_xds_mode=0; // Back to normal (CEA 608-8.6.2)
|
||||
if (!context) // Not XDS and we don't have a writebuffer, nothing else would have an effect
|
||||
continue;
|
||||
|
||||
// printf ("\r[%02X:%02X]\n",hi,lo);
|
||||
|
||||
if (hi>=0x10 && hi<=0x1e) {
|
||||
int ch = (hi<=0x17)? 1 : 2;
|
||||
if (current_field == 2)
|
||||
ch+=2;
|
||||
|
||||
file_report.cc_channels_608[ch - 1] = 1;
|
||||
}
|
||||
|
||||
if (hi >= 0x01 && hi <= 0x0E && (context == NULL || context->my_field == 2)) // XDS can only exist in field 2.
|
||||
if (context->last_c1 == hi && context->last_c2 == lo)
|
||||
{
|
||||
if (context)
|
||||
context->channel = 3;
|
||||
if (!in_xds_mode)
|
||||
{
|
||||
ts_start_of_xds=get_fts();
|
||||
in_xds_mode=1;
|
||||
}
|
||||
|
||||
file_report.xds=1;
|
||||
}
|
||||
if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block
|
||||
{
|
||||
in_xds_mode=0;
|
||||
do_end_of_xds (lo);
|
||||
if (context)
|
||||
context->channel = context->new_channel; // Switch from channel 3
|
||||
// Duplicate dual code, discard. Correct to do it only in
|
||||
// non-XDS, XDS codes shall not be repeated.
|
||||
dbg_print(CCX_DMT_608, "Skipping command %02X,%02X Duplicate\n", hi, lo);
|
||||
// Ignore only the first repetition
|
||||
context->last_c1=-1;
|
||||
context->last_c2 = -1;
|
||||
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
|
||||
context->last_c1 = hi;
|
||||
context->last_c2 = lo;
|
||||
wrote_to_screen = disCommand(hi, lo, context, sub);
|
||||
if(sub->got_output)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_xds_mode && (context == NULL || context->my_field == 2))
|
||||
{
|
||||
// We were writing characters before, start a new line for
|
||||
// diagnostic output from disCommand()
|
||||
if (textprinted == 1 )
|
||||
process_xds_bytes (hi,lo);
|
||||
continue;
|
||||
}
|
||||
if (!context) // No XDS code after this point, and user doesn't want captions.
|
||||
continue;
|
||||
|
||||
context->last_c1 = -1;
|
||||
context->last_c2 = -1;
|
||||
|
||||
if (hi>=0x20) // Standard characters (always in pairs)
|
||||
{
|
||||
// Only print if the channel is active
|
||||
if (context->channel != ccx_options.cc_channel)
|
||||
continue;
|
||||
|
||||
if( textprinted == 0 )
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\n");
|
||||
textprinted = 0;
|
||||
textprinted = 1;
|
||||
}
|
||||
if (!context || context->my_field == 2)
|
||||
in_xds_mode=0; // Back to normal (CEA 608-8.6.2)
|
||||
if (!context) // Not XDS and we don't have a writebuffer, nothing else would have an effect
|
||||
continue;
|
||||
if (context->last_c1 == hi && context->last_c2 == lo)
|
||||
{
|
||||
// Duplicate dual code, discard. Correct to do it only in
|
||||
// non-XDS, XDS codes shall not be repeated.
|
||||
dbg_print(CCX_DMT_608, "Skipping command %02X,%02X Duplicate\n", hi, lo);
|
||||
// Ignore only the first repetition
|
||||
context->last_c1=-1;
|
||||
context->last_c2 = -1;
|
||||
continue;
|
||||
}
|
||||
context->last_c1 = hi;
|
||||
context->last_c2 = lo;
|
||||
wrote_to_screen = disCommand(hi, lo, context);
|
||||
|
||||
handle_single(hi, context);
|
||||
handle_single(lo, context);
|
||||
wrote_to_screen=1;
|
||||
context->last_c1 = 0;
|
||||
context->last_c2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_xds_mode && (context == NULL || context->my_field == 2))
|
||||
{
|
||||
process_xds_bytes (hi,lo);
|
||||
continue;
|
||||
}
|
||||
if (!context) // No XDS code after this point, and user doesn't want captions.
|
||||
continue;
|
||||
|
||||
context->last_c1 = -1;
|
||||
context->last_c2 = -1;
|
||||
if (!textprinted && context->channel == ccx_options.cc_channel)
|
||||
{ // Current FTS information after the characters are shown
|
||||
dbg_print(CCX_DMT_608, "Current FTS: %s\n", print_mstime(get_fts()));
|
||||
//printf(" N:%u", unsigned(fts_now) );
|
||||
//printf(" G:%u", unsigned(fts_global) );
|
||||
//printf(" F:%d %d %d %d\n",
|
||||
// current_field, cb_field1, cb_field2, cb_708 );
|
||||
}
|
||||
|
||||
if (hi>=0x20) // Standard characters (always in pairs)
|
||||
{
|
||||
// Only print if the channel is active
|
||||
if (context->channel != ccx_options.cc_channel)
|
||||
continue;
|
||||
|
||||
if( textprinted == 0 )
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\n");
|
||||
textprinted = 1;
|
||||
}
|
||||
|
||||
handle_single(hi, context);
|
||||
handle_single(lo, context);
|
||||
wrote_to_screen=1;
|
||||
context->last_c1 = 0;
|
||||
context->last_c2 = 0;
|
||||
}
|
||||
|
||||
if (!textprinted && context->channel == ccx_options.cc_channel)
|
||||
{ // Current FTS information after the characters are shown
|
||||
dbg_print(CCX_DMT_608, "Current FTS: %s\n", print_mstime(get_fts()));
|
||||
//printf(" N:%u", unsigned(fts_now) );
|
||||
//printf(" G:%u", unsigned(fts_global) );
|
||||
//printf(" F:%d %d %d %d\n",
|
||||
// current_field, cb_field1, cb_field2, cb_708 );
|
||||
}
|
||||
|
||||
if (wrote_to_screen && ccx_options.direct_rollup && // If direct_rollup is enabled and
|
||||
if (wrote_to_screen && ccx_options.direct_rollup && // If direct_rollup is enabled and
|
||||
(context->mode == MODE_FAKE_ROLLUP_1 || // we are in rollup mode, write now.
|
||||
context->mode == MODE_ROLLUP_2 ||
|
||||
context->mode == MODE_ROLLUP_3 ||
|
||||
context->mode == MODE_ROLLUP_4))
|
||||
{
|
||||
// We don't increase screenfuls_counter here.
|
||||
write_cc_buffer(context);
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
}
|
||||
context->mode == MODE_ROLLUP_2 ||
|
||||
context->mode == MODE_ROLLUP_3 ||
|
||||
context->mode == MODE_ROLLUP_4))
|
||||
{
|
||||
// We don't increase screenfuls_counter here.
|
||||
write_cc_buffer(context, sub);
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
}
|
||||
if (wrote_to_screen && cc_to_stdout)
|
||||
fflush (stdout);
|
||||
} // for
|
||||
}
|
||||
}
|
||||
if (wrote_to_screen && cc_to_stdout)
|
||||
fflush (stdout);
|
||||
} // for
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
51
src/608.h
51
src/608.h
@@ -12,13 +12,42 @@ enum cc_modes
|
||||
MODE_FAKE_ROLLUP_1 = 100
|
||||
};
|
||||
|
||||
enum ccx_eia608_format
|
||||
{
|
||||
SFORMAT_CC_SCREEN,
|
||||
SFORMAT_CC_LINE,
|
||||
SFORMAT_XDS
|
||||
};
|
||||
/**
|
||||
* This structure have fields which need to be ignored according to format,
|
||||
* for example if format is SFORMAT_XDS then all fields other then
|
||||
* xds related (xds_str, xds_len and cur_xds_packet_class) should be
|
||||
* ignored and not to be derefrenced.
|
||||
*
|
||||
* TODO use union inside struct for each kind of fields
|
||||
*/
|
||||
struct eia608_screen // A CC buffer
|
||||
{
|
||||
/** format of data inside this structure */
|
||||
enum ccx_eia608_format format;
|
||||
unsigned char characters[15][33];
|
||||
unsigned char colors[15][33];
|
||||
unsigned char fonts[15][33]; // Extra char at the end for a 0
|
||||
int row_used[15]; // Any data in row?
|
||||
int empty; // Buffer completely empty?
|
||||
int empty; // Buffer completely empty?
|
||||
/** start time of this CC buffer */
|
||||
LLONG start_time;
|
||||
/** end time of this CC buffer */
|
||||
LLONG end_time;
|
||||
enum cc_modes mode;
|
||||
int channel; // Currently selected channel
|
||||
int my_field; // Used for sanity checks
|
||||
/** XDS string */
|
||||
char *xds_str;
|
||||
/** length of XDS string */
|
||||
size_t xds_len;
|
||||
/** Class of XDS string */
|
||||
int cur_xds_packet_class;
|
||||
};
|
||||
|
||||
struct s_context_cc608
|
||||
@@ -27,10 +56,8 @@ struct s_context_cc608
|
||||
struct eia608_screen buffer2;
|
||||
int cursor_row, cursor_column;
|
||||
int visible_buffer;
|
||||
int srt_counter; // Number of subs currently written
|
||||
int screenfuls_counter; // Number of meaningful screenfuls written
|
||||
LLONG current_visible_start_ms; // At what time did the current visible buffer became so?
|
||||
// unsigned current_visible_start_cc; // At what time did the current visible buffer became so?
|
||||
enum cc_modes mode;
|
||||
unsigned char last_c1, last_c2;
|
||||
int channel; // Currently selected channel
|
||||
@@ -54,15 +81,9 @@ extern unsigned enc_buffer_capacity;
|
||||
extern int new_sentence;
|
||||
extern const char *color_text[][2];
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_srt(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
void capitalize (int line_num, struct eia608_screen *data);
|
||||
void correct_case (int line_num, struct eia608_screen *data);
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
void correct_case (int line_num, struct eia608_screen *data);
|
||||
void capitalize (int line_num, struct eia608_screen *data);
|
||||
void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank);
|
||||
@@ -70,12 +91,7 @@ unsigned get_decoder_line_basic (unsigned char *buffer, int line_num, struct eia
|
||||
unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
void delete_all_lines_but_current (struct eia608_screen *data, int row);
|
||||
void try_to_add_start_credits(struct s_context_cc608 *context);
|
||||
void try_to_add_end_credits(struct s_context_cc608 *context);
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
|
||||
void handle_end_of_data(struct s_context_cc608 *context);
|
||||
void process608(const unsigned char *data, int length, struct s_context_cc608 *context);
|
||||
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c);
|
||||
void get_char_in_unicode (unsigned char *buffer, unsigned char c);
|
||||
int get_char_in_utf_8 (unsigned char *buffer, unsigned char c);
|
||||
@@ -86,12 +102,11 @@ LLONG get_visible_end (void);
|
||||
|
||||
#define CC608_SCREEN_WIDTH 32
|
||||
|
||||
#define REQUEST_BUFFER_CAPACITY(length) if (length>enc_buffer_capacity) \
|
||||
{enc_buffer_capacity=length*2; enc_buffer=(unsigned char*) realloc (enc_buffer, enc_buffer_capacity); \
|
||||
if (enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
|
||||
#define REQUEST_BUFFER_CAPACITY(ctx,length) if (length>ctx->capacity) \
|
||||
{ctx->capacity=length*2; ctx->buffer=(unsigned char*) realloc (ctx->buffer, ctx->capacity); \
|
||||
if (ctx->buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
|
||||
}
|
||||
|
||||
|
||||
enum color_code
|
||||
{
|
||||
COL_WHITE = 0,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ccextractor.h"
|
||||
#include "utility.h"
|
||||
#include "cc_encoders_common.h"
|
||||
//extern unsigned char encoded_crlf[16];
|
||||
|
||||
// Encodes a generic string. Note that since we use the encoders for closed caption
|
||||
@@ -288,15 +289,15 @@ void delete_all_lines_but_current (struct eia608_screen *data, int row)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fprintf_encoded (FILE *fh, const char *string)
|
||||
void fprintf_encoded (struct encoder_ctx *ctx,FILE *fh, const char *string)
|
||||
{
|
||||
REQUEST_BUFFER_CAPACITY(strlen (string)*3);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) string);
|
||||
fwrite (enc_buffer,enc_buffer_used,1,fh);
|
||||
int used;
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (string)*3);
|
||||
used=encode_line (ctx->buffer,(unsigned char *) string);
|
||||
fwrite (ctx->buffer,used,1,fh);
|
||||
}
|
||||
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
@@ -311,7 +312,7 @@ void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *
|
||||
if (!with_data)
|
||||
return;
|
||||
|
||||
ms_start= context->current_visible_start_ms;
|
||||
ms_start= data->start_time;
|
||||
|
||||
ms_start+=subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
@@ -324,7 +325,7 @@ void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *
|
||||
fprintf (stderr, "###SUBTITLE#");
|
||||
if (!time_reported)
|
||||
{
|
||||
LLONG ms_end = get_fts()+subs_delay;
|
||||
LLONG ms_end = data->end_time;
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
// Note, only MM:SS here as we need to save space in the preview window
|
||||
@@ -344,95 +345,3 @@ void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *
|
||||
}
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
void try_to_add_end_credits(struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG window, length, st, end;
|
||||
if (context->out->fh == -1)
|
||||
return;
|
||||
window=get_fts()-last_displayed_subs_ms-1;
|
||||
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
|
||||
return;
|
||||
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.endcreditsforatmost.time_in_ms;
|
||||
|
||||
st=get_fts()-length-1;
|
||||
end=get_fts();
|
||||
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.end_credits_text, context, st, end);
|
||||
break ;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void try_to_add_start_credits(struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG st, end, window, length;
|
||||
LLONG l = context->current_visible_start_ms + subs_delay;
|
||||
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
|
||||
|
||||
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
|
||||
return;
|
||||
|
||||
if (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
|
||||
return;
|
||||
|
||||
st = ccx_options.startcreditsnotbefore.time_in_ms>(last_displayed_subs_ms+1) ?
|
||||
ccx_options.startcreditsnotbefore.time_in_ms : (last_displayed_subs_ms+1); // When would credits actually start
|
||||
|
||||
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
|
||||
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
|
||||
|
||||
window = end-st; // Allowable time in MS
|
||||
|
||||
if (ccx_options.startcreditsforatleast.time_in_ms>window) // Window is too short
|
||||
return;
|
||||
|
||||
length=ccx_options.startcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.startcreditsforatmost.time_in_ms;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
|
||||
last_displayed_subs_ms, l);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
|
||||
ccx_options.startcreditsnotbefore.time_in_ms,
|
||||
ccx_options.startcreditsnotafter.time_in_ms);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Start of window: %lld End of window: %lld\n",st,end);
|
||||
|
||||
if (window>length+2)
|
||||
{
|
||||
// Center in time window
|
||||
LLONG pad=window-length;
|
||||
st+=(pad/2);
|
||||
}
|
||||
end=st+length;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.start_credits_text,context,st,end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
startcredits_displayed=1;
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
|
||||
189
src/608_sami.c
189
src/608_sami.c
@@ -1,7 +1,12 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
#include "cc_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)ms_start);
|
||||
@@ -9,8 +14,9 @@ void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG
|
||||
{
|
||||
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);
|
||||
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
@@ -56,8 +62,8 @@ void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG
|
||||
{
|
||||
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);
|
||||
used=encode_line (context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)ms_end);
|
||||
@@ -65,23 +71,170 @@ void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG
|
||||
{
|
||||
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(context->out->fh, context->buffer, used);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start + subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time + subs_delay;
|
||||
ms_end = sub->end_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *token = NULL;
|
||||
sprintf(context->buffer,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
|
||||
,(unsigned long long)ms_start);
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
token = strtok(str,"\r\n");
|
||||
while (token)
|
||||
{
|
||||
|
||||
sprintf(context->buffer,"%s",token);
|
||||
token = strtok(NULL,"\r\n");
|
||||
if(token)
|
||||
strcat(context->buffer,"<br>\n");
|
||||
else
|
||||
strcat(context->buffer,"\n");
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
|
||||
}
|
||||
sprintf(context->buffer,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n"
|
||||
,(unsigned long long)ms_end);
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
LLONG startms, endms;
|
||||
int wrote_something=0;
|
||||
startms = context->current_visible_start_ms;
|
||||
startms = data->start_time;
|
||||
|
||||
startms+=subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = get_visible_end()+subs_delay;
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
@@ -90,8 +243,8 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
@@ -114,8 +267,8 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)endms);
|
||||
@@ -123,7 +276,7 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
return wrote_something;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#include "ccextractor.h"
|
||||
#include "cc_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
|
||||
// Produces minimally-compliant SMPTE Timed Text (W3C TTML)
|
||||
// format-compatible output
|
||||
@@ -22,8 +27,9 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
|
||||
@@ -35,8 +41,8 @@ void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLO
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
@@ -82,33 +88,168 @@ void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLO
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\">\n\n",h2,m2,s2,ms2);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
free(el);
|
||||
free(unescaped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start + subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time + subs_delay;
|
||||
ms_end = sub->end_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
sprintf ((char *) context->buffer,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
write (context->out->fh, context->buffer,strlen(context->buffer) );
|
||||
len = strlen(str);
|
||||
write (context->out->fh, str, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG endms;
|
||||
int wrote_something=0;
|
||||
LLONG startms = context->current_visible_start_ms;
|
||||
LLONG startms = data->start_time;
|
||||
|
||||
startms+=subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = get_visible_end()+subs_delay;
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
mstotime (startms,&h1,&m1,&s1,&ms1);
|
||||
mstotime (endms-1,&h2,&m2,&s2,&ms2);
|
||||
@@ -119,8 +260,8 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc60
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
@@ -142,14 +283,14 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc60
|
||||
{
|
||||
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);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
//write (wb->fh, enc_buffer,enc_buffer_used);
|
||||
|
||||
return wrote_something;
|
||||
|
||||
@@ -194,9 +194,9 @@ unknown_error:
|
||||
|
||||
int
|
||||
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
struct s_context_cc608 *context)
|
||||
struct encoder_ctx *context)
|
||||
{
|
||||
LLONG ms_start = context->current_visible_start_ms + subs_delay;
|
||||
LLONG ms_start = data->start_time + subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
@@ -220,7 +220,7 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLONG ms_end = get_visible_end() + subs_delay;
|
||||
LLONG ms_end = data->end_time;
|
||||
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
|
||||
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
|
||||
@@ -267,7 +267,7 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
write_spucomment(sp,str);
|
||||
return 1;
|
||||
}
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context)
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context)
|
||||
{
|
||||
if (0 != context->out->spupng_data)
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "cc_encoders_common.h"
|
||||
|
||||
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context);
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context);
|
||||
|
||||
#endif /* __608_SPUPNG_H__ */
|
||||
|
||||
357
src/608_srt.c
357
src/608_srt.c
@@ -1,85 +1,228 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
#include "cc_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
|
||||
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
|
||||
if there is any */
|
||||
void write_stringz_as_srt (char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
dbg_print(CCX_DMT_608, "\n- - - SRT caption - - -\n");
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_srt() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
dbg_print(CCX_DMT_608, "\n- - - SRT caption - - -\n");
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
|
||||
write(context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_srt() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
int wrote_something = 0;
|
||||
ms_start = context->current_visible_start_ms;
|
||||
char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start;
|
||||
ms_end = sub->start_time;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time;
|
||||
ms_end = sub->end_time;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
len = strlen(str);
|
||||
write (context->out->fh, str, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
int wrote_something = 0;
|
||||
ms_start = data->start_time;
|
||||
|
||||
int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
|
||||
int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
|
||||
int empty_buf=1;
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
empty_buf=0;
|
||||
break;
|
||||
@@ -88,47 +231,47 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *c
|
||||
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
|
||||
return 0;
|
||||
|
||||
ms_start+=subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
ms_start+=subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
ms_end=get_visible_end()+subs_delay;
|
||||
ms_end = data->end_time;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
|
||||
dbg_print(CCX_DMT_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
if (ccx_options.sentence_cap)
|
||||
{
|
||||
capitalize (i,data);
|
||||
correct_case(i,data);
|
||||
}
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
if (ccx_options.sentence_cap)
|
||||
{
|
||||
capitalize (i,data);
|
||||
correct_case(i,data);
|
||||
}
|
||||
if (ccx_options.autodash && ccx_options.trim_subs)
|
||||
{
|
||||
int first=0, last=31, center1=-1, center2=-1;
|
||||
unsigned char *line = data->characters[i];
|
||||
unsigned char *line = data->characters[i];
|
||||
int do_dash=1, colon_pos=-1;
|
||||
find_limit_characters(line,&first,&last);
|
||||
if (first==-1 || last==-1) // Probably a bug somewhere though
|
||||
break;
|
||||
// Is there a speaker named, for example: TOM: What are you doing?
|
||||
for (int j=first;j<=last;j++)
|
||||
{
|
||||
{
|
||||
if (line[j]==':')
|
||||
{
|
||||
colon_pos=j;
|
||||
@@ -146,20 +289,20 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *c
|
||||
if (first>prev_line_start && last<prev_line_end) // Fully contained
|
||||
do_dash=0;
|
||||
if ((first>prev_line_start && first<prev_line_end) || // Overlap
|
||||
(last>prev_line_start && last<prev_line_end))
|
||||
(last>prev_line_start && last<prev_line_end))
|
||||
do_dash=0;
|
||||
|
||||
center1=(first+last)/2;
|
||||
if (colon_pos!=-1)
|
||||
{
|
||||
while (colon_pos<CC608_SCREEN_WIDTH &&
|
||||
(line[colon_pos]==':' ||
|
||||
line[colon_pos]==' ' ||
|
||||
line[colon_pos]==0x89))
|
||||
(line[colon_pos]==':' ||
|
||||
line[colon_pos]==' ' ||
|
||||
line[colon_pos]==0x89))
|
||||
colon_pos++; // Find actual text
|
||||
center2=(colon_pos+last)/2;
|
||||
}
|
||||
else
|
||||
else
|
||||
center2=center1;
|
||||
|
||||
if (center1>=prev_line_center1-1 && center1<=prev_line_center1+1 && center1!=-1) // Center align
|
||||
@@ -175,21 +318,21 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *c
|
||||
prev_line_center2=center2;
|
||||
|
||||
}
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
wrote_something=1;
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
}
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
return wrote_something;
|
||||
wrote_something=1;
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
}
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
return wrote_something;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,9 @@ void clearTV (cc708_service_decoder *decoder, int buffer) // Buffer => 1 or 2
|
||||
|
||||
void printTVtoSRT (cc708_service_decoder *decoder, int which)
|
||||
{
|
||||
if (CCX_OF_NULL == ccx_options.write_format)
|
||||
return;
|
||||
|
||||
/* tvscreen *tv = (which==1)? &decoder->tv1:&decoder->tv2; */
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
@@ -267,7 +270,7 @@ void updateScreen (cc708_service_decoder *decoder)
|
||||
if (decoder->windows[i].is_defined && decoder->windows[i].visible && !decoder->windows[i].is_empty)
|
||||
wnd[visible++]=&decoder->windows[i];
|
||||
}
|
||||
qsort (wnd,visible,sizeof (int),compWindowsPriorities);
|
||||
qsort (wnd,visible,sizeof (e708Window *),compWindowsPriorities);
|
||||
dbg_print(CCX_DMT_708, "Visible (and populated) windows in priority order: ");
|
||||
for (int i=0;i<visible;i++)
|
||||
{
|
||||
@@ -1204,7 +1207,7 @@ void do_708 (const unsigned char *data, int datalength)
|
||||
process_current_packet();
|
||||
if (cc_valid)
|
||||
{
|
||||
if (current_packet_length>253)
|
||||
if (current_packet_length>127)
|
||||
{
|
||||
dbg_print(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ uint32_t asf_readval(void *val, int ltype)
|
||||
|
||||
char *guidstr(void *val)
|
||||
{
|
||||
static char sbuf[32];
|
||||
static char sbuf[40];
|
||||
|
||||
sprintf(sbuf,"%08lX-%04X-%04X-",
|
||||
(long)*((uint32_t*)((char*)val+0)),
|
||||
|
||||
@@ -12,7 +12,7 @@ static void sei_rbsp (unsigned char *seibuf, unsigned char *seiend);
|
||||
static unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend);
|
||||
static void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend);
|
||||
static void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend);
|
||||
static void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type);
|
||||
static void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
|
||||
|
||||
static unsigned char cc_count;
|
||||
// buffer to hold cc data
|
||||
@@ -44,7 +44,7 @@ void init_avc(void)
|
||||
cc_data = (unsigned char*)malloc(1024);
|
||||
}
|
||||
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length)
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *NALstop;
|
||||
unsigned nal_unit_type = *NALstart & 0x1F;
|
||||
@@ -76,7 +76,7 @@ void do_NAL (unsigned char *NALstart, LLONG NAL_length)
|
||||
// Found coded slice of a non-IDR picture
|
||||
// We only need the slice header data, no need to implement
|
||||
// slice_layer_without_partitioning_rbsp( );
|
||||
slice_header(NALstart+1, NALstop, nal_unit_type);
|
||||
slice_header(NALstart+1, NALstop, nal_unit_type, sub);
|
||||
}
|
||||
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
|
||||
{
|
||||
@@ -99,7 +99,7 @@ void do_NAL (unsigned char *NALstart, LLONG NAL_length)
|
||||
|
||||
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
|
||||
// The number of processed bytes is returned.
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *bpos = avcbuf;
|
||||
unsigned char *NALstart;
|
||||
@@ -203,7 +203,7 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
|
||||
dvprint("BEGIN NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions before: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
|
||||
do_NAL (NALstart, NALstop-NALstart);
|
||||
do_NAL (NALstart, NALstop-NALstart, sub);
|
||||
|
||||
dvprint("END NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions after: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
@@ -563,151 +563,223 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
|
||||
dvprint("SEQUENCE PARAMETER SET (bitlen: %lld)\n", q1.bitsleft);
|
||||
tmp=u(&q1,8);
|
||||
dvprint("profile_idc= %llX\n", tmp);
|
||||
LLONG profile_idc = tmp;
|
||||
dvprint("profile_idc= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("constraint_set0_flag= %llX\n", tmp);
|
||||
dvprint("constraint_set0_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("constraint_set1_flag= %llX\n", tmp);
|
||||
dvprint("constraint_set1_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("constraint_set2_flag= %llX\n", tmp);
|
||||
tmp=u(&q1,5);
|
||||
dvprint("reserved= %llX\n", tmp);
|
||||
dvprint("constraint_set2_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("constraint_set3_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("constraint_set4_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("constraint_set5_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,2);
|
||||
dvprint("reserved= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,8);
|
||||
dvprint("level_idc= %llX\n", tmp);
|
||||
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
|
||||
seq_parameter_set_id = ue(&q1);
|
||||
dvprint("seq_parameter_set_id= %llX\n", seq_parameter_set_id);
|
||||
log2_max_frame_num = (int)ue(&q1)+4;
|
||||
dvprint("log2_max_frame_num4= %X\n", log2_max_frame_num);
|
||||
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,seq_parameter_set_id);
|
||||
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|
||||
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
|
||||
|| profile_idc == 86 || profile_idc == 118 || profile_idc == 128){
|
||||
LLONG chroma_format_idc = ue(&q1);
|
||||
dvprint("chroma_format_idc= % 4lld (%#llX)\n", chroma_format_idc,chroma_format_idc);
|
||||
if (chroma_format_idc == 3){
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("separate_colour_plane_flag= % 4lld (%#llX)\n", tmp, tmp);
|
||||
}
|
||||
tmp = ue(&q1);
|
||||
dvprint("bit_depth_luma_minus8= % 4lld (%#llX)\n", tmp, tmp);
|
||||
tmp = ue(&q1);
|
||||
dvprint("bit_depth_chroma_minus8= % 4lld (%#llX)\n", tmp, tmp);
|
||||
tmp = u(&q1,1);
|
||||
dvprint("qpprime_y_zero_transform_bypass_flag= % 4lld (%#llX)\n", tmp, tmp);
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("seq_scaling_matrix_present_flag= % 4lld (%#llX)\n", tmp, tmp);
|
||||
if (tmp == 1){
|
||||
// WVI: untested, just copied from specs.
|
||||
for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++){
|
||||
tmp = u(&q1, 1);
|
||||
dvprint("seq_scaling_list_present_flag[%d]= % 4lld (%#llX)\n",i,tmp, tmp);
|
||||
if (tmp){
|
||||
// We use a "dummy"/slimmed-down replacement here. Actual/full code can be found in the spec (ISO/IEC 14496-10:2012(E)) chapter 7.3.2.1.1.1 - Scaling list syntax
|
||||
if (i < 6){
|
||||
// Scaling list size 16
|
||||
// TODO: replace with full scaling list implementation?
|
||||
int nextScale = 8;
|
||||
int lastScale = 8;
|
||||
for (int j = 0; j < 16; j++){
|
||||
if (nextScale != 0){
|
||||
int64_t delta_scale = se(&q1);
|
||||
nextScale = (lastScale + delta_scale + 256) % 256;
|
||||
}
|
||||
lastScale = (nextScale == 0) ? lastScale : nextScale;
|
||||
}
|
||||
// END of TODO
|
||||
}
|
||||
else {
|
||||
// Scaling list size 64
|
||||
// TODO: replace with full scaling list implementation?
|
||||
int nextScale = 8;
|
||||
int lastScale = 8;
|
||||
for (int j = 0; j < 64; j++){
|
||||
if (nextScale != 0){
|
||||
int64_t delta_scale = se(&q1);
|
||||
nextScale = (lastScale + delta_scale + 256) % 256;
|
||||
}
|
||||
lastScale = (nextScale == 0) ? lastScale : nextScale;
|
||||
}
|
||||
// END of TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log2_max_frame_num = (int)ue(&q1);
|
||||
dvprint("log2_max_frame_num4_minus4= % 4d (%#X)\n", log2_max_frame_num,log2_max_frame_num);
|
||||
log2_max_frame_num += 4; // 4 is added due to the formula.
|
||||
pic_order_cnt_type = (int)ue(&q1);
|
||||
dvprint("pic_order_cnt_type= %X\n", pic_order_cnt_type);
|
||||
dvprint("pic_order_cnt_type= % 4d (%#X)\n", pic_order_cnt_type,pic_order_cnt_type);
|
||||
if( pic_order_cnt_type == 0 )
|
||||
{
|
||||
log2_max_pic_order_cnt_lsb = (int)ue(&q1)+4;
|
||||
dvprint("log2_max_pic_order_cnt_lsb= %X\n", log2_max_pic_order_cnt_lsb);
|
||||
log2_max_pic_order_cnt_lsb = (int)ue(&q1);
|
||||
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", log2_max_pic_order_cnt_lsb,log2_max_pic_order_cnt_lsb);
|
||||
log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
|
||||
}
|
||||
else if( pic_order_cnt_type == 1 )
|
||||
{
|
||||
// CFS: Untested, just copied from specs.
|
||||
tmp= u(&q1,1);
|
||||
dvprint("delta_pic_order_always_zero_flag= %llX\n", tmp);
|
||||
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = se(&q1);
|
||||
dvprint("offset_for_non_ref_pic= %llX\n", tmp);
|
||||
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = se(&q1);
|
||||
dvprint("offset_for_top_to_bottom_field %llX\n", tmp);
|
||||
dvprint("offset_for_top_to_bottom_field % 4lld (%#llX)\n",tmp,tmp);
|
||||
LLONG num_ref_frame_in_pic_order_cnt_cycle = ue (&q1);
|
||||
dvprint("num_ref_frame_in_pic_order_cnt_cycle %llX\n", num_ref_frame_in_pic_order_cnt_cycle);
|
||||
dvprint("num_ref_frame_in_pic_order_cnt_cycle % 4lld (%#llX)\n", num_ref_frame_in_pic_order_cnt_cycle,num_ref_frame_in_pic_order_cnt_cycle);
|
||||
for (int i=0; i<num_ref_frame_in_pic_order_cnt_cycle; i++)
|
||||
{
|
||||
tmp=se(&q1);
|
||||
dvprint("offset_for_ref_frame [%d / %d] = %llX\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp);
|
||||
}
|
||||
|
||||
dvprint("offset_for_ref_frame [%d / %d] = % 4lld (%#llX)\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp,tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// CFS: Looks like nothing needs to be parsed for pic_order_cnt_type==2 ?
|
||||
// fatal(EXIT_BUG_BUG, "AVC: pic_order_cnt_type > 1 is not yet supported.");
|
||||
// Nothing needs to be parsed when pic_order_cnt_type == 2
|
||||
}
|
||||
|
||||
tmp=ue(&q1);
|
||||
dvprint("num_ref_frames= %llX\n", tmp);
|
||||
|
||||
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("gaps allowed= %llX\n", tmp);
|
||||
dvprint("gaps_in_frame_num_value_allowed_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("pic_width_in_mbs_minus1= %llX\n", tmp);
|
||||
dvprint("pic_width_in_mbs_minus1= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("pic_height_in_map_units_minus1= %llX\n", tmp);
|
||||
dvprint("pic_height_in_map_units_minus1= % 4lld (%#llX)\n",tmp,tmp);
|
||||
frame_mbs_only_flag = (int)u(&q1,1);
|
||||
dvprint("frame_mbs_only_flag= %X\n", frame_mbs_only_flag);
|
||||
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", frame_mbs_only_flag,frame_mbs_only_flag);
|
||||
if ( !frame_mbs_only_flag )
|
||||
{
|
||||
tmp=u(&q1,1);
|
||||
dvprint("mb_adaptive_fr_fi_flag= %llX\n", tmp);
|
||||
dvprint("mb_adaptive_fr_fi_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("direct_8x8_inference_f= %llX\n", tmp);
|
||||
dvprint("direct_8x8_inference_f= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("frame_cropping_flag= %llX\n", tmp);
|
||||
dvprint("frame_cropping_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=ue(&q1);
|
||||
dvprint("frame_crop_left_offset= %llX\n", tmp);
|
||||
dvprint("frame_crop_left_offset= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("frame_crop_right_offset= %llX\n", tmp);
|
||||
dvprint("frame_crop_right_offset= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("frame_crop_top_offset= %llX\n", tmp);
|
||||
dvprint("frame_crop_top_offset= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("frame_crop_bottom_offset= %llX\n", tmp);
|
||||
dvprint("frame_crop_bottom_offset= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("vui_parameters_present= %llX\n", tmp);
|
||||
dvprint("vui_parameters_present= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
dvprint("\nVUI parameters\n");
|
||||
tmp=u(&q1,1);
|
||||
dvprint("aspect_ratio_info_pres= %llX\n", tmp);
|
||||
dvprint("aspect_ratio_info_pres= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=u(&q1,8);
|
||||
dvprint("aspect_ratio_idc= %llX\n", tmp);
|
||||
dvprint("aspect_ratio_idc= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp == 255 )
|
||||
{
|
||||
tmp=u(&q1,16);
|
||||
dvprint("sar_width= %llX\n", tmp);
|
||||
dvprint("sar_width= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,16);
|
||||
dvprint("sar_height= %llX\n", tmp);
|
||||
dvprint("sar_height= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("overscan_info_pres_flag= %llX\n", tmp);
|
||||
dvprint("overscan_info_pres_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=u(&q1,1);
|
||||
dvprint("overscan_appropriate_flag= %llX\n", tmp);
|
||||
dvprint("overscan_appropriate_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("video_signal_type_present_flag= %llX\n", tmp);
|
||||
dvprint("video_signal_type_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=u(&q1,3);
|
||||
dvprint("video_format= %llX\n", tmp);
|
||||
dvprint("video_format= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("video_full_range_flag= %llX\n", tmp);
|
||||
dvprint("video_full_range_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("colour_description_present_flag= %llX\n", tmp);
|
||||
dvprint("colour_description_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=u(&q1,8);
|
||||
dvprint("colour_primaries= %llX\n", tmp);
|
||||
dvprint("colour_primaries= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,8);
|
||||
dvprint("transfer_characteristics= %llX\n", tmp);
|
||||
dvprint("transfer_characteristics= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,8);
|
||||
dvprint("matrix_coefficients= %llX\n", tmp);
|
||||
dvprint("matrix_coefficients= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("chroma_loc_info_present_flag= %llX\n", tmp);
|
||||
dvprint("chroma_loc_info_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=ue(&q1);
|
||||
dvprint("chroma_sample_loc_type_top_field= %llX\n", tmp);
|
||||
dvprint("chroma_sample_loc_type_top_field= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("chroma_sample_loc_type_bottom_field= %llX\n", tmp);
|
||||
dvprint("chroma_sample_loc_type_bottom_field= % 4lld (%#llX)\n",tmp,tmp);
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("timing_info_present_flag= %llX\n", tmp);
|
||||
dvprint("timing_info_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
tmp=u(&q1,32);
|
||||
dvprint("num_units_in_tick= %llX\n", tmp);
|
||||
LLONG num_units_in_tick = tmp;
|
||||
dvprint("num_units_in_tick= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,32);
|
||||
dvprint("time_scale= %llX\n", tmp);
|
||||
LLONG time_scale = tmp;
|
||||
dvprint("time_scale= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("fixed_frame_rate_flag= %llX\n", tmp);
|
||||
int fixed_frame_rate_flag = (int) tmp;
|
||||
dvprint("fixed_frame_rate_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
// Change: use num_units_in_tick and time_scale to calculate FPS. (ISO/IEC 14496-10:2012(E), page 397 & further)
|
||||
if (fixed_frame_rate_flag){
|
||||
double clock_tick = (double) num_units_in_tick / time_scale;
|
||||
dvprint("clock_tick= %f\n", clock_tick);
|
||||
current_fps = (double)time_scale / (2 * num_units_in_tick); // Based on formula D-2, p. 359 of the ISO/IEC 14496-10:2012(E) spec.
|
||||
mprint("Changed fps using NAL to: %f\n", current_fps);
|
||||
}
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("nal_hrd_parameters_present_flag= %llX\n", tmp);
|
||||
dvprint("nal_hrd_parameters_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
@@ -728,13 +800,13 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
if ( tmp || tmp1 )
|
||||
{
|
||||
tmp=u(&q1,1);
|
||||
dvprint("low_delay_hrd_flag= %llX\n", tmp);
|
||||
dvprint("low_delay_hrd_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
return;
|
||||
}
|
||||
tmp=u(&q1,1);
|
||||
dvprint("pic_struct_present_flag= %llX\n", tmp);
|
||||
dvprint("pic_struct_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("bitstream_restriction_flag= %llX\n", tmp);
|
||||
dvprint("bitstream_restriction_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
// ..
|
||||
// The hope was to find the GOP length in max_dec_frame_buffering, but
|
||||
// it was not set in the testfile. Ignore the rest here, it's
|
||||
@@ -745,7 +817,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
|
||||
|
||||
// Process slice header in AVC data.
|
||||
void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type)
|
||||
void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
|
||||
{
|
||||
LLONG tmp;
|
||||
struct bitstream q1;
|
||||
@@ -772,11 +844,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
|
||||
dvprint("\nSLICE HEADER\n");
|
||||
tmp=ue(&q1);
|
||||
dvprint("first_mb_in_slice= %llX\n", tmp);
|
||||
dvprint("first_mb_in_slice= % 4lld (%#llX)\n",tmp,tmp);
|
||||
slice_type=ue(&q1);
|
||||
dvprint("slice_type= %llX\n", slice_type);
|
||||
tmp=ue(&q1);
|
||||
dvprint("pic_parameter_set_id= %llX\n", tmp);
|
||||
dvprint("pic_parameter_set_id= % 4lld (%#llX)\n",tmp,tmp);
|
||||
|
||||
lastframe_num = frame_num;
|
||||
int maxframe_num = (int) ((1<<log2_max_frame_num) - 1);
|
||||
@@ -808,7 +880,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
if( nal_unit_type == 5 )
|
||||
{
|
||||
tmp=ue(&q1);
|
||||
dvprint("idr_pic_id= %llX\n", tmp);
|
||||
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
|
||||
//TODO
|
||||
}
|
||||
if( pic_order_cnt_type == 0 )
|
||||
@@ -910,7 +982,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc();
|
||||
process_hdcc(sub);
|
||||
}
|
||||
last_gop_length = frames_since_last_gop;
|
||||
frames_since_last_gop=0;
|
||||
@@ -1042,11 +1114,9 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
total_frames_count++;
|
||||
frames_since_last_gop++;
|
||||
|
||||
store_hdcc(cc_data, cc_count, curridx, fts_now);
|
||||
store_hdcc(cc_data, cc_count, curridx, fts_now, sub);
|
||||
cc_buffer_saved=1; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
|
||||
cc_count=0;
|
||||
|
||||
//exit(1);
|
||||
}
|
||||
|
||||
// max_dec_frame_buffering .. Max frames in buffer
|
||||
|
||||
63
src/cc_decoders_common.h
Normal file
63
src/cc_decoders_common.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef _CC_DECODER_COMMON
|
||||
#define _CC_DECODER_COMMON
|
||||
|
||||
/* flag raised when end of display marker arrives in Dvb Subtitle */
|
||||
#define SUB_EOD_MARKER (1 << 0 )
|
||||
struct cc_bitmap
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int nb_colors;
|
||||
unsigned char *data[2];
|
||||
int linesize[2];
|
||||
};
|
||||
/**
|
||||
* Raw Subtitle struct used as output of decoder (cc608)
|
||||
* and input for encoder (sami, srt, transcript or smptett etc)
|
||||
*/
|
||||
struct cc_subtitle
|
||||
{
|
||||
/**
|
||||
* A generic data which contain data according to decoder
|
||||
* just now only struct cc_eia608_screen is placed here
|
||||
* @warn decoder cant output multiple types of data
|
||||
*/
|
||||
void *data;
|
||||
/** number of data */
|
||||
unsigned int nb_data;
|
||||
/** type of subtitle */
|
||||
enum subtype type;
|
||||
/* set only when all the data is to be displayed at same time */
|
||||
LLONG start_time;
|
||||
LLONG end_time;
|
||||
/* flags */
|
||||
int flags;
|
||||
/* index of language table */
|
||||
int lang_index;
|
||||
/** flag to tell that decoder has given output */
|
||||
int got_output;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param data raw cc608 data to be processed
|
||||
*
|
||||
* @param length length of data passed
|
||||
*
|
||||
* @param context context of cc608 where important information related to 608
|
||||
* are stored.
|
||||
*
|
||||
* @param sub pointer to subtitle should be memset to 0 when passed first time
|
||||
* subtitle are stored when structure return
|
||||
*
|
||||
* @return number of bytes used from data, -1 when any error is encountered
|
||||
*/
|
||||
int process608(const unsigned char *data, int length, struct s_context_cc608 *context, struct cc_subtitle *sub);
|
||||
|
||||
/**
|
||||
* Issue a EraseDisplayedMemory here so if there's any captions pending
|
||||
* they get written to cc_subtitle
|
||||
*/
|
||||
void handle_end_of_data(struct s_context_cc608 *context, struct cc_subtitle *sub);
|
||||
#endif
|
||||
594
src/cc_encoders_common.c
Normal file
594
src/cc_encoders_common.c
Normal file
@@ -0,0 +1,594 @@
|
||||
#include "ccextractor.h"
|
||||
#include "cc_decoders_common.h"
|
||||
#include "cc_encoders_common.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "608_spupng.h"
|
||||
#include "utility.h"
|
||||
#include "xds.h"
|
||||
#include "ocr.h"
|
||||
|
||||
static const char *sami_header= // TODO: Revise the <!-- comments
|
||||
"<SAMI>\n\
|
||||
<HEAD>\n\
|
||||
<STYLE TYPE=\"text/css\">\n\
|
||||
<!--\n\
|
||||
P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
|
||||
text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
|
||||
.UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
|
||||
-->\n\
|
||||
</STYLE>\n\
|
||||
</HEAD>\n\n\
|
||||
<BODY>\n";
|
||||
|
||||
static const char *smptett_header =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\
|
||||
<tt xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n\
|
||||
<body>\n<div>\n" ;
|
||||
|
||||
void write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
{
|
||||
int used;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SAMI:
|
||||
sprintf ((char *) str,"</BODY></SAMI>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
used=encode_line (ctx->buffer,(unsigned char *) str);
|
||||
write(out->fh, ctx->buffer, used);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
sprintf ((char *) str,"</div></body></tt>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
used=encode_line (ctx->buffer,(unsigned char *) str);
|
||||
write (out->fh, ctx->buffer,used);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_footer(out);
|
||||
break;
|
||||
default: // Nothing to do, no footer on this format
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_subtitle_file_header(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
{
|
||||
int used;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT: // Subrip subtitles have no header
|
||||
break;
|
||||
case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI
|
||||
//fprintf_encoded (wb->fh, sami_header);
|
||||
REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3);
|
||||
used=encode_line (ctx->buffer,(unsigned char *) sami_header);
|
||||
write (out->fh, ctx->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(ctx,strlen (smptett_header)*3);
|
||||
used=encode_line (ctx->buffer,(unsigned char *) smptett_header);
|
||||
write(out->fh, ctx->buffer, used);
|
||||
break;
|
||||
case CCX_OF_RCWT: // Write header
|
||||
write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
net_send_header(rcwt_header, sizeof(rcwt_header));
|
||||
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
write_spumux_header(out);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT: // No header. Fall thru
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context, int line_number)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG start_time = data->start_time;
|
||||
LLONG end_time = data->end_time;
|
||||
if (ccx_options.sentence_cap)
|
||||
{
|
||||
capitalize (line_number,data);
|
||||
correct_case(line_number,data);
|
||||
}
|
||||
int length = get_decoder_line_basic (subline, line_number, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
if (length>0)
|
||||
{
|
||||
if (data->start_time == -1)
|
||||
{
|
||||
// CFS: Means that the line has characters but we don't have a timestamp for the first one. Since the timestamp
|
||||
// is set for example by the write_char function, it possible that we don't have one in empty lines (unclear)
|
||||
// For now, let's not consider this a bug as before and just return.
|
||||
// fatal (EXIT_BUG_BUG, "Bug in timedtranscript (ts_start_of_current_line==-1). Please report.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showStartTime){
|
||||
char buf1[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
millis_to_date(start_time + subs_delay, buf1);
|
||||
fdprintf(context->out->fh, "%s|", buf1);
|
||||
}
|
||||
else {
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showEndTime){
|
||||
char buf2[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
millis_to_date(end_time, buf2);
|
||||
fdprintf(context->out->fh, "%s|", buf2);
|
||||
}
|
||||
else {
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = end_time / 1000;
|
||||
int end_time_dec = end_time % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showCC){
|
||||
fdprintf(context->out->fh, "CC%d|", data->my_field == 1 ? data->channel : data->channel + 2); // Data from field 2 is CC3 or 4
|
||||
}
|
||||
if (ccx_options.transcript_settings.showMode){
|
||||
const char *mode = "???";
|
||||
switch (data->mode)
|
||||
{
|
||||
case MODE_POPON:
|
||||
mode = "POP";
|
||||
break;
|
||||
case MODE_FAKE_ROLLUP_1:
|
||||
mode = "RU1";
|
||||
break;
|
||||
case MODE_ROLLUP_2:
|
||||
mode = "RU2";
|
||||
break;
|
||||
case MODE_ROLLUP_3:
|
||||
mode = "RU3";
|
||||
break;
|
||||
case MODE_ROLLUP_4:
|
||||
mode = "RU4";
|
||||
break;
|
||||
case MODE_TEXT:
|
||||
mode = "TXT";
|
||||
break;
|
||||
case MODE_PAINTON:
|
||||
mode = "PAI";
|
||||
break;
|
||||
}
|
||||
fdprintf(context->out->fh, "%s|", mode);
|
||||
}
|
||||
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int wrote_something = 0;
|
||||
dbg_print(CCX_DMT_608, "\n- - - TRANSCRIPT caption - - -\n");
|
||||
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
write_cc_line_as_transcript2 (data, context, i);
|
||||
}
|
||||
wrote_something=1;
|
||||
}
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
return wrote_something;
|
||||
}
|
||||
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG start_time, end_time;
|
||||
char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
start_time = context->prev_start + subs_delay;
|
||||
end_time = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
start_time = sub->start_time + subs_delay;
|
||||
end_time = sub->end_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *token = NULL;
|
||||
token = strtok(str,"\r\n");
|
||||
while (token)
|
||||
{
|
||||
|
||||
if (ccx_options.transcript_settings.showStartTime)
|
||||
{
|
||||
char buf1[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp)
|
||||
{
|
||||
millis_to_date(start_time + subs_delay, buf1);
|
||||
fdprintf(context->out->fh, "%s|", buf1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.showEndTime)
|
||||
{
|
||||
char buf2[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp)
|
||||
{
|
||||
millis_to_date(end_time, buf2);
|
||||
fdprintf(context->out->fh, "%s|", buf2);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = end_time / 1000;
|
||||
int end_time_dec = end_time % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
|
||||
}
|
||||
}
|
||||
if (ccx_options.transcript_settings.showCC)
|
||||
{
|
||||
fdprintf(context->out->fh,"%s|",language[sub->lang_index]);
|
||||
}
|
||||
if (ccx_options.transcript_settings.showMode)
|
||||
{
|
||||
fdprintf(context->out->fh,"DVB|");
|
||||
}
|
||||
fdprintf(context->out->fh,"%s\n",token);
|
||||
token = strtok(NULL,"\r\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
void try_to_add_end_credits(struct encoder_ctx *context, struct ccx_s_write *out)
|
||||
{
|
||||
LLONG window, length, st, end;
|
||||
if (out->fh == -1)
|
||||
return;
|
||||
window=get_fts()-last_displayed_subs_ms-1;
|
||||
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
|
||||
return;
|
||||
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.endcreditsforatmost.time_in_ms;
|
||||
|
||||
st=get_fts()-length-1;
|
||||
end=get_fts();
|
||||
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.end_credits_text, context, st, end);
|
||||
break ;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
|
||||
{
|
||||
LLONG st, end, window, length;
|
||||
LLONG l = start_ms + subs_delay;
|
||||
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
|
||||
|
||||
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
|
||||
return;
|
||||
|
||||
if (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
|
||||
return;
|
||||
|
||||
st = ccx_options.startcreditsnotbefore.time_in_ms>(last_displayed_subs_ms+1) ?
|
||||
ccx_options.startcreditsnotbefore.time_in_ms : (last_displayed_subs_ms+1); // When would credits actually start
|
||||
|
||||
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
|
||||
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
|
||||
|
||||
window = end-st; // Allowable time in MS
|
||||
|
||||
if (ccx_options.startcreditsforatleast.time_in_ms>window) // Window is too short
|
||||
return;
|
||||
|
||||
length=ccx_options.startcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.startcreditsforatmost.time_in_ms;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
|
||||
last_displayed_subs_ms, l);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
|
||||
ccx_options.startcreditsnotbefore.time_in_ms,
|
||||
ccx_options.startcreditsnotafter.time_in_ms);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Start of window: %lld End of window: %lld\n",st,end);
|
||||
|
||||
if (window>length+2)
|
||||
{
|
||||
// Center in time window
|
||||
LLONG pad=window-length;
|
||||
st+=(pad/2);
|
||||
}
|
||||
end=st+length;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.start_credits_text,context,st,end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
startcredits_displayed=1;
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
{
|
||||
ctx->buffer = (unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY);
|
||||
if (ctx->buffer==NULL)
|
||||
return -1;
|
||||
ctx->capacity=INITIAL_ENC_BUFFER_CAPACITY;
|
||||
ctx->srt_counter = 0;
|
||||
ctx->out = out;
|
||||
/** used in case of SUB_EOD_MARKER */
|
||||
ctx->prev_start = -1;
|
||||
write_subtitle_file_header(ctx,out);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void dinit_encoder(struct encoder_ctx *ctx)
|
||||
{
|
||||
|
||||
if (ccx_options.end_credits_text!=NULL)
|
||||
try_to_add_end_credits(ctx,ctx->out);
|
||||
write_subtitle_file_footer(ctx,ctx->out);
|
||||
freep(&ctx->buffer);
|
||||
ctx->capacity = 0;
|
||||
}
|
||||
|
||||
int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
{
|
||||
int wrote_something = 0 ;
|
||||
|
||||
if (ccx_options.extract!=1)
|
||||
context++;
|
||||
|
||||
if (sub->type == CC_608)
|
||||
{
|
||||
struct eia608_screen *data = NULL;
|
||||
for(data = sub->data; sub->nb_data ; sub->nb_data--,data++)
|
||||
{
|
||||
new_sentence=1;
|
||||
|
||||
if(data->format == SFORMAT_XDS)
|
||||
{
|
||||
xds_write_transcript_line_prefix (context->out, data->start_time, data->end_time,data->cur_xds_packet_class);
|
||||
if(data->xds_len > 0)
|
||||
write (context->out->fh, data->xds_str,data->xds_len);
|
||||
freep (&data->xds_str);
|
||||
xds_write_transcript_line_suffix (context->out);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!data->start_time)
|
||||
break;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_srt(data, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_sami(data, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_smptett(data, context);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_buffer_as_transcript2(data, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_buffer_as_spupng(data, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (wrote_something)
|
||||
last_displayed_subs_ms=get_fts()+subs_delay;
|
||||
|
||||
if (ccx_options.gui_mode_reports)
|
||||
write_cc_buffer_to_gui(sub->data, context);
|
||||
}
|
||||
freep(&sub->data);
|
||||
}
|
||||
if(sub->type == CC_BITMAP)
|
||||
{
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_srt(sub, context);
|
||||
case CCX_OF_SAMI:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_sami(sub, context);
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_smptett(sub, context);
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
wrote_something = write_cc_bitmap_as_transcript(sub, context);
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
wrote_something = write_cc_bitmap_as_spupng(sub, context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!sub->nb_data)
|
||||
freep(&sub->data);
|
||||
return wrote_something;
|
||||
}
|
||||
67
src/cc_encoders_common.h
Normal file
67
src/cc_encoders_common.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef _CC_ENCODER_COMMON_H
|
||||
#define _CC_ENCODER_COMMON_H
|
||||
|
||||
/**
|
||||
* Context of encoder, This structure gives single interface
|
||||
* to all encoder
|
||||
*/
|
||||
struct encoder_ctx
|
||||
{
|
||||
/** common buffer used by all encoder */
|
||||
unsigned char *buffer;
|
||||
/** capacity of buffer */
|
||||
unsigned int capacity;
|
||||
/* keep count of srt subtitle*/
|
||||
unsigned int srt_counter;
|
||||
/** output contet */
|
||||
struct ccx_s_write *out;
|
||||
/** start time of previous sub */
|
||||
LLONG prev_start;
|
||||
};
|
||||
|
||||
#define INITIAL_ENC_BUFFER_CAPACITY 2048
|
||||
/**
|
||||
* Inialize encoder context with output context
|
||||
* allocate initial memory to buffer of context
|
||||
* write subtitle header to file refrenced by
|
||||
* output context
|
||||
*
|
||||
* @param ctx preallocated encoder ctx
|
||||
* @param out output context
|
||||
*
|
||||
* @return 0 on SUCESS, -1 on failure
|
||||
*/
|
||||
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out);
|
||||
|
||||
/**
|
||||
* try to add end credits in subtitle file and then write subtitle
|
||||
* footer
|
||||
*
|
||||
* deallocate encoder ctx, so before using encoder_ctx again
|
||||
* after deallocating user need to allocate encoder ctx again
|
||||
*
|
||||
* @oaram ctx Initialized encoder ctx using init_encoder
|
||||
*/
|
||||
void dinit_encoder(struct encoder_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @param ctx encoder context
|
||||
* @param sub subtitle context returned by decoder
|
||||
*/
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
|
||||
int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@ License: GPL 2.0
|
||||
#include <stdio.h>
|
||||
#include "ccextractor.h"
|
||||
#include "configuration.h"
|
||||
#include "cc_encoders_common.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -174,8 +175,13 @@ void init_options (struct ccx_s_options *options)
|
||||
options->ts_datastreamtype = -1; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
options->ts_forced_streamtype=CCX_STREAM_TYPE_UNKNOWNSTREAM; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
options->udpaddr = 0;
|
||||
options->udpaddr = NULL;
|
||||
options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
options->send_to_srv = 0;
|
||||
options->tcpport = NULL;
|
||||
options->tcp_password = NULL;
|
||||
options->srv_addr = NULL;
|
||||
options->srv_port = NULL;
|
||||
options->line_terminator_lf=0; // 0 = CRLF
|
||||
options->noautotimeref=0; // Do NOT set time automatically?
|
||||
options->input_source=CCX_DS_FILE; // Files, stdin or network
|
||||
@@ -219,12 +225,7 @@ unsigned hauppauge_warning_shown=0; // Did we detect a possible Hauppauge captur
|
||||
unsigned teletext_warning_shown=0; // Did we detect a possible PAL (with teletext subs) and told the user already?
|
||||
|
||||
|
||||
|
||||
struct sockaddr_in servaddr, cliaddr;
|
||||
|
||||
|
||||
struct ccx_s_write wbout1, wbout2; // Output structures
|
||||
struct ccx_s_write *wbxdsout=NULL; // Pointer, so it can share the same output file
|
||||
|
||||
/* File handles */
|
||||
FILE *fh_out_elementarystream;
|
||||
@@ -236,7 +237,9 @@ struct PMT_entry *PIDs_programs[65536];
|
||||
|
||||
int temp_debug=0; // This is a convenience variable used to enable/disable debug on variable conditions. Find references to understand.
|
||||
|
||||
#ifdef DEBUG_TELEXCC
|
||||
int main_telxcc (int argc, char *argv[]);
|
||||
#endif
|
||||
LLONG process_raw_with_field (void);
|
||||
|
||||
|
||||
@@ -244,6 +247,8 @@ LLONG process_raw_with_field (void);
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *c;
|
||||
struct encoder_ctx enc_ctx[2];
|
||||
struct cc_subtitle dec_sub;
|
||||
|
||||
// Initialize some constants
|
||||
init_ts();
|
||||
@@ -278,26 +283,31 @@ int main(int argc, char *argv[])
|
||||
int show_myth_banner = 0;
|
||||
|
||||
memset (&cea708services[0],0,63*sizeof (int));
|
||||
memset (&dec_sub, 0,sizeof(dec_sub));
|
||||
parse_configuration(&ccx_options);
|
||||
parse_parameters (argc,argv);
|
||||
|
||||
if (num_input_files==0 && ccx_options.input_source==CCX_DS_FILE)
|
||||
{
|
||||
usage ();
|
||||
fatal (EXIT_NO_INPUT_FILES, "(This help screen was shown because there were no input files)\n");
|
||||
fatal (EXIT_NO_INPUT_FILES, "(This help screen was shown because there were no input files)\n");
|
||||
}
|
||||
if (num_input_files>1 && ccx_options.live_stream)
|
||||
{
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "Live stream mode accepts only one input file.\n");
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "Live stream mode accepts only one input file.\n");
|
||||
}
|
||||
if (num_input_files && ccx_options.input_source==CCX_DS_NETWORK)
|
||||
{
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "UDP mode is not compatible with input files.\n");
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "UDP mode is not compatible with input files.\n");
|
||||
}
|
||||
if (ccx_options.input_source==CCX_DS_NETWORK)
|
||||
if (ccx_options.input_source==CCX_DS_NETWORK || ccx_options.input_source==CCX_DS_TCP)
|
||||
{
|
||||
ccx_options.buffer_input=1; // Mandatory, because each datagram must be read complete.
|
||||
}
|
||||
if (num_input_files && ccx_options.input_source==CCX_DS_TCP)
|
||||
{
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "TCP mode is not compatible with input files.\n");
|
||||
}
|
||||
|
||||
// teletext page number out of range
|
||||
if ((tlt_config.page != 0) && ((tlt_config.page < 100) || (tlt_config.page > 899))) {
|
||||
@@ -378,6 +388,7 @@ int main(int argc, char *argv[])
|
||||
basefilename = (char *) malloc (strlen (basefilename_for_stdin)+1);
|
||||
break;
|
||||
case CCX_DS_NETWORK:
|
||||
case CCX_DS_TCP:
|
||||
basefilename = (char *) malloc (strlen (basefilename_for_network)+1);
|
||||
break;
|
||||
}
|
||||
@@ -392,6 +403,7 @@ int main(int argc, char *argv[])
|
||||
strcpy (basefilename, basefilename_for_stdin);
|
||||
break;
|
||||
case CCX_DS_NETWORK:
|
||||
case CCX_DS_TCP:
|
||||
strcpy (basefilename, basefilename_for_network);
|
||||
break;
|
||||
}
|
||||
@@ -412,11 +424,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (buffer == NULL || pesheaderbuf==NULL ||
|
||||
wbout1.filename == NULL || wbout2.filename == NULL ||
|
||||
subline==NULL || init_file_buffer() || general_608_init())
|
||||
subline==NULL || init_file_buffer() )
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
connect_to_srv(ccx_options.srv_addr, ccx_options.srv_port);
|
||||
}
|
||||
|
||||
if (ccx_options.write_format!=CCX_OF_NULL)
|
||||
{
|
||||
/* # DVD format uses one raw file for both fields, while Broadcast requires 2 */
|
||||
@@ -480,15 +497,20 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case CCX_OF_DVDRAW:
|
||||
break;
|
||||
case CCX_OF_RCWT:
|
||||
if( init_encoder(enc_ctx,&wbout1) )
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
if (ccx_options.encoding==CCX_ENC_UTF_8) // Write BOM
|
||||
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.out);
|
||||
if( init_encoder(enc_ctx,&wbout1) )
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
}
|
||||
if (ccx_options.extract == 12)
|
||||
if (ccx_options.extract == 12 && ccx_options.write_format != CCX_OF_RAW)
|
||||
mprint (" and \n");
|
||||
if (ccx_options.extract!=1)
|
||||
{
|
||||
@@ -497,6 +519,11 @@ int main(int argc, char *argv[])
|
||||
wbout1.fh=STDOUT_FILENO;
|
||||
mprint ("Sending captions to stdout.\n");
|
||||
}
|
||||
else if(ccx_options.write_format == CCX_OF_RAW
|
||||
&& ccx_options.extract == 12)
|
||||
{
|
||||
memcpy(&wbout2, &wbout1,sizeof(wbout1));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wbout2.filename[0]==0)
|
||||
@@ -512,20 +539,26 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
fatal (EXIT_FILE_CREATION_FAILED, "Failed\n");
|
||||
}
|
||||
if(ccx_options.write_format == CCX_OF_RAW)
|
||||
writeraw (BROADCAST_HEADER,sizeof (BROADCAST_HEADER),&wbout2);
|
||||
}
|
||||
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_RAW:
|
||||
writeraw (BROADCAST_HEADER,sizeof (BROADCAST_HEADER),&wbout2);
|
||||
break;
|
||||
case CCX_OF_DVDRAW:
|
||||
break;
|
||||
case CCX_OF_RCWT:
|
||||
if( init_encoder(enc_ctx+1,&wbout2) )
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
if (ccx_options.encoding==CCX_ENC_UTF_8) // Write BOM
|
||||
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.out);
|
||||
if( init_encoder(enc_ctx+1,&wbout2) )
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -533,16 +566,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_TRANSCRIPT)
|
||||
if (ccx_options.write_format != CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
if (wbout1.fh!=-1)
|
||||
wbxdsout=&wbout1;
|
||||
else
|
||||
if (wbout2.fh!=-1)
|
||||
wbxdsout=&wbout2;
|
||||
}
|
||||
else
|
||||
ccx_options.transcript_settings.xds = 0;
|
||||
mprint ("Warning: -xds ignored, XDS can only be exported to transcripts at this time.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.teletext_mode == CCX_TXT_IN_USE) // Here, it would mean it was forced by user
|
||||
@@ -614,9 +642,11 @@ int main(int argc, char *argv[])
|
||||
case CCX_SM_MP4:
|
||||
mprint ("\rFile seems to be a MP4\n");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("\rFile seems to be an hexadecimal dump\n");
|
||||
break;
|
||||
#endif
|
||||
case CCX_SM_MYTH:
|
||||
case CCX_SM_AUTODETECT:
|
||||
fatal(EXIT_BUG_BUG, "Cannot be reached!");
|
||||
@@ -673,30 +703,32 @@ int main(int argc, char *argv[])
|
||||
if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something
|
||||
ccx_options.use_gop_as_pts = 0;
|
||||
mprint ("\rAnalyzing data in general mode\n");
|
||||
general_loop();
|
||||
general_loop(&enc_ctx);
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("\rAnalyzing data in McPoodle raw mode\n");
|
||||
raw_loop();
|
||||
raw_loop(&enc_ctx);
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("\rAnalyzing data in CCExtractor's binary format\n");
|
||||
rcwt_loop();
|
||||
rcwt_loop(&enc_ctx);
|
||||
break;
|
||||
case CCX_SM_MYTH:
|
||||
mprint ("\rAnalyzing data in MythTV mode\n");
|
||||
show_myth_banner = 1;
|
||||
myth_loop();
|
||||
myth_loop(&enc_ctx);
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("\rAnalyzing data with GPAC (MP4 library)\n");
|
||||
close_input_file(); // No need to have it open. GPAC will do it for us
|
||||
processmp4 (inputfile[0]);
|
||||
processmp4 (inputfile[0],&enc_ctx);
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
close_input_file(); // processhex will open it in text mode
|
||||
processhex (inputfile[0]);
|
||||
processhex (inputfile[0]);
|
||||
break;
|
||||
#endif
|
||||
case CCX_SM_AUTODETECT:
|
||||
fatal(EXIT_BUG_BUG, "Cannot be reached!");
|
||||
break;
|
||||
@@ -824,38 +856,38 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (wbout1.fh!=-1)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_SPUPNG)
|
||||
{
|
||||
handle_end_of_data(&context_cc608_field_1);
|
||||
}
|
||||
if (ccx_options.write_format==CCX_OF_SMPTETT || ccx_options.write_format==CCX_OF_SAMI ||
|
||||
ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT)
|
||||
ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT
|
||||
|| ccx_options.write_format==CCX_OF_SPUPNG )
|
||||
{
|
||||
handle_end_of_data(&context_cc608_field_1);
|
||||
handle_end_of_data(&context_cc608_field_1, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
else if(ccx_options.write_format==CCX_OF_RCWT)
|
||||
{
|
||||
// Write last header and data
|
||||
writercwtdata (NULL);
|
||||
}
|
||||
if (ccx_options.end_credits_text!=NULL)
|
||||
try_to_add_end_credits(&context_cc608_field_1);
|
||||
write_subtitle_file_footer(context_cc608_field_1.out);
|
||||
dinit_encoder(enc_ctx);
|
||||
}
|
||||
if (wbout2.fh!=-1)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_SPUPNG)
|
||||
{
|
||||
handle_end_of_data(&context_cc608_field_2);
|
||||
}
|
||||
if (ccx_options.write_format==CCX_OF_SMPTETT || ccx_options.write_format==CCX_OF_SAMI ||
|
||||
ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT)
|
||||
ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT
|
||||
|| ccx_options.write_format==CCX_OF_SPUPNG )
|
||||
{
|
||||
handle_end_of_data(&context_cc608_field_2);
|
||||
handle_end_of_data(&context_cc608_field_2, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
if (ccx_options.end_credits_text!=NULL)
|
||||
try_to_add_end_credits(&context_cc608_field_2);
|
||||
write_subtitle_file_footer(context_cc608_field_2.out);
|
||||
dinit_encoder(enc_ctx+1);
|
||||
}
|
||||
telxcc_close();
|
||||
flushbuffer (&wbout1,true);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// compatibility across platforms
|
||||
#include "platform.h"
|
||||
|
||||
#define VERSION "0.70"
|
||||
#define VERSION "0.72"
|
||||
|
||||
extern int cc_buffer_saved; // Do we have anything in the CC buffer already?
|
||||
extern int ccblocks_in_avc_total; // Total CC blocks found by the AVC code
|
||||
@@ -23,6 +23,8 @@ extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to
|
||||
#include "708.h"
|
||||
#include "bitstream.h"
|
||||
#include "constants.h"
|
||||
#include "cc_decoders_common.h"
|
||||
#include "networking.h"
|
||||
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
|
||||
@@ -114,8 +116,13 @@ struct ccx_s_options // Options from user parameters
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
in_addr_t udpaddr;
|
||||
char *udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
unsigned send_to_srv;
|
||||
char *tcpport;
|
||||
char *tcp_password;
|
||||
char *srv_addr;
|
||||
char *srv_port;
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
int noautotimeref; // Do NOT set time automatically?
|
||||
enum ccx_datasource input_source; // Files, stdin or network
|
||||
@@ -244,11 +251,11 @@ void position_sanity_check ();
|
||||
int init_file_buffer( void );
|
||||
LLONG ps_getmoredata( void );
|
||||
LLONG general_getmoredata( void );
|
||||
void raw_loop (void);
|
||||
LLONG process_raw (void);
|
||||
void general_loop(void);
|
||||
void raw_loop (void *enc_ctx);
|
||||
LLONG process_raw (struct cc_subtitle *sub);
|
||||
void general_loop(void *enc_ctx);
|
||||
void processhex (char *filename);
|
||||
void rcwt_loop( void );
|
||||
void rcwt_loop(void *enc_ctx);
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define false 0
|
||||
@@ -283,21 +290,21 @@ LLONG asf_getmoredata( void );
|
||||
LLONG wtv_getmoredata( void );
|
||||
|
||||
// avc_functions.c
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen);
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen, struct cc_subtitle *sub);
|
||||
void init_avc(void);
|
||||
|
||||
// es_functions.c
|
||||
LLONG process_m2v (unsigned char *data, LLONG length);
|
||||
LLONG process_m2v (unsigned char *data, LLONG length, struct cc_subtitle *sub);
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
// es_userdata.c
|
||||
int user_data(struct bitstream *ustream, int udtype);
|
||||
int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
|
||||
|
||||
// bitstream.c - see bitstream.h
|
||||
|
||||
// 608.c
|
||||
int write_cc_buffer(struct s_context_cc608 *context);
|
||||
int write_cc_buffer(struct s_context_cc608 *context, struct cc_subtitle *sub);
|
||||
unsigned char *debug_608toASC (unsigned char *ccdata, int channel);
|
||||
|
||||
|
||||
@@ -311,7 +318,6 @@ LLONG gettotalfilessize (void);
|
||||
void prepare_for_new_file (void);
|
||||
void close_input_file (void);
|
||||
int switch_to_next_file (LLONG bytesinbuffer);
|
||||
int init_sockets (void);
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// timing.c
|
||||
@@ -326,13 +332,12 @@ void calculate_ms_gop_time (struct gop_time_code *g);
|
||||
|
||||
// sequencing.c
|
||||
void init_hdcc (void);
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts);
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts, struct cc_subtitle *sub);
|
||||
void anchor_hdcc(int seq);
|
||||
void process_hdcc (void);
|
||||
int do_cb (unsigned char *cc_block);
|
||||
|
||||
void process_hdcc (struct cc_subtitle *sub);
|
||||
int do_cb (unsigned char *cc_block, struct cc_subtitle *sub);
|
||||
// mp4.c
|
||||
int processmp4 (char *file);
|
||||
int processmp4 (char *file,void *enc_ctx);
|
||||
|
||||
// params_dump.c
|
||||
void params_dump(void);
|
||||
@@ -341,9 +346,9 @@ void print_file_report(void);
|
||||
// output.c
|
||||
void init_write (struct ccx_s_write *wb);
|
||||
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
|
||||
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context);
|
||||
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context, struct cc_subtitle *sub);
|
||||
void flushbuffer (struct ccx_s_write *wb, int closefile);
|
||||
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2);
|
||||
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2, struct cc_subtitle *sub);
|
||||
void writercwtdata (const unsigned char *data);
|
||||
|
||||
// stream_functions.c
|
||||
@@ -362,28 +367,17 @@ int parse_PMT (unsigned char *buf,int len, int pos);
|
||||
int parse_PAT (void);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(void);
|
||||
|
||||
// mp4_bridge2bento4.c
|
||||
void mp4_loop (char *filename);
|
||||
void myth_loop(void *enc_ctx);
|
||||
|
||||
// xds.c
|
||||
void process_xds_bytes (const unsigned char hi, int lo);
|
||||
void do_end_of_xds (unsigned char expected_checksum);
|
||||
void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum);
|
||||
void xds_init();
|
||||
|
||||
// ccextractor.c
|
||||
LLONG calculate_gop_mstime (struct gop_time_code *g);
|
||||
void set_fts(void);
|
||||
char *print_mstime( LLONG mstime );
|
||||
void print_debug_timing( void );
|
||||
int switch_to_next_file (LLONG bytesinbuffer);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
void dvprint(const char *fmt, ...);
|
||||
void mprint (const char *fmt, ...);
|
||||
void subsprintf (const char *fmt, ...);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
void fdprintf (int fd, const char *fmt, ...);
|
||||
void init_boundary_time (struct ccx_boundary_time *bt);
|
||||
@@ -398,8 +392,6 @@ 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 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) ;
|
||||
@@ -433,8 +425,6 @@ extern int current_file;
|
||||
extern LLONG result; // Number of bytes read/skipped in last read operation
|
||||
|
||||
|
||||
extern struct sockaddr_in servaddr, cliaddr;
|
||||
|
||||
extern int strangeheader;
|
||||
|
||||
extern unsigned char startbytes[STARTBYTESLENGTH];
|
||||
|
||||
@@ -115,14 +115,17 @@ static void parse_file(FILE *f,struct ccx_s_options *opt)
|
||||
int comments = 0;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
while ((c = fgetc(f)) != EOF )
|
||||
*str = '\0';
|
||||
while ((c = (char)fgetc(f)) != EOF )
|
||||
{
|
||||
if( c == '\n')
|
||||
{
|
||||
if( str[0] != '\0')
|
||||
{
|
||||
ret = parse_opts(str,opt);
|
||||
if(ret < 0)
|
||||
mprint("invalid configuration file\n");
|
||||
}
|
||||
comments = 0;
|
||||
i = 0;
|
||||
str[0] = '\0';
|
||||
@@ -140,10 +143,10 @@ static void parse_file(FILE *f,struct ccx_s_options *opt)
|
||||
}
|
||||
void parse_configuration(struct ccx_s_options *opt)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
if( (f = fopen(CNF_FILE,"r") ) != NULL)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
if( (f = fopen(CNF_FILE,"r") ) != NULL)
|
||||
{
|
||||
parse_file(f,opt);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,3 +123,11 @@ enum
|
||||
DTVCC_PACKET_DATA = 2,
|
||||
DTVCC_PACKET_START = 3,
|
||||
};
|
||||
|
||||
const char *language[4] =
|
||||
{
|
||||
"und",
|
||||
"eng",
|
||||
"fin",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -138,7 +138,8 @@ enum ccx_datasource
|
||||
{
|
||||
CCX_DS_FILE=0,
|
||||
CCX_DS_STDIN=1,
|
||||
CCX_DS_NETWORK=2
|
||||
CCX_DS_NETWORK=2,
|
||||
CCX_DS_TCP=3
|
||||
};
|
||||
|
||||
enum ccx_output_format
|
||||
@@ -173,7 +174,9 @@ enum ccx_stream_mode_enum
|
||||
CCX_SM_RCWT = 5, // Raw Captions With Time, not used yet.
|
||||
CCX_SM_MYTH = 6, // Use the myth loop
|
||||
CCX_SM_MP4 = 7, // MP4, ISO-
|
||||
#ifdef WTV_DEBUG
|
||||
CCX_SM_HEX_DUMP = 8, // Hexadecimal dump generated by wtvccdump
|
||||
#endif
|
||||
CCX_SM_WTV = 9,
|
||||
CCX_SM_AUTODETECT = 16
|
||||
};
|
||||
@@ -255,8 +258,11 @@ enum cxx_code_type
|
||||
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
|
||||
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
|
||||
|
||||
|
||||
#define CCX_OF_TYPE_TEXT 1
|
||||
#define CCX_OF_TYPE_IMAGE 2
|
||||
|
||||
enum subtype
|
||||
{
|
||||
CC_BITMAP,
|
||||
CC_608,
|
||||
CC_TEXT,
|
||||
};
|
||||
extern const char *language[4];
|
||||
#endif
|
||||
|
||||
@@ -21,20 +21,10 @@
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf(str,size,format,...) _snprintf(str,size-1,format,__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PNG_DEBUG 3
|
||||
#include "png.h"
|
||||
#endif
|
||||
#include "cc_decoders_common.h"
|
||||
|
||||
#define DVBSUB_PAGE_SEGMENT 0x10
|
||||
#define DVBSUB_REGION_SEGMENT 0x11
|
||||
@@ -95,7 +85,6 @@ const uint8_t crop_tab[256 + 2 * MAX_NEG_CROP] = { times256(0x00), 0x00, 0x01,
|
||||
|
||||
#define cm (crop_tab + MAX_NEG_CROP)
|
||||
|
||||
const char *dvb_language[] = { "und", "eng", "fin", NULL };
|
||||
|
||||
static __inline unsigned int bytestream_get_byte(const uint8_t **b)
|
||||
{
|
||||
@@ -161,7 +150,7 @@ static __inline unsigned int get_bits(GetBitContext *s, int n)
|
||||
unsigned int re_cache = 0;
|
||||
unsigned int re_size_plus8 = s->size_in_bits_plus8;
|
||||
|
||||
if (n <= 0 && n > 25)
|
||||
if (n <= 0 || n > 25)
|
||||
return -1;
|
||||
re_cache = RB32( s->buffer + (re_index >> 3 )) << (re_index & 7);
|
||||
|
||||
@@ -189,308 +178,6 @@ static __inline unsigned int get_bits1(GetBitContext *s)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void freep(void *arg)
|
||||
{
|
||||
void **ptr = (void **) arg;
|
||||
if (*ptr)
|
||||
free(*ptr);
|
||||
*ptr = NULL;
|
||||
|
||||
}
|
||||
#ifdef DEBUG
|
||||
|
||||
struct transIntensity
|
||||
{
|
||||
uint8_t *t;
|
||||
uint8_t *i;
|
||||
};
|
||||
int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
struct transIntensity *ti = arg;
|
||||
unsigned char* tmp = (unsigned char*)p1;
|
||||
unsigned char* act = (unsigned char*)p2;
|
||||
|
||||
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && ti->i[*tmp] < ti->i[*act]))
|
||||
return -1;
|
||||
else if (ti->t[*tmp] == ti->t[*act] && ti->i[*tmp] == ti->i[*act])
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
uint8_t depth)
|
||||
{
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
palette[i].red = ((clut[i] >> 16) & 0xff);
|
||||
palette[i].green = ((clut[i] >> 8) & 0xff);
|
||||
palette[i].blue = (clut[i] & 0xff);
|
||||
alpha[i] = ((clut[i] >> 24) & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* @param alpha out
|
||||
* @param intensity in
|
||||
* @param palette out should be already initialized
|
||||
* @param bitmap in
|
||||
* @param size in size of bitmap
|
||||
* @param max_color in
|
||||
* @param nb_color in
|
||||
*/
|
||||
int quantize_map(png_byte *alpha, uint8_t *intensity, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color)
|
||||
{
|
||||
/*
|
||||
* occurrence of color in image
|
||||
*/
|
||||
uint32_t *histogram = NULL;
|
||||
/* intensity ordered table */
|
||||
uint8_t *iot = NULL;
|
||||
/* array of color with most occurrence according to histogram
|
||||
* save index of intensity order table
|
||||
*/
|
||||
uint32_t *mcit = NULL;
|
||||
struct transIntensity ti = { alpha,intensity};
|
||||
|
||||
int ret = 0;
|
||||
|
||||
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!histogram)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
|
||||
if (!iot)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!mcit)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(histogram, 0, nb_color * sizeof(uint32_t));
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
iot[i] = i;
|
||||
}
|
||||
memset(mcit, 0, nb_color * sizeof(uint32_t));
|
||||
|
||||
/* calculate histogram of image */
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
histogram[bitmap[i]]++;
|
||||
}
|
||||
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
|
||||
|
||||
/* using selection sort since need to find only max_color */
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
uint32_t max_val = 0;
|
||||
uint32_t max_ind = 0;
|
||||
int j;
|
||||
for (j = 0; j < nb_color; j++)
|
||||
{
|
||||
if (max_val < histogram[iot[j]])
|
||||
{
|
||||
max_val = histogram[iot[j]];
|
||||
max_ind = j;
|
||||
}
|
||||
}
|
||||
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
|
||||
{
|
||||
mcit[j] = mcit[j - 1];
|
||||
}
|
||||
mcit[j] = max_ind;
|
||||
histogram[iot[max_ind]] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0, mxi = 0; i < nb_color; i++)
|
||||
{
|
||||
int step, inc;
|
||||
if (i == mcit[mxi])
|
||||
{
|
||||
mxi = (mxi < max_color) ? mxi + 1 : mxi;
|
||||
continue;
|
||||
}
|
||||
inc = (mxi) ? -1 : 0;
|
||||
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 3);
|
||||
if (i <= step)
|
||||
{
|
||||
int index = iot[mcit[mxi + inc]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = iot[mcit[mxi]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
|
||||
}
|
||||
end: freep(&histogram);
|
||||
freep(&mcit);
|
||||
freep(&iot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int pre_process_bitmap(png_color **palette, png_byte **alpha, int size,
|
||||
uint32_t *clut, uint8_t *luit, uint8_t *bitmap, uint8_t depth)
|
||||
{
|
||||
/*local pointer to palette */
|
||||
png_color *lpalette = NULL;
|
||||
/* local pointer to alpha */
|
||||
png_byte *lalpha = NULL;
|
||||
int nb_color = (1<< depth);
|
||||
int ret = 0;
|
||||
|
||||
|
||||
lpalette = (png_color*) malloc(nb_color * sizeof(png_color));
|
||||
if(!lpalette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
lalpha = (png_byte*) malloc(nb_color * sizeof(png_byte));
|
||||
if(!lalpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
if(clut)
|
||||
mapclut_paletee(lpalette, lalpha, clut, nb_color);
|
||||
else
|
||||
{
|
||||
/* initialize colors with white */
|
||||
memset(palette,0xff,sizeof(nb_color * sizeof(*lpalette)));
|
||||
|
||||
/* initialize transparency as complete transparent */
|
||||
memset(lalpha,0,sizeof(nb_color * sizeof(*lalpha)));
|
||||
}
|
||||
|
||||
if(bitmap)
|
||||
{
|
||||
quantize_map(lalpha, luit, lpalette, bitmap, size, 3, nb_color);
|
||||
}
|
||||
*palette = lpalette;
|
||||
*alpha = lalpha;
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
|
||||
png_color *palette, png_byte *alpha, int nb_color)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
png_bytep* row_pointer = NULL;
|
||||
int i, j, ret = 0;
|
||||
int k = 0;
|
||||
if(!h)
|
||||
h = 1;
|
||||
if(!w)
|
||||
w = 1;
|
||||
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
{
|
||||
mprint("DVB:unable to open %s in write mode \n", filename);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,NULL);
|
||||
if (!png_ptr)
|
||||
{
|
||||
mprint("DVB:unable to create png write struct\n");
|
||||
goto end;
|
||||
}
|
||||
if (!(info_ptr = png_create_info_struct(png_ptr)))
|
||||
{
|
||||
mprint("DVB:unable to create png info struct\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
row_pointer = (png_bytep*) malloc(sizeof(png_bytep) * h);
|
||||
if (!row_pointer)
|
||||
{
|
||||
mprint("DVB: unable to allocate row_pointer\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
memset(row_pointer, 0, sizeof(png_bytep) * h);
|
||||
png_init_io(png_ptr, f);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h,
|
||||
/* bit_depth */8,
|
||||
PNG_COLOR_TYPE_PALETTE,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, nb_color);
|
||||
png_set_tRNS(png_ptr, info_ptr, alpha, nb_color, NULL);
|
||||
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
row_pointer[i] = (png_byte*) malloc(
|
||||
png_get_rowbytes(png_ptr, info_ptr));
|
||||
if (row_pointer[i] == NULL)
|
||||
break;
|
||||
}
|
||||
if (i != h)
|
||||
{
|
||||
mprint("DVB: unable to allocate row_pointer internals\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++)
|
||||
{
|
||||
if(bitmap)
|
||||
k = bitmap[i * w + (j)];
|
||||
else
|
||||
k = 0;
|
||||
row_pointer[i][j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, row_pointer);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
end: if (row_pointer)
|
||||
{
|
||||
for (i = 0; i < h; i++)
|
||||
freep(&row_pointer[i]);
|
||||
freep(&row_pointer);
|
||||
}
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
if (f)
|
||||
fclose(f);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
|
||||
|
||||
typedef struct DVBSubCLUT
|
||||
@@ -582,7 +269,7 @@ typedef struct DVBSubContext
|
||||
{
|
||||
int composition_id;
|
||||
int ancillary_id;
|
||||
|
||||
int lang_index;
|
||||
int version;
|
||||
int time_out;
|
||||
DVBSubRegion *region_list;
|
||||
@@ -591,17 +278,8 @@ typedef struct DVBSubContext
|
||||
|
||||
DVBSubRegionDisplay *display_list;
|
||||
DVBSubDisplayDefinition *display_definition;
|
||||
struct ccx_s_write *out;
|
||||
long long prev_start;
|
||||
} DVBSubContext;
|
||||
|
||||
typedef struct DVBOutContext
|
||||
{
|
||||
long long start_time;
|
||||
long long end_time;
|
||||
|
||||
}DVBOutContext;
|
||||
|
||||
static DVBSubObject* get_object(DVBSubContext *ctx, int object_id)
|
||||
{
|
||||
DVBSubObject *ptr = ctx->object_list;
|
||||
@@ -729,124 +407,6 @@ static void delete_regions(DVBSubContext *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void save_display_set(DVBSubContext *ctx)
|
||||
{
|
||||
DVBSubRegion *region;
|
||||
DVBSubRegionDisplay *display;
|
||||
DVBSubCLUT *clut;
|
||||
int x_pos, y_pos, width, height;
|
||||
int x, y, y_off, x_off;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
void *sp = ctx->out->spupng_data;
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
|
||||
for (display = ctx->display_list; display; display = display->next)
|
||||
{
|
||||
region = get_region(ctx, display->region_id);
|
||||
|
||||
if (x_pos == -1)
|
||||
{
|
||||
x_pos = display->x_pos;
|
||||
y_pos = display->y_pos;
|
||||
width = region->width;
|
||||
height = region->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (display->x_pos < x_pos)
|
||||
{
|
||||
width += (x_pos - display->x_pos);
|
||||
x_pos = display->x_pos;
|
||||
}
|
||||
|
||||
if (display->y_pos < y_pos)
|
||||
{
|
||||
height += (y_pos - display->y_pos);
|
||||
y_pos = display->y_pos;
|
||||
}
|
||||
|
||||
if (display->x_pos + region->width > x_pos + width)
|
||||
{
|
||||
width = display->x_pos + region->width - x_pos;
|
||||
}
|
||||
|
||||
if (display->y_pos + region->height > y_pos + height)
|
||||
{
|
||||
height = display->y_pos + region->height - y_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x_pos >= 0)
|
||||
{
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
|
||||
filename = get_spupng_filename(sp);
|
||||
inc_spupng_fileindex(sp);
|
||||
set_spupng_offset(sp,y_pos,x_pos);
|
||||
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for (display = ctx->display_list; display; display = display->next)
|
||||
{
|
||||
region = get_region(ctx, display->region_id);
|
||||
|
||||
x_off = display->x_pos - x_pos;
|
||||
y_off = display->y_pos - y_pos;
|
||||
|
||||
clut = get_clut(ctx, region->clut);
|
||||
|
||||
if (clut == 0)
|
||||
clut = &default_clut;
|
||||
|
||||
for (y = 0; y < region->height; y++)
|
||||
{
|
||||
for (x = 0; x < region->width; x++)
|
||||
{
|
||||
pbuf[((y + y_off) * width) + x_off + x] =
|
||||
region->pbuf[y * region->width + x];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
pre_process_bitmap(&palette,&alpha,width*height,clut->clut16, clut->ilut16,pbuf,region->depth);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str)
|
||||
{
|
||||
write_spucomment(sp,str);
|
||||
}
|
||||
#endif
|
||||
save_spupng(filename, pbuf, width, height, palette, alpha,(1 << region->depth));
|
||||
|
||||
free(pbuf);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
}
|
||||
else if(!ctx->prev_start)
|
||||
{
|
||||
png_color palette = {0,0,0};
|
||||
png_byte alpha = 0;
|
||||
filename = get_spupng_filename(sp);
|
||||
inc_spupng_fileindex(sp);
|
||||
/* save dummy frame */
|
||||
save_spupng(filename,NULL,1,1,&palette,&alpha,1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param composition_id composition-page_id found in Subtitle descriptors
|
||||
@@ -859,14 +419,15 @@ static void save_display_set(DVBSubContext *ctx)
|
||||
* @return DVB context kept as void* for abstraction
|
||||
*
|
||||
*/
|
||||
void* dvbsub_init_decoder(int composition_id, int ancillary_id)
|
||||
void* dvbsub_init_decoder(struct dvb_config* cfg)
|
||||
{
|
||||
int i, r, g, b, a = 0;
|
||||
DVBSubContext *ctx = (DVBSubContext*) malloc(sizeof(DVBSubContext));
|
||||
memset(ctx, 0, sizeof(DVBSubContext));
|
||||
|
||||
ctx->composition_id = composition_id;
|
||||
ctx->ancillary_id = ancillary_id;
|
||||
ctx->composition_id = cfg->composition_id[0];
|
||||
ctx->ancillary_id = cfg->ancillary_id[0];
|
||||
ctx->lang_index = cfg->lang_index[0];
|
||||
|
||||
ctx->version = -1;
|
||||
|
||||
@@ -1738,9 +1299,6 @@ static void dvbsub_parse_page_segment(void *dvb_ctx, const uint8_t *buf,
|
||||
int page_state;
|
||||
int timeout;
|
||||
int version;
|
||||
long long start = get_visible_start();
|
||||
void *sp = ctx->out->spupng_data;
|
||||
|
||||
|
||||
if (buf_size < 1)
|
||||
return;
|
||||
@@ -1758,19 +1316,6 @@ static void dvbsub_parse_page_segment(void *dvb_ctx, const uint8_t *buf,
|
||||
ctx->time_out = timeout;
|
||||
ctx->version = version;
|
||||
|
||||
if(ctx->prev_start == 0)
|
||||
{
|
||||
write_sputag(sp, ctx->prev_start, start);
|
||||
save_display_set(ctx);
|
||||
}
|
||||
else if(ctx->display_list)
|
||||
{
|
||||
write_sputag(sp, ctx->prev_start, start);
|
||||
save_display_set(ctx);
|
||||
}
|
||||
|
||||
ctx->prev_start = start;
|
||||
|
||||
if (page_state == 1 || page_state == 2)
|
||||
{
|
||||
delete_regions(ctx);
|
||||
@@ -1870,23 +1415,45 @@ static void dvbsub_parse_display_definition_segment(void *dvb_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static int dvbsub_display_end_segment(void *dvb_ctx, const uint8_t *buf,
|
||||
int buf_size)
|
||||
static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
|
||||
DVBSubRegion *region;
|
||||
DVBSubRegionDisplay *display;
|
||||
DVBSubCLUT *clut;
|
||||
int i;
|
||||
DVBSubDisplayDefinition *display_def = ctx->display_definition;
|
||||
struct cc_bitmap *rect = NULL;
|
||||
uint32_t *clut_table;
|
||||
int offset_x=0, offset_y=0;
|
||||
|
||||
sub->type = CC_BITMAP;
|
||||
sub->lang_index = ctx->lang_index;
|
||||
if (display_def)
|
||||
{
|
||||
offset_x = display_def->x;
|
||||
offset_y = display_def->y;
|
||||
}
|
||||
|
||||
for (display = ctx->display_list; display; display = display->next)
|
||||
{
|
||||
region = get_region(ctx, display->region_id);
|
||||
if (region && region->dirty)
|
||||
sub->nb_data++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
sub->start_time = get_visible_start();
|
||||
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
|
||||
sub->flags |= SUB_EOD_MARKER;
|
||||
sub->got_output = 1;
|
||||
if( sub->nb_data <= 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
rect = malloc( sizeof(struct cc_bitmap) * sub->nb_data);
|
||||
if(!rect)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
sub->data = rect;
|
||||
for (display = ctx->display_list; display; display = display->next)
|
||||
{
|
||||
region = get_region(ctx, display->region_id);
|
||||
@@ -1896,34 +1463,60 @@ static int dvbsub_display_end_segment(void *dvb_ctx, const uint8_t *buf,
|
||||
|
||||
if (!region->dirty)
|
||||
continue;
|
||||
|
||||
rect->x = display->x_pos + offset_x;
|
||||
rect->y = display->y_pos + offset_y;
|
||||
rect->w = region->width;
|
||||
rect->h = region->height;
|
||||
rect->nb_colors = (1 << region->depth);
|
||||
rect->linesize[0] = region->width;
|
||||
|
||||
clut = get_clut(ctx, region->clut);
|
||||
|
||||
if (!clut)
|
||||
clut = &default_clut;
|
||||
|
||||
i++;
|
||||
switch (region->depth)
|
||||
{
|
||||
case 2:
|
||||
clut_table = clut->clut4;
|
||||
case 8:
|
||||
clut_table = clut->clut256;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
clut_table = clut->clut16;
|
||||
break;
|
||||
}
|
||||
|
||||
rect->data[1] = malloc(1024);
|
||||
memset(rect->data[1], 0, 1024);
|
||||
memcpy(rect->data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
|
||||
|
||||
rect->data[0] = malloc(region->buf_size);
|
||||
memcpy(rect->data[0], region->pbuf, region->buf_size);
|
||||
rect++;
|
||||
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DeBUG
|
||||
if (ctx->object_list)
|
||||
{
|
||||
//save_display_set(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @param dvb_ctx PreInitialized DVB context using DVB
|
||||
* @param data output subtitle data, to be implemented
|
||||
* @param data_size Output subtitle data size. pass the pointer to an integer, NOT to be NULL.
|
||||
* @param buf buffer containing segment data, first sync byte need to 0x0f.
|
||||
* does not include data_identifier and subtitle_stream_id.
|
||||
* @param buf_size size of buf buffer
|
||||
* @param sub output subtitle data
|
||||
*
|
||||
* @return -1 on error
|
||||
*/
|
||||
int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
|
||||
const unsigned char *buf, int buf_size)
|
||||
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
const uint8_t *p, *p_end;
|
||||
@@ -1973,7 +1566,7 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
|
||||
case DVBSUB_CLUT_SEGMENT:
|
||||
ret = dvbsub_parse_clut_segment(dvb_ctx, p, segment_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto end;
|
||||
got_segment |= 4;
|
||||
break;
|
||||
case DVBSUB_OBJECT_SEGMENT:
|
||||
@@ -1985,8 +1578,7 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
|
||||
segment_length);
|
||||
break;
|
||||
case DVBSUB_DISPLAY_SEGMENT:
|
||||
*data_size = dvbsub_display_end_segment(dvb_ctx, p,
|
||||
segment_length);
|
||||
write_dvb_sub(dvb_ctx,sub);
|
||||
got_segment |= 16;
|
||||
break;
|
||||
default:
|
||||
@@ -2002,11 +1594,15 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
|
||||
// segments then we need no further data.
|
||||
if (got_segment == 15)
|
||||
{
|
||||
*data_size = dvbsub_display_end_segment(dvb_ctx, p, 0);
|
||||
write_dvb_sub(dvb_ctx,sub);
|
||||
|
||||
|
||||
}
|
||||
end:
|
||||
if ( ret >= 0 )
|
||||
ret = p - buf;
|
||||
|
||||
return p - buf;
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @func parse_dvb_description
|
||||
@@ -2051,9 +1647,9 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
|
||||
for (i = 0; i < cfg->n_language; i++, data += i * 8)
|
||||
{
|
||||
/* setting language to undefined if not found in language lkup table */
|
||||
for (j = 0, cfg->lang_index[i] = 0; dvb_language[j] != NULL; j++)
|
||||
for (j = 0, cfg->lang_index[i] = 0; language[j] != NULL; j++)
|
||||
{
|
||||
if (!strncmp((const char*) (data), dvb_language[j], 3))
|
||||
if (!strncmp((const char*) (data), language[j], 3))
|
||||
cfg->lang_index[i] = j;
|
||||
}
|
||||
cfg->sub_type[i] = data[3];
|
||||
@@ -2064,17 +1660,3 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* @func dvbsub_set_write the output structure in dvb
|
||||
* set ccx_s_write structure in dvb_ctx
|
||||
*
|
||||
* @param dvb_ctx context of dvb which was returned by dvbsub_init_decoder
|
||||
*
|
||||
* @param out output context returned by init_write
|
||||
*
|
||||
*/
|
||||
void dvbsub_set_write(void *dvb_ctx, struct ccx_s_write *out)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
ctx->out = out;
|
||||
}
|
||||
|
||||
@@ -37,32 +37,26 @@ struct dvb_config
|
||||
};
|
||||
|
||||
/**
|
||||
* @param composition_id composition-page_id found in Subtitle descriptors
|
||||
* associated with subtitle stream in the PMT
|
||||
* it could be -1 if not found in PMT.
|
||||
* @param ancillary_id ancillary-page_id found in Subtitle descriptors
|
||||
* associated with subtitle stream in the PMT.
|
||||
* it could be -1 if not found in PMT.
|
||||
* @param cfg Structure containg configuration
|
||||
*
|
||||
* @return DVB context kept as void* for abstraction
|
||||
*
|
||||
*/
|
||||
void* dvbsub_init_decoder(int composition_id, int ancillary_id);
|
||||
void* dvbsub_init_decoder(struct dvb_config* cfg);
|
||||
|
||||
int dvbsub_close_decoder(void *dvb_ctx);
|
||||
|
||||
/**
|
||||
* @param dvb_ctx PreInitialized DVB context using DVB
|
||||
* @param data output subtitle data, to be implemented
|
||||
* @param data_size Output subtitle data size. pass the pointer to an intiger, NOT to be NULL.
|
||||
* @param buf buffer containg segment data, first sync byte needto 0x0f.
|
||||
* @param buf buffer containing segment data, first sync byte need to 0x0f.
|
||||
* does not include data_identifier and subtitle_stream_id.
|
||||
* @param buf_size size of buf buffer
|
||||
* @param sub output subtitle data
|
||||
*
|
||||
* @return -1 on error
|
||||
*/
|
||||
int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
|
||||
const unsigned char *buf, int buf_size);
|
||||
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
|
||||
|
||||
/**
|
||||
* @func parse_dvb_description
|
||||
*
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
// Functions to parse a mpeg-2 data stream, see ISO/IEC 13818-2 6.2
|
||||
|
||||
static int no_bitstream_error = 0;
|
||||
@@ -20,24 +19,24 @@ static unsigned pulldownfields = 0;
|
||||
|
||||
static uint8_t search_start_code(struct bitstream *esstream);
|
||||
static uint8_t next_start_code(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct bitstream *esstream);
|
||||
static int sequence_header(struct bitstream *esstream);
|
||||
static int sequence_ext(struct bitstream *esstream);
|
||||
static int read_gop_info(struct bitstream *esstream);
|
||||
static int gop_header(struct bitstream *esstream);
|
||||
static int read_pic_info(struct bitstream *esstream);
|
||||
static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int pic_header(struct bitstream *esstream);
|
||||
static int pic_coding_ext(struct bitstream *esstream);
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype);
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype);
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype , struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int read_pic_data(struct bitstream *esstream);
|
||||
|
||||
|
||||
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data".
|
||||
* The number of processed bytes is returned.
|
||||
* Defined in ISO/IEC 13818-2 6.2 */
|
||||
LLONG process_m2v (unsigned char *data, LLONG length)
|
||||
LLONG process_m2v (unsigned char *data, LLONG length,struct cc_subtitle *sub)
|
||||
{
|
||||
if (length<8) // Need to look ahead 8 bytes
|
||||
return length;
|
||||
@@ -48,7 +47,7 @@ LLONG process_m2v (unsigned char *data, LLONG length)
|
||||
|
||||
// Process data. The return value is ignored as esstream.pos holds
|
||||
// the information how far the parsing progressed.
|
||||
es_video_sequence(&esstream);
|
||||
es_video_sequence(&esstream, sub);
|
||||
|
||||
// This returns how many bytes were processed and can therefore
|
||||
// be discarded from "buffer". "esstream.pos" points to the next byte
|
||||
@@ -185,7 +184,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
// Otherwise. estream->pos shall point to the position where
|
||||
// the next call will continue, i.e. the possible begin of an
|
||||
// unfinished video sequence or after the finished sequence.
|
||||
static int es_video_sequence(struct bitstream *esstream)
|
||||
static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
// Avoid "Skip forward" message on first call and later only
|
||||
// once per search.
|
||||
@@ -272,7 +271,7 @@ static int es_video_sequence(struct bitstream *esstream)
|
||||
|
||||
if (!in_pic_data && startcode == 0xB8)
|
||||
{
|
||||
if (!read_gop_info(esstream))
|
||||
if (!read_gop_info(esstream,sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -284,7 +283,7 @@ static int es_video_sequence(struct bitstream *esstream)
|
||||
|
||||
if (!in_pic_data && startcode == 0x00)
|
||||
{
|
||||
if (!read_pic_info(esstream))
|
||||
if (!read_pic_info(esstream, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -300,7 +299,7 @@ static int es_video_sequence(struct bitstream *esstream)
|
||||
// This check needs to be before the "in_pic_data" part.
|
||||
if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
|
||||
{
|
||||
if (!read_eau_info(esstream, saw_seqgoppic-1))
|
||||
if (!read_eau_info(esstream, saw_seqgoppic-1, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -527,7 +526,7 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_gop_info(struct bitstream *esstream)
|
||||
static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info\n");
|
||||
|
||||
@@ -540,7 +539,7 @@ static int read_gop_info(struct bitstream *esstream)
|
||||
// after getting more.
|
||||
unsigned char *gop_info_start = esstream->pos;
|
||||
|
||||
gop_header(esstream);
|
||||
gop_header(esstream, sub);
|
||||
//extension_and_user_data(esstream);
|
||||
|
||||
if (esstream->error)
|
||||
@@ -561,7 +560,7 @@ static int read_gop_info(struct bitstream *esstream)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int gop_header(struct bitstream *esstream)
|
||||
static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
|
||||
|
||||
@@ -594,7 +593,7 @@ static int gop_header(struct bitstream *esstream)
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc();
|
||||
process_hdcc(sub);
|
||||
}
|
||||
|
||||
// Last GOPs pulldown frames
|
||||
@@ -698,7 +697,7 @@ static int gop_header(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_pic_info(struct bitstream *esstream)
|
||||
static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info\n");
|
||||
|
||||
@@ -737,7 +736,7 @@ static int read_pic_info(struct bitstream *esstream)
|
||||
// uses fts_now to re-create the timeline !!!!!
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc();
|
||||
process_hdcc(sub);
|
||||
}
|
||||
anchor_hdcc(temporal_reference);
|
||||
// }
|
||||
@@ -945,7 +944,7 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype)
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info\n");
|
||||
|
||||
@@ -959,7 +958,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype)
|
||||
// user data is not evaluated twice. Should the function run out of
|
||||
// data it will make sure that esstream points to where we want to
|
||||
// continue after getting more.
|
||||
if( !extension_and_user_data(esstream, udtype) )
|
||||
if( !extension_and_user_data(esstream, udtype, sub) )
|
||||
{
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nWarning: Retry while reading Extension and User Data!\n");
|
||||
@@ -978,7 +977,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype)
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data(%d)\n", udtype);
|
||||
|
||||
@@ -1030,7 +1029,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype)
|
||||
{
|
||||
struct bitstream ustream;
|
||||
init_bitstream(&ustream, dstart, esstream->pos);
|
||||
user_data(&ustream, udtype);
|
||||
user_data(&ustream, udtype, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if ustream->error
|
||||
// is FALSE, parsing can set ustream->error to TRUE.
|
||||
int user_data(struct bitstream *ustream, int udtype)
|
||||
int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
|
||||
|
||||
@@ -92,7 +92,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
rcbcount++;
|
||||
}
|
||||
else
|
||||
@@ -123,7 +123,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
ecbcount++;
|
||||
}
|
||||
else
|
||||
@@ -192,7 +192,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
}
|
||||
}
|
||||
cc_data[cc_count*3]=0xFF;
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now);
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
|
||||
}
|
||||
@@ -214,12 +214,12 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
data[0]=0x05; // Field 2
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
}
|
||||
// HDTV - see A/53 Part 4 (Video)
|
||||
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
|
||||
@@ -264,7 +264,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
// Please note we store the current value of the global
|
||||
// fts_now variable (and not get_fts()) as we are going to
|
||||
// re-create the timeline in process_hdcc() (Slightly ugly).
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now);
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
|
||||
}
|
||||
@@ -344,7 +344,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
|
||||
dishdata[cc_count*3] = 0xFF; // Set end marker
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -369,7 +369,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 4 (0x020A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -434,7 +434,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
|
||||
break;
|
||||
@@ -460,7 +460,7 @@ int user_data(struct bitstream *ustream, int udtype)
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
// This is probably incomplete!
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
long FILEBUFFERSIZE = 1024*1024*16; // 16 Mbytes no less. Minimize number of real read calls()
|
||||
LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
@@ -10,10 +9,17 @@ LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
LLONG getfilesize (int in)
|
||||
{
|
||||
LLONG current=LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in,0,SEEK_END);
|
||||
LSEEK (in,current,SEEK_SET);
|
||||
return length;
|
||||
int ret = 0;
|
||||
LLONG current=LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in,0,SEEK_END);
|
||||
if(current < 0 ||length < 0)
|
||||
return -1;
|
||||
|
||||
ret = LSEEK (in,current,SEEK_SET);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
LLONG gettotalfilessize (void) // -1 if one or more files failed to open
|
||||
@@ -89,26 +95,6 @@ void close_input_file (void)
|
||||
}
|
||||
}
|
||||
|
||||
int init_sockets (void)
|
||||
{
|
||||
static int socket_inited=0;
|
||||
if (!socket_inited)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData = {0};
|
||||
// Initialize Winsock
|
||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
wprintf(L"WSAStartup failed: %d\n", iResult);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
socket_inited=1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close current file and open next one in list -if any- */
|
||||
/* bytesinbuffer is the number of bytes read (in some buffer) that haven't been added
|
||||
to 'past' yet. We provide this number to switch_to_next_file() so a final sanity check
|
||||
@@ -144,42 +130,25 @@ int switch_to_next_file (LLONG bytesinbuffer)
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (init_sockets())
|
||||
return 1;
|
||||
infd=socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (IN_MULTICAST(ccx_options.udpaddr))
|
||||
|
||||
infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
|
||||
return 1;
|
||||
if(infd < 0)
|
||||
fatal (EXIT_BUG_BUG, "socket() failed.");
|
||||
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_TCP)
|
||||
{
|
||||
if (infd != -1)
|
||||
{
|
||||
int on = 1;
|
||||
(void)setsockopt(infd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
||||
}
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr=htonl(IN_MULTICAST(ccx_options.udpaddr) ? ccx_options.udpaddr : INADDR_ANY);
|
||||
servaddr.sin_port=htons(ccx_options.udpport);
|
||||
if (bind(infd,(struct sockaddr *)&servaddr,sizeof(servaddr)))
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "bind() failed.");
|
||||
}
|
||||
if (IN_MULTICAST(ccx_options.udpaddr)) {
|
||||
struct ip_mreq group;
|
||||
group.imr_multiaddr.s_addr = htonl(ccx_options.udpaddr);
|
||||
group.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (setsockopt(infd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "cannot join multicast group.");
|
||||
}
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
if (ccx_options.udpaddr == INADDR_ANY)
|
||||
{
|
||||
mprint ("\rReading from UDP socket %u\n",ccx_options.udpport);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl(ccx_options.udpaddr);
|
||||
mprint ("\rReading from UDP socket %s:%u\n", inet_ntoa(in), ccx_options.udpport);
|
||||
}
|
||||
infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -417,11 +386,8 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
|
||||
i=read (infd, filebuffer+keep,FILEBUFFERSIZE-keep);
|
||||
else
|
||||
{
|
||||
socklen_t len = sizeof(cliaddr);
|
||||
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,(struct sockaddr *)&cliaddr,&len);
|
||||
}
|
||||
if( i == -1)
|
||||
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
|
||||
if (i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
|
||||
if (i==0)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "708.h"
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
|
||||
#include "cc_encoders_common.h"
|
||||
// IMPORTED TRASH INFO, REMOVE
|
||||
extern long num_nal_unit_type_7;
|
||||
extern long num_vcl_hrd;
|
||||
@@ -44,7 +44,7 @@ int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
extern void *cxx_dvb_context;
|
||||
|
||||
LLONG process_raw_with_field (void);
|
||||
LLONG process_raw_with_field (struct cc_subtitle *sub);
|
||||
|
||||
// Program stream specific data grabber
|
||||
LLONG ps_getmoredata(void)
|
||||
@@ -266,6 +266,7 @@ LLONG general_getmoredata(void)
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
#ifdef WTV_DEBUG
|
||||
// Hexadecimal dump process
|
||||
void processhex (char *filename)
|
||||
{
|
||||
@@ -425,16 +426,18 @@ void processhex (char *filename)
|
||||
}
|
||||
fclose(fr);
|
||||
}
|
||||
|
||||
#endif
|
||||
// Raw file process
|
||||
void raw_loop ()
|
||||
void raw_loop (void *enc_ctx)
|
||||
{
|
||||
LLONG got;
|
||||
LLONG processed;
|
||||
struct cc_subtitle dec_sub;
|
||||
|
||||
current_pts = 90; // Pick a valid PTS time
|
||||
pts_set = 1;
|
||||
set_fts(); // Now set the FTS related variables
|
||||
memset(&dec_sub, 0, sizeof(dec_sub));
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
@@ -449,7 +452,12 @@ void raw_loop ()
|
||||
if (got == 0) // Shortcircuit if we got nothing to process
|
||||
break;
|
||||
|
||||
processed=process_raw();
|
||||
processed=process_raw(&dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
|
||||
int ccblocks = cb_field1;
|
||||
current_pts += cb_field1*1001/30*(MPEG_CLOCK_FREQ/1000);
|
||||
@@ -471,7 +479,7 @@ void raw_loop ()
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (three byte packets, the first being the field).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw_with_field (void)
|
||||
LLONG process_raw_with_field ( struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=0x04; // Field 1
|
||||
@@ -491,7 +499,7 @@ LLONG process_raw_with_field (void)
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data);
|
||||
do_cb(data, sub);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
@@ -500,7 +508,7 @@ LLONG process_raw_with_field (void)
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (two byte packets).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw (void)
|
||||
LLONG process_raw (struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=0x04; // Field 1
|
||||
@@ -519,22 +527,23 @@ LLONG process_raw (void)
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data);
|
||||
do_cb(data,sub);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
|
||||
void general_loop(void)
|
||||
void general_loop(void *enc_ctx)
|
||||
{
|
||||
LLONG overlap=0;
|
||||
LLONG pos = 0; /* Current position in buffer */
|
||||
struct cc_subtitle dec_sub;
|
||||
inbuf = 0; // No data yet
|
||||
|
||||
end_of_file = 0;
|
||||
current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
|
||||
memset(&dec_sub, 0,sizeof(dec_sub));
|
||||
while (!end_of_file && !processed_enough)
|
||||
{
|
||||
/* Get rid of the bytes we already processed */
|
||||
@@ -593,20 +602,19 @@ void general_loop(void)
|
||||
|
||||
if (ccx_options.hauppauge_mode)
|
||||
{
|
||||
got = process_raw_with_field();
|
||||
got = process_raw_with_field(&dec_sub);
|
||||
if (pts_set)
|
||||
set_fts(); // Try to fix timing from TS data
|
||||
}
|
||||
else if(ccx_bufferdatatype == CCX_DVB_SUBTITLE)
|
||||
{
|
||||
int out_size = 0;
|
||||
dvbsub_decode(cxx_dvb_context,NULL,&out_size,buffer + 2,inbuf);
|
||||
dvbsub_decode(cxx_dvb_context, buffer + 2, inbuf, &dec_sub);
|
||||
set_fts();
|
||||
got = inbuf;
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PES)
|
||||
{
|
||||
got = process_m2v (buffer, inbuf);
|
||||
got = process_m2v (buffer, inbuf,&dec_sub);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_TELETEXT)
|
||||
{
|
||||
@@ -654,11 +662,11 @@ void general_loop(void)
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
|
||||
got = process_raw();
|
||||
got = process_raw(&dec_sub);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_H264) // H.264 data from TS file
|
||||
{
|
||||
got = process_avc(buffer, inbuf);
|
||||
got = process_avc(buffer, inbuf,&dec_sub);
|
||||
}
|
||||
else
|
||||
fatal(EXIT_BUG_BUG, "Unknown data type!");
|
||||
@@ -695,11 +703,16 @@ void general_loop(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
position_sanity_check();
|
||||
}
|
||||
// Flush remaining HD captions
|
||||
if (has_ccdata_buffered)
|
||||
process_hdcc();
|
||||
process_hdcc(&dec_sub);
|
||||
|
||||
if (total_past!=total_inputsize && ccx_options.binary_concat && !processed_enough)
|
||||
{
|
||||
@@ -715,11 +728,13 @@ void general_loop(void)
|
||||
}
|
||||
|
||||
// Raw caption with FTS file process
|
||||
void rcwt_loop( void )
|
||||
void rcwt_loop(void *enc_ctx)
|
||||
{
|
||||
static unsigned char *parsebuf;
|
||||
static long parsebufsize = 1024;
|
||||
struct cc_subtitle dec_sub;
|
||||
|
||||
memset(&dec_sub, 0,sizeof(dec_sub));
|
||||
// As BUFSIZE is a macro this is just a reminder
|
||||
if (BUFSIZE < (3*0xFFFF + 10))
|
||||
fatal (EXIT_BUG_BUG, "BUFSIZE too small for RCWT caption block.\n");
|
||||
@@ -817,9 +832,14 @@ void rcwt_loop( void )
|
||||
|
||||
for (int j=0; j<cbcount*3; j=j+3)
|
||||
{
|
||||
do_cb(parsebuf+j);
|
||||
do_cb(parsebuf+j, &dec_sub);
|
||||
}
|
||||
}
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
} // end while(1)
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "Processed %d bytes\n", bread);
|
||||
|
||||
@@ -398,23 +398,6 @@ GF_ISOFile *gf_isom_open_file(const char *fileName, u32 OpenMode, const char *tm
|
||||
return mov;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
void gf_utc_time_since_1970(u32 *sec, u32 *msec)
|
||||
{
|
||||
#if defined (WIN32) && !defined(_WIN32_WCE)
|
||||
struct _timeb tb;
|
||||
_ftime( &tb );
|
||||
*sec = (u32) tb.time;
|
||||
*msec = tb.millitm;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
*sec = tv.tv_sec;
|
||||
*msec = tv.tv_usec/1000;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
u64 gf_isom_get_mp4time()
|
||||
{
|
||||
u32 calctime, msec;
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
#include <gpac/isomedia.h>
|
||||
#include "../ccextractor.h"
|
||||
#include "../utility.h"
|
||||
#include "../cc_encoders_common.h"
|
||||
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length); // From avc_functions.c
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub); // From avc_functions.c
|
||||
void set_fts(void); // From timing.c
|
||||
|
||||
static short bswap16(short v)
|
||||
@@ -24,14 +26,14 @@ static struct {
|
||||
unsigned type[32];
|
||||
}s_nalu_stats;
|
||||
|
||||
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
|
||||
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
|
||||
{
|
||||
int status = 0;
|
||||
u32 i;
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
|
||||
if (pts_set==0)
|
||||
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
|
||||
@@ -59,19 +61,20 @@ static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
|
||||
temp_debug=0;
|
||||
|
||||
if (nal_length>0)
|
||||
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length);
|
||||
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
i += nal_length;
|
||||
} // outer for
|
||||
assert(i == s->dataLength);
|
||||
|
||||
return status;
|
||||
}
|
||||
static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count;
|
||||
|
||||
int status;
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -79,29 +82,30 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
|
||||
status = 0;
|
||||
|
||||
for(i = 0; i < sample_count; i++){
|
||||
for(i = 0; i < sample_count; i++)
|
||||
{
|
||||
u32 sdi;
|
||||
|
||||
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
|
||||
if (s!=NULL) {
|
||||
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
if (s!=NULL)
|
||||
{
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
|
||||
process_m2v ((unsigned char *) s->data,s->dataLength);
|
||||
process_m2v ((unsigned char *) s->data,s->dataLength, sub);
|
||||
gf_isom_sample_del(&s);
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(100, cur_sec/60, cur_sec%60);
|
||||
@@ -109,13 +113,14 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count, last_sdi = 0;
|
||||
int status;
|
||||
GF_AVCConfig* c = NULL;
|
||||
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -123,19 +128,24 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
|
||||
status = 0;
|
||||
|
||||
for(i = 0; i < sample_count; i++){
|
||||
for(i = 0; i < sample_count; i++)
|
||||
{
|
||||
u32 sdi;
|
||||
|
||||
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
|
||||
|
||||
if(s != NULL){
|
||||
if(sdi != last_sdi){
|
||||
if(c != NULL){
|
||||
if(s != NULL)
|
||||
{
|
||||
if(sdi != last_sdi)
|
||||
{
|
||||
if(c != NULL)
|
||||
{
|
||||
gf_odf_avc_cfg_del(c);
|
||||
c = NULL;
|
||||
}
|
||||
|
||||
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL){
|
||||
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL)
|
||||
{
|
||||
gf_isom_sample_del(&s);
|
||||
status = -1;
|
||||
break;
|
||||
@@ -144,27 +154,29 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
last_sdi = sdi;
|
||||
}
|
||||
|
||||
status = process_avc_sample(timescale, c, s);
|
||||
status = process_avc_sample(timescale, c, s, sub);
|
||||
|
||||
gf_isom_sample_del(&s);
|
||||
|
||||
if(status != 0){
|
||||
if(status != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(100, cur_sec/60, cur_sec%60);
|
||||
|
||||
if(c != NULL){
|
||||
if(c != NULL)
|
||||
{
|
||||
gf_odf_avc_cfg_del(c);
|
||||
c = NULL;
|
||||
}
|
||||
@@ -180,19 +192,25 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
if track is AVC track
|
||||
for each sample in track
|
||||
for each NALU in sample
|
||||
send to avc.cpp for processing
|
||||
send to avc.c for processing
|
||||
close(media)
|
||||
}
|
||||
|
||||
*/
|
||||
int processmp4 (char *file)
|
||||
int processmp4 (char *file,void *enc_ctx)
|
||||
{
|
||||
GF_ISOFile* f;
|
||||
u32 i, j, track_count, avc_track_count, cc_track_count;
|
||||
|
||||
mprint("opening \'%s\': ", file);
|
||||
struct cc_subtitle dec_sub;
|
||||
|
||||
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL){
|
||||
memset(&dec_sub,0,sizeof(dec_sub));
|
||||
mprint("opening \'%s\': ", file);
|
||||
#ifdef MP4_DEBUG
|
||||
gf_log_set_tool_level(GF_LOG_CONTAINER,GF_LOG_DEBUG);
|
||||
#endif
|
||||
|
||||
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL)
|
||||
{
|
||||
mprint("failed to open\n");
|
||||
return -2;
|
||||
}
|
||||
@@ -218,7 +236,8 @@ int processmp4 (char *file)
|
||||
avc_track_count++;
|
||||
}
|
||||
|
||||
for(i = 0; i < track_count; i++){
|
||||
for(i = 0; i < track_count; i++)
|
||||
{
|
||||
const u32 type = gf_isom_get_media_type(f, i + 1);
|
||||
const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1);
|
||||
|
||||
@@ -226,10 +245,17 @@ int processmp4 (char *file)
|
||||
{
|
||||
if (cc_track_count && !ccx_options.mp4vidtrack)
|
||||
continue;
|
||||
if(process_xdvb_track(file, f, i + 1) != 0){
|
||||
if(process_xdvb_track(file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
} }
|
||||
}
|
||||
if(dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
|
||||
{
|
||||
@@ -240,15 +266,21 @@ int processmp4 (char *file)
|
||||
{
|
||||
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
|
||||
{
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL ((unsigned char *) seqcnf->data,seqcnf->size);
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL ((unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
}
|
||||
}
|
||||
|
||||
if(process_avc_track(file, f, i + 1) != 0){
|
||||
if(process_avc_track(file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
}
|
||||
if(dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -257,16 +289,20 @@ int processmp4 (char *file)
|
||||
if (avc_track_count && ccx_options.mp4vidtrack)
|
||||
continue;
|
||||
|
||||
/* unsigned num_streams = gf_isom_get_sample_description_count (f,i+1); */
|
||||
#ifdef MP4_DEBUG
|
||||
unsigned num_streams = gf_isom_get_sample_description_count (f,i+1);
|
||||
#endif
|
||||
unsigned num_samples = gf_isom_get_sample_count (f,i+1);
|
||||
|
||||
u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet
|
||||
u32 timescale = gf_isom_get_media_timescale(f,i+1);
|
||||
// u64 duration = gf_isom_get_media_duration(f,i+1);
|
||||
/* mprint ("%u streams\n",num_streams);
|
||||
#ifdef MP$DEBUG
|
||||
u64 duration = gf_isom_get_media_duration(f,i+1);
|
||||
mprint ("%u streams\n",num_streams);
|
||||
mprint ("%u sample counts\n",num_samples);
|
||||
mprint ("%u timescale\n",(unsigned) timescale);
|
||||
mprint ("%u duration\n",(unsigned) duration); */
|
||||
mprint ("%u duration\n",(unsigned) duration);
|
||||
#endif
|
||||
for (unsigned k = 0; k <num_samples; k++)
|
||||
{
|
||||
u32 StreamDescriptionIndex;
|
||||
@@ -281,39 +317,50 @@ int processmp4 (char *file)
|
||||
ProcessingStreamDescriptionIndex=StreamDescriptionIndex;
|
||||
if (sample==NULL)
|
||||
continue;
|
||||
// mprint ("Data length: %lu\n",sample->dataLength);
|
||||
/* const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale; */
|
||||
#ifdef DEBUG
|
||||
mprint ("Data length: %lu\n",sample->dataLength);
|
||||
const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale;
|
||||
#endif
|
||||
current_pts=(LLONG )(sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
|
||||
// Change by Willem
|
||||
|
||||
// Apparently the first 4 bytes are the sample length, and then comes 'cdat', and then the data itself
|
||||
/*if (sample->dataLength>8 && strncmp (sample->data+4, "cdat", 4)==0)
|
||||
int atomStart = 0;
|
||||
// process Atom by Atom
|
||||
while (atomStart < sample->dataLength)
|
||||
{
|
||||
//dump (256,( unsigned char *) sample->data+8,sample->dataLength-8,0, 1);
|
||||
process608((const unsigned char *)sample->data + 8, sample->dataLength - 8, &context_cc608_field_1);
|
||||
}*/
|
||||
|
||||
// Based on https://developer.apple.com/library/prerelease/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW87
|
||||
// An atom consists of the Atom size, Atom Type and the data.
|
||||
// First 4 bytes are length in bytes of this atom
|
||||
// byte 5-8 are the atom type. Should be either cdat or cdt2
|
||||
// byte 9-x are actual data.
|
||||
// This means a sample can contain multiple atoms!
|
||||
if (sample->dataLength > 8 && strncmp(sample->data + 4, "cdat", 4) == 0){ // The format of the closed captioning sample data is a sequence of one or more atoms, one of which must be a 'cdat' atom.
|
||||
int atomStart = 0;
|
||||
// process Atom by Atom
|
||||
while (atomStart < sample->dataLength){
|
||||
unsigned int atomLength = (unsigned char)sample->data[atomStart] << 24 | (unsigned char)sample->data[atomStart + 1] << 16 | (unsigned char)sample->data[atomStart + 2] << 8 | (unsigned char)sample->data[atomStart + 3];
|
||||
if (atomLength > 8 && (strncmp(sample->data + atomStart + 4, "cdat", 4) == 0 || strncmp(sample->data + atomStart + 4, "cdt2", 4) == 0)){
|
||||
dump(256, (unsigned char *)sample->data +atomStart+ 8, atomLength - 8, 0, 1);
|
||||
process608((const unsigned char *)sample->data + atomStart + 8, atomLength - 8, &context_cc608_field_1);
|
||||
}
|
||||
atomStart += atomLength;
|
||||
char *data = sample->data + atomStart;
|
||||
unsigned int atomLength = RB32(data);
|
||||
if(atomLength < 8 || atomLength > sample->dataLength)
|
||||
{
|
||||
mprint ("Invalid atom.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
data += 4;
|
||||
if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4))
|
||||
{
|
||||
int ret = 0;
|
||||
int len = atomLength - 8;
|
||||
data += 4;
|
||||
#ifdef MP4_DEBUG
|
||||
dump(256, (unsigned char *)data, atomLength - 8, 0, 1);
|
||||
#endif
|
||||
do
|
||||
{
|
||||
ret = process608((unsigned char*)data, len, &context_cc608_field_1, &dec_sub);
|
||||
len -= ret;
|
||||
data += ret;
|
||||
if(dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
} while (len > 0);
|
||||
}
|
||||
atomStart += atomLength;
|
||||
|
||||
}
|
||||
|
||||
// End of change
|
||||
@@ -321,7 +368,7 @@ int processmp4 (char *file)
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
@@ -336,9 +383,12 @@ int processmp4 (char *file)
|
||||
f = NULL;
|
||||
mprint ("ok\n");
|
||||
|
||||
if(avc_track_count == 0){
|
||||
if(avc_track_count == 0)
|
||||
{
|
||||
mprint("Found no AVC track(s). ", file);
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
mprint("Found %d AVC track(s). ", avc_track_count);
|
||||
}
|
||||
if (cc_track_count)
|
||||
|
||||
1399
src/myth.c
1399
src/myth.c
File diff suppressed because it is too large
Load Diff
955
src/networking.c
Normal file
955
src/networking.c
Normal file
@@ -0,0 +1,955 @@
|
||||
#include "ccextractor.h"
|
||||
#include "networking.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define DEBUG_OUT 0
|
||||
|
||||
/* Protocol constants: */
|
||||
#define INT_LEN 10
|
||||
#define OK 1
|
||||
#define PASSWORD 2
|
||||
#define BIN_MODE 3
|
||||
#define ERROR 51
|
||||
#define UNKNOWN_COMMAND 52
|
||||
#define WRONG_PASSWORD 53
|
||||
#define CONN_LIMIT 54
|
||||
|
||||
#define DFT_PORT "2048" /* Default port for server and client */
|
||||
#define WRONG_PASSWORD_DELAY 2 /* Seconds */
|
||||
#define BUFFER_SIZE 50
|
||||
|
||||
int srv_sd = -1; /* Server socket descriptor */
|
||||
|
||||
/*
|
||||
* Established connection to speciefied addres.
|
||||
* Returns socked id
|
||||
*/
|
||||
int tcp_connect(const char *addr, const char *port);
|
||||
|
||||
/*
|
||||
* Asks password from stdin, sends it to the server and waits for
|
||||
* it's response
|
||||
*/
|
||||
int ask_passwd(int sd);
|
||||
|
||||
int check_password(int fd, const char *pwd);
|
||||
|
||||
int tcp_bind(const char *port, int *family);
|
||||
|
||||
/*
|
||||
* Writes/reads data according to protocol to descriptor
|
||||
* block format: * command | lenght | data | \r\n
|
||||
* 1 byte | INT_LEN bytes | lenght bytes | 2 bytes
|
||||
*/
|
||||
ssize_t write_block(int fd, char command, const char *buf, size_t buf_len);
|
||||
ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len);
|
||||
|
||||
/* Reads n bytes from descriptor */
|
||||
ssize_t readn(int fd, void *vptr, size_t n);
|
||||
|
||||
/* Writes n bytes to descriptor */
|
||||
ssize_t writen(int fd, const void *vptr, size_t n);
|
||||
|
||||
/* Convinence functions */
|
||||
ssize_t write_byte(int fd, char status);
|
||||
ssize_t read_byte(int fd, char *status);
|
||||
|
||||
void init_sockets (void);
|
||||
|
||||
#if DEBUG_OUT
|
||||
void pr_command(char c);
|
||||
#endif
|
||||
|
||||
void connect_to_srv(const char *addr, const char *port)
|
||||
{
|
||||
if (NULL == addr)
|
||||
{
|
||||
mprint("Server addres is not set\n");
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
}
|
||||
|
||||
if (NULL == port)
|
||||
port = DFT_PORT;
|
||||
|
||||
mprint("\n\r----------------------------------------------------------------------\n");
|
||||
mprint("Connecting to %s:%s\n", addr, port);
|
||||
|
||||
if ((srv_sd = tcp_connect(addr, port)) < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
|
||||
if (ask_passwd(srv_sd) < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
|
||||
mprint("Connected to %s:%s\n", addr, port);
|
||||
}
|
||||
|
||||
void net_send_header(const unsigned char *data, size_t len)
|
||||
{
|
||||
assert(srv_sd > 0);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "Sending header (len = %u): \n", len);
|
||||
fprintf(stderr, "File created by %02X version %02X%02X\n", data[3], data[4], data[5]);
|
||||
fprintf(stderr, "File format revision: %02X%02X\n", data[6], data[7]);
|
||||
#endif
|
||||
if (write_block(srv_sd, BIN_MODE, NULL, 0) <= 0)
|
||||
{
|
||||
printf("Can't send BIN header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char ok;
|
||||
if (read_byte(srv_sd, &ok) != 1)
|
||||
return;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
if (ERROR == ok)
|
||||
{
|
||||
printf("Internal server error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t rc;
|
||||
if ((rc = writen(srv_sd, data, len)) != (int) len)
|
||||
{
|
||||
if (rc < 0)
|
||||
mprint("write() error: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void net_send_cc(const unsigned char *data, size_t len)
|
||||
{
|
||||
assert(srv_sd > 0);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[C] Sending %u bytes\n", len);
|
||||
#endif
|
||||
|
||||
ssize_t rc;
|
||||
if ((rc = writen(srv_sd, data, len)) != (int) len)
|
||||
{
|
||||
if (rc < 0)
|
||||
mprint("write() error: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
|
||||
/* Sleep(100); */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* command | lenght | data | \r\n
|
||||
* 1 byte | INT_LEN bytes | lenght bytes | 2 bytes
|
||||
*/
|
||||
ssize_t write_block(int fd, char command, const char *buf, size_t buf_len)
|
||||
{
|
||||
assert(fd > 0);
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[C] ");
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
ssize_t nwritten = 0;
|
||||
|
||||
if ((rc = write_byte(fd, command)) < 0)
|
||||
return -1;
|
||||
else if (rc != 1)
|
||||
return 0;
|
||||
nwritten++;
|
||||
|
||||
#if DEBUG_OUT
|
||||
pr_command(command);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
char len_str[INT_LEN] = {0};
|
||||
snprintf(len_str, INT_LEN, "%zu", buf_len);
|
||||
if ((rc = writen(fd, len_str, INT_LEN)) < 0)
|
||||
return -1;
|
||||
else if (rc != INT_LEN)
|
||||
return 0;
|
||||
nwritten += rc;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fwrite(len_str, sizeof(char), INT_LEN, stderr);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
if (buf_len > 0)
|
||||
{
|
||||
if ((rc = writen(fd, buf, buf_len)) < 0)
|
||||
return -1;
|
||||
else if (rc != (int) buf_len)
|
||||
return 0;
|
||||
nwritten += rc;
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
if (buf != NULL)
|
||||
{
|
||||
fwrite(buf, sizeof(char), buf_len, stderr);
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((rc = write_byte(fd, '\r')) < 0)
|
||||
return -1;
|
||||
else if (rc != 1)
|
||||
return 0;
|
||||
nwritten++;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "\\r");
|
||||
#endif
|
||||
|
||||
if ((rc = write_byte(fd, '\n')) < 0)
|
||||
return -1;
|
||||
else if (rc != 1)
|
||||
return 0;
|
||||
nwritten++;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "\\n\n");
|
||||
#endif
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
int tcp_connect(const char *host, const char *port)
|
||||
{
|
||||
assert(host != NULL);
|
||||
assert(port != NULL);
|
||||
|
||||
init_sockets();
|
||||
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
struct addrinfo *ai;
|
||||
int rc = getaddrinfo(host, port, &hints, &ai);
|
||||
if (rc != 0) {
|
||||
mprint("getaddrinfo() error: %s\n", gai_strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct addrinfo *p;
|
||||
int sockfd;
|
||||
|
||||
/* Try each address until we sucessfully connect */
|
||||
for (p = ai; p != NULL; p = p->ai_next) {
|
||||
sockfd = socket(p->ai_family, SOCK_STREAM, p->ai_protocol);
|
||||
|
||||
if (-1 == sockfd) {
|
||||
#if _WIN32
|
||||
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("socket() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
if (p->ai_next != NULL)
|
||||
mprint("trying next addres ...\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0)
|
||||
break;
|
||||
#if _WIN32
|
||||
wprintf(L"connect() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("connect() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
if (p->ai_next != NULL)
|
||||
mprint("trying next addres ...\n");
|
||||
|
||||
#if _WIN32
|
||||
closesocket(sockfd);
|
||||
#else
|
||||
close(sockfd);
|
||||
#endif
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
if (NULL == p)
|
||||
return -1;
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int ask_passwd(int sd)
|
||||
{
|
||||
assert(sd >= 0);
|
||||
|
||||
size_t len;
|
||||
char pw[BUFFER_SIZE] = { 0 };
|
||||
|
||||
char ok;
|
||||
|
||||
do {
|
||||
do {
|
||||
if (read_byte(sd, &ok) != 1)
|
||||
{
|
||||
fatal(EXIT_FAILURE, "read() error: %s", strerror(errno));
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
if (OK == ok)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (CONN_LIMIT == ok)
|
||||
{
|
||||
mprint("Too many connections to the server, try later\n");
|
||||
return -1;
|
||||
}
|
||||
else if (ERROR == ok)
|
||||
{
|
||||
mprint("Internal server error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while(ok != PASSWORD);
|
||||
|
||||
printf("Enter password: ");
|
||||
fflush(stdout);
|
||||
|
||||
char *p = pw;
|
||||
while ((unsigned)(p - pw) < sizeof(pw) && ((*p = fgetc(stdin)) != '\n'))
|
||||
p++;
|
||||
len = p - pw; /* without \n */
|
||||
|
||||
if (write_block(sd, PASSWORD, pw, len) < 0)
|
||||
return -1;
|
||||
|
||||
if (read_byte(sd, &ok) != 1)
|
||||
return -1;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
if (UNKNOWN_COMMAND == ok)
|
||||
{
|
||||
printf("Wrong password\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
else if (ERROR == ok)
|
||||
{
|
||||
mprint("Internal server error\n");
|
||||
return -1;
|
||||
}
|
||||
} while(OK != ok);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int start_tcp_srv(const char *port, const char *pwd)
|
||||
{
|
||||
if (NULL == port)
|
||||
port = DFT_PORT;
|
||||
|
||||
mprint("\n\r----------------------------------------------------------------------\n");
|
||||
|
||||
mprint("Binding to %s\n", port);
|
||||
int fam;
|
||||
int listen_sd = tcp_bind(port, &fam);
|
||||
if (listen_sd < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to start server\n");
|
||||
|
||||
if (pwd != NULL)
|
||||
mprint("Password: %s\n", pwd);
|
||||
|
||||
mprint("Waiting for connections\n");
|
||||
|
||||
int sockfd = -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
socklen_t clilen;
|
||||
if (AF_INET == fam)
|
||||
clilen = sizeof(struct sockaddr_in);
|
||||
else
|
||||
clilen = sizeof(struct sockaddr_in6);
|
||||
struct sockaddr *cliaddr = (struct sockaddr *) malloc(clilen);
|
||||
if (NULL == cliaddr)
|
||||
fatal(EXIT_FAILURE, "malloc() error: %s", strerror(errno));
|
||||
|
||||
if ((sockfd = accept(listen_sd, cliaddr, &clilen)) < 0)
|
||||
{
|
||||
if (EINTR == errno) /* TODO not necessary */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"accept() eror: %ld\n", WSAGetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
fatal(EXIT_FAILURE, "accept() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char host[NI_MAXHOST];
|
||||
char serv[NI_MAXSERV];
|
||||
int rc;
|
||||
if ((rc = getnameinfo(cliaddr, clilen,
|
||||
host, sizeof(host), serv, sizeof(serv), 0)) != 0)
|
||||
{
|
||||
mprint("getnameinfo() error: %s\n", gai_strerror(rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
mprint("%s:%s Connceted\n", host, serv);
|
||||
}
|
||||
|
||||
free(cliaddr);
|
||||
|
||||
if (pwd != NULL && (rc = check_password(sockfd, pwd)) <= 0)
|
||||
goto close_conn;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] OK\n");
|
||||
#endif
|
||||
if (write_byte(sockfd, OK) != 1)
|
||||
goto close_conn;
|
||||
|
||||
char c;
|
||||
size_t len = BUFFER_SIZE;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
||||
do {
|
||||
if (read_block(sockfd, &c, buf, &len) <= 0)
|
||||
goto close_conn;
|
||||
} while (c != BIN_MODE);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] OK\n");
|
||||
#endif
|
||||
if (write_byte(sockfd, OK) != 1)
|
||||
goto close_conn;
|
||||
|
||||
break;
|
||||
|
||||
close_conn:
|
||||
mprint("Connection closed\n");
|
||||
#if _WIN32
|
||||
closesocket(sockfd);
|
||||
#else
|
||||
close(sockfd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
closesocket(listen_sd);
|
||||
#else
|
||||
close(listen_sd);
|
||||
#endif
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int check_password(int fd, const char *pwd)
|
||||
{
|
||||
assert(pwd != NULL);
|
||||
|
||||
char c;
|
||||
int rc;
|
||||
size_t len;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
||||
while(1)
|
||||
{
|
||||
len = BUFFER_SIZE;
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] PASSWORD\n");
|
||||
#endif
|
||||
if ((rc = write_byte(fd, PASSWORD)) <= 0)
|
||||
return rc;
|
||||
|
||||
if ((rc = read_block(fd, &c, buf, &len)) <= 0)
|
||||
return rc;
|
||||
|
||||
if (c != PASSWORD)
|
||||
return -1;
|
||||
|
||||
if (strlen(pwd) != len || strncmp(pwd, buf, len) != 0)
|
||||
{
|
||||
sleep(WRONG_PASSWORD_DELAY);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] WRONG_PASSWORD\n");
|
||||
#endif
|
||||
if ((rc = write_byte(fd, WRONG_PASSWORD)) <= 0)
|
||||
return rc;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int tcp_bind(const char *port, int *family)
|
||||
{
|
||||
init_sockets();
|
||||
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
struct addrinfo *ai;
|
||||
int rc = getaddrinfo(NULL, port, &hints, &ai);
|
||||
if (rc != 0)
|
||||
{
|
||||
mprint("getaddrinfo() error: %s\n", gai_strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct addrinfo *p;
|
||||
int sockfd = -1;
|
||||
/* Try each address until we sucessfully bind */
|
||||
for (p = ai; p != NULL; p = p->ai_next)
|
||||
{
|
||||
sockfd = socket(p->ai_family, SOCK_STREAM, p->ai_protocol);
|
||||
|
||||
if (-1 == sockfd)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("socket() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
if (p->ai_next != NULL)
|
||||
mprint("trying next addres ...\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AF_INET6 == p->ai_family)
|
||||
{
|
||||
int no = 0;
|
||||
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"setsockopt() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("setsockopt() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
if (p->ai_next != NULL)
|
||||
mprint("trying next addres ...\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(sockfd, p->ai_addr, p->ai_addrlen) < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"bind() eror: %ld\n", WSAGetLastError());
|
||||
closesocket(sockfd);
|
||||
#else
|
||||
mprint("bind() error: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
#endif
|
||||
if (p->ai_next != NULL)
|
||||
mprint("trying next addres ...\n");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
*family = p->ai_family;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
if (NULL == p)
|
||||
return -1;
|
||||
|
||||
if (listen(sockfd, SOMAXCONN) != 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"listen() eror: %ld\n", WSAGetLastError());
|
||||
closesocket(sockfd);
|
||||
#else
|
||||
perror("listen() error");
|
||||
close(sockfd);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
|
||||
{
|
||||
assert(command != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(buf_len != NULL);
|
||||
assert(*buf_len > 0);
|
||||
|
||||
ssize_t rc;
|
||||
ssize_t nread = 0;
|
||||
|
||||
if ((rc = readn(fd, command, 1)) < 0)
|
||||
return -1;
|
||||
else if ((size_t) rc != 1)
|
||||
return 0;
|
||||
nread += rc;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[C] ");
|
||||
pr_command(*command);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
char len_str[INT_LEN] = {0};
|
||||
if ((rc = readn(fd, len_str, INT_LEN)) < 0)
|
||||
return -1;
|
||||
else if (rc != INT_LEN)
|
||||
return 0;
|
||||
nread += rc;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fwrite(len_str, sizeof(char), INT_LEN, stderr);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
size_t len = atoi(len_str);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
size_t ign_bytes = 0;
|
||||
if (len > *buf_len)
|
||||
{
|
||||
ign_bytes = len - *buf_len;
|
||||
mprint("read_block() warning: Buffer overflow, ignoring %d bytes\n",
|
||||
ign_bytes);
|
||||
len = *buf_len;
|
||||
}
|
||||
|
||||
if ((rc = readn(fd, buf, len)) < 0)
|
||||
return -1;
|
||||
else if ((size_t) rc != len)
|
||||
return 0;
|
||||
nread += rc;
|
||||
*buf_len = len;
|
||||
|
||||
if ((rc = readn(fd, 0, ign_bytes)) < 0)
|
||||
return -1;
|
||||
else if ((size_t) rc != ign_bytes)
|
||||
return 0;
|
||||
nread += rc;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fwrite(buf, sizeof(char), len, stderr);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
}
|
||||
|
||||
char end[2] = {0};
|
||||
if ((rc = readn(fd, end, sizeof(end))) < 0)
|
||||
return -1;
|
||||
else if ((size_t) rc != sizeof(end))
|
||||
return 0;
|
||||
nread += rc;
|
||||
|
||||
if (end[0] != '\r' || end[1] != '\n')
|
||||
{
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "read_block(): No end marker present\n");
|
||||
fprintf(stderr, "Closing connection\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "\\r\\n\n");
|
||||
#endif
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG_OUT
|
||||
void pr_command(char c)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case OK:
|
||||
fprintf(stderr, "OK");
|
||||
break;
|
||||
case BIN_MODE:
|
||||
fprintf(stderr, "BIN_MODE");
|
||||
break;
|
||||
case WRONG_PASSWORD:
|
||||
fprintf(stderr, "WRONG_PASSWORD");
|
||||
break;
|
||||
case UNKNOWN_COMMAND:
|
||||
fprintf(stderr, "UNKNOWN_COMMAND");
|
||||
break;
|
||||
case ERROR:
|
||||
fprintf(stderr, "ERROR");
|
||||
break;
|
||||
case CONN_LIMIT:
|
||||
fprintf(stderr, "CONN_LIMIT");
|
||||
break;
|
||||
case PASSWORD:
|
||||
fprintf(stderr, "PASSWORD");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "UNKNOWN (%d)", (int) c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ssize_t readn(int fd, void *vptr, size_t n)
|
||||
{
|
||||
assert(fd > 0);
|
||||
size_t nleft;
|
||||
ssize_t nread;
|
||||
char *ptr;
|
||||
|
||||
ptr = vptr;
|
||||
nleft = n;
|
||||
while (nleft > 0)
|
||||
{
|
||||
if (NULL == vptr) {
|
||||
char c;
|
||||
nread = recv(fd, &c, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
nread = recv(fd, (void*)ptr, nleft, 0);
|
||||
}
|
||||
|
||||
if (nread < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"recv() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("recv() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == nread)
|
||||
{
|
||||
break; /* EOF */
|
||||
}
|
||||
|
||||
nleft -= nread;
|
||||
ptr += nread;
|
||||
}
|
||||
|
||||
return n - nleft;
|
||||
}
|
||||
|
||||
ssize_t writen(int fd, const void *vptr, size_t n)
|
||||
{
|
||||
assert(fd > 0);
|
||||
assert((n > 0 && vptr != NULL) || (n == 0 && vptr == NULL));
|
||||
|
||||
size_t nleft;
|
||||
ssize_t nwritten;
|
||||
const char *ptr;
|
||||
|
||||
ptr = vptr;
|
||||
nleft = n;
|
||||
while (nleft > 0)
|
||||
{
|
||||
if ((nwritten = send(fd, ptr, nleft, 0)) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
nwritten = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"send() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("send() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == nwritten)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nleft -= nwritten;
|
||||
ptr += nwritten;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t write_byte(int fd, char ch)
|
||||
{
|
||||
assert(fd > 0);
|
||||
|
||||
return writen(fd, &ch, 1);
|
||||
}
|
||||
|
||||
ssize_t read_byte(int fd, char *ch)
|
||||
{
|
||||
assert(fd > 0);
|
||||
assert(ch != NULL);
|
||||
|
||||
return readn(fd, ch, 1);
|
||||
}
|
||||
|
||||
int start_upd_srv(const char *addr_str, unsigned port)
|
||||
{
|
||||
init_sockets();
|
||||
|
||||
in_addr_t addr;
|
||||
if (addr_str != NULL)
|
||||
{
|
||||
struct hostent *host = gethostbyname(addr_str);
|
||||
if (NULL == host)
|
||||
{
|
||||
fatal(EXIT_MALFORMED_PARAMETER, "Cannot look up udp network address: %s\n",
|
||||
addr_str);
|
||||
}
|
||||
else if (host->h_addrtype != AF_INET)
|
||||
{
|
||||
fatal(EXIT_MALFORMED_PARAMETER, "No support for non-IPv4 network addresses: %s\n",
|
||||
addr_str);
|
||||
}
|
||||
|
||||
addr = ntohl(((struct in_addr *)host->h_addr_list[0])->s_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (-1 == sockfd) {
|
||||
#if _WIN32
|
||||
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
mprint("socket() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IN_MULTICAST(addr))
|
||||
{
|
||||
int on = 1;
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"setsockopt() error: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("setsockopt() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in servaddr;
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_port = htons(port);
|
||||
if (IN_MULTICAST(addr))
|
||||
servaddr.sin_addr.s_addr = htonl(addr);
|
||||
else
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"bind() eror: %ld\n", WSAGetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
fatal(EXIT_BUG_BUG, "bind() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IN_MULTICAST(addr)) {
|
||||
struct ip_mreq group;
|
||||
group.imr_multiaddr.s_addr = htonl(addr);
|
||||
group.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"setsockopt() error: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("setsockopt() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
fatal(EXIT_BUG_BUG, "Cannot join multicast group.");
|
||||
}
|
||||
}
|
||||
|
||||
mprint("\n\r----------------------------------------------------------------------\n");
|
||||
if (addr == INADDR_ANY)
|
||||
{
|
||||
mprint("\rReading from UDP socket %u\n", port);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl(addr);
|
||||
mprint("\rReading from UDP socket %s:%u\n", inet_ntoa(in), port);
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
void init_sockets (void)
|
||||
{
|
||||
static int socket_inited = 0;
|
||||
if (!socket_inited)
|
||||
{
|
||||
// Initialize Winsock
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData = {0};
|
||||
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0)
|
||||
{
|
||||
wprintf(L"WSAStartup failed: %d\n", iResult);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
socket_inited = 1;
|
||||
}
|
||||
}
|
||||
15
src/networking.h
Normal file
15
src/networking.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef NETWORKING_H
|
||||
#define NETWORKING_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
void connect_to_srv(const char *addr, const char *port);
|
||||
|
||||
void net_send_header(const unsigned char *data, size_t len);
|
||||
void net_send_cc(const unsigned char *data, size_t len);
|
||||
|
||||
int start_tcp_srv(const char *port, const char *pwd);
|
||||
|
||||
int start_upd_srv(const char *addr, unsigned port);
|
||||
|
||||
#endif /* end of include guard: NETWORKING_H */
|
||||
@@ -44,7 +44,7 @@ char* ocr_bitmap(png_color *palette,png_byte *alpha, unsigned char* indata,int w
|
||||
}
|
||||
|
||||
//text_out = TessBaseAPIProcessPages(api, "/home/anshul/test_videos/dvbsubtest.d/sub0018.png", 0, 0);
|
||||
text_out = TessBaseAPIProcessPage(api, pix, 0, NULL, NULL, 1000);
|
||||
text_out = TessBaseAPIProcessPage(api, pix, 0, NULL, NULL, 0);
|
||||
if(!text_out)
|
||||
printf("\nsomething messy\n");
|
||||
return text_out;
|
||||
|
||||
26
src/output.c
26
src/output.c
@@ -18,7 +18,7 @@ void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb)
|
||||
write (wb->fh,data,length);
|
||||
}
|
||||
|
||||
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context)
|
||||
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context, struct cc_subtitle *sub)
|
||||
{
|
||||
// Don't do anything for empty data
|
||||
if (data==NULL)
|
||||
@@ -26,7 +26,7 @@ void writedata(const unsigned char *data, int length, struct s_context_cc608 *co
|
||||
|
||||
if (ccx_options.write_format==CCX_OF_RAW || ccx_options.write_format==CCX_OF_DVDRAW)
|
||||
{
|
||||
if (context->out)
|
||||
if (context && context->out)
|
||||
writeraw (data,length,context->out);
|
||||
}
|
||||
else if (ccx_options.write_format==CCX_OF_SMPTETT ||
|
||||
@@ -35,7 +35,7 @@ void writedata(const unsigned char *data, int length, struct s_context_cc608 *co
|
||||
ccx_options.write_format==CCX_OF_TRANSCRIPT ||
|
||||
ccx_options.write_format==CCX_OF_SPUPNG ||
|
||||
ccx_options.write_format==CCX_OF_NULL)
|
||||
process608 (data,length,context);
|
||||
process608 (data,length,context, sub);
|
||||
else
|
||||
fatal(EXIT_BUG_BUG, "Should not be reached!");
|
||||
}
|
||||
@@ -102,7 +102,7 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
}
|
||||
|
||||
void printdata (const unsigned char *data1, int length1,
|
||||
const unsigned char *data2, int length2)
|
||||
const unsigned char *data2, int length2, struct cc_subtitle *sub)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_DVDRAW)
|
||||
writeDVDraw (data1,length1,data2,length2,&wbout1);
|
||||
@@ -110,14 +110,14 @@ void printdata (const unsigned char *data1, int length1,
|
||||
{
|
||||
if (length1 && ccx_options.extract!=2)
|
||||
{
|
||||
writedata(data1, length1, &context_cc608_field_1);
|
||||
writedata(data1, length1, &context_cc608_field_1, sub);
|
||||
}
|
||||
if (length2)
|
||||
{
|
||||
if (ccx_options.extract!=1)
|
||||
writedata(data2, length2, &context_cc608_field_2);
|
||||
writedata(data2, length2, &context_cc608_field_2, sub);
|
||||
else // User doesn't want field 2 data, but we want XDS.
|
||||
writedata (data2,length2,NULL);
|
||||
writedata (data2,length2,NULL, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +180,12 @@ void writercwtdata (const unsigned char *data)
|
||||
{
|
||||
writeraw(cbheader,10,&wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, &wbout1);
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
net_send_cc(cbheader, 10);
|
||||
net_send_cc(cbbuffer, 3*cbcount);
|
||||
}
|
||||
}
|
||||
cbcount = 0;
|
||||
cbempty = 0;
|
||||
@@ -225,6 +231,12 @@ void writercwtdata (const unsigned char *data)
|
||||
writeraw(cbheader,10,&wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, &wbout1);
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
net_send_cc(cbheader, 10);
|
||||
net_send_cc(cbbuffer, 3*cbcount);
|
||||
}
|
||||
|
||||
cbcount = 0;
|
||||
cbempty = 0;
|
||||
|
||||
|
||||
1917
src/params.c
1917
src/params.c
File diff suppressed because it is too large
Load Diff
@@ -14,15 +14,16 @@ void params_dump(void)
|
||||
mprint ("stdin");
|
||||
break;
|
||||
case CCX_DS_NETWORK:
|
||||
if (ccx_options.udpaddr == INADDR_ANY)
|
||||
if (ccx_options.udpaddr == NULL)
|
||||
mprint ("Network, UDP/%u",ccx_options.udpport);
|
||||
else
|
||||
{
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl(ccx_options.udpaddr);
|
||||
mprint ("Network, %s:%d",inet_ntoa(in), ccx_options.udpport);
|
||||
mprint ("Network, %s:%d",ccx_options.udpaddr, ccx_options.udpport);
|
||||
}
|
||||
break;
|
||||
case CCX_DS_TCP:
|
||||
mprint("Network, TCP/%s", ccx_options.tcpport);
|
||||
break;
|
||||
}
|
||||
mprint ("\n");
|
||||
mprint ("[Extract: %d] ", ccx_options.extract);
|
||||
@@ -56,9 +57,11 @@ void params_dump(void)
|
||||
case CCX_SM_MP4:
|
||||
mprint ("MP4");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("Hex");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fatal (EXIT_BUG_BUG, "BUG: Unknown stream mode.\n");
|
||||
break;
|
||||
@@ -171,7 +174,7 @@ void params_dump(void)
|
||||
mprint ("Yes, timeout: %d seconds",ccx_options.live_stream);
|
||||
}
|
||||
mprint ("] [Clock frequency: %d]\n",MPEG_CLOCK_FREQ);
|
||||
mprint ("Teletext page: ");
|
||||
mprint ("Teletext page: [");
|
||||
if (tlt_config.page)
|
||||
mprint ("%d]\n",tlt_config.page);
|
||||
else
|
||||
@@ -214,6 +217,7 @@ void print_file_report(void)
|
||||
case CCX_DS_STDIN:
|
||||
printf("stdin\n");
|
||||
break;
|
||||
case CCX_DS_TCP:
|
||||
case CCX_DS_NETWORK:
|
||||
printf("network\n");
|
||||
break;
|
||||
@@ -283,9 +287,11 @@ void print_file_report(void)
|
||||
case CCX_SM_RCWT:
|
||||
printf("BIN\n");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
printf("Hex\n");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <io.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
@@ -13,11 +14,14 @@
|
||||
#include "inttypes.h"
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
typedef int socklen_t;
|
||||
typedef int ssize_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)
|
||||
#define snprintf(buf, len, fmt, ...) _snprintf(buf, len, fmt, __VA_ARGS__)
|
||||
#define sleep(sec) Sleep((sec) * 1000)
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ void init_hdcc (void)
|
||||
}
|
||||
|
||||
// Buffer caption blocks for later sorting/flushing.
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now)
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now,struct cc_subtitle *sub)
|
||||
{
|
||||
// Uninitialized?
|
||||
if (anchor_seq_number < 0)
|
||||
@@ -51,7 +51,7 @@ void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG
|
||||
// Maybe missing an anchor frame - try to recover
|
||||
dbg_print(CCX_DMT_VERBOSE, "Too many B-frames, or missing anchor frame. Trying to recover ..\n");
|
||||
|
||||
process_hdcc();
|
||||
process_hdcc(sub);
|
||||
anchor_hdcc( sequence_number);
|
||||
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ void anchor_hdcc(int seq)
|
||||
}
|
||||
|
||||
// Sort/flash caption block buffer
|
||||
void process_hdcc (void)
|
||||
void process_hdcc (struct cc_subtitle *sub)
|
||||
{
|
||||
// Remember the current value
|
||||
LLONG store_fts_now = fts_now;
|
||||
@@ -167,7 +167,7 @@ void process_hdcc (void)
|
||||
cc_data_pkts[seq][j+1]=0x7F;
|
||||
}
|
||||
}
|
||||
do_cb(cc_data_pkts[seq]+j);
|
||||
do_cb(cc_data_pkts[seq]+j, sub);
|
||||
|
||||
} // for loop over packets
|
||||
}
|
||||
@@ -180,7 +180,7 @@ void process_hdcc (void)
|
||||
}
|
||||
|
||||
|
||||
int do_cb (unsigned char *cc_block)
|
||||
int do_cb (unsigned char *cc_block, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char cc_valid = (*cc_block & 4) >>2;
|
||||
unsigned char cc_type = *cc_block & 3;
|
||||
@@ -237,7 +237,7 @@ int do_cb (unsigned char *cc_block)
|
||||
if (timeok)
|
||||
{
|
||||
if(ccx_options.write_format!=CCX_OF_RCWT)
|
||||
printdata (cc_block+1,2,0,0);
|
||||
printdata (cc_block+1,2,0,0, sub);
|
||||
else
|
||||
writercwtdata(cc_block);
|
||||
}
|
||||
@@ -261,7 +261,7 @@ int do_cb (unsigned char *cc_block)
|
||||
if (timeok)
|
||||
{
|
||||
if(ccx_options.write_format!=CCX_OF_RCWT)
|
||||
printdata (0,0,cc_block+1,2);
|
||||
printdata (0,0,cc_block+1,2, sub);
|
||||
else
|
||||
writercwtdata(cc_block);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
#include "platform.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include <assert.h>
|
||||
#include "cc_encoders_common.h"
|
||||
#include "utility.h"
|
||||
#ifdef ENABLE_OCR
|
||||
#include "ocr.h"
|
||||
#endif
|
||||
|
||||
#define CCPL (ccfont2_width / CCW * ccfont2_height / CCH)
|
||||
|
||||
@@ -70,6 +75,7 @@ struct spupng_t *spunpg_init(struct ccx_s_write *out)
|
||||
if (NULL == sp->pngfile)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
|
||||
sp->fileIndex = 0;
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex);
|
||||
|
||||
// For NTSC closed captions and 720x480 DVD subtitle resolution:
|
||||
// Each character is 16x26.
|
||||
@@ -311,20 +317,16 @@ void write_spucomment(struct spupng_t *sp,const char *str)
|
||||
fprintf(sp->fpxml, "-->\n");
|
||||
}
|
||||
|
||||
int get_spupng_subtype(void)
|
||||
{
|
||||
return (1 << CCX_OF_TYPE_TEXT)|(1<<CCX_OF_TYPE_IMAGE);
|
||||
}
|
||||
char* get_spupng_filename(void *ctx)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)ctx;
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex);
|
||||
return sp->pngfile;
|
||||
}
|
||||
void inc_spupng_fileindex(void *ctx)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)ctx;
|
||||
sp->fileIndex++;
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex);
|
||||
}
|
||||
void set_spupng_offset(void *ctx,int x,int y)
|
||||
{
|
||||
@@ -332,4 +334,372 @@ void set_spupng_offset(void *ctx,int x,int y)
|
||||
sp->xOffset = x;
|
||||
sp->yOffset = y;
|
||||
}
|
||||
static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
|
||||
png_color *palette, png_byte *alpha, int nb_color)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
png_bytep* row_pointer = NULL;
|
||||
int i, j, ret = 0;
|
||||
int k = 0;
|
||||
if(!h)
|
||||
h = 1;
|
||||
if(!w)
|
||||
w = 1;
|
||||
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
{
|
||||
mprint("DVB:unable to open %s in write mode \n", filename);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,NULL);
|
||||
if (!png_ptr)
|
||||
{
|
||||
mprint("DVB:unable to create png write struct\n");
|
||||
goto end;
|
||||
}
|
||||
if (!(info_ptr = png_create_info_struct(png_ptr)))
|
||||
{
|
||||
mprint("DVB:unable to create png info struct\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
row_pointer = (png_bytep*) malloc(sizeof(png_bytep) * h);
|
||||
if (!row_pointer)
|
||||
{
|
||||
mprint("DVB: unable to allocate row_pointer\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
memset(row_pointer, 0, sizeof(png_bytep) * h);
|
||||
png_init_io(png_ptr, f);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h,
|
||||
/* bit_depth */8,
|
||||
PNG_COLOR_TYPE_PALETTE,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, nb_color);
|
||||
png_set_tRNS(png_ptr, info_ptr, alpha, nb_color, NULL);
|
||||
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
row_pointer[i] = (png_byte*) malloc(
|
||||
png_get_rowbytes(png_ptr, info_ptr));
|
||||
if (row_pointer[i] == NULL)
|
||||
break;
|
||||
}
|
||||
if (i != h)
|
||||
{
|
||||
mprint("DVB: unable to allocate row_pointer internals\n");
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++)
|
||||
{
|
||||
if(bitmap)
|
||||
k = bitmap[i * w + (j)];
|
||||
else
|
||||
k = 0;
|
||||
row_pointer[i][j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, row_pointer);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
end: if (row_pointer)
|
||||
{
|
||||
for (i = 0; i < h; i++)
|
||||
freep(&row_pointer[i]);
|
||||
freep(&row_pointer);
|
||||
}
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
if (f)
|
||||
fclose(f);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
uint8_t depth)
|
||||
{
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
palette[i].red = ((clut[i] >> 16) & 0xff);
|
||||
palette[i].green = ((clut[i] >> 8) & 0xff);
|
||||
palette[i].blue = (clut[i] & 0xff);
|
||||
alpha[i] = ((clut[i] >> 24) & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct transIntensity
|
||||
{
|
||||
uint8_t *t;
|
||||
png_color *palette;
|
||||
};
|
||||
int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
struct transIntensity *ti = arg;
|
||||
unsigned char* tmp = (unsigned char*)p1;
|
||||
unsigned char* act = (unsigned char*)p2;
|
||||
unsigned char tmp_i;
|
||||
unsigned char act_i;
|
||||
/** TODO verify that RGB follow ITU-R BT.709
|
||||
* Below fomula is valid only for 709 standurd
|
||||
* Y = 0.2126 R + 0.7152 G + 0.0722 B
|
||||
*/
|
||||
tmp_i = (0.2126 * ti->palette[*tmp].red) + (0.7152 * ti->palette[*tmp].green) + (0.0722 * ti->palette[*tmp].blue);
|
||||
act_i = (0.2126 * ti->palette[*act].red) + (0.7152 * ti->palette[*act].green) + (0.0722 * ti->palette[*act].blue);;
|
||||
|
||||
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && tmp_i < act_i))
|
||||
return -1;
|
||||
else if (ti->t[*tmp] == ti->t[*act] && tmp_i == act_i)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* @param alpha out
|
||||
* @param intensity in
|
||||
* @param palette out should be already initialized
|
||||
* @param bitmap in
|
||||
* @param size in size of bitmap
|
||||
* @param max_color in
|
||||
* @param nb_color in
|
||||
*/
|
||||
int quantize_map(png_byte *alpha, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color)
|
||||
{
|
||||
/*
|
||||
* occurrence of color in image
|
||||
*/
|
||||
uint32_t *histogram = NULL;
|
||||
/* intensity ordered table */
|
||||
uint8_t *iot = NULL;
|
||||
/* array of color with most occurrence according to histogram
|
||||
* save index of intensity order table
|
||||
*/
|
||||
uint32_t *mcit = NULL;
|
||||
struct transIntensity ti = { alpha,palette};
|
||||
|
||||
int ret = 0;
|
||||
|
||||
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!histogram)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
|
||||
if (!iot)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!mcit)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(histogram, 0, nb_color * sizeof(uint32_t));
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
iot[i] = i;
|
||||
}
|
||||
memset(mcit, 0, nb_color * sizeof(uint32_t));
|
||||
|
||||
/* calculate histogram of image */
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
histogram[bitmap[i]]++;
|
||||
}
|
||||
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
|
||||
|
||||
/* using selection sort since need to find only max_color */
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
uint32_t max_val = 0;
|
||||
uint32_t max_ind = 0;
|
||||
int j;
|
||||
for (j = 0; j < nb_color; j++)
|
||||
{
|
||||
if (max_val < histogram[iot[j]])
|
||||
{
|
||||
max_val = histogram[iot[j]];
|
||||
max_ind = j;
|
||||
}
|
||||
}
|
||||
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
|
||||
{
|
||||
mcit[j] = mcit[j - 1];
|
||||
}
|
||||
mcit[j] = max_ind;
|
||||
histogram[iot[max_ind]] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0, mxi = 0; i < nb_color; i++)
|
||||
{
|
||||
int step, inc;
|
||||
if (i == mcit[mxi])
|
||||
{
|
||||
mxi = (mxi < max_color) ? mxi + 1 : mxi;
|
||||
continue;
|
||||
}
|
||||
inc = (mxi) ? -1 : 0;
|
||||
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 3);
|
||||
if (i <= step)
|
||||
{
|
||||
int index = iot[mcit[mxi + inc]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = iot[mcit[mxi]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
|
||||
}
|
||||
end: freep(&histogram);
|
||||
freep(&mcit);
|
||||
freep(&iot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
write_sputag(sp, context->prev_start, sub->start_time);
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
write_sputag(sp, sub->start_time, sub->end_time);
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
inc_spupng_fileindex(sp);
|
||||
filename = get_spupng_filename(sp);
|
||||
set_spupng_offset(sp,y_pos,x_pos);
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
write_spucomment(sp,str);
|
||||
}
|
||||
#endif
|
||||
save_spupng(filename,pbuf,width, height, palette, alpha,rect[0].nb_colors);
|
||||
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -32,4 +32,8 @@ void write_spucomment(struct spupng_t *sp,const char *str);
|
||||
char* get_spupng_filename(void *ctx);
|
||||
void inc_spupng_fileindex(void *ctx);
|
||||
void set_spupng_offset(void *ctx,int x,int y);
|
||||
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
uint8_t depth);
|
||||
int quantize_map(png_byte *alpha, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color);
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,7 @@ void detect_stream_type (void)
|
||||
startbytes[3]==0x20)
|
||||
stream_mode=CCX_SM_WTV;
|
||||
}
|
||||
#ifdef WTV_DEBUG
|
||||
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=6)
|
||||
{
|
||||
// Check for hexadecimal dump generated by wtvccdump
|
||||
@@ -42,6 +43,7 @@ void detect_stream_type (void)
|
||||
startbytes[5]=='D')
|
||||
stream_mode= CCX_SM_HEX_DUMP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=11)
|
||||
{
|
||||
|
||||
@@ -1127,6 +1127,7 @@ void telxcc_close(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TELXCC
|
||||
int main_telxcc (int argc, char *argv[]) {
|
||||
FILE *infile;
|
||||
|
||||
@@ -1308,4 +1309,4 @@ int main_telxcc (int argc, char *argv[]) {
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -37,7 +37,9 @@ void set_fts(void)
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
case CCX_SM_RCWT:
|
||||
case CCX_SM_MP4:
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
#endif
|
||||
dif = 0;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -267,11 +267,13 @@ int parse_PMT (unsigned char *buf,int len, int pos)
|
||||
{
|
||||
enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++);
|
||||
desc_len = (*es_info++);
|
||||
#ifndef ENABLE_OCR
|
||||
if(ccx_options.write_format != CCX_OF_SPUPNG )
|
||||
{
|
||||
mprint ("DVB subtitle only support spupng type as output\n");
|
||||
mprint ("Please Compile with ENABLE_OCR flag \n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if(CCX_MPEG_DSC_DVB_SUBTITLE == descriptor_tag)
|
||||
{
|
||||
struct dvb_config cnf;
|
||||
@@ -279,10 +281,9 @@ int parse_PMT (unsigned char *buf,int len, int pos)
|
||||
ret = parse_dvb_description(&cnf,es_info,desc_len);
|
||||
if(ret < 0)
|
||||
break;
|
||||
cxx_dvb_context = dvbsub_init_decoder(cnf.composition_id[0],cnf.ancillary_id[0]);
|
||||
cxx_dvb_context = dvbsub_init_decoder(&cnf);
|
||||
if (cxx_dvb_context == NULL)
|
||||
break;
|
||||
dvbsub_set_write(cxx_dvb_context,&wbout1);
|
||||
ccx_options.ts_cappid = newcappid = elementary_PID;
|
||||
cap_stream_type = newcap_stream_type = ccx_stream_type;
|
||||
max_dif = 10;
|
||||
|
||||
@@ -133,6 +133,8 @@ void fdprintf (int fd, const char *fmt, ...)
|
||||
char *p, *np;
|
||||
va_list ap;
|
||||
|
||||
if( fd < 0)
|
||||
return;
|
||||
if ((p = (char *) malloc (size)) == NULL)
|
||||
return;
|
||||
|
||||
@@ -255,7 +257,7 @@ void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, uns
|
||||
mprint (" | ");
|
||||
for (int j=0; j<16; j++)
|
||||
{
|
||||
if (x+j<=l && start[x+j]>=' ')
|
||||
if (x+j<l && start[x+j]>=' ')
|
||||
mprint ("%c",start[x+j] & (clear_high_bit?0x7F:0xFF)); // 0x7F < remove high bit, convenient for visual CC inspection
|
||||
else
|
||||
mprint (" ");
|
||||
@@ -336,3 +338,12 @@ int string_cmp(const void *p1,const void *p2)
|
||||
{
|
||||
return string_cmp2(p1, p2, NULL);
|
||||
}
|
||||
|
||||
void freep(void *arg)
|
||||
{
|
||||
void **ptr = (void **) arg;
|
||||
if (*ptr)
|
||||
free(*ptr);
|
||||
*ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
void shell_sort(void *base, int nb,size_t size,int (*compar)(const void*p1,const void *p2,void*arg),void *arg);
|
||||
int string_cmp(const void *p1,const void *p2);
|
||||
int string_cmp2(const void *p1,const void *p2,void *arg);
|
||||
void freep(void *arg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define WTV_STREAM2 "\xA2\xC3\xD2\xC2\x7E\x9A\xDA\x11\x8B\xF7\x00\x07\xE9\x5E\xAD\x8D"
|
||||
#define WTV_DATA "\x95\xC3\xD2\xC2\x7E\x9A\xDA\x11\x8B\xF7\x00\x07\xE9\x5E\xAD\x8D"
|
||||
#define WTV_STREAM_VIDEO "\x76\x69\x64\x73\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71"
|
||||
#define WTV_STREAM_AUDIO "\x61\x75\x64\x73\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71"
|
||||
#define WTV_STREAM_MSTVCAPTION "\x89\x8A\x8B\xB8\x49\xB0\x80\x4C\xAD\xCF\x58\x98\x98\x5E\x22\xC1"
|
||||
#define WTV_EOF "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
#define WTV_TIMING "\x5B\x05\xE6\x1B\x97\xA9\x49\x43\x88\x17\x1A\x65\x5A\x29\x8A\x97"
|
||||
@@ -18,6 +19,9 @@
|
||||
//Maximum size we will try and malloc for chunked_buffer. 100MB
|
||||
#define WTV_MAX_ALLOC 1024*1024*100
|
||||
|
||||
#define WTV_CC_TIMESTAMP_MAGIC 1668330
|
||||
#define WTV_CC_TIMESTAMP_MAGIC_THRESH 2 //Only switch to alt stream after THRESH magic numbers
|
||||
|
||||
struct wtv_chunked_buffer
|
||||
{
|
||||
uint64_t skip_chunks[256];
|
||||
|
||||
@@ -297,6 +297,8 @@ int read_header(struct wtv_chunked_buffer *cb) {
|
||||
|
||||
LLONG get_data(struct wtv_chunked_buffer *cb) {
|
||||
static int video_streams[32];
|
||||
static int alt_stream; //Stream to use for timestamps if the cc stream has broken timestamps
|
||||
static int use_alt_stream = 0;
|
||||
static int num_streams=0;
|
||||
while(1)
|
||||
{
|
||||
@@ -368,9 +370,12 @@ LLONG get_data(struct wtv_chunked_buffer *cb) {
|
||||
video_streams[num_streams]=stream_id; // We keep a list of stream ids
|
||||
num_streams++; // Even though there should only be 1
|
||||
}
|
||||
if (memcmp(stream_type, WTV_STREAM_AUDIO, 16))
|
||||
alt_stream = stream_id;
|
||||
len-=28;
|
||||
}
|
||||
if( !memcmp(guid, WTV_TIMING, 16 ) && check_stream_id(stream_id, video_streams, num_streams))
|
||||
if (!memcmp(guid, WTV_TIMING, 16) && ((use_alt_stream < WTV_CC_TIMESTAMP_MAGIC_THRESH && check_stream_id(stream_id, video_streams, num_streams))
|
||||
|| (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH && stream_id == alt_stream)))
|
||||
{
|
||||
// The WTV_TIMING GUID contains a timestamp for the given stream_id
|
||||
dbg_print(CCX_DMT_PARSE, "WTV TIMING\n");
|
||||
@@ -379,12 +384,18 @@ LLONG get_data(struct wtv_chunked_buffer *cb) {
|
||||
int64_t time;
|
||||
memcpy(&time, cb->buffer+0x8, 8); // Read the timestamp
|
||||
dbg_print(CCX_DMT_PARSE, "TIME: %ld\n", time);
|
||||
if(time!=-1) { // Ignore -1 timestamps
|
||||
if (time != -1 && time != WTV_CC_TIMESTAMP_MAGIC) { // Ignore -1 timestamps
|
||||
current_pts = time_to_pes_time(time); // Convert from WTV to PES time
|
||||
pts_set = 1;
|
||||
frames_since_ref_time = 0;
|
||||
set_fts();
|
||||
}
|
||||
}
|
||||
else if (time == WTV_CC_TIMESTAMP_MAGIC && stream_id != alt_stream) {
|
||||
use_alt_stream++;
|
||||
mprint("WARNING: %i WTV_CC_TIMESTAMP_MAGIC detected in cc timestamps. \n", use_alt_stream);
|
||||
if (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH)
|
||||
mprint("WARNING: WTV_CC_TIMESTAMP_MAGIC_THRESH reached. Switching to alt timestamps!\n");
|
||||
}
|
||||
len-=16;
|
||||
}
|
||||
if( !memcmp(guid, WTV_DATA, 16 )
|
||||
|
||||
209
src/xds.c
209
src/xds.c
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "utility.h"
|
||||
|
||||
// Program Identification Number (Start Time) for current program
|
||||
static int current_xds_min=-1;
|
||||
@@ -71,6 +72,7 @@ static const char *XDSProgramTypes[]=
|
||||
#define XDS_CLASS_RESERVED 5
|
||||
#define XDS_CLASS_PRIVATE 6
|
||||
#define XDS_CLASS_END 7
|
||||
#define XDS_CLASS_OUT_OF_BAND 0x40 // Not a real class, a marker for packets for out-of-band data.
|
||||
|
||||
// Types for the classes current and future
|
||||
#define XDS_TYPE_PIN_START_TIME 1
|
||||
@@ -97,6 +99,7 @@ static const char *XDSProgramTypes[]=
|
||||
// Types for miscellaneous packets
|
||||
#define XDS_TYPE_TIME_OF_DAY 1
|
||||
#define XDS_TYPE_LOCAL_TIME_ZONE 4
|
||||
#define XDS_TYPE_OUT_OF_BAND_CHANNEL_NUMBER 0x40
|
||||
|
||||
#define NUM_XDS_BUFFERS 9 // CEA recommends no more than one level of interleaving. Play it safe
|
||||
#define NUM_BYTES_PER_PACKET 35 // Class + type (repeated for convenience) + data + zero
|
||||
@@ -117,6 +120,35 @@ static int cur_xds_payload_length;
|
||||
static int cur_xds_packet_type;
|
||||
|
||||
|
||||
int write_xds_string(struct cc_subtitle *sub,char *p,size_t len)
|
||||
{
|
||||
struct eia608_screen *data = NULL;
|
||||
data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
|
||||
if (!data)
|
||||
{
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
mprint("No Memory left");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sub->data = data;
|
||||
data = (struct eia608_screen *)sub->data + sub->nb_data;
|
||||
data->format = SFORMAT_XDS;
|
||||
data->start_time = ts_start_of_xds;
|
||||
data->end_time = get_fts();
|
||||
data->xds_str = p;
|
||||
data->xds_len = len;
|
||||
data->cur_xds_packet_class = cur_xds_packet_class;
|
||||
sub->nb_data++;
|
||||
sub->type = CC_608;
|
||||
sub->got_output = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
void xds_init()
|
||||
{
|
||||
for (int i=0;i<NUM_XDS_BUFFERS;i++)
|
||||
@@ -143,14 +175,14 @@ void xds_write_transcript_line_suffix (struct ccx_s_write *wb)
|
||||
write (wb->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
|
||||
void xds_write_transcript_line_prefix (struct ccx_s_write *wb)
|
||||
void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
if (!wb || wb->fh==-1)
|
||||
return;
|
||||
|
||||
if (ts_start_of_xds == -1)
|
||||
if (start_time == -1)
|
||||
{
|
||||
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
|
||||
fatal (EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
|
||||
@@ -162,17 +194,17 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb)
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
if (utc_refvalue == UINT64_MAX)
|
||||
{
|
||||
mstotime(ts_start_of_xds + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h1, m1, s1, ccx_options.millis_separator, ms1);
|
||||
}
|
||||
else {
|
||||
fdprintf(wb->fh, "%lld%c%03d|", (ts_start_of_xds + subs_delay) / 1000, ccx_options.millis_separator, (ts_start_of_xds + subs_delay) % 1000);
|
||||
fdprintf(wb->fh, "%lld%c%03d|", (start_time + subs_delay) / 1000, ccx_options.millis_separator, (start_time + subs_delay) % 1000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mstotime(ts_start_of_xds + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (ts_start_of_xds + subs_delay) / 1000;
|
||||
int start_time_dec = (ts_start_of_xds + subs_delay) % 1000;
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(wb->fh, "%s%c%03d|", buffer,ccx_options.millis_separator,start_time_dec);
|
||||
@@ -184,18 +216,18 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb)
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
if (utc_refvalue == UINT64_MAX)
|
||||
{
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
mstotime(end_time + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h2, m2, s2, ccx_options.millis_separator, ms2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fdprintf(wb->fh, "%lld%s%03d|", (get_fts() + subs_delay) / 1000, ccx_options.millis_separator, (get_fts() + subs_delay) % 1000);
|
||||
fdprintf(wb->fh, "%lld%s%03d|", (end_time + subs_delay) / 1000, ccx_options.millis_separator, (end_time + subs_delay) % 1000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = (get_fts() + subs_delay) / 1000;
|
||||
int end_time_dec = (get_fts() + subs_delay) % 1000;
|
||||
mstotime(end_time + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = (end_time + subs_delay) / 1000;
|
||||
int end_time_dec = (end_time + subs_delay) % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(wb->fh, "%s%c%03d|", buffer, ccx_options.millis_separator, end_time_dec);
|
||||
@@ -211,13 +243,8 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb)
|
||||
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
|
||||
}
|
||||
}
|
||||
|
||||
void xdsprint (const char *fmt,...)
|
||||
void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
|
||||
{
|
||||
if (wbxdsout==NULL || wbxdsout->fh==-1)
|
||||
return;
|
||||
xds_write_transcript_line_prefix (wbxdsout);
|
||||
|
||||
/* Guess we need no more than 100 bytes. */
|
||||
int n, size = 100;
|
||||
char *p, *np;
|
||||
@@ -226,8 +253,8 @@ void xdsprint (const char *fmt,...)
|
||||
if ((p = (char *) malloc (size)) == NULL)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/* Try to print in the allocated space. */
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf (p, size, fmt, ap);
|
||||
@@ -235,10 +262,8 @@ void xdsprint (const char *fmt,...)
|
||||
/* If that worked, return the string. */
|
||||
if (n > -1 && n < size)
|
||||
{
|
||||
write (wbxdsout->fh, p, n);
|
||||
free (p);
|
||||
xds_write_transcript_line_suffix (wbxdsout);
|
||||
return;
|
||||
write_xds_string(sub, p, n);
|
||||
return;
|
||||
}
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) /* glibc 2.1 */
|
||||
@@ -248,23 +273,22 @@ void xdsprint (const char *fmt,...)
|
||||
if ((np = (char *) realloc (p, size)) == NULL)
|
||||
{
|
||||
free(p);
|
||||
xds_write_transcript_line_suffix (wbxdsout);
|
||||
return ;
|
||||
return ;
|
||||
} else {
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xds_debug_test()
|
||||
void xds_debug_test(struct cc_subtitle *sub)
|
||||
{
|
||||
process_xds_bytes (0x05,0x02);
|
||||
process_xds_bytes (0x20,0x20);
|
||||
do_end_of_xds (0x2a);
|
||||
do_end_of_xds (sub, 0x2a);
|
||||
|
||||
}
|
||||
|
||||
void xds_cea608_test()
|
||||
void xds_cea608_test(struct cc_subtitle *sub)
|
||||
{
|
||||
/* This test is the sample data that comes in CEA-608. It sets the program name
|
||||
to be "Star Trek". The checksum is 0x1d and the validation must succeed. */
|
||||
@@ -276,7 +300,7 @@ void xds_cea608_test()
|
||||
process_xds_bytes (0x02,0x03);
|
||||
process_xds_bytes (0x02,0x03);
|
||||
process_xds_bytes (0x6b,0x00);
|
||||
do_end_of_xds (0x1d);
|
||||
do_end_of_xds (sub, 0x1d);
|
||||
}
|
||||
|
||||
int how_many_used()
|
||||
@@ -368,7 +392,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
|
||||
}
|
||||
}
|
||||
|
||||
void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
|
||||
void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
{
|
||||
static unsigned last_c1=-1, last_c2=-1;
|
||||
static char copy_permited[256];
|
||||
@@ -407,9 +431,12 @@ void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
|
||||
|
||||
}
|
||||
|
||||
xdsprint(copy_permited);
|
||||
xdsprint(aps);
|
||||
xdsprint(rcd);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
{
|
||||
xdsprint(sub, copy_permited);
|
||||
xdsprint(sub, aps);
|
||||
xdsprint(sub, rcd);
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
mprint ("\rXDS: %s\n",copy_permited);
|
||||
@@ -421,7 +448,7 @@ void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
|
||||
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",rcd);
|
||||
}
|
||||
|
||||
void xds_do_content_advisory (unsigned c1, unsigned c2)
|
||||
void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
{
|
||||
static unsigned last_c1=-1, last_c2=-1;
|
||||
static char age[256];
|
||||
@@ -497,8 +524,11 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
|
||||
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
|
||||
if (!a1 && a0) // US TV parental guidelines
|
||||
{
|
||||
xdsprint(age);
|
||||
xdsprint(content);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
{
|
||||
xdsprint(sub, age);
|
||||
xdsprint(sub, content);
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
mprint ("\rXDS: %s\n ",age);
|
||||
@@ -511,7 +541,8 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
|
||||
(a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
|
||||
)
|
||||
{
|
||||
xdsprint(rating);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, rating);
|
||||
if (changed)
|
||||
mprint ("\rXDS: %s\n ",rating);
|
||||
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",rating);
|
||||
@@ -523,9 +554,14 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
|
||||
|
||||
}
|
||||
|
||||
int xds_do_current_and_future ()
|
||||
int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
{
|
||||
int was_proc=0;
|
||||
|
||||
char *str = malloc(1024);
|
||||
char *tstr = NULL;
|
||||
int str_len = 1024;
|
||||
|
||||
switch (cur_xds_packet_type)
|
||||
{
|
||||
case XDS_TYPE_PIN_START_TIME:
|
||||
@@ -554,7 +590,8 @@ int xds_do_current_and_future ()
|
||||
dbg_print(CCX_DMT_XDS, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
|
||||
(cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
|
||||
date,month,hour,min);
|
||||
xdsprint ( "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint (sub, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
|
||||
(cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
|
||||
date,month,hour,min);
|
||||
|
||||
@@ -580,7 +617,8 @@ int xds_do_current_and_future ()
|
||||
else
|
||||
dbg_print(CCX_DMT_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
|
||||
xdsprint("Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, "Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
|
||||
if (cur_xds_payload_length>6) // Next two bytes (optional) available
|
||||
{
|
||||
@@ -590,7 +628,8 @@ int xds_do_current_and_future ()
|
||||
mprint ("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
else
|
||||
dbg_print(CCX_DMT_XDS, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
xdsprint("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
|
||||
}
|
||||
if (cur_xds_payload_length>8) // Next two bytes (optional) available
|
||||
@@ -598,10 +637,11 @@ int xds_do_current_and_future ()
|
||||
int el_sec=cur_xds_payload[6] & 0x3f; // 6 bits
|
||||
if (!xds_program_length_shown)
|
||||
dbg_print(CCX_DMT_XDS, ":%02d",el_sec);
|
||||
xdsprint("Elapsed (SS) :%02d",el_sec);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, "Elapsed (SS) :%02d",el_sec);
|
||||
}
|
||||
if (!xds_program_length_shown)
|
||||
printf ("\n");
|
||||
mprint("\n");
|
||||
else
|
||||
dbg_print(CCX_DMT_XDS, "\n");
|
||||
xds_program_length_shown=1;
|
||||
@@ -616,13 +656,14 @@ int xds_do_current_and_future ()
|
||||
xds_program_name[i-2]=cur_xds_payload[i];
|
||||
xds_program_name[i-2]=0;
|
||||
dbg_print(CCX_DMT_XDS, "\rXDS Program name: %s\n",xds_program_name);
|
||||
xdsprint("Program name: %s",xds_program_name);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, "Program name: %s",xds_program_name);
|
||||
if (cur_xds_packet_class==XDS_CLASS_CURRENT &&
|
||||
strcmp (xds_program_name, current_xds_program_name)) // Change of program
|
||||
{
|
||||
if (!ccx_options.gui_mode_reports)
|
||||
mprint ("\rXDS Notice: Program is now %s\n", xds_program_name);
|
||||
strcpy (current_xds_program_name,xds_program_name);
|
||||
strncpy (current_xds_program_name,xds_program_name, 33);
|
||||
activity_xds_program_name (xds_program_name);
|
||||
}
|
||||
break;
|
||||
@@ -652,20 +693,22 @@ int xds_do_current_and_future ()
|
||||
current_xds_program_type[cur_xds_payload_length]=0;
|
||||
if (!current_program_type_reported)
|
||||
mprint ("\rXDS Program Type: ");
|
||||
xds_write_transcript_line_prefix(wbxdsout);
|
||||
if (wbxdsout && wbxdsout->fh!=-1)
|
||||
fdprintf (wbxdsout->fh,"Program type ");
|
||||
|
||||
*str = '\0';
|
||||
tstr = str;
|
||||
for (int i=2;i<cur_xds_payload_length - 1; i++)
|
||||
{
|
||||
if (cur_xds_payload[i]==0) // Padding
|
||||
continue;
|
||||
if (!current_program_type_reported)
|
||||
mprint ("[%02X-", cur_xds_payload[i]);
|
||||
if (wbxdsout && wbxdsout->fh!=-1)
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
{
|
||||
if (cur_xds_payload[i]>=0x20 && cur_xds_payload[i]<0x7F)
|
||||
fdprintf (wbxdsout->fh,"[%s] ",XDSProgramTypes[cur_xds_payload[i]-0x20]);
|
||||
{
|
||||
snprintf(tstr,str_len - (tstr - str),"[%s] ",XDSProgramTypes[cur_xds_payload[i]-0x20]);
|
||||
tstr += strlen(tstr);
|
||||
}
|
||||
}
|
||||
if (!current_program_type_reported)
|
||||
{
|
||||
@@ -675,8 +718,9 @@ int xds_do_current_and_future ()
|
||||
mprint ("ILLEGAL VALUE");
|
||||
mprint ("] ");
|
||||
}
|
||||
}
|
||||
xds_write_transcript_line_suffix(wbxdsout);
|
||||
}
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub,"Program type %s",str);
|
||||
if (!current_program_type_reported)
|
||||
mprint ("\n");
|
||||
current_program_type_reported=1;
|
||||
@@ -685,14 +729,14 @@ int xds_do_current_and_future ()
|
||||
was_proc=1;
|
||||
if (cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
xds_do_content_advisory (cur_xds_payload[2],cur_xds_payload[3]);
|
||||
xds_do_content_advisory (sub, cur_xds_payload[2],cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_AUDIO_SERVICES:
|
||||
was_proc=1; // I don't have any sample with this.
|
||||
break;
|
||||
case XDS_TYPE_CGMS:
|
||||
was_proc=1;
|
||||
xds_do_copy_generation_management_system (cur_xds_payload[2],cur_xds_payload[3]);
|
||||
xds_do_copy_generation_management_system (sub, cur_xds_payload[2],cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_PROGRAM_DESC_1:
|
||||
case XDS_TYPE_PROGRAM_DESC_2:
|
||||
@@ -725,16 +769,19 @@ int xds_do_current_and_future ()
|
||||
{
|
||||
dbg_print(CCX_DMT_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
|
||||
}
|
||||
xdsprint("XDS description line %d: %s",line_num,xds_desc);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint(sub, "XDS description line %d: %s",line_num,xds_desc);
|
||||
activity_xds_program_description (line_num, xds_desc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
int xds_do_channel ()
|
||||
int xds_do_channel (struct cc_subtitle *sub)
|
||||
{
|
||||
int was_proc=0;
|
||||
switch (cur_xds_packet_type)
|
||||
@@ -747,7 +794,8 @@ int xds_do_channel ()
|
||||
xds_network_name[i-2]=cur_xds_payload[i];
|
||||
xds_network_name[i-2]=0;
|
||||
dbg_print(CCX_DMT_XDS, "XDS Network name: %s\n",xds_network_name);
|
||||
xdsprint ("Network: %s",xds_network_name);
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint (sub, "Network: %s",xds_network_name);
|
||||
if (strcmp (xds_network_name, current_xds_network_name)) // Change of station
|
||||
{
|
||||
mprint ("XDS Notice: Network is now %s\n", xds_network_name);
|
||||
@@ -757,8 +805,8 @@ int xds_do_channel ()
|
||||
case XDS_TYPE_CALL_LETTERS_AND_CHANNEL:
|
||||
{
|
||||
was_proc=1;
|
||||
char xds_call_letters[33];
|
||||
if (cur_xds_payload_length<7) // We need 4-6 data bytes
|
||||
char xds_call_letters[7];
|
||||
if (cur_xds_payload_length != 7 && cur_xds_payload_length != 9) // We need 4-6 data bytes
|
||||
break;
|
||||
for (i=2;i<cur_xds_payload_length-1;i++)
|
||||
{
|
||||
@@ -767,11 +815,12 @@ int xds_do_channel ()
|
||||
}
|
||||
xds_call_letters[i-2]=0;
|
||||
dbg_print(CCX_DMT_XDS, "XDS Network call letters: %s\n",xds_call_letters);
|
||||
xdsprint ("Call Letters: %s",xds_call_letters);
|
||||
if (strcmp (xds_call_letters, current_xds_call_letters)) // Change of station
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
xdsprint (sub, "Call Letters: %s",xds_call_letters);
|
||||
if (strncmp (xds_call_letters, current_xds_call_letters, 7)) // Change of station
|
||||
{
|
||||
mprint ("XDS Notice: Network call letters now %s\n", xds_call_letters);
|
||||
strcpy (current_xds_call_letters,xds_call_letters);
|
||||
strncpy (current_xds_call_letters, xds_call_letters, 7);
|
||||
activity_xds_network_call_letters (current_xds_call_letters);
|
||||
}
|
||||
}
|
||||
@@ -787,8 +836,8 @@ int xds_do_channel ()
|
||||
unsigned b3=(cur_xds_payload[4])&0x10;
|
||||
unsigned b4=(cur_xds_payload[5])&0x10;
|
||||
unsigned tsid=(b4<<12) | (b3<<8) | (b2<<4) | b1;
|
||||
if (tsid)
|
||||
xdsprint ("TSID: %u",tsid);
|
||||
if (tsid && ccx_options.transcript_settings.xds)
|
||||
xdsprint (sub, "TSID: %u",tsid);
|
||||
break;
|
||||
}
|
||||
return was_proc;
|
||||
@@ -796,15 +845,16 @@ int xds_do_channel ()
|
||||
|
||||
|
||||
|
||||
int xds_do_private_data ()
|
||||
int xds_do_private_data (struct cc_subtitle *sub)
|
||||
{
|
||||
if (wbxdsout==NULL) // Only thing we can do with private data is dump it.
|
||||
char *str = malloc((cur_xds_payload_length *3) + 1);
|
||||
if (str==NULL) // Only thing we can do with private data is dump it.
|
||||
return 1;
|
||||
xds_write_transcript_line_prefix (wbxdsout);
|
||||
for (int i=2;i<cur_xds_payload_length-1;i++)
|
||||
fdprintf(wbxdsout->fh, "%02X ",cur_xds_payload[i]);
|
||||
sprintf(str, "%02X ",cur_xds_payload[i]);
|
||||
|
||||
xds_write_transcript_line_suffix (wbxdsout);
|
||||
xdsprint(sub,str);
|
||||
free(str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -848,7 +898,7 @@ int xds_do_misc ()
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
void do_end_of_xds (unsigned char expected_checksum)
|
||||
void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
|
||||
{
|
||||
if (cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */
|
||||
!xds_buffers[cur_xds_buffer_idx].in_use)
|
||||
@@ -883,7 +933,11 @@ void do_end_of_xds (unsigned char expected_checksum)
|
||||
}
|
||||
|
||||
int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */
|
||||
|
||||
if (cur_xds_packet_type & 0x40) // Bit 6 set
|
||||
{
|
||||
cur_xds_packet_class = XDS_CLASS_OUT_OF_BAND;
|
||||
}
|
||||
|
||||
switch (cur_xds_packet_class)
|
||||
{
|
||||
case XDS_CLASS_FUTURE: // Info on future program
|
||||
@@ -893,10 +947,10 @@ void do_end_of_xds (unsigned char expected_checksum)
|
||||
break;
|
||||
}
|
||||
case XDS_CLASS_CURRENT: // Info on current program
|
||||
was_proc = xds_do_current_and_future();
|
||||
was_proc = xds_do_current_and_future(sub);
|
||||
break;
|
||||
case XDS_CLASS_CHANNEL:
|
||||
was_proc = xds_do_channel();
|
||||
was_proc = xds_do_channel(sub);
|
||||
break;
|
||||
|
||||
case XDS_CLASS_MISC:
|
||||
@@ -905,7 +959,12 @@ void do_end_of_xds (unsigned char expected_checksum)
|
||||
case XDS_CLASS_PRIVATE: // CEA-608:
|
||||
// The Private Data Class is for use in any closed system for whatever that
|
||||
// system wishes. It shall not be defined by this standard now or in the future.
|
||||
was_proc=xds_do_private_data();
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
was_proc=xds_do_private_data(sub);
|
||||
break;
|
||||
case XDS_CLASS_OUT_OF_BAND:
|
||||
dbg_print(CCX_DMT_XDS, "Out-of-band data, ignored.");
|
||||
was_proc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
8
src/xds.h
Normal file
8
src/xds.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _XDS_H
|
||||
#define _XDS_H
|
||||
|
||||
|
||||
void xds_write_transcript_line_suffix (struct ccx_s_write *wb);
|
||||
void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
Binary file not shown.
@@ -17,6 +17,7 @@
|
||||
<ClInclude Include="..\src\asf_constants.h" />
|
||||
<ClInclude Include="..\src\bitstream.h" />
|
||||
<ClInclude Include="..\src\ccextractor.h" />
|
||||
<ClInclude Include="..\src\cc_encoders_common.h" />
|
||||
<ClInclude Include="..\src\configuration.h" />
|
||||
<ClInclude Include="..\src\constants.h" />
|
||||
<ClInclude Include="..\src\disable_warnings.h" />
|
||||
@@ -54,6 +55,7 @@
|
||||
<ClInclude Include="..\src\libpng\pnglibconf.h" />
|
||||
<ClInclude Include="..\src\libpng\pngpriv.h" />
|
||||
<ClInclude Include="..\src\libpng\pngstruct.h" />
|
||||
<ClInclude Include="..\src\networking.h" />
|
||||
<ClInclude Include="..\src\platform.h" />
|
||||
<ClInclude Include="..\src\spupng_encoder.h" />
|
||||
<ClInclude Include="..\src\stdint.h" />
|
||||
@@ -88,6 +90,7 @@
|
||||
<ClCompile Include="..\src\ccextractor.c" />
|
||||
<ClCompile Include="..\src\cc_bitstream.c" />
|
||||
<ClCompile Include="..\src\cc_decoders_common.c" />
|
||||
<ClCompile Include="..\src\cc_encoders_common.c" />
|
||||
<ClCompile Include="..\src\configuration.c" />
|
||||
<ClCompile Include="..\src\constants.c" />
|
||||
<ClCompile Include="..\src\dvb_subtitle_decoder.c" />
|
||||
@@ -154,6 +157,7 @@
|
||||
<ClCompile Include="..\src\libpng\pngwtran.c" />
|
||||
<ClCompile Include="..\src\libpng\pngwutil.c" />
|
||||
<ClCompile Include="..\src\myth.c" />
|
||||
<ClCompile Include="..\src\networking.c" />
|
||||
<ClCompile Include="..\src\output.c" />
|
||||
<ClCompile Include="..\src\params.c" />
|
||||
<ClCompile Include="..\src\params_dump.c" />
|
||||
|
||||
@@ -216,6 +216,12 @@
|
||||
<ClInclude Include="..\src\configuration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\cc_encoders_common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\networking.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\gpacmp4\stbl_read.c">
|
||||
@@ -521,5 +527,11 @@
|
||||
<ClCompile Include="..\src\configuration.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\cc_encoders_common.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\networking.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,266 +0,0 @@
|
||||
# Makefile for MinGW using the cygwin environment
|
||||
|
||||
# Run make in the src directory with the following command:
|
||||
# make -f ../windows/cygming.mak
|
||||
|
||||
CXX=g++
|
||||
#CXXFLAGS=-g -Wall
|
||||
CXXFLAGS=-g -mno-cygwin -Wall
|
||||
#CXXFLAGS=-O2 -mno-cygwin -Wall
|
||||
|
||||
objects = 608.o \
|
||||
608_helpers.o \
|
||||
608_sami.o \
|
||||
608_srt.o \
|
||||
708.o \
|
||||
708_encoding.o \
|
||||
activity.o \
|
||||
asf_functions.o \
|
||||
avc_functions.o \
|
||||
bitstream.o \
|
||||
ccextractor.o \
|
||||
encoding.o \
|
||||
es_functions.o \
|
||||
es_userdata.o \
|
||||
file_functions.o \
|
||||
general_loop.o \
|
||||
mp4_bridge2bento4.o \
|
||||
myth.o \
|
||||
output.o \
|
||||
params.o \
|
||||
params_dump.o \
|
||||
sequencing.o \
|
||||
stream_functions.o \
|
||||
timing.o \
|
||||
ts_functions.o
|
||||
|
||||
bentoobjects = bento4/Ap48bdlAtom.o \
|
||||
bento4/Ap4AdtsParser.o \
|
||||
bento4/Ap4AesBlockCipher.o \
|
||||
bento4/Ap4Atom.o \
|
||||
bento4/Ap4AtomFactory.o \
|
||||
bento4/Ap4AtomSampleTable.o \
|
||||
bento4/Ap4AvcParser.o \
|
||||
bento4/Ap4AvccAtom.o \
|
||||
bento4/Ap4BitStream.o \
|
||||
bento4/Ap4ByteStream.o \
|
||||
bento4/Ap4Co64Atom.o \
|
||||
bento4/Ap4Command.o \
|
||||
bento4/Ap4CommandFactory.o \
|
||||
bento4/Ap4ContainerAtom.o \
|
||||
bento4/Ap4CttsAtom.o \
|
||||
bento4/Ap4DataBuffer.o \
|
||||
bento4/Ap4Debug.o \
|
||||
bento4/Ap4DecoderConfigDescriptor.o \
|
||||
bento4/Ap4DecoderSpecificInfoDescriptor.o \
|
||||
bento4/Ap4Descriptor.o \
|
||||
bento4/Ap4DescriptorFactory.o \
|
||||
bento4/Ap4DrefAtom.o \
|
||||
bento4/Ap4ElstAtom.o \
|
||||
bento4/Ap4EsDescriptor.o \
|
||||
bento4/Ap4EsdsAtom.o \
|
||||
bento4/Ap4Expandable.o \
|
||||
bento4/Ap4File.o \
|
||||
bento4/Ap4FileCopier.o \
|
||||
bento4/Ap4FileWriter.o \
|
||||
bento4/Ap4FragmentSampleTable.o \
|
||||
bento4/Ap4FrmaAtom.o \
|
||||
bento4/Ap4FtypAtom.o \
|
||||
bento4/Ap4GrpiAtom.o \
|
||||
bento4/Ap4HdlrAtom.o \
|
||||
bento4/Ap4HintTrackReader.o \
|
||||
bento4/Ap4Hmac.o \
|
||||
bento4/Ap4HmhdAtom.o \
|
||||
bento4/Ap4IkmsAtom.o \
|
||||
bento4/Ap4IodsAtom.o \
|
||||
bento4/Ap4Ipmp.o \
|
||||
bento4/Ap4IproAtom.o \
|
||||
bento4/Ap4IsfmAtom.o \
|
||||
bento4/Ap4IsltAtom.o \
|
||||
bento4/Ap4IsmaCryp.o \
|
||||
bento4/Ap4KeyWrap.o \
|
||||
bento4/Ap4LinearReader.o \
|
||||
bento4/Ap4Marlin.o \
|
||||
bento4/Ap4MdhdAtom.o \
|
||||
bento4/Ap4MehdAtom.o \
|
||||
bento4/Ap4MetaData.o \
|
||||
bento4/Ap4MfhdAtom.o \
|
||||
bento4/Ap4MfroAtom.o \
|
||||
bento4/Ap4MoovAtom.o \
|
||||
bento4/Ap4Movie.o \
|
||||
bento4/Ap4MovieFragment.o \
|
||||
bento4/Ap4Mp4AudioInfo.o \
|
||||
bento4/Ap4Mpeg2Ts.o \
|
||||
bento4/Ap4MvhdAtom.o \
|
||||
bento4/Ap4NmhdAtom.o \
|
||||
bento4/Ap4ObjectDescriptor.o \
|
||||
bento4/Ap4OdafAtom.o \
|
||||
bento4/Ap4OddaAtom.o \
|
||||
bento4/Ap4OdheAtom.o \
|
||||
bento4/Ap4OhdrAtom.o \
|
||||
bento4/Ap4OmaDcf.o \
|
||||
bento4/Ap4Piff.o \
|
||||
bento4/Ap4Processor.o \
|
||||
bento4/Ap4Protection.o \
|
||||
bento4/Ap4Results.o \
|
||||
bento4/Ap4RtpAtom.o \
|
||||
bento4/Ap4RtpHint.o \
|
||||
bento4/Ap4SLConfigDescriptor.o \
|
||||
bento4/Ap4Sample.o \
|
||||
bento4/Ap4SampleDescription.o \
|
||||
bento4/Ap4SampleEntry.o \
|
||||
bento4/Ap4SampleSource.o \
|
||||
bento4/Ap4SampleTable.o \
|
||||
bento4/Ap4SchmAtom.o \
|
||||
bento4/Ap4SdpAtom.o \
|
||||
bento4/Ap4SmhdAtom.o \
|
||||
bento4/Ap4StcoAtom.o \
|
||||
bento4/Ap4StdCFileByteStream.o \
|
||||
bento4/Ap4StreamCipher.o \
|
||||
bento4/Ap4String.o \
|
||||
bento4/Ap4StscAtom.o \
|
||||
bento4/Ap4StsdAtom.o \
|
||||
bento4/Ap4StssAtom.o \
|
||||
bento4/Ap4StszAtom.o \
|
||||
bento4/Ap4SttsAtom.o \
|
||||
bento4/Ap4SyntheticSampleTable.o \
|
||||
bento4/Ap4TfhdAtom.o \
|
||||
bento4/Ap4TfraAtom.o \
|
||||
bento4/Ap4TimsAtom.o \
|
||||
bento4/Ap4TkhdAtom.o \
|
||||
bento4/Ap4Track.o \
|
||||
bento4/Ap4TrakAtom.o \
|
||||
bento4/Ap4TrefTypeAtom.o \
|
||||
bento4/Ap4TrexAtom.o \
|
||||
bento4/Ap4TrunAtom.o \
|
||||
bento4/Ap4UrlAtom.o \
|
||||
bento4/Ap4Utils.o \
|
||||
bento4/Ap4UuidAtom.o \
|
||||
bento4/Ap4VmhdAtom.o \
|
||||
bento4/LinearReaderTest.o
|
||||
|
||||
bentoheaders = bento4/Ap4.h \
|
||||
bento4/Ap48bdlAtom.h \
|
||||
bento4/Ap4AdtsParser.h \
|
||||
bento4/Ap4AesBlockCipher.h \
|
||||
bento4/Ap4Array.h \
|
||||
bento4/Ap4Atom.h \
|
||||
bento4/Ap4AtomFactory.h \
|
||||
bento4/Ap4AtomSampleTable.h \
|
||||
bento4/Ap4AvcParser.h \
|
||||
bento4/Ap4AvccAtom.h \
|
||||
bento4/Ap4BitStream.h \
|
||||
bento4/Ap4ByteStream.h \
|
||||
bento4/Ap4Co64Atom.h \
|
||||
bento4/Ap4Command.h \
|
||||
bento4/Ap4CommandFactory.h \
|
||||
bento4/Ap4Config.h \
|
||||
bento4/Ap4Constants.h \
|
||||
bento4/Ap4ContainerAtom.h \
|
||||
bento4/Ap4CttsAtom.h \
|
||||
bento4/Ap4DataBuffer.h \
|
||||
bento4/Ap4Debug.h \
|
||||
bento4/Ap4DecoderConfigDescriptor.h \
|
||||
bento4/Ap4DecoderSpecificInfoDescriptor.h \
|
||||
bento4/Ap4Descriptor.h \
|
||||
bento4/Ap4DescriptorFactory.h \
|
||||
bento4/Ap4DrefAtom.h \
|
||||
bento4/Ap4DynamicCast.h \
|
||||
bento4/Ap4ElstAtom.h \
|
||||
bento4/Ap4EsDescriptor.h \
|
||||
bento4/Ap4EsdsAtom.h \
|
||||
bento4/Ap4Expandable.h \
|
||||
bento4/Ap4File.h \
|
||||
bento4/Ap4FileByteStream.h \
|
||||
bento4/Ap4FileCopier.h \
|
||||
bento4/Ap4FileWriter.h \
|
||||
bento4/Ap4FragmentSampleTable.h \
|
||||
bento4/Ap4FrmaAtom.h \
|
||||
bento4/Ap4FtypAtom.h \
|
||||
bento4/Ap4GrpiAtom.h \
|
||||
bento4/Ap4HdlrAtom.h \
|
||||
bento4/Ap4HintTrackReader.h \
|
||||
bento4/Ap4Hmac.h \
|
||||
bento4/Ap4HmhdAtom.h \
|
||||
bento4/Ap4IkmsAtom.h \
|
||||
bento4/Ap4Interfaces.h \
|
||||
bento4/Ap4IodsAtom.h \
|
||||
bento4/Ap4Ipmp.h \
|
||||
bento4/Ap4IproAtom.h \
|
||||
bento4/Ap4IsfmAtom.h \
|
||||
bento4/Ap4IsltAtom.h \
|
||||
bento4/Ap4IsmaCryp.h \
|
||||
bento4/Ap4KeyWrap.h \
|
||||
bento4/Ap4LinearReader.h \
|
||||
bento4/Ap4List.h \
|
||||
bento4/Ap4Marlin.h \
|
||||
bento4/Ap4MdhdAtom.h \
|
||||
bento4/Ap4MehdAtom.h \
|
||||
bento4/Ap4MetaData.h \
|
||||
bento4/Ap4MfhdAtom.h \
|
||||
bento4/Ap4MfroAtom.h \
|
||||
bento4/Ap4MoovAtom.h \
|
||||
bento4/Ap4Movie.h \
|
||||
bento4/Ap4MovieFragment.h \
|
||||
bento4/Ap4Mp4AudioInfo.h \
|
||||
bento4/Ap4Mpeg2Ts.h \
|
||||
bento4/Ap4MvhdAtom.h \
|
||||
bento4/Ap4NmhdAtom.h \
|
||||
bento4/Ap4ObjectDescriptor.h \
|
||||
bento4/Ap4OdafAtom.h \
|
||||
bento4/Ap4OddaAtom.h \
|
||||
bento4/Ap4OdheAtom.h \
|
||||
bento4/Ap4OhdrAtom.h \
|
||||
bento4/Ap4OmaDcf.h \
|
||||
bento4/Ap4Piff.h \
|
||||
bento4/Ap4Processor.h \
|
||||
bento4/Ap4Protection.h \
|
||||
bento4/Ap4Results.h \
|
||||
bento4/Ap4RtpAtom.h \
|
||||
bento4/Ap4RtpHint.h \
|
||||
bento4/Ap4SLConfigDescriptor.h \
|
||||
bento4/Ap4Sample.h \
|
||||
bento4/Ap4SampleDescription.h \
|
||||
bento4/Ap4SampleEntry.h \
|
||||
bento4/Ap4SampleSource.h \
|
||||
bento4/Ap4SampleTable.h \
|
||||
bento4/Ap4SchmAtom.h \
|
||||
bento4/Ap4SdpAtom.h \
|
||||
bento4/Ap4SmhdAtom.h \
|
||||
bento4/Ap4StcoAtom.h \
|
||||
bento4/Ap4StreamCipher.h \
|
||||
bento4/Ap4String.h \
|
||||
bento4/Ap4StscAtom.h \
|
||||
bento4/Ap4StsdAtom.h \
|
||||
bento4/Ap4StssAtom.h \
|
||||
bento4/Ap4StszAtom.h \
|
||||
bento4/Ap4SttsAtom.h \
|
||||
bento4/Ap4SyntheticSampleTable.h \
|
||||
bento4/Ap4TfhdAtom.h \
|
||||
bento4/Ap4TfraAtom.h \
|
||||
bento4/Ap4TimsAtom.h \
|
||||
bento4/Ap4TkhdAtom.h \
|
||||
bento4/Ap4Track.h \
|
||||
bento4/Ap4TrakAtom.h \
|
||||
bento4/Ap4TrefTypeAtom.h \
|
||||
bento4/Ap4TrexAtom.h \
|
||||
bento4/Ap4TrunAtom.h \
|
||||
bento4/Ap4Types.h \
|
||||
bento4/Ap4UrlAtom.h \
|
||||
bento4/Ap4Utils.h \
|
||||
bento4/Ap4UuidAtom.h \
|
||||
bento4/Ap4Version.h \
|
||||
bento4/Ap4VmhdAtom.h \
|
||||
|
||||
ccextractor : $(objects) $(bentoobjects)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(objects) $(bentoobjects)
|
||||
strip $@
|
||||
|
||||
$(objects) : ccextractor.h 608.h 708.h bitstream.h
|
||||
|
||||
# Lazy solution.
|
||||
$(bentoobjects) : $(bentoheaders)
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm ccextractor.exe $(objects) $(bentoobjects)
|
||||
Reference in New Issue
Block a user