Compare commits

...

133 Commits
v0.70 ... v0.72

Author SHA1 Message Date
cfsmp3
7fa59a14f7 Updated MD 2014-08-12 17:15:39 +02:00
wforums
4e6c0352b0 XDS segfault fix
Fixes segfault on using TTXT + XDS
2014-08-12 10:39:01 +02:00
cfsmp3
cc7ebbc4d7 Replace g++ with gcc in OSX 2014-08-11 14:33:52 +02:00
Ruslan Kuchumov
7a74b815fa segfault on error fix 2014-08-09 21:23:27 +00:00
Ruslan Kuchumov
331038634d password bug fix 2014-08-09 21:17:41 +00:00
Ruslan Kuchumov
aa2c316093 Chris's patch 2014-08-09 20:52:15 +00:00
cfsmp3
3347f5d345 Version bump 2014-08-09 13:18:56 +02:00
cfsmp3
141792a299 Delete upgradelog. 2014-08-09 13:18:14 +02:00
cfsmp3
183e613981 Merge branch 'pr/n93_wforums' 2014-08-08 16:39:02 +02:00
wforums
19e2912a71 AVC fps fix
- Will now change current_fps based on AVC data (if present). Should fix
an issue with low fps video that was submitted.
2014-08-07 21:09:45 +02:00
wforums
dc82154a03 AVC fps fix
Changes.txt updated.
2014-08-07 21:09:31 +02:00
cfsmp3
2029dab3bf Merge branch 'pr/n92_anshul1912' 2014-08-05 21:24:08 +02:00
wforums
405d808d0b WTV fix
Fixed WTV
2014-08-04 21:10:17 +02:00
Anshul Maheshwari
783e889634 showing language at channel in DVB transcript 2014-07-31 01:28:19 +05:30
Anshul Maheshwari
a32c8a3b7f dvb output as transcript 2014-07-30 23:00:55 +05:30
Anshul Maheshwari
5618df35c6 Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-07-30 21:17:44 +05:30
Anshul Maheshwari
c054594383 output of dvb in srt sami smptett format 2014-07-30 21:17:04 +05:30
Anshul Maheshwari
c58f99378f removing redundant snprintf defines 2014-07-30 00:33:47 -07:00
Anshul Maheshwari
45d1dfe425 merging src/cc_encoders_common.c 2014-07-30 11:45:25 +05:30
Anshul Maheshwari
a5dcf9242d dvb_sub_decoder use common encoder interface 2014-07-30 11:40:12 +05:30
cfsmp3
ecc0714f48 Correction to text files 2014-07-29 10:12:22 +02:00
cfsmp3
26410b991d Version pump 2014-07-29 10:06:45 +02:00
cfsmp3
19b1bff7f4 Merge branch 'pr/n91_anshul1912'
Conflicts:
	docs/CHANGES.TXT
2014-07-29 09:28:28 +02:00
Anshul Maheshwari
bc1aff78d7 updated README 2014-07-29 08:16:00 +02:00
Anshul Maheshwari
2df8931d00 updated changes.txt 2014-07-29 08:13:54 +02:00
wforums
b765198d53 Updated for 0.71
-
2014-07-28 22:22:47 +02:00
cfsmp3
22f620400a Merge branch 'pr/n89_anshul1912' 2014-07-28 21:22:29 +02:00
cfsmp3
a68add78d0 Merge branch 'pr/n88_rkuchumov'
Conflicts:
	docs/CHANGES.TXT
2014-07-28 17:56:15 +02:00
Ruslan Kuchumov
14d866e8a2 -stdin parameter 2014-07-28 18:48:07 +00:00
Anshul Maheshwari
335bca4507 uninitialized values used in encoder 2014-07-28 17:48:25 +02:00
Ruslan Kuchumov
f31425e9f0 cygwin support 2014-07-28 13:57:54 +00:00
Anshul Maheshwari
3f54fab5f4 Indentation of file 2014-07-28 11:19:33 +05:30
Anshul Maheshwari
59c62d48b3 handle memory leakage 2014-07-28 10:55:46 +05:30
Ruslan Kuchumov
a926766478 merge conflict 2014-07-27 23:24:19 +00:00
Ruslan Kuchumov
cc233c61f2 changes.txt 2014-07-27 23:23:11 +00:00
cfsmp3
e9fcdf392f Merge branch 'pr/n83_rkuchumov'
Conflicts:
	src/file_functions.c
	src/params.c
2014-07-27 20:29:05 +02:00
Ruslan
c42f039297 fix 2014-07-26 21:17:20 +04:00
Ruslan Kuchumov
8cbaf09b4f moved udp code to networking.c 2014-07-26 21:07:45 +00:00
Ruslan Kuchumov
ee8d5dff66 goddamn windows 2014-07-26 17:56:58 +00:00
Ruslan Kuchumov
ec0873f5a2 windows support 2014-07-26 12:06:17 +00:00
Ruslan Kuchumov
29515bfcd5 some changes to the protocol 2014-07-25 19:58:16 +00:00
Ruslan Kuchumov
c85ebb0c1e usage & no debug 2014-07-25 18:17:46 +00:00
Ruslan Kuchumov
d6e66d5c7f password 2014-07-24 22:47:47 +00:00
Ruslan Kuchumov
f65f2b229a params 2014-07-24 21:14:56 +00:00
Ruslan Kuchumov
5094351469 listening tcp port 2014-07-24 20:19:13 +00:00
Anshul Maheshwari
5d6a770ce8 error checking for socket 2014-07-23 13:34:36 +05:30
Anshul Maheshwari
010d7f9ce4 error checking in fdprintf 2014-07-23 13:14:20 +05:30
Anshul Maheshwari
fb49e680a6 error checking in getfilesize 2014-07-23 13:10:42 +05:30
Anshul Maheshwari
6b98856892 put telexcc debug code inside a macro 2014-07-23 13:08:04 +05:30
Anshul Maheshwari
1a479a7199 looking for writing beyond the memory
increasing memory to 40, though only 38 is required but to make it
multiple of 4 and 8 looking at 32bit and 64 bit system.
2014-07-23 11:58:38 +05:30
Anshul Maheshwari
2894bcd7ff closed cid 26479 getc does not match eof 2014-07-22 15:36:00 +05:30
Anshul Maheshwari
1ae8040bd7 closing configurtion file correctly 2014-07-22 14:08:02 +05:30
Ruslan Kuchumov
57a80084ce bin support 2014-07-21 13:18:20 +00:00
Ruslan Kuchumov
e35b4ea62c small fix 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
3546526177 teletext support 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
12efb6166a constants 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
9beee068ce debug output 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
9efcba5c02 608 support & params 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
947333ea64 init 2014-07-21 11:08:29 +00:00
Anshul Maheshwari
7e527fc62a memory leakage for 608_smptett 2014-07-21 14:09:02 +05:30
Anshul Maheshwari
9f78c595b3 resource leak in configuration 2014-07-21 13:54:42 +05:30
Anshul Maheshwari
fa03442c85 leakage of file handler 2014-07-21 13:54:33 +05:30
Anshul Maheshwari
e664c035a1 handle memory leakage 2014-07-21 13:54:04 +05:30
Anshul Maheshwari
c522e3b054 error checking fr cur_xds_payload_length 2014-07-21 13:52:41 +05:30
Anshul Maheshwari
b3c037ab21 indentation of param_c 2014-07-21 12:16:16 +05:30
Anshul Maheshwari
097fdb643b corecting boundary of xds_call_letters 2014-07-21 11:41:42 +05:30
Anshul Maheshwari
43094a9897 fix typo while checking boundary 2014-07-21 11:36:20 +05:30
Anshul Maheshwari
aefa623cd4 reverted typo for xds with mprint 2014-07-20 20:07:28 +05:30
Anshul Maheshwari
1be11738eb removed redundant declaration in header file 2014-07-20 20:06:36 +05:30
Anshul Maheshwari
5a09c116f6 correct xdsprint argument 2014-07-20 14:26:42 +05:30
cfsmp3
bb700db08e Merge branch 'pr/n78_anshul1912' 2014-07-20 10:46:38 +02:00
cfsmp3
2e8582b14c Merge branch 'pr/n74_anshul1912'
Conflicts:
	src/608_sami.c
2014-07-20 10:46:21 +02:00
Anshul Maheshwari
8d47dc2f82 corrected size of expression 2014-07-20 13:37:35 +05:30
Anshul Maheshwari
6a3c736195 Added comments, to use function and structure 2014-07-20 08:53:43 +05:30
Anshul Maheshwari
9463999325 added snprintf in utility 2014-07-19 12:27:22 -07:00
Anshul Maheshwari
e50c30eaaa not to write 0 bytes
write have undefined( not mentioned behaviour when 0 bytes written)
write xds data even if start_time is 0
2014-07-19 22:10:50 +05:30
Anshul Maheshwari
45a3e21897 passed as argument cur_xds_packet_class 2014-07-19 18:34:42 +05:30
Anshul Maheshwari
47dbcdff9c write xds data only when option is passed 2014-07-19 18:15:53 +05:30
Anshul Maheshwari
dc164f81e5 improved xds logic 2014-07-19 17:46:16 +05:30
Anshul Maheshwari
bab0ec8b60 removed implicit declaration warning 2014-07-19 16:35:53 +05:30
Anshul Maheshwari
f543e3f4e2 xds extraction in seprate output context 2014-07-19 16:29:28 +05:30
Ruslan Kuchumov
43d4b9abaa typo fix 2014-07-18 21:45:57 +00:00
Ruslan Kuchumov
f5bbb6aef5 output to stdout when -out=null removed 2014-07-18 21:44:47 +00:00
Ruslan Kuchumov
25b666c2ae seg fault fix 2014-07-18 21:43:53 +00:00
Anshul Maheshwari
78087073ac mpg file correction 2014-07-18 11:23:16 +02:00
Anshul Maheshwari
12c2ced497 corrected transcript for mov files 2014-07-17 17:26:14 +02:00
cfsmp3
87954419ba Typo fix 2014-07-16 14:31:41 +02:00
cfsmp3
0add0bc2e9 Detect out-of-band XDS packets and a couple of other bugfixes. 2014-07-16 14:30:59 +02:00
Anshul Maheshwari
7858afb837 Merge branch 'seprate_output_context' of https://github.com/anshul1912/ccextractor into seprate_output_context 2014-07-16 16:07:21 +05:30
Anshul Maheshwari
69c0b2e223 handling end of data correctly 2014-07-16 16:06:29 +05:30
Anshul Maheshwari
855ca48220 not to use g++ 2014-07-16 16:05:55 +05:30
Anshul Maheshwari
02bee86397 correct value for try_to_add_start_credits 2014-07-14 21:28:27 +05:30
Anshul Maheshwari
315d466da8 updated mythtv for encoder 2014-07-14 18:47:54 +05:30
Anshul Maheshwari
d4597e0094 indentation of mythtv 2014-07-14 17:52:06 +05:30
cfsmp3
b8ff3414c0 Fix is packet size, as reporte by Coverity 2014-07-14 14:12:12 +02:00
Anshul Maheshwari
2206cc1f78 adding encoder in rcwt loop 2014-07-14 17:24:20 +05:30
Anshul Maheshwari
00433467be use_"-12"_and_"-out=raw"_tn_both_fields_in_1_file 2014-07-14 17:20:03 +05:30
Anshul Maheshwari
1000e33e7f adding raw data support 2014-07-14 13:37:30 +05:30
Anshul Maheshwari
a64245fb5b correcting help message typo 2014-07-14 13:37:07 +05:30
Anshul Maheshwari
2f784f00ff correcting logic of devide time
Added another loop so that data whose start time is
already set, does not get affected while setting
others time.

in cc_encoder doing data++ so that it can buffer
more then 2 data
2014-07-14 13:32:54 +05:30
Anshul Maheshwari
136012c558 moving write header in init_encoder
RCWT header can't have a BOM before it, or parsing it later will not
be possible
2014-07-13 18:40:50 +05:30
Anshul Maheshwari
874abf6442 added encoder context in spupng 2014-07-13 18:28:39 +05:30
Anshul Maheshwari
20975957ee corrected corruption of sub for mp4 2014-07-13 18:28:33 +05:30
Anshul Maheshwari
1fabae2870 using encoder from cc_encoder_common 2014-07-13 18:28:28 +05:30
Anshul Maheshwari
abb3523ee3 passing encoder context 2014-07-13 18:28:22 +05:30
Anshul Maheshwari
ec63a06e25 generic-code-from-608-encoder-to-common-encoder 2014-07-13 18:28:16 +05:30
Anshul Maheshwari
8b4353f08c passing-subtitle-in-output_c 2014-07-13 18:28:11 +05:30
Anshul Maheshwari
8bfb3b87c3 remove declaration conflicts 2014-07-13 18:28:06 +05:30
Anshul Maheshwari
f1a493b999 passing-subtitle-in-myth.c-n-sequencing.c 2014-07-13 18:28:00 +05:30
Anshul Maheshwari
3afcfa79e1 allocating-cc_subtitle-for-mp4 2014-07-13 18:27:55 +05:30
Anshul Maheshwari
adaa436f6b allocating-cc_subtitle-in-general_loop.c 2014-07-13 18:27:49 +05:30
Anshul Maheshwari
37135762c5 passing-av-subtitle-in-es_userdata.c 2014-07-13 18:27:44 +05:30
Anshul Maheshwari
e6aa7128df passing cc_subtitle in ccextractor_h n es_function_c 2014-07-13 18:27:37 +05:30
Anshul Maheshwari
da8d4a290c passing cc_subtitle in src/avc_functions.c 2014-07-13 18:27:30 +05:30
Anshul Maheshwari
4d11a727d9 passing cc_subtitle in cc608 decoder 2014-07-13 18:27:20 +05:30
Anshul Maheshwari
3c232bfca0 Merge remote-tracking branch 'upstream/master' 2014-07-13 18:24:37 +05:30
Anshul Maheshwari
b3fe96477a dereferebcing NULL pointer 2014-07-13 18:08:44 +05:30
Anshul Maheshwari
5f87544a0d Invalid memory access at boundary 2014-07-13 01:43:27 +05:30
cfsmp3
f0c0ca4566 Merge branch 'pr/n73_anshul1912' 2014-07-12 21:26:45 +02:00
Anshul Maheshwari
23719526cd update changes_text 2014-07-13 00:54:57 +05:30
cfsmp3
67ffe22460 Merge branch 'pr/n72_anshul1912' 2014-07-12 21:18:07 +02:00
Anshul Maheshwari
08996a3253 using freep and removing redundant code 2014-07-12 19:42:38 +05:30
Anshul Maheshwari
95e2f7665b corrected time roll up 2014-07-12 11:28:43 +05:30
Anshul Maheshwari
a5ef2d1574 some memory check before accessing 2014-07-11 13:13:48 -07:00
Anshul Maheshwari
cc0a786004 compile on windows 2014-07-11 22:13:33 +05:30
Anshul Maheshwari
4d6693d948 cleaned mp4.c file 2014-07-11 19:09:34 +05:30
Anshul Maheshwari
9c0792c5a0 using time from data structure 2014-07-11 18:51:04 +05:30
Anshul Maheshwari
0f06f47ab4 logic to devide time between frames 2014-07-11 18:40:00 +05:30
Anshul Maheshwari
5371f854fc indentation of 608_srt.c 2014-07-11 16:59:20 +05:30
wforums
bd49f0f959 Fix for .bin/RCWT file generation
When not using latin1 charset, we were producing unreadable .bin files.

Fixed by adding a separate case where for an RCWT under no circumstance
BOM's can be added before the header.
2014-07-10 12:37:30 +02:00
Willem
63d3071233 Merge pull request #1 from CCExtractor/master
put wtv specific dump in WTV_DEBUG macro
2014-07-10 11:36:00 +02:00
Anshul Maheshwari
015a50bafd put wtv specific dump in WTV_DEBUG macro 2014-07-07 18:02:59 +05:30
Anshul Maheshwari
1ee4b9bd01 put wtv specific dump in WTV_DEBUG macro 2014-07-07 17:45:12 +05:30
59 changed files with 5561 additions and 3546 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -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\">&nbsp;</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\">&nbsp;</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\">&nbsp;</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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -123,3 +123,11 @@ enum
DTVCC_PACKET_DATA = 2,
DTVCC_PACKET_START = 3,
};
const char *language[4] =
{
"und",
"eng",
"fin",
NULL
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

955
src/networking.c Normal file
View 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
View 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 */

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -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" />

View File

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

View File

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