Compare commits

...

474 Commits
v0.76 ... v0.78

Author SHA1 Message Date
cfsmp3
509ed756fd 0.78 2015-12-14 21:29:45 +01:00
cfsmp3
152b69ddba Changed version number to 0.78 2015-12-12 18:53:48 +01:00
Anshul Maheshwari
c2eedab33d Adding simple xml support
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-12-12 17:49:54 +05:30
Carlos Fernandez
677fee4145 Start segments at 1 2015-10-28 06:58:26 -07:00
Anshul Maheshwari
72dad743dc remove white space
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 19:14:52 +05:30
Anshul Maheshwari
e262b0699a Memory Cleanup
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 19:05:52 +05:30
Anshul Maheshwari
6942089a32 Remove Dead Code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 17:59:10 +05:30
Anshul Maheshwari
993adc3dec Indenting psi function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 17:58:09 +05:30
Anshul Maheshwari
fe7a39c0cb initialized end of string
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 17:53:20 +05:30
Anshul Maheshwari
3bd704e495 working explicit no roll up in ISDB
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-27 13:59:13 +05:30
Anshul Maheshwari
6992e54f8e Correct indentation
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-26 10:15:15 +05:30
Anshul Maheshwari
4d5ab77fed improve isdb
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-25 15:29:18 +05:30
Anshul Maheshwari
1b2328d728 Adding No Rollup in ISDB
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-23 19:34:47 +05:30
Anshul Maheshwari
2944e12541 remove unnecessary space
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-23 15:33:13 +05:30
Anshul Maheshwari
763972ca4b Added latin-1 support for teletext transcript
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-23 04:22:11 +05:30
Anshul Maheshwari
01fe0c1fc9 consider last character
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-23 01:56:39 +05:30
Anshul Maheshwari
8d160a70ff Correcting broken encoding of telexcc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-23 01:15:40 +05:30
Anshul Maheshwari
fc90b9c9f5 Added caption server details in logs
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-21 20:52:50 +05:30
Anshul Maheshwari
0a803df23f Adding parsing logic for private user data
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-21 18:24:36 +05:30
Anshul Maheshwari
d3a1ed4b06 Adding Caption descriptor
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>

This description has been added with refrence to descripton defined
in ATSC Standard

Standard Name:   Digital Video Service Multiplex and
              Transport System Standard for Cable Television

Standard Number: ANSI/SCTE 54 2009
Table 5.5 Descriptors
Section 5.8.3.6 Caption service descriptor

This was implemented for broken video in Willem testSuite with number 6
2015-10-21 17:21:39 +05:30
Anshul Maheshwari
ad89e0074b revert back max bframe
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-21 14:05:59 +05:30
Anshul Maheshwari
169a39eb3e correct Garbeled cc in multiple slice header
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-21 13:19:46 +05:30
Anshul Maheshwari
a6145af7f3 newline after showing all payload
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-19 16:47:28 +05:30
Anshul Maheshwari
03b60ef140 use common logger
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-19 13:37:51 +05:30
Anshul Maheshwari
1b7ef1e198 remove dead code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-19 13:37:01 +05:30
Anshul Maheshwari
72de68a575 Specify es paresr specific function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>

They should be moved in structure instead of writing them openly in
common decoder
2015-10-19 13:34:07 +05:30
Anshul Maheshwari
24e7b94599 regards for local count while allocatinf buffer
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-19 13:33:19 +05:30
Anshul Maheshwari
c5dc4531ae use CCX_TRUE instead of 1
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-19 13:31:22 +05:30
Anshul Maheshwari
a3e07b4a63 putting back logic of skiping packet when empty
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-17 18:16:43 +05:30
Anshul Maheshwari
d48555b849 clear buffer after copid to cc_sub
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-06 13:48:04 +05:30
Anshul Maheshwari
a1f05caddf same name buf instead buf1 buf2
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-06 13:17:05 +05:30
Anshul Maheshwari
669eb36603 remove redundant logs
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-10-06 08:54:09 +02:00
Anshul Maheshwari
ce379bcfda nb of data not decreased properly
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-10-06 08:51:43 +02:00
Anshul Maheshwari
00657ffdcd reset payload
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-10-05 15:59:56 +02:00
Anshul Maheshwari
d9e0ba027f memset payload
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-05 19:26:38 +05:30
Anshul Maheshwari
a7279e3d8a initialize min glb time stamp
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-05 19:07:19 +05:30
Anshul Maheshwari
61ae7e9f10 Merge branch 'master' of github.com:anshul1912/ccextractor 2015-10-05 19:03:20 +05:30
Anshul Maheshwari
548d323ca1 Initialize maxtref
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-05 19:03:01 +05:30
Anshul Maheshwari
d2d7a17f3b strtok_r for windows
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-05 12:58:09 +05:30
cfsmp3
65b0ed0038 Merge branch 'pr/n232_kisselef' 2015-10-04 09:56:20 +02:00
cfsmp3
2b0523d34c Merge branch 'pr/n233_anshul1912' 2015-10-04 09:55:28 +02:00
Anshul Maheshwari
5bef6bd5a4 ISDB tag in transcript mode
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-03 20:25:36 +05:30
Anshul Maheshwari
5ca3965c7b care newline in isdb to transcript
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-10-03 19:18:37 +05:30
Oleg Kisselef
e855665c87 cea-708 fixed unhandled predefined window styles 2015-10-02 13:25:14 +03:00
cfsmp3
e9bf8dad9f Merge branch 'pr/n231_anshul1912' 2015-09-30 13:54:15 +02:00
Anshul Maheshwari
54c2b21a4c Update isdb changes
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-30 17:21:53 +05:30
cfsmp3
afe5cba480 Merge branch 'pr/n230_anshul1912' 2015-09-30 13:45:15 +02:00
Anshul Maheshwari
8c34f4cbb2 make pcr program wise
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-30 16:34:27 +05:30
Anshul Maheshwari
e422e7075a correct buffered_read_opt declaration
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-30 14:06:35 +05:30
Anshul Maheshwari
cc0ee507dd remove some vs warning
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-30 13:37:27 +05:30
cfsmp3
540850f0b9 Merge branch 'pr/n230_anshul1912' 2015-09-29 17:05:54 +02:00
Anshul Maheshwari
a973c0a9c3 Merge remote-tracking branch 'upstream/master' into isdb 2015-09-29 20:34:42 +05:30
Anshul Maheshwari
ae27b3411b changed some variable name in isdb
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-29 20:34:20 +05:30
cfsmp3
89c4ac091a Merge branch 'pr/n230_anshul1912' 2015-09-29 16:56:34 +02:00
Anshul Maheshwari
843ca9b60a add ISDB source files
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-29 20:22:53 +05:30
cfsmp3
d135362d40 Add leading 0s in segment names 2015-09-29 16:51:59 +02:00
Anshul Maheshwari
2f1b9df6e9 ISDB support
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-29 20:18:50 +05:30
cfsmp3
5ef2519bf5 Merge branch 'pr/n228_anshul1912' 2015-09-24 12:22:45 +02:00
Anshul Maheshwari
f258d317cc remove uninitialized memory
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-24 15:51:35 +05:30
cfsmp3
4d3fcd6779 Merge branch 'pr/n228_anshul1912' 2015-09-24 11:54:23 +02:00
Anshul Maheshwari
f1b0aff789 Adding system segmentation logic
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-24 15:18:46 +05:30
wforums
6e9a30b354 fix solution
-
2015-09-24 00:08:19 +02:00
wforums
37091708b7 Merge remote-tracking branch 'CCExtractor/master'
Conflicts:
	windows/ccextractor.vcxproj.filters
2015-09-24 00:05:46 +02:00
wforums
0885aae79c Updating project files
-
2015-09-24 00:03:54 +02:00
Anshul Maheshwari
5e5d30d154 Merge branch 'master' of github.com:anshul1912/ccextractor 2015-09-23 23:25:40 +05:30
Anshul Maheshwari
a614db1e20 Add option to segment file
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-23 23:25:18 +05:30
Anshul Maheshwari
f7f29e558b removed uninitialized use of result
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-09-18 11:59:00 +02:00
Anshul Maheshwari
ddc1bfe74f removed global variable result
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-18 12:39:27 +05:30
Anshul Maheshwari
18b95d9564 renamed headerfile
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 15:51:20 +05:30
Anshul Maheshwari
b012f87d87 move buffered read to file_buffer
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 15:45:16 +05:30
Anshul Maheshwari
73f277fe95 rename to keep consistency with other file
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 00:52:38 +05:30
Anshul Maheshwari
bd3df850a5 renamed 608 encoder to generic cc_encoders
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 00:36:12 +05:30
Anshul Maheshwari
73b52462c0 rename encoders from 608 to generic
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 00:28:15 +05:30
Anshul Maheshwari
267d7b4a2e moved buffer_read to file_buffer
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-17 00:00:22 +05:30
Anshul Maheshwari
35cdeda56c Adding error checking for memory in epg
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-16 17:59:44 +05:30
Anshul Maheshwari
0f90eebdf6 uninitialized section length
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-16 17:59:40 +05:30
Anshul Maheshwari
962357ed0f Adding comments
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 19:56:46 +05:30
Anshul Maheshwari
69d077df9e Adding space and reindenting
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 18:07:54 +05:30
Anshul Maheshwari
e2b0534374 remove dead code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 17:57:39 +05:30
Anshul Maheshwari
4204b7878d remove dangling declaration
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 17:55:39 +05:30
Anshul Maheshwari
1e2237f7ec saving missing result
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 17:41:00 +05:30
Anshul Maheshwari
6bfe3b3f86 Merge branch 'master' of github.com:anshul1912/ccextractor 2015-09-15 17:12:06 +05:30
Anshul Maheshwari
940bee33a4 Merge remote-tracking branch 'upstream/master' 2015-09-15 17:10:54 +05:30
cfsmp3
7c787157d8 Added -dumpdef (dump defective TS packet) as a debug option 2015-09-15 12:40:45 +02:00
Anshul Maheshwari
7514886199 change from int to LLONG
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 15:15:37 +05:30
Anshul Maheshwari
ad5b917f3b Compile code in vs2013
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 15:04:59 +05:30
Anshul Maheshwari
66408fc950 moved buffered_read to inline function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-15 13:51:34 +05:30
cfsmp3
94ec02eea9 Merge branch 'pr/n226_anshul1912' 2015-09-14 13:08:31 +02:00
Anshul Maheshwari
5e33e2e2ac Avoid derefrence of NULL
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-12 21:13:07 +05:30
cfsmp3
34613037fc bugfix in webvtt 2015-09-08 17:17:38 +02:00
Anshul Maheshwari
f2b24f13af refactor Webvtt
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>

1) remove srt counter from webvtt
2) add include files so that compiler gives error at incorrect arguments in function call
3) WEBVTT Header do not use srt counter but declared as static const str wriiteen while writing any header
4) Removed srt counter from output file from webvtt refrence taken from http://dev.w3.org/html5/webvtt/
2015-09-08 16:10:37 +05:30
cfsmp3
c718d21d0f Changes to other files 2015-09-08 11:17:28 +02:00
cfsmp3
a2828f0060 -Merge branch 'pr/n216_anshul1912'
-Added WebVTT support (manual merge of the previous PR)
2015-09-07 11:29:07 +02:00
rkuchumov
4b3b846a2c updated changes.txt 2015-09-03 20:49:29 +03:00
Anshul Maheshwari
b232945c71 refactoring headers includes
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-02 12:32:22 +05:30
Anshul Maheshwari
f91d1cb9b7 remove errors due to incorrect merge
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-01 15:26:50 +05:30
Anshul Maheshwari
fadd8aad8b merge multiprogram changes to main
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-09-01 12:53:05 +05:30
cfsmp3
b0479b247a Merge branch 'pr/n219_kisselef' 2015-08-28 10:12:19 +02:00
cfsmp3
a659544bd2 Merge branch 'pr/n217_brooss' 2015-08-28 10:09:29 +02:00
Oleg Kisselef
9ce4c99180 cea-708 usage help updated 2015-08-28 09:58:50 +03:00
Oleg Kisselef
52f51147b8 cea-708 predefined window styles 2015-08-28 09:49:10 +03:00
Oleg Kisselef
34836b50a1 cea-708 structures renamed according to POSIX. enums names updated. 2015-08-27 22:04:13 +03:00
Oleg Kisselef
7179796365 fixed linux build scripts 2015-08-27 13:50:55 +03:00
Oleg Kisselef
966c90eece win-build: strndup function implementation added 2015-08-27 11:19:03 +03:00
Oleg Kisselef
3281bf929a win-build: iconv updated and executable code removed from header 2015-08-27 11:14:34 +03:00
Oleg Kisselef
906a0704bc -awin-build: networking.c endl 2015-08-27 11:08:17 +03:00
Oleg Kisselef
20785c095c -awin-build: fixed ioctl on windows 2015-08-27 11:07:54 +03:00
Oleg Kisselef
dee2280d06 cea-708 fixed txt,ttxt crlf output 2015-08-26 21:46:40 +03:00
Oleg Kisselef
f6b69b64c3 cea-708 norollup parameter passing. removed ccx_options dependency 2015-08-26 21:42:57 +03:00
Oleg Kisselef
2f09b37f7c cea-708 fixed default pen color 2015-08-26 21:29:32 +03:00
Oleg Kisselef
20cf0f5151 cea-708 detecting malformed services parameter 2015-08-26 19:55:05 +03:00
Oleg Kisselef
860e926b5a cea-708 fixed mem usage bugs 2015-08-26 17:53:12 +03:00
Oleg Kisselef
9f81a4b5c1 cea-708 charset support 2015-08-26 17:26:19 +03:00
Oleg Kisselef
5d85220121 cea-708 cleaning up writers 2015-08-26 16:16:36 +03:00
Oleg Kisselef
6423efa2d7 cea-708 multiprogram support done 2015-08-26 15:54:52 +03:00
Oleg Kisselef
932cb77265 encoding cea-708 2015-08-26 13:54:09 +03:00
Anshul Maheshwari
691244a00e initilaize min_pts to 0 in rcwt
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 17:52:07 +05:30
Anshul Maheshwari
440c59a5fd Adding space to rcwt_loop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 17:33:07 +05:30
Anshul Maheshwari
8a3e2b5efc remove derefrencing global variable
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 16:37:11 +05:30
Anshul Maheshwari
119a4361df remove if condition
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-08-25 12:35:17 +02:00
Anshul Maheshwari
6c93b6dcf4 initialized variables
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 15:56:07 +05:30
Oleg Kisselef
4d76cd30c0 cea-708 removed unnecessary data from dtvcc decoder 2015-08-25 12:41:30 +03:00
Anshul Maheshwari
96fd051e01 pass dec_ctx instead of its channel
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 14:12:30 +05:30
Anshul Maheshwari
2fe0da30be ignore xds if not selected in transcript
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-25 11:51:09 +05:30
Brooss
890e045a88 SDT: Remove code adding extra null to channel name string end. 2015-08-25 12:34:36 +10:00
Oleg Kisselef
b333df4317 cea-708 keeping symbols in 16-bit variables 2015-08-25 00:05:34 +03:00
Oleg Kisselef
33d91a979c fixed charset handling for cea-708 2015-08-24 23:59:43 +03:00
Anshul Maheshwari
b3614f592f dont derefrence global variables
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-24 20:36:24 +05:30
Anshul Maheshwari
3bdb5f3863 remove xds global init
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-24 20:21:58 +05:30
Anshul Maheshwari
ad6346f802 making xds_context and moving global vars
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-24 20:11:14 +05:30
Anshul Maheshwari
66f41438be moving global variable of sequence to ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-24 16:55:06 +05:30
Anshul Maheshwari
647a91eafa shifting global variable in context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-24 13:41:35 +05:30
Brooss
ecf200e290 Add support for parsing the Service Description Table in MPEGTS and using it to provide real channel names in EPG output. 2015-08-24 14:35:10 +10:00
Anshul Maheshwari
da576bff2b Pass timing in get_fts function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-22 17:45:09 +05:30
Anshul Maheshwari
fcbf113526 Merge remote-tracking branch 'upstream/master' 2015-08-22 14:46:06 +05:30
cfsmp3
b90d144ff6 Merge branch 'pr/n213_anshul1912' 2015-08-22 10:48:45 +02:00
cfsmp3
2ac0ed2032 Merge branch 'pr/n214_rkuchumov' 2015-08-22 10:47:49 +02:00
cfsmp3
0afefc0392 Merge branch 'pr/n215_brooss' 2015-08-22 10:46:29 +02:00
Oleg Kisselef
9efe2b4b22 cea-708 debug message on decoder creation added 2015-08-22 09:51:02 +03:00
Oleg Kisselef
d54d881390 cea-708 color-per-row support 2015-08-22 00:03:13 +03:00
Oleg Kisselef
58b496a434 log text updated 2015-08-21 23:14:31 +03:00
Oleg Kisselef
41a8803860 checking if current window is set 2015-08-21 23:13:35 +03:00
Oleg Kisselef
4146423878 cea-708 code flow almost same as for 608 captions 2015-08-21 23:07:10 +03:00
Oleg Kisselef
1c35dcae03 fixed creating of file if output=null 2015-08-22 10:30:25 +03:00
Oleg Kisselef
3bcdbce709 dependencies updated 2015-08-22 08:56:52 +03:00
Brooss
250ee1f29b Parse after buffer fill, not on next packet 2015-08-22 04:04:46 +10:00
Brooss
fd1a86b2f5 Add support for multi-packet PATs and PMTs in MPEGTS 2015-08-22 02:25:10 +10:00
Anshul Maheshwari
3433ed2e5c removed somestatic variable from avc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-21 15:22:30 +05:30
rkuchumov
c7606beae1 segfault when closing socket input fixed (forgot about this file) 2015-08-20 19:58:38 +03:00
rkuchumov
d639323e4c segfault when closing socket input fixed 2015-08-20 19:48:34 +03:00
rkuchumov
72e780f175 ccextractor-ccextractor connection fix 2015-08-20 17:16:47 +03:00
Anshul Maheshwari
651dc67a5d update linux related chages in ocr
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-20 18:24:37 +05:30
Oleg Kisselef
6cfd7710a7 Merge branch 'master' into feature-cea-708 2015-08-19 23:47:59 +03:00
Oleg Kisselef
adc1d4662d changes 2015-08-19 20:25:07 +03:00
Oleg Kisselef
5c51b582bf cea-708 yet another big refactoring. rollup captions added. 2015-08-19 19:16:19 +03:00
Oleg Kisselef
16e794163c cea-708 added show/hide time for screens and windows 2015-08-19 18:58:43 +03:00
Oleg Kisselef
4e25d80b48 checking if have 708 captions when updating fts_global 2015-08-19 18:57:37 +03:00
Oleg Kisselef
2949918ed1 some timing debug info added 2015-08-19 18:55:47 +03:00
Oleg Kisselef
46ea522ecb cea-708 output style fix 2015-08-19 08:19:13 +03:00
Oleg Kisselef
f571a04ffc cea-708 doc updated 2015-08-18 23:28:32 +03:00
Oleg Kisselef
610b811d53 cea-708 encoding->charset 2015-08-18 17:09:57 +03:00
Oleg Kisselef
e5c4053c05 cea-708 decoder ff and hcr handling 2015-08-18 14:28:34 +03:00
Anshul Maheshwari
0b9bf16850 updated ocr doc file
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-18 16:14:54 +05:30
Oleg Kisselef
8489edf966 cea-708 params help updated 2015-08-18 13:34:41 +03:00
Oleg Kisselef
22127cccb0 added extra space because unicode symbols can be 6-byte long. cleaning windows where needed. 2015-08-18 11:57:35 +03:00
Anshul Maheshwari
57eb42c7bb Compile code using Visual studio
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-18 12:19:33 +05:30
Oleg Kisselef
0a6630f7ab specifying an encoding for non-latin languages for CEA-708 captions 2015-08-18 09:26:01 +03:00
Oleg Kisselef
b89dd8d401 cea-708 Korean encoder anchor position issue workarounded 2015-08-17 21:40:32 +03:00
Oleg Kisselef
778e66f951 cea-708 sami output merged 2015-08-17 17:55:18 +03:00
Oleg Kisselef
7a06d99443 cea-708 transcript output merged 2015-08-17 17:25:40 +03:00
Oleg Kisselef
3fff94a555 cea-708 srt and debug output refactored and improved 2015-08-17 17:09:53 +03:00
Oleg Kisselef
b65cc8ad8e dont handling 16-bit chars for cea-708 2015-08-17 09:53:24 +03:00
rkuchumov
28ddfef2b1 sending header when reconnecting 2015-08-16 19:15:15 +03:00
rkuchumov
f23cc1f41e reconnecting when no ping arrived 2015-08-16 12:25:01 +03:00
rkuchumov
1ca63ba125 mandatory desc and passw blocks 2015-08-16 11:14:00 +03:00
Oleg Kisselef
af66ace345 cea-708 defined utf8 symbol max size in bytes 2015-08-14 23:33:06 +03:00
Oleg Kisselef
c0079aee6f cea-708 handling 16-bit characters (utf16) 2015-08-14 23:29:32 +03:00
Oleg Kisselef
21a88f9cc1 added utf16 to utf8 conversion function 2015-08-14 23:28:39 +03:00
Oleg Kisselef
9923ef98ee added "all" value for cea-708 services 2015-08-14 20:52:28 +03:00
Oleg Kisselef
abce1dd873 moved cea-708 global variables into single context variable 2015-08-14 13:28:59 +03:00
Oleg Kisselef
308d500308 more cea-708 refactoring 2015-08-14 09:49:22 +03:00
Oleg Kisselef
ae6cf97bce more cea-708 refactorings 2015-08-14 00:30:53 +03:00
rkuchumov
53bedd30c1 sending ping to server 2015-08-13 22:59:45 +03:00
Oleg Kisselef
764d251986 cea-708 code refactoring 2015-08-13 20:59:28 +03:00
Anshul Maheshwari
1bfb96151f support 3.04 tesseract
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-13 21:11:52 +05:30
rkuchumov
741e87e00e empty description support 2015-08-11 09:59:04 +03:00
rkuchumov
098bff1230 Merge branch 'master' into networking_epg_support 2015-08-10 10:09:55 +03:00
rkuchumov
0374c5ec78 small fix & closing connection when server doesnt responce 2015-08-10 10:07:29 +03:00
Anshul Maheshwari
e7bec67c93 remove static timestamps from teletext
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-08 17:23:45 +05:30
Anshul Maheshwari
b9e0f67dec Correcting redundant check
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-08 16:20:30 +05:30
Anshul Maheshwari
acd96d44d2 Initialize stream mode before using it
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-08 14:01:19 +05:30
Anshul Maheshwari
4e4da44c39 Add 0x for hex represntation
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-06 18:05:16 +05:30
Anshul Maheshwari
bb0f836e84 removing redundant code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-06 15:55:02 +05:30
Anshul Maheshwari
5f6a8c7f54 Using EOF instead global variable
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-06 15:48:42 +05:30
Anshul Maheshwari
0c6bf5d8b1 make some space
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-06 14:41:40 +05:30
Anshul Maheshwari
f8210f94f2 Passing only demuxer ctx to wtv getdata
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-06 14:33:22 +05:30
rkuchumov
243674ed96 adding ping support from the server 2015-08-06 11:58:19 +03:00
Anshul Maheshwari
322d352ca0 selecting multiprogram for ts stream in report mode
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-04 18:59:48 +05:30
Anshul Maheshwari
c8c71085e1 Adding return from set_fts
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-04 18:54:17 +05:30
Anshul Maheshwari
4969e6a8fd Initialize Teletext when data not present
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-04 15:10:20 +05:30
Anshul Maheshwari
ece4a5fa8a Memory Leakage in Teletext
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-08-04 13:59:01 +05:30
cfsmp3
7d034f44e4 Merge branch 'pr/n202_anshul1912' 2015-08-02 16:39:55 +02:00
cfsmp3
c12d3856f2 Merge branch 'pr/n201_december-soul'
Conflicts:
	src/ccextractor.c
	src/lib_ccx/ccx_encoders_common.c
	src/lib_ccx/lib_ccx.c
2015-08-02 16:38:43 +02:00
Anshul Maheshwari
24f9106cde Merge remote-tracking branch 'carlos/master' 2015-08-01 12:21:44 +05:30
Anshul Maheshwari
58503141c3 Ignore empty string Srt encoder
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-31 22:44:08 +05:30
Anshul Maheshwari
3b214f491b correcting sub delay for end time
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-31 22:23:14 +05:30
Anshul Maheshwari
f83ca18c7d Merge branch 'master' of https://github.com/anshul1912/ccextractor 2015-07-31 21:36:01 +05:30
Anshul Maheshwari
1261cee8dc incorrect update of stream
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-31 21:33:18 +05:30
Anshul Maheshwari
92ecaa9434 dont check program number in single stream mode
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-07-31 11:03:10 +02:00
Anshul Maheshwari
fd66228b26 Cleaning stream data when PAT changes
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-31 12:30:41 +05:30
Anshul Maheshwari
bfd7556b50 free memory for ignored stream
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-31 11:15:44 +05:30
Anshul Maheshwari
3174e3dc9e remove multi addition of data_node len
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-30 13:40:44 +05:30
Anshul Maheshwari
ec26080bd2 if last crc is equal to present crc dont update pmt
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-30 12:22:12 +05:30
Anshul Maheshwari
5ea83ccf9d corrected len and buf for crc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-30 11:37:16 +05:30
Anshul Maheshwari
5af65d941a need capinfo only true when any good crc already found
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 19:21:12 +05:30
Anshul Maheshwari
0d79ad3cb6 crc used while checking packet second time
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 19:18:42 +05:30
Anshul Maheshwari
8499a6b426 Init bufferdatatype
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 18:02:52 +05:30
Anshul Maheshwari
577a79de47 initialized gop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 15:18:21 +05:30
Anshul Maheshwari
6133b9c26d print fps message once
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 12:52:06 +05:30
Anshul Maheshwari
c4e91f8ccc Remove memory leakage
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-29 11:58:42 +05:30
cfsmp3
589fd91d8e Merge branch 'pr/n202_anshul1912' 2015-07-28 22:33:15 +02:00
Anshul Maheshwari
03eba6114b remove invalid access of memory
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-28 20:23:32 +05:30
Anshul Maheshwari
56f0786cc3 correct broken Freport
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-28 11:30:09 +05:30
cfsmp3
aff591fd9b Merge branch 'pr/n202_anshul1912' 2015-07-28 07:05:22 +02:00
Anshul Maheshwari
bdaa3a1352 Completed Freport for teletext and DVB
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 22:02:47 +05:30
Anshul Maheshwari
f3b104584d update multiprogram changes in doc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 16:04:28 +05:30
Anshul Maheshwari
e47315e423 not to unset remaining buffer
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 15:36:36 +05:30
Anshul Maheshwari
43335e30a9 move strange header to demux_ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 13:43:58 +05:30
Anshul Maheshwari
79c4a48d60 ES code in Context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 13:33:00 +05:30
Anshul Maheshwari
a5538902ec moving telxcc related globals to telxcc Ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 11:51:20 +05:30
Anshul Maheshwari
1b9d905b28 move global vars from es to decode ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 10:43:45 +05:30
Anshul Maheshwari
89c8b018c8 move parity code to ccx_common_common.c
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 10:42:16 +05:30
Anshul Maheshwari
cde69fdd88 remove segfault in epg
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-27 10:05:00 +05:30
rkuchumov
a798fdf57e merge conflicts 2015-07-26 13:09:55 +03:00
Anshul Maheshwari
8b89ad0c5a refactor enc demux cfg
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-25 16:52:13 +05:30
Anshul Maheshwari
309f4130e0 Clean ts code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-25 16:29:55 +05:30
Anshul Maheshwari
0f2ccdbe4f added newline in warning
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-25 16:17:22 +05:30
Anshul Maheshwari
eeb33de590 Verified checksum and save section in pinfo
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-25 16:15:13 +05:30
rkuchumov
91a8997826 Merge branch 'networking_epg_support' of https://github.com/rkuchumov/ccextractor into networking_epg_support 2015-07-24 22:48:04 +03:00
rkuchumov
5fb7bc434c changed net protocol (passw check) 2015-07-24 22:24:51 +03:00
rkuchumov
77540355ed epg lang and category fields support 2015-07-24 22:24:51 +03:00
rkuchumov
c5362b682e indentation fix 2015-07-24 22:24:51 +03:00
rkuchumov
e0f3751fe8 sending epg 2015-07-24 22:23:51 +03:00
rkuchumov
54583f95a3 wrapping bin data with headers 2015-07-24 22:23:51 +03:00
rkuchumov
990e653e91 Merge branch 'networking_epg_support' of https://github.com/rkuchumov/ccextractor into networking_epg_support 2015-07-24 18:44:49 +03:00
rkuchumov
9d2fb48d3d changed net protocol (passw check) 2015-07-24 18:39:42 +03:00
rkuchumov
e5e51c4389 epg lang and category fields support 2015-07-24 18:39:42 +03:00
rkuchumov
74dbd4d7e5 indentation fix 2015-07-24 18:39:42 +03:00
rkuchumov
784a46d165 sending epg 2015-07-24 18:37:12 +03:00
rkuchumov
83e1959db8 wrapping bin data with headers 2015-07-24 18:37:12 +03:00
cfsmp3
e0bf79f28b Merge branch 'pr/n200_anshul1912' 2015-07-24 16:28:50 +02:00
cfsmp3
5c1f4772c7 typo fix 2015-07-24 16:28:37 +02:00
Anshul Maheshwari
deca14c2c2 refresh dvb codec
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-24 16:38:04 +05:30
Anshul Maheshwari
8023ebe8e2 revert current pts flag
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-24 15:54:25 +05:30
Anshul Maheshwari
0e98604267 made telexcc working in bin format
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-24 12:49:42 +05:30
Anshul Maheshwari
7e68c8e823 cross check for cinfo
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-24 11:15:59 +05:30
Anshul Maheshwari
601dbfd062 use encoder with pn
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 21:43:30 +05:30
Anshul Maheshwari
35983534f1 remove seg fault
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 20:06:58 +05:30
Anshul Maheshwari
f88330c7c9 close telexcc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 20:01:29 +05:30
Anshul Maheshwari
a0bf7dadf8 move init_hdcc to dec_ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 19:48:48 +05:30
Anshul Maheshwari
f2added8d1 revert hdcc flush
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 19:45:30 +05:30
Anshul Maheshwari
9f78a843ee Add global hdcc flag to decode context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 18:47:04 +05:30
Anshul Maheshwari
3e78fdd675 wait till stream stream type is know
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 18:21:35 +05:30
Anshul Maheshwari
c5dfd52eb9 Initialize cinfo with codec
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 17:45:26 +05:30
Anshul Maheshwari
08df39c3d4 initialize max_gop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 17:08:19 +05:30
Anshul Maheshwari
9fad88fee3 cleaning ts tables
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 17:04:58 +05:30
rkuchumov
6ae94fdbab changed net protocol (passw check) 2015-07-23 13:59:18 +03:00
rkuchumov
8d5f0e5505 epg lang and category fields support 2015-07-23 12:55:37 +03:00
Anshul Maheshwari
11b614cedf Initialize codec in dec update
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 12:43:13 +05:30
Anshul Maheshwari
fc79649c9c initialize file buffer in stdin
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 12:35:21 +05:30
Anshul Maheshwari
b85e93a2cb opening raw type condition
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-23 12:21:34 +05:30
Anshul Maheshwari
dd8923b2e4 error checking in init decoder 2015-07-23 12:13:31 +05:30
Anshul Maheshwari
1437aea328 multiple decode context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-22 15:33:09 +05:30
Anshul Maheshwari
1fdad2314f remove segfault at free of filename
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-21 18:07:24 +05:30
Anshul Maheshwari
6aac9dad43 not working multiprogram
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-21 13:13:25 +05:30
Anshul Maheshwari
fc248dd41f not to use data_node before recieved
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-14 21:22:11 +05:30
Anshul Maheshwari
a2394df838 remove derefrence NULL pointer
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-14 21:07:20 +05:30
Anshul Maheshwari
306d60ccf9 encoder ctx initilaziation only when required
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-14 21:01:08 +05:30
Anshul Maheshwari
d78a722260 moved encoder related code in each loop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-14 15:39:35 +05:30
Anshul Maheshwari
4a34799e09 Adding flush logic in function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-14 15:22:07 +05:30
Anshul Maheshwari
489622fb0b Merge branch 'master' of https://github.com/anshul1912/ccextractor 2015-07-14 12:02:41 +05:30
Anshul Maheshwari
9689dd8c19 remove VS Compiler error from list.h
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 09:31:35 -07:00
Anshul Maheshwari
d29f6817c6 error checking in encoder
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 18:49:06 +05:30
Anshul Maheshwari
f9ea7009fe removed segfault from 708
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 18:46:33 +05:30
Anshul Maheshwari
ddd8381440 Correcting out context selection on basis of field
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 18:08:15 +05:30
Anshul Maheshwari
964b8c1165 refactored encoder
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 03:32:26 +05:30
Anshul Maheshwari
0541a2fb62 move output context in encoder from global context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-13 00:16:26 +05:30
Anshul Maheshwari
f3654174fc moving file_function to demux ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 23:33:52 +05:30
rkuchumov
0fc1055da6 indentation fix 2015-07-10 17:26:26 +03:00
rkuchumov
a654b133e5 sending epg 2015-07-10 17:21:46 +03:00
Anshul Maheshwari
3a886c6a5b proper initialization of cc_data
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 19:42:48 +05:30
Anshul Maheshwari
4a8d51aed1 including avc header
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 19:24:37 +05:30
Anshul Maheshwari
70f5723c89 making context of avc
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 19:22:51 +05:30
rkuchumov
b85702a706 wrapping bin data with headers 2015-07-10 15:45:06 +03:00
Anshul Maheshwari
0bf1e83fa1 free pat payload
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 17:51:36 +05:30
Anshul Maheshwari
67d62631aa remove ignore param from demux_data
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 17:24:03 +05:30
Anshul Maheshwari
43f276abca correctcondition to ignore stream
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 17:13:23 +05:30
Anshul Maheshwari
7cea808f46 ignore unused stream in cap info
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 17:10:29 +05:30
Anshul Maheshwari
adbe8ed934 eof handle in rawloop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 15:59:22 +05:30
Anshul Maheshwari
a3eba7cf45 error checking in copy capbuf
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 13:13:29 +05:30
Anshul Maheshwari
3f26290614 Check pid before needs
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 12:14:30 +05:30
Anshul Maheshwari
d63660468a init datastream with sane value
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 02:34:05 +05:30
Anshul Maheshwari
3daecf66a3 replced stream info array from list
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-10 02:06:49 +05:30
Anshul Maheshwari
16db90a630 Free mem allocated for input file name
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 23:41:35 +05:30
Anshul Maheshwari
c1d7f82819 handling wrong pes header
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 22:07:08 +05:30
Anshul Maheshwari
f8ee9504a8 handling wrong pes header
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 21:26:58 +05:30
Anshul Maheshwari
c75d056b76 Handling boundary condition
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 13:16:23 +05:30
Anshul Maheshwari
6c38f1b73b rename windex to len
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 12:59:07 +05:30
Anshul Maheshwari
00b61a291d Initialize demux node in general loop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 12:36:06 +05:30
Anshul Maheshwari
fcdc5f852b Passing demux ctx instead of lib ctx
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-09 12:08:38 +05:30
Anshul Maheshwari
0424b0f119 remove memory leakage in teletext 2015-07-08 23:10:39 +05:30
Anshul Maheshwari
82559fd572 Initialize demuxer data
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-08 22:40:20 +05:30
Anshul Maheshwari
3837ffae59 Correct asf and wtv
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-08 22:25:53 +05:30
Anshul Maheshwari
2e4cda0383 working telxcc code with srt
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-08 22:02:33 +05:30
Anshul Maheshwari
dc6ef18c21 Free tree of streams and program 2015-07-08 16:51:58 +05:30
Anshul Maheshwari
bf3790183a woorking telxcc code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-08 16:41:52 +05:30
Anshul Maheshwari
bfa8b593ab teletext to srt working
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-08 11:20:49 +05:30
Anshul Maheshwari
401d679f80 reversed priority 2015-07-07 19:27:43 +05:30
Anshul Maheshwari
157faaf0b5 Add multistream support in databuffer 2015-07-07 19:11:45 +05:30
Anshul Maheshwari
cb49812d17 broken teletext
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-07 12:10:05 +05:30
Anshul Maheshwari
d88fa2a3ce remove context dependency from write_section 2015-07-06 22:13:17 +05:30
Anshul Maheshwari
5716ab7cfc Add back haupage support in ts 2015-07-06 21:14:25 +05:30
Anshul Maheshwari
04b9e40cc5 Add reset hack back again 2015-07-06 21:08:47 +05:30
Anshul Maheshwari
2f92036557 Initialize databuffertype 2015-07-06 18:24:41 +05:30
Anshul Maheshwari
6aaa4fe2d4 Add windex instead len 2015-07-06 17:01:15 +05:30
Anshul Maheshwari
ab0f54bb57 correct handling for eof
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-06 15:43:44 +05:30
Anshul Maheshwari
6642084132 Open up more buffer type 2015-07-06 02:12:50 +05:30
Anshul Maheshwari
c5ca7c7e1a working with srt output and single program input
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-06 01:48:08 +05:30
Anshul Maheshwari
5b24334b43 move pmt code related comments near parsePMT
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-03 14:59:44 +05:30
Anshul Maheshwari
df93801021 Initilaize param
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-03 12:43:25 +05:30
Anshul Maheshwari
64285879db encoding flushed bytes 2015-07-03 11:51:03 +05:30
Anshul Maheshwari
0523f0bcd5 check array boundary before acess
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-02 18:49:14 +05:30
Anshul Maheshwari
c6721ebc3e making array of cap pid
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-02 16:40:44 +05:30
Anshul Maheshwari
9d22f9a466 Adding error Message at boundary
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-02 16:39:41 +05:30
Anshul Maheshwari
d58fb00970 Correcting boundary condtions
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-02 14:43:56 +05:30
Anshul Maheshwari
62e189a9cb correctin loss of last frame 2015-07-01 17:06:55 +05:30
Anshul Maheshwari
dc17946a55 Remove infinite loops
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-07-01 11:21:50 +05:30
Anshul Maheshwari
78d8d858d2 Adding header file
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-30 21:56:36 +05:30
Anshul Maheshwari
30e7f95f38 move pmt from global to demuxer ctx 2015-06-30 21:32:46 +05:30
Anshul Maheshwari
8026d2e671 Remove unused loop
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-30 20:34:01 +05:30
Anshul Maheshwari
c98e00201a remove seg fault while overwrite detection
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-30 19:09:49 +05:30
Anshul Maheshwari
9b0ba130f1 Corrected broken position_sanity_check 2015-06-30 19:00:33 +05:30
Anshul Maheshwari
83aa9709f4 moving subline bufffer to encoder context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-30 11:39:32 +05:30
Anshul Maheshwari
340549e916 coreected broken detect stream 2015-06-29 21:34:15 +05:30
Anshul Maheshwari
6d41964bba Addin decoded subtitle in decoder context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-29 21:31:37 +05:30
Anshul Maheshwari
71f030f4ee move parameter checking to parameter ctx 2015-06-29 12:10:50 +05:30
Anshul Maheshwari
67653d06d3 Restore default when no -o param provided 2015-06-29 11:38:36 +05:30
Anshul Maheshwari
ab9f3a4b4a give memory for '\0' character in output file 2015-06-29 11:37:19 +05:30
Anshul Maheshwari
d9e9305e2c Seprate wbout context 2015-06-28 15:41:34 +05:30
Anshul Maheshwari
2bcc0c5561 corrected elementry to elementary 2015-06-27 15:21:00 +05:30
Anshul Maheshwari
cd03d8a658 moved filename part in lib_ccx 2015-06-27 15:18:42 +05:30
Anshul Maheshwari
589074886b removing multiple file in encoder ctx 2015-06-27 14:55:02 +05:30
Anshul Maheshwari
c6ca493752 Removed redundant wbout struct 2015-06-27 14:34:40 +05:30
Anshul Maheshwari
aef649d23a Initialize past value in open 2015-06-26 21:05:06 +05:30
Anshul Maheshwari
610b7323f4 time depend on demuxer init 2015-06-26 20:26:09 +05:30
Anshul Maheshwari
eb6f6a9000 Added Demuxer data to seprate out context 2015-06-26 20:18:49 +05:30
Anshul Maheshwari
f3fe829d48 remove false warning about premature file completion 2015-06-25 20:06:54 +05:30
Anshul Maheshwari
cb39d12615 Making demuxer context
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-25 19:09:54 +05:30
Anshul Maheshwari
5d52026736 remove wbout dependency 2015-06-23 22:21:07 +05:30
Anshul Maheshwari
48dce9c7ce correct header guard 2015-06-22 17:12:41 +05:30
Anshul Maheshwari
2032a754e6 moved credits initializations 2015-06-22 14:30:38 +05:30
Anshul Maheshwari
aa353140ef remove wbout dependency from decoder 2015-06-21 23:55:19 +05:30
Anshul Maheshwari
ee47e8458f Use cc_sub in raw dvd 2015-06-21 23:49:08 +05:30
Anshul Maheshwari
081f127c85 remove compiler warnings
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-20 21:26:01 +05:30
cfsmp3
7169c71360 Merge branch 'pr/n187_anshul1912' 2015-06-20 13:54:47 +02:00
cfsmp3
5c3a757e5b Updated CHANGES.TXT with release date 2015-06-20 13:54:21 +02:00
Anshul Maheshwari
673cadc6bf Version 0.77 2015-06-20 17:00:19 +05:30
cfsmp3
2318e714db Merge branch 'pr/n186_anshul1912' 2015-06-20 11:06:41 +02:00
Anshul Maheshwari
a6d27a2de5 compile on windows
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-19 23:31:37 -07:00
Anshul Maheshwari
dc842b0312 removed segfault with cap file 2015-06-19 22:59:22 +05:30
cfsmp3
3879f5c7ef Merge branch 'pr/n156_kisselef'
Conflicts:
	src/lib_ccx/CMakeLists.txt

Changed 0.76 to 0.77
2015-06-19 13:14:55 +02:00
Anshul Maheshwari
e01d93afa8 Corrected typos in help info
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-18 17:24:47 +05:30
Anshul Maheshwari
6ec8086b0a remove invalid warn at srt 2015-06-18 11:39:20 +05:30
Anshul Maheshwari
b80572c3b6 Corrected help display for BOM 2015-06-17 19:38:53 +05:30
Anshul Maheshwari
3f6fd51f45 removed segfault at ccextractor.c 2015-06-17 19:09:52 +05:30
Anshul Maheshwari
87af82f022 corrected broken raw output 2015-06-17 18:42:08 +05:30
Anshul Maheshwari
020ca9a1cf Merge remote-tracking branch 'carlos/master' 2015-06-17 16:26:00 +05:30
Anshul Maheshwari
beccc3d5b7 Correct broken rcwt
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-17 16:23:33 +05:30
Anshul Maheshwari
1d03bd7d13 pass cc_sub structure to rcwt 2015-06-17 11:59:04 +05:30
cfsmp3
13290294a6 Merge branch 'pr/n182_anshul1912' 2015-06-16 20:10:26 +02:00
Anshul Maheshwari
1eef500c73 Indent decoder 2015-06-16 23:34:22 +05:30
Anshul Maheshwari
ca5135c8aa passing decoder sub structure in teletext 2015-06-16 20:15:47 +05:30
Anshul Maheshwari
740a1d798e add space in code 2015-06-13 19:22:24 +05:30
Anshul Maheshwari
b68a086698 remove dead code 2015-06-13 19:09:31 +05:30
Anshul Maheshwari
0e60ceb4d0 moving option check in param context 2015-06-13 19:08:40 +05:30
Anshul Maheshwari
2030c16b22 Display usage when no input file 2015-06-13 10:58:17 +02:00
cfsmp3
79b1bca8f7 Merge branch 'pr/n179_anshul1912' 2015-06-12 08:02:56 +02:00
cfsmp3
76b3d3e4d1 Merge branch 'pr/n180_rkuchumov' 2015-06-12 08:02:09 +02:00
rkuchumov
90d8731a03 dep target is fixed 2015-06-10 21:50:01 +03:00
rkuchumov
85270c7047 optimization is removed for ccextractor.c 2015-06-10 21:39:53 +03:00
rkuchumov
c9e596e60a flushing cc buffer every I, P slice for both fields 2015-06-10 08:25:20 +03:00
Anshul Maheshwari
24d83e130a Remove Segmentation Fault at opt service
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-06-05 12:11:05 +05:30
cfsmp3
4fc19d4289 Merge branch 'pr/n175_wforums' 2015-06-04 22:09:40 +02:00
wforums
74ad11b44f Release project build fix
Fixed release project for VS. New subfolders weren't included.
2015-06-04 00:34:08 +02:00
wforums
051a6f1f67 git ignore update
Updated gitignore with some more VS project files.
2015-06-04 00:31:29 +02:00
Oleg Kisselef
3f7eb981e6 Fixed millis_to_date usage with ocr enabled build 2015-06-04 03:02:39 +06:00
Carlos Fernandez
8ca152262e Merge branch 'pr/n171_kisselef' 2015-05-28 06:53:39 -07:00
Anshul Maheshwari
f17501f0e5 linux build using Cmake 2015-05-28 12:05:10 +05:30
Oleg Kisselef
6cc8d7de05 ts/ps detection fall through removed 2015-05-27 17:10:01 +06:00
Carlos Fernandez
d4f6db8479 Merge branch 'pr/n168_codeman38' 2015-05-26 18:35:39 -07:00
Anshul Maheshwari
7b22a8d966 Segmentation Fault supression 2015-05-26 11:42:18 +05:30
Anshul Maheshwari
c5cebeaa4f Adding some space 2015-05-25 18:49:00 +05:30
Anshul Maheshwari
f1cf6c7be8 Added check on boundary condition 2015-05-25 18:48:20 +05:30
Cody Boisclair
80303ddde5 Add iconv to EXTRA_LIBS in CMakeLists.
Compilation via cmake fails on OS X if libiconv is not
specified as a required library.
2015-05-24 00:40:16 -04:00
Anshul Maheshwari
89ee62ea14 EPG help at new line 2015-05-22 17:35:46 +05:30
Anshul Maheshwari
a1959d20f3 remove make clean hangsup problem 2015-05-19 19:56:33 +05:30
Anshul Maheshwari
810cb73203 Indenting code 2015-05-19 15:50:01 +05:30
Anshul Maheshwari
38b9ed7fcd Indenting code 2015-05-19 15:28:14 +05:30
Anshul Maheshwari
35b8f2375f Indenting Code 2015-05-19 14:17:09 +05:30
Anshul Maheshwari
aa619b5f93 Indenting Code 2015-05-19 14:11:10 +05:30
Anshul Maheshwari
c03d3032aa Merge remote-tracking branch 'carlos/master' 2015-05-19 12:41:18 +05:30
Anshul Maheshwari
191cdd2bdc Indentation of 708 decoder 2015-05-19 12:40:15 +05:30
Anshul Maheshwari
9d5c8759e5 Indenting code 2015-05-19 12:28:20 +05:30
Anshul Maheshwari
a4b5c6e028 Indent code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 12:24:22 +05:30
Anshul Maheshwari
113b606091 Indentation of cc_bitstream 2015-05-19 12:11:18 +05:30
Anshul Maheshwari
a69e031835 Indentation of avc_function
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 12:07:51 +05:30
Anshul Maheshwari
ba38055bed lib_ccx/asf_functions.c
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 11:59:27 +05:30
Anshul Maheshwari
3c086e8ff0 Indent asf constants
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 11:54:29 +05:30
Anshul Maheshwari
f9c26d8684 Indent activity.c 2015-05-19 11:37:41 +05:30
Anshul Maheshwari
2ed9789f9c Indenting 708_encoding 2015-05-19 11:14:57 +05:30
Anshul Maheshwari
282108942b Correcting Header guard for spupng
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 11:12:41 +05:30
Anshul Maheshwari
6c107a0d4e Indent spupng code 2015-05-19 11:08:45 +05:30
Anshul Maheshwari
6e4ab6faae Fails earlier if not enough memory
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 10:57:01 +05:30
Anshul Maheshwari
e8016edfc1 Move copyright notice to top
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 10:52:48 +05:30
Anshul Maheshwari
30839f7c2c Indent smptett code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 10:50:27 +05:30
Anshul Maheshwari
89459a6c2e Indenting sami code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 10:45:04 +05:30
Anshul Maheshwari
c49db8c083 Removing runtime warnings 2015-05-19 10:40:40 +05:30
Anshul Maheshwari
fa6588fa80 Remove redundant print code
Signed-off-by: Anshul Maheshwari <er.anshul.maheshwari@gmail.com>
2015-05-19 10:38:05 +05:30
Carlos Fernandez
7d74256664 Merge branch 'pr/n166_anshul1912' 2015-05-18 09:28:39 -07:00
Anshul Maheshwari
2210660ae4 Indentation no change in logic 2015-05-18 19:46:57 +05:30
Anshul Maheshwari
f2fc93b7f8 removed dead code 2015-05-18 19:36:22 +05:30
Anshul Maheshwari
d54a2d9486 Indentation of utility.c 2015-05-18 19:10:48 +05:30
Anshul Maheshwari
88015d6d4b Adding milliseprator in tlt_config init 2015-05-18 12:22:35 +05:30
Anshul Maheshwari
f1ff75b846 Remove ccxoptions fromm encoder 2015-05-16 15:04:22 +05:30
Anshul Maheshwari
1123755dc7 Remove options from decoder 2015-05-16 13:16:25 +05:30
Carlos Fernandez
6a4f379ab7 Merge branch 'pr/n165_wforums' 2015-05-15 08:21:39 -07:00
Anshul Maheshwari
9369cde9a3 partially removing global options from utility 2015-05-15 19:56:01 +05:30
Anshul Maheshwari
a1d985b4ca Remove use of global options in sami 2015-05-15 18:07:31 +05:30
Anshul Maheshwari
b26854d3d7 Removing ccx_options from output ctx 2015-05-15 17:57:10 +05:30
Anshul Maheshwari
cbb4b4c7bb remove use of global var in telexcc 2015-05-15 13:37:15 +05:30
wforums
1a1aa746d5 Possible MP4 detection fix
Expanded detection for mp4. Needs to be checked with test suite and then
discussed :)
2015-05-14 23:52:23 +02:00
Anshul Maheshwari
b4f5b5b98e Removing global options from Mp4 2015-05-15 00:31:18 +05:30
Anshul Maheshwari
fa3b651ee1 Remove use glb bar ccx_options in param ctx 2015-05-14 23:54:26 +05:30
Carlos Fernandez
91d079be1e Merge branch 'pr/n164_anshul1912' 2015-05-14 19:54:17 +02:00
Anshul Maheshwari
d16ea0a7ea Decleare Xds related func in Xds header 2015-05-14 23:14:55 +05:30
wforums
6133bf6297 Revert of changes in stream format detection
Regression testing points out that at least 12 files no longer produce
correct results due to this change. Reverting is necessary until a
better solution for #69 can be found that does not break current other
files.
2015-05-13 18:44:58 +02:00
Oleg Kisselef
14e1420b7e Merge branch 'master' into feature-with-ocr-cmake-parameter 2015-05-05 13:30:16 +06:00
Oleg Kisselef
10568a0270 Merge branch 'master' into feature-mp4-c708-support 2015-05-05 12:56:23 +06:00
cfsmp3
53da058fe1 Merge branch 'pr/n155_kisselef' 2015-05-04 13:40:49 +02:00
cfsmp3
4d199fb03b Merge branch 'pr/n159_kisselef' 2015-05-04 13:39:47 +02:00
cfsmp3
f04cbbd99c Experiments with 708 in MP4. 2015-05-04 13:39:06 +02:00
Oleg Kisselef
e572ba8b6e better naming 2015-04-26 21:47:02 +06:00
Oleg Kisselef
45974e88be debug constant typo fix 2015-04-26 21:40:36 +06:00
Oleg Kisselef
8140bf3e52 mp4 708: fixed *cc_count value obtaining 2015-04-24 18:27:28 +06:00
Oleg Kisselef
4570965af2 removed ide auto-added header include 2015-04-24 15:51:07 +06:00
Oleg Kisselef
fcd250a557 basic c708 support for mp4 2015-04-24 15:43:59 +06:00
Oleg Kisselef
b92e42e685 yet another gpac fix applied 2015-04-24 15:42:08 +06:00
Oleg Kisselef
5daccf4268 gpac size calculation fix merged from gpac repo 2015-04-24 15:40:15 +06:00
Oleg Kisselef
e0903a0789 cdp sections enum added 2015-04-24 15:39:20 +06:00
Oleg Kisselef
bcf1546fc2 added c708 media subtype 2015-04-24 15:38:15 +06:00
Oleg Kisselef
92f53be666 fixed cmake to add gpac platform dependent defines 2015-04-23 17:30:22 +06:00
Oleg Kisselef
8ae0bd7f16 cmake build doc updated 2015-04-17 22:50:57 +06:00
Oleg Kisselef
754159e2bc cmakelists codestyle 2015-04-17 22:35:29 +06:00
Oleg Kisselef
3f817d655c added WITH_OCR parameter to cmake and libs dependencies 2015-04-17 22:16:42 +06:00
Oleg Kisselef
572837d7ba if ENABLE_OCR replaced everywhere with ifdef to have one style 2015-04-17 22:15:56 +06:00
Oleg Kisselef
fb8dcf4025 handling 7-byte PES packets for dvb-subs stream 2015-04-17 22:10:42 +06:00
cfsmp3
c7b77b5555 Fix crash on broken PMT section
Moved order of file format (MP4 now higher priority than PS)
2015-04-12 23:30:26 +02:00
cfsmp3
fe1ac8564a Merge branch 'pr/n148_kisselef' 2015-04-08 11:20:07 +02:00
cfsmp3
9230390937 Merge branch 'pr/n149_kisselef' 2015-04-08 11:17:20 +02:00
cfsmp3
14f926124d Merge branch 'pr/n150_anshul1912' 2015-04-08 11:15:31 +02:00
cfsmp3
76e8489304 XDS: Support for Canadian French content advisory
XDS: Support for the (obsolete) aspect ratio packet type
2015-04-08 11:14:50 +02:00
Anshul Maheshwari
0e0b1973f0 removing redundant init_options 2015-04-08 01:12:27 +05:30
Oleg Kisselef
a6666a4fbd detecting when output filename is same as one of input filenames to avoid overwrite 2015-04-07 12:02:52 +06:00
Oleg Kisselef
3a66db200d typo in mp4 detection algorithm fixed: 'feee'->'free'
added 'wide' box to mp4 detection algorithm
2015-04-06 22:22:00 +06:00
113 changed files with 22811 additions and 15490 deletions

5
.gitignore vendored
View File

@@ -9,10 +9,13 @@ CVS
*.o
linux/ccextractor
linux/depend
windows/debug/*
windows/debug/**
windows/release/**
####
# Visual Studio project Ignored files
*.suo
*.sdf
*.opensdf
*.user

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.75
V = 0.77
DISTFILES = ccextractor.${V:S/.//}-src.zip
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
DISTNAME = ccextractor-$V

View File

@@ -28,4 +28,17 @@ To do:
CCExtractor fully support Asian languages. I do need samples
though. No samples, no support.
- A few commands are not yet supported, specifically those related
to delay.
to delay.
- Detect and extract captions from MP4 (MOV) files, handled by gpacmp4
Done (18.08.2015):
- Major refactoring
- Librarized as much as possible (global vars moved to dtvcc context)
- Added some control commands support
- 16 bit charset support added (not "moved everything to 16-bit", but they could be successfully exported)
- SAMI output added
- Transcript output added
- Timed transcript output added
- Added colour support (only one colour/style can be applied for the whole screen at the moment)
- Roll up captions handling

View File

@@ -1,3 +1,25 @@
0.78 (2015-12-12)
-----------------
- Support to extract Closed Caption from MultiProgram at once.
- CEA-708: exporting to SAMI (.smi), Transcript (.txt), Timed Transcript (ttxt) and SubRip (.srt).
- CEA-708: 16 bit charset support (tested on Korean).
- CEA-708: Roll Up captions handling.
- Changed TCP connection protocol (BIN data is now wrapped in packets, added EPG support and keep-alive packets).
- TCP connection password prompt is removed. To set connection password use -tcppassword argument instead.
- Support ISDB Closed Caption.
- Added a new output format, simplexml (used internally by a CCExtractor user, may or may not be useful for
anyone else).
0.77 (2015-06-20)
-----------------
- Fixed bug in capitalization code ('I' was not being capitalized).
- GUI should now run in Windows 8 (using the include .Net runtime, since
3.5 cannot be installed in Windows 8 apparently).
- Fixed Mac build script, binary is now compiled with support for
files over 2 GB.
- Fixed bug in PMT code, damaged PMT sections could make CCExtractor
crash.
0.76 (2015-03-28)
-----------------
- Added basic M2TS support

View File

@@ -43,9 +43,10 @@ sudo make install
sudo ldconfig
Note:
1) CCExtractor is tested with Tesseract 3.02.02 version.
1) CCExtractor is tested with Tesseract 3.04 version but it works with older versions.
you can download tesseract from https://drive.google.com/folderview?id=0B7l10Bj_LprhQnpSRkpGMGV2eE0&usp=sharing
you can download tesseract from https://github.com/tesseract-ocr/tesseract/archive/3.04.00.tar.gz
you can download tesseract training data from https://github.com/tesseract-ocr/tessdata/archive/3.04.00.tar.gz
@@ -57,11 +58,8 @@ make ENABLE_OCR=yes
How to compile ccextractor on Windows with OCR
===============================================
Download prebuild library of leptonica from following link
http://www.leptonica.com/source/leptonica-1.68-win32-lib-include-dirs.zip
Download prebuild library of tesseract from following tesseract official link
https://code.google.com/p/tesseract-ocr/downloads/detail?name=tesseract-3.02.02-win32-lib-include-dirs.zip
Download prebuild library of leptonica and tesseract from following link
https://drive.google.com/file/d/0B2ou7ZfB-2nZOTRtc3hJMHBtUFk/view?usp=sharing
put the path of libs/include of leptonica and tesseract in library paths.
step 1) In visual studio 2013 right click <Project> and select property.
@@ -85,12 +83,12 @@ Step 2)Select Configuration properties
Step 3)Select Linker in left panel(column)
Step 4)Select Input
Step 5)Select Additional dependencies in right panel
Step 6)Add libtesseract302.lib in new line
Step 7)Add liblept168.lib in new line
Step 6)Add libtesseract304d.lib in new line
Step 7)Add liblept172.lib in new line
Download language data from following link
https://code.google.com/p/tesseract-ocr/downloads/list
after downloading the tesseract-ocr-3.02.eng.tar.gz extract the tar file and put
tessdata folder where you have kept ccextractor executable
Copy the tesseract and leptonica dll in the folder of executable or in system32.
Copy the tesseract and leptonica dll from lib folder downloaded from above link to folder of executable or in system32.

View File

@@ -1,4 +1,4 @@
ccextractor, 0.75
ccextractor, 0.78
-----------------
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
Maintainer: cfsmp3
@@ -18,6 +18,15 @@ Google Summer of Code 2014 students
- Ruslan KuchumoV
- Anshul Maheshwari
Google Summer of Code 2015 students
- Willem van iseghem
- Ruslan Kuchumov
- Anshul Maheshwari
- Nurendra Choudhary
- Oleg Kiselev
- Vasanth Kalingeri
License
-------
GPL 2.0.

View File

@@ -24,5 +24,8 @@ Step 5) Use CCextractor as you would like
If you want to build CCExtractor with FFMpeg you need to pass
cmake -DWITH_FFMPEG=ON ../src/
If you want to build CCExtractor with OCR you need to pass
cmake -DWITH_OCR=ON ../src/
Hint for looking all the things you want to set from outside
cmake -LAH ../src/

View File

@@ -42,7 +42,7 @@ INSTLALL_PROGRAM = $(INSTLALL)
DESTDIR = /usr/bin
ifeq ($(ENABLE_OCR),yes)
CFLAGS+=-DENABLE_OCR
CFLAGS+=-DENABLE_OCR -DPNG_NO_CONFIG_H
TESS_LDFLAGS+= $(shell pkg-config --libs tesseract)
LEPT_LDFLAGS+= $(shell pkg-config --libs lept)
@@ -93,12 +93,15 @@ $(OBJS_DIR)/%.o: %.c
$(OBJS_DIR)/%.o: %.cpp
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@ -I../src/gpacmp4
$(OBJS_DIR)/ccextractor.o: ccextractor.c
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) -O0 $< -o $@
.PHONY: clean
clean:
rm $(TARGET) 2>/dev/null || true
rm $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
rm -rd $(OBJS_DIR) 2>/dev/null || true
rm .depend 2>/dev/null || true
rm -rf $(TARGET) 2>/dev/null || true
rm -rf $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
rm -rdf $(OBJS_DIR) 2>/dev/null || true
rm -rf .depend 2>/dev/null || true
.PHONY: install
install: $(TARGET)
@@ -110,7 +113,7 @@ uninstall:
.PHONY: depend dep
depend dep:
$(CC) $(CFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CXX) \
$(CC) $(CFLAGS) $(INCLUDE) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CCX) \
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend

View File

@@ -1,2 +1,11 @@
#!/bin/bash
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
BLD_FLAGS="-std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64"
BLD_INCLUDE="-I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/"
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')"
SRC_GPAC="$(find ../src/gpacmp4/ -name '*.c')"
BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG"
BLD_LINKER="-lm -zmuldefs"
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER

View File

@@ -1,2 +1,11 @@
#!/bin/bash
gcc -g -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
BLD_FLAGS="-g -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64"
BLD_INCLUDE="-I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/"
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')"
SRC_GPAC="$(find ../src/gpacmp4/ -name '*.c')"
BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG"
BLD_LINKER="-lm -zmuldefs"
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER

View File

@@ -1 +1,2 @@
gcc -std=gnu99 -Wno-write-strings -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I ../src/gpacmp4 -I ../src/lib_ccx -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp' \! -name 'win_*') $(find ../src/ -name '*.c' \! -name 'win_*') -liconv
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_DARWIN -D_FILE_OFFSET_BITS=64 -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I ../src/gpacmp4 -I ../src/lib_ccx -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp' \! -name 'win_*') $(find ../src/ -name '*.c' \! -name 'win_*') -liconv

View File

@@ -2,10 +2,12 @@ cmake_minimum_required (VERSION 3.0.2)
project (CCExtractor)
option(WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF)
option (WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF)
option (WITH_OCR "Build with OCR (Optical Character Recognition) feature" OFF)
#Version number
set (CCEXTRACTOR_VERSION_MAJOR 0)
set (CCEXTRACTOR_VERSION_MINOR 75)
set (CCEXTRACTOR_VERSION_MINOR 77)
# configure a header file to pass some of the CMake settings
# to the source code
@@ -18,37 +20,69 @@ configure_file (
include_directories ("${PROJECT_SOURCE_DIR}")
include_directories ("${PROJECT_SOURCE_DIR}/lib_ccx")
include_directories ("${PROJECT_SOURCE_DIR}/gpacmp4/")
include_directories ("${PROJECT_SOURCE_DIR}/libccx_common/")
#Adding some platform specific library path
LINK_DIRECTORIES(/opt/local/lib)
LINK_DIRECTORIES(/usr/local/lib)
link_directories (/opt/local/lib)
link_directories (/usr/local/lib)
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g -std=gnu99 -Wno-write-strings -D_FILE_OFFSET_BITS=64")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g -std=gnu99 -Wno-write-strings -D_FILE_OFFSET_BITS=64")
add_subdirectory (lib_ccx)
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} SOURCEFILE)
aux_source_directory (${PROJECT_SOURCE_DIR} SOURCEFILE)
set (EXTRA_LIBS ${EXTRA_LIBS} ccx)
set (EXTRA_LIBS ${EXTRA_LIBS} png)
set (EXTRA_LIBS ${EXTRA_LIBS} m)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set (EXTRA_LIBS ${EXTRA_LIBS} iconv)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
find_package (PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PNG libpng )
if(PNG_FOUND)
set (EXTRA_LIBS ${EXTRA_LIBS} png)
else (PNG_FOUND)
include_directories ("${PROJECT_SOURCE_DIR}/libpng/")
aux_source_directory ("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
aux_source_directory ("${PROJECT_SOURCE_DIR}/zlib/" SOURCEFILE)
endif(PNG_FOUND)
endif (PKG_CONFIG_FOUND)
########################################################
# Build using FFmpeg libraries
#
if (WITH_FFMPEG)
########################################################
find_package(PkgConfig)
pkg_check_modules(AVFORMAT REQUIRED libavformat)
pkg_check_modules(AVUTIL REQUIRED libavutil)
pkg_check_modules(AVCODEC REQUIRED libavcodec)
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVFORMAT_STATIC_LIBRARIES} )
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVUTIL_STATIC_LIBRARIES} )
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVCODEC_STATIC_LIBRARIES} )
if (PKG_CONFIG_FOUND AND WITH_FFMPEG)
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
endif (WITH_FFMPEG)
pkg_check_modules (AVFORMAT REQUIRED libavformat)
pkg_check_modules (AVUTIL REQUIRED libavutil)
pkg_check_modules (AVCODEC REQUIRED libavcodec)
add_executable(ccextractor ${SOURCEFILE})
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVFORMAT_STATIC_LIBRARIES})
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVUTIL_STATIC_LIBRARIES})
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVCODEC_STATIC_LIBRARIES})
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
endif (PKG_CONFIG_FOUND AND WITH_FFMPEG)
########################################################
# Build with OCR using leptonica and tesseract libraries
########################################################
if (WITH_OCR)
find_package(PkgConfig)
pkg_check_modules (TESSERACT REQUIRED tesseract)
pkg_check_modules (LEPTONICA REQUIRED lept)
set (EXTRA_LIBS ${EXTRA_LIBS} ${TESSERACT_STATIC_LIBRARIES})
set (EXTRA_LIBS ${EXTRA_LIBS} ${LEPTONICA_STATIC_LIBRARIES})
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR ${TESSERACT_CFLAGS} ${LEPTONICA_CFLAGS}")
endif (WITH_OCR)
add_executable (ccextractor ${SOURCEFILE})
target_link_libraries (ccextractor ${EXTRA_LIBS})
install (TARGETS ccextractor DESTINATION bin)

View File

@@ -10,8 +10,7 @@ License: GPL 2.0
#include <signal.h>
#include "ffmpeg_intgr.h"
#include "ccx_common_option.h"
void xds_cea608_test();
#include "ccx_mp4.h"
struct lib_ccx_ctx *signal_ctx;
void sigint_handler()
@@ -22,118 +21,45 @@ void sigint_handler()
exit(EXIT_SUCCESS);
}
struct ccx_s_options ccx_options;
int main(int argc, char *argv[])
{
char *c;
struct encoder_ctx enc_ctx[2];
struct cc_subtitle dec_sub;
#ifdef ENABLE_FFMPEG
void *ffmpeg_ctx = NULL;
#endif
struct lib_ccx_ctx *ctx;
struct lib_cc_decode *dec_ctx = NULL;
int ret = 0;
enum ccx_stream_mode_enum stream_mode;
init_options (&ccx_options);
parse_configuration(&ccx_options);
parse_parameters (&ccx_options, argc, argv);
// Initialize libraries
ctx = init_libraries(&ccx_options);
dec_ctx = ctx->dec_ctx;
// Prepare write structures
init_write(&ctx->wbout1,ccx_options.wbout1.filename);
init_write(&ctx->wbout2,ccx_options.wbout2.filename);
int show_myth_banner = 0;
memset (&cea708services[0],0,CCX_DECODERS_708_MAX_SERVICES*sizeof (int)); // Cannot (yet) be moved because it's needed in parse_parameters.
memset (&dec_sub, 0,sizeof(dec_sub));
if (ctx->num_input_files==0 && ccx_options.input_source==CCX_DS_FILE)
ret = parse_parameters (&ccx_options, argc, argv);
if (ret == EXIT_NO_INPUT_FILES)
{
usage ();
fatal (EXIT_NO_INPUT_FILES, "(This help screen was shown because there were no input files)\n");
}
if (ctx->num_input_files>1 && ccx_options.live_stream)
else if (ret != EXIT_OK)
{
fatal(EXIT_TOO_MANY_INPUT_FILES, "Live stream mode accepts only one input file.\n");
}
if (ctx->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");
}
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 (ctx->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");
exit(ret);
}
// Initialize libraries
ctx = init_libraries(&ccx_options);
if (!ctx && errno == ENOMEM)
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
else if (!ctx && errno == EINVAL)
fatal (CCX_COMMON_EXIT_BUG_BUG, "Invalid option to CCextractor Library\n");
else if (!ctx && errno == EPERM)
fatal (CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to create Output File\n");
else if (!ctx && errno == EACCES)
fatal (CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to create Output File\n");
else if (!ctx)
fatal (EXIT_NOT_CLASSIFIED, "Unable to create Library Context %d\n",errno);
if (ctx->num_input_files > 0)
{
ctx->wbout1.multiple_files = 1;
ctx->wbout1.first_input_file = ctx->inputfile[0];
ctx->wbout2.multiple_files = 1;
ctx->wbout2.first_input_file = ctx->inputfile[0];
}
int show_myth_banner = 0;
// teletext page number out of range
if ((tlt_config.page != 0) && ((tlt_config.page < 100) || (tlt_config.page > 899))) {
fatal (EXIT_NOT_CLASSIFIED, "Teletext page number could not be lower than 100 or higher than 899\n");
}
if (ccx_options.output_filename!=NULL)
{
// Use the given output file name for the field specified by
// the -1, -2 switch. If -12 is used, the filename is used for
// field 1.
if (ccx_options.extract==2)
ctx->wbout2.filename=ccx_options.output_filename;
else
ctx->wbout1.filename=ccx_options.output_filename;
}
switch (ccx_options.write_format)
{
case CCX_OF_RAW:
ctx->extension = ".raw";
break;
case CCX_OF_SRT:
ctx->extension = ".srt";
break;
case CCX_OF_SAMI:
ctx->extension = ".smi";
break;
case CCX_OF_SMPTETT:
ctx->extension = ".ttml";
break;
case CCX_OF_TRANSCRIPT:
ctx->extension = ".txt";
break;
case CCX_OF_RCWT:
ctx->extension = ".bin";
break;
case CCX_OF_SPUPNG:
ctx->extension = ".xml";
break;
case CCX_OF_NULL:
ctx->extension = "";
break;
case CCX_OF_DVDRAW:
ctx->extension = ".dvdraw";
break;
default:
fatal (CCX_COMMON_EXIT_BUG_BUG, "write_format doesn't have any legal value, this is a bug.\n");
}
params_dump(ctx);
// default teletext page
@@ -142,227 +68,6 @@ int main(int argc, char *argv[])
tlt_config.page = ((tlt_config.page / 100) << 8) | (((tlt_config.page / 10) % 10) << 4) | (tlt_config.page % 10);
}
if (ctx->auto_stream==CCX_SM_MCPOODLESRAW && ccx_options.write_format==CCX_OF_RAW)
{
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "-in=raw can only be used if the output is a subtitle file.\n");
}
if (ctx->auto_stream==CCX_SM_RCWT && ccx_options.write_format==CCX_OF_RCWT && ccx_options.output_filename==NULL)
{
fatal (EXIT_INCOMPATIBLE_PARAMETERS,
"CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n");
}
subline = (unsigned char *) malloc (SUBLINESIZE);
switch (ccx_options.input_source)
{
case CCX_DS_FILE:
ctx->basefilename = (char *) malloc (strlen (ctx->inputfile[0])+1);
break;
case CCX_DS_STDIN:
ctx->basefilename = (char *) malloc (strlen (ctx->basefilename_for_stdin)+1);
break;
case CCX_DS_NETWORK:
case CCX_DS_TCP:
ctx->basefilename = (char *) malloc (strlen (ctx->basefilename_for_network)+1);
break;
}
if (ctx->basefilename == NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
switch (ccx_options.input_source)
{
case CCX_DS_FILE:
strcpy (ctx->basefilename, ctx->inputfile[0]);
break;
case CCX_DS_STDIN:
strcpy (ctx->basefilename, ctx->basefilename_for_stdin);
break;
case CCX_DS_NETWORK:
case CCX_DS_TCP:
strcpy (ctx->basefilename, ctx->basefilename_for_network);
break;
}
for (c = ctx->basefilename + strlen(ctx->basefilename) - 1; c>ctx->basefilename &&
*c!='.'; c--) {;} // Get last .
if (*c=='.')
*c=0;
if (ctx->wbout1.filename==NULL)
{
ctx->wbout1.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension));
ctx->wbout1.filename[0]=0;
}
if (ctx->wbout2.filename==NULL)
{
ctx->wbout2.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension));
ctx->wbout2.filename[0]=0;
}
if (ctx->buffer == NULL || ctx->pesheaderbuf==NULL ||
ctx->wbout1.filename == NULL || ctx->wbout2.filename == NULL ||
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, ccx_options.tcp_desc);
}
if (ccx_options.write_format!=CCX_OF_NULL)
{
/* # DVD format uses one raw file for both fields, while Broadcast requires 2 */
if (ccx_options.write_format==CCX_OF_DVDRAW)
{
if (ctx->wbout1.filename[0]==0)
{
strcpy (ctx->wbout1.filename,ctx->basefilename);
strcat (ctx->wbout1.filename,".raw");
}
if (ctx->cc_to_stdout)
{
ctx->wbout1.fh=STDOUT_FILENO;
mprint ("Sending captions to stdout.\n");
}
else
{
mprint ("Creating %s\n", ctx->wbout1.filename);
ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (ctx->wbout1.fh==-1)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n");
}
}
}
else
{
if (ctx->cc_to_stdout && ccx_options.extract==12)
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You can't extract both fields to stdout at the same time in broadcast mode.");
if (ccx_options.write_format == CCX_OF_SPUPNG && ctx->cc_to_stdout)
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You cannot use -out=spupng with -stdout.");
if (ccx_options.extract!=2)
{
if (ctx->cc_to_stdout)
{
ctx->wbout1.fh=STDOUT_FILENO;
mprint ("Sending captions to stdout.\n");
}
else if (!ccx_options.send_to_srv)
{
if (ctx->wbout1.filename[0]==0)
{
strcpy (ctx->wbout1.filename,ctx->basefilename);
if (ccx_options.extract==12) // _1 only added if there's two files
strcat (ctx->wbout1.filename,"_1");
strcat (ctx->wbout1.filename,(const char *) ctx->extension);
}
mprint ("Creating %s\n", ctx->wbout1.filename);
ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (ctx->wbout1.fh==-1)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed (errno=%d)\n", errno);
}
}
switch (ccx_options.write_format)
{
case CCX_OF_RAW:
init_encoder(enc_ctx, &ctx->wbout1);
writeraw(BROADCAST_HEADER, sizeof(BROADCAST_HEADER), &ctx->wbout1);
break;
case CCX_OF_DVDRAW:
break;
case CCX_OF_RCWT:
if (init_encoder(enc_ctx, &ctx->wbout1))
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
set_encoder_subs_delay(enc_ctx, ctx->subs_delay);
set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms);
set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed);
break;
default:
if (!ccx_options.no_bom){
if (ccx_options.encoding == CCX_ENC_UTF_8){ // Write BOM
writeraw(UTF8_BOM, sizeof(UTF8_BOM), &ctx->wbout1);
}
if (ccx_options.encoding == CCX_ENC_UNICODE){ // Write BOM
writeraw(LITTLE_ENDIAN_BOM, sizeof(LITTLE_ENDIAN_BOM), &ctx->wbout1);
}
}
if (init_encoder(enc_ctx, &ctx->wbout1)){
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
}
set_encoder_subs_delay(enc_ctx, ctx->subs_delay);
set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms);
set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed);
}
}
if (ccx_options.extract == 12 && ccx_options.write_format != CCX_OF_RAW)
mprint (" and \n");
if (ccx_options.extract!=1)
{
if (ctx->cc_to_stdout)
{
ctx->wbout1.fh=STDOUT_FILENO;
mprint ("Sending captions to stdout.\n");
}
else if(ccx_options.write_format == CCX_OF_RAW
&& ccx_options.extract == 12)
{
memcpy(&ctx->wbout2, &ctx->wbout1,sizeof(ctx->wbout1));
}
else if (!ccx_options.send_to_srv)
{
if (ctx->wbout2.filename[0]==0)
{
strcpy (ctx->wbout2.filename,ctx->basefilename);
if (ccx_options.extract==12) // _ only added if there's two files
strcat (ctx->wbout2.filename,"_2");
strcat (ctx->wbout2.filename,(const char *) ctx->extension);
}
mprint ("Creating %s\n", ctx->wbout2.filename);
ctx->wbout2.fh=open (ctx->wbout2.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (ctx->wbout2.fh==-1)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n");
}
if(ccx_options.write_format == CCX_OF_RAW)
writeraw (BROADCAST_HEADER,sizeof (BROADCAST_HEADER),&ctx->wbout2);
}
switch (ccx_options.write_format)
{
case CCX_OF_RAW:
case CCX_OF_DVDRAW:
break;
case CCX_OF_RCWT:
if( init_encoder(enc_ctx+1,&ctx->wbout2) )
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
set_encoder_subs_delay(enc_ctx+1, ctx->subs_delay);
set_encoder_last_displayed_subs_ms(enc_ctx+1, ctx->last_displayed_subs_ms);
set_encoder_startcredits_displayed(enc_ctx+1, ctx->startcredits_displayed);
break;
default:
if (!ccx_options.no_bom){
if (ccx_options.encoding == CCX_ENC_UTF_8){ // Write BOM
writeraw(UTF8_BOM, sizeof(UTF8_BOM), &ctx->wbout2);
}
if (ccx_options.encoding == CCX_ENC_UNICODE){ // Write BOM
writeraw(LITTLE_ENDIAN_BOM, sizeof(LITTLE_ENDIAN_BOM), &ctx->wbout2);
}
}
if (init_encoder(enc_ctx + 1, &ctx->wbout2)){
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
}
set_encoder_subs_delay(enc_ctx+1, ctx->subs_delay);
set_encoder_last_displayed_subs_ms(enc_ctx+1, ctx->last_displayed_subs_ms);
set_encoder_startcredits_displayed(enc_ctx+1, ctx->startcredits_displayed);
}
}
}
}
if (ccx_options.transcript_settings.xds)
{
if (ccx_options.write_format != CCX_OF_TRANSCRIPT)
@@ -372,34 +77,10 @@ int main(int argc, char *argv[])
}
}
if (ccx_options.teletext_mode == CCX_TXT_IN_USE) // Here, it would mean it was forced by user
telxcc_init(ctx);
ctx->fh_out_elementarystream = NULL;
if (ccx_options.out_elementarystream_filename!=NULL)
{
if ((ctx->fh_out_elementarystream = fopen (ccx_options.out_elementarystream_filename,"wb"))==NULL)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to open clean file: %s\n", ccx_options.out_elementarystream_filename);
}
}
// Initialize HDTV caption buffer
init_hdcc();
if (ccx_options.line_terminator_lf)
encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\n");
else
encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\r\n");
encoded_br_length = encode_line(encoded_br, (unsigned char *) "<br>");
time_t start, final;
time(&start);
dec_ctx->processed_enough=0;
if (ccx_options.binary_concat)
{
ctx->total_inputsize=gettotalfilessize(ctx);
@@ -412,7 +93,7 @@ int main(int argc, char *argv[])
m_signal(SIGINT, sigint_handler);
#endif
while (switch_to_next_file(ctx, 0) && !dec_ctx->processed_enough)
while (switch_to_next_file(ctx, 0))
{
prepare_for_new_file(ctx);
#ifdef ENABLE_FFMPEG
@@ -442,11 +123,11 @@ int main(int argc, char *argv[])
}
else
cc_count = len/3;
ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_sub);
if(ret >= 0 && dec_sub.got_output)
ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_ctx->dec_sub);
if(ret >= 0 && dec_ctx->dec_sub.got_output)
{
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
encode_sub(enc_ctx, &dec_ctx->dec_sub);
dec_ctx->dec_sub.got_output = 0;
}
}while(1);
continue;
@@ -456,103 +137,29 @@ int main(int argc, char *argv[])
mprint ("\rFailed to initialized ffmpeg falling back to legacy\n");
}
#endif
if (ctx->auto_stream == CCX_SM_AUTODETECT)
{
detect_stream_type(ctx);
switch (ctx->stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
mprint ("\rFile seems to be an elementary stream, enabling ES mode\n");
break;
case CCX_SM_TRANSPORT:
mprint ("\rFile seems to be a transport stream, enabling TS mode\n");
break;
case CCX_SM_PROGRAM:
mprint ("\rFile seems to be a program stream, enabling PS mode\n");
break;
case CCX_SM_ASF:
mprint ("\rFile seems to be an ASF, enabling DVR-MS mode\n");
break;
case CCX_SM_WTV:
mprint ("\rFile seems to be a WTV, enabling WTV mode\n");
break;
case CCX_SM_MCPOODLESRAW:
mprint ("\rFile seems to be McPoodle raw data\n");
break;
case CCX_SM_RCWT:
mprint ("\rFile seems to be a raw caption with time data\n");
break;
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(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
break;
}
}
else
{
ctx->stream_mode=ctx->auto_stream;
}
/* -----------------------------------------------------------------
MAIN LOOP
----------------------------------------------------------------- */
// The myth loop autodetect will only be used with ES or PS streams
switch (ccx_options.auto_myth)
{
case 0:
// Use whatever stream mode says
break;
case 1:
// Force stream mode to myth
ctx->stream_mode=CCX_SM_MYTH;
break;
case 2:
// autodetect myth files, but only if it does not conflict with
// the current stream mode
switch (ctx->stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
case CCX_SM_PROGRAM:
if ( detect_myth(ctx) )
{
ctx->stream_mode=CCX_SM_MYTH;
}
break;
default:
// Keep stream_mode
break;
}
break;
}
stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx);
// Disable sync check for raw formats - they have the right timeline.
// Also true for bin formats, but -nosync might have created a
// broken timeline for debug purposes.
// Disable too in MP4, specs doesn't say that there can't be a jump
switch (ctx->stream_mode)
switch (stream_mode)
{
case CCX_SM_MCPOODLESRAW:
case CCX_SM_RCWT:
case CCX_SM_MP4:
case CCX_SM_MCPOODLESRAW:
case CCX_SM_RCWT:
case CCX_SM_MP4:
#ifdef WTV_DEBUG
case CCX_SM_HEX_DUMP:
case CCX_SM_HEX_DUMP:
#endif
ccx_common_timing_settings.disable_sync_check = 1;
break;
default:
break;
ccx_common_timing_settings.disable_sync_check = 1;
break;
default:
break;
}
switch (ctx->stream_mode)
/* -----------------------------------------------------------------
MAIN LOOP
----------------------------------------------------------------- */
switch (stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something
@@ -565,25 +172,27 @@ 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(ctx, &enc_ctx);
general_loop(ctx);
break;
case CCX_SM_MCPOODLESRAW:
mprint ("\rAnalyzing data in McPoodle raw mode\n");
raw_loop(ctx, &enc_ctx);
raw_loop(ctx);
break;
case CCX_SM_RCWT:
mprint ("\rAnalyzing data in CCExtractor's binary format\n");
rcwt_loop(ctx, &enc_ctx);
rcwt_loop(ctx);
break;
case CCX_SM_MYTH:
mprint ("\rAnalyzing data in MythTV mode\n");
show_myth_banner = 1;
myth_loop(ctx, &enc_ctx);
myth_loop(ctx);
break;
case CCX_SM_MP4:
case CCX_SM_MP4:
mprint ("\rAnalyzing data with GPAC (MP4 library)\n");
close_input_file(ctx); // No need to have it open. GPAC will do it for us
processmp4 (ctx, ctx->inputfile[0],&enc_ctx);
processmp4 (ctx, &ctx->mp4_cfg, ctx->inputfile[0]);
if (ccx_options.print_file_reports)
print_file_report(ctx);
break;
#ifdef WTV_DEBUG
case CCX_SM_HEX_DUMP:
@@ -596,39 +205,7 @@ int main(int argc, char *argv[])
break;
}
mprint("\n");
dbg_print(CCX_DMT_DECODER_608, "\nTime stamps after last caption block was written:\n");
dbg_print(CCX_DMT_DECODER_608, "Last time stamps: PTS: %s (%+2dF) ",
print_mstime( (LLONG) (sync_pts/(MPEG_CLOCK_FREQ/1000)
+frames_since_ref_time*1000.0/current_fps) ),
frames_since_ref_time);
dbg_print(CCX_DMT_DECODER_608, "GOP: %s \n", print_mstime(gop_time.ms) );
// Blocks since last PTS/GOP time stamp.
dbg_print(CCX_DMT_DECODER_608, "Calc. difference: PTS: %s (%+3lldms incl.) ",
print_mstime( (LLONG) ((sync_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
+ fts_offset + frames_since_ref_time*1000.0/current_fps)),
fts_offset + (LLONG) (frames_since_ref_time*1000.0/current_fps) );
dbg_print(CCX_DMT_DECODER_608, "GOP: %s (%+3dms incl.)\n",
print_mstime((LLONG)(gop_time.ms
-first_gop_time.ms
+get_fts_max()-fts_at_gop_start)),
(int)(get_fts_max()-fts_at_gop_start));
// When padding is active the CC block time should be within
// 1000/29.97 us of the differences.
dbg_print(CCX_DMT_DECODER_608, "Max. FTS: %s (without caption blocks since then)\n",
print_mstime(get_fts_max()));
if (ctx->stat_hdtv)
{
mprint ("\rCC type 0: %d (%s)\n", dec_ctx->cc_stats[0], cc_types[0]);
mprint ("CC type 1: %d (%s)\n", dec_ctx->cc_stats[1], cc_types[1]);
mprint ("CC type 2: %d (%s)\n", dec_ctx->cc_stats[2], cc_types[2]);
mprint ("CC type 3: %d (%s)\n", dec_ctx->cc_stats[3], cc_types[3]);
}
mprint ("\nTotal frames time: %s (%u frames at %.2ffps)\n",
print_mstime( (LLONG)(total_frames_count*1000/current_fps) ),
total_frames_count, current_fps);
#if 0
if (ctx->total_pulldownframes)
mprint ("incl. pulldown frames: %s (%u frames at %.2ffps)\n",
print_mstime( (LLONG)(ctx->total_pulldownframes*1000/current_fps) ),
@@ -648,7 +225,7 @@ int main(int argc, char *argv[])
- min_pts/(MPEG_CLOCK_FREQ/1000) + fts_offset ));
}
// dvr-ms files have invalid GOPs
if (gop_time.inited && first_gop_time.inited && ctx->stream_mode != CCX_SM_ASF)
if (gop_time.inited && first_gop_time.inited && stream_mode != CCX_SM_ASF)
{
mprint ("\nInitial GOP time: %s\n",
print_mstime(first_gop_time.ms));
@@ -688,76 +265,68 @@ int main(int argc, char *argv[])
mprint("caption is not well understood!\n\n");
mprint("Please submit samples to the developers.\n\n\n");
}
#endif
// Add one frame as fts_max marks the beginning of the last frame,
// but we need the end.
fts_global += fts_max + (LLONG) (1000.0/current_fps);
// CFS: At least in Hauppage mode, cb_field can be responsible for ALL the
// timing (cb_fields having a huge number and fts_now and fts_global being 0 all
// the time), so we need to take that into account in fts_global before resetting
// counters.
if (cb_field1!=0)
fts_global += cb_field1*1001/3;
else
fts_global += cb_field2*1001/3;
// Reset counters - This is needed if some captions are still buffered
// and need to be written after the last file is processed.
cb_field1 = 0; cb_field2 = 0; cb_708 = 0;
fts_now = 0;
fts_max = 0;
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
{
mprint("\n");
dbg_print(CCX_DMT_DECODER_608, "\nTime stamps after last caption block was written:\n");
dbg_print(CCX_DMT_DECODER_608, "GOP: %s \n", print_mstime(gop_time.ms) );
dbg_print(CCX_DMT_DECODER_608, "GOP: %s (%+3dms incl.)\n",
print_mstime((LLONG)(gop_time.ms
-first_gop_time.ms
+get_fts_max(dec_ctx->timing)-fts_at_gop_start)),
(int)(get_fts_max(dec_ctx->timing)-fts_at_gop_start));
// When padding is active the CC block time should be within
// 1000/29.97 us of the differences.
dbg_print(CCX_DMT_DECODER_608, "Max. FTS: %s (without caption blocks since then)\n",
print_mstime(get_fts_max(dec_ctx->timing)));
mprint ("\nTotal frames time: %s (%u frames at %.2ffps)\n",
print_mstime( (LLONG)(total_frames_count*1000/current_fps) ),
total_frames_count, current_fps);
if (ctx->stat_hdtv)
{
mprint ("\rCC type 0: %d (%s)\n", dec_ctx->cc_stats[0], cc_types[0]);
mprint ("CC type 1: %d (%s)\n", dec_ctx->cc_stats[1], cc_types[1]);
mprint ("CC type 2: %d (%s)\n", dec_ctx->cc_stats[2], cc_types[2]);
mprint ("CC type 3: %d (%s)\n", dec_ctx->cc_stats[3], cc_types[3]);
}
// Add one frame as fts_max marks the beginning of the last frame,
// but we need the end.
dec_ctx->timing->fts_global += dec_ctx->timing->fts_max + (LLONG) (1000.0/current_fps);
// CFS: At least in Hauppage mode, cb_field can be responsible for ALL the
// timing (cb_fields having a huge number and fts_now and fts_global being 0 all
// the time), so we need to take that into account in fts_global before resetting
// counters.
if (cb_field1!=0)
dec_ctx->timing->fts_global += cb_field1*1001/3;
else if (cb_field2!=0)
dec_ctx->timing->fts_global += cb_field2*1001/3;
else
dec_ctx->timing->fts_global += cb_708*1001/3;
// Reset counters - This is needed if some captions are still buffered
// and need to be written after the last file is processed.
cb_field1 = 0; cb_field2 = 0; cb_708 = 0;
dec_ctx->timing->fts_now = 0;
dec_ctx->timing->fts_max = 0;
}
if(is_decoder_processed_enough(ctx) == CCX_TRUE)
break;
} // file loop
close_input_file(ctx);
if (ctx->fh_out_elementarystream!=NULL)
fclose (ctx->fh_out_elementarystream);
flushbuffer (ctx, &ctx->wbout1, false);
flushbuffer (ctx, &ctx->wbout2, false);
prepare_for_new_file (ctx); // To reset counters used by handle_end_of_data()
telxcc_close(ctx);
if (ctx->wbout1.fh!=-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_SPUPNG )
{
handle_end_of_data(dec_ctx->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 (dec_ctx, NULL);
}
dinit_encoder(enc_ctx);
}
if (ctx->wbout2.fh!=-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_SPUPNG )
{
handle_end_of_data(dec_ctx->context_cc608_field_2, &dec_sub);
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
}
dinit_encoder(enc_ctx+1);
}
flushbuffer (ctx, &ctx->wbout1,true);
flushbuffer (ctx, &ctx->wbout2,true);
time (&final);
long proc_time=(long) (final-start);
mprint ("\rDone, processing time = %ld seconds\n", proc_time);
#if 0
if (proc_time>0)
{
LLONG ratio=(get_fts_max()/10)/proc_time;
@@ -766,21 +335,17 @@ int main(int argc, char *argv[])
mprint ("Performance (real length/process time) = %u.%02u\n",
s1, s2);
}
dbg_print(CCX_DMT_708, "The 708 decoder was reset [%d] times.\n",resets_708);
#endif
dbg_print(CCX_DMT_708, "[CEA-708] The 708 decoder was reset [%d] times.\n", ctx->freport.data_from_708->reset_count);
/*
if (ccx_options.teletext_mode == CCX_TXT_IN_USE)
mprint ( "Teletext decoder: %"PRIu32" packets processed, %"PRIu32" SRT frames written.\n", tlt_packet_counter, tlt_frames_produced);
if (dec_ctx->processed_enough)
*/
if (is_decoder_processed_enough(ctx) == CCX_TRUE)
{
mprint ("\rNote: Processing was cancelled before all data was processed because\n");
mprint ("\rone or more user-defined limits were reached.\n");
}
if (ccblocks_in_avc_lost>0)
{
mprint ("Total caption blocks received: %d\n", ccblocks_in_avc_total);
mprint ("Total caption blocks lost: %d\n", ccblocks_in_avc_lost);
}
mprint ("This is beta software. Report issues to carlos at ccextractor org...\n");
if (show_myth_banner)
{

View File

@@ -6159,6 +6159,12 @@ static void gf_isom_check_sample_desc(GF_TrackBox *trak)
u32 i;
i=0;
if(!trak->Media->information->sampleTable->SampleDescription)
{
printf("\nCCEXTRACTOR: Ignore table without description\n");
return;
}
while ((a = (GF_UnknownBox*)gf_list_enum(trak->Media->information->sampleTable->SampleDescription->boxList, &i))) {
switch (a->type) {
case GF_ISOM_BOX_TYPE_MP4S:

View File

@@ -227,7 +227,8 @@ enum
GF_ISOM_SUBTYPE_LSR1 = GF_4CC( 'l', 's', 'r', '1' ),
/* CAPTIONS */
GF_ISOM_SUBTYPE_C608 = GF_4CC ('c', '6', '0', '8' )
GF_ISOM_SUBTYPE_C608 = GF_4CC( 'c', '6', '0', '8' ),
GF_ISOM_SUBTYPE_C708 = GF_4CC( 'c', '7', '0', '8' )
};

View File

@@ -1736,15 +1736,15 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min
chunk_dur += dur;
stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size);
chunk_size += size;
}
if (dmin>chunk_dur) dmin = chunk_dur;
if (dmax<chunk_dur) dmax = chunk_dur;
davg += chunk_dur;
if (smin>chunk_size) smin = chunk_size;
if (smax<chunk_size) smax = chunk_size;
savg += chunk_dur;
savg += chunk_size;
tot_chunks ++;
sample_idx += stsc->entries[i].samplesPerChunk;
if (i+1==stsc->nb_entries) break;
@@ -1752,8 +1752,10 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min
if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break;
}
}
if (tot_chunks) davg /= tot_chunks;
if (tot_chunks) {
davg /= tot_chunks;
savg /= tot_chunks;
}
if (dur_min) *dur_min = dmin;
if (dur_avg) *dur_avg = (u32) davg;
if (dur_max) *dur_max = dmax;

View File

@@ -333,10 +333,12 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp,
//divided into the original and the edition files
if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) {
//same as last call in read mode
if (!mdia->information->dataHandler || (mdia->information->dataEntryIndex != dataRefIndex)) {
if (!mdia->information->dataHandler) {
e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
if (e) return e;
}
if (mdia->information->dataEntryIndex != dataRefIndex)
mdia->information->dataEntryIndex = dataRefIndex;
} else {
e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
if (e) return e;

View File

@@ -7,9 +7,9 @@
#include "utility.h"
#include "ccx_encoders_common.h"
#include "ccx_common_option.h"
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub);
void set_fts(void); // From timing.c
#include "ccx_mp4.h"
#include "activity.h"
#include "ccx_dtvcc.h"
static short bswap16(short v)
{
@@ -32,11 +32,12 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
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
struct lib_cc_decode *dec_ctx = NULL;
if (pts_set==0)
pts_set=1;
set_fts();
dec_ctx = update_decoder_list(ctx);
set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
set_fts(dec_ctx->timing);
for(i = 0; i < s->dataLength; )
{
@@ -62,7 +63,7 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
temp_debug=0;
if (nal_length>0)
do_NAL (ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
do_NAL (dec_ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
i += nal_length;
} // outer for
assert(i == s->dataLength);
@@ -72,8 +73,11 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
{
u32 timescale, i, sample_count;
int status;
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = update_decoder_list(ctx);
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
{
return 0;
@@ -91,24 +95,22 @@ static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_
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();
set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
set_fts(dec_ctx->timing);
process_m2v (ctx, (unsigned char *) s->data,s->dataLength, sub);
process_m2v (dec_ctx, (unsigned char *) s->data,s->dataLength, sub);
gf_isom_sample_del(&s);
}
int progress = (int) ((i*100) / sample_count);
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(100, cur_sec/60, cur_sec%60);
return status;
@@ -119,6 +121,9 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
u32 timescale, i, sample_count, last_sdi = 0;
int status;
GF_AVCConfig* c = NULL;
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = update_decoder_list(ctx);
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
{
@@ -168,12 +173,12 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
int progress = (int) ((i*100) / sample_count);
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(100, cur_sec/60, cur_sec%60);
if(c != NULL)
@@ -185,6 +190,87 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
return status;
}
unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count)
{
unsigned char *data = ccdp_atom_content;
if (len < 4)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected size of cdp\n");
return NULL;
}
unsigned int cdp_id = (data[0] << 8) | data[1];
if (cdp_id != 0x9669)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected header %hhX %hhX\n", data[0], data[1]);
return NULL;
}
data += 2;
len -= 2;
unsigned int cdp_data_count = data[0];
unsigned int cdp_frame_rate = data[1] >> 4; //frequency could be calculated
if (cdp_data_count != len + 2)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected data length %u %u\n", cdp_data_count, len + 2);
return NULL;
}
data += 2;
len -= 2;
unsigned int cdp_flags = data[0];
unsigned int cdp_counter = (data[1] << 8) | data[2];
data += 3;
len -= 3;
unsigned int cdp_timecode_added = (cdp_flags & 0x80) >> 7;
unsigned int cdp_data_added = (cdp_flags & 0x40) >> 6;
if (!cdp_data_added)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: packet without data\n");
return NULL;
}
if (cdp_timecode_added)
{
data += 4;
len -= 4;
}
if (data[0] != CDP_SECTION_DATA)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: cdp_data_section byte not found\n");
return NULL;
}
*cc_count = (unsigned int) (data[1] & 0x1F);
if (*cc_count != 10 && *cc_count != 20 && *cc_count != 25 && *cc_count != 30)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", *cc_count);
return NULL;
}
data += 2;
len -= 2;
if ((*cc_count) * 3 > len)
{
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, *cc_count);
return NULL;
}
(void)(cdp_counter);
(void)(cdp_frame_rate);
return data;
}
/*
Here is application algorithm described in some C-like pseudo code:
main(){
@@ -198,11 +284,15 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
}
*/
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file)
{
GF_ISOFile* f;
u32 i, j, track_count, avc_track_count, cc_track_count;
struct cc_subtitle dec_sub;
struct lib_cc_decode *dec_ctx = NULL;
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
dec_ctx = update_decoder_list(ctx);
memset(&dec_sub,0,sizeof(dec_sub));
mprint("opening \'%s\': ", file);
@@ -231,20 +321,23 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
(unsigned char) ((type>>16)%0x100),(unsigned char) ((type>>8)%0x100),(unsigned char) (type%0x100),
(unsigned char) (subtype>>24%0x100),
(unsigned char) ((subtype>>16)%0x100),(unsigned char) ((subtype>>8)%0x100),(unsigned char) (subtype%0x100));
if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608)
cc_track_count++;
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
if ((type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) ||
(type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C708))
cc_track_count++;
if (type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
avc_track_count++;
}
mprint("mp4: found %u tracks: %u avc and %u cc\n", track_count, avc_track_count, cc_track_count);
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);
if ( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_XDVB)
{
if (cc_track_count && !ccx_options.mp4vidtrack)
if (cc_track_count && !cfg->mp4vidtrack)
continue;
if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
{
@@ -259,8 +352,8 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
}
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
{
if (cc_track_count && !ccx_options.mp4vidtrack)
{
if (cc_track_count && !cfg->mp4vidtrack)
continue;
GF_AVCConfig *cnf = gf_isom_avc_config_get(f,i+1,1);
if (cnf!=NULL)
@@ -268,7 +361,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
{
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
do_NAL (ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
do_NAL (dec_ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
}
}
@@ -282,22 +375,21 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
}
}
if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608)
{
if (avc_track_count && ccx_options.mp4vidtrack)
if (type == GF_ISOM_MEDIA_CAPTIONS &&
(subtype == GF_ISOM_SUBTYPE_C608 || subtype == GF_ISOM_SUBTYPE_C708))
{
if (avc_track_count && cfg->mp4vidtrack)
continue;
#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);
#ifdef MP$DEBUG
#ifdef MP4_DEBUG
u64 duration = gf_isom_get_media_duration(f,i+1);
mprint ("%u streams\n",num_streams);
mprint ("%u sample counts\n",num_samples);
@@ -306,7 +398,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
#endif
for (unsigned k = 0; k <num_samples; k++)
{
u32 StreamDescriptionIndex;
u32 StreamDescriptionIndex;
GF_ISOSample *sample= gf_isom_get_sample(f, i+1, k+1, &StreamDescriptionIndex);
if (ProcessingStreamDescriptionIndex && ProcessingStreamDescriptionIndex!=StreamDescriptionIndex)
{
@@ -322,10 +414,8 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
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();
set_current_pts(dec_ctx->timing, (sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale);
set_fts(dec_ctx->timing);
int atomStart = 0;
// process Atom by Atom
@@ -333,47 +423,116 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
{
char *data = sample->data + atomStart;
unsigned int atomLength = RB32(data);
if(atomLength < 8 || atomLength > sample->dataLength)
if (atomLength < 8 || atomLength > sample->dataLength)
{
mprint ("Invalid atom.\n");
mprint ("Invalid atom length. Atom length: %u, should be: %u\n", atomLength, sample->dataLength);
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);
dump(256, (unsigned char *)data, atomLength - 8, 0, 1);
#endif
do
data += 4;
int is_ccdp = !strncmp(data, "ccdp", 4);
if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4) || is_ccdp)
{
if (subtype == GF_ISOM_SUBTYPE_C708)
{
ret = process608((unsigned char*)data, len, ctx->dec_ctx->context_cc608_field_1, &dec_sub);
len -= ret;
data += ret;
if(dec_sub.got_output)
if (!is_ccdp)
{
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
mprint("Your video file seems to be an interesting sample for us\n");
mprint("We haven't met c708 subtitle not in a \'ccdp\' atom before\n");
mprint("Please, report\n");
break;
}
} while (len > 0);
unsigned int cc_count;
data += 4;
unsigned char *cc_data = ccdp_find_data((unsigned char *) data, sample->dataLength - 8, &cc_count);
if (!cc_data)
{
dbg_print(CCX_DMT_PARSE, "mp4-708: no cc data found in ccdp\n");
break;
}
ctx->dec_global_setting->settings_dtvcc->enabled = 1;
unsigned char temp[4];
for (int cc_i = 0; cc_i < cc_count; cc_i++, cc_data += 3)
{
unsigned char cc_info = cc_data[0];
unsigned char cc_valid = (unsigned char) ((cc_info & 4) >> 2);
unsigned char cc_type = (unsigned char) (cc_info & 3);
if (cc_info == CDP_SECTION_SVC_INFO || cc_info == CDP_SECTION_FOOTER)
{
dbg_print(CCX_DMT_PARSE, "mp4-708: premature end of sample (0x73 or 0x74)\n");
break;
}
if ((cc_info == 0xFA || cc_info == 0xFC || cc_info == 0xFD)
&& (cc_data[1] & 0x7F) == 0 && (cc_data[2] & 0x7F) == 0)
{
dbg_print(CCX_DMT_PARSE, "mp4-708: skipped (zero cc data)\n");
continue;
}
temp[0] = cc_valid;
temp[1] = cc_type;
temp[2] = cc_data[1];
temp[3] = cc_data[2];
if (cc_type < 2)
{
dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n");
continue;
}
dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work
//TODO is it really always 4-bytes long?
ccx_dtvcc_process_data(dec_ctx, (unsigned char *) temp, 4);
cb_708++;
}
atomStart = sample->dataLength;
}
else //subtype == GF_ISOM_SUBTYPE_C608
{
if (is_ccdp)
{
mprint("Your video file seems to be an interesting sample for us\n");
mprint("We haven't met c608 subtitle in a \'ccdp\' atom before\n");
mprint("Please, report\n");
break;
}
int ret = 0;
int len = atomLength - 8;
data += 4;
do {
ret = process608((unsigned char *) data, len, dec_ctx,
&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
int progress = (int) ((k*100) / num_samples);
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress(100, cur_sec/60, cur_sec%60);
}
}
@@ -398,8 +557,6 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
mprint ("found no dedicated CC track(s).\n");
ctx->freport.mp4_cc_track_cnt = cc_track_count;
if (ccx_options.print_file_reports)
print_file_report(ctx);
return 0;
}

View File

@@ -1,204 +0,0 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_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);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - 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_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_br, encoded_br_length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
write(context->out->fh, context->buffer, used);
free(el);
free(unescaped);
}
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + context->subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + context->subs_delay;
ms_end = sub->end_time - 1;
}
else if ( context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER) )
{
ms_start = 1 + context->subs_delay;
ms_end = sub->start_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
#if ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *token = NULL;
char *buf = (char*)context->buffer;
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
,(unsigned long long)ms_start);
write(context->out->fh, buf, strlen(buf));
token = strtok(rect[0].ocr_text,"\r\n");
while (token)
{
sprintf(buf, "%s", token);
token = strtok(NULL,"\r\n");
if(token)
strcat(buf, "<br>\n");
else
strcat(buf, "\n");
write(context->out->fh, buf, strlen(buf));
}
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n"
,(unsigned long long)ms_end);
write(context->out->fh, buf, strlen(buf));
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
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 = data->start_time;
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = data->end_time;
endms--; // To prevent overlapping with next line.
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
(unsigned long long)startms);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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])
{
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write (context->out->fh, subline, length);
wrote_something=1;
if (i!=14)
write (context->out->fh, encoded_br, encoded_br_length);
write (context->out->fh,encoded_crlf, encoded_crlf_length);
}
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
return wrote_something;
}

View File

@@ -1,225 +0,0 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_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
// See http://www.w3.org/TR/ttaf1-dfxp/ and
// https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
// Copyright (C) 2012 John Kemp
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// 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 encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
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);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - 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_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, el, u);
//write (wb->fh, encoded_br, encoded_br_length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
sprintf ((char *) str,"</p>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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_DECODER_608, "\r%s\n", str);
}
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_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
//char timeline[128];
int len = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + context->subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + context->subs_delay;
ms_end = sub->end_time - 1;
}
else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = 1 + context->subs_delay;
ms_end = sub->start_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
#ifdef ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *buf = (char *) context->buffer;
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.
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, buf,strlen(buf) );
len = strlen(rect[0].ocr_text);
write (context->out->fh, rect[0].ocr_text, len);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
sprintf ( buf,"</p>\n");
write (context->out->fh, buf,strlen(buf) );
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
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 = data->start_time;
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = data->end_time;
endms--; // To prevent overlapping with next line.
mstotime (startms,&h1,&m1,&s1,&ms1);
mstotime (endms-1,&h2,&m2,&s2,&ms2);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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])
{
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, subline, length);
wrote_something=1;
write(context->out->fh, encoded_crlf, encoded_crlf_length);
}
}
sprintf ((char *) str,"</p>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
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_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
//write (wb->fh, enc_buffer,enc_buffer_used);
return wrote_something;
}

View File

@@ -1,278 +0,0 @@
#include <assert.h>
#include <sys/stat.h>
#include "608_spupng.h"
void
draw_row(struct eia608_screen* data, int row, uint8_t * canvas, int rowstride)
{
int column;
int unicode = 0;
uint8_t pen[2];
uint8_t* cell;
int first = -1;
int last = 0;
pen[0] = COL_BLACK;
for (column = 0; column < COLUMNS ; column++) {
if (COL_TRANSPARENT != data->colors[row][column])
{
cell = canvas + ((column+1) * CCW);
get_char_in_unicode((unsigned char*)&unicode, data->characters[row][column]);
pen[1] = data->colors[row][column];
int attr = data->fonts[row][column];
draw_char_indexed(cell, rowstride, pen, unicode, (attr & FONT_ITALICS) != 0, (attr & FONT_UNDERLINED) != 0);
if (first < 0)
{
// draw a printable space before the first non-space char
first = column;
if (unicode != 0x20)
{
cell = canvas + ((first) * CCW);
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
}
}
last = column;
}
}
// draw a printable space after the last non-space char
// unicode should still contain the last character
// check whether it is a space
if (unicode != 0x20)
{
cell = canvas + ((last+2) * CCW);
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
}
}
static png_color palette[10] =
{
{ 0xff, 0xff, 0xff }, // COL_WHITE = 0,
{ 0x00, 0xff, 0x00 }, // COL_GREEN = 1,
{ 0x00, 0x00, 0xff }, // COL_BLUE = 2,
{ 0x00, 0xff, 0xff }, // COL_CYAN = 3,
{ 0xff, 0x00, 0x00 }, // COL_RED = 4,
{ 0xff, 0xff, 0x00 }, // COL_YELLOW = 5,
{ 0xff, 0x00, 0xff }, // COL_MAGENTA = 6,
{ 0xff, 0xff, 0xff }, // COL_USERDEFINED = 7,
{ 0x00, 0x00, 0x00 }, // COL_BLACK = 8
{ 0x00, 0x00, 0x00 } // COL_TRANSPARENT = 9
};
static png_byte alpha[10] =
{
255,
255,
255,
255,
255,
255,
255,
255,
255,
0
};
int
spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
png_structp png_ptr, png_infop info_ptr,
png_bytep image,
png_bytep* row_pointer,
unsigned int ww, unsigned int wh)
{
unsigned int i;
if (setjmp(png_jmpbuf(png_ptr)))
return 0;
png_init_io (png_ptr, sp->fppng);
png_set_IHDR (png_ptr,
info_ptr,
ww,
wh,
/* 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, sizeof(palette) / sizeof(palette[0]));
png_set_tRNS (png_ptr, info_ptr, alpha, sizeof(alpha) / sizeof(alpha[0]), NULL);
png_set_gAMA (png_ptr, info_ptr, 1.0 / 2.2);
png_write_info (png_ptr, info_ptr);
for (i = 0; i < wh; i++)
row_pointer[i] = image + i * ww;
png_write_image (png_ptr, row_pointer);
png_write_end (png_ptr, info_ptr);
return 1;
}
int
spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
{
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointer;
png_bytep image;
int ww, wh, rowstride, row_adv;
int row;
assert ((sizeof(png_byte) == sizeof(uint8_t))
&& (sizeof(*image) == sizeof(uint8_t)));
// Allow space at beginning and end of each row for a padding space
ww = CCW * (COLUMNS+2);
wh = CCH * ROWS;
row_adv = (COLUMNS+2) * CCW * CCH;
rowstride = ww * sizeof(*image);
if (!(row_pointer = (png_bytep*)malloc(sizeof(*row_pointer) * wh))) {
mprint("Unable to allocate %d byte buffer.\n",
sizeof(*row_pointer) * wh);
return 0;
}
if (!(image = (png_bytep)malloc(wh * ww * sizeof(*image)))) {
mprint("Unable to allocate %d KB image buffer.",
wh * ww * sizeof(*image) / 1024);
free(row_pointer);
return 0;
}
// Initialize image to transparent
memset(image, COL_TRANSPARENT, wh * ww * sizeof(*image));
/* draw the image */
for (row = 0; row < ROWS; row++) {
if (data->row_used[row])
draw_row(data, row, image + row * row_adv, rowstride);
}
/* Now save the image */
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL)))
goto unknown_error;
if (!(info_ptr = png_create_info_struct(png_ptr))) {
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
goto unknown_error;
}
if (!spupng_write_png (sp, data, png_ptr, info_ptr, image, row_pointer, ww, wh)) {
png_destroy_write_struct (&png_ptr, &info_ptr);
goto write_error;
}
png_destroy_write_struct (&png_ptr, &info_ptr);
free (row_pointer);
free (image);
return 1;
write_error:
unknown_error:
free (row_pointer);
free (image);
return 0;
}
int
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
struct encoder_ctx *context)
{
LLONG ms_start = data->start_time + context->subs_delay;
if (ms_start < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
return 0;
}
int row;
int empty_buf = 1;
char str[256] = "";
for (row = 0; row < 15; row++)
{
if (data->row_used[row])
{
empty_buf = 0;
break;
}
}
if (empty_buf)
{
dbg_print(CCX_DMT_VERBOSE, "Blank page\n");
return 0;
}
LLONG ms_end = data->end_time;
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
sp->pngfile, strerror(errno));
}
if (!spupng_export_png(sp, data))
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
sp->pngfile, strerror(errno));
}
fclose(sp->fppng);
write_sputag(sp,ms_start,ms_end);
for (row = 0; row < ROWS; row++)
{
if (data->row_used[row])
{
int len = get_decoder_line_encoded(subline, row, data);
// Check for characters that spumux won't parse
// null chars will be changed to space
// pairs of dashes will be changed to underscores
for (unsigned char* ptr = subline; ptr < subline+len; ptr++)
{
switch (*ptr)
{
case 0:
*ptr = ' ';
break;
case '-':
if (*(ptr+1) == '-')
{
*ptr++ = '_';
*ptr = '_';
}
break;
}
}
strncat(str,(const char*)subline,256);
strncat(str,"\n",256);
}
}
write_spucomment(sp,str);
return 1;
}
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context)
{
if (0 != context->out->spupng_data)
{
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
return spupng_write_ccbuffer(sp, data, context);
}
return 0;
}

View File

@@ -1,18 +1,42 @@
cmake_policy(SET CMP0037 NEW)
cmake_policy (SET CMP0037 NEW)
SET (CMAKE_C_FLAGS "-O0 -Wall -g -std=gnu99")
set (CMAKE_C_FLAGS "-O0 -Wall -g -std=gnu99")
if (WITH_FFMPEG)
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
endif (WITH_FFMPEG)
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
#AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
add_library(ccx ${SOURCEFILE})
if (WITH_OCR)
find_package(PkgConfig)
FILE(GLOB HeaderFiles *.h)
file(WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
pkg_check_modules(TESSERACT REQUIRED tesseract)
pkg_check_modules(LEPTONICA REQUIRED lept)
set (EXTRA_LIBS ${EXTRA_LIBS} ${TESSERACT_STATIC_LIBRARIES})
set (EXTRA_LIBS ${EXTRA_LIBS} ${LEPTONICA_STATIC_LIBRARIES})
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR ${TESSERACT_CFLAGS} ${LEPTONICA_CFLAGS}")
endif (WITH_OCR)
aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
aux_source_directory ("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
add_library (ccx ${SOURCEFILE} ccx_dtvcc.h ccx_dtvcc.c)
if (MINGW OR CYGWIN)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_WIN32")
endif (MINGW OR CYGWIN)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_LINUX")
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_DARWIN")
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
file (GLOB HeaderFiles *.h)
file (WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
"includedir=\${prefix}/include\n"
"libdir=\${prefix}/lib\n\n"
"Name: ccx\n"
@@ -20,8 +44,9 @@ file(WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
"Version: 0.75\n"
"Cflags: -I\${includedir}/\n"
"Libs: -L\${libdir} -lccx -lpng\n"
"Libs.private: -lpng\n" )
"Libs.private: -lpng\n"
)
install (TARGETS ccx DESTINATION lib)
install (FILES ${HeaderFiles} DESTINATION include)
install (FILES ccx.pc DESTINATION lib/pkgconfig )
install (FILES ccx.pc DESTINATION lib/pkgconfig)

View File

@@ -7,53 +7,54 @@ relevant events. */
static int credits_shown=0;
unsigned long net_activity_gui=0;
/* Print current progress. For percentaje, -1 -> streaming mode */
void activity_progress (int percentaje, int cur_min, int cur_sec)
/* Print current progress. For percentage, -1 -> streaming mode */
void activity_progress (int percentage, int cur_min, int cur_sec)
{
if (!ccx_options.no_progress_bar)
{
if (percentaje==-1)
mprint ("\rStreaming | %02d:%02d", cur_min, cur_sec);
else
mprint ("\r%3d%% | %02d:%02d",percentaje, cur_min, cur_sec);
}
fflush (stdout);
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###PROGRESS#%d#%d#%d\n", percentaje, cur_min, cur_sec);
fflush (stderr);
}
if (!ccx_options.no_progress_bar)
{
if (percentage==-1)
mprint ("\rStreaming | %02d:%02d", cur_min, cur_sec);
else
mprint ("\r%3d%% | %02d:%02d",percentage, cur_min, cur_sec);
}
fflush (stdout);
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###PROGRESS#%d#%d#%d\n", percentage, cur_min, cur_sec);
fflush (stderr);
}
}
void activity_input_file_open (const char *filename)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
fflush (stderr);
}
}
void activity_library_process(enum ccx_common_logging_gui message_type, ...){
void activity_library_process(enum ccx_common_logging_gui message_type, ...)
{
if (ccx_options.gui_mode_reports){
va_list args;
va_start(args, message_type);
switch (message_type)
{
case CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS:
vfprintf(stderr, "###XDSNETWORKCALLLETTERS#%s\n",args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION:
vfprintf(stderr, "###XDSPROGRAMDESC#%d#%s\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR:
vfprintf(stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME:
vfprintf(stderr, "###XDSPROGRAMNAME#%s\n", args);
break;
default:
break;
case CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS:
vfprintf(stderr, "###XDSNETWORKCALLLETTERS#%s\n",args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION:
vfprintf(stderr, "###XDSPROGRAMDESC#%d#%s\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR:
vfprintf(stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME:
vfprintf(stderr, "###XDSPROGRAMNAME#%s\n", args);
break;
default:
break;
}
fflush(stderr);
va_end(args);
@@ -61,65 +62,65 @@ void activity_library_process(enum ccx_common_logging_gui message_type, ...){
}
void activity_video_info (int hor_size,int vert_size,
const char *aspect_ratio, const char *framerate)
const char *aspect_ratio, const char *framerate)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
hor_size,vert_size, aspect_ratio, framerate);
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
hor_size,vert_size, aspect_ratio, framerate);
fflush (stderr);
}
}
void activity_message (const char *fmt, ...)
{
if (ccx_options.gui_mode_reports)
{
va_list args;
fprintf (stderr, "###MESSAGE#");
va_start(args, fmt);
fprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
va_list args;
fprintf (stderr, "###MESSAGE#");
va_start(args, fmt);
fprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
fflush (stderr);
}
}
void activity_input_file_closed (void)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILECLOSED\n");
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILECLOSED\n");
fflush (stderr);
}
}
void activity_program_number (unsigned program_number)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n",program_number);
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n", program_number);
fflush (stderr);
}
}
void activity_report_version (void)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###VERSION#CCExtractor#%s\n",VERSION);
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###VERSION#CCExtractor#%s\n", VERSION);
fflush (stderr);
}
}
void activity_report_data_read (void)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###DATAREAD#%lu\n",net_activity_gui/1000);
fflush (stderr);
}
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###DATAREAD#%lu\n", net_activity_gui/1000);
fflush (stderr);
}
}
@@ -127,7 +128,7 @@ void activity_header (void)
{
if (!credits_shown)
{
credits_shown=1;
credits_shown = 1;
mprint ("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION);
mprint ("Teletext portions taken from Petr Kutalek's telxcc\n");
mprint ("--------------------------------------------------------------------------\n");

17
src/lib_ccx/activity.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef ACTIVITY_H
#define ACTIVITY_H
extern unsigned long net_activity_gui;
void activity_header (void);
void activity_progress (int percentaje, int cur_min, int cur_sec);
void activity_report_version (void);
void activity_input_file_closed (void);
void activity_input_file_open (const char *filename);
void activity_message (const char *fmt, ...);
void activity_video_info (int hor_size,int vert_size,
const char *aspect_ratio, const char *framerate);
void activity_program_number (unsigned program_number);
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
void activity_report_data_read (void);
#endif

View File

@@ -85,10 +85,10 @@ typedef struct {
// Payload parsing information
int MultiplePayloads; // ASF
int PacketLType; // ASF
int ReplicatedLType; // ASF
int OffsetMediaLType; // ASF
int MediaNumberLType; // ASF
int StreamNumberLType; // ASF
int ReplicatedLType; // ASF
int OffsetMediaLType; // ASF
int MediaNumberLType; // ASF
int StreamNumberLType; // ASF
uint32_t PacketLength;
uint32_t PaddingLength;
} asf_data;
} asf_data;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
#ifndef AVC_FUNCTION_H
#define AVC_FUNCTION_H
struct avc_ctx
{
unsigned char cc_count;
// buffer to hold cc data
unsigned char *cc_data;
long cc_databufsize;
int cc_buffer_saved; // Was the CC buffer saved after it was last updated?
int got_seq_para;
unsigned nal_ref_idc;
LLONG seq_parameter_set_id;
int log2_max_frame_num;
int pic_order_cnt_type;
int log2_max_pic_order_cnt_lsb;
int frame_mbs_only_flag;
// Use and throw stats for debug, remove this uglyness soon
long num_nal_unit_type_7;
long num_vcl_hrd;
long num_nal_hrd;
long num_jump_in_frames;
long num_unexpected_sei_length;
int ccblocks_in_avc_total;
int ccblocks_in_avc_lost;
LLONG frame_num;
LLONG lastframe_num;
int currref;
int maxidx;
int lastmaxidx;
// Used to find tref zero in PTS mode
int minidx;
int lastminidx;
// Used to remember the max temporal reference number (poc mode)
int maxtref;
int last_gop_maxtref;
// Used for PTS ordering of CC blocks
LLONG currefpts;
LLONG last_pic_order_cnt_lsb;
LLONG last_slice_pts;
};
struct avc_ctx *init_avc(void);
void dinit_avc(struct avc_ctx **ctx);
void do_NAL (struct lib_cc_decode *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub);
size_t process_avc(struct lib_cc_decode *ctx, unsigned char *avcbuf, size_t avcbuflen, struct cc_subtitle *sub);
#endif

View File

@@ -9,22 +9,22 @@
// end is used to check that nothing is read at "end" or after it.
struct bitstream
{
unsigned char *pos;
int bpos;
unsigned char *end;
// Indicate how many bits are left in the stream after the previous
// read call. A negative number indicates that a read after the
// end of the stream was attempted.
int64_t bitsleft;
// Indicate an error occured while parsing the bitstream.
// This is meant to store high level syntax errors, i.e a function
// using the bitstream functions found a syntax error.
int error;
// Internal (private) variable - used to store the the bitstream
// position until it is decided if the bitstream pointer will be
// increased by the calling function, or not.
unsigned char *_i_pos;
int _i_bpos;
unsigned char *pos;
int bpos;
unsigned char *end;
// Indicate how many bits are left in the stream after the previous
// read call. A negative number indicates that a read after the
// end of the stream was attempted.
int64_t bitsleft;
// Indicate an error occured while parsing the bitstream.
// This is meant to store high level syntax errors, i.e a function
// using the bitstream functions found a syntax error.
int error;
// Internal (private) variable - used to store the the bitstream
// position until it is decided if the bitstream pointer will be
// increased by the calling function, or not.
unsigned char *_i_pos;
int _i_bpos;
};
#define read_u8(bstream) (uint8_t)bitstream_get_num(bstream,1,1)

View File

@@ -14,17 +14,17 @@
int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *end)
{
bstr->pos = start;
bstr->bpos = 8;
bstr->end = end;
bstr->bitsleft = (bstr->end - bstr->pos)*8;
bstr->error = 0;
bstr->_i_pos = NULL;
bstr->_i_bpos = 0;
bstr->bpos = 8;
bstr->end = end;
bstr->bitsleft = (bstr->end - bstr->pos)*8;
bstr->error = 0;
bstr->_i_pos = NULL;
bstr->_i_bpos = 0;
if(bstr->bitsleft < 0)
if(bstr->bitsleft < 0)
{
// See if we can somehow recover of this disaster by reporting the problem instead of terminating.
mprint ( "init_bitstream: bitstream has negative length!");
mprint ( "init_bitstream: bitstream has negative length!");
return 1;
}
return 0;
@@ -37,70 +37,70 @@ int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *
// there are not enough bits left in the bitstream.
uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
{
uint64_t res = 0;
uint64_t res = 0;
if(bnum > 64)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
if(bnum > 64)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
// Keep a negative bitstream.bitsleft, but correct it.
if (bstr->bitsleft <= 0)
{
bstr->bitsleft -= bnum;
return 0;
}
// Keep a negative bitstream.bitsleft, but correct it.
if (bstr->bitsleft <= 0)
{
bstr->bitsleft -= bnum;
return 0;
}
// Calculate the remaining number of bits in bitstream after reading.
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
if (bstr->bitsleft < 0)
return 0;
// Calculate the remaining number of bits in bitstream after reading.
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
if (bstr->bitsleft < 0)
return 0;
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 0;
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 0;
int vbit = bstr->bpos;
unsigned char *vpos = bstr->pos;
int vbit = bstr->bpos;
unsigned char *vpos = bstr->pos;
if(vbit < 1 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
}
if(vbit < 1 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
}
while( 1 )
{
if(vpos >= bstr->end)
{
// We should not get here ...
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
}
while( 1 )
{
if(vpos >= bstr->end)
{
// We should not get here ...
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
}
res |= (*vpos & (0x01 << (vbit-1)) ? 1 : 0);
vbit--;
bnum--;
res |= (*vpos & (0x01 << (vbit-1)) ? 1 : 0);
vbit--;
bnum--;
if(vbit == 0)
{
vpos++;
vbit = 8;
}
if(vbit == 0)
{
vpos++;
vbit = 8;
}
if(bnum)
{
res <<= 1;
}
else
break;
}
if(bnum)
{
res <<= 1;
}
else
break;
}
// Remember the bitstream position
bstr->_i_bpos = vbit;
bstr->_i_pos = vpos;
// Remember the bitstream position
bstr->_i_bpos = vbit;
bstr->_i_pos = vpos;
return res;
return res;
}
@@ -108,18 +108,18 @@ uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
// bit read first. A 64 bit unsigned integer is returned.
uint64_t read_bits(struct bitstream *bstr, unsigned bnum)
{
uint64_t res = next_bits(bstr, bnum);
uint64_t res = next_bits(bstr, bnum);
// Special case for reading zero bits. Also abort when not enough
// bits are left. Return zero
if(bnum == 0 || bstr->bitsleft < 0)
return 0;
// Special case for reading zero bits. Also abort when not enough
// bits are left. Return zero
if(bnum == 0 || bstr->bitsleft < 0)
return 0;
// Advance the bitstream
bstr->bpos = bstr->_i_bpos;
bstr->pos = bstr->_i_pos;
// Advance the bitstream
bstr->bpos = bstr->_i_bpos;
bstr->pos = bstr->_i_pos;
return res;
return res;
}
@@ -128,35 +128,35 @@ uint64_t read_bits(struct bitstream *bstr, unsigned bnum)
// Return TRUE when successfull, otherwise FALSE
int skip_bits(struct bitstream *bstr, unsigned bnum)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
bstr->bitsleft -= bnum;
return 0;
}
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
bstr->bitsleft -= bnum;
return 0;
}
// Calculate the remaining number of bits in bitstream after reading.
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
if (bstr->bitsleft < 0)
return 0;
// Calculate the remaining number of bits in bitstream after reading.
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
if (bstr->bitsleft < 0)
return 0;
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 1;
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 1;
bstr->bpos -= bnum%8;
bstr->pos += bnum/8;
bstr->bpos -= bnum%8;
bstr->pos += bnum/8;
if (bstr->bpos < 1)
{
bstr->bpos += 8;
bstr->pos += 1;
}
return 1;
if (bstr->bpos < 1)
{
bstr->bpos += 8;
bstr->pos += 1;
}
return 1;
}
@@ -165,55 +165,55 @@ int skip_bits(struct bitstream *bstr, unsigned bnum)
// a byte, otherwise return FALSE
int is_byte_aligned(struct bitstream *bstr)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
int vbit = bstr->bpos;
int vbit = bstr->bpos;
if(vbit == 0 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
}
if(vbit == 0 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
}
if (vbit == 8)
return 1;
else
return 0;
if (vbit == 8)
return 1;
else
return 0;
}
// Move bitstream to next byte border. Adjust bitsleft.
void make_byte_aligned(struct bitstream *bstr)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
int vbit = bstr->bpos;
int vbit = bstr->bpos;
if(vbit == 0 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
}
if(vbit == 0 || vbit > 8)
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
}
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
// Pay attention to the bit alignment
bstr->bitsleft = (bstr->bitsleft-7)/8 *8;
return;
}
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
// Pay attention to the bit alignment
bstr->bitsleft = (bstr->bitsleft-7)/8 *8;
return;
}
if(bstr->bpos != 8)
{
bstr->bpos = 8;
bstr->pos += 1;
}
// Reset, in case a next_???() function was used before
bstr->bitsleft = 0LL + 8*(bstr->end-bstr->pos-1)+bstr->bpos;
if(bstr->bpos != 8)
{
bstr->bpos = 8;
bstr->pos += 1;
}
// Reset, in case a next_???() function was used before
bstr->bitsleft = 0LL + 8*(bstr->end-bstr->pos-1)+bstr->bpos;
return;
return;
}
@@ -224,27 +224,27 @@ void make_byte_aligned(struct bitstream *bstr)
// This function does not advance the bitstream pointer.
unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
bstr->bitsleft -= bynum*8;
return NULL;
}
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
{
bstr->bitsleft -= bynum*8;
return NULL;
}
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bynum*8;
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bynum*8;
if (!is_byte_aligned(bstr) || bstr->bitsleft < 0 || bynum < 1)
return NULL;
if (!is_byte_aligned(bstr) || bstr->bitsleft < 0 || bynum < 1)
return NULL;
// Remember the bitstream position
bstr->_i_bpos = 8;
bstr->_i_pos = bstr->pos + bynum;
// Remember the bitstream position
bstr->_i_bpos = 8;
bstr->_i_pos = bstr->pos + bynum;
return bstr->pos;
return bstr->pos;
}
@@ -255,15 +255,15 @@ unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum)
// This function does advance the bitstream pointer.
unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum)
{
unsigned char *res = next_bytes(bstr, bynum);
unsigned char *res = next_bytes(bstr, bynum);
// Advance the bitstream when a read was possible
if(res)
{
bstr->bpos = bstr->_i_bpos;
bstr->pos = bstr->_i_pos;
}
return res;
// Advance the bitstream when a read was possible
if(res)
{
bstr->bpos = bstr->_i_bpos;
bstr->pos = bstr->_i_pos;
}
return res;
}
@@ -275,19 +275,19 @@ unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum)
// little-endian and big-endian CPUs.
uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
{
void *bpos;
uint64_t rval=0;
void *bpos;
uint64_t rval=0;
if (advance)
bpos = read_bytes(bstr, bytes);
else
bpos = next_bytes(bstr, bytes);
if (advance)
bpos = read_bytes(bstr, bytes);
else
bpos = next_bytes(bstr, bytes);
if (!bpos)
return 0;
if (!bpos)
return 0;
switch (bytes)
{
switch (bytes)
{
case 1:
case 2:
case 4:
@@ -295,47 +295,47 @@ uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
break;
default:
fatal (CCX_COMMON_EXIT_BUG_BUG, "bitstream_get_num: Illegal precision value [%u]!",
bytes);
bytes);
break;
}
}
for (unsigned i=0;i<bytes;i++)
{
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
unsigned char uc=*ucpos;
rval=(rval<<8) + uc;
}
return rval;
return rval;
}
// Read unsigned Exp-Golomb code from bitstream
uint64_t ue(struct bitstream *bstr)
{
uint64_t res = 0;
int zeros=0;
uint64_t res = 0;
int zeros=0;
while(!read_bits(bstr,1))
zeros++;
while(!read_bits(bstr,1))
zeros++;
res = (0x01 << zeros) - 1 + read_bits(bstr,zeros);
res = (0x01 << zeros) - 1 + read_bits(bstr,zeros);
return res;
return res;
}
// Read signed Exp-Golomb code from bitstream
int64_t se(struct bitstream *bstr)
{
int64_t res = 0;
int64_t res = 0;
res = ue(bstr);
res = ue(bstr);
// The following function might truncate when res+1 overflows
//res = (res+1)/2 * (res % 2 ? 1 : -1);
// Use this:
res = (res/2+(res%2 ? 1 : 0)) * (res % 2 ? 1 : -1);
// The following function might truncate when res+1 overflows
//res = (res+1)/2 * (res % 2 ? 1 : -1);
// Use this:
res = (res/2+(res%2 ? 1 : 0)) * (res % 2 ? 1 : -1);
return res;
return res;
}
@@ -343,33 +343,33 @@ int64_t se(struct bitstream *bstr)
// alias for read_bits().
uint64_t u(struct bitstream *bstr, unsigned bnum)
{
return read_bits(bstr, bnum);
return read_bits(bstr, bnum);
}
// Read signed integer with bnum bits length.
int64_t i(struct bitstream *bstr, unsigned bnum)
{
uint64_t res = read_bits(bstr, bnum);
uint64_t res = read_bits(bstr, bnum);
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 0;
// Special case for reading zero bits. Return zero
if(bnum == 0)
return 0;
return (0xFFFFFFFFFFFFFFFFULL << bnum) | res;
return (0xFFFFFFFFFFFFFFFFULL << bnum) | res;
}
// Return the value with the bit order reversed.
uint8_t reverse8(uint8_t data)
{
uint8_t res = 0;
uint8_t res = 0;
for (int k=0;k<8;k++)
{
res <<= 1;
res |= (data & (0x01 << k) ? 1 : 0);
}
for (int k=0;k<8;k++)
{
res <<= 1;
res |= (data & (0x01 << k) ? 1 : 0);
}
return res;
return res;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
#include "ccx_common_common.h"
int cc608_parity_table[256];
/* printf() for fd instead of FILE*, since dprintf is not portable */
void fdprintf(int fd, const char *fmt, ...)
{
@@ -36,7 +38,8 @@ void fdprintf(int fd, const char *fmt, ...)
free(p);
return;
}
else {
else
{
p = np;
}
}
@@ -63,3 +66,63 @@ void freep(void *arg)
*ptr = NULL;
}
int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
LLONG end_time, char *info, char *mode, enum ccx_encoding_type e_type)
{
if (sub->nb_data)
{
for(;sub->next;sub = sub->next);
sub->next = malloc(sizeof(struct cc_subtitle));
if(!sub->next)
return -1;
sub->next->prev = sub;
sub = sub->next;
}
sub->type = CC_TEXT;
sub->enc_type = e_type;
sub->data = strdup(str);
sub->nb_data = strlen(str);
sub->start_time = start_time;
sub->end_time = end_time;
if(info)
strncpy(sub->info, info, 4);
if(mode)
strncpy(sub->mode, mode, 4);
sub->got_output = 1;
sub->next = NULL;
return 0;
}
int cc608_parity(unsigned int byte)
{
int ones = 0;
for (int i = 0; i < 7; i++)
{
if (byte & (1 << i))
ones++;
}
return ones & 1;
}
void cc608_build_parity_table(int *parity_table)
{
unsigned int byte;
int parity_v;
for (byte = 0; byte <= 127; byte++)
{
parity_v = cc608_parity(byte);
/* CC uses odd parity (i.e., # of 1's in byte is odd.) */
parity_table[byte] = parity_v;
parity_table[byte | 0x80] = !parity_v;
}
}
void build_parity_table (void)
{
cc608_build_parity_table(cc608_parity_table);
}

View File

@@ -2,12 +2,40 @@
#define _CC_COMMON_COMMON
#include "ccx_common_platform.h"
#include "ccx_common_structs.h"
// Define possible exit codes that will be passed on to the fatal function
#define CCX_COMMON_EXIT_FILE_CREATION_FAILED 5
#define CCX_COMMON_EXIT_UNSUPPORTED 9
#define EXIT_NOT_ENOUGH_MEMORY 500
#define CCX_COMMON_EXIT_BUG_BUG 1000
/* Exit codes. Take this seriously as the GUI depends on them.
0 means OK as usual,
<100 means display whatever was output to stderr as a warning
>=100 means display whatever was output to stdout as an error
*/
#define EXIT_OK 0
#define EXIT_NO_INPUT_FILES 2
#define EXIT_TOO_MANY_INPUT_FILES 3
#define EXIT_INCOMPATIBLE_PARAMETERS 4
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
#define EXIT_MALFORMED_PARAMETER 7
#define EXIT_READ_ERROR 8
#define EXIT_NOT_CLASSIFIED 300
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
#define EXIT_BUFFER_FULL 502
#define EXIT_MISSING_ASF_HEADER 1001
#define EXIT_MISSING_RCWT_HEADER 1002
#define CCX_COMMON_EXIT_FILE_CREATION_FAILED 5
#define CCX_COMMON_EXIT_UNSUPPORTED 9
#define EXIT_NOT_ENOUGH_MEMORY 500
#define CCX_COMMON_EXIT_BUG_BUG 1000
#define CCX_OK 0
#define CCX_FALSE 0
#define CCX_TRUE 1
#define CCX_EAGAIN -100
#define CCX_EOF -101
#define CCX_EINVAL -102
#define CCX_ENOSUPP -103
#define CCX_ENOMEM -104
// Declarations
void fdprintf(int fd, const char *fmt, ...);
@@ -15,6 +43,8 @@ void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds,
void freep(void *arg);
void dbg_print(LLONG mask, const char *fmt, ...);
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
LLONG end_time, char *info, char *mode, enum ccx_encoding_type);
extern int cc608_parity_table[256]; // From myth
#endif

View File

@@ -24,104 +24,104 @@ const unsigned char lc6[1]={0xfe};
const double framerates_values[16]=
{
0,
24000.0/1001, /* 23.976 */
24.0,
25.0,
30000.0/1001, /* 29.97 */
30.0,
50.0,
60000.0/1001, /* 59.94 */
60.0,
0,
0,
0,
0,
0
0,
24000.0/1001, /* 23.976 */
24.0,
25.0,
30000.0/1001, /* 29.97 */
30.0,
50.0,
60000.0/1001, /* 59.94 */
60.0,
0,
0,
0,
0,
0
};
const char *framerates_types[16]=
{
"00 - forbidden",
"01 - 23.976",
"02 - 24",
"03 - 25",
"04 - 29.97",
"05 - 30",
"06 - 50",
"07 - 59.94",
"08 - 60",
"09 - reserved",
"10 - reserved",
"11 - reserved",
"12 - reserved",
"13 - reserved",
"14 - reserved",
"15 - reserved"
"00 - forbidden",
"01 - 23.976",
"02 - 24",
"03 - 25",
"04 - 29.97",
"05 - 30",
"06 - 50",
"07 - 59.94",
"08 - 60",
"09 - reserved",
"10 - reserved",
"11 - reserved",
"12 - reserved",
"13 - reserved",
"14 - reserved",
"15 - reserved"
};
const char *aspect_ratio_types[16]=
{
"00 - forbidden",
"01 - 1:1",
"02 - 4:3",
"03 - 16:9",
"04 - 2.21:1",
"05 - reserved",
"06 - reserved",
"07 - reserved",
"08 - reserved",
"09 - reserved",
"10 - reserved",
"11 - reserved",
"12 - reserved",
"13 - reserved",
"14 - reserved",
"15 - reserved"
"00 - forbidden",
"01 - 1:1",
"02 - 4:3",
"03 - 16:9",
"04 - 2.21:1",
"05 - reserved",
"06 - reserved",
"07 - reserved",
"08 - reserved",
"09 - reserved",
"10 - reserved",
"11 - reserved",
"12 - reserved",
"13 - reserved",
"14 - reserved",
"15 - reserved"
};
const char *pict_types[8]=
{
"00 - ilegal (0)",
"01 - I",
"02 - P",
"03 - B",
"04 - ilegal (D)",
"05 - ilegal (5)",
"06 - ilegal (6)",
"07 - ilegal (7)"
"00 - ilegal (0)",
"01 - I",
"02 - P",
"03 - B",
"04 - ilegal (D)",
"05 - ilegal (5)",
"06 - ilegal (6)",
"07 - ilegal (7)"
};
const char *slice_types[10]=
{
"0 - P",
"1 - B",
"2 - I",
"3 - SP",
"4 - SI",
"5 - P",
"6 - B",
"7 - I",
"8 - SP",
"9 - SI"
"0 - P",
"1 - B",
"2 - I",
"3 - SP",
"4 - SI",
"5 - P",
"6 - B",
"7 - I",
"8 - SP",
"9 - SI"
};
const char *cc_types[4] =
{
"NTSC line 21 field 1 closed captions",
"NTSC line 21 field 2 closed captions",
"DTVCC Channel Packet Data",
"DTVCC Channel Packet Start"
"NTSC line 21 field 1 closed captions",
"NTSC line 21 field 2 closed captions",
"DTVCC Channel Packet Data",
"DTVCC Channel Packet Start"
};
enum
{
NTSC_CC_f1 = 0,
NTSC_CC_f2 = 1,
DTVCC_PACKET_DATA = 2,
DTVCC_PACKET_START = 3,
NTSC_CC_f1 = 0,
NTSC_CC_f2 = 1,
DTVCC_PACKET_DATA = 2,
DTVCC_PACKET_START = 3,
};
/**

View File

@@ -36,6 +36,7 @@ extern unsigned char rcwt_header[11];
#define TS_PACKET_PAYLOAD_LENGTH 184 // From specs
#define SUBLINESIZE 2048 // Max. length of a .srt line - TODO: Get rid of this
#define STARTBYTESLENGTH (1024*1024)
#define UTF8_MAX_BYTES 6
#define XMLRPC_CHUNK_SIZE (64*1024) // 64 Kb per chunk, to avoid too many realloc()
@@ -56,6 +57,7 @@ enum ccx_debug_message_types
CCX_DMT_PAT=0x400, // Program Allocation Table dump
CCX_DMT_PMT=0x800, // Program Map Table dump
CCX_DMT_LEVENSHTEIN=0x1000, // Levenshtein distance calculations
CCX_DMT_DUMPDEF=0x2000 // Dump defective TS packets
};
// AVC NAL types
@@ -98,12 +100,11 @@ enum ccx_avc_nal_types
// MPEG-2 TS stream types
enum ccx_stream_type
{
CCX_STREAM_TYPE_UNKNOWNSTREAM = 0,
CCX_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
CCX_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
CCX_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
CCX_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
CCX_STREAM_TYPE_UNKNOWNSTREAM = 0,
CCX_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
CCX_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
CCX_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
CCX_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
CCX_STREAM_TYPE_PRIVATE_TABLE_MPEG2 = 0x05,
CCX_STREAM_TYPE_PRIVATE_MPEG2 = 0x06,
CCX_STREAM_TYPE_MHEG_PACKETS = 0x07,
@@ -113,13 +114,13 @@ enum ccx_stream_type
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_B = 0x0B,
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_C = 0x0C,
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_D = 0x0D,
CCX_STREAM_TYPE_AUDIO_AAC = 0x0f,
CCX_STREAM_TYPE_VIDEO_MPEG4 = 0x10,
CCX_STREAM_TYPE_VIDEO_H264 = 0x1b,
CCX_STREAM_TYPE_AUDIO_AAC = 0x0f,
CCX_STREAM_TYPE_VIDEO_MPEG4 = 0x10,
CCX_STREAM_TYPE_VIDEO_H264 = 0x1b,
CCX_STREAM_TYPE_PRIVATE_USER_MPEG2=0x80,
CCX_STREAM_TYPE_AUDIO_AC3 = 0x81,
CCX_STREAM_TYPE_AUDIO_HDMV_DTS = 0x82,
CCX_STREAM_TYPE_AUDIO_DTS = 0x8a,
CCX_STREAM_TYPE_AUDIO_AC3 = 0x81,
CCX_STREAM_TYPE_AUDIO_HDMV_DTS = 0x82,
CCX_STREAM_TYPE_AUDIO_DTS = 0x8a,
};
enum ccx_mpeg_descriptor
@@ -131,6 +132,7 @@ enum ccx_mpeg_descriptor
CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR = 0x46,
CCX_MPEG_DSC_TELETEXT_DESCRIPTOR = 0x56,
CCX_MPEG_DSC_DVB_SUBTITLE = 0x59,
CCX_MPEG_DSC_CAPTION_SERVICE = 0x86,
CCX_MPEG_DESC_DATA_COMP = 0xfd,
};
@@ -152,15 +154,17 @@ enum ccx_datasource
enum ccx_output_format
{
CCX_OF_RAW = 0,
CCX_OF_SRT = 1,
CCX_OF_SAMI = 2,
CCX_OF_TRANSCRIPT = 3,
CCX_OF_RCWT = 4,
CCX_OF_RAW = 0,
CCX_OF_SRT = 1,
CCX_OF_SAMI = 2,
CCX_OF_TRANSCRIPT = 3,
CCX_OF_RCWT = 4,
CCX_OF_NULL = 5,
CCX_OF_SMPTETT = 6,
CCX_OF_SPUPNG = 7,
CCX_OF_SPUPNG = 7,
CCX_OF_DVDRAW = 8, // See -d at http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML#CCExtract
CCX_OF_WEBVTT = 9,
CCX_OF_SIMPLE_XML = 10,
};
enum ccx_output_date_format
@@ -174,47 +178,49 @@ enum ccx_output_date_format
enum ccx_stream_mode_enum
{
CCX_SM_ELEMENTARY_OR_NOT_FOUND=0,
CCX_SM_TRANSPORT=1,
CCX_SM_PROGRAM=2,
CCX_SM_ASF=3,
CCX_SM_MCPOODLESRAW = 4,
CCX_SM_RCWT = 5, // Raw Captions With Time, not used yet.
CCX_SM_MYTH = 6, // Use the myth loop
CCX_SM_ELEMENTARY_OR_NOT_FOUND=0,
CCX_SM_TRANSPORT=1,
CCX_SM_PROGRAM=2,
CCX_SM_ASF=3,
CCX_SM_MCPOODLESRAW = 4,
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
CCX_SM_WTV = 9,
CCX_SM_AUTODETECT = 16
};
enum ccx_encoding_type
{
CCX_ENC_UNICODE = 0,
CCX_ENC_LATIN_1 = 1,
CCX_ENC_UTF_8 = 2
CCX_ENC_UNICODE = 0,
CCX_ENC_LATIN_1 = 1,
CCX_ENC_UTF_8 = 2,
CCX_ENC_ASCII = 3
};
enum ccx_bufferdata_type
{
CCX_UNKNOWN = 0,
CCX_PES = 1,
CCX_RAW = 2,
CCX_H264 = 3,
CCX_UNKNOWN = 0,
CCX_PES = 1,
CCX_RAW = 2,
CCX_H264 = 3,
CCX_HAUPPAGE = 4,
CCX_TELETEXT = 5,
CCX_PRIVATE_MPEG2_CC = 6,
CCX_DVB_SUBTITLE = 7,
CCX_ISDB_SUBTITLE = 8,
};
enum ccx_frame_type
{
CCX_FRAME_TYPE_RESET_OR_UNKNOWN = 0,
CCX_FRAME_TYPE_I_FRAME = 1,
CCX_FRAME_TYPE_P_FRAME = 2,
CCX_FRAME_TYPE_B_FRAME = 3,
CCX_FRAME_TYPE_D_FRAME = 4
CCX_FRAME_TYPE_RESET_OR_UNKNOWN = 0,
CCX_FRAME_TYPE_I_FRAME = 1,
CCX_FRAME_TYPE_P_FRAME = 2,
CCX_FRAME_TYPE_B_FRAME = 3,
CCX_FRAME_TYPE_D_FRAME = 4
};
typedef enum {
@@ -229,8 +235,17 @@ enum ccx_code_type
CCX_CODEC_TELETEXT,
CCX_CODEC_DVB,
CCX_CODEC_ISDB_CC,
CCX_CODEC_ATSC_CC,
CCX_CODEC_NONE,
};
enum cdp_section_type
{
CDP_SECTION_DATA = 0x72,
CDP_SECTION_SVC_INFO = 0x73,
CDP_SECTION_FOOTER = 0x74
};
/*
* This Macro check whether descriptor tag is valid for teletext
* codec or not.
@@ -242,15 +257,15 @@ enum ccx_code_type
*/
#define IS_VALID_TELETEXT_DESC(desc) ( ((desc) == CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR )|| \
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
/*
* This macro to be used when you want to find out whether you
* should parse f_sel subtitle codec type or not
*
* @param u_sel pass the codec selected by user to be searched in
* all elementry stream, we ignore the not to be selected stream
* all elementary stream, we ignore the not to be selected stream
* if we find stream this is selected stream. since setting
* selected stream and not selected to same codec does not
* make ay sense.
@@ -263,10 +278,18 @@ enum ccx_code_type
* to parse.
*/
#define IS_FEASIBLE(u_sel,u_nsel,f_sel) ( ( (u_sel) == CCX_CODEC_ANY && (u_nsel) != (f_sel) ) || (u_sel) == (f_sel) )
#define CCX_TXT_FORBIDDEN 0 // Ignore teletext packets
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
#define CCX_TXT_FORBIDDEN 0 // Ignore teletext packets
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
#define NB_LANGUAGE 5
extern const char *language[NB_LANGUAGE];
#define DEF_VAL_STARTCREDITSNOTBEFORE "0"
// To catch the theme after the teaser in TV shows
#define DEF_VAL_STARTCREDITSNOTAFTER "5:00"
#define DEF_VAL_STARTCREDITSFORATLEAST "2"
#define DEF_VAL_STARTCREDITSFORATMOST "5"
#define DEF_VAL_ENDCREDITSFORATLEAST "2"
#define DEF_VAL_ENDCREDITSFORATMOST "5"
#endif

View File

@@ -1,22 +1,20 @@
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_708.h"
#include "utility.h"
struct ccx_s_options ccx_options;
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
/* Parameters */
void init_options (struct ccx_s_options *options)
{
#ifdef _WIN32
options->buffer_input = 1; // In Windows buffering seems to help
options->no_bom = 0;
#else
options->buffer_input = 0; // In linux, not so much.
options->no_bom = 1;
#endif
options->nofontcolor=0; // 1 = don't put <font color> tags
options->notypesetting=0; // 1 = Don't put <i>, <u>, etc typesetting tags
options->no_bom = 0; // Use BOM by default.
options->settings_608.direct_rollup = 0;
options->settings_608.no_rollup = 0;
@@ -24,22 +22,15 @@ void init_options (struct ccx_s_options *options)
options->settings_608.screens_to_process = -1;
options->settings_608.default_color = COL_TRANSPARENT; // Defaults to transparant/no-color.
/* Select subtitle codec */
options->codec = CCX_CODEC_ANY;
options->nocodec = CCX_CODEC_NONE;
/* Credit stuff */
options->start_credits_text=NULL;
options->end_credits_text=NULL;
options->extract = 1; // Extract 1st field only (primary language)
options->cc_channel = 1; // Channel we want to dump in srt mode
options->binary_concat=1; // Disabled by -ve or --videoedited
options->use_gop_as_pts = 0; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
options->fix_padding = 0; // Replace 0000 with 8080 in HDTV (needed for some cards)
options->trim_subs=0; // " Remove spaces at sides? "
options->gui_mode_reports=0; // If 1, output in stderr progress updates so the GUI can grab them
options->no_progress_bar=0; // If 1, suppress the output of the progress to stdout
options->sentence_cap =0 ; // FIX CASE? = Fix case?
options->enc_cfg.sentence_cap =0 ; // FIX CASE? = Fix case?
options->sentence_cap_file=NULL; // Extra words file?
options->live_stream=0; // 0 -> A regular file
options->messages_target=1; // 1=stdout
@@ -58,30 +49,19 @@ void init_options (struct ccx_s_options *options)
options->mp4vidtrack=0; // Process the video track even if a CC dedicated track exists.
/* General stuff */
options->usepicorder = 0; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
options->autodash=0; // Add dashes (-) before each speaker automatically?
options->xmltv=0; // 1 = full output. 2 = live output. 3 = both
options->xmltvliveinterval=10; // interval in seconds between writting xmltv output files in live mode
options->xmltvoutputinterval=0; // interval in seconds between writting xmltv full file output
options->xmltvonlycurrent=0; // 0 off 1 on
options->teletext_mode=CCX_TXT_AUTO_NOT_YET_FOUND; // 0=Disabled, 1 = Not found, 2=Found
options->transcript_settings = ccx_encoders_default_transcript_settings;
options->millis_separator=',';
options->encoding = CCX_ENC_UTF_8;
options->write_format=CCX_OF_SRT; // 0=Raw, 1=srt, 2=SMI
options->date_format=ODF_NONE;
options->output_filename=NULL;
options->out_elementarystream_filename=NULL;
options->output_filename = NULL;
options->debug_mask=CCX_DMT_GENERIC_NOTICES; // dbg_print will use this mask to print or ignore different types
options->debug_mask_on_debug=CCX_DMT_VERBOSE; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
options->ts_autoprogram =0; // Try to find a stream with captions automatically (no -pn needed)
options->ts_cappid = 0; // PID for stream that holds caption information
options->ts_forced_cappid = 0; // If 1, never mess with the selected PID
options->ts_forced_program=0; // Specific program to process in TS files, if ts_forced_program_selected==1
options->ts_forced_program_selected=0;
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 = NULL;
options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files.
@@ -91,20 +71,62 @@ void init_options (struct ccx_s_options *options)
options->tcp_desc = 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
options->auto_stream = CCX_SM_AUTODETECT;
options->m2ts = 0;
options->multiprogram = 0;
options->out_interval = -1;
options->subs_delay = 0;
/* Select subtitle codec */
options->demux_cfg.codec = CCX_CODEC_ANY;
options->demux_cfg.nocodec = CCX_CODEC_NONE;
options->demux_cfg.auto_stream = CCX_SM_AUTODETECT;
options->demux_cfg.m2ts = 0;
options->demux_cfg.out_elementarystream_filename=NULL;
options->demux_cfg.ts_autoprogram =0; // Try to find a stream with captions automatically (no -pn needed)
options->demux_cfg.ts_cappids[0] = 0; // PID for stream that holds caption information
options->demux_cfg.nb_ts_cappid = 0;
options->demux_cfg.ts_forced_program = -1; // Specific program to process in TS files, if ts_forced_program_selected==1
options->demux_cfg.ts_forced_program_selected=0;
options->demux_cfg.ts_datastreamtype = CCX_STREAM_TYPE_UNKNOWNSTREAM; // User WANTED stream type (i.e. use the stream that has this type)
options->demux_cfg.ts_forced_streamtype=CCX_STREAM_TYPE_UNKNOWNSTREAM; // User selected (forced) stream type
options->enc_cfg.autodash=0; // Add dashes (-) before each speaker automatically?
options->enc_cfg.trim_subs=0; // " Remove spaces at sides? "
options->enc_cfg.in_format = 1;
options->enc_cfg.line_terminator_lf=0; // 0 = CRLF
options->enc_cfg.start_credits_text=NULL;
options->enc_cfg.end_credits_text=NULL;
options->enc_cfg.encoding = CCX_ENC_UTF_8;
options->enc_cfg.no_bom = 0; // Use BOM by default.
options->enc_cfg.services_charsets = NULL;
options->enc_cfg.all_services_charset = NULL;
options->settings_dtvcc.enabled = 0;
options->settings_dtvcc.active_services_count = 0;
options->settings_dtvcc.print_file_reports = 1;
options->settings_dtvcc.no_rollup = 0;
options->settings_dtvcc.report = NULL;
memset(options->settings_dtvcc.services_enabled, 0, CCX_DTVCC_MAX_SERVICES);
// Prepare time structures
init_boundary_time (&options->extraction_start);
init_boundary_time (&options->extraction_end);
init_boundary_time (&options->startcreditsnotbefore);
init_boundary_time (&options->startcreditsnotafter);
init_boundary_time (&options->startcreditsforatleast);
init_boundary_time (&options->startcreditsforatmost);
init_boundary_time (&options->endcreditsforatleast);
init_boundary_time (&options->endcreditsforatmost);
init_boundary_time (&options->enc_cfg.startcreditsnotbefore);
init_boundary_time (&options->enc_cfg.startcreditsnotafter);
init_boundary_time (&options->enc_cfg.startcreditsforatleast);
init_boundary_time (&options->enc_cfg.startcreditsforatmost);
init_boundary_time (&options->enc_cfg.endcreditsforatleast);
init_boundary_time (&options->enc_cfg.endcreditsforatmost);
// Sensible default values for credits
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &options->enc_cfg.startcreditsnotbefore);
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &options->enc_cfg.startcreditsnotafter);
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &options->enc_cfg.startcreditsforatleast);
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &options->enc_cfg.startcreditsforatmost);
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &options->enc_cfg.endcreditsforatleast);
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &options->enc_cfg.endcreditsforatmost);
}

View File

@@ -4,9 +4,72 @@
#include "ccx_common_timing.h"
#include "ccx_decoders_608.h"
#include "ccx_encoders_structs.h"
#include "list.h"
struct demuxer_cfg
{
int m2ts; // Regular TS or M2TS
enum ccx_stream_mode_enum auto_stream;
char *out_elementarystream_filename;
/* subtitle codec type */
enum ccx_code_type codec;
enum ccx_code_type nocodec;
unsigned ts_autoprogram; // Try to find a stream with captions automatically (no -pn needed)
unsigned ts_allprogram;
unsigned ts_cappids[128]; // PID for stream that holds caption information
int nb_ts_cappid;
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
int ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
unsigned ts_forced_program_selected;
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
};
struct encoder_cfg
{
int extract; // Extract 1st, 2nd or both fields
int dtvcc_extract; // 1 or 0
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
char *output_filename;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
enum ccx_encoding_type encoding;
enum ccx_output_date_format date_format;
char millis_separator;
int autodash; // Add dashes (-) before each speaker automatically?
int trim_subs; // " Remove spaces at sides? "
int sentence_cap ; // FIX CASE? = Fix case?
/* Credit stuff */
char *start_credits_text;
char *end_credits_text;
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
unsigned int send_to_srv;
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
char *first_input_file;
int multiple_files;
int no_font_color;
int no_type_setting;
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
int line_terminator_lf; // 0 = CRLF, 1=LF
LLONG subs_delay; // ms to delay (or advance) subs
int program_number;
unsigned char in_format;
//CEA-708
int services_enabled[CCX_DTVCC_MAX_SERVICES];
char** services_charsets;
char* all_services_charset;
};
struct ccx_s_options // Options from user parameters
{
int extract; // Extract 1st, 2nd or both fields
int no_rollup;
int cc_channel; // Channel we want to dump in srt mode
int buffer_input;
int nofontcolor;
@@ -14,26 +77,16 @@ struct ccx_s_options // Options from user parameters
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
int print_file_reports;
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
ccx_decoder_dtvcc_settings settings_dtvcc; //Same for 708 decoder
/* subtitle codec type */
enum ccx_code_type codec;
enum ccx_code_type nocodec;
/* Credit stuff */
char *start_credits_text;
char *end_credits_text;
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
char millis_separator;
int binary_concat; // Disabled by -ve or --videoedited
int use_gop_as_pts; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
int trim_subs; // " Remove spaces at sides? "
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
int no_progress_bar; // If 1, suppress the output of the progress to stdout
int sentence_cap ; // FIX CASE? = Fix case?
char *sentence_cap_file; // Extra words file?
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
0 -> A regular file
@@ -44,7 +97,7 @@ struct ccx_s_options // Options from user parameters
int investigate_packets; // Look for captions in all packets when everything else fails
int fullbin; // Disable pruning of padding cc blocks
int nosync; // Disable syncing
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
int wtvconvertfix; // Fix broken Windows 7 conversion
int wtvmpeg2;
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
@@ -52,50 +105,38 @@ struct ccx_s_options // Options from user parameters
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
/* General settings */
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
int autodash; // Add dashes (-) before each speaker automatically?
int xmltv; // 1 = full output. 2 = live output. 3 = both
int xmltvliveinterval; // interval in seconds between writting xmltv output files in live mode
int xmltvoutputinterval; // interval in seconds between writting xmltv full file output
int xmltvonlycurrent; // 0 off 1 on
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
char millis_separator;
enum ccx_encoding_type encoding;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
enum ccx_output_date_format date_format;
char *output_filename;
char *out_elementarystream_filename;
unsigned send_to_srv;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
LLONG debug_mask; // dbg_print will use this mask to print or ignore different types
LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
unsigned ts_autoprogram ; // Try to find a stream with captions automatically (no -pn needed)
unsigned ts_cappid ; // PID for stream that holds caption information
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
unsigned ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
unsigned ts_forced_program_selected;
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 */
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 *tcp_desc;
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
char *output_filename;
char **inputfile; // List of files to process
int num_input_files; // How many?
enum ccx_stream_mode_enum auto_stream;
int m2ts; // Regular TS or M2TS
struct demuxer_cfg demux_cfg;
struct encoder_cfg enc_cfg;
LLONG subs_delay; // ms to delay (or advance) subs
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
// Output structures
struct ccx_s_write wbout1;
struct ccx_s_write wbout2;
int multiprogram;
int out_interval;
};
extern struct ccx_s_options ccx_options;

View File

@@ -14,6 +14,8 @@
#define __STDC_FORMAT_MACROS
#ifdef _WIN32
#define inline _inline
#define typeof decltype
#include <io.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -110,4 +112,4 @@
typedef int64_t LLONG;
#endif // CCX_PLATFORM_H
#endif // CCX_PLATFORM_H

View File

@@ -1,6 +1,8 @@
#ifndef _CC_COMMON_STRUCTS
#define _CC_COMMON_STRUCTS
#include "ccx_common_constants.h"
enum ccx_common_logging_gui {
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME, // Called with xds_program_name
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR, // Called with current_xds_min, current_xds_hour, current_xds_date, current_xds_month
@@ -9,7 +11,7 @@ enum ccx_common_logging_gui {
};
struct ccx_common_logging_t {
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
LLONG debug_mask; // The debug mask that is used to determine if things should be printed or not.
void(*fatal_ftn) (int exit_code, const char *fmt, ...); // Used when an unrecoverable error happens. This should log output/save the error and then exit the program.
void(*debug_ftn) (LLONG mask, const char *fmt, ...); // Used to process debug output. Mask can be ignored (custom set by debug_mask).
void(*log_ftn)(const char *fmt, ...); // Used to print things. Replacement of standard printf, to allow more control.
@@ -21,33 +23,52 @@ enum subtype
{
CC_BITMAP,
CC_608,
CC_708,
CC_TEXT,
CC_RAW,
};
/**
* Raw Subtitle struct used as output of decoder (cc608)
* and input for encoder (sami, srt, transcript or smptett etc)
*
* if subtype CC_BITMAP then data contain nb_data numbers of rectangle
* which have to be displayed at same time.
*/
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;
/** Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen*/
enum ccx_encoding_type enc_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;
char mode[5];
char info[4];
struct cc_subtitle *next;
struct cc_subtitle *prev;
};
#endif

View File

@@ -11,32 +11,18 @@
// Count 608 (per field) and 708 blocks since last set_fts() call
int cb_field1, cb_field2, cb_708;
int pts_set; //0 = No, 1 = received, 2 = min_pts set
int MPEG_CLOCK_FREQ = 90000; // This "constant" is part of the standard
LLONG min_pts, max_pts, sync_pts;
LLONG current_pts = 0;
int max_dif = 5;
unsigned pts_big_change;
// PTS timing related stuff
LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
LLONG fts_offset; // Time before first sync_pts
LLONG fts_fc_offset; // Time before first GOP
LLONG fts_max; // Remember the maximum fts that we saw in current file
LLONG fts_global = 0; // Duration of previous files (-ve mode), see c1global
enum ccx_frame_type current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
int current_tref = 0; // Store temporal reference of current frame
double current_fps = (double) 30000.0 / 1001; /* 29.97 */ // TODO: Get from framerates_values[] instead
int frames_since_ref_time = 0;
unsigned total_frames_count;
// Remember the current field for 608 decoding
int current_field = 1; // 1 = field 1, 2 = field 2, 3 = 708
struct gop_time_code gop_time, first_gop_time, printed_gop;
LLONG fts_at_gop_start = 0;
int gop_rollover = 0;
@@ -51,263 +37,331 @@ void ccx_common_timing_init(LLONG *file_position,int no_sync)
ccx_common_timing_settings.no_sync = no_sync;
}
void set_fts(void)
void dinit_timing_ctx(struct ccx_common_timing_ctx **arg)
{
int pts_jump = 0;
freep(arg);
}
struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_t *cfg)
{
struct ccx_common_timing_ctx *ctx = malloc(sizeof(struct ccx_common_timing_ctx));
if(!ctx)
return NULL;
// ES don't have PTS unless GOP timing is used
if (!pts_set && ccx_common_timing_settings.is_elementary_stream)
return;
ctx->pts_set = 0;
ctx->current_tref = 0;
ctx->current_pts = 0;
ctx->current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
ctx->min_pts = 0x01FFFFFFFFLL; // 33 bit
ctx->max_pts = 0;
ctx->sync_pts = 0;
ctx->minimum_fts = 0;
// First check for timeline jump (only when min_pts was set (implies sync_pts)).
int dif = 0;
if (pts_set == 2)
{
dif=(int) (current_pts-sync_pts)/MPEG_CLOCK_FREQ;
ctx->fts_now = 0; // Time stamp of current file (w/ fts_offset, w/o fts_global)
ctx->fts_offset = 0; // Time before first sync_pts
ctx->fts_fc_offset = 0; // Time before first GOP
ctx->fts_max = 0; // Remember the maximum fts that we saw in current file
ctx->fts_global = 0; // Duration of previous files (-ve mode), see c1global
return ctx;
}
void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts)
{
set_current_pts(ctx, ctx->current_pts + pts);
}
void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts)
{
ctx->current_pts = pts;
if(ctx->pts_set == 0)
ctx->pts_set = 1;
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)", print_mstime(ctx->current_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (ctx->current_pts));
dbg_print(CCX_DMT_VIDES, " FTS: %s \n",print_mstime(ctx->fts_now));
}
int set_fts(struct ccx_common_timing_ctx *ctx)
{
int pts_jump = 0;
// ES don't have PTS unless GOP timing is used
if (!ctx->pts_set && ccx_common_timing_settings.is_elementary_stream)
return CCX_OK;
// First check for timeline jump (only when min_pts was set (implies sync_pts)).
int dif = 0;
if (ctx->pts_set == 2)
{
dif=(int) (ctx->current_pts - ctx->sync_pts)/MPEG_CLOCK_FREQ;
if (ccx_common_timing_settings.disable_sync_check){
// Disables sync check. Used for several input formats.
dif = 0;
}
if (dif < -0.2 || dif >= max_dif )
{
// ATSC specs: More than 3501 ms means missing component
ccx_common_logging.log_ftn ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, *ccx_common_timing_settings.file_position);
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",sync_pts);
ccx_common_logging.log_ftn ("Current PTS value: %lld\n",current_pts);
pts_jump = 1;
pts_big_change=1;
if (dif < -0.2 || dif >= max_dif )
{
// ATSC specs: More than 3501 ms means missing component
ccx_common_logging.log_ftn ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, *ccx_common_timing_settings.file_position);
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",ctx->sync_pts);
ccx_common_logging.log_ftn ("Current PTS value: %lld\n",ctx->current_pts);
pts_jump = 1;
pts_big_change = 1;
// Discard the gap if it is not on an I-frame or temporal reference zero.
if(current_tref != 0 && current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
{
fts_now = fts_max;
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
return;
}
}
}
// Discard the gap if it is not on an I-frame or temporal reference zero.
if(ctx->current_tref != 0 && ctx->current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
{
ctx->fts_now = ctx->fts_max;
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
return CCX_OK;
}
}
}
// Set min_pts, fts_offset
if (pts_set!=0)
{
pts_set=2;
// Set min_pts, fts_offset
if (ctx->pts_set != 0)
{
ctx->pts_set = 2;
// Use this part only the first time min_pts is set. Later treat
// it as a reference clock change
if (current_pts<min_pts && !pts_jump)
{
// If this is the first GOP, and seq 0 was not encountered yet
// we might reset min_pts/fts_offset again
// Use this part only the first time min_pts is set. Later treat
// it as a reference clock change
if (ctx->current_pts < ctx->min_pts && !pts_jump)
{
// If this is the first GOP, and seq 0 was not encountered yet
// we might reset min_pts/fts_offset again
min_pts=current_pts;
ctx->min_pts = ctx->current_pts;
// Avoid next async test
sync_pts = (LLONG)(current_pts
-current_tref*1000.0/current_fps
*(MPEG_CLOCK_FREQ/1000));
// Avoid next async test
ctx->sync_pts = (LLONG)(ctx->current_pts
-ctx->current_tref*1000.0/current_fps
*(MPEG_CLOCK_FREQ/1000));
if(current_tref == 0)
{ // Earliest time in GOP.
fts_offset = 0;
}
else if ( total_frames_count-frames_since_ref_time == 0 )
{ // If this is the first frame (PES) there cannot be an offset.
// This part is also reached for dvr-ms/NTSC (RAW) as
// total_frames_count = frames_since_ref_time = 0 when
// this is called for the first time.
fts_offset = 0;
}
else
{ // It needs to be "+1" because the current frame is
// not yet counted.
fts_offset = (LLONG)((total_frames_count
-frames_since_ref_time+1)
*1000.0/current_fps);
}
if(ctx->current_tref == 0)
{ // Earliest time in GOP.
ctx->fts_offset = 0;
}
else if ( total_frames_count-frames_since_ref_time == 0 )
{ // If this is the first frame (PES) there cannot be an offset.
// This part is also reached for dvr-ms/NTSC (RAW) as
// total_frames_count = frames_since_ref_time = 0 when
// this is called for the first time.
ctx->fts_offset = 0;
}
else
{ // It needs to be "+1" because the current frame is
// not yet counted.
ctx->fts_offset = (LLONG)((total_frames_count
-frames_since_ref_time+1)
*1000.0/current_fps);
}
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nFirst sync time PTS: %s %+lldms (time before this PTS)\n",
print_mstime(min_pts/(MPEG_CLOCK_FREQ/1000)),
fts_offset );
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
total_frames_count, frames_since_ref_time);
}
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
ctx->fts_offset );
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
total_frames_count, frames_since_ref_time);
}
// -nosync disables syncing
if (pts_jump && !ccx_common_timing_settings.no_sync)
{
// The current time in the old time base is calculated using
// sync_pts (set at the beginning of the last GOP) plus the
// time of the frames since then.
fts_offset = fts_offset
+ (sync_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
+ (LLONG) (frames_since_ref_time*1000/current_fps);
fts_max = fts_offset;
// -nosync disables syncing
if (pts_jump && !ccx_common_timing_settings.no_sync)
{
// The current time in the old time base is calculated using
// sync_pts (set at the beginning of the last GOP) plus the
// time of the frames since then.
ctx->fts_offset = ctx->fts_offset
+ (ctx->sync_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
+ (LLONG) (frames_since_ref_time*1000/current_fps);
ctx->fts_max = ctx->fts_offset;
// Start counting again from here
pts_set=1; // Force min to be set again
// Start counting again from here
ctx->pts_set = 1; // Force min to be set again
// Avoid next async test - the gap might have occured on
// current_tref != 0.
sync_pts = (LLONG) (current_pts
-current_tref*1000.0/current_fps
*(MPEG_CLOCK_FREQ/1000));
// Set min_pts = sync_pts as this is used for fts_now
min_pts = sync_pts;
// Avoid next async test - the gap might have occured on
// current_tref != 0.
ctx->sync_pts = (LLONG) (ctx->current_pts
-ctx->current_tref*1000.0/current_fps
*(MPEG_CLOCK_FREQ/1000));
// Set min_pts = sync_pts as this is used for fts_now
ctx->min_pts = ctx->sync_pts;
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n",
print_mstime(min_pts/(MPEG_CLOCK_FREQ/1000)),
fts_offset );
}
}
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n",
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
ctx->fts_offset );
}
}
// Set sync_pts, fts_offset
if(current_tref == 0)
sync_pts = current_pts;
// Set sync_pts, fts_offset
if(ctx->current_tref == 0)
ctx->sync_pts = ctx->current_pts;
// Reset counters
cb_field1 = 0;
cb_field2 = 0;
cb_708 = 0;
// Reset counters
cb_field1 = 0;
cb_field2 = 0;
cb_708 = 0;
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
// for uninitialized min_pts
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
// for uninitialized min_pts
if (1) // CFS: Remove or think decent condition
{
if ( pts_set )
if ( ctx->pts_set )
{
// If pts_set is TRUE we have min_pts
fts_now = (LLONG)((current_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
+ fts_offset);
ctx->fts_now = (LLONG)((ctx->current_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
+ ctx->fts_offset);
}
else
{
// No PTS info at all!!
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG,
"No PTS info. Please write bug report.");
ccx_common_logging.log_ftn("Set PTS called without any global timestamp set\n");
return CCX_EINVAL;
}
}
if ( fts_now > fts_max )
{
fts_max = fts_now;
}
if ( ctx->fts_now > ctx->fts_max )
{
ctx->fts_max = ctx->fts_now;
}
return CCX_OK;
}
LLONG get_fts(void)
LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field)
{
LLONG fts;
LLONG fts;
switch (current_field)
{
case 1:
fts = fts_now + fts_global + cb_field1*1001/30;
break;
case 2:
fts = fts_now + fts_global + cb_field2*1001/30;
break;
case 3:
fts = fts_now + fts_global + cb_708*1001/30;
break;
default:
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
}
return fts;
switch (current_field)
{
case 1:
fts = ctx->fts_now + ctx->fts_global + cb_field1*1001/30;
break;
case 2:
fts = ctx->fts_now + ctx->fts_global + cb_field2*1001/30;
break;
case 3:
fts = ctx->fts_now + ctx->fts_global + cb_708*1001/30;
break;
default:
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "get_fts: unhandled branch");
}
// ccx_common_logging.debug_ftn(CCX_DMT_TIME, "[FTS] "
// "fts: %llu, fts_now: %llu, fts_global: %llu, current_field: %llu, cb_708: %llu\n",
// fts, fts_now, fts_global, current_field, cb_708);
return fts;
}
LLONG get_fts_max(void)
LLONG get_fts_max(struct ccx_common_timing_ctx *ctx)
{
// This returns the maximum FTS that belonged to a frame. Caption block
// counters are not applicable.
return fts_max + fts_global;
// This returns the maximum FTS that belonged to a frame. Caption block
// counters are not applicable.
return ctx->fts_max + ctx->fts_global;
}
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
to the microsecond value in mstime. */
to the microsecond value in mstime. */
char *print_mstime2buf( LLONG mstime , char *buf )
{
unsigned hh,mm,ss,ms;
int signoffset = (mstime < 0 ? 1 : 0);
unsigned hh,mm,ss,ms;
int signoffset = (mstime < 0 ? 1 : 0);
if (mstime<0) // Avoid loss of data warning with abs()
mstime=-mstime;
hh = (unsigned) (mstime/1000/60/60);
mm = (unsigned) (mstime/1000/60 - 60*hh);
ss = (unsigned) (mstime/1000 - 60*(mm + 60*hh));
ms = (int) (mstime - 1000*(ss + 60*(mm + 60*hh)));
if (mstime<0) // Avoid loss of data warning with abs()
mstime=-mstime;
hh = (unsigned) (mstime/1000/60/60);
mm = (unsigned) (mstime/1000/60 - 60*hh);
ss = (unsigned) (mstime/1000 - 60*(mm + 60*hh));
ms = (int) (mstime - 1000*(ss + 60*(mm + 60*hh)));
buf[0]='-';
sprintf (buf+signoffset, "%02u:%02u:%02u:%03u",hh,mm,ss,ms);
buf[0]='-';
sprintf (buf+signoffset, "%02u:%02u:%02u:%03u",hh,mm,ss,ms);
return buf;
return buf;
}
/**
* Fill buffer with a time string using specified format
* @param fmt has to contain 4 format specifiers for h, m, s and ms respectively
*/
size_t mstime_sprintf(LLONG mstime, char *fmt, char *buf)
{
unsigned hh, mm, ss, ms;
int signoffset = (mstime < 0 ? 1 : 0);
if (mstime < 0) // Avoid loss of data warning with abs()
mstime = -mstime;
hh = (unsigned) (mstime / 1000 / 60 / 60);
mm = (unsigned) (mstime / 1000 / 60 - 60 * hh);
ss = (unsigned) (mstime / 1000 - 60 * (mm + 60 * hh));
ms = (unsigned) (mstime - 1000 * (ss + 60 * (mm + 60 * hh)));
buf[0] = '-';
return (size_t) sprintf(buf + signoffset, fmt, hh, mm, ss, ms);
}
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
to the microsecond value in mstime. */
to the microsecond value in mstime. */
char *print_mstime( LLONG mstime )
{
static char buf[15]; // 14 should be long enough
static char buf[15]; // 14 should be long enough
return print_mstime2buf (mstime, buf);
}
/* Helper function for to display debug timing info. */
void print_debug_timing( void )
void print_debug_timing(struct ccx_common_timing_ctx *ctx)
{
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
// for uninitialized min_pts
LLONG tempmin_pts = (min_pts==0x01FFFFFFFFLL ? sync_pts : min_pts);
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
// for uninitialized min_pts
LLONG tempmin_pts = (ctx->min_pts==0x01FFFFFFFFLL ? ctx->sync_pts : ctx->min_pts);
ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ",
print_mstime((sync_pts)/(MPEG_CLOCK_FREQ/1000)) );
ccx_common_logging.log_ftn("GOP: %s \n", print_mstime(gop_time.ms));
ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ",
print_mstime((ctx->sync_pts)/(MPEG_CLOCK_FREQ/1000)) );
ccx_common_logging.log_ftn("GOP: %s \n", print_mstime(gop_time.ms));
// Length first GOP to last GOP
LLONG goplenms = (LLONG) (gop_time.ms - first_gop_time.ms);
// Length at last sync point
LLONG ptslenms = (unsigned)((sync_pts-tempmin_pts)/(MPEG_CLOCK_FREQ/1000)
+ fts_offset);
// Length first GOP to last GOP
LLONG goplenms = (LLONG) (gop_time.ms - first_gop_time.ms);
// Length at last sync point
LLONG ptslenms = (unsigned)((ctx->sync_pts-tempmin_pts)/(MPEG_CLOCK_FREQ/1000)
+ ctx->fts_offset);
ccx_common_logging.log_ftn("Last FTS: %s",
print_mstime(get_fts_max()));
ccx_common_logging.log_ftn(" GOP start FTS: %s\n",
print_mstime(fts_at_gop_start));
ccx_common_logging.log_ftn("Last FTS: %s",
print_mstime(get_fts_max(ctx)));
ccx_common_logging.log_ftn(" GOP start FTS: %s\n",
print_mstime(fts_at_gop_start));
// Times are based on last GOP and/or sync time
ccx_common_logging.log_ftn("Max FTS diff. to PTS: %6lldms GOP: %6lldms\n\n",
get_fts_max()+(LLONG)(1000.0/current_fps)-ptslenms,
get_fts_max()+(LLONG)(1000.0/current_fps)-goplenms);
// Times are based on last GOP and/or sync time
ccx_common_logging.log_ftn("Max FTS diff. to PTS: %6lldms GOP: %6lldms\n\n",
get_fts_max(ctx)+(LLONG)(1000.0/current_fps)-ptslenms,
get_fts_max(ctx)+(LLONG)(1000.0/current_fps)-goplenms);
}
void calculate_ms_gop_time (struct gop_time_code *g)
{
int seconds=(g->time_code_hours*3600)+(g->time_code_minutes*60)+g->time_code_seconds;
g->ms = (LLONG)( 1000*(seconds + g->time_code_pictures/current_fps) );
if (gop_rollover)
g->ms += 24*60*60*1000;
int seconds=(g->time_code_hours*3600)+(g->time_code_minutes*60)+g->time_code_seconds;
g->ms = (LLONG)( 1000*(seconds + g->time_code_pictures/current_fps) );
if (gop_rollover)
g->ms += 24*60*60*1000;
}
int gop_accepted(struct gop_time_code* g )
{
if (! ((g->time_code_hours <= 23)
&& (g->time_code_minutes <= 59)
&& (g->time_code_seconds <= 59)
&& (g->time_code_pictures <= 59)))
return 0;
if (! ((g->time_code_hours <= 23)
&& (g->time_code_minutes <= 59)
&& (g->time_code_seconds <= 59)
&& (g->time_code_pictures <= 59)))
return 0;
if (gop_time.time_code_hours==23 && gop_time.time_code_minutes==59 &&
g->time_code_hours==0 && g->time_code_minutes==0)
{
gop_rollover = 1;
return 1;
}
if (gop_time.inited)
{
if (gop_time.ms > g->ms)
{
// We are going back in time but it's not a complete day rollover
return 0;
}
}
return 1;
if (gop_time.time_code_hours==23 && gop_time.time_code_minutes==59 &&
g->time_code_hours==0 && g->time_code_minutes==0)
{
gop_rollover = 1;
return 1;
}
if (gop_time.inited)
{
if (gop_time.ms > g->ms)
{
// We are going back in time but it's not a complete day rollover
return 0;
}
}
return 1;
}

View File

@@ -1,7 +1,8 @@
#ifndef __Timing_H__
#define __Timing_H__
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
struct gop_time_code
{
int drop_frame_flag;
@@ -14,7 +15,8 @@ struct gop_time_code
LLONG ms;
};
struct ccx_common_timing_settings_t {
struct ccx_common_timing_settings_t
{
int disable_sync_check; // If 1, timeline jumps will be ignored. This is important in several input formats that are assumed to have correct timing, no matter what.
int no_sync; // If 1, there will be no sync at all. Mostly useful for debugging.
int is_elementary_stream; // Needs to be set, as it's used in set_fts.
@@ -29,44 +31,55 @@ struct ccx_boundary_time
int set;
};
struct ccx_common_timing_ctx
{
int pts_set; //0 = No, 1 = received, 2 = min_pts set
LLONG current_pts;
enum ccx_frame_type current_picture_coding_type;
int current_tref; // Store temporal reference of current frame
LLONG min_pts;
LLONG max_pts;
LLONG sync_pts;
LLONG minimum_fts; // No screen should start before this FTS
LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
LLONG fts_offset; // Time before first sync_pts
LLONG fts_fc_offset; // Time before first GOP
LLONG fts_max; // Remember the maximum fts that we saw in current file
LLONG fts_global; // Duration of previous files (-ve mode)
};
// Count 608 (per field) and 708 blocks since last set_fts() call
extern int cb_field1, cb_field2, cb_708;
extern int pts_set; //0 = No, 1 = received, 2 = min_pts set
extern int MPEG_CLOCK_FREQ; // This is part of the standard
extern LLONG min_pts, max_pts, sync_pts, current_pts;
extern int max_dif;
extern unsigned pts_big_change;
extern LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
extern LLONG fts_offset; // Time before first sync_pts
extern LLONG fts_fc_offset; // Time before first GOP
extern LLONG fts_max; // Remember the maximum fts that we saw in current file
extern LLONG fts_global; // Duration of previous files (-ve mode)
extern enum ccx_frame_type current_picture_coding_type;
extern int current_tref; // Store temporal reference of current frame
extern double current_fps;
extern int frames_since_ref_time;
extern unsigned total_frames_count;
extern int current_field;
extern struct gop_time_code gop_time, first_gop_time, printed_gop;
extern LLONG fts_at_gop_start;
extern int gop_rollover;
void ccx_common_timing_init(LLONG *file_position, int no_sync);
void set_fts(void);
LLONG get_fts(void);
LLONG get_fts_max(void);
void dinit_timing_ctx(struct ccx_common_timing_ctx **arg);
struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_t *cfg);
void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts);
void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts);
int set_fts(struct ccx_common_timing_ctx *ctx);
LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field);
LLONG get_fts_max(struct ccx_common_timing_ctx *ctx);
char *print_mstime(LLONG mstime);
char *print_mstime2buf(LLONG mstime, char *buf);
void print_debug_timing(void);
size_t mstime_sprintf(LLONG mstime, char *fmt, char *buf);
void print_debug_timing(struct ccx_common_timing_ctx *ctx);
int gop_accepted(struct gop_time_code* g);
void calculate_ms_gop_time(struct gop_time_code *g);
#define __Timing_H__
#endif

View File

@@ -10,7 +10,7 @@ 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;
unsigned char str[2048]; // Another generic general purpose buffer
//unsigned char str[2048]; // Another generic general purpose buffer
const unsigned char pac2_attribs[][3] = // Color, font, ident
{
@@ -48,8 +48,6 @@ const unsigned char pac2_attribs[][3] = // Color, font, ident
{ COL_WHITE, FONT_UNDERLINED, 28 } // 0x5f || 0x7f
};
unsigned char *subline; // Temp storage for .srt lines
int new_sentence=1; // Capitalize next letter?
static const char *command_type[] =
{
@@ -88,7 +86,8 @@ static const char *cc_modes_text[]=
"Pop-Up captions"
};
#endif
const char *color_text[][2]=
const char *color_text[MAX_COLOR][2]=
{
{"white",""},
{"green","<font color=\"#00ff00\">"},
@@ -109,7 +108,7 @@ void clear_eia608_cc_buffer(ccx_decoder_608_context *context, struct eia608_scre
{
memset(data->characters[i], ' ', CCX_DECODER_608_SCREEN_WIDTH);
data->characters[i][CCX_DECODER_608_SCREEN_WIDTH] = 0;
memset(data->colors[i], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH + 1);
memset(data->colors[i], context->settings->default_color, CCX_DECODER_608_SCREEN_WIDTH + 1);
memset(data->fonts[i], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH + 1);
data->row_used[i]=0;
}
@@ -120,11 +119,10 @@ void ccx_decoder_608_dinit_library(void **ctx)
{
freep(ctx);
}
ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel,
int field, int trim_subs,
enum ccx_encoding_type encoding, int *halt,
int cc_to_stdout, LLONG subs_delay,
enum ccx_output_format output_format)
ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_settings *settings, int channel,
int field, int *halt,
int cc_to_stdout,
enum ccx_output_format output_format, struct ccx_common_timing_ctx *timing)
{
ccx_decoder_608_context *data = NULL;
@@ -148,19 +146,18 @@ ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings s
data->bytes_processed_608 = 0;
data->my_field = field;
data->my_channel = channel;
data->out = NULL;
data->have_cursor_position = 0;
data->trim_subs = trim_subs;
data->encoding = encoding;
data->output_format = output_format;
data->cc_to_stdout = cc_to_stdout;
data->textprinted = 0;
data->ts_start_of_current_line = 0;
data->halt = halt;
data->cc_to_stdout = cc_to_stdout;
data->subs_delay = subs_delay;
data->output_format = output_format;
data->settings = settings;
data->current_color = data->settings.default_color;
data->current_color = data->settings->default_color;
data->report = settings->report;
data->timing = timing;
clear_eia608_cc_buffer(data, &data->buffer1);
clear_eia608_cc_buffer(data, &data->buffer2);
@@ -207,7 +204,7 @@ void delete_to_end_of_row(ccx_decoder_608_context *context)
// TODO: This can change the 'used' situation of a column, so we'd
// need to check and correct.
use_buffer->characters[context->cursor_row][i] = ' ';
use_buffer->colors[context->cursor_row][i] = context->settings.default_color;
use_buffer->colors[context->cursor_row][i] = context->settings->default_color;
use_buffer->fonts[context->cursor_row][i] = context->font;
}
}
@@ -229,15 +226,15 @@ void write_char(const unsigned char c, ccx_decoder_608_context *context)
if (use_buffer->empty)
{
if (MODE_POPON != context->mode)
context->current_visible_start_ms = get_visible_start();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
}
use_buffer->empty=0;
if (context->cursor_column<CCX_DECODER_608_SCREEN_WIDTH - 1)
context->cursor_column++;
if (context->ts_start_of_current_line == -1)
context->ts_start_of_current_line = get_fts();
context->ts_last_char_received = get_fts();
context->ts_start_of_current_line = get_fts(context->timing, context->my_field);
context->ts_last_char_received = get_fts(context->timing, context->my_field);
}
}
@@ -289,8 +286,8 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
LLONG end_time;
if (context->settings.screens_to_process != -1 &&
context->screenfuls_counter >= context->settings.screens_to_process)
if (context->settings->screens_to_process != -1 &&
context->screenfuls_counter >= context->settings->screens_to_process)
{
// We are done.
*context->halt=1;
@@ -304,7 +301,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
context->current_visible_start_ms = context->ts_start_of_current_line;
start_time = context->current_visible_start_ms;
end_time = get_visible_end() + context->subs_delay;
end_time = get_visible_end(context->timing, context->my_field);
sub->type = CC_608;
data->format = SFORMAT_CC_SCREEN;
data->start_time = 0;
@@ -313,7 +310,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
data->channel = context->channel;
data->my_field = context->my_field;
if (!data->empty)
if (!data->empty && context->output_format != CCX_OF_NULL)
{
sub->data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
if (!sub->data)
@@ -357,11 +354,10 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
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 + context->subs_delay;
end_time = get_fts() + context->subs_delay;
start_time = context->ts_start_of_current_line;
end_time = get_fts(context->timing, context->my_field);
sub->type = CC_608;
data->format = SFORMAT_CC_LINE;
data->start_time = 0;
@@ -370,9 +366,7 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
data->channel = context->channel;
data->my_field = context->my_field;
//TODO need to put below functionality in encoder context
ret = get_decoder_line_basic (subline, context->cursor_row, data,context->trim_subs,context->encoding);
if( ret > 0 )
if (!data->empty)
{
sub->data = (struct eia608_screen *) realloc(sub->data,(sub->nb_data +1) * sizeof(*data));
if (!sub->data)
@@ -534,13 +528,13 @@ int roll_up(ccx_decoder_608_context *context)
for (int j = 0; j<(1 + context->cursor_row - keep_lines); j++)
{
memset(use_buffer->characters[j], ' ', CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[j], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[j], context->settings->default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->fonts[j], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH);
use_buffer->characters[j][CCX_DECODER_608_SCREEN_WIDTH] = 0;
use_buffer->row_used[j]=0;
}
memset(use_buffer->characters[lastrow], ' ', CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[lastrow], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[lastrow], context->settings->default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->fonts[lastrow], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH);
use_buffer->characters[lastrow][CCX_DECODER_608_SCREEN_WIDTH] = 0;
@@ -599,7 +593,7 @@ int is_current_row_empty(ccx_decoder_608_context *context)
}
/* Process GLOBAL CODES */
void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_decoder_608_context *context, struct cc_subtitle *sub)
void handle_command(unsigned char c1, const unsigned char c2, ccx_decoder_608_context *context, struct cc_subtitle *sub)
{
int changes=0;
@@ -646,12 +640,12 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
if ((c1==0x14 || c1==0x1C) && c2==0x2b)
command = COM_RESUMETEXTDISPLAY;
if ((command == COM_ROLLUP2 || command == COM_ROLLUP3 || command == COM_ROLLUP4) && context->settings.force_rollup == 1)
if ((command == COM_ROLLUP2 || command == COM_ROLLUP3 || command == COM_ROLLUP4) && context->settings->force_rollup == 1)
command=COM_FAKE_RULLUP1;
if ((command == COM_ROLLUP3 || command == COM_ROLLUP4) && context->settings.force_rollup == 2)
if ((command == COM_ROLLUP3 || command == COM_ROLLUP4) && context->settings->force_rollup == 2)
command=COM_ROLLUP2;
else if (command == COM_ROLLUP4 && context->settings.force_rollup == 3)
else if (command == COM_ROLLUP4 && context->settings->force_rollup == 3)
command=COM_ROLLUP3;
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\rCommand begin: %02X %02X (%s)\n", c1, c2, command_type[command]);
@@ -756,14 +750,14 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
{
if (write_cc_buffer(context, sub))
context->screenfuls_counter++;
if (context->settings.no_rollup)
if (context->settings->no_rollup)
erase_memory(context, true); // Make sure the lines we just wrote aren't written again
}
}
roll_up(context); // The roll must be done anyway of course.
context->ts_start_of_current_line = -1; // Unknown.
if (changes)
context->current_visible_start_ms = get_visible_start();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
context->cursor_column = 0;
break;
case COM_ERASENONDISPLAYEDMEMORY:
@@ -791,7 +785,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
context->screenfuls_counter++;
}
erase_memory(context, true);
context->current_visible_start_ms = get_visible_start();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
break;
case COM_ENDOFCAPTION: // Switch buffers
// The currently *visible* buffer is leaving, so now we know its ending
@@ -799,10 +793,10 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
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();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
context->cursor_column = 0;
context->cursor_row = 0;
context->current_color = context->settings.default_color;
context->current_color = context->settings->default_color;
context->font = FONT_REGULAR;
context->mode = MODE_POPON;
break;
@@ -828,7 +822,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
}
void handle_end_of_data(ccx_decoder_608_context *context, struct cc_subtitle *sub)
void flush_608_context(ccx_decoder_608_context *context, struct cc_subtitle *sub)
{
// We issue a EraseDisplayedMemory here so if there's any captions pending
// they get written to Subtitle.
@@ -926,7 +920,7 @@ void handle_pac(unsigned char c1, unsigned char c2, ccx_decoder_608_context *con
int indent=pac2_attribs[c2][2];
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, " -- Position: %d:%d, color: %s, font: %s\n", row,
indent, color_text[context->current_color][0], font_text[context->font]);
if (context->settings.default_color == COL_USERDEFINED && (context->current_color == COL_WHITE || context->current_color == COL_TRANSPARENT))
if (context->settings->default_color == COL_USERDEFINED && (context->current_color == COL_WHITE || context->current_color == COL_TRANSPARENT))
context->current_color = COL_USERDEFINED;
if (context->mode != MODE_TEXT)
{
@@ -949,7 +943,7 @@ void handle_pac(unsigned char c1, unsigned char c2, ccx_decoder_608_context *con
if (use_buffer->row_used[j])
{
memset(use_buffer->characters[j], ' ', CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[j], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->colors[j], context->settings->default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->fonts[j], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH);
use_buffer->characters[j][CCX_DECODER_608_SCREEN_WIDTH] = 0;
use_buffer->row_used[j] = 0;
@@ -977,10 +971,10 @@ void erase_both_memories(ccx_decoder_608_context *context, struct cc_subtitle *s
// time. Time to actually write it to file.
if (write_cc_buffer(context, sub))
context->screenfuls_counter++;
context->current_visible_start_ms = get_visible_start();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
context->cursor_column = 0;
context->cursor_row = 0;
context->current_color = context->settings.default_color;
context->current_color = context->settings->default_color;
context->font = FONT_REGULAR;
erase_memory(context, true);
@@ -1075,15 +1069,29 @@ int disCommand(unsigned char hi, unsigned char lo, ccx_decoder_608_context *cont
return wrote_to_screen;
}
/* If wb is NULL, then only XDS will be processed */
int process608(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub)
/* If private data is NULL, then only XDS will be processed */
int process608(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub)
{
struct ccx_decoder_608_report *report = NULL;
static int textprinted = 0;
struct lib_cc_decode *dec_ctx = private_data;
struct ccx_decoder_608_context *context;
int i;
if(dec_ctx->current_field == 1)
{
context = dec_ctx->context_cc608_field_1;
}
else if (dec_ctx->current_field == 2 && dec_ctx->extract == 1)
{
context = NULL;
}
else
{
context = dec_ctx->context_cc608_field_2;
}
if (context)
{
report = &context->report;
report = context->report;
context->bytes_processed_608 += length;
}
if (!data)
@@ -1118,16 +1126,16 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
context->channel = 3;
if (!in_xds_mode)
{
ts_start_of_xds=get_fts();
in_xds_mode=1;
ts_start_of_xds = get_fts(dec_ctx->timing, dec_ctx->current_field);
in_xds_mode = 1;
}
if(report)
report->xds=1;
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);
do_end_of_xds (sub, dec_ctx->xds_ctx, lo);
if (context)
context->channel = context->new_channel; // Switch from channel 3
continue;
@@ -1136,17 +1144,19 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
// 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 )
{
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_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;
// We were writing characters before, start a new line for
// diagnostic output from disCommand()
if (context->textprinted == 1 )
{
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\n");
context->textprinted = 0;
}
if (context->last_c1 == hi && context->last_c2 == lo)
{
// Duplicate dual code, discard. Correct to do it only in
@@ -1167,7 +1177,7 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
{
if (in_xds_mode && (context == NULL || context->my_field == 2))
{
process_xds_bytes (hi,lo);
process_xds_bytes (dec_ctx->xds_ctx, hi, lo);
continue;
}
if (!context) // No XDS code after this point, and user doesn't want captions.
@@ -1182,10 +1192,10 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
if (context->channel != context->my_channel)
continue;
if( textprinted == 0 )
if( context->textprinted == 0 )
{
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\n");
textprinted = 1;
context->textprinted = 1;
}
handle_single(hi, context);
@@ -1195,16 +1205,16 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
context->last_c2 = 0;
}
if (!textprinted && context->channel == context->my_channel)
if (!context->textprinted && context->channel == context->my_channel)
{ // Current FTS information after the characters are shown
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Current FTS: %s\n", print_mstime(get_fts()));
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Current FTS: %s\n", print_mstime(get_fts(dec_ctx->timing, context->my_field)));
//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 && context->settings.direct_rollup && // If direct_rollup is enabled and
if (wrote_to_screen && context->settings->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 ||
@@ -1212,7 +1222,7 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
{
// We don't increase screenfuls_counter here.
write_cc_buffer(context, sub);
context->current_visible_start_ms = get_visible_start();
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
}
}
if (wrote_to_screen && context->cc_to_stdout)

View File

@@ -1,5 +1,5 @@
#ifndef __608_H__
#ifndef CCX_DECODER_608_H
#define CCX_DECODER_608_H
#include "ccx_common_platform.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
@@ -7,14 +7,14 @@
extern LLONG ts_start_of_xds;
/*
This variable (ccx_decoder_608_report) holds data on the cc channels & xds packets that are encountered during file parse.
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
for the report functionality.
*/
This variable (ccx_decoder_608_report) holds data on the cc channels & xds packets that are encountered during file parse.
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
for the report functionality.
*/
struct ccx_decoder_608_report
{
unsigned xds : 1;
unsigned cc_channels[4];
uint8_t xds : 1;
uint8_t cc_channels[4];
};
typedef struct ccx_decoder_608_settings
@@ -24,11 +24,12 @@ typedef struct ccx_decoder_608_settings
int no_rollup; // If 1, write one line at a time
unsigned char default_color; // Default color to use.
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
struct ccx_decoder_608_report *report;
} ccx_decoder_608_settings;
typedef struct ccx_decoder_608_context
{
ccx_decoder_608_settings settings;
ccx_decoder_608_settings *settings;
eia608_screen buffer1;
eia608_screen buffer2;
int cursor_row, cursor_column;
@@ -47,65 +48,60 @@ typedef struct ccx_decoder_608_context
int my_field; // Used for sanity checks
int my_channel; // Used for sanity checks
long bytes_processed_608; // To be written ONLY by process_608
struct ccx_s_write *out;
int have_cursor_position;
int trim_subs;
enum ccx_encoding_type encoding;
int *halt; // Can be used to halt the feeding of caption data. Set to 1 if screens_to_progress != -1 && screenfuls_counter >= screens_to_process
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
struct ccx_decoder_608_report report;
struct ccx_decoder_608_report *report;
LLONG subs_delay; // ms to delay (or advance) subs
enum ccx_output_format output_format; // What kind of output format should be used?
int textprinted;
struct ccx_common_timing_ctx *timing;
} ccx_decoder_608_context;
extern unsigned char *enc_buffer;
extern unsigned char str[2048];
extern unsigned enc_buffer_used;
extern unsigned enc_buffer_capacity;
extern int new_sentence;
extern const char *color_text[][2];
#define MAX_COLOR 10
extern const char *color_text[MAX_COLOR][2];
typedef enum ccx_decoder_608_color_code
{
COL_WHITE = 0,
COL_GREEN = 1,
COL_BLUE = 2,
COL_CYAN = 3,
COL_RED = 4,
COL_YELLOW = 5,
COL_MAGENTA = 6,
COL_USERDEFINED = 7,
COL_BLACK = 8,
COL_TRANSPARENT = 9
COL_WHITE = 0,
COL_GREEN = 1,
COL_BLUE = 2,
COL_CYAN = 3,
COL_RED = 4,
COL_YELLOW = 5,
COL_MAGENTA = 6,
COL_USERDEFINED = 7,
COL_BLACK = 8,
COL_TRANSPARENT = 9
} ccx_decoder_608_color_code;
enum font_bits
{
FONT_REGULAR = 0,
FONT_ITALICS = 1,
FONT_UNDERLINED = 2,
FONT_UNDERLINED_ITALICS = 3
FONT_REGULAR = 0,
FONT_ITALICS = 1,
FONT_UNDERLINED = 2,
FONT_UNDERLINED_ITALICS = 3
};
enum command_code
{
COM_UNKNOWN = 0,
COM_ERASEDISPLAYEDMEMORY = 1,
COM_RESUMECAPTIONLOADING = 2,
COM_ENDOFCAPTION = 3,
COM_TABOFFSET1 = 4,
COM_TABOFFSET2 = 5,
COM_TABOFFSET3 = 6,
COM_ROLLUP2 = 7,
COM_ROLLUP3 = 8,
COM_ROLLUP4 = 9,
COM_CARRIAGERETURN = 10,
COM_ERASENONDISPLAYEDMEMORY = 11,
COM_BACKSPACE = 12,
COM_UNKNOWN = 0,
COM_ERASEDISPLAYEDMEMORY = 1,
COM_RESUMECAPTIONLOADING = 2,
COM_ENDOFCAPTION = 3,
COM_TABOFFSET1 = 4,
COM_TABOFFSET2 = 5,
COM_TABOFFSET3 = 6,
COM_ROLLUP2 = 7,
COM_ROLLUP3 = 8,
COM_ROLLUP4 = 9,
COM_CARRIAGERETURN = 10,
COM_ERASENONDISPLAYEDMEMORY = 11,
COM_BACKSPACE = 12,
COM_RESUMETEXTDISPLAY = 13,
COM_ALARMOFF =14,
COM_ALARMON = 15,
@@ -121,18 +117,17 @@ void ccx_decoder_608_dinit_library(void **ctx);
/*
*
*/
ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel,
int field, int trim_subs,
enum ccx_encoding_type encoding, int *halt,
int cc_to_stdout, LLONG subs_delay,
enum ccx_output_format output_format);
ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_settings *settings, int channel,
int field, int *halt,
int cc_to_stdout,
enum ccx_output_format output_format, struct ccx_common_timing_ctx *timing);
/**
* @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
* @param private_data 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
@@ -140,15 +135,14 @@ ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings s
*
* @return number of bytes used from data, -1 when any error is encountered
*/
int process608(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
int process608(const unsigned char *data, int length, void *private_data, 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(ccx_decoder_608_context *context, struct cc_subtitle *sub);
void flush_608_context(ccx_decoder_608_context *context, struct cc_subtitle *sub);
int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub);
#define __608_H__
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -2,312 +2,371 @@
#define _INCLUDE_708_
#include <sys/stat.h>
#include "ccx_decoders_common.h"
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#define MAX_708_PACKET_LENGTH 128
#define CCX_DECODERS_708_MAX_SERVICES 63
#define CCX_DTVCC_MAX_PACKET_LENGTH 128 //According to EIA-708B, part 5
#define CCX_DTVCC_MAX_SERVICES 63
#define I708_MAX_ROWS 15
#define I708_MAX_COLUMNS 42
#define CCX_DTVCC_MAX_ROWS 15
/**
* This value should be 32, but there were 16-bit encoded samples (from Korea),
* where RowCount calculated another way and equals 46 (23[8bit]*2)
*/
#define CCX_DTVCC_MAX_COLUMNS (32*2)
#define I708_SCREENGRID_ROWS 75
#define I708_SCREENGRID_COLUMNS 210
#define CCX_DTVCC_SCREENGRID_ROWS 75
#define CCX_DTVCC_SCREENGRID_COLUMNS 210
#define I708_MAX_WINDOWS 8
#define CCX_DTVCC_MAX_WINDOWS 8
/*
This variable (ccx_decoder_708_report) holds data on the cc channels & xds packets that are encountered during file parse.
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
for the report functionality.
*/
struct ccx_decoder_708_report_t
#define CCX_DTVCC_FILENAME_TEMPLATE ".p%u.svc%02u"
#define CCX_DTVCC_NO_LAST_SEQUENCE -1
enum CCX_DTVCC_COMMANDS_C0_CODES
{
unsigned services[CCX_DECODERS_708_MAX_SERVICES];
};
extern struct ccx_decoder_708_report_t ccx_decoder_708_report;
enum COMMANDS_C0_CODES
{
NUL=0,
ETX=3,
BS=8,
FF=0xC,
CR=0xD,
HCR=0xE,
EXT1=0x10,
P16=0x18
CCX_DTVCC_C0_NUL = 0x00,
CCX_DTVCC_C0_ETX = 0x03,
CCX_DTVCC_C0_BS = 0x08,
CCX_DTVCC_C0_FF = 0x0c,
CCX_DTVCC_C0_CR = 0x0d,
CCX_DTVCC_C0_HCR = 0x0e,
CCX_DTVCC_C0_EXT1 = 0x10,
CCX_DTVCC_C0_P16 = 0x18
};
enum COMMANDS_C1_CODES
enum CCX_DTVCC_COMMANDS_C1_CODES
{
CW0=0x80,
CW1=0x81,
CW2=0x82,
CW3=0x83,
CW4=0x84,
CW5=0x85,
CW6=0x86,
CW7=0x87,
CLW=0x88,
DSW=0x89,
HDW=0x8A,
TGW=0x8B,
DLW=0x8C,
DLY=0x8D,
DLC=0x8E,
RST=0x8F,
SPA=0x90,
SPC=0x91,
SPL=0x92,
RSV93=0x93,
RSV94=0x94,
RSV95=0x95,
RSV96=0x96,
SWA=0x97,
DF0=0x98,
DF1=0x99,
DF2=0x9A,
DF3=0x9B,
DF4=0x9C,
DF5=0x9D,
DF6=0x9E,
DF7=0x9F
CCX_DTVCC_C1_CW0 = 0x80,
CCX_DTVCC_C1_CW1 = 0x81,
CCX_DTVCC_C1_CW2 = 0x82,
CCX_DTVCC_C1_CW3 = 0x83,
CCX_DTVCC_C1_CW4 = 0x84,
CCX_DTVCC_C1_CW5 = 0x85,
CCX_DTVCC_C1_CW6 = 0x86,
CCX_DTVCC_C1_CW7 = 0x87,
CCX_DTVCC_C1_CLW = 0x88,
CCX_DTVCC_C1_DSW = 0x89,
CCX_DTVCC_C1_HDW = 0x8A,
CCX_DTVCC_C1_TGW = 0x8B,
CCX_DTVCC_C1_DLW = 0x8C,
CCX_DTVCC_C1_DLY = 0x8D,
CCX_DTVCC_C1_DLC = 0x8E,
CCX_DTVCC_C1_RST = 0x8F,
CCX_DTVCC_C1_SPA = 0x90,
CCX_DTVCC_C1_SPC = 0x91,
CCX_DTVCC_C1_SPL = 0x92,
CCX_DTVCC_C1_RSV93 = 0x93,
CCX_DTVCC_C1_RSV94 = 0x94,
CCX_DTVCC_C1_RSV95 = 0x95,
CCX_DTVCC_C1_RSV96 = 0x96,
CCX_DTVCC_C1_SWA = 0x97,
CCX_DTVCC_C1_DF0 = 0x98,
CCX_DTVCC_C1_DF1 = 0x99,
CCX_DTVCC_C1_DF2 = 0x9A,
CCX_DTVCC_C1_DF3 = 0x9B,
CCX_DTVCC_C1_DF4 = 0x9C,
CCX_DTVCC_C1_DF5 = 0x9D,
CCX_DTVCC_C1_DF6 = 0x9E,
CCX_DTVCC_C1_DF7 = 0x9F
};
struct S_COMMANDS_C1
struct CCX_DTVCC_S_COMMANDS_C1
{
int code;
const char *name;
const char *description;
int length;
int code;
const char *name;
const char *description;
int length;
};
enum eWindowsAttribJustify
enum ccx_dtvcc_window_justify
{
left=0,
right=1,
center=2,
full=3
CCX_DTVCC_WINDOW_JUSTIFY_LEFT = 0,
CCX_DTVCC_WINDOW_JUSTIFY_RIGHT = 1,
CCX_DTVCC_WINDOW_JUSTIFY_CENTER = 2,
CCX_DTVCC_WINDOW_JUSTIFY_FULL = 3
};
enum eWindowsAttribPrintDirection
enum ccx_dtvcc_window_pd //Print Direction
{
pd_left_to_right=0,
pd_right_to_left=1,
pd_top_to_bottom=2,
pd_bottom_to_top=3
CCX_DTVCC_WINDOW_PD_LEFT_RIGHT = 0, //left -> right
CCX_DTVCC_WINDOW_PD_RIGHT_LEFT = 1,
CCX_DTVCC_WINDOW_PD_TOP_BOTTOM = 2,
CCX_DTVCC_WINDOW_PD_BOTTOM_TOP = 3
};
enum eWindowsAttribScrollDirection
enum ccx_dtvcc_window_sd //Scroll Direction
{
sd_left_to_right=0,
sd_right_to_left=1,
sd_top_to_bottom=2,
sd_bottom_to_top=3
CCX_DTVCC_WINDOW_SD_LEFT_RIGHT = 0,
CCX_DTVCC_WINDOW_SD_RIGHT_LEFT = 1,
CCX_DTVCC_WINDOW_SD_TOP_BOTTOM = 2,
CCX_DTVCC_WINDOW_SD_BOTTOM_TOP = 3
};
enum eWindowsAttribScrollDisplayEffect
enum ccx_dtvcc_window_sde //Scroll Display Effect
{
snap=0,
fade=1,
wipe=2
CCX_DTVCC_WINDOW_SDE_SNAP = 0,
CCX_DTVCC_WINDOW_SDE_FADE = 1,
CCX_DTVCC_WINDOW_SDE_WIPE = 2
};
enum eWindowsAttribEffectDirection
enum ccx_dtvcc_window_ed //Effect Direction
{
left_to_right=0,
right_to_left=1,
top_to_bottom=2,
bottom_to_top=3
CCX_DTVCC_WINDOW_ED_LEFT_RIGHT = 0,
CCX_DTVCC_WINDOW_ED_RIGHT_LEFT = 1,
CCX_DTVCC_WINDOW_ED_TOP_BOTTOM = 2,
CCX_DTVCC_WINDOW_ED_BOTTOM_TOP = 3
};
enum eWindowsAttribFillOpacity
enum ccx_dtvcc_window_fo //Fill Opacity
{
solid=0,
flash=1,
traslucent=2,
transparent=3
CCX_DTVCC_WINDOW_FO_SOLID = 0,
CCX_DTVCC_WINDOW_FO_FLASH = 1,
CCX_DTVCC_WINDOW_FO_TRANSLUCENT = 2,
CCX_DTVCC_WINDOW_FO_TRANSPARENT = 3
};
enum eWindowsAttribBorderType
enum ccx_dtvcc_window_border
{
none=0,
raised=1,
depressed=2,
uniform=3,
shadow_left=4,
shadow_right=5
CCX_DTVCC_WINDOW_BORDER_NONE = 0,
CCX_DTVCC_WINDOW_BORDER_RAISED = 1,
CCX_DTVCC_WINDOW_BORDER_DEPRESSED = 2,
CCX_DTVCC_WINDOW_BORDER_UNIFORM = 3,
CCX_DTVCC_WINDOW_BORDER_SHADOW_LEFT = 4,
CCX_DTVCC_WINDOW_BORDER_SHADOW_RIGHT = 5
};
enum ePenAttribSize
enum ccx_dtvcc_pen_size
{
pensize_small=0,
pensize_standard=1,
pensize_large=2
CCX_DTVCC_PEN_SIZE_SMALL = 0,
CCX_DTVCC_PEN_SIZE_STANDART = 1,
CCX_DTVCC_PEN_SIZE_LARGE = 2
};
enum ePenAttribFontStyle
enum ccx_dtvcc_pen_font_style
{
fontstyle_default_or_undefined=0,
monospaced_with_serifs=1,
proportionally_spaced_with_serifs=2,
monospaced_without_serifs=3,
proportionally_spaced_without_serifs=4,
casual_font_type=5,
cursive_font_type=6,
small_capitals=7
CCX_DTVCC_PEN_FONT_STYLE_DEFAULT_OR_UNDEFINED = 0,
CCX_DTVCC_PEN_FONT_STYLE_MONOSPACED_WITH_SERIFS = 1,
CCX_DTVCC_PEN_FONT_STYLE_PROPORTIONALLY_SPACED_WITH_SERIFS = 2,
CCX_DTVCC_PEN_FONT_STYLE_MONOSPACED_WITHOUT_SERIFS = 3,
CCX_DTVCC_PEN_FONT_STYLE_PROPORTIONALLY_SPACED_WITHOUT_SERIFS = 4,
CCX_DTVCC_PEN_FONT_STYLE_CASUAL_FONT_TYPE = 5,
CCX_DTVCC_PEN_FONT_STYLE_CURSIVE_FONT_TYPE = 6,
CCX_DTVCC_PEN_FONT_STYLE_SMALL_CAPITALS = 7
};
enum ePanAttribTextTag
enum ccx_dtvcc_pen_text_tag
{
texttag_dialog=0,
texttag_source_or_speaker_id=1,
texttag_electronic_voice=2,
texttag_foreign_language=3,
texttag_voiceover=4,
texttag_audible_translation=5,
texttag_subtitle_translation=6,
texttag_voice_quality_description=7,
texttag_song_lyrics=8,
texttag_sound_effect_description=9,
texttag_musical_score_description=10,
texttag_expletitive=11,
texttag_undefined_12=12,
texttag_undefined_13=13,
texttag_undefined_14=14,
texttag_not_to_be_displayed=15
CCX_DTVCC_PEN_TEXT_TAG_DIALOG = 0,
CCX_DTVCC_PEN_TEXT_TAG_SOURCE_OR_SPEAKER_ID = 1,
CCX_DTVCC_PEN_TEXT_TAG_ELECTRONIC_VOICE = 2,
CCX_DTVCC_PEN_TEXT_TAG_FOREIGN_LANGUAGE = 3,
CCX_DTVCC_PEN_TEXT_TAG_VOICEOVER = 4,
CCX_DTVCC_PEN_TEXT_TAG_AUDIBLE_TRANSLATION = 5,
CCX_DTVCC_PEN_TEXT_TAG_SUBTITLE_TRANSLATION = 6,
CCX_DTVCC_PEN_TEXT_TAG_VOICE_QUALITY_DESCRIPTION = 7,
CCX_DTVCC_PEN_TEXT_TAG_SONG_LYRICS = 8,
CCX_DTVCC_PEN_TEXT_TAG_SOUND_EFFECT_DESCRIPTION = 9,
CCX_DTVCC_PEN_TEXT_TAG_MUSICAL_SCORE_DESCRIPTION = 10,
CCX_DTVCC_PEN_TEXT_TAG_EXPLETIVE = 11,
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_12 = 12,
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_13 = 13,
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_14 = 14,
CCX_DTVCC_PEN_TEXT_TAG_NOT_TO_BE_DISPLAYED = 15
};
enum ePanAttribOffset
enum ccx_dtvcc_pen_offset
{
offset_subscript=0,
offset_normal=1,
offset_superscript=2
CCX_DTVCC_PEN_OFFSET_SUBSCRIPT = 0,
CCX_DTVCC_PEN_OFFSET_NORMAL = 1,
CCX_DTVCC_PEN_OFFSET_SUPERSCRIPT = 2
};
enum ePanAttribEdgeType
enum ccx_dtvcc_pen_edge
{
edgetype_none=0,
edgetype_raised=1,
edgetype_depressed=2,
edgetype_uniform=3,
edgetype_left_drop_shadow=4,
edgetype_right_drop_shadow=5
CCX_DTVCC_PEN_EDGE_NONE = 0,
CCX_DTVCC_PEN_EDGE_RAISED = 1,
CCX_DTVCC_PEN_EDGE_DEPRESSED = 2,
CCX_DTVCC_PEN_EDGE_UNIFORM = 3,
CCX_DTVCC_PEN_EDGE_LEFT_DROP_SHADOW = 4,
CCX_DTVCC_PEN_EDGE_RIGHT_DROP_SHADOW = 5
};
enum eAnchorPoints
enum ccx_dtvcc_pen_anchor_point
{
anchorpoint_top_left = 0,
anchorpoint_top_center = 1,
anchorpoint_top_right =2,
anchorpoint_middle_left = 3,
anchorpoint_middle_center = 4,
anchorpoint_middle_right = 5,
anchorpoint_bottom_left = 6,
anchorpoint_bottom_center = 7,
anchorpoint_bottom_right = 8
CCX_DTVCC_ANCHOR_POINT_TOP_LEFT = 0,
CCX_DTVCC_ANCHOR_POINT_TOP_CENTER = 1,
CCX_DTVCC_ANCHOR_POINT_TOP_RIGHT = 2,
CCX_DTVCC_ANCHOR_POINT_MIDDLE_LEFT = 3,
CCX_DTVCC_ANCHOR_POINT_MIDDLE_CENTER = 4,
CCX_DTVCC_ANCHOR_POINT_MIDDLE_RIGHT = 5,
CCX_DTVCC_ANCHOR_POINT_BOTTOM_LEFT = 6,
CCX_DTVCC_ANCHOR_POINT_BOTTOM_CENTER = 7,
CCX_DTVCC_ANCHOR_POINT_BOTTOM_RIGHT = 8
};
typedef struct e708Pen_color
typedef struct ccx_dtvcc_pen_color
{
int fg_color;
int fg_opacity;
int bg_color;
int bg_opacity;
int edge_color;
} e708Pen_color;
int fg_color;
int fg_opacity;
int bg_color;
int bg_opacity;
int edge_color;
} ccx_dtvcc_pen_color;
typedef struct e708Pen_attribs
typedef struct ccx_dtvcc_pen_attribs
{
int pen_size;
int offset;
int text_tag;
int font_tag;
int edge_type;
int underline;
int italic;
} e708Pen_attribs;
int pen_size;
int offset;
int text_tag;
int font_tag;
int edge_type;
int underline;
int italic;
} ccx_dtvcc_pen_attribs;
typedef struct e708Window_attribs
typedef struct ccx_dtvcc_window_attribs
{
int fill_color;
int fill_opacity;
int border_color;
int border_type01;
int justify;
int scroll_dir;
int print_dir;
int word_wrap;
int border_type;
int display_eff;
int effect_dir;
int effect_speed;
} e708Window_attribs;
int justify;
int print_direction;
int scroll_direction;
int word_wrap;
int display_effect;
int effect_direction;
int effect_speed;
int fill_color;
int fill_opacity;
int border_type;
int border_color;
} ccx_dtvcc_window_attribs;
typedef struct e708Window
/**
* Since 1-byte and 2-byte symbols could appear in captions and
* since we have to keep symbols alignment and several windows could appear on a screen at one time,
* we use special structure for holding symbols
*/
typedef struct ccx_dtvcc_symbol
{
int is_defined;
int number; // Handy, in case we only have a pointer to the window
int priority;
int col_lock;
int row_lock;
int visible;
int anchor_vertical;
int relative_pos;
int anchor_horizontal;
int row_count;
int anchor_point;
int col_count;
int pen_style;
int win_style;
unsigned char commands[6]; // Commands used to create this window
e708Window_attribs attribs;
e708Pen_attribs pen;
e708Pen_color pen_color;
int pen_row;
int pen_column;
unsigned char *rows[I708_MAX_ROWS+1]; // Max is 15, but we define an extra one for convenience
int memory_reserved;
unsigned short sym; //symbol itself, at least 16 bit
unsigned char len; //length. could be 1 or 2
} ccx_dtvcc_symbol;
#define CCX_DTVCC_SYM_SET(x, c) {x.len = 1; x.sym = c;}
#define CCX_DTVCC_SYM_SET_16(x, c1, c2) {x.len = 2; x.sym = (c1 << 8) | c2;}
#define CCX_DTVCC_SYM_IS_16(x) (x.len == 2)
#define CCX_DTVCC_SYM(x) ((unsigned char)(x.sym))
#define CCX_DTVCC_SYM_16_FIRST(x) ((unsigned char)(x.sym >> 8))
#define CCX_DTVCC_SYM_16_SECOND(x) ((unsigned char)(x.sym & 0xff))
#define CCX_DTVCC_SYM_IS_EMPTY(x) (x.len == 0)
#define CCX_DTVCC_SYM_IS_SET(x) (x.len > 0)
typedef struct ccx_dtvcc_window
{
int is_defined;
int number;
int priority;
int col_lock;
int row_lock;
int visible;
int anchor_vertical;
int relative_pos;
int anchor_horizontal;
int row_count;
int anchor_point;
int col_count;
int pen_style;
int win_style;
unsigned char commands[6]; // Commands used to create this window
ccx_dtvcc_window_attribs attribs;
int pen_row;
int pen_column;
ccx_dtvcc_symbol *rows[CCX_DTVCC_MAX_ROWS];
ccx_dtvcc_pen_color pen_colors[CCX_DTVCC_MAX_ROWS];
ccx_dtvcc_pen_attribs pen_attribs[CCX_DTVCC_MAX_ROWS];
int memory_reserved;
int is_empty;
} e708Window;
LLONG time_ms_show;
LLONG time_ms_hide;
} ccx_dtvcc_window;
typedef struct tvscreen
typedef struct dtvcc_tv_screen
{
unsigned char chars[I708_SCREENGRID_ROWS][I708_SCREENGRID_COLUMNS+1];
}
tvscreen;
ccx_dtvcc_symbol chars[CCX_DTVCC_SCREENGRID_ROWS][CCX_DTVCC_SCREENGRID_COLUMNS];
ccx_dtvcc_pen_color pen_colors[CCX_DTVCC_SCREENGRID_ROWS];
ccx_dtvcc_pen_attribs pen_attribs[CCX_DTVCC_SCREENGRID_ROWS];
LLONG time_ms_show;
LLONG time_ms_hide;
unsigned int cc_count;
int service_number;
} dtvcc_tv_screen;
typedef struct cc708_service_decoder
/**
* Holds data on the CEA 708 services that are encountered during file parse
* This can be interesting, so CCExtractor uses it for the report functionality.
*/
typedef struct ccx_decoder_dtvcc_report
{
e708Window windows[I708_MAX_WINDOWS];
int current_window;
int inited;
LLONG current_visible_start_ms;
tvscreen tv1, tv2; // Current and previous "screenfuls", note that we switch between them
int is_empty_tv1, is_empty_tv2;
int cur_tv; // 1 or 2 rather than 0 or 1, to at least be consistent with the decoder
tvscreen *tv; // Pointer to the current TV buffer
char *filename; // Where we are going to write our output
int fh; // Handle to output file. -1 if not yet open
int srt_counter;
enum ccx_output_format output_format; // What kind of output format should be used?
LLONG subs_delay; // ms to delay (or advance) subs
}
cc708_service_decoder;
int reset_count;
unsigned services[CCX_DTVCC_MAX_SERVICES];
} ccx_decoder_dtvcc_report;
extern int do_cea708; // Process 708 data?
extern int cea708services[]; // [] -> 1 for services to be processed
typedef struct ccx_dtvcc_service_decoder
{
ccx_dtvcc_window windows[CCX_DTVCC_MAX_WINDOWS];
int current_window;
dtvcc_tv_screen *tv;
int cc_count;
} ccx_dtvcc_service_decoder;
extern int resets_708;
typedef struct ccx_decoder_dtvcc_settings
{
int enabled;
int print_file_reports;
int no_rollup;
ccx_decoder_dtvcc_report *report;
int active_services_count;
int services_enabled[CCX_DTVCC_MAX_SERVICES];
struct ccx_common_timing_ctx *timing;
} ccx_decoder_dtvcc_settings;
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength);
/**
* TODO
* solution requires "sink" or "writer" entity to write captions to output file
* decoders have to know nothing about output files
*/
unsigned char get_internal_from_G0 (unsigned char g0_char);
unsigned char get_internal_from_G1 (unsigned char g1_char);
unsigned char get_internal_from_G2 (unsigned char g2_char);
unsigned char get_internal_from_G3 (unsigned char g3_char);
void process_character (cc708_service_decoder *decoder, unsigned char internal_char);
typedef struct ccx_dtvcc_ctx
{
int is_active;
int active_services_count;
int services_active[CCX_DTVCC_MAX_SERVICES]; //0 - inactive, 1 - active
int report_enabled;
ccx_decoder_dtvcc_report *report;
ccx_dtvcc_service_decoder decoders[CCX_DTVCC_MAX_SERVICES];
unsigned char current_packet[CCX_DTVCC_MAX_PACKET_LENGTH];
int current_packet_length;
int last_sequence;
void *encoder; //we can't include header, so keeping it this way
int no_rollup;
struct ccx_common_timing_ctx *timing;
} ccx_dtvcc_ctx;
void ccx_dtvcc_clear_packet(ccx_dtvcc_ctx *ctx);
void ccx_dtvcc_windows_reset(ccx_dtvcc_service_decoder *decoder);
void ccx_dtvcc_decoder_flush(ccx_dtvcc_ctx *dtvcc, ccx_dtvcc_service_decoder *decoder);
void ccx_dtvcc_process_current_packet(ccx_dtvcc_ctx *dtvcc);
void ccx_dtvcc_process_service_block(ccx_dtvcc_ctx *dtvcc,
ccx_dtvcc_service_decoder *decoder,
unsigned char *data,
int data_length);
void ccx_decoders_708_init_library(char *basefilename,const char *extension, int report);
#endif

View File

@@ -12,34 +12,34 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
A0-FF -> Group G1 as is - non-English characters and symbols
*/
unsigned char get_internal_from_G0 (unsigned char g0_char)
unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char)
{
return g0_char;
return g0_char;
}
unsigned char get_internal_from_G1 (unsigned char g1_char)
unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char)
{
return g1_char;
return g1_char;
}
// TODO: Probably not right
// G2: Extended Control Code Set 1
unsigned char get_internal_from_G2 (unsigned char g2_char)
unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char)
{
if (g2_char>=0x20 && g2_char<=0x3F)
return g2_char-0x20;
if (g2_char>=0x60 && g2_char<=0x7F)
return g2_char+0x20;
// Rest unmapped, so we return a blank space
return 0x20;
if (g2_char >= 0x20 && g2_char <= 0x3F)
return g2_char - (unsigned char)0x20;
if (g2_char >= 0x60 && g2_char <= 0x7F)
return g2_char + (unsigned char)0x20;
// Rest unmapped, so we return a blank space
return 0x20;
}
// TODO: Probably not right
// G3: Future Characters and Icon Expansion
unsigned char get_internal_from_G3 (unsigned char g3_char)
unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char)
{
if (g3_char==0xa0) // The "CC" (closed captions) sign
return 0x06;
// Rest unmapped, so we return a blank space
return 0x20;
if (g3_char == 0xa0) // The "CC" (closed captions) sign
return 0x06;
// Rest unmapped, so we return a blank space
return 0x20;
}

View File

@@ -0,0 +1,9 @@
#ifndef _CCX_DECODERS_708_ENCODING_H_
#define _CCX_DECODERS_708_ENCODING_H_
unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char);
unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char);
unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char);
unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char);
#endif /*_CCX_DECODERS_708_ENCODING_H_*/

View File

@@ -0,0 +1,425 @@
#include "ccx_decoders_708_output.h"
#include "ccx_encoders_common.h"
#include "utility.h"
#include "ccx_common_common.h"
int _dtvcc_is_row_empty(dtvcc_tv_screen *tv, int row_index)
{
for (int j = 0; j < CCX_DTVCC_SCREENGRID_COLUMNS; j++)
{
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][j]))
return 0;
}
return 1;
}
int _dtvcc_is_screen_empty(dtvcc_tv_screen *tv)
{
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
{
if (!_dtvcc_is_row_empty(tv, i))
return 0;
}
return 1;
}
void _dtvcc_get_write_interval(dtvcc_tv_screen *tv, int row_index, int *first, int *last)
{
for (*first = 0; *first < CCX_DTVCC_SCREENGRID_COLUMNS; (*first)++)
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][*first]))
break;
for (*last = CCX_DTVCC_SCREENGRID_COLUMNS - 1; *last > 0; (*last)--)
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][*last]))
break;
}
void _dtvcc_color_to_hex(int color, unsigned *hR, unsigned *hG, unsigned *hB)
{
*hR = (unsigned) (color >> 4);
*hG = (unsigned) ((color >> 2) & 0x3);
*hB = (unsigned) (color & 0x3);
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] Color: %d [%06x] %u %u %u\n",
color, color, *hR, *hG, *hB);
}
void _dtvcc_write_tag_open(dtvcc_tv_screen *tv, struct encoder_ctx *encoder, int row_index)
{
char *buf = (char *) encoder->buffer;
size_t buf_len = 0;
if (tv->pen_attribs[row_index].italic)
buf_len += sprintf(buf + buf_len, "<i>");
if (tv->pen_attribs[row_index].underline)
buf_len += sprintf(buf + buf_len, "<u>");
if (tv->pen_colors[row_index].fg_color != 0x3f && !encoder->no_font_color) //assuming white is default
{
unsigned red, green, blue;
_dtvcc_color_to_hex(tv->pen_colors[row_index].fg_color, &red, &green, &blue);
red = (255 / 3) * red;
green = (255 / 3) * green;
blue = (255 / 3) * blue;
buf_len += sprintf(buf + buf_len, "<font color=\"%02x%02x%02x\">", red, green, blue);
}
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
}
void _dtvcc_write_tag_close(dtvcc_tv_screen *tv, struct encoder_ctx *encoder, int row_index)
{
char *buf = (char *) encoder->buffer;
size_t buf_len = 0;
if (tv->pen_colors[row_index].fg_color != 0x3f && !encoder->no_font_color)
buf_len += sprintf(buf + buf_len, "</font>");
if (tv->pen_attribs[row_index].underline)
buf_len += sprintf(buf + buf_len, "</u>");
if (tv->pen_attribs[row_index].italic)
buf_len += sprintf(buf + buf_len, "</i>");
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
}
void _dtvcc_write_row(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, int row_index, struct encoder_ctx *encoder)
{
char *buf = (char *) encoder->buffer;
size_t buf_len = 0;
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY * sizeof(char));
int first, last;
_dtvcc_get_write_interval(tv, row_index, &first, &last);
for (int j = first; j <= last; j++)
{
if (CCX_DTVCC_SYM_IS_16(tv->chars[row_index][j]))
{
buf[buf_len++] = CCX_DTVCC_SYM_16_FIRST(tv->chars[row_index][j]);
buf[buf_len++] = CCX_DTVCC_SYM_16_SECOND(tv->chars[row_index][j]);
}
else
{
buf[buf_len++] = CCX_DTVCC_SYM(tv->chars[row_index][j]);
}
}
int fd = encoder->dtvcc_writers[tv->service_number - 1].fd;
if (writer->cd != (iconv_t) -1)
{
char *encoded_buf = calloc(INITIAL_ENC_BUFFER_CAPACITY, sizeof(char));
if (!encoded_buf)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "_dtvcc_write_row");
char *encoded_buf_start = encoded_buf;
size_t in_bytes_left = buf_len;
size_t out_bytes_left = INITIAL_ENC_BUFFER_CAPACITY * sizeof(char);
size_t result = iconv(writer->cd, &buf, &in_bytes_left, &encoded_buf, &out_bytes_left);
if (result == -1)
ccx_common_logging.log_ftn("[CEA-708] _dtvcc_write_row: "
"conversion failed: %s\n", strerror(errno));
write(fd, encoded_buf_start, encoded_buf - encoded_buf_start);
free(encoded_buf_start);
}
else
{
write(fd, buf, buf_len);
}
}
void ccx_dtvcc_write_srt(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
if (_dtvcc_is_screen_empty(tv))
return;
if (tv->time_ms_show + encoder->subs_delay < 0)
return;
char *buf = (char *) encoder->buffer;
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY);
sprintf(buf, "%u%s", tv->cc_count, encoder->encoded_crlf);
mstime_sprintf(tv->time_ms_show + encoder->subs_delay,
"%02u:%02u:%02u,%03u", buf + strlen(buf));
sprintf(buf + strlen(buf), " --> ");
mstime_sprintf(tv->time_ms_hide + encoder->subs_delay,
"%02u:%02u:%02u,%03u", buf + strlen(buf));
sprintf(buf + strlen(buf), (char *) encoder->encoded_crlf);
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
{
if (!_dtvcc_is_row_empty(tv, i))
{
_dtvcc_write_tag_open(tv, encoder, i);
_dtvcc_write_row(writer, tv, i, encoder);
_dtvcc_write_tag_close(tv, encoder, i);
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_crlf, encoder->encoded_crlf_length);
}
}
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_crlf, encoder->encoded_crlf_length);
}
void ccx_dtvcc_write_debug(dtvcc_tv_screen *tv)
{
char tbuf1[SUBLINESIZE],
tbuf2[SUBLINESIZE];
print_mstime2buf(tv->time_ms_show, tbuf1);
print_mstime2buf(tv->time_ms_hide, tbuf2);
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\r%s --> %s\n", tbuf1, tbuf2);
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
{
if (!_dtvcc_is_row_empty(tv, i))
{
int first, last;
_dtvcc_get_write_interval(tv, i, &first, &last);
for (int j = first; j <= last; j++)
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "%c", tv->chars[i][j]);
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\n");
}
}
}
void ccx_dtvcc_write_transcript(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
if (_dtvcc_is_screen_empty(tv))
return;
if (tv->time_ms_show + encoder->subs_delay < 0) // Drop screens that because of subs_delay start too early
return;
char *buf = (char *) encoder->buffer;
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
{
if (!_dtvcc_is_row_empty(tv, i))
{
buf[0] = 0;
if (encoder->transcript_settings->showStartTime)
mstime_sprintf(tv->time_ms_show + encoder->subs_delay,
"%02u:%02u:%02u,%03u|", buf + strlen(buf));
if (encoder->transcript_settings->showEndTime)
mstime_sprintf(tv->time_ms_hide + encoder->subs_delay,
"%02u:%02u:%02u,%03u|", buf + strlen(buf));
if (encoder->transcript_settings->showCC)
sprintf(buf + strlen(buf), "CC1|"); //always CC1 because CEA-708 is field-independent
if (encoder->transcript_settings->showMode)
sprintf(buf + strlen(buf), "POP|"); //TODO caption mode(pop, rollup, etc.)
if (strlen(buf))
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
_dtvcc_write_row(writer, tv, i, encoder);
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_crlf, encoder->encoded_crlf_length);
}
}
}
void _dtvcc_write_sami_header(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
char *buf = (char *) encoder->buffer;
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY);
size_t buf_len = 0;
buf_len += sprintf(buf + buf_len, "<sami>%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "<head>%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "<style type=\"text/css\">%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "<!--%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len,
"p {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;%s",
encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len,
"text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}%s",
encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, ".unknowncc {Name:Unknown; lang:en-US; SAMIType:CC;}%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "-->%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "</style>%s", encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "</head>%s%s", encoder->encoded_crlf, encoder->encoded_crlf);
buf_len += sprintf(buf + buf_len, "<body>%s", encoder->encoded_crlf);
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
}
void _dtvcc_write_sami_footer(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
char *buf = (char *) encoder->buffer;
sprintf(buf, "</body></sami>");
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_crlf, encoder->encoded_crlf_length);
}
void ccx_dtvcc_write_sami(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
if (_dtvcc_is_screen_empty(tv))
return;
if (tv->time_ms_show + encoder->subs_delay < 0)
return;
if (tv->cc_count == 1)
_dtvcc_write_sami_header(tv, encoder);
char *buf = (char *) encoder->buffer;
buf[0] = 0;
sprintf(buf, "<sync start=%llu><p class=\"unknowncc\">%s",
(unsigned long long) tv->time_ms_show + encoder->subs_delay,
encoder->encoded_crlf);
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
{
if (!_dtvcc_is_row_empty(tv, i))
{
_dtvcc_write_tag_open(tv, encoder, i);
_dtvcc_write_row(writer, tv, i, encoder);
_dtvcc_write_tag_close(tv, encoder, i);
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_br, encoder->encoded_br_length);
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
encoder->encoded_crlf, encoder->encoded_crlf_length);
}
}
sprintf(buf, "<sync start=%llu><p class=\"unknowncc\">&nbsp;</p></sync>%s%s",
(unsigned long long) tv->time_ms_hide + encoder->subs_delay,
encoder->encoded_crlf, encoder->encoded_crlf);
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
}
void _ccx_dtvcc_write(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
switch (encoder->write_format)
{
case CCX_OF_NULL:
break;
case CCX_OF_SRT:
ccx_dtvcc_write_srt(writer, tv, encoder);
break;
case CCX_OF_TRANSCRIPT:
ccx_dtvcc_write_transcript(writer, tv, encoder);
break;
case CCX_OF_SAMI:
ccx_dtvcc_write_sami(writer, tv, encoder);
break;
default:
ccx_dtvcc_write_debug(tv);
break;
}
}
void ccx_dtvcc_write_done(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
switch (encoder->write_format)
{
case CCX_OF_SAMI:
_dtvcc_write_sami_footer(tv, encoder);
break;
default:
ccx_common_logging.debug_ftn(
CCX_DMT_708, "[CEA-708] ccx_dtvcc_write_done: no handling required\n");
break;
}
}
void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
char *base_filename,
int program_number,
int service_number,
enum ccx_output_format write_format,
struct encoder_cfg *cfg)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init\n");
writer->fd = -1;
writer->cd = (iconv_t) -1;
if (write_format == CCX_OF_NULL)
{
writer->filename = NULL;
return;
}
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init: "
"[%s][%d][%d]\n", base_filename, program_number, service_number);
char *ext = get_file_extension(write_format);
char suffix[32];
sprintf(suffix, CCX_DTVCC_FILENAME_TEMPLATE, program_number, service_number);
writer->filename = create_outfilename(base_filename, suffix, ext);
if (!writer->filename)
ccx_common_logging.fatal_ftn(
EXIT_NOT_ENOUGH_MEMORY, "[CEA-708] _dtvcc_decoder_init_write: not enough memory");
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init: inited [%s]\n", writer->filename);
char *charset = cfg->all_services_charset ?
cfg->all_services_charset :
cfg->services_charsets[service_number - 1];
if (charset)
{
writer->cd = iconv_open("UTF-8", charset);
if (writer->cd == (iconv_t) -1)
{
ccx_common_logging.fatal_ftn(EXIT_FAILURE, "[CEA-708] dtvcc_init: "
"can't create iconv for charset \"%s\": %s\n",
charset, strerror(errno));
}
}
free(ext);
}
void ccx_dtvcc_writer_cleanup(ccx_dtvcc_writer_ctx *writer)
{
if (writer->fd >= 0 && writer->fd != STDOUT_FILENO)
close(writer->fd);
free(writer->filename);
if (writer->cd == (iconv_t) -1)
{
//TODO nothing to do here
}
else
iconv_close(writer->cd);
}
void ccx_dtvcc_writer_output(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_output: "
"writing... [%s][%d]\n", writer->filename, writer->fd);
if (!writer->filename && writer->fd < 0)
return;
if (writer->filename && writer->fd < 0) //first request to write
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] "
"ccx_dtvcc_writer_output: creating %s\n", writer->filename);
writer->fd = open(writer->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (writer->fd == -1)
{
ccx_common_logging.fatal_ftn(
CCX_COMMON_EXIT_FILE_CREATION_FAILED, "[CEA-708] Failed to open a file\n");
}
if (!encoder->no_bom)
write(writer->fd, UTF8_BOM, sizeof(UTF8_BOM));
}
_ccx_dtvcc_write(writer, tv, encoder);
}

View File

@@ -0,0 +1,19 @@
#ifndef _CCX_DECODERS_708_OUTPUT_H_
#define _CCX_DECODERS_708_OUTPUT_H_
#include "ccx_decoders_708.h"
#include "ccx_encoders_common.h"
#include "ccx_common_option.h"
void ccx_dtvcc_write_done(dtvcc_tv_screen *tv, struct encoder_ctx *encoder);
void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
char *base_filename,
int program_number,
int service_number,
enum ccx_output_format write_format,
struct encoder_cfg *cfg);
void ccx_dtvcc_writer_cleanup(ccx_dtvcc_writer_ctx *writer);
void ccx_dtvcc_writer_output(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder);
#endif /*_CCX_DECODERS_708_OUTPUT_H_*/

View File

@@ -8,96 +8,37 @@ made to reuse, not duplicate, as many functions as possible */
#include "ccx_common_timing.h"
#include "ccx_common_common.h"
#include "lib_ccx.h"
#include "ccx_decoders_608.h"
#include "ccx_decoders_708.h"
#include "ccx_decoders_xds.h"
#include "ccx_dtvcc.h"
uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */
extern int in_xds_mode;
// Preencoded strings
unsigned char encoded_crlf[16];
unsigned int encoded_crlf_length;
unsigned char encoded_br[16];
unsigned int encoded_br_length;
LLONG minimum_fts = 0; // No screen should start before this FTS
/* This function returns a FTS that is guaranteed to be at least 1 ms later than the end of the previous screen. It shouldn't be needed
obviously but it guarantees there's no timing overlap */
LLONG get_visible_start (void)
LLONG get_visible_start (struct ccx_common_timing_ctx *ctx, int current_field)
{
LLONG fts = get_fts();
if (fts <= minimum_fts)
fts = minimum_fts+1;
LLONG fts = get_fts(ctx, current_field);
if (fts <= ctx->minimum_fts)
fts = ctx->minimum_fts + 1;
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible Start time=%s\n", print_mstime(fts));
return fts;
}
/* This function returns the current FTS and saves it so it can be used by get_visible_start */
LLONG get_visible_end (void)
/* This function returns the current FTS and saves it so it can be used by ctxget_visible_start */
LLONG get_visible_end (struct ccx_common_timing_ctx *ctx, int current_field)
{
LLONG fts = get_fts();
if (fts>minimum_fts)
minimum_fts=fts;
LLONG fts = get_fts(ctx, current_field);
if (fts > ctx->minimum_fts)
ctx->minimum_fts = fts;
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible End time=%s\n", print_mstime(fts));
return fts;
}
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank)
{
*last_non_blank = -1;
*first_non_blank = -1;
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
{
unsigned char c = line[i];
if (c != ' ' && c != 0x89)
{
if (*first_non_blank == -1)
*first_non_blank = i;
*last_non_blank = i;
}
}
}
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding)
{
unsigned char *line = data->characters[line_num];
int last_non_blank = -1;
int first_non_blank = -1;
unsigned char *orig = buffer; // Keep for debugging
find_limit_characters(line, &first_non_blank, &last_non_blank);
if (!trim_subs)
first_non_blank = 0;
if (first_non_blank == -1)
{
*buffer = 0;
return 0;
}
int bytes = 0;
for (int i = first_non_blank; i <= last_non_blank; i++)
{
char c = line[i];
switch (encoding)
{
case CCX_ENC_UTF_8:
bytes = get_char_in_utf_8(buffer, c);
break;
case CCX_ENC_LATIN_1:
get_char_in_latin_1(buffer, c);
bytes = 1;
break;
case CCX_ENC_UNICODE:
get_char_in_unicode(buffer, c);
bytes = 2;
break;
}
buffer += bytes;
}
*buffer = 0;
return (unsigned)(buffer - orig); // Return length
}
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub)
{
int ret = -1;
@@ -139,20 +80,20 @@ int validate_cc_data_pair (unsigned char *cc_data_pair)
}
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub)
{
unsigned char cc_valid = (*cc_block & 4) >>2;
unsigned char cc_type = *cc_block & 3;
unsigned char cc_valid = (*cc_block & 4) >>2;
unsigned char cc_type = *cc_block & 3;
int timeok = 1;
int timeok = 1;
if ( ctx->fix_padding
&& cc_valid==0 && cc_type <= 1 // Only fix NTSC packets
&& cc_block[1]==0 && cc_block[2]==0 )
{
/* Padding */
cc_valid=1;
cc_block[1]=0x80;
cc_block[2]=0x80;
}
if ( ctx->fix_padding
&& cc_valid==0 && cc_type <= 1 // Only fix NTSC packets
&& cc_block[1]==0 && cc_block[2]==0 )
{
/* Padding */
cc_valid=1;
cc_block[1]=0x80;
cc_block[2]=0x80;
}
if ( ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
ctx->write_format!=CCX_OF_DVDRAW &&
@@ -160,116 +101,128 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
&& (cc_block[1]&0x7F)==0 && (cc_block[2]&0x7F)==0) // CFS: Skip non-data, makes debugging harder.
return 1;
// Print raw data with FTS.
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(fts_now + fts_global),in_xds_mode,
cc_block[0], cc_block[1]&0x7f,cc_block[2]&0x7f, cc_block[2]);
// Print raw data with FTS.
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(ctx->timing->fts_now + ctx->timing->fts_global),in_xds_mode,
cc_block[0], cc_block[1]&0x7f,cc_block[2]&0x7f, cc_block[2]);
/* In theory the writercwtdata() function could return early and not
* go through the 608/708 cases below. We do that to get accurate
* counts for cb_field1, cb_field2 and cb_708.
* Note that printdata() and do_708() must not be called for
* the CCX_OF_RCWT case. */
/* In theory the writercwtdata() function could return early and not
* go through the 608/708 cases below. We do that to get accurate
* counts for cb_field1, cb_field2 and cb_708.
* Note that printdata() and dtvcc_process_data() must not be called for
* the CCX_OF_RCWT case. */
if (cc_valid || cc_type==3)
{
ctx->cc_stats[cc_type]++;
if (cc_valid || cc_type==3)
{
ctx->cc_stats[cc_type]++;
switch (cc_type)
{
case 0:
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
switch (cc_type)
{
case 0:
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
current_field=1;
ctx->saw_caption_block = 1;
ctx->current_field = 1;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, cc_block+1,2,0,0, sub);
else
writercwtdata(ctx, cc_block);
}
cb_field1++;
break;
case 1:
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
if (ctx->extraction_start.set &&
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, cc_block+1,2,0,0, sub);
else
writercwtdata(ctx, cc_block, sub);
}
cb_field1++;
break;
case 1:
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
current_field=2;
ctx->saw_caption_block = 1;
ctx->current_field = 2;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, 0,0,cc_block+1,2, sub);
else
writercwtdata(ctx, cc_block);
}
cb_field2++;
break;
case 2: //EIA-708
// DTVCC packet data
// Fall through
case 3: //EIA-708
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
if (ctx->extraction_start.set &&
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, 0,0,cc_block+1,2, sub);
else
writercwtdata(ctx, cc_block, sub);
}
cb_field2++;
break;
case 2: //EIA-708
// DTVCC packet data
// Fall through
case 3: //EIA-708
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
// DTVCC packet start
current_field=3;
// DTVCC packet start
ctx->current_field = 3;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
char temp[4];
temp[0]=cc_valid;
temp[1]=cc_type;
temp[2]=cc_block[1];
temp[3]=cc_block[2];
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
do_708 (ctx,(const unsigned char *) temp, 4);
else
writercwtdata(ctx, cc_block);
}
cb_708++;
// Check for bytes read
// printf ("Warning: Losing EIA-708 data!\n");
break;
default:
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
} // switch (cc_type)
} // cc_valid
else
{
dbg_print(CCX_DMT_CBRAW, " .. .. ..\n");
dbg_print(CCX_DMT_VERBOSE, "Found !(cc_valid || cc_type==3) - ignore this block\n");
}
if (ctx->extraction_start.set &&
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
char temp[4];
temp[0]=cc_valid;
temp[1]=cc_type;
temp[2]=cc_block[1];
temp[3]=cc_block[2];
if (timeok)
{
if (ctx->write_format != CCX_OF_RCWT)
ccx_dtvcc_process_data(ctx, (const unsigned char *) temp, 4);
else
writercwtdata(ctx, cc_block, sub);
}
cb_708++;
// Check for bytes read
// printf ("Warning: Losing EIA-708 data!\n");
break;
default:
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
} // switch (cc_type)
} // cc_valid
else
{
dbg_print(CCX_DMT_CBRAW, " .. .. ..\n");
dbg_print(CCX_DMT_VERBOSE, "Found !(cc_valid || cc_type==3) - ignore this block\n");
}
return 1;
return 1;
}
void dinit_cc_decode(struct lib_cc_decode **ctx)
{
struct lib_cc_decode *lctx = *ctx;
ccx_dtvcc_free(&lctx->dtvcc);
dinit_avc(&lctx->avc_ctx);
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
dinit_timing_ctx(&lctx->timing);
freep(ctx);
}
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting)
{
struct lib_cc_decode *ctx = NULL;
@@ -278,42 +231,162 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
if(!ctx)
return NULL;
// Prepare 608 context
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
ccx_options.settings_608,
ccx_options.cc_channel,
1,
ccx_options.trim_subs,
ccx_options.encoding,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->subs_delay,
setting->output_format
);
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
ccx_options.settings_608,
ccx_options.cc_channel,
2,
ccx_options.trim_subs,
ccx_options.encoding,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->subs_delay,
setting->output_format
);
ctx->avc_ctx = init_avc();
ctx->codec = setting->codec;
ctx->timing = init_timing_ctx(&ccx_common_timing_settings);
setting->settings_dtvcc->timing = ctx->timing;
setting->settings_608->no_rollup = setting->no_rollup;
setting->settings_dtvcc->no_rollup = setting->no_rollup;
ctx->no_rollup = setting->no_rollup;
ctx->dtvcc = ccx_dtvcc_init(setting->settings_dtvcc);
ctx->dtvcc->is_active = setting->settings_dtvcc->enabled;
if(setting->codec == CCX_CODEC_ATSC_CC)
{
// Prepare 608 context
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
setting->settings_608,
setting->cc_channel,
1,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->output_format,
ctx->timing
);
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
setting->settings_608,
setting->cc_channel,
2,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->output_format,
ctx->timing
);
}
else
{
ctx->context_cc608_field_1 = NULL;
ctx->context_cc608_field_2 = NULL;
}
ctx->current_field = 1;
ctx->private_data = setting->private_data;
ctx->fix_padding = setting->fix_padding;
ctx->write_format = setting->output_format;
ctx->subs_delay = setting->subs_delay;
ctx->wbout1 = setting->wbout1;
ctx->extract = setting->extract;
ctx->fullbin = setting->fullbin;
ctx->hauppauge_mode = setting->hauppauge_mode;
ctx->program_number = setting->program_number;
ctx->processed_enough = 0;
ctx->max_gop_length = 0;
ctx->has_ccdata_buffered = 0;
ctx->in_bufferdatatype = CCX_UNKNOWN;
ctx->frames_since_last_gop = 0;
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
if (setting->send_to_srv)
ctx->writedata = net_send_cc;
else if (setting->output_format==CCX_OF_RAW ||
setting->output_format==CCX_OF_DVDRAW ||
setting->output_format==CCX_OF_RCWT )
ctx->writedata = writeraw;
else if (setting->output_format==CCX_OF_SMPTETT ||
setting->output_format==CCX_OF_SAMI ||
setting->output_format==CCX_OF_SRT ||
setting->output_format == CCX_OF_WEBVTT ||
setting->output_format==CCX_OF_TRANSCRIPT ||
setting->output_format==CCX_OF_SPUPNG ||
setting->output_format==CCX_OF_SIMPLE_XML ||
setting->output_format==CCX_OF_NULL)
ctx->writedata = process608;
else
fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid Write Format Selected");
memset (&ctx->dec_sub, 0,sizeof(ctx->dec_sub));
// Initialize HDTV caption buffer
init_hdcc(ctx);
ctx->current_hor_size = 0;
ctx->current_vert_size = 0;
ctx->current_aspect_ratio = 0;
ctx->current_frame_rate = 4; // Assume standard fps, 29.97
//Variables used while parsing elementry stream
ctx->no_bitstream_error = 0;
ctx->saw_seqgoppic = 0;
ctx->in_pic_data = 0;
ctx->current_progressive_sequence = 2;
ctx->current_pulldownfields = 32768;
ctx->temporal_reference = 0;
ctx->maxtref = 0;
ctx->picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
ctx->picture_structure = 0;
ctx->top_field_first = 0;
ctx->repeat_first_field = 0;
ctx->progressive_frame = 0;
ctx->pulldownfields = 0;
//es parser related variable ends here
memset(ctx->cc_stats, 0, 4 * sizeof(int));
ctx->anchor_seq_number = -1;
// Init XDS buffers
if(setting->ignore_xds == CCX_TRUE)
ctx->xds_ctx = NULL;
else
ctx->xds_ctx = ccx_decoders_xds_init_library(ctx->timing);
//xds_cea608_test(ctx->xds_ctx);
return ctx;
}
void dinit_cc_decode(struct lib_cc_decode **ctx)
void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
{
struct lib_cc_decode *lctx = *ctx;
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
freep(ctx);
if(ctx->codec == CCX_CODEC_ATSC_CC)
{
if (ctx->extract != 2)
{
if (ctx->write_format==CCX_OF_SMPTETT || ctx->write_format==CCX_OF_SAMI ||
ctx->write_format==CCX_OF_SRT || ctx->write_format==CCX_OF_TRANSCRIPT ||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG)
{
flush_608_context(ctx->context_cc608_field_1, sub);
}
else if(ctx->write_format == CCX_OF_RCWT)
{
// Write last header and data
writercwtdata (ctx, NULL, sub);
}
}
if (ctx->extract != 1)
{
if (ctx->write_format == CCX_OF_SMPTETT || ctx->write_format == CCX_OF_SAMI ||
ctx->write_format == CCX_OF_SRT || ctx->write_format == CCX_OF_TRANSCRIPT ||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG)
{
flush_608_context(ctx->context_cc608_field_2, sub);
}
}
}
if (ctx->dtvcc->is_active)
{
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
ccx_dtvcc_service_decoder *decoder = &ctx->dtvcc->decoders[i];
if (!ctx->dtvcc->services_active[i])
continue;
if (decoder->cc_count > 0)
{
ctx->current_field = 3;
ccx_dtvcc_decoder_flush(ctx->dtvcc, decoder);
}
}
}
}

View File

@@ -5,22 +5,15 @@
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
extern unsigned char encoded_crlf[16]; // We keep it encoded here so we don't have to do it many times
extern unsigned int encoded_crlf_length;
extern unsigned char encoded_br[16];
extern unsigned int encoded_br_length;
extern LLONG minimum_fts; // No screen should start before this FTS
#include "ccx_common_option.h"
extern uint64_t utc_refvalue; // UTC referential value
// Declarations
LLONG get_visible_start(void);
LLONG get_visible_end(void);
LLONG get_visible_start (struct ccx_common_timing_ctx *ctx, int current_field);
LLONG get_visible_end (struct ccx_common_timing_ctx *ctx, int current_field);
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank);
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding);
unsigned int get_decoder_str_basic(unsigned char *buffer, unsigned char *line, int trim_subs, enum ccx_encoding_type encoding);
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format);
@@ -31,4 +24,5 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt
const unsigned char *data2, int length2, struct cc_subtitle *sub);
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting);
void dinit_cc_decode(struct lib_cc_decode **ctx);
void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
#ifndef ISDB_H
#define ISDB_H
#include "ccx_common_platform.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
int isdb_set_global_time(struct lib_cc_decode *dec_ctx, uint64_t timestamp);
int isdbsub_decode(struct lib_cc_decode *dec_ctx, const uint8_t *buf, size_t buf_size, struct cc_subtitle *sub);
void delete_isdb_decoder(void **isdb_ctx);
void *init_isdb_decoder(void);
#endif

View File

@@ -4,9 +4,14 @@
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
#include "ccx_common_timing.h"
#include "ccx_common_structs.h"
#include "list.h"
#include "ccx_decoders_708.h"
// Define max width in characters/columns on the screen
#define CCX_DECODER_608_SCREEN_WIDTH 32
#define MAXBFRAMES 50
#define SORTBUF (2*MAXBFRAMES+1)
/* flag raised when end of display marker arrives in Dvb Subtitle */
#define SUB_EOD_MARKER (1 << 0 )
@@ -81,9 +86,21 @@ struct ccx_decoders_common_settings_t
enum ccx_output_format output_format; // What kind of output format should be used?
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
void *wbout1;
int cc_to_stdout;
int extract; // Extract 1st, 2nd or both fields
int fullbin; // Disable pruning of padding cc blocks
int no_rollup;
struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder.
ccx_decoder_dtvcc_settings *settings_dtvcc; //Same for cea 708 captions decoder (dtvcc)
int cc_channel; // Channel we want to dump in srt mode
unsigned send_to_srv;
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
int program_number;
enum ccx_code_type codec;
int ignore_xds;
void *private_data;
};
struct lib_cc_decode
{
int cc_stats[4];
@@ -95,12 +112,75 @@ struct lib_cc_decode
void *context_cc608_field_1;
void *context_cc608_field_2;
int no_rollup; // If 1, write one line at a time
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
void *wbout1;
void *wbout2;
LLONG subs_delay; // ms to delay (or advance) subs
int extract; // Extract 1st, 2nd or both fields
int fullbin; // Disable pruning of padding cc blocks
struct cc_subtitle dec_sub;
enum ccx_bufferdata_type in_bufferdatatype;
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
int frames_since_last_gop;
/* GOP-based timing */
int saw_gop_header;
/* Time info for timed-transcript */
int max_gop_length; // (Maximum) length of a group of pictures
int last_gop_length; // Length of the previous group of pictures
unsigned total_pulldownfields;
unsigned total_pulldownframes;
int program_number;
struct list_head list;
struct ccx_common_timing_ctx *timing;
enum ccx_code_type codec;
// Set to true if data is buffered
int has_ccdata_buffered;
struct avc_ctx *avc_ctx;
void *private_data;
/* General video information */
unsigned int current_hor_size;
unsigned int current_vert_size;
unsigned int current_aspect_ratio;
unsigned int current_frame_rate; // Assume standard fps, 29.97
/* Reguired in es_function.c */
int no_bitstream_error;
int saw_seqgoppic;
int in_pic_data;
unsigned int current_progressive_sequence;
unsigned int current_pulldownfields ;
int temporal_reference;
enum ccx_frame_type picture_coding_type;
unsigned picture_structure;
unsigned repeat_first_field;
unsigned progressive_frame;
unsigned pulldownfields;
/* Reguired in es_function.c and es_userdata.c */
unsigned top_field_first; // Needs to be global
ccx_dtvcc_ctx *dtvcc;
int current_field;
// Analyse/use the picture information
int maxtref; // Use to remember the temporal reference number
int cc_data_count[SORTBUF];
// Store fts;
LLONG cc_fts[SORTBUF];
// Store HD CC packets
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
// The sequence number of the current anchor frame. All currently read
// B-Frames belong to this I- or P-frame.
int anchor_seq_number;
struct ccx_decoders_xds_context *xds_ctx;
int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,13 @@
#ifndef _XDS_H
#define _XDS_H
#ifndef CCX_DECODER_XDS_H
#define CCX_DECODER_XDS_H
#include "ccx_decoders_common.h"
#include "ccx_encoders_common.h"
void process_xds_bytes(const unsigned char hi, int lo);
void do_end_of_xds(struct cc_subtitle *sub, unsigned char expected_checksum);
struct ccx_decoders_xds_context;
void process_xds_bytes (struct ccx_decoders_xds_context *ctx, const unsigned char hi, int lo);
void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned char expected_checksum);
void ccx_decoders_xds_init_library(ccx_encoders_transcript_format *transcriptSettings, LLONG subs_delay, char millis_separator);
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);
struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing);
void xds_cea608_test();
#endif

381
src/lib_ccx/ccx_demuxer.c Normal file
View File

@@ -0,0 +1,381 @@
#include "ccx_demuxer.h"
#include "activity.h"
#include "lib_ccx.h"
#include "utility.h"
static void ccx_demuxer_reset(struct ccx_demuxer *ctx)
{
ctx->startbytes_pos=0;
ctx->startbytes_avail=0;
memset (ctx->PIDs_seen, 0, 65536*sizeof (int));
memset (ctx->PIDs_programs, 0, 65536*sizeof (struct PMT_entry *));
}
static void ccx_demuxer_close(struct ccx_demuxer *ctx)
{
ctx->past = 0;
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
{
close (ctx->infd);
ctx->infd=-1;
activity_input_file_closed();
}
}
static int ccx_demuxer_isopen(struct ccx_demuxer *ctx)
{
return ctx->infd != -1;
}
static int ccx_demuxer_open(struct ccx_demuxer *ctx, const char *file)
{
init_file_buffer(ctx);
if (ccx_options.input_source==CCX_DS_STDIN)
{
if (ctx->infd != -1) // Means we had already processed stdin. So we're done.
{
if (ccx_options.print_file_reports)
print_file_report(ctx->parent);
return -1;
}
ctx->infd = 0;
mprint ("\n\r-----------------------------------------------------------------\n");
mprint ("\rReading from standard input\n");
}
else if (ccx_options.input_source == CCX_DS_NETWORK)
{
if (ctx->infd != -1) // Means we have already bound a socket.
{
if (ccx_options.print_file_reports)
print_file_report(ctx->parent);
return -1;
}
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
if(ctx->infd < 0)
{
print_error(ccx_options.gui_mode_reports,"socket() failed.");
return CCX_COMMON_EXIT_BUG_BUG;
}
}
else if (ccx_options.input_source == CCX_DS_TCP)
{
if (ctx->infd != -1)
{
if (ccx_options.print_file_reports)
print_file_report(ctx->parent);
return -1;
}
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
}
else
{
#ifdef _WIN32
ctx->infd = OPEN (file, O_RDONLY | O_BINARY);
#else
ctx->infd = OPEN (file, O_RDONLY);
#endif
if (ctx->infd < 0)
return -1;
}
if (ctx->auto_stream == CCX_SM_AUTODETECT)
{
detect_stream_type(ctx);
switch (ctx->stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
mprint ("\rFile seems to be an elementary stream, enabling ES mode\n");
break;
case CCX_SM_TRANSPORT:
mprint ("\rFile seems to be a transport stream, enabling TS mode\n");
break;
case CCX_SM_PROGRAM:
mprint ("\rFile seems to be a program stream, enabling PS mode\n");
break;
case CCX_SM_ASF:
mprint ("\rFile seems to be an ASF, enabling DVR-MS mode\n");
break;
case CCX_SM_WTV:
mprint ("\rFile seems to be a WTV, enabling WTV mode\n");
break;
case CCX_SM_MCPOODLESRAW:
mprint ("\rFile seems to be McPoodle raw data\n");
break;
case CCX_SM_RCWT:
mprint ("\rFile seems to be a raw caption with time data\n");
break;
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(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
break;
}
}
else
{
ctx->stream_mode = ctx->auto_stream;
}
// The myth loop autodetect will only be used with ES or PS streams
switch (ccx_options.auto_myth)
{
case 0:
// Use whatever stream mode says
break;
case 1:
// Force stream mode to myth
ctx->stream_mode=CCX_SM_MYTH;
break;
case 2:
// autodetect myth files, but only if it does not conflict with
// the current stream mode
switch (ctx->stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
case CCX_SM_PROGRAM:
if ( detect_myth(ctx->parent) )
{
ctx->stream_mode=CCX_SM_MYTH;
}
break;
default:
// Keep stream_mode
break;
}
break;
}
ctx->past = 0;
ctx->min_global_timestamp = 0;
ctx->global_timestamp_inited = 0;
ctx->last_global_timestamp = 0;
ctx->offset_global_timestamp = 0;
return 0;
}
LLONG ccx_demuxer_getfilesize (struct ccx_demuxer *ctx)
{
LLONG ret = 0;
int in = ctx->infd;
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;
}
static int ccx_demuxer_get_stream_mode(struct ccx_demuxer *ctx)
{
return ctx->stream_mode;
}
static void ccx_demuxer_print_cfg(struct ccx_demuxer *ctx)
{
switch (ctx->auto_stream)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
mprint ("Elementary");
break;
case CCX_SM_TRANSPORT:
mprint ("Transport");
break;
case CCX_SM_PROGRAM:
mprint ("Program");
break;
case CCX_SM_ASF:
mprint ("DVR-MS");
break;
case CCX_SM_WTV:
mprint ("Windows Television (WTV)");
break;
case CCX_SM_MCPOODLESRAW:
mprint ("McPoodle's raw");
break;
case CCX_SM_AUTODETECT:
mprint ("Autodetect");
break;
case CCX_SM_RCWT:
mprint ("BIN");
break;
case CCX_SM_MP4:
mprint ("MP4");
break;
#ifdef WTV_DEBUG
case CCX_SM_HEX_DUMP:
mprint ("Hex");
break;
#endif
default:
fatal(CCX_COMMON_EXIT_BUG_BUG, "BUG: Unknown stream mode.\n");
break;
}
}
int ccx_demuxer_write_es(struct ccx_demuxer *ctx, unsigned char* buf, size_t len)
{
if (ctx->fh_out_elementarystream!=NULL)
fwrite (buf, 1, len,ctx->fh_out_elementarystream);
return CCX_OK;
}
void ccx_demuxer_delete(struct ccx_demuxer **ctx)
{
struct ccx_demuxer *lctx = *ctx;
int i;
dinit_cap(lctx);
freep(&lctx->last_pat_payload);
for (i = 0; i < MAX_PSI_PID; i++)
{
if(lctx->PID_buffers[i]!=NULL && lctx->PID_buffers[i]->buffer!=NULL)
{
free(lctx->PID_buffers[i]->buffer);
lctx->PID_buffers[i]->buffer=NULL;
lctx->PID_buffers[i]->buffer_length=0;
}
freep(&lctx->PID_buffers[i]);
}
for (i = 0; i < MAX_PID; i++)
{
if( lctx->PIDs_programs[i])
freep(lctx->PIDs_programs + i);
}
if (lctx->fh_out_elementarystream != NULL)
fclose (lctx->fh_out_elementarystream);
freep(&lctx->filebuffer);
freep(ctx);
}
struct ccx_demuxer *init_demuxer(void *parent, struct demuxer_cfg *cfg)
{
int i;
struct ccx_demuxer *ctx = malloc(sizeof(struct ccx_demuxer));
if(!ctx)
return NULL;
ctx->infd = -1;//Set to -1 to indicate no file is open.
ctx->m2ts = cfg->m2ts;
ctx->auto_stream = cfg->auto_stream;
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
ctx->ts_autoprogram = cfg->ts_autoprogram;
ctx->ts_allprogram = cfg->ts_allprogram;
ctx->ts_datastreamtype = cfg->ts_datastreamtype;
ctx->nb_program = 0;
ctx->multi_stream_per_prog = 0;
if(cfg->ts_forced_program != -1)
{
ctx->pinfo[ctx->nb_program].pid = CCX_UNKNOWN;
ctx->pinfo[ctx->nb_program].program_number = cfg->ts_forced_program;
ctx->flag_ts_forced_pn = CCX_TRUE;
ctx->nb_program++;
}
else
{
ctx->flag_ts_forced_pn = CCX_FALSE;
}
INIT_LIST_HEAD(&ctx->cinfo_tree.all_stream);
INIT_LIST_HEAD(&ctx->cinfo_tree.sib_stream);
INIT_LIST_HEAD(&ctx->cinfo_tree.pg_stream);
ctx->codec = cfg->codec;
ctx->flag_ts_forced_cappid = CCX_FALSE;
for(i = 0; i < cfg->nb_ts_cappid; i++)
{
if(ctx->codec == CCX_CODEC_ANY)
update_capinfo(ctx, cfg->ts_cappids[i], cfg->ts_datastreamtype, CCX_CODEC_NONE, 0, NULL);
else
update_capinfo(ctx, cfg->ts_cappids[i], cfg->ts_datastreamtype, ctx->codec, 0, NULL);
}
ctx->flag_ts_forced_cappid = cfg->nb_ts_cappid ? CCX_TRUE : CCX_FALSE;
ctx->nocodec = cfg->nocodec;
ctx->reset = ccx_demuxer_reset;
ctx->close = ccx_demuxer_close;
ctx->open = ccx_demuxer_open;
ctx->is_open = ccx_demuxer_isopen;
ctx->get_filesize = ccx_demuxer_getfilesize;
ctx->get_stream_mode = ccx_demuxer_get_stream_mode;
ctx->print_cfg = ccx_demuxer_print_cfg;
ctx->write_es = ccx_demuxer_write_es;
ctx->hauppauge_warning_shown = 0;
ctx->parent = parent;
ctx->last_pat_payload = NULL;
ctx->last_pat_length = 0;
ctx->fh_out_elementarystream = NULL;
ctx->warning_program_not_found_shown = CCX_FALSE;
ctx->strangeheader = 0;
memset(&ctx->freport, 0, sizeof(ctx->freport));
if (cfg->out_elementarystream_filename != NULL)
{
if ((ctx->fh_out_elementarystream = fopen (cfg->out_elementarystream_filename,"wb"))==NULL)
{
print_error(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to open clean file: %s\n", cfg->out_elementarystream_filename);
return NULL;
}
}
for(i = 0; i < MAX_PSI_PID; i++)
ctx->PID_buffers[i]=NULL;
init_ts(ctx);
ctx->filebuffer = NULL;
return ctx;
}
void delete_demuxer_data(struct demuxer_data *data)
{
free(data->buffer);
free(data);
}
struct demuxer_data* alloc_demuxer_data(void)
{
struct demuxer_data* data = malloc(sizeof(struct demuxer_data));
if(!data)
{
return NULL;
}
data->buffer = (unsigned char *) malloc (BUFSIZE);
if(!data->buffer)
{
free(data);
return NULL;
}
data->len = 0;
data->bufferdatatype = CCX_PES;
data->program_number = -1;
data->stream_pid = -1;
data->codec = CCX_CODEC_NONE;
data->len = 0;
data->pts = CCX_NOPTS;
data->next_stream = 0;
data->next_program = 0;
return data;
}

174
src/lib_ccx/ccx_demuxer.h Normal file
View File

@@ -0,0 +1,174 @@
#ifndef CCX_DEMUXER_H
#define CCX_DEMUXER_H
#include "ccx_common_constants.h"
#include "ccx_common_option.h"
#include "ts_functions.h"
#include "list.h"
#include "activity.h"
/* Report information */
#define SUB_STREAMS_CNT 10
#define MAX_PID 65536
#define MAX_PSI_PID 8191
#define TS_PMT_MAP_SIZE 128
#define MAX_PROGRAM 128
#define MAX_PROGRAM_NAME_LEN 128
struct ccx_demux_report
{
unsigned program_cnt;
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
unsigned mp4_cc_track_cnt;
};
struct program_info
{
int pid;
int program_number;
uint8_t analysed_PMT_once:1;
uint8_t version;
uint8_t saved_section[1021];
int32_t crc;
uint8_t valid_crc:1;
char name[MAX_PROGRAM_NAME_LEN];
/**
* -1 pid represent that pcr_pid is not available
*/
int16_t pcr_pid;
};
struct cap_info
{
int pid;
int program_number;
enum ccx_stream_type stream;
enum ccx_code_type codec;
long capbufsize;
unsigned char *capbuf;
long capbuflen; // Bytes read in capbuf
int saw_pesstart;
int prev_counter;
void *codec_private_data;
int ignore;
/**
List joining all stream in TS
*/
struct list_head all_stream;
/**
List joining all sibling Stream in Program
*/
struct list_head sib_head;
struct list_head sib_stream;
/**
List joining all sibling Stream in Program
*/
struct list_head pg_stream;
};
struct ccx_demuxer
{
int m2ts;
enum ccx_stream_mode_enum stream_mode;
enum ccx_stream_mode_enum auto_stream;
// Small buffer to help us with the initial sync
unsigned char startbytes[STARTBYTESLENGTH];
unsigned int startbytes_pos;
int startbytes_avail;
// User Specified Param
int ts_autoprogram;
int ts_allprogram;
int flag_ts_forced_pn;
int flag_ts_forced_cappid;
int ts_datastreamtype;
struct program_info pinfo[MAX_PROGRAM];
int nb_program;
/* subtitle codec type */
enum ccx_code_type codec;
enum ccx_code_type nocodec;
struct cap_info cinfo_tree;
/* File handles */
FILE *fh_out_elementarystream;
int infd; // descriptor number to input.
LLONG past; /* Position in file, if in sync same as ftell() */
// TODO relates to fts_global
int64_t global_timestamp;
int64_t min_global_timestamp;
int64_t offset_global_timestamp;
int64_t last_global_timestamp;
int global_timestamp_inited;
struct PSI_buffer *PID_buffers[MAX_PSI_PID];
int PIDs_seen[MAX_PID];
struct PMT_entry *PIDs_programs[MAX_PID];
struct ccx_demux_report freport;
/* Hauppauge support */
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
int multi_stream_per_prog;
unsigned char *last_pat_payload;
unsigned last_pat_length;
unsigned char *filebuffer;
LLONG filebuffer_start; // Position of buffer start relative to file
unsigned int filebuffer_pos; // Position of pointer relative to buffer start
unsigned int bytesinbuffer; // Number of bytes we actually have on buffer
int warning_program_not_found_shown;
// Remember if the last header was valid. Used to suppress too much output
// and the expected unrecognized first header for TiVo files.
int strangeheader;
void *parent;
void (*print_cfg)(struct ccx_demuxer *ctx);
void (*reset)(struct ccx_demuxer *ctx);
void (*close)(struct ccx_demuxer *ctx);
int (*open)(struct ccx_demuxer *ctx, const char *file_name);
int (*is_open)(struct ccx_demuxer *ctx);
int (*get_stream_mode)(struct ccx_demuxer *ctx);
LLONG (*get_filesize) (struct ccx_demuxer *ctx);
int (*write_es)(struct ccx_demuxer *ctx, unsigned char* buf, size_t len);
};
struct demuxer_data
{
int program_number;
int stream_pid;
enum ccx_code_type codec;
enum ccx_bufferdata_type bufferdatatype;
unsigned char *buffer;
size_t len;
LLONG pts;
struct demuxer_data *next_stream;
struct demuxer_data *next_program;
};
struct cap_info *get_sib_stream_by_type(struct cap_info* program, enum ccx_code_type type);
struct ccx_demuxer *init_demuxer(void *parent, struct demuxer_cfg *cfg);
void ccx_demuxer_delete(struct ccx_demuxer **ctx);
struct demuxer_data* alloc_demuxer_data(void);
void delete_demuxer_data(struct demuxer_data *data);
int update_capinfo(struct ccx_demuxer *ctx, int pid, enum ccx_stream_type stream, enum ccx_code_type codec, int pn, void *private_data);
struct cap_info * get_cinfo(struct ccx_demuxer *ctx, int pid);
int need_capInfo(struct ccx_demuxer *ctx, int program_number);
int need_capInfo_for_pid(struct ccx_demuxer *ctx, int pid);
struct demuxer_data *get_best_data(struct demuxer_data *data);
struct demuxer_data *get_data_stream(struct demuxer_data *data, int pid);
int get_best_stream(struct ccx_demuxer *ctx);
void ignore_other_stream(struct ccx_demuxer *ctx, int pid);
void dinit_cap (struct ccx_demuxer *ctx);
int get_programme_number(struct ccx_demuxer *ctx, int pid);
struct cap_info* get_best_sib_stream(struct cap_info* program);
void ignore_other_sib_stream(struct cap_info* head, int pid);
#endif

147
src/lib_ccx/ccx_dtvcc.c Normal file
View File

@@ -0,0 +1,147 @@
#include "ccx_dtvcc.h"
#include "ccx_common_common.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_708_output.h"
void ccx_dtvcc_process_data(struct lib_cc_decode *ctx,
const unsigned char *data,
int data_length)
{
/*
* Note: the data has following format:
* 1 byte for cc_valid
* 1 byte for cc_type
* 2 bytes for the actual data
*/
ccx_dtvcc_ctx *dtvcc = ctx->dtvcc;
if (!dtvcc->is_active && !dtvcc->report_enabled)
return;
for (int i = 0; i < data_length; i += 4)
{
unsigned char cc_valid = data[i];
unsigned char cc_type = data[i + 1];
switch (cc_type)
{
case 2:
ccx_common_logging.debug_ftn (CCX_DMT_708, "[CEA-708] dtvcc_process_data: DTVCC Channel Packet Data\n");
if (cc_valid == 0) // This ends the previous packet
ccx_dtvcc_process_current_packet(dtvcc);
else
{
if (dtvcc->current_packet_length > 253)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] dtvcc_process_data: "
"Warning: Legal packet size exceeded (1), data not added.\n");
}
else
{
dtvcc->current_packet[dtvcc->current_packet_length++] = data[i + 2];
dtvcc->current_packet[dtvcc->current_packet_length++] = data[i + 3];
}
}
break;
case 3:
ccx_common_logging.debug_ftn (CCX_DMT_708, "[CEA-708] dtvcc_process_data: DTVCC Channel Packet Start\n");
ccx_dtvcc_process_current_packet(dtvcc);
if (cc_valid)
{
if (dtvcc->current_packet_length > CCX_DTVCC_MAX_PACKET_LENGTH - 1)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] dtvcc_process_data: "
"Warning: Legal packet size exceeded (2), data not added.\n");
}
else
{
dtvcc->current_packet[dtvcc->current_packet_length++] = data[i + 2];
dtvcc->current_packet[dtvcc->current_packet_length++] = data[i + 3];
}
}
break;
default:
ccx_common_logging.fatal_ftn (CCX_COMMON_EXIT_BUG_BUG, "[CEA-708] dtvcc_process_data: "
"shouldn't be here - cc_type: %d\n", cc_type);
}
}
}
//--------------------------------------------------------------------------------------
ccx_dtvcc_ctx *ccx_dtvcc_init(struct ccx_decoder_dtvcc_settings *opts)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] initializing dtvcc decoder\n");
ccx_dtvcc_ctx *ctx = (ccx_dtvcc_ctx *) malloc(sizeof(ccx_dtvcc_ctx));
if (!ctx)
{
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "[CEA-708] ccx_dtvcc_init");
return NULL;
}
ctx->report = opts->report;
ctx->report->reset_count = 0;
ctx->is_active = 0;
ctx->report_enabled = 0;
ctx->no_rollup = opts->no_rollup;
ctx->active_services_count = opts->active_services_count;
memcpy(ctx->services_active, opts->services_enabled, CCX_DTVCC_MAX_SERVICES * sizeof(int));
ccx_dtvcc_clear_packet(ctx);
ctx->last_sequence = CCX_DTVCC_NO_LAST_SEQUENCE;
ctx->report_enabled = opts->print_file_reports;
ctx->timing = opts->timing;
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] initializing services\n");
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
if (!ctx->services_active[i])
continue;
ccx_dtvcc_service_decoder *decoder = &ctx->decoders[i];
decoder->cc_count = 0;
decoder->tv = (dtvcc_tv_screen *) malloc(sizeof(dtvcc_tv_screen));
decoder->tv->service_number = i + 1;
decoder->tv->cc_count = 0;
if (!decoder->tv)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "ccx_dtvcc_init");
for (int j = 0; j < CCX_DTVCC_MAX_WINDOWS; j++)
decoder->windows[j].memory_reserved = 0;
ccx_dtvcc_windows_reset(decoder);
}
return ctx;
}
void ccx_dtvcc_free(ccx_dtvcc_ctx **ctx_ptr)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] dtvcc_free: cleaning up\n");
ccx_dtvcc_ctx *ctx = *ctx_ptr;
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
if (!ctx->services_active[i])
continue;
ccx_dtvcc_service_decoder *decoder = &ctx->decoders[i];
for (int j = 0; j < CCX_DTVCC_MAX_WINDOWS; j++)
if (decoder->windows[j].memory_reserved)
{
for (int k = 0; k < CCX_DTVCC_MAX_ROWS; k++)
free(decoder->windows[j].rows[k]);
decoder->windows[j].memory_reserved = 0;
}
free(decoder->tv);
}
freep(ctx_ptr);
}

14
src/lib_ccx/ccx_dtvcc.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef CCEXTRACTOR_CCX_DTVCC_H
#define CCEXTRACTOR_CCX_DTVCC_H
#include "ccx_decoders_708.h"
#include "ccx_common_option.h"
void ccx_dtvcc_process_data(struct lib_cc_decode *ctx,
const unsigned char *data,
int data_length);
ccx_dtvcc_ctx *ccx_dtvcc_init(ccx_decoder_dtvcc_settings *opts);
void ccx_dtvcc_free(ccx_dtvcc_ctx **);
#endif //CCEXTRACTOR_CCX_DTVCC_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,28 @@
#ifndef _CC_ENCODER_COMMON_H
#define _CC_ENCODER_COMMON_H
#ifdef WIN32
#include "..\\win_iconv\\iconv.h"
#else
#include "iconv.h"
#endif
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
#include "ccx_encoders_structs.h"
#include "ccx_encoders_helpers.h"
#include "ccx_common_option.h"
#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"); } \
}
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
typedef struct ccx_dtvcc_writer_ctx
{
int fd;
char *filename;
iconv_t cd;
} ccx_dtvcc_writer_ctx;
/**
* Context of encoder, This structure gives single interface
@@ -25,14 +36,64 @@ struct encoder_ctx
unsigned int capacity;
/* keep count of srt subtitle*/
unsigned int srt_counter;
/* output context */
/* Input outputs */
/* Flag giving hint that output is send to server through network */
unsigned int send_to_srv;
/* Used only in Spupng output */
int multiple_files;
/* Used only in Spupng output and creating name of output file*/
char *first_input_file;
/* Its array with length of number of languages */
struct ccx_s_write *out;
/* number of member in array of write out array */
int nb_out;
/* Input file format used in Teletext for exceptional output */
unsigned int in_fileformat; //1 =Normal, 2=Teletext
/* Flag saying BOM to be written in each output file */
enum ccx_encoding_type encoding;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
struct ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
int no_bom;
int sentence_cap ; // FIX CASE? = Fix case?
int trim_subs; // " Remove spaces at sides? "
int autodash; // Add dashes (-) before each speaker automatically?
int no_font_color;
int no_type_setting;
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
unsigned char *subline; // Temp storage for storing each line
int extract;
int dtvcc_extract; //1 or 0 depending if we have to handle dtvcc
ccx_dtvcc_writer_ctx dtvcc_writers[CCX_DTVCC_MAX_SERVICES];
/* Timing related variables*/
/* start time of previous sub */
LLONG prev_start;
LLONG subs_delay;
LLONG last_displayed_subs_ms;
enum ccx_output_date_format date_format;
char millis_separator;
/* Credit stuff */
int startcredits_displayed;
char *start_credits_text;
char *end_credits_text;
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
// Preencoded strings
unsigned char encoded_crlf[16];
unsigned int encoded_crlf_length;
unsigned char encoded_br[16];
unsigned int encoded_br_length;
int new_sentence; // Capitalize next letter?
int program_number;
struct list_head list;
};
#define INITIAL_ENC_BUFFER_CAPACITY 2048
@@ -42,12 +103,11 @@ struct encoder_ctx
* write subtitle header to file refrenced by
* output context
*
* @param ctx preallocated encoder ctx
* @param out output context
* @param cfg Option to initilaize encoder cfg params
*
* @return 0 on SUCESS, -1 on failure
* @return Allocated and properly initilaized Encoder Context, NULL on failure
*/
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out);
struct encoder_ctx *init_encoder(struct encoder_cfg *opt);
/**
* try to add end credits in subtitle file and then write subtitle
@@ -56,9 +116,11 @@ int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out);
* 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
* @oaram arg pointer to initialized encoder ctx using init_encoder
*
* @param current_fts to calculate window for end credits
*/
void dinit_encoder(struct encoder_ctx *ctx);
void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts);
/**
* @param ctx encoder context
@@ -67,17 +129,28 @@ void dinit_encoder(struct encoder_ctx *ctx);
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_subtitle_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context);
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
int write_cc_buffer_as_webvtt(struct eia608_screen *data, struct encoder_ctx *context);
int write_cc_subtitle_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context);
int write_stringz_as_webvtt(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_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
int write_cc_subtitle_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context);
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);
int write_cc_subtitle_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
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_subtitle_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_webvtt(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);
@@ -85,4 +158,9 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms);
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay);
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed);
void set_encoder_rcwt_fileformat(struct encoder_ctx *ctx, short int format);
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len);
int get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_subs,
enum ccx_encoding_type in_enc, enum ccx_encoding_type out_enc, int max_len);
#endif

View File

@@ -3,6 +3,7 @@
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_common.h"
#include "ccx_encoders_common.h"
#ifdef _MSC_VER
#define strcasecmp stricmp
@@ -17,7 +18,6 @@ char **spell_lower = NULL;
char **spell_correct = NULL;
int spell_words = 0;
int spell_capacity = 0;
struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
// Some basic English words, so user-defined doesn't have to
// include the common stuff
static const char *spell_builtin[] =
@@ -68,9 +68,9 @@ void correct_case(int line_num, struct eia608_screen *data)
free(line);
}
void capitalize(int line_num, struct eia608_screen *data)
void capitalize(struct encoder_ctx *context, int line_num, struct eia608_screen *data)
{
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
for (int i = 0; i < CCX_DECODER_608_SCREEN_WIDTH; i++)
{
switch (data->characters[line_num][i])
{
@@ -82,14 +82,14 @@ void capitalize(int line_num, struct eia608_screen *data)
case '?': // Fallthrough
case '!':
case ':':
new_sentence = 1;
context->new_sentence = 1;
break;
default:
if (new_sentence)
if (context->new_sentence)
data->characters[line_num][i] = cctoupper(data->characters[line_num][i]);
else
data->characters[line_num][i] = cctolower(data->characters[line_num][i]);
new_sentence = 0;
context->new_sentence = 0;
break;
}
}
@@ -98,12 +98,12 @@ void capitalize(int line_num, struct eia608_screen *data)
// Encodes a generic string. Note that since we use the encoders for closed caption
// data, text would have to be encoded as CCs... so using special characters here
// it's a bad idea.
unsigned encode_line(unsigned char *buffer, unsigned char *text)
unsigned encode_line(struct encoder_ctx *ctx, unsigned char *buffer, unsigned char *text)
{
unsigned bytes = 0;
while (*text)
{
switch (ccx_encoders_helpers_settings.encoding)
switch (ctx->encoding)
{
case CCX_ENC_UTF_8:
case CCX_ENC_LATIN_1:
@@ -120,6 +120,7 @@ unsigned encode_line(unsigned char *buffer, unsigned char *text)
}
text++;
}
*buffer = 0;
return bytes;
}
@@ -128,7 +129,7 @@ unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, s
unsigned char *line = data->characters[line_num];
unsigned char *orig = buffer; // Keep for debugging
int first = 0, last = 31;
find_limit_characters(line, &first, &last);
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
for (int i = first; i <= last; i++)
{
get_char_in_latin_1(buffer, line[i]);
@@ -139,7 +140,7 @@ unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, s
}
unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
unsigned char *close_tag(struct encoder_ctx *ctx, unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
{
for (int l = strlen(tagstack) - 1; l >= 0; l--)
{
@@ -147,15 +148,15 @@ unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, in
switch (cur)
{
case 'F':
buffer += encode_line(buffer, (unsigned char *) "</font>");
buffer += encode_line(ctx, buffer, (unsigned char *) "</font>");
(*pchanged_font)--;
break;
case 'U':
buffer += encode_line(buffer, (unsigned char *) "</u>");
buffer += encode_line(ctx, buffer, (unsigned char *) "</u>");
(*punderlined)--;
break;
case 'I':
buffer += encode_line(buffer, (unsigned char *) "</i>");
buffer += encode_line(ctx, buffer, (unsigned char *) "</i>");
(*pitalics)--;
break;
}
@@ -168,7 +169,7 @@ unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, in
return buffer;
}
unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct eia608_screen *data)
unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
{
int col = COL_WHITE;
int underlined = 0;
@@ -179,25 +180,33 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
unsigned char *line = data->characters[line_num];
unsigned char *orig = buffer; // Keep for debugging
int first = 0, last = 31;
if (ccx_encoders_helpers_settings.trim_subs)
find_limit_characters(line, &first, &last);
if (ctx->trim_subs)
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
for (int i = first; i <= last; i++)
{
// Handle color
int its_col = data->colors[line_num][i];
if (its_col != col && !ccx_encoders_helpers_settings.no_font_color &&
if (its_col != col && !ctx->no_font_color &&
!(col == COL_USERDEFINED && its_col == COL_WHITE)) // Don't replace user defined with white
{
if (changed_font)
buffer = close_tag(buffer, tagstack, 'F', &underlined, &italics, &changed_font);
buffer = close_tag(ctx, buffer, tagstack, 'F', &underlined, &italics, &changed_font);
// Add new font tag
buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]);
if ( MAX_COLOR > its_col)
buffer += encode_line(ctx, buffer, (unsigned char*)color_text[its_col][1]);
else
{
ccx_common_logging.log_ftn("WARNING:get_decoder_line_encoded:Invalid Color index Selected %d\n", its_col);
its_col = COL_WHITE;
}
if (its_col == COL_USERDEFINED)
{
// The previous sentence doesn't copy the whole
// <font> tag, just up to the quote before the color
buffer += encode_line(buffer, (unsigned char*)usercolor_rgb);
buffer += encode_line(buffer, (unsigned char*) "\">");
buffer += encode_line(ctx, buffer, (unsigned char*)usercolor_rgb);
buffer += encode_line(ctx, buffer, (unsigned char*) "\">");
}
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
{
@@ -208,30 +217,30 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
}
// Handle underlined
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
if (is_underlined && underlined == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open underline
if (is_underlined && underlined == 0 && !ctx->no_type_setting) // Open underline
{
buffer += encode_line(buffer, (unsigned char *) "<u>");
buffer += encode_line(ctx, buffer, (unsigned char *) "<u>");
strcat(tagstack, "U");
underlined++;
}
if (is_underlined == 0 && underlined && !ccx_encoders_helpers_settings.no_type_setting) // Close underline
if (is_underlined == 0 && underlined && !ctx->no_type_setting) // Close underline
{
buffer = close_tag(buffer, tagstack, 'U', &underlined, &italics, &changed_font);
buffer = close_tag(ctx, buffer, tagstack, 'U', &underlined, &italics, &changed_font);
}
// Handle italics
int has_ita = data->fonts[line_num][i] & FONT_ITALICS;
if (has_ita && italics == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open italics
if (has_ita && italics == 0 && !ctx->no_type_setting) // Open italics
{
buffer += encode_line(buffer, (unsigned char *) "<i>");
buffer += encode_line(ctx, buffer, (unsigned char *) "<i>");
strcat(tagstack, "I");
italics++;
}
if (has_ita == 0 && italics && !ccx_encoders_helpers_settings.no_type_setting) // Close italics
if (has_ita == 0 && italics && !ctx->no_type_setting) // Close italics
{
buffer = close_tag(buffer, tagstack, 'I', &underlined, &italics, &changed_font);
buffer = close_tag(ctx, buffer, tagstack, 'I', &underlined, &italics, &changed_font);
}
int bytes = 0;
switch (ccx_encoders_helpers_settings.encoding)
switch (ctx->encoding)
{
case CCX_ENC_UTF_8:
bytes = get_char_in_utf_8(buffer, line[i]);
@@ -247,7 +256,7 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
}
buffer += bytes;
}
buffer = close_tag(buffer, tagstack, 'A', &underlined, &italics, &changed_font);
buffer = close_tag(ctx, buffer, tagstack, 'A', &underlined, &italics, &changed_font);
if (underlined || italics || changed_font)
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Not all tags closed in encoding, this is a bug, please report.\n");
*buffer = 0;
@@ -293,6 +302,11 @@ int add_word(const char *word)
ptr_correct = (char **)realloc(spell_correct, sizeof (char *)*
spell_capacity);
}
else
{
ptr_lower = spell_lower;
ptr_correct = spell_correct;
}
size_t len = strlen(word);
new_lower = (char *)malloc(len + 1);
new_correct = (char *)malloc(len + 1);
@@ -356,6 +370,9 @@ int add_built_in_words(void)
* @param size size of each element
* @param compar Comparison function, which is called with three argument
* that point to the objects being compared and arg.
* compare Funtion should return an integer less than, equal to,
* or greater than zero if p1 is found, respectively, to be less than,
* to match, or be greater than p2.
* @param arg argument passed as it is, to compare function
*/
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg)
@@ -384,9 +401,3 @@ void ccx_encoders_helpers_perform_shellsort_words(void)
shell_sort(spell_correct, spell_words, sizeof(*spell_correct), string_cmp2, NULL);
}
void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding,int no_font_color,int no_type_setting,int trim_subs){
ccx_encoders_helpers_settings.encoding = encoding;
ccx_encoders_helpers_settings.no_font_color = no_font_color;
ccx_encoders_helpers_settings.no_type_setting = no_type_setting;
ccx_encoders_helpers_settings.trim_subs = trim_subs;
}

View File

@@ -5,6 +5,7 @@
#include "ccx_common_constants.h"
#include "ccx_decoders_structs.h"
#include "ccx_decoders_608.h"
#include "ccx_encoders_common.h"
extern char **spell_lower;
extern char **spell_correct;
@@ -19,18 +20,18 @@ struct ccx_encoders_helpers_settings_t {
int no_type_setting;
enum ccx_encoding_type encoding;
};
extern struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
// Helper functions
void correct_case(int line_num, struct eia608_screen *data);
void capitalize(int line_num, struct eia608_screen *data);
void capitalize(struct encoder_ctx *context, int line_num, struct eia608_screen *data);
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);
unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data);
int string_cmp(const void *p1, const void *p2);
int string_cmp2(const void *p1, const void *p2, void *arg);
int add_built_in_words(void);
int add_word(const char *word);
unsigned encode_line (struct encoder_ctx *ctx, unsigned char *buffer, unsigned char *text);
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg);

View File

@@ -0,0 +1,270 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "png.h"
#include "spupng_encoder.h"
#include "ocr.h"
#include "utility.h"
#include "ccx_encoders_helpers.h"
int write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
int used;
int len = 0;
int ret = 0;
unsigned char *unescaped = NULL;
unsigned char *el = NULL;
char str[1024];
sprintf (str,"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer, (unsigned char *) str);
ret = write (context->out->fh, context->buffer, used);
if(ret != used)
{
return ret;
}
len = strlen (string);
unescaped= (unsigned char *) malloc (len+1);
if(!unescaped)
{
mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
ret = -1;
goto end;
}
el = (unsigned char *) malloc (len*3+1); // Be generous
if (el == NULL)
{
mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
ret = -1;
goto end;
}
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 (context, el, begin);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
}
ret = write(context->out->fh, el, u);
if(ret != u)
goto end;
ret = write(context->out->fh, context->encoded_br, context->encoded_br_length);
if(ret != context->encoded_br_length)
goto end;
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
if(ret != context->encoded_crlf_length)
goto end;
begin += strlen ((const char *) begin) + 1;
}
sprintf ((char *) str, "</P></SYNC>\r\n");
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line (context, context->buffer,(unsigned char *) str);
ret = write(context->out->fh, context->buffer, used);
if(ret != used)
goto end;
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
(unsigned long long)ms_end);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
ret = write(context->out->fh, context->buffer, used);
if(ret != used)
goto end;
end:
free(el);
free(unescaped);
return ret;
}
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
#ifdef ENABLE_OCR
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + context->subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + context->subs_delay;
ms_end = sub->end_time - 1;
}
else if ( context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER) )
{
ms_start = 1 + context->subs_delay;
ms_end = sub->start_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *token = NULL;
char *buf = (char*)context->buffer;
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
,(unsigned long long)ms_start);
write(context->out->fh, buf, strlen(buf));
token = strtok(rect[0].ocr_text,"\r\n");
while (token)
{
sprintf(buf, "%s", token);
token = strtok(NULL,"\r\n");
if(token)
strcat(buf, "<br>\n");
else
strcat(buf, "\n");
write(context->out->fh, buf, strlen(buf));
}
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n"
,(unsigned long long)ms_end);
write(context->out->fh, buf, strlen(buf));
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
int write_cc_subtitle_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_subtitle *osub = sub;
struct cc_subtitle *lsub = sub;
while(sub)
{
if(sub->type == CC_TEXT)
{
ret = write_stringz_as_sami(sub->data, context, sub->start_time, sub->end_time);
freep(&sub->data);
sub->nb_data = 0;
}
lsub = sub;
sub = sub->next;
}
while(lsub != osub)
{
sub = lsub->prev;
freep(&lsub);
lsub = sub;
}
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;
char str[1024];
startms = data->start_time;
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = data->end_time;
endms--; // To prevent overlapping with next line.
sprintf (str,"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
(unsigned long long)startms);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
int length = get_decoder_line_encoded (context, context->subline, i, data);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
}
write (context->out->fh, context->subline, length);
wrote_something = 1;
if (i!=14)
write (context->out->fh, context->encoded_br, context->encoded_br_length);
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
}
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, 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);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
return wrote_something;
}

View File

@@ -0,0 +1,258 @@
/*
Produces minimally-compliant SMPTE Timed Text (W3C TTML)
format-compatible output
See http://www.w3.org/TR/ttaf1-dfxp/ and
https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
Copyright (C) 2012 John Kemp
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "png.h"
#include "spupng_encoder.h"
#include "ocr.h"
#include "utility.h"
#include "ccx_encoders_helpers.h"
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;
int len = strlen (string);
unsigned char *unescaped= (unsigned char *) malloc (len+1);
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
int pos_r = 0;
int pos_w = 0;
char str[1024];
if (el == NULL || unescaped == NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
mstotime (ms_start, &h1, &m1, &s1, &ms1);
mstotime (ms_end-1, &h2, &m2, &s2, &ms2);
sprintf ((char *) str, "<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n", h1, m1, s1, ms1, h2, m2, s2, ms2);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer, (unsigned char *) str);
write (context->out->fh, context->buffer, used);
// 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 (context, el, begin);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
}
write(context->out->fh, el, u);
//write (wb->fh, encoded_br, encoded_br_length);
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
begin += strlen ((const char *) begin)+1;
}
sprintf ((char *) str, "</p>\n");
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, 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 (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer, (unsigned char *) str);
write (context->out->fh, context->buffer, used);
sprintf ((char *) str, "</p>\n");
free(el);
free(unescaped);
}
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
#ifdef ENABLE_OCR
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
//char timeline[128];
int len = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + context->subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + context->subs_delay;
ms_end = sub->end_time - 1;
}
else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = 1 + context->subs_delay;
ms_end = sub->start_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *buf = (char *) context->buffer;
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.
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, buf,strlen(buf) );
len = strlen(rect[0].ocr_text);
write (context->out->fh, rect[0].ocr_text, len);
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
sprintf ( buf,"</p>\n");
write (context->out->fh, buf,strlen(buf) );
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
int write_cc_subtitle_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_subtitle *osub = sub;
struct cc_subtitle *lsub = sub;
while(sub)
{
if(sub->type == CC_TEXT)
{
write_stringz_as_smptett(sub->data, context, sub->start_time, sub->end_time);
freep(&sub->data);
sub->nb_data = 0;
}
lsub = sub;
sub = sub->next;
}
while(lsub != osub)
{
sub = lsub->prev;
freep(&lsub);
lsub = sub;
}
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 = data->start_time;
char str[1024];
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = data->end_time;
endms--; // To prevent overlapping with next line.
mstotime (startms,&h1,&m1,&s1,&ms1);
mstotime (endms-1,&h2,&m2,&s2,&ms2);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
for (int i=0; i < 15; i++)
{
if (data->row_used[i])
{
int length = get_decoder_line_encoded (context, context->subline, i, data);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
}
write(context->out->fh, context->subline, length);
wrote_something=1;
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
}
}
sprintf ((char *) str,"</p>\n");
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context, context->buffer,(unsigned char *) str);
//write (wb->fh, enc_buffer,enc_buffer_used);
return wrote_something;
}

View File

@@ -0,0 +1,414 @@
#include <assert.h>
#include <sys/stat.h>
#include "ccx_encoders_spupng.h"
#include "ccx_encoders_helpers.h"
void draw_str(char *str, uint8_t * canvas, int rowstride)
{
char *ptr;
uint8_t* cell;
uint8_t pen[2];
int i = 0;
pen[0] = COL_BLACK;
pen[1] = COL_WHITE;
for(ptr = str; ptr != '\0';ptr++)
{
cell = canvas + ((i+1) * CCW);
draw_char_indexed(cell, rowstride, pen, 0, 0, 0);
i++;
}
}
void draw_row(struct eia608_screen* data, int row, uint8_t * canvas, int rowstride)
{
int column;
int unicode = 0;
uint8_t pen[2];
uint8_t* cell;
int first = -1;
int last = 0;
pen[0] = COL_BLACK;
for (column = 0; column < COLUMNS ; column++) {
if (COL_TRANSPARENT != data->colors[row][column])
{
cell = canvas + ((column+1) * CCW);
get_char_in_unicode((unsigned char*)&unicode, data->characters[row][column]);
pen[1] = data->colors[row][column];
int attr = data->fonts[row][column];
draw_char_indexed(cell, rowstride, pen, unicode, (attr & FONT_ITALICS) != 0, (attr & FONT_UNDERLINED) != 0);
if (first < 0)
{
// draw a printable space before the first non-space char
first = column;
if (unicode != 0x20)
{
cell = canvas + ((first) * CCW);
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
}
}
last = column;
}
}
// draw a printable space after the last non-space char
// unicode should still contain the last character
// check whether it is a space
if (unicode != 0x20)
{
cell = canvas + ((last+2) * CCW);
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
}
}
static png_color palette[10] =
{
{ 0xff, 0xff, 0xff }, // COL_WHITE = 0,
{ 0x00, 0xff, 0x00 }, // COL_GREEN = 1,
{ 0x00, 0x00, 0xff }, // COL_BLUE = 2,
{ 0x00, 0xff, 0xff }, // COL_CYAN = 3,
{ 0xff, 0x00, 0x00 }, // COL_RED = 4,
{ 0xff, 0xff, 0x00 }, // COL_YELLOW = 5,
{ 0xff, 0x00, 0xff }, // COL_MAGENTA = 6,
{ 0xff, 0xff, 0xff }, // COL_USERDEFINED = 7,
{ 0x00, 0x00, 0x00 }, // COL_BLACK = 8
{ 0x00, 0x00, 0x00 } // COL_TRANSPARENT = 9
};
static png_byte alpha[10] =
{
255,
255,
255,
255,
255,
255,
255,
255,
255,
0
};
int spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
png_structp png_ptr, png_infop info_ptr,
png_bytep image,
png_bytep* row_pointer,
unsigned int ww, unsigned int wh)
{
unsigned int i;
if (setjmp(png_jmpbuf(png_ptr)))
return 0;
png_init_io (png_ptr, sp->fppng);
png_set_IHDR (png_ptr,
info_ptr,
ww,
wh,
/* 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, sizeof(palette) / sizeof(palette[0]));
png_set_tRNS (png_ptr, info_ptr, alpha, sizeof(alpha) / sizeof(alpha[0]), NULL);
png_set_gAMA (png_ptr, info_ptr, 1.0 / 2.2);
png_write_info (png_ptr, info_ptr);
for (i = 0; i < wh; i++)
row_pointer[i] = image + i * ww;
png_write_image (png_ptr, row_pointer);
png_write_end (png_ptr, info_ptr);
return 1;
}
int spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
{
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointer;
png_bytep image;
int ww, wh, rowstride, row_adv;
int row;
assert ((sizeof(png_byte) == sizeof(uint8_t))
&& (sizeof(*image) == sizeof(uint8_t)));
// Allow space at beginning and end of each row for a padding space
ww = CCW * (COLUMNS+2);
wh = CCH * ROWS;
row_adv = (COLUMNS+2) * CCW * CCH;
rowstride = ww * sizeof(*image);
if (!(row_pointer = (png_bytep*)malloc(sizeof(*row_pointer) * wh))) {
mprint("Unable to allocate %d byte buffer.\n",
sizeof(*row_pointer) * wh);
return 0;
}
if (!(image = (png_bytep)malloc(wh * ww * sizeof(*image)))) {
mprint("Unable to allocate %d KB image buffer.",
wh * ww * sizeof(*image) / 1024);
free(row_pointer);
return 0;
}
// Initialize image to transparent
memset(image, COL_TRANSPARENT, wh * ww * sizeof(*image));
/* draw the image */
for (row = 0; row < ROWS; row++) {
if (data->row_used[row])
draw_row(data, row, image + row * row_adv, rowstride);
}
/* Now save the image */
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL)))
goto unknown_error;
if (!(info_ptr = png_create_info_struct(png_ptr))) {
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
goto unknown_error;
}
if (!spupng_write_png (sp, data, png_ptr, info_ptr, image, row_pointer, ww, wh)) {
png_destroy_write_struct (&png_ptr, &info_ptr);
goto write_error;
}
png_destroy_write_struct (&png_ptr, &info_ptr);
free (row_pointer);
free (image);
return 1;
write_error:
unknown_error:
free (row_pointer);
free (image);
return 0;
}
int spupng_export_string2png(struct spupng_t *sp, char *str)
{
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointer;
png_bytep image;
int ww, wh, rowstride, row_adv;
int row = 0;
assert ((sizeof(png_byte) == sizeof(uint8_t))
&& (sizeof(*image) == sizeof(uint8_t)));
// Allow space at beginning and end of each row for a padding space
ww = CCW * (COLUMNS+2);
wh = CCH * ROWS;
row_adv = (COLUMNS+2) * CCW * CCH;
rowstride = ww * sizeof(*image);
if (!(row_pointer = (png_bytep*)malloc(sizeof(*row_pointer) * wh))) {
mprint("Unable to allocate %d byte buffer.\n",
sizeof(*row_pointer) * wh);
return 0;
}
if (!(image = (png_bytep)malloc(wh * ww * sizeof(*image)))) {
mprint("Unable to allocate %d KB image buffer.",
wh * ww * sizeof(*image) / 1024);
free(row_pointer);
return 0;
}
// Initialize image to transparent
memset(image, COL_TRANSPARENT, wh * ww * sizeof(*image));
/* draw the image */
draw_str(str, image + row * row_adv, rowstride);
/* Now save the image */
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL)))
goto unknown_error;
if (!(info_ptr = png_create_info_struct(png_ptr))) {
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
goto unknown_error;
}
#if 0
if (!spupng_write_png (sp, data, png_ptr, info_ptr, image, row_pointer, ww, wh)) {
png_destroy_write_struct (&png_ptr, &info_ptr);
goto write_error;
}
#endif
png_destroy_write_struct (&png_ptr, &info_ptr);
free (row_pointer);
free (image);
return 1;
unknown_error:
free (row_pointer);
free (image);
return 0;
}
int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
struct encoder_ctx *context)
{
int row;
int empty_buf = 1;
char str[256] = "";
int str_len = 0;
LLONG ms_start = data->start_time + context->subs_delay;
if (ms_start < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
return 0;
}
for (row = 0; row < 15; row++)
{
if (data->row_used[row])
{
empty_buf = 0;
break;
}
}
if (empty_buf)
{
dbg_print(CCX_DMT_VERBOSE, "Blank page\n");
return 0;
}
LLONG ms_end = data->end_time;
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
sp->pngfile, strerror(errno));
}
if (!spupng_export_png(sp, data))
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
sp->pngfile, strerror(errno));
}
fclose(sp->fppng);
write_sputag(sp,ms_start,ms_end);
for (row = 0; row < ROWS; row++)
{
if (data->row_used[row])
{
int len = get_decoder_line_encoded(context, context->subline, row, data);
// Check for characters that spumux won't parse
// null chars will be changed to space
// pairs of dashes will be changed to underscores
for (unsigned char* ptr = context->subline; ptr < context->subline+len; ptr++)
{
switch (*ptr)
{
case 0:
*ptr = ' ';
break;
case '-':
if (*(ptr+1) == '-')
{
*ptr++ = '_';
*ptr = '_';
}
break;
}
}
if (str_len + len + 3 > 256 )
{
mprint("WARNING: Possible Loss of data\n");
break;
}
strncat(str, (const char*)context->subline, len);
strncat(str,"\n",3);
str_len = str_len + len + 2;
}
}
write_spucomment(sp,str);
return 1;
}
int spupng_write_string(struct spupng_t *sp, char *string, LLONG start_time, LLONG end_time,
struct encoder_ctx *context)
{
char str[256] = "";
LLONG ms_start = start_time + context->subs_delay;
if (ms_start < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
return 0;
}
LLONG ms_end = end_time;
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
sp->pngfile, strerror(errno));
}
if (!spupng_export_string2png(sp, str))
{
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
sp->pngfile, strerror(errno));
}
fclose(sp->fppng);
write_sputag(sp,ms_start,ms_end);
write_spucomment(sp,str);
return 1;
}
int write_cc_subtitle_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
if (!sp)
return -1;
if(sub->type == CC_TEXT)
{
spupng_write_string(sp, sub->data, sub->start_time, sub->end_time, context);
}
return 0;
}
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
if (NULL != sp)
{
return spupng_write_ccbuffer(sp, data, context);
}
return 0;
}

View File

@@ -1,4 +1,5 @@
#ifndef __608_SPUPNG_H__
#define __608_SPUPNG_H__
#include "lib_ccx.h"
#include "spupng_encoder.h"

View File

@@ -2,25 +2,30 @@
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "utility.h"
#include "ccx_encoders_helpers.h"
#include "ocr.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 encoder_ctx *context, LLONG ms_start, LLONG ms_end)
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
int used;
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
char timeline[128];
if(!string || !string[0])
return 0;
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%s", context->srt_counter, encoded_crlf);
used = encode_line(context->buffer,(unsigned char *) timeline);
sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
used = encode_line(context, context->buffer,(unsigned char *) timeline);
write(context->out->fh, context->buffer, used);
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
used = encode_line(context->buffer,(unsigned char *) timeline);
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
used = encode_line(context, context->buffer,(unsigned char *) timeline);
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
@@ -52,36 +57,39 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
unsigned int u = encode_line (context, el, begin);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
write(context->out->fh, encoded_crlf, encoded_crlf_length);
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
free(el);
free(unescaped);
return 0;
}
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
#ifdef ENABLE_OCR
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
#ifdef ENABLE_OCR
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
char timeline[128];
int len = 0;
int used;
#endif
int i = 0;
char *str;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
@@ -105,9 +113,8 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
if(sub->flags & SUB_EOD_MARKER)
context->prev_start = sub->start_time;
rect = sub->data;
#ifdef ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
str = paraof_ocrtext(sub);
if (str)
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
@@ -115,16 +122,22 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
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);
used = encode_line(context, 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);
used = encode_line(context, context->buffer,(unsigned char *) timeline);
write (context->out->fh, context->buffer, used);
len = strlen(rect[0].ocr_text);
write (context->out->fh, rect[0].ocr_text, len);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
len = strlen(str);
write (context->out->fh, str, len);
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
}
freep(&str);
}
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
{
freep(rect->data);
freep(rect->data+1);
}
#endif
sub->nb_data = 0;
@@ -132,6 +145,33 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
return ret;
}
int write_cc_subtitle_as_srt(struct cc_subtitle *sub,struct encoder_ctx *context)
{
int ret = 0;
struct cc_subtitle *osub = sub;
struct cc_subtitle *lsub = sub;
while(sub)
{
if(sub->type == CC_TEXT)
{
ret = write_stringz_as_srt(sub->data, context, sub->start_time, sub->end_time);
freep(&sub->data);
sub->nb_data = 0;
}
lsub = sub;
sub = sub->next;
}
while(lsub != osub)
{
sub = lsub->prev;
freep(&lsub);
lsub = sub;
}
return ret;
}
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
{
int used;
@@ -165,12 +205,12 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
char timeline[128];
context->srt_counter++;
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
used = encode_line(context->buffer,(unsigned char *) timeline);
sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
used = encode_line(context, context->buffer,(unsigned char *) timeline);
write(context->out->fh, context->buffer, used);
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
used = encode_line(context->buffer,(unsigned char *) timeline);
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
used = encode_line(context, context->buffer,(unsigned char *) timeline);
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
@@ -180,17 +220,17 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
{
if (data->row_used[i])
{
if (ccx_options.sentence_cap)
if (context->sentence_cap)
{
capitalize (i,data);
capitalize (context, i, data);
correct_case(i,data);
}
if (ccx_options.autodash && ccx_options.trim_subs)
if (context->autodash && context->trim_subs)
{
int first=0, last=31, center1=-1, center2=-1;
unsigned char *line = data->characters[i];
int do_dash=1, colon_pos=-1;
find_limit_characters(line,&first,&last);
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
if (first==-1 || last==-1) // Probably a bug somewhere though
break;
// Is there a speaker named, for example: TOM: What are you doing?
@@ -242,21 +282,21 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
prev_line_center2=center2;
}
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
int length = get_decoder_line_encoded (context, context->subline, i, data);
if (context->encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
}
write(context->out->fh, subline, length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
write(context->out->fh, context->subline, length);
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
wrote_something=1;
// fprintf (wb->fh,encoded_crlf);
// fprintf (wb->fh,context->encoded_crlf);
}
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
// fprintf (wb->fh, encoded_crlf);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
// fprintf (wb->fh, context->encoded_crlf);
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
return wrote_something;
}

View File

@@ -1,4 +1,5 @@
#ifndef CCX_ENCODERS_STRUCTS_H
#define CCX_ENCODERS_STRUCTS_H
typedef struct ccx_encoders_transcript_format {
// TODO: add more options, and (perhaps) reduce other ccextractor options?
@@ -14,12 +15,9 @@ typedef struct ccx_encoders_transcript_format {
struct ccx_s_write
{
int multiple_files;
char *first_input_file;
int fh;
char *filename;
void* spupng_data;
};
#define CCX_ENCODERS_STRUCTS_H
#endif

View File

@@ -0,0 +1,272 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "ccx_encoders_helpers.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 */
int write_stringz_as_webvtt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
int used;
unsigned h1, m1, s1, ms1;
unsigned h2, m2, s2, ms2;
int written;
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.
used = encode_line(context, context->buffer, (unsigned char *)timeline);
written = write(context->out->fh, context->buffer, used);
if (written != used)
return -1;
sprintf(timeline, "%02u:%02u:%02u.%03u --> %02u:%02u:%02u.%03u%s",
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
used = encode_line(context, context->buffer, (unsigned char *)timeline);
dbg_print(CCX_DMT_DECODER_608, "\n- - - WEBVTT caption - - -\n");
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);
written = write(context->out->fh, context->buffer, used);
if (written != used)
return -1;
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_webvtt() - 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(context, el, begin);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
}
written = write(context->out->fh, el, u);
if (written != u)
{
free(el);
free(unescaped);
return -1;
}
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
if (written != context->encoded_crlf_length)
{
return -1;
}
begin += strlen((const char *)begin) + 1;
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
free(el);
free(unescaped);
if (written != context->encoded_crlf_length)
{
return -1;
}
return 0;
}
int write_cc_bitmap_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
//TODO
int ret = 0;
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
int write_cc_subtitle_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_subtitle *osub = sub;
struct cc_subtitle *lsub = sub;
while (sub)
{
if (sub->type == CC_TEXT)
{
ret = write_stringz_as_webvtt(sub->data, context, sub->start_time, sub->end_time);
freep(&sub->data);
sub->nb_data = 0;
}
lsub = sub;
sub = sub->next;
}
while (lsub != osub)
{
sub = lsub->prev;
freep(&lsub);
lsub = sub;
}
return ret;
}
int write_cc_buffer_as_webvtt(struct eia608_screen *data, struct encoder_ctx *context)
{
int used;
int written;
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;
char timeline[128] = "";
for (int i = 0; i<15; i++)
{
if (data->row_used[i])
{
empty_buf = 0;
break;
}
}
if (empty_buf) // Prevent writing empty screens. Not needed in .vtt
return 0;
ms_start += context->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return 0;
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.
sprintf(timeline, "%02u:%02u:%02u.%03u --> %02u:%02u:%02u.%03u%s",
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
used = encode_line(context, context->buffer, (unsigned char *)timeline);
dbg_print(CCX_DMT_DECODER_608, "\n- - - WEBVTT caption - - -\n");
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);
written = write(context->out->fh, context->buffer, used);
if (written != used)
return -1;
for (int i = 0; i<15; i++)
{
if (data->row_used[i])
{
if (context->sentence_cap)
{
capitalize(context, i, data);
correct_case(i, data);
}
if (context->autodash && context->trim_subs)
{
int first = 0, last = 31, center1 = -1, center2 = -1;
unsigned char *line = data->characters[i];
int do_dash = 1, colon_pos = -1;
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
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;
break;
}
if (!isupper(line[j]))
break;
}
if (prev_line_start == -1)
do_dash = 0;
if (first == prev_line_start) // Case of left alignment
do_dash = 0;
if (last == prev_line_end) // Right align
do_dash = 0;
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))
do_dash = 0;
center1 = (first + last) / 2;
if (colon_pos != -1)
{
while (colon_pos<CCX_DECODER_608_SCREEN_WIDTH &&
(line[colon_pos] == ':' ||
line[colon_pos] == ' ' ||
line[colon_pos] == 0x89))
colon_pos++; // Find actual text
center2 = (colon_pos + last) / 2;
}
else
center2 = center1;
if (center1 >= prev_line_center1 - 1 && center1 <= prev_line_center1 + 1 && center1 != -1) // Center align
do_dash = 0;
if (center2 >= prev_line_center2 - 2 && center1 <= prev_line_center2 + 2 && center1 != -1) // Center align
do_dash = 0;
if (do_dash)
{
written = write(context->out->fh, "- ", 2);
if (written != 2)
return -1;
}
prev_line_start = first;
prev_line_end = last;
prev_line_center1 = center1;
prev_line_center2 = center2;
}
int length = get_decoder_line_encoded(context, context->subline, i, data);
if (context->encoding != CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
}
written = write(context->out->fh, context->subline, length);
if (written != length)
return -1;
written = write(context->out->fh,
context->encoded_crlf, context->encoded_crlf_length);
if (written != context->encoded_crlf_length)
return -1;
wrote_something = 1;
// fprintf (wb->fh,encoded_crlf);
}
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
// fprintf (wb->fh, encoded_crlf);
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
if (written != context->encoded_crlf_length)
return -1;
return wrote_something;
}

View File

@@ -0,0 +1,95 @@
#include "ccx_common_platform.h"
#include "ccx_common_common.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_common.h"
static const char *XDSclasses_short[]=
{
"CUR",
"FUT",
"CHN",
"MIS",
"PUB",
"RES",
"PRV",
"END"
};
void xds_write_transcript_line_prefix (struct encoder_ctx *context, 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 (start_time == -1)
{
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
}
if (context->transcript_settings->showStartTime)
{
char buffer[80];
if (context->transcript_settings->relativeTimestamp)
{
if (utc_refvalue == UINT64_MAX)
{
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h1, m1, s1, context->millis_separator, ms1);
}
else
{
fdprintf(wb->fh, "%lld%c%03d|", (start_time + context->subs_delay) / 1000,
context->millis_separator, (start_time + context->subs_delay) % 1000);
}
}
else
{
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
time_t start_time_int = (start_time + context->subs_delay) / 1000;
int start_time_dec = (start_time + context->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, context->millis_separator, start_time_dec);
}
}
if (context->transcript_settings->showEndTime)
{
char buffer[80];
if (context->transcript_settings->relativeTimestamp)
{
if (utc_refvalue == UINT64_MAX)
{
mstotime(end_time, &h2, &m2, &s2, &ms2);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h2, m2, s2, context->millis_separator, ms2);
}
else
{
fdprintf(wb->fh, "%lld%s%03d|", end_time / 1000, context->millis_separator, end_time% 1000);
}
}
else
{
mstotime(end_time, &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(buffer, sizeof(buffer), "%Y%m%d%H%M%S", end_time_struct);
fdprintf(wb->fh, "%s%c%03d|", buffer, context->millis_separator, end_time_dec);
}
}
if (context->transcript_settings->showMode)
{
const char *mode = "XDS";
fdprintf(wb->fh, "%s|", mode);
}
if (context->transcript_settings->showCC)
{
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
}
}

View File

@@ -0,0 +1,5 @@
#ifndef _CCX_ENCODER_XDS_H
#define _CCX_ENCODER_XDS_H
void xds_write_transcript_line_prefix (struct encoder_ctx *context, struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class);
#endif

7
src/lib_ccx/ccx_mp4.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef CXX_MP4_H
#define CXX_MP4_H
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file);
#endif

View File

@@ -47,28 +47,13 @@ struct conf_map configuration_map[] = {
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
{"NOFONT_COLOR",offsetof(struct ccx_s_options,nofontcolor),set_int},
{"NOTYPE_SETTING",offsetof(struct ccx_s_options,notypesetting),set_int},
{"CODEC",offsetof(struct ccx_s_options,codec),set_int},
{"NOCODEC",offsetof(struct ccx_s_options,nocodec),set_int},
{"OUTPUT_FORMAT",offsetof(struct ccx_s_options,write_format),set_int},
{"START_CREDIT_TEXT",offsetof(struct ccx_s_options,start_credits_text),set_string},
{"START_CREDIT_NOT_BEFORE",offsetof(struct ccx_s_options,startcreditsnotbefore),set_time},
{"START_CREDIT_NOT_AFTER",offsetof(struct ccx_s_options,startcreditsnotafter),set_time},
{"START_CREDIT_FOR_ATLEAST",offsetof(struct ccx_s_options,startcreditsforatleast),set_time},
{"START_CREDIT_FOR_ATMOST",offsetof(struct ccx_s_options,startcreditsforatmost),set_time},
{"END_CREDITS_TEXT",offsetof(struct ccx_s_options,end_credits_text),set_string},
{"END_CREDITS_FOR_ATLEAST",offsetof(struct ccx_s_options,endcreditsforatleast),set_time},
{"END_CREDITS_FOR_ATMOST",offsetof(struct ccx_s_options,endcreditsforatmost),set_time},
{"VIDEO_EDITED",offsetof(struct ccx_s_options,binary_concat),set_int},
{"GOP_TIME",offsetof(struct ccx_s_options,use_gop_as_pts),set_int},
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
{"TRIM",offsetof(struct ccx_s_options,trim_subs),set_int},
{"GUI_MODE_REPORTS",offsetof(struct ccx_s_options,gui_mode_reports),set_int},
{"NO_PROGRESS_BAR",offsetof(struct ccx_s_options,no_progress_bar),set_int},
{"SENTENCE_CAP",offsetof(struct ccx_s_options,sentence_cap),set_int},
{"CAP_FILE",offsetof(struct ccx_s_options,sentence_cap_file),set_string},
{"PROGRAM_NUMBER",offsetof(struct ccx_s_options,ts_forced_program),set_int},
{"AUTO_PROGRAM",offsetof(struct ccx_s_options,ts_autoprogram),set_int},
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
{"START_AT",offsetof(struct ccx_s_options,extraction_start),set_time},
{"END_AT",offsetof(struct ccx_s_options,extraction_end),set_time},
{"INVASTIGATE_PACKET",offsetof(struct ccx_s_options,investigate_packets),set_int},
@@ -76,15 +61,9 @@ struct conf_map configuration_map[] = {
{"NO_SYNC",offsetof(struct ccx_s_options,nosync),set_int},
{"HAUPPAUGE_MODE",offsetof(struct ccx_s_options,hauppauge_mode),set_int},
{"MP4_VIDEO_TRACK",offsetof(struct ccx_s_options,mp4vidtrack),set_int},
{"ENCODING",offsetof(struct ccx_s_options,encoding),set_int},
{"USE_PIC_ORDER",offsetof(struct ccx_s_options,usepicorder),set_int},
{"AUTO_MYTH",offsetof(struct ccx_s_options,auto_myth),set_int},
{"WTV_MPEG2",offsetof(struct ccx_s_options,wtvmpeg2),set_int},
{"OUTPUT_FILENAME",offsetof(struct ccx_s_options,output_filename),set_string},
{"OUT_ELEMENTRY_STREAM_FILENAME",offsetof(struct ccx_s_options,out_elementarystream_filename),set_string},
{"DATA_PID",offsetof(struct ccx_s_options,ts_cappid),set_int},
{"STREAM_TYPE",offsetof(struct ccx_s_options,ts_datastreamtype),set_int},
{"TS_FORCED_STREAM_TYPE",offsetof(struct ccx_s_options,ts_forced_streamtype),set_int},
{"DATE_FORMAT",offsetof(struct ccx_s_options,date_format),set_int},
// Settings for 608 decoder
{ "NO_ROLL_UP", offsetof(struct ccx_s_options, settings_608.no_rollup), set_int },

View File

@@ -429,9 +429,18 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
DVBSubContext *ctx = (DVBSubContext*) malloc(sizeof(DVBSubContext));
memset(ctx, 0, sizeof(DVBSubContext));
ctx->composition_id = cfg->composition_id[0];
ctx->ancillary_id = cfg->ancillary_id[0];
ctx->lang_index = cfg->lang_index[0];
if(cfg)
{
ctx->composition_id = cfg->composition_id[0];
ctx->ancillary_id = cfg->ancillary_id[0];
ctx->lang_index = cfg->lang_index[0];
}
else
{
ctx->composition_id = 1;
ctx->ancillary_id = 1;
ctx->lang_index = 1;
}
#ifdef ENABLE_OCR
ctx->ocr_ctx = init_ocr(ctx->lang_index);
@@ -522,9 +531,9 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
return (void*) ctx;
}
int dvbsub_close_decoder(void *dvb_ctx)
int dvbsub_close_decoder(void **dvb_ctx)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
DVBSubContext *ctx = (DVBSubContext *) *dvb_ctx;
DVBSubRegionDisplay *display;
delete_regions(ctx);
@@ -542,6 +551,10 @@ int dvbsub_close_decoder(void *dvb_ctx)
free(display);
}
#ifdef ENABLE_OCR
delete_ocr(&ctx->ocr_ctx);
#endif
freep(dvb_ctx);
return 0;
}
@@ -1427,20 +1440,29 @@ static void dvbsub_parse_display_definition_segment(void *dvb_ctx,
}
}
static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
/**
* Write Subtitle in cc_subtitle structure in CC_BITMAP format
* when OCR subsystem is present then it also write recognised text in
* cc_bitmap ocr_text variable.
*/
static int write_dvb_sub(struct lib_cc_decode *dec_ctx, struct cc_subtitle *sub)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
DVBSubContext *ctx;
DVBSubRegion *region;
DVBSubRegionDisplay *display;
DVBSubCLUT *clut;
DVBSubDisplayDefinition *display_def = ctx->display_definition;
DVBSubDisplayDefinition *display_def;
struct cc_bitmap *rect = NULL;
uint32_t *clut_table;
int offset_x=0, offset_y=0;
int ret = 0;
ctx = (DVBSubContext *) dec_ctx->private_data;
display_def = ctx->display_definition;
sub->type = CC_BITMAP;
sub->lang_index = ctx->lang_index;
if (display_def)
{
offset_x = display_def->x;
@@ -1464,7 +1486,8 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
return -1;
}
sub->start_time = get_visible_start();
/* USE PTS and convert here in required time */
sub->start_time = get_visible_start(dec_ctx->timing, 1);
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
sub->flags |= SUB_EOD_MARKER;
sub->got_output = 1;
@@ -1521,12 +1544,6 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
rect++;
}
#ifdef DeBUG
if (ctx->object_list)
{
//save_display_set(ctx);
}
#endif
return 0;
}
@@ -1539,9 +1556,9 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
*
* @return -1 on error
*/
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
int dvbsub_decode(struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
DVBSubContext *ctx = (DVBSubContext *) dec_ctx->private_data;
const uint8_t *p, *p_end;
int segment_type;
int page_id;
@@ -1551,14 +1568,16 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
if (buf_size <= 6 || *buf != 0x0f)
{
mprint("incomplete or broken packet\n");
mprint("dvbsub_decode: incomplete, broken or empty packet\n");
return -1;
}
p = buf;
p_end = buf + buf_size;
set_fts();
dec_ctx->timing->current_tref = 0;
set_fts(dec_ctx->timing);
while (p_end - p >= 6 && *p == 0x0f)
{
p += 1;
@@ -1570,7 +1589,7 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
if (p_end - p < segment_length)
{
mprint("incomplete or broken packet\n");
mprint("dvbsub_decode: incomplete, broken or empty packet\n");
return -1;
}
@@ -1580,29 +1599,29 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
switch (segment_type)
{
case DVBSUB_PAGE_SEGMENT:
dvbsub_parse_page_segment(dvb_ctx, p, segment_length);
dvbsub_parse_page_segment(ctx, p, segment_length);
got_segment |= 1;
break;
case DVBSUB_REGION_SEGMENT:
dvbsub_parse_region_segment(dvb_ctx, p, segment_length);
dvbsub_parse_region_segment(ctx, p, segment_length);
got_segment |= 2;
break;
case DVBSUB_CLUT_SEGMENT:
ret = dvbsub_parse_clut_segment(dvb_ctx, p, segment_length);
ret = dvbsub_parse_clut_segment(ctx, p, segment_length);
if (ret < 0)
goto end;
got_segment |= 4;
break;
case DVBSUB_OBJECT_SEGMENT:
dvbsub_parse_object_segment(dvb_ctx, p, segment_length);
dvbsub_parse_object_segment(ctx, p, segment_length);
got_segment |= 8;
break;
case DVBSUB_DISPLAYDEFINITION_SEGMENT:
dvbsub_parse_display_definition_segment(dvb_ctx, p,
dvbsub_parse_display_definition_segment(ctx, p,
segment_length);
break;
case DVBSUB_DISPLAY_SEGMENT:
write_dvb_sub(dvb_ctx,sub);
write_dvb_sub(dec_ctx, sub);
got_segment |= 16;
break;
default:
@@ -1618,7 +1637,7 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
// segments then we need no further data.
if (got_segment == 15)
{
write_dvb_sub(dvb_ctx,sub);
write_dvb_sub(dec_ctx, sub);
}

View File

@@ -44,7 +44,7 @@ struct dvb_config
*/
void* dvbsub_init_decoder(struct dvb_config* cfg);
int dvbsub_close_decoder(void *dvb_ctx);
int dvbsub_close_decoder(void **dvb_ctx);
/**
* @param dvb_ctx PreInitialized DVB context using DVB
@@ -55,7 +55,7 @@ int dvbsub_close_decoder(void *dvb_ctx);
*
* @return -1 on error
*/
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
int dvbsub_decode(struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
/**
* @func parse_dvb_description

File diff suppressed because it is too large Load Diff

View File

@@ -9,473 +9,473 @@
// 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 lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
int user_data(struct lib_cc_decode *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
// Shall not happen
if (ustream->error || ustream->bitsleft <= 0)
// Shall not happen
if (ustream->error || ustream->bitsleft <= 0)
{
// ustream->error=1;
return 0; // Actually discarded on call.
// CFS: Seen in a Wobble edited file.
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
}
// Do something
ctx->stat_numuserheaders++;
//header+=4;
// Do something
//ctx->stat_numuserheaders++;
//header+=4;
unsigned char *ud_header = next_bytes(ustream, 4);
if (ustream->error || ustream->bitsleft <= 0)
unsigned char *ud_header = next_bytes(ustream, 4);
if (ustream->error || ustream->bitsleft <= 0)
{
return 0; // Actually discarded on call.
// CFS: Seen in Stick_VHS.mpg.
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
}
// DVD CC header, see
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
{
ctx->stat_dvdccheaders++;
// DVD CC header, see
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
{
// ctx->stat_dvdccheaders++;
// Probably unneeded, but keep looking for extra caption blocks
int maybeextracb = 1;
// Probably unneeded, but keep looking for extra caption blocks
int maybeextracb = 1;
read_bytes(ustream, 4); // "43 43 01 F8"
read_bytes(ustream, 4); // "43 43 01 F8"
unsigned char pattern_flag = (unsigned char) read_bits(ustream,1);
read_bits(ustream,1);
int capcount=(int) read_bits(ustream,5);
int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra
unsigned char pattern_flag = (unsigned char) read_bits(ustream,1);
read_bits(ustream,1);
int capcount=(int) read_bits(ustream,5);
int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra
int field1packet = 0; // expect Field 1 first
if (pattern_flag == 0x00)
field1packet=1; // expect Field 1 second
int field1packet = 0; // expect Field 1 first
if (pattern_flag == 0x00)
field1packet=1; // expect Field 1 second
dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n",
capcount, (truncate_flag?"+1":""));
dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n",
capcount, (truncate_flag?"+1":""));
capcount += truncate_flag;
capcount += truncate_flag;
// This data comes before the first frame header, so
// in order to get the correct timing we need to set the
// current time to one frame after the maximum time of the
// last GOP. Only usefull when there are frames before
// the GOP.
if (fts_max > 0)
fts_now = fts_max + (LLONG) (1000.0/current_fps);
// This data comes before the first frame header, so
// in order to get the correct timing we need to set the
// current time to one frame after the maximum time of the
// last GOP. Only usefull when there are frames before
// the GOP.
if (ctx->timing->fts_max > 0)
ctx->timing->fts_now = ctx->timing->fts_max + (LLONG) (1000.0/current_fps);
int rcbcount = 0;
for (int i=0; i<capcount; i++)
{
for (int j=0;j<2;j++)
{
unsigned char data[3];
data[0]=read_u8(ustream);
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
int rcbcount = 0;
for (int i=0; i<capcount; i++)
{
for (int j=0;j<2;j++)
{
unsigned char data[3];
data[0]=read_u8(ustream);
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
// Obey the truncate flag.
if ( truncate_flag && i == capcount-1 && j == 1 )
{
maybeextracb = 0;
break;
}
/* Field 1 and 2 data can be in either order,
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(dec_ctx, data, sub);
rcbcount++;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "Illegal caption segment - stop here.\n");
maybeextracb = 0;
break;
}
}
}
// Theoretically this should not happen, oh well ...
// Deal with extra closed captions some DVD have.
int ecbcount = 0;
while ( maybeextracb && (next_u8(ustream)&0xFE) == 0xFE )
{
for (int j=0;j<2;j++)
{
unsigned char data[3];
data[0]=read_u8(ustream);
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
/* Field 1 and 2 data can be in either order,
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(dec_ctx, data, sub);
ecbcount++;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "Illegal (extra) caption segment - stop here.\n");
maybeextracb = 0;
break;
}
}
}
// Obey the truncate flag.
if ( truncate_flag && i == capcount-1 && j == 1 )
{
maybeextracb = 0;
break;
}
/* Field 1 and 2 data can be in either order,
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(ctx, data, sub);
rcbcount++;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "Illegal caption segment - stop here.\n");
maybeextracb = 0;
break;
}
}
}
// Theoretically this should not happen, oh well ...
// Deal with extra closed captions some DVD have.
int ecbcount = 0;
while ( maybeextracb && (next_u8(ustream)&0xFE) == 0xFE )
{
for (int j=0;j<2;j++)
{
unsigned char data[3];
data[0]=read_u8(ustream);
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
/* Field 1 and 2 data can be in either order,
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(ctx, data, sub);
ecbcount++;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "Illegal (extra) caption segment - stop here.\n");
maybeextracb = 0;
break;
}
}
}
dbg_print(CCX_DMT_VERBOSE, "Read %d/%d DVD CC blocks\n", rcbcount, ecbcount);
}
// SCTE 20 user data
else if (ud_header[0] == 0x03)
{
if ((ud_header[1]&0x7F) == 0x01)
{
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
dbg_print(CCX_DMT_VERBOSE, "Read %d/%d DVD CC blocks\n", rcbcount, ecbcount);
}
// SCTE 20 user data
else if (ud_header[0] == 0x03)
{
if ((ud_header[1]&0x7F) == 0x01)
{
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
ctx->stat_scte20ccheaders++;
read_bytes(ustream, 2); // "03 01"
// ctx->stat_scte20ccheaders++;
read_bytes(ustream, 2); // "03 01"
unsigned cc_count = (unsigned int) read_bits(ustream,5);
dbg_print(CCX_DMT_VERBOSE, "Reading %d SCTE 20 CC blocks\n", cc_count);
unsigned cc_count = (unsigned int) read_bits(ustream,5);
dbg_print(CCX_DMT_VERBOSE, "Reading %d SCTE 20 CC blocks\n", cc_count);
unsigned field_number;
unsigned cc_data1;
unsigned cc_data2;
/* unsigned marker; */
for (unsigned j=0;j<cc_count;j++)
{
skip_bits(ustream,2); // priority - unused
field_number = (unsigned int) read_bits(ustream,2);
skip_bits(ustream,5); // line_offset - unused
cc_data1 = (unsigned int) read_bits(ustream,8);
cc_data2 = (unsigned int) read_bits(ustream,8);
/* marker = (unsigned int)read_bits(ustream,1); // TODO: Add syntax check */
unsigned field_number;
unsigned cc_data1;
unsigned cc_data2;
/* unsigned marker; */
for (unsigned j=0;j<cc_count;j++)
{
skip_bits(ustream,2); // priority - unused
field_number = (unsigned int) read_bits(ustream,2);
skip_bits(ustream,5); // line_offset - unused
cc_data1 = (unsigned int) read_bits(ustream,8);
cc_data2 = (unsigned int) read_bits(ustream,8);
/* marker = (unsigned int)read_bits(ustream,1); // TODO: Add syntax check */
if (ustream->bitsleft < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Oops!");
if (ustream->bitsleft < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Oops!");
// Field_number is either
// 0 .. forbiden
// 1 .. field 1 (odd)
// 2 .. field 2 (even)
// 3 .. repeated, from repeat_first_field, effectively field 1
if (field_number < 1)
{
// 0 is invalid
cc_data[j*3]=0x00; // Set to invalid
cc_data[j*3+1]=0x00;
cc_data[j*3+2]=0x00;
}
else
{
// Treat field_number 3 as 1
field_number = (field_number - 1) & 0x01;
// top_field_first also affects to which field the caption
// belongs.
if(!top_field_first)
field_number ^= 0x01;
cc_data[j*3]=0x04|(field_number);
cc_data[j*3+1]=reverse8(cc_data1);
cc_data[j*3+2]=reverse8(cc_data2);
}
}
cc_data[cc_count*3]=0xFF;
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
// Field_number is either
// 0 .. forbiden
// 1 .. field 1 (odd)
// 2 .. field 2 (even)
// 3 .. repeated, from repeat_first_field, effectively field 1
if (field_number < 1)
{
// 0 is invalid
cc_data[j*3]=0x00; // Set to invalid
cc_data[j*3+1]=0x00;
cc_data[j*3+2]=0x00;
}
else
{
// Treat field_number 3 as 1
field_number = (field_number - 1) & 0x01;
// top_field_first also affects to which field the caption
// belongs.
if(!ctx->top_field_first)
field_number ^= 0x01;
cc_data[j*3]=0x04|(field_number);
cc_data[j*3+1]=reverse8(cc_data1);
cc_data[j*3+2]=reverse8(cc_data2);
}
}
cc_data[cc_count*3]=0xFF;
store_hdcc(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
}
// reserved - unspecified
}
// ReplayTV 4000/5000 caption header - parsing information
// derived from CCExtract.bdl
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|| ud_header[0] == 0x99) //ReplayTV 5000
&& ud_header[1] == 0x02 )
{
unsigned char data[3];
if (ud_header[0]==0xbb)
ctx->stat_replay4000headers++;
else
ctx->stat_replay5000headers++;
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
}
// reserved - unspecified
}
// ReplayTV 4000/5000 caption header - parsing information
// derived from CCExtract.bdl
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|| ud_header[0] == 0x99) //ReplayTV 5000
&& ud_header[1] == 0x02 )
{
unsigned char data[3];
#if 0
if (ud_header[0]==0xbb)
ctx->stat_replay4000headers++;
else
ctx->stat_replay5000headers++;
#endif
read_bytes(ustream, 2); // "BB 02" or "99 02"
data[0]=0x05; // Field 2
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(dec_ctx, 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(dec_ctx, data, sub);
}
// HDTV - see A/53 Part 4 (Video)
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
{
ctx->stat_hdtv++;
read_bytes(ustream, 2); // "BB 02" or "99 02"
data[0]=0x05; // Field 2
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(ctx, 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(ctx, data, sub);
}
// HDTV - see A/53 Part 4 (Video)
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
{
// ctx->stat_hdtv++;
read_bytes(ustream, 4); // "47 41 39 34"
read_bytes(ustream, 4); // "47 41 39 34"
unsigned char type_code = read_u8(ustream);
if (type_code==0x03) // CC data.
{
skip_bits(ustream,1); // reserved
unsigned char process_cc_data = (unsigned char) read_bits(ustream,1);
skip_bits(ustream,1); // additional_data - unused
unsigned char cc_count = (unsigned char) read_bits(ustream,5);
read_bytes(ustream, 1); // "FF"
if (process_cc_data)
{
dbg_print(CCX_DMT_VERBOSE, "Reading %d HDTV CC blocks\n", cc_count);
unsigned char type_code = read_u8(ustream);
if (type_code==0x03) // CC data.
{
skip_bits(ustream,1); // reserved
unsigned char process_cc_data = (unsigned char) read_bits(ustream,1);
skip_bits(ustream,1); // additional_data - unused
unsigned char cc_count = (unsigned char) read_bits(ustream,5);
read_bytes(ustream, 1); // "FF"
if (process_cc_data)
{
dbg_print(CCX_DMT_VERBOSE, "Reading %d HDTV CC blocks\n", cc_count);
int proceed = 1;
unsigned char *cc_data = read_bytes(ustream, cc_count*3);
if (ustream->bitsleft < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Not enough for CC captions!");
int proceed = 1;
unsigned char *cc_data = read_bytes(ustream, cc_count*3);
if (ustream->bitsleft < 0)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Not enough for CC captions!");
// Check for proper marker - This read makes sure that
// cc_count*3+1 bytes are read and available in cc_data.
if (read_u8(ustream)!=0xFF)
proceed=0;
// Check for proper marker - This read makes sure that
// cc_count*3+1 bytes are read and available in cc_data.
if (read_u8(ustream)!=0xFF)
proceed=0;
if (!proceed)
{
dbg_print(CCX_DMT_VERBOSE, "\rThe following payload is not properly terminated.\n");
dump (CCX_DMT_VERBOSE, cc_data, cc_count*3+1, 0, 0);
}
dbg_print(CCX_DMT_VERBOSE, "Reading %d HD CC blocks\n", cc_count);
if (!proceed)
{
dbg_print(CCX_DMT_VERBOSE, "\rThe following payload is not properly terminated.\n");
dump (CCX_DMT_VERBOSE, cc_data, cc_count*3+1, 0, 0);
}
dbg_print(CCX_DMT_VERBOSE, "Reading %d HD CC blocks\n", cc_count);
// B-frames might be (temporal) before or after the anchor
// frame they belong to. Store the buffer until the next anchor
// frame occurs. The buffer will be flushed (sorted) in the
// picture header (or GOP) section when the next anchor occurs.
// 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(ctx, cc_data, cc_count, current_tref, fts_now, sub);
// B-frames might be (temporal) before or after the anchor
// frame they belong to. Store the buffer until the next anchor
// frame occurs. The buffer will be flushed (sorted) in the
// picture header (or GOP) section when the next anchor occurs.
// 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(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
}
}
// reserved - additional_cc_data
}
// DVB closed caption header for Dish Network (Field 1 only) */
else if ( !memcmp(ud_header,"\x05\x02", 2 ) )
{
// Like HDTV (above) Dish Network captions can be stored at each
// frame, but maximal two caption blocks per frame and only one
// field is stored.
// To process this with the HDTV framework we create a "HDTV" caption
// format compatible array. Two times 3 bytes plus one for the 0xFF
// marker at the end. Pre-init to field 1 and set the 0xFF marker.
static unsigned char dishdata[7] = {0x04, 0, 0, 0x04, 0, 0, 0xFF};
int cc_count;
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
}
}
// reserved - additional_cc_data
}
// DVB closed caption header for Dish Network (Field 1 only) */
else if ( !memcmp(ud_header,"\x05\x02", 2 ) )
{
// Like HDTV (above) Dish Network captions can be stored at each
// frame, but maximal two caption blocks per frame and only one
// field is stored.
// To process this with the HDTV framework we create a "HDTV" caption
// format compatible array. Two times 3 bytes plus one for the 0xFF
// marker at the end. Pre-init to field 1 and set the 0xFF marker.
static unsigned char dishdata[7] = {0x04, 0, 0, 0x04, 0, 0, 0xFF};
int cc_count;
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
ctx->stat_dishheaders++;
// ctx->stat_dishheaders++;
read_bytes(ustream, 2); // "05 02"
read_bytes(ustream, 2); // "05 02"
// The next bytes are like this:
// header[2] : ID: 0x04 (MPEG?), 0x03 (H264?)
// header[3-4]: Two byte counter (counting (sub-)GOPs?)
// header[5-6]: Two bytes, maybe checksum?
// header[7]: Pattern type
// on B-frame: 0x02, 0x04
// on I-/P-frame: 0x05
unsigned char id = read_u8(ustream);
unsigned dishcount = read_u16(ustream);
unsigned something = read_u16(ustream);
unsigned char type = read_u8(ustream);
dbg_print(CCX_DMT_PARSE, "DN ID: %02X Count: %5u Unknown: %04X Pattern: %X",
id, dishcount, something, type);
// The next bytes are like this:
// header[2] : ID: 0x04 (MPEG?), 0x03 (H264?)
// header[3-4]: Two byte counter (counting (sub-)GOPs?)
// header[5-6]: Two bytes, maybe checksum?
// header[7]: Pattern type
// on B-frame: 0x02, 0x04
// on I-/P-frame: 0x05
unsigned char id = read_u8(ustream);
unsigned dishcount = read_u16(ustream);
unsigned something = read_u16(ustream);
unsigned char type = read_u8(ustream);
dbg_print(CCX_DMT_PARSE, "DN ID: %02X Count: %5u Unknown: %04X Pattern: %X",
id, dishcount, something, type);
unsigned char hi;
unsigned char hi;
// The following block needs 4 to 6 bytes starting from the
// current position
unsigned char *dcd = ustream->pos; // dish caption data
switch (type)
{
case 0x02:
// Two byte caption - always on B-frame
// The following 4 bytes are:
// 0 : 0x09
// 1-2: caption block
// 3 : REPEAT - 02: two bytes
// - 04: four bytes (repeat first two)
dbg_print(CCX_DMT_PARSE, "\n02 %02X %02X:%02X - R:%02X :",
dcd[0], dcd[1], dcd[2], dcd[3]);
// The following block needs 4 to 6 bytes starting from the
// current position
unsigned char *dcd = ustream->pos; // dish caption data
switch (type)
{
case 0x02:
// Two byte caption - always on B-frame
// The following 4 bytes are:
// 0 : 0x09
// 1-2: caption block
// 3 : REPEAT - 02: two bytes
// - 04: four bytes (repeat first two)
dbg_print(CCX_DMT_PARSE, "\n02 %02X %02X:%02X - R:%02X :",
dcd[0], dcd[1], dcd[2], dcd[3]);
cc_count = 1;
dishdata[1]=dcd[1];
dishdata[2]=dcd[2];
cc_count = 1;
dishdata[1]=dcd[1];
dishdata[2]=dcd[2];
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
type=dcd[3]; // repeater (0x02 or 0x04)
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
if (type==0x04 && hi<32) // repeat (only for non-character pairs)
{
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dishdata[1];
dishdata[5]=dishdata[2];
type=dcd[3]; // repeater (0x02 or 0x04)
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
if (type==0x04 && hi<32) // repeat (only for non-character pairs)
{
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dishdata[1];
dishdata[5]=dishdata[2];
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
else
{
dbg_print(CCX_DMT_PARSE, ":\n");
}
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
else
{
dbg_print(CCX_DMT_PARSE, ":\n");
}
dishdata[cc_count*3] = 0xFF; // Set end marker
dishdata[cc_count*3] = 0xFF; // Set end marker
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
// Ignore 3 (0x0A, followed by two unknown) bytes.
break;
case 0x04:
// Four byte caption - always on B-frame
// The following 5 bytes are:
// 0 : 0x09
// 1-2: caption block
// 3-4: caption block
dbg_print(CCX_DMT_PARSE, "\n04 %02X %02X:%02X:%02X:%02X :",
dcd[0], dcd[1], dcd[2], dcd[3], dcd[4]);
// Ignore 3 (0x0A, followed by two unknown) bytes.
break;
case 0x04:
// Four byte caption - always on B-frame
// The following 5 bytes are:
// 0 : 0x09
// 1-2: caption block
// 3-4: caption block
dbg_print(CCX_DMT_PARSE, "\n04 %02X %02X:%02X:%02X:%02X :",
dcd[0], dcd[1], dcd[2], dcd[3], dcd[4]);
cc_count = 2;
dishdata[1]=dcd[1];
dishdata[2]=dcd[2];
cc_count = 2;
dishdata[1]=dcd[1];
dishdata[2]=dcd[2];
dishdata[3]=0x04; // Field 1
dishdata[4]=dcd[3];
dishdata[5]=dcd[4];
dishdata[6] = 0xFF; // Set end marker
dishdata[3]=0x04; // Field 1
dishdata[4]=dcd[3];
dishdata[5]=dcd[4];
dishdata[6] = 0xFF; // Set end marker
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
// Ignore 4 (0x020A, followed by two unknown) bytes.
break;
case 0x05:
// Buffered caption - always on I-/P-frame
// The following six bytes are:
// 0 : 0x04
// - the following are from previous 0x05 caption header -
// 1 : prev dcd[2]
// 2-3: prev dcd[3-4]
// 4-5: prev dcd[5-6]
dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n",
dcd[0], dcd[1],
(unsigned)dcd[2]*256+dcd[3],
dcd[4], dcd[5]);
dcd+=6; // Skip these 6 bytes
// Ignore 4 (0x020A, followed by two unknown) bytes.
break;
case 0x05:
// Buffered caption - always on I-/P-frame
// The following six bytes are:
// 0 : 0x04
// - the following are from previous 0x05 caption header -
// 1 : prev dcd[2]
// 2-3: prev dcd[3-4]
// 4-5: prev dcd[5-6]
dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n",
dcd[0], dcd[1],
(unsigned)dcd[2]*256+dcd[3],
dcd[4], dcd[5]);
dcd+=6; // Skip these 6 bytes
// Now one of the "regular" 0x02 or 0x04 captions follows
dbg_print(CCX_DMT_PARSE, "%02X %02X %02X:%02X",
dcd[0], dcd[1], dcd[2], dcd[3]);
// Now one of the "regular" 0x02 or 0x04 captions follows
dbg_print(CCX_DMT_PARSE, "%02X %02X %02X:%02X",
dcd[0], dcd[1], dcd[2], dcd[3]);
type=dcd[0]; // Number of caption bytes (0x02 or 0x04)
type=dcd[0]; // Number of caption bytes (0x02 or 0x04)
cc_count = 1;
dishdata[1]=dcd[2];
dishdata[2]=dcd[3];
cc_count = 1;
dishdata[1]=dcd[2];
dishdata[2]=dcd[3];
dcd+=4; // Skip the first 4 bytes.
if (type==0x02)
{
type=dcd[0]; // repeater (0x02 or 0x04)
dcd++; // Skip the repeater byte.
dcd+=4; // Skip the first 4 bytes.
if (type==0x02)
{
type=dcd[0]; // repeater (0x02 or 0x04)
dcd++; // Skip the repeater byte.
dbg_print(CCX_DMT_PARSE, " - R:%02X :%s", type, debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, " - R:%02X :%s", type, debug_608toASC( dishdata, 0) );
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
if (type==0x04 && hi<32)
{
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dishdata[1];
dishdata[5]=dishdata[2];
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
else
{
dbg_print(CCX_DMT_PARSE, ":\n");
}
dishdata[cc_count*3] = 0xFF; // Set end marker
}
else
{
dbg_print(CCX_DMT_PARSE, ":%02X:%02X ",
dcd[0], dcd[1]);
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dcd[0];
dishdata[5]=dcd[1];
dishdata[6] = 0xFF; // Set end marker
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
if (type==0x04 && hi<32)
{
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dishdata[1];
dishdata[5]=dishdata[2];
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
else
{
dbg_print(CCX_DMT_PARSE, ":\n");
}
dishdata[cc_count*3] = 0xFF; // Set end marker
}
else
{
dbg_print(CCX_DMT_PARSE, ":%02X:%02X ",
dcd[0], dcd[1]);
cc_count = 2;
dishdata[3]=0x04; // Field 1
dishdata[4]=dcd[0];
dishdata[5]=dcd[1];
dishdata[6] = 0xFF; // Set end marker
dbg_print(CCX_DMT_PARSE, ":%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
dbg_print(CCX_DMT_PARSE, ":%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
break;
default:
// printf ("Unknown?\n");
break;
} // switch
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
break;
default:
// printf ("Unknown?\n");
break;
} // switch
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data - done\n");
}
// CEA 608 / aka "Divicom standard", see:
// http://www.pixeltools.com/tech_tip_closed_captioning.html
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
{
// Either a documentation or more examples are needed.
ctx->stat_divicom++;
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data - done\n");
}
// CEA 608 / aka "Divicom standard", see:
// http://www.pixeltools.com/tech_tip_closed_captioning.html
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
{
// Either a documentation or more examples are needed.
// ctx->stat_divicom++;
unsigned char data[3];
unsigned char data[3];
read_bytes(ustream, 2); // "02 09"
read_bytes(ustream, 2); // "80 80" ???
read_bytes(ustream, 2); // "02 0A" ???
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(dec_ctx, data, sub);
// This is probably incomplete!
}
else
{
// Some other user data
// 06 02 ... Seems to be DirectTV
dbg_print(CCX_DMT_VERBOSE, "Unrecognized user data:\n");
int udatalen = ustream->end - ustream->pos;
dump (CCX_DMT_VERBOSE, ustream->pos, (udatalen > 128 ? 128 : udatalen),0 ,0);
}
read_bytes(ustream, 2); // "02 09"
read_bytes(ustream, 2); // "80 80" ???
read_bytes(ustream, 2); // "02 0A" ???
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(ctx, data, sub);
// This is probably incomplete!
}
else
{
// Some other user data
// 06 02 ... Seems to be DirectTV
dbg_print(CCX_DMT_VERBOSE, "Unrecognized user data:\n");
int udatalen = ustream->end - ustream->pos;
dump (CCX_DMT_VERBOSE, ustream->pos, (udatalen > 128 ? 128 : udatalen),0 ,0);
}
dbg_print(CCX_DMT_VERBOSE, "User data - processed\n");
dbg_print(CCX_DMT_VERBOSE, "User data - processed\n");
// Read complete
return 1;
// Read complete
return 1;
}

92
src/lib_ccx/file_buffer.h Normal file
View File

@@ -0,0 +1,92 @@
#ifndef FILE_BUFFER_H
#define FILE_BUFFER_H
/**
* Read from buffer if there is insufficient data then cache the buffer
*
* @param ctx ccx_demuxer context properly initilaized ccx_demuxer with some input
* Not to be NULL, since ctx is derefrenced inside this function
*
* @param buffer if buffer then it must be allocated to at;east bytes len as
* passed in third argument, If buffer is NULL then those number of bytes
* are skipped from input.
* @param bytes number of bytes to be read from file buffer.
*
* @return 0 or number of bytes, if returned 0 then op should check error number to know
* details of error
*/
size_t buffered_read_opt (struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes);
/**
* Skip bytes from file buffer and if needed also seek file for number of bytes.
*
*/
static size_t inline buffered_skip(struct ccx_demuxer *ctx, unsigned int bytes)
{
size_t result;
if (bytes <= ctx->bytesinbuffer - ctx->filebuffer_pos)
{
ctx->filebuffer_pos += bytes;
result = bytes;
}
else
{
result = buffered_read_opt (ctx, NULL, bytes);
}
return result;
}
/**
* Read bytes from file buffer and if needed also read file for number of bytes.
*
*/
static size_t inline buffered_read(struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes)
{
size_t result;
if (bytes <= ctx->bytesinbuffer - ctx->filebuffer_pos)
{
if (buffer != NULL)
memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, bytes);
ctx->filebuffer_pos+=bytes;
result = bytes;
}
else
{
result = buffered_read_opt (ctx, buffer, bytes);
if (ccx_options.gui_mode_reports && ccx_options.input_source == CCX_DS_NETWORK)
{
net_activity_gui++;
if (!(net_activity_gui%1000))
activity_report_data_read();
}
}
return result;
}
/**
* Read single byte from file buffer and if needed also read file for number of bytes.
*
*/
static size_t inline buffered_read_byte(struct ccx_demuxer *ctx, unsigned char *buffer)
{
size_t result;
if (ctx->bytesinbuffer - ctx->filebuffer_pos)
{
if (buffer)
{
*buffer=ctx->filebuffer[ctx->filebuffer_pos];
ctx->filebuffer_pos++;
result = 1;
}
}
else
result = buffered_read_opt (ctx, buffer, 1);
return result;
}
unsigned short buffered_get_be16(struct ccx_demuxer *ctx);
unsigned char buffered_get_byte (struct ccx_demuxer *ctx);
unsigned int buffered_get_be32(struct ccx_demuxer *ctx);
#endif

View File

@@ -1,22 +1,23 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "activity.h"
#include "file_buffer.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);
#ifdef _WIN32
WSADATA wsaData = {0};
int iResult = 0;
WSADATA wsaData = {0};
int iResult = 0;
#endif
LLONG getfilesize (int in)
{
int ret = 0;
LLONG current=LSEEK (in, 0, SEEK_CUR);
LLONG length = LSEEK (in,0,SEEK_END);
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);
ret = LSEEK (in, current, SEEK_SET);
if (ret < 0)
return -1;
@@ -25,87 +26,69 @@ LLONG getfilesize (int in)
LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files failed to open
{
LLONG ts=0;
int h;
for (int i=0;i<ctx->num_input_files;i++)
{
if (0 == strcmp(ctx->inputfile[i],"-")) // Skip stdin
LLONG ts=0;
int h;
for (int i = 0; i < ctx->num_input_files; i++)
{
if (0 == strcmp(ctx->inputfile[i], "-")) // Skip stdin
continue;
#ifdef _WIN32
h=OPEN (ctx->inputfile[i],O_RDONLY | O_BINARY);
h = OPEN (ctx->inputfile[i], O_RDONLY | O_BINARY);
#else
h=OPEN (ctx->inputfile[i],O_RDONLY);
h = OPEN (ctx->inputfile[i], O_RDONLY);
#endif
if (h==-1)
{
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
return -1;
}
if (!ccx_options.live_stream)
ts+=getfilesize (h);
close (h);
}
return ts;
if (h == -1)
{
mprint ("\rUnable to open %s\r\n", ctx->inputfile[i]);
return -1;
}
if (!ccx_options.live_stream)
ts += getfilesize (h);
close (h);
}
return ts;
}
void prepare_for_new_file (struct lib_ccx_ctx *ctx)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
// Init per file variables
min_pts=0x01FFFFFFFFLL; // 33 bit
sync_pts=0;
pts_set = 0;
// inputsize=0; Now responsibility of switch_to_next_file()
ctx->last_reported_progress=-1;
ctx->stat_numuserheaders = 0;
ctx->stat_dvdccheaders = 0;
ctx->stat_scte20ccheaders = 0;
ctx->stat_replay5000headers = 0;
ctx->stat_replay4000headers = 0;
ctx->stat_dishheaders = 0;
ctx->stat_hdtv = 0;
ctx->stat_divicom = 0;
total_frames_count = 0;
ctx->total_pulldownfields = 0;
ctx->total_pulldownframes = 0;
dec_ctx->cc_stats[0]=0; dec_ctx->cc_stats[1]=0; dec_ctx->cc_stats[2]=0; dec_ctx->cc_stats[3]=0;
ctx->false_pict_header=0;
ctx->frames_since_last_gop=0;
frames_since_ref_time=0;
gop_time.inited=0;
first_gop_time.inited=0;
gop_rollover=0;
printed_gop.inited=0;
dec_ctx->saw_caption_block=0;
ctx->past=0;
pts_big_change=0;
ctx->startbytes_pos=0;
ctx->startbytes_avail=0;
init_file_buffer();
anchor_hdcc(-1);
firstcall = 1;
for(int x=0; x<0xfff; x++) {
ctx->epg_buffers[x].buffer=NULL;
ctx->epg_buffers[x].ccounter=0;
ctx->last_reported_progress =-1;
ctx->stat_numuserheaders = 0;
ctx->stat_dvdccheaders = 0;
ctx->stat_scte20ccheaders = 0;
ctx->stat_replay5000headers = 0;
ctx->stat_replay4000headers = 0;
ctx->stat_dishheaders = 0;
ctx->stat_hdtv = 0;
ctx->stat_divicom = 0;
total_frames_count = 0;
ctx->false_pict_header = 0;
frames_since_ref_time = 0;
gop_time.inited = 0;
first_gop_time.inited = 0;
gop_rollover = 0;
printed_gop.inited = 0;
pts_big_change = 0;
firstcall = 1;
for(int x = 0; x < 0xfff; x++)
{
ctx->epg_buffers[x].buffer = NULL;
ctx->epg_buffers[x].ccounter = 0;
}
for (int i = 0; i < TS_PMT_MAP_SIZE; i++) {
ctx->eit_programs[i].array_len=0;
ctx->eit_current_events[i]=-1;
for (int i = 0; i < TS_PMT_MAP_SIZE; i++)
{
ctx->eit_programs[i].array_len = 0;
ctx->eit_current_events[i] = -1;
}
ctx->epg_last_output=-1;
ctx->epg_last_live_output=-1;
ctx->epg_last_output = -1;
ctx->epg_last_live_output = -1;
}
/* Close input file if there is one and let the GUI know */
void close_input_file (struct lib_ccx_ctx *ctx)
{
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
{
close (ctx->infd);
ctx->infd=-1;
activity_input_file_closed();
}
ctx->demux_ctx->close(ctx->demux_ctx);
}
/* Close current file and open next one in list -if any- */
@@ -115,368 +98,389 @@ can be done */
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
if (ctx->current_file==-1 || !ccx_options.binary_concat)
int ret = 0;
if (ctx->current_file == -1 || !ccx_options.binary_concat)
{
memset (ctx->PIDs_seen,0,65536*sizeof (int));
memset (ctx->PIDs_programs,0,65536*sizeof (struct PMT_entry *));
ctx->demux_ctx->reset(ctx->demux_ctx);
}
if (ccx_options.input_source==CCX_DS_STDIN)
switch(ccx_options.input_source)
{
if (ctx->infd!=-1) // Means we had already processed stdin. So we're done.
{
if (ccx_options.print_file_reports)
print_file_report(ctx);
return 0;
}
ctx->infd=0;
mprint ("\n\r-----------------------------------------------------------------\n");
mprint ("\rReading from standard input\n");
return 1;
case CCX_DS_STDIN:
case CCX_DS_NETWORK:
case CCX_DS_TCP:
ret = ctx->demux_ctx->open(ctx->demux_ctx, NULL);
if (ret < 0)
return 0;
else if (ret)
return ret;
else
return 1;
break;
default:
break;
}
if (ccx_options.input_source==CCX_DS_NETWORK)
/* Close current and make sure things are still sane */
if (ctx->demux_ctx->is_open(ctx->demux_ctx))
{
if (ctx->infd!=-1) // Means we have already bound a socket.
{
if (ccx_options.print_file_reports)
print_file_report(ctx);
return 0;
}
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
return 1;
if(ctx->infd < 0)
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
}
if (ccx_options.input_source==CCX_DS_TCP)
{
if (ctx->infd != -1)
{
if (ccx_options.print_file_reports)
print_file_report(ctx);
return 0;
}
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
return 1;
}
/* Close current and make sure things are still sane */
if (ctx->infd!=-1)
{
if (ccx_options.print_file_reports)
print_file_report(ctx);
close_input_file (ctx);
if (ctx->inputsize>0 && ((ctx->past+bytesinbuffer) < ctx->inputsize) && !dec_ctx->processed_enough)
{
mprint("\n\n\n\nATTENTION!!!!!!\n");
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
}
if (ccx_options.binary_concat)
{
ctx->total_past+=ctx->inputsize;
ctx->past=0; // Reset always or at the end we'll have double the size
}
}
for (;;)
{
ctx->current_file++;
if (ctx->current_file>=ctx->num_input_files)
break;
// The following \n keeps the progress percentage from being overwritten.
mprint ("\n\r-----------------------------------------------------------------\n");
if (ctx->inputsize > 0 && ((ctx->demux_ctx->past+bytesinbuffer) < ctx->inputsize) && is_decoder_processed_enough(ctx) == CCX_FALSE)
{
mprint("\n\n\n\nATTENTION!!!!!!\n");
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->demux_ctx->past, ctx->inputsize);
}
close_input_file (ctx);
if (ccx_options.binary_concat)
{
ctx->total_past += ctx->inputsize;
ctx->demux_ctx->past = 0; // Reset always or at the end we'll have double the size
}
}
for (;;)
{
ctx->current_file++;
if (ctx->current_file >= ctx->num_input_files)
break;
// The following \n keeps the progress percentage from being overwritten.
mprint ("\n\r-----------------------------------------------------------------\n");
mprint ("\rOpening file: %s\n", ctx->inputfile[ctx->current_file]);
#ifdef _WIN32
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY | O_BINARY);
#else
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY);
#endif
if (ctx->infd == -1)
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
else
{
activity_input_file_open (ctx->inputfile[ctx->current_file]);
if (!ccx_options.live_stream)
{
ctx->inputsize = getfilesize (ctx->infd);
if (!ccx_options.binary_concat)
ctx->total_inputsize=ctx->inputsize;
}
return 1; // Succeeded
}
}
return 0;
ret = ctx->demux_ctx->open(ctx->demux_ctx, ctx->inputfile[ctx->current_file]);
if (ret < 0)
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
else
{
activity_input_file_open (ctx->inputfile[ctx->current_file]);
if (!ccx_options.live_stream)
{
ctx->inputsize = ctx->demux_ctx->get_filesize (ctx->demux_ctx);
if (!ccx_options.binary_concat)
ctx->total_inputsize = ctx->inputsize;
}
return 1; // Succeeded
}
}
return 0;
}
void position_sanity_check (void)
void position_sanity_check (int in)
{
#ifdef SANITY_CHECK
if (in!=-1)
{
LLONG realpos=LSEEK (in,0,SEEK_CUR);
if (realpos!=ctx->past-filebuffer_pos+bytesinbuffer)
{
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,ctx->past);
}
}
if (in!=-1)
{
LLONG realpos = LSEEK (in,0,SEEK_CUR);
if (realpos != ctx->demux_ctx->past - filebuffer_pos + bytesinbuffer)
{
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n", realpos, ctx->demux_ctx->past);
}
}
#endif
}
int init_file_buffer(void)
int init_file_buffer(struct ccx_demuxer *ctx)
{
filebuffer_start=0;
filebuffer_pos=0;
if (filebuffer==NULL)
{
filebuffer=(unsigned char *) malloc (FILEBUFFERSIZE);
bytesinbuffer=0;
}
if (filebuffer==NULL)
{
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
}
return 0;
ctx->filebuffer_start = 0;
ctx->filebuffer_pos = 0;
if (ctx->filebuffer == NULL)
{
ctx->filebuffer = (unsigned char *) malloc (FILEBUFFERSIZE);
ctx->bytesinbuffer = 0;
}
if (ctx->filebuffer == NULL)
{
return -1;
}
return 0;
}
void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
void buffered_seek (struct ccx_demuxer *ctx, int offset)
{
position_sanity_check();
if (offset<0)
{
filebuffer_pos+=offset;
if (filebuffer_pos<0)
{
// We got into the start buffer (hopefully)
if ((filebuffer_pos+ctx->startbytes_pos) < 0)
{
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
}
ctx->startbytes_pos+=filebuffer_pos;
filebuffer_pos=0;
}
}
else
{
buffered_read_opt (ctx, NULL, offset);
position_sanity_check();
}
position_sanity_check(ctx->infd);
if (offset < 0)
{
ctx->filebuffer_pos += offset;
if (ctx->filebuffer_pos < 0)
{
// We got into the start buffer (hopefully)
if ((ctx->filebuffer_pos + ctx->startbytes_pos) < 0)
{
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
}
ctx->startbytes_pos += ctx->filebuffer_pos;
ctx->filebuffer_pos = 0;
}
}
else
{
buffered_read_opt (ctx, NULL, offset);
position_sanity_check(ctx->infd);
}
}
void sleepandchecktimeout (time_t start)
{
if (ccx_options.input_source==CCX_DS_STDIN)
{
if (ccx_options.input_source == CCX_DS_STDIN)
{
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
// real time input from hardware.
sleep_secs (1);
ccx_options.live_stream=0;
return;
}
sleep_secs (1);
ccx_options.live_stream = 0;
return;
}
if (ccx_options.live_stream==-1) // Just sleep, no timeout to check
{
sleep_secs (1);
return;
}
if (time(NULL)>start+ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
ccx_options.live_stream=0;
else
sleep_secs(1);
if (ccx_options.live_stream == -1) // Just sleep, no timeout to check
{
sleep_secs (1);
return;
}
if (time(NULL) > start + ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
ccx_options.live_stream = 0;
else
sleep_secs(1);
}
void return_to_buffer (unsigned char *buffer, unsigned int bytes)
void return_to_buffer (struct ccx_demuxer *ctx, unsigned char *buffer, unsigned int bytes)
{
if (bytes == filebuffer_pos)
if (bytes == ctx->filebuffer_pos)
{
// Usually we're just going back in the buffer and memcpy would be
// unnecessary, but we do it in case we intentionally messed with the
// buffer
memcpy (filebuffer, buffer, bytes);
filebuffer_pos=0;
memcpy (ctx->filebuffer, buffer, bytes);
ctx->filebuffer_pos = 0;
return;
}
if (filebuffer_pos>0) // Discard old bytes, because we may need the space
if (ctx->filebuffer_pos > 0) // Discard old bytes, because we may need the space
{
// Non optimal since data is moved later again but we don't care since
// we're never here in ccextractor.
memmove (filebuffer,filebuffer+filebuffer_pos,bytesinbuffer-filebuffer_pos);
bytesinbuffer-=filebuffer_pos;
bytesinbuffer=0;
filebuffer_pos=0;
memmove (ctx->filebuffer, ctx->filebuffer + ctx->filebuffer_pos, ctx->bytesinbuffer-ctx->filebuffer_pos);
ctx->bytesinbuffer -= ctx->filebuffer_pos;
ctx->bytesinbuffer = 0;
ctx->filebuffer_pos = 0;
}
if (bytesinbuffer + bytes > FILEBUFFERSIZE)
if (ctx->bytesinbuffer + bytes > FILEBUFFERSIZE)
fatal (CCX_COMMON_EXIT_BUG_BUG, "Invalid return_to_buffer() - please submit a bug report.");
memmove (filebuffer+bytes,filebuffer,bytesinbuffer);
memcpy (filebuffer,buffer,bytes);
bytesinbuffer+=bytes;
memmove (ctx->filebuffer + bytes, ctx->filebuffer, ctx->bytesinbuffer);
memcpy (ctx->filebuffer, buffer, bytes);
ctx->bytesinbuffer += bytes;
}
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes)
/**
* @param buffer can be NULL, in case when user want to just buffer it or skip some data.
*
* Global options that have efffect on this function are following
* 1) ccx_options.live_stream
* 2) ccx_options.buffer_input
* 3) ccx_options.input_source
* 4) ccx_options.binary_concat
*
* TODO instead of using global ccx_options move them to ccx_demuxer
*/
size_t buffered_read_opt (struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes)
{
LLONG copied=0;
position_sanity_check();
time_t seconds=0;
if (ccx_options.live_stream>0)
time (&seconds);
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
{
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
int eof = (ctx->infd==-1);
size_t copied = 0;
time_t seconds = 0;
while ((!eof || ccx_options.live_stream) && bytes)
{
if (eof)
{
// No more data available inmediately, we sleep a while to give time
// for the data to come up
sleepandchecktimeout (seconds);
}
size_t ready = bytesinbuffer-filebuffer_pos;
if (ready==0) // We really need to read more
{
if (!ccx_options.buffer_input)
{
// We got in the buffering code because of the initial buffer for
// detection stuff. However we don't want more buffering so
// we do the rest directly on the final buffer.
int i;
do
{
position_sanity_check(ctx->infd);
if (ccx_options.live_stream > 0)
time (&seconds);
if (ccx_options.buffer_input || ctx->filebuffer_pos < ctx->bytesinbuffer)
{
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
int eof = (ctx->infd == -1);
while ((!eof || ccx_options.live_stream) && bytes)
{
if (eof)
{
// No more data available inmediately, we sleep a while to give time
// for the data to come up
sleepandchecktimeout (seconds);
}
size_t ready = ctx->bytesinbuffer - ctx->filebuffer_pos;
if (ready == 0) // We really need to read more
{
if (!ccx_options.buffer_input)
{
// We got in the buffering code because of the initial buffer for
// detection stuff. However we don't want more buffering so
// we do the rest directly on the final buffer.
int i;
do
{
// No code for network support here, because network is always
// buffered - if here, then it must be files.
if (buffer!=NULL) // Read
{
i=read (ctx->infd,buffer,bytes);
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
buffer+=i;
}
else // Seek
{
if (buffer != NULL) // Read
{
i = read (ctx->infd, buffer, bytes);
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
buffer += i;
}
else // Seek
{
LLONG op, np;
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
return 0;
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
i=(int) (np-op);
}
if (i==0 && ccx_options.live_stream)
{
if (ccx_options.input_source==CCX_DS_STDIN)
{
ccx_options.live_stream = 0;
break;
}
else
{
sleepandchecktimeout (seconds);
}
}
else
{
copied+=i;
bytes-=i;
}
op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos
if (op + bytes < 0) // Would mean moving beyond start of file: Not supported
return 0;
np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving
i = (int) (np - op);
}
// if both above lseek returned -1 (error); i would be 0 here and
// in case when its not live stream copied would decrease and bytes would...
if (i == 0 && ccx_options.live_stream)
{
if (ccx_options.input_source == CCX_DS_STDIN)
{
ccx_options.live_stream = 0;
break;
}
else
{
sleepandchecktimeout (seconds);
}
}
else
{
copied += i;
bytes -= i;
}
}
while ((i || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))) && bytes);
return copied;
}
// Keep the last 8 bytes, so we have a guaranteed
// working seek (-8) - needed by mythtv.
int keep = bytesinbuffer > 8 ? 8 : bytesinbuffer;
memmove (filebuffer,filebuffer+(FILEBUFFERSIZE-keep),keep);
}
while ((i || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))) && bytes);
return copied;
}
// Keep the last 8 bytes, so we have a guaranteed
// working seek (-8) - needed by mythtv.
int keep = ctx->bytesinbuffer > 8 ? 8 : ctx->bytesinbuffer;
memmove (ctx->filebuffer, ctx->filebuffer+(FILEBUFFERSIZE-keep),keep);
int i;
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
i=read (ctx->infd, filebuffer+keep,FILEBUFFERSIZE-keep);
if (ccx_options.input_source == CCX_DS_FILE || ccx_options.input_source == CCX_DS_STDIN)
i = read (ctx->infd, ctx->filebuffer + keep, FILEBUFFERSIZE-keep);
else if (ccx_options.input_source == CCX_DS_TCP)
i = net_tcp_read(ctx->infd, (char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep);
else
i = recvfrom(ctx->infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
if (i == -1)
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
if (i==0)
{
/* If live stream, don't try to switch - acknowledge eof here as it won't
cause a loop end */
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx, copied)))
eof=1;
}
filebuffer_pos=keep;
bytesinbuffer=(int) i+keep;
ready=i;
}
int copy = (int) (ready>=bytes ? bytes:ready);
if (copy)
{
if (buffer!=NULL)
{
memcpy (buffer, filebuffer+filebuffer_pos, copy);
buffer+=copy;
}
filebuffer_pos+=copy;
bytes-=copy;
copied+=copy;
}
}
return copied;
}
else // Read without buffering
{
i = recvfrom(ctx->infd,(char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep, 0, NULL, NULL);
if (i == -1)
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
if (i == 0)
{
/* If live stream, don't try to switch - acknowledge eof here as it won't
cause a loop end */
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied)))
eof = 1;
}
ctx->filebuffer_pos = keep;
ctx->bytesinbuffer = (int) i + keep;
ready = i;
}
int copy = (int) (ready>=bytes ? bytes:ready);
if (copy)
{
if (buffer != NULL)
{
memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, copy);
buffer += copy;
}
ctx->filebuffer_pos += copy;
bytes -= copy;
copied += copy;
}
}
}
else // Read without buffering
{
if (buffer!=NULL)
{
int i;
while (bytes>0 && ctx->infd!=-1 &&
((i=read(ctx->infd,buffer,bytes))!=0 || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))))
{
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
else if (i==0)
sleepandchecktimeout (seconds);
else
{
copied+=i;
bytes-=i;
buffer+=i;
}
}
return copied;
}
// return fread(buffer,1,bytes,in);
//return FSEEK (in,bytes,SEEK_CUR);
while (bytes!=0 && ctx->infd!=-1)
{
if (buffer != NULL)
{
int i;
while (bytes > 0 && ctx->infd != -1 &&
((i = read(ctx->infd, buffer, bytes)) != 0 || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))))
{
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
else if (i == 0)
sleepandchecktimeout (seconds);
else
{
copied += i;
bytes -= i;
buffer += i;
}
}
return copied;
}
while (bytes != 0 && ctx->infd != -1)
{
LLONG op, np;
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
return 0;
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
copied=copied+(np-op);
bytes=bytes-(unsigned int) copied;
if (copied==0)
{
if (ccx_options.live_stream)
sleepandchecktimeout (seconds);
else
{
if (ccx_options.binary_concat)
switch_to_next_file(ctx, 0);
else
break;
}
}
}
return copied;
}
op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos
if (op + bytes < 0) // Would mean moving beyond start of file: Not supported
return 0;
np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving
copied = copied + (np - op);
bytes = bytes- (unsigned int) copied;
if (copied == 0)
{
if (ccx_options.live_stream)
sleepandchecktimeout (seconds);
else
{
if (ccx_options.binary_concat)
switch_to_next_file(ctx->parent, 0);
else
break;
}
}
}
}
return copied;
}
unsigned short buffered_get_be16(struct ccx_demuxer *ctx)
{
unsigned char a,b;
unsigned char *a_p = &a; // Just to suppress warnings
unsigned char *b_p = &b;
buffered_read_byte(ctx, a_p);
ctx->past++;
buffered_read_byte(ctx, b_p);
ctx->past++;
return ( (unsigned short) (a<<8) )| ( (unsigned short) b);
}
unsigned char buffered_get_byte (struct ccx_demuxer *ctx)
{
unsigned char b;
unsigned char *b_p = &b;
size_t result;
result = buffered_read_byte(ctx, b_p);
if (result == 1)
{
ctx->past++;
return b;
}
else
return 0;
}
unsigned int buffered_get_be32(struct ccx_demuxer *ctx)
{
unsigned int val;
val = buffered_get_be16(ctx) << 16;
val |= buffered_get_be16(ctx);
return val;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,10 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "activity.h"
#include "utility.h"
#include "dvb_subtitle_decoder.h"
#include "ccx_decoders_708.h"
#include "ccx_decoders_isdb.h"
struct ccx_common_logging_t ccx_common_logging;
static struct ccx_decoders_common_settings_t *init_decoder_setting(
@@ -14,9 +19,19 @@ static struct ccx_decoders_common_settings_t *init_decoder_setting(
setting->subs_delay = opt->subs_delay;
setting->output_format = opt->write_format;
setting->fix_padding = opt->fix_padding;
setting->extract = opt->extract;
setting->fullbin = opt->fullbin;
setting->no_rollup = opt->no_rollup;
memcpy(&setting->extraction_start,&opt->extraction_start,sizeof(struct ccx_boundary_time));
memcpy(&setting->extraction_end,&opt->extraction_end,sizeof(struct ccx_boundary_time));
setting->cc_to_stdout = opt->cc_to_stdout;
setting->settings_608 = &opt->settings_608;
setting->settings_dtvcc = &opt->settings_dtvcc;
setting->cc_channel = opt->cc_channel;
setting->send_to_srv = opt->send_to_srv;
setting->hauppauge_mode = opt->hauppauge_mode;
/* if in transcript setting xds is not selected then set ignore xds flag */
setting->ignore_xds = !opt->transcript_settings.xds;
return setting;
}
static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setting)
@@ -24,40 +39,78 @@ static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setti
freep(setting);
}
static int init_ctx_outbase(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
{
char *file;
if (opt->output_filename)
{
ctx->basefilename = get_basename(opt->output_filename);
}
else
{
switch (opt->input_source)
{
case CCX_DS_FILE:
if(!ctx->inputfile || !ctx->inputfile[0])
{
errno = EINVAL;
return -1;
}
file = ctx->inputfile[0];
break;
case CCX_DS_STDIN:
file = "stdin";
break;
case CCX_DS_NETWORK:
case CCX_DS_TCP:
file = "network";
break;
default:
errno = EINVAL;
return -1;
}
ctx->basefilename = get_basename(file);
}
return 0;
}
struct encoder_ctx *get_encoder_by_pn(struct lib_ccx_ctx *ctx, int pn)
{
struct encoder_ctx *enc_ctx;
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
{
if (enc_ctx->program_number == pn)
return enc_ctx;
}
return NULL;
}
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
{
struct lib_ccx_ctx *ctx;
struct ccx_decoder_608_report *report_608;
struct ccx_decoders_common_settings_t *dec_setting;
int ret = 0;
ctx = malloc(sizeof(struct lib_ccx_ctx));
struct lib_ccx_ctx *ctx = malloc(sizeof(struct lib_ccx_ctx));
if(!ctx)
return NULL;
memset(ctx,0,sizeof(struct lib_ccx_ctx));
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "lib_ccx_ctx");
memset(ctx, 0, sizeof(struct lib_ccx_ctx));
report_608 = malloc(sizeof(struct ccx_decoder_608_report));
struct ccx_decoder_608_report *report_608 = malloc(sizeof(struct ccx_decoder_608_report));
if (!report_608)
return NULL;
memset(report_608,0,sizeof(struct ccx_decoder_608_report));
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "report_608");
memset(report_608, 0, sizeof(struct ccx_decoder_608_report));
ctx->capbufsize = 20000;
ctx->capbuf = NULL;
ctx->capbuflen = 0; // Bytes read in capbuf
ccx_decoder_dtvcc_report *report_dtvcc = (ccx_decoder_dtvcc_report *)
malloc(sizeof(ccx_decoder_dtvcc_report));
if (!report_dtvcc)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "report_dtvcc");
memset(report_dtvcc, 0, sizeof(ccx_decoder_dtvcc_report));
// Initialize some constants
init_ts(ctx);
init_avc();
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
ctx->auto_stream = opt->auto_stream;
ctx->m2ts = opt->m2ts;
ctx->screens_to_process = -1;
ctx->current_file = -1;
ctx->infd = -1;//Set to -1 to indicate no file is open.
// Default name for output files if input is stdin
ctx->basefilename_for_stdin=(char *) "stdin";
// Default name for output files if input is network
ctx->basefilename_for_network=(char *) "network";
// Set logging functions for libraries
ccx_common_logging.debug_ftn = &dbg_print;
@@ -66,63 +119,271 @@ struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
ccx_common_logging.log_ftn = &mprint;
ccx_common_logging.gui_ftn = &activity_library_process;
// Init shared decoder settings
ctx->dec_global_setting = init_decoder_setting(opt);
if (!ctx->dec_global_setting)
return NULL;
// Need to set the 608 data for the report to the correct variable.
ctx->freport.data_from_608 = report_608;
// Same applies for 708 data
ctx->freport.data_from_708 = &ccx_decoder_708_report;
// Init shared decoder settings
dec_setting = init_decoder_setting(opt);
ctx->dec_ctx = init_cc_decode(dec_setting);
dinit_decoder_setting(&dec_setting);
// Init encoder helper variables
ccx_encoders_helpers_setup(opt->encoding, opt->nofontcolor, opt->notypesetting, opt->trim_subs);
// Init 708 decoder(s)
ccx_decoders_708_init_library(ctx->basefilename,ctx->extension,opt->print_file_reports);
// Set output structures for the 608 decoder
//ctx->dec_ctx->context_cc608_field_1->out = ctx->dec_ctx->wbout1;
//ctx->dec_ctx->context_cc608_field_2->out = ctx->dec_ctx->wbout2;
// Init XDS buffers
ccx_decoders_xds_init_library(&opt->transcript_settings, ctx->subs_delay, opt->millis_separator);
//xds_cea608_test();
ctx->dec_global_setting->settings_608->report = report_608;
ctx->freport.data_from_708 = report_dtvcc;
ctx->dec_global_setting->settings_dtvcc->report = report_dtvcc;
ctx->mp4_cfg.mp4vidtrack = opt->mp4vidtrack;
//Initialize input files
ctx->inputfile = opt->inputfile;
ctx->num_input_files = opt->num_input_files;
ctx->subs_delay = opt->subs_delay;
ctx->wbout1.filename = opt->wbout2.filename;
ctx->wbout2.filename = opt->wbout2.filename;
ctx->buffer = (unsigned char *) malloc (BUFSIZE);
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
// Init timing
ccx_common_timing_init(&ctx->past,opt->nosync);
ret = init_ctx_outbase(opt, ctx);
if (ret < 0) {
goto end;
}
ctx->subs_delay = opt->subs_delay;
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
ctx->cc_to_stdout = opt->cc_to_stdout;
ctx->hauppauge_mode = opt->hauppauge_mode;
ctx->live_stream = opt->live_stream;
ctx->binary_concat = opt->binary_concat;
build_parity_table();
ctx->demux_ctx = init_demuxer(ctx, &opt->demux_cfg);
INIT_LIST_HEAD(&ctx->dec_ctx_head);
INIT_LIST_HEAD(&ctx->enc_ctx_head);
// Init timing
ccx_common_timing_init(&ctx->demux_ctx->past,opt->nosync);
ctx->multiprogram = opt->multiprogram;
ctx->write_format = opt->write_format;
ctx->out_interval = opt->out_interval;
ctx->segment_counter = 0;
ctx->system_start_time = -1;
end:
if (ret != EXIT_OK)
{
free(ctx);
return NULL;
}
return ctx;
}
void dinit_libraries( struct lib_ccx_ctx **ctx)
{
struct lib_ccx_ctx *lctx = *ctx;
int i = 0;
for (i = 0; i < MAX_PID; i++)
struct encoder_ctx *enc_ctx;
struct lib_cc_decode *dec_ctx;
struct lib_cc_decode *dec_ctx1;
int i;
list_for_each_entry_safe(dec_ctx, dec_ctx1, &lctx->dec_ctx_head, list, struct lib_cc_decode)
{
if( lctx->PIDs_programs[i])
freep(lctx->PIDs_programs + i);
LLONG cfts;
if (dec_ctx->codec == CCX_CODEC_DVB)
dvbsub_close_decoder(&dec_ctx->private_data);
//Test memory for teletext
//else if (dec_ctx->codec == CCX_CODEC_TELETEXT)
// telxcc_close(&dec_ctx->private_data, NULL);
else if (dec_ctx->codec == CCX_CODEC_ISDB_CC)
delete_isdb_decoder(&dec_ctx->private_data);
flush_cc_decode(dec_ctx, &dec_ctx->dec_sub);
cfts = get_fts(dec_ctx->timing, dec_ctx->current_field);
enc_ctx = get_encoder_by_pn(lctx, dec_ctx->program_number);
if (enc_ctx && dec_ctx->dec_sub.got_output == CCX_TRUE)
{
encode_sub(enc_ctx, &dec_ctx->dec_sub);
dec_ctx->dec_sub.got_output = CCX_FALSE;
}
list_del(&dec_ctx->list);
dinit_cc_decode(&dec_ctx);
if (enc_ctx)
{
list_del(&enc_ctx->list);
dinit_encoder(&enc_ctx, cfts);
}
}
// free EPG memory
EPG_free(lctx);
dinit_ts(lctx);
dinit_cc_decode(&lctx->dec_ctx);
freep(&lctx->buffer);
freep(&lctx->pesheaderbuf);
freep(&lctx->freport.data_from_608);
freep(&lctx->freport.data_from_708);
ccx_demuxer_delete(&lctx->demux_ctx);
dinit_decoder_setting(&lctx->dec_global_setting);
freep(&ccx_options.enc_cfg.output_filename);
freep(&lctx->basefilename);
freep(&lctx->pesheaderbuf);
for(i = 0;i < lctx->num_input_files;i++)
freep(&lctx->inputfile[i]);
freep(&lctx->inputfile);
freep(ctx);
}
int is_decoder_processed_enough(struct lib_ccx_ctx *ctx)
{
struct lib_cc_decode *dec_ctx;
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
{
if (dec_ctx->processed_enough == CCX_TRUE && ctx->multiprogram == CCX_FALSE)
return CCX_TRUE;
}
return CCX_FALSE;
}
struct lib_cc_decode *update_decoder_list(struct lib_ccx_ctx *ctx)
{
struct lib_cc_decode *dec_ctx;
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
{
return dec_ctx;
}
if (list_empty(&ctx->dec_ctx_head))
{
ctx->dec_global_setting->codec = CCX_CODEC_ATSC_CC;
ctx->dec_global_setting->program_number = 0;
dec_ctx = init_cc_decode(ctx->dec_global_setting);
if (!dec_ctx)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
}
return dec_ctx;
}
struct lib_cc_decode *update_decoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo)
{
struct lib_cc_decode *dec_ctx = NULL;
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
{
if (!cinfo || ctx->multiprogram == CCX_FALSE)
return dec_ctx;
if (dec_ctx->program_number == cinfo->program_number)
return dec_ctx;
}
if(cinfo)
{
ctx->dec_global_setting->program_number = cinfo->program_number;
ctx->dec_global_setting->codec = cinfo->codec;
ctx->dec_global_setting->private_data = cinfo->codec_private_data;
}
else
{
ctx->dec_global_setting->program_number = 0;
ctx->dec_global_setting->codec = CCX_CODEC_ATSC_CC;
}
if(ctx->multiprogram == CCX_FALSE)
{
if (list_empty(&ctx->dec_ctx_head))
{
dec_ctx = init_cc_decode(ctx->dec_global_setting);
if (!dec_ctx)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
}
}
else
{
dec_ctx = init_cc_decode(ctx->dec_global_setting);
if (!dec_ctx)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
}
return dec_ctx;
}
struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo)
{
struct encoder_ctx *enc_ctx;
unsigned int pn = 0;
unsigned char in_format = 1;
char *extension;
if (ctx->write_format == CCX_OF_NULL)
return NULL;
if(cinfo)
{
pn = cinfo->program_number;
if (cinfo->codec == CCX_CODEC_ISDB_CC)
in_format = 3;
else if (cinfo->codec == CCX_CODEC_TELETEXT)
in_format = 2;
else
in_format = 1;
}
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
{
if ( ctx->multiprogram == CCX_FALSE)
return enc_ctx;
if (enc_ctx->program_number == pn)
return enc_ctx;
}
extension = get_file_extension(ccx_options.enc_cfg.write_format);
if(!extension)
return NULL;
if(ctx->multiprogram == CCX_FALSE)
{
if(ctx->out_interval != -1)
{
int len;
len = strlen(ctx->basefilename) + 10 + strlen(extension);
freep(&ccx_options.enc_cfg.output_filename);
ccx_options.enc_cfg.output_filename = malloc(len);
sprintf(ccx_options.enc_cfg.output_filename, "%s_%06d%s", ctx->basefilename, ctx->segment_counter+1, extension);
}
if (list_empty(&ctx->enc_ctx_head))
{
ccx_options.enc_cfg.program_number = pn;
ccx_options.enc_cfg.in_format = in_format;
enc_ctx = init_encoder(&ccx_options.enc_cfg);
if (!enc_ctx)
return NULL;
list_add_tail( &(enc_ctx->list), &(ctx->enc_ctx_head) );
}
}
else
{
int len;
len = strlen(ctx->basefilename) + 10 + strlen(extension);
ccx_options.enc_cfg.program_number = pn;
ccx_options.enc_cfg.output_filename = malloc(len);
if (!ccx_options.enc_cfg.output_filename)
{
freep(&extension);
return NULL;
}
sprintf(ccx_options.enc_cfg.output_filename, "%s_%d%s", ctx->basefilename, pn, extension);
enc_ctx = init_encoder(&ccx_options.enc_cfg);
if (!enc_ctx)
{
freep(&extension);
freep(&ccx_options.enc_cfg.output_filename);
return NULL;
}
list_add_tail( &(enc_ctx->list), &(ctx->enc_ctx_head) );
freep(&extension);
freep(&ccx_options.enc_cfg.output_filename);
}
freep(&extension);
return enc_ctx;
}
struct encoder_ctx *update_encoder_list(struct lib_ccx_ctx *ctx)
{
return update_encoder_list_cinfo(ctx, NULL);
}

View File

@@ -1,7 +1,7 @@
#ifndef CCX_CCEXTRACTOR_H
#define CCX_CCEXTRACTOR_H
#define VERSION "0.76"
#define VERSION "0.78"
// Load common includes and constants for library usage
#include "ccx_common_platform.h"
@@ -12,111 +12,33 @@
#include "ccx_common_timing.h"
#include "ccx_common_option.h"
#include "ccx_demuxer.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_608.h"
#include "ccx_decoders_xds.h"
#include "ccx_decoders_708.h"
#include "ccx_decoders_common.h"
#include "bitstream.h"
#include "networking.h"
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
extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to overwrites (should be 0)
#define TS_PMT_MAP_SIZE 128
struct ts_payload
{
unsigned char *start; // Payload start
unsigned length; // Payload length
unsigned pesstart; // PES or PSI start
unsigned pid; // Stream PID
int counter; // continuity counter
int transport_error; // 0 = packet OK, non-zero damaged
unsigned char section_buf[1024];
int section_index;
int section_size;
};
struct PAT_entry
{
unsigned program_number;
unsigned PMT_PID;
unsigned char *last_pmt_payload;
unsigned last_pmt_length;
};
struct PMT_entry
{
unsigned program_number;
unsigned PMT_PID;
unsigned elementary_PID;
unsigned ccx_stream_type;
unsigned printable_stream_type;
};
struct EIT_buffer
{
uint32_t prev_ccounter;
uint8_t *buffer;
uint32_t buffer_length;
uint32_t ccounter;
};
struct EPG_rating
{
char country_code[4];
uint8_t age;
};
struct EPG_event
{
uint32_t id;
char start_time_string[21]; //"YYYYMMDDHHMMSS +0000" = 20 chars
char end_time_string[21];
uint8_t running_status;
uint8_t free_ca_mode;
char ISO_639_language_code[4];
char *event_name;
char *text;
char extended_ISO_639_language_code[4];
char *extended_text;
uint8_t has_simple;
struct EPG_rating *ratings;
uint32_t num_ratings;
uint8_t *categories;
uint32_t num_categories;
uint16_t service_id;
long long int count; //incremented by one each time the event is updated
uint8_t live_output; //boolean flag, true if this event has been output
};
#define EPG_MAX_EVENTS 60*24*7
struct EIT_program
{
uint32_t array_len;
struct EPG_event epg_events[EPG_MAX_EVENTS];
};
#include "avc_functions.h"
//#include "ccx_decoders_708.h"
/* Report information */
#define SUB_STREAMS_CNT 10
#define TELETEXT_CHUNK_LEN 1 + 8 + 44
struct file_report
{
unsigned program_cnt;
unsigned width;
unsigned height;
unsigned aspect_ratio;
unsigned frame_rate;
struct ccx_decoder_608_report *data_from_608;
struct ccx_decoder_708_report_t *data_from_708;
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
struct ccx_decoder_dtvcc_report *data_from_708;
unsigned mp4_cc_track_cnt;
};
// Stuff for telcc.c
struct ccx_s_teletext_config {
struct ccx_s_teletext_config
{
uint8_t verbose : 1; // should telxcc be verbose?
uint16_t page; // teletext page containing cc we want to filter
uint16_t tid; // 13-bit packet ID for teletext stream
@@ -126,19 +48,27 @@ struct ccx_s_teletext_config {
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
// uint64_t utc_refvalue; // UTC referential value => Moved to ccx_decoders_common, so can be used for other decoders (608/xds) too
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
enum ccx_output_date_format date_format;
int noautotimeref; // Do NOT set time automatically?
unsigned send_to_srv;
enum ccx_encoding_type encoding;
int nofontcolor;
char millis_separator;
};
#define MAX_PID 65536
struct ccx_s_mp4Cfg
{
unsigned int mp4vidtrack :1;
};
struct lib_ccx_ctx
{
// TODO relates to fts_global
uint32_t global_timestamp;
uint32_t min_global_timestamp;
int global_timestamp_inited;
// Stuff common to both loops
unsigned char *buffer;
LLONG past; /* Position in file, if in sync same as ftell() */
unsigned char *pesheaderbuf;
LLONG inputsize;
LLONG total_inputsize;
@@ -146,10 +76,6 @@ struct lib_ccx_ctx
int last_reported_progress;
// Small buffer to help us with the initial sync
unsigned char startbytes[STARTBYTESLENGTH];
unsigned int startbytes_pos;
int startbytes_avail;
/* Stats */
int stat_numuserheaders;
@@ -160,26 +86,11 @@ struct lib_ccx_ctx
int stat_dishheaders;
int stat_hdtv;
int stat_divicom;
unsigned total_pulldownfields;
unsigned total_pulldownframes;
int false_pict_header;
/* GOP-based timing */
int saw_gop_header;
int frames_since_last_gop;
/* Time info for timed-transcript */
int max_gop_length; // (Maximum) length of a group of pictures
int last_gop_length; // Length of the previous group of pictures
// int hex_mode=HEX_NONE; // Are we processing an hex file?
struct lib_cc_decode *dec_ctx;
enum ccx_stream_mode_enum stream_mode;
enum ccx_stream_mode_enum auto_stream;
int m2ts;
struct ccx_decoders_common_settings_t *dec_global_setting;
struct list_head dec_ctx_head;
int rawmode; // Broadcast or DVD
// See -d from
@@ -201,24 +112,9 @@ struct lib_ccx_ctx
char **inputfile; // List of files to process
int num_input_files; // How many?
/* Hauppauge support */
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
unsigned teletext_warning_shown; // Did we detect a possible PAL (with teletext subs) and told the user already?
// Output structures
struct ccx_s_write wbout1;
struct ccx_s_write wbout2;
/* File handles */
FILE *fh_out_elementarystream;
int infd; // descriptor number to input.
char *basefilename_for_stdin;
char *basefilename_for_network;
int PIDs_seen[MAX_PID];
struct PMT_entry *PIDs_programs[MAX_PID];
//struct EIT_buffer eit_buffer;
struct EIT_buffer epg_buffers[0xfff+1];
struct PSI_buffer epg_buffers[0xfff+1];
struct EIT_program eit_programs[TS_PMT_MAP_SIZE+1];
int32_t eit_current_events[TS_PMT_MAP_SIZE+1];
int16_t ATSC_source_pg_map[0xffff];
@@ -226,97 +122,59 @@ struct lib_ccx_ctx
int epg_last_live_output;
struct file_report freport;
long capbufsize;
unsigned char *capbuf;
long capbuflen; // Bytes read in capbuf
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
0 -> A regular file
>0 -> Live stream with a timeout of this value in seconds */
int binary_concat; // Disabled by -ve or --videoedited
int multiprogram;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
struct ccx_demuxer *demux_ctx;
struct list_head enc_ctx_head;
struct ccx_s_mp4Cfg mp4_cfg;
int out_interval;
int segment_counter;
LLONG system_start_time;
};
#ifdef DEBUG_TELEXCC
int main_telxcc (int argc, char *argv[]);
#endif
#define buffered_skip(ctx, bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
filebuffer_pos+=bytes; \
result=bytes; \
} else result=buffered_read_opt (ctx, NULL,bytes);
#define buffered_read(ctx, buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
filebuffer_pos+=bytes; \
result=bytes; \
} else { result=buffered_read_opt (ctx, buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
buffer[1]=filebuffer[filebuffer_pos+1]; \
buffer[2]=filebuffer[filebuffer_pos+2]; \
buffer[3]=filebuffer[filebuffer_pos+3]; \
filebuffer_pos+=4; \
result=4; } \
} else result=buffered_read_opt (buffer,4);
#define buffered_read_byte(ctx, buffer) if (bytesinbuffer-filebuffer_pos) { \
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
filebuffer_pos++; \
result=1; } \
} else result=buffered_read_opt (ctx, buffer,1);
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes);
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt);
void dinit_libraries( struct lib_ccx_ctx **ctx);
//params.c
void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]);
int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]);
void usage (void);
int detect_input_file_overwrite(struct lib_ccx_ctx *ctx, const char *output_filename);
int atoi_hex (char *s);
int stringztoms (const char *s, struct ccx_boundary_time *bt);
// general_loop.c
void position_sanity_check (void);
int init_file_buffer( void );
LLONG ps_getmoredata(struct lib_ccx_ctx *ctx);
LLONG general_getmoredata(struct lib_ccx_ctx *ctx);
void raw_loop (struct lib_ccx_ctx *ctx, void *enc_ctx);
LLONG process_raw (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
void position_sanity_check (int in);
int init_file_buffer(struct ccx_demuxer *ctx);
int ps_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
int general_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **data);
void raw_loop (struct lib_ccx_ctx *ctx);
size_t process_raw(struct lib_cc_decode *ctx, struct cc_subtitle *sub, unsigned char *buffer, size_t len);
void general_loop(struct lib_ccx_ctx *ctx);
void processhex (char *filename);
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
void rcwt_loop(struct lib_ccx_ctx *ctx);
// activity.c
void activity_header (void);
void activity_progress (int percentaje, int cur_min, int cur_sec);
void activity_report_version (void);
void activity_input_file_closed (void);
void activity_input_file_open (const char *filename);
void activity_message (const char *fmt, ...);
void activity_video_info (int hor_size,int vert_size,
const char *aspect_ratio, const char *framerate);
void activity_program_number (unsigned program_number);
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
void activity_report_data_read (void);
extern LLONG result;
extern int end_of_file;
extern LLONG inbuf;
extern int ccx_bufferdatatype; // Can be RAW or PES
// asf_functions.c
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx);
int asf_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
// wtv_functions.c
LLONG wtv_getmoredata(struct lib_ccx_ctx *ctx);
// avc_functions.c
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub);
void init_avc(void);
int wtv_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
// es_functions.c
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length,struct cc_subtitle *sub);
size_t process_m2v(struct lib_cc_decode *ctx, unsigned char *data, size_t length, struct cc_subtitle *sub);
extern unsigned top_field_first;
// es_userdata.c
int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
int user_data(struct lib_cc_decode *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
// bitstream.c - see bitstream.h
@@ -326,52 +184,50 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx);
void prepare_for_new_file (struct lib_ccx_ctx *ctx);
void close_input_file (struct lib_ccx_ctx *ctx);
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer);
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
void return_to_buffer (struct ccx_demuxer *ctx, unsigned char *buffer, unsigned int bytes);
// sequencing.c
void init_hdcc (void);
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number,
LLONG current_fts_now,struct cc_subtitle *sub);
void anchor_hdcc(int seq);
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
// mp4.c
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx);
void init_hdcc (struct lib_cc_decode *ctx);
void store_hdcc(struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now, struct cc_subtitle *sub);
void anchor_hdcc(struct lib_cc_decode *ctx, int seq);
void process_hdcc (struct lib_cc_decode *ctx, struct cc_subtitle *sub);
// params_dump.c
void params_dump(struct lib_ccx_ctx *ctx);
void print_file_report(struct lib_ccx_ctx *ctx);
// output.c
void init_write(struct ccx_s_write *wb, char *filename);
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
void writedata(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
void dinit_write(struct ccx_s_write *wb);
int init_write (struct ccx_s_write *wb,char *filename);
int writeraw (const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile);
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data);
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data, struct cc_subtitle *sub);
// stream_functions.c
void detect_stream_type (struct lib_ccx_ctx *ctx);
int detect_myth( struct lib_ccx_ctx *ctx );
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen);
int read_pts_pes(unsigned char*header, int len);
int isValidMP4Box(unsigned char *buffer, long position, long *nextBoxLocation, int *boxScore);
void detect_stream_type (struct ccx_demuxer *ctx);
int detect_myth( struct ccx_demuxer *ctx );
int read_video_pes_header (struct ccx_demuxer *ctx, struct demuxer_data *data, unsigned char *nextheader, int *headerlength, int sbuflen);
// ts_functions.c
void init_ts(struct lib_ccx_ctx *ctx);
void dinit_ts (struct lib_ccx_ctx *ctx);
int ts_readpacket(struct lib_ccx_ctx* ctx);
long ts_readstream(struct lib_ccx_ctx *ctx);
LLONG ts_getmoredata(struct lib_ccx_ctx *ctx);
int write_section(struct lib_ccx_ctx *ctx, struct ts_payload *payload, unsigned char*buf, int size, int pos);
int parse_PMT (struct lib_ccx_ctx *ctx, unsigned char *buf, int len, int pos);
int parse_PAT (struct lib_ccx_ctx *ctx);
void init_ts(struct ccx_demuxer *ctx);
int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload);
long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data);
int ts_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **data);
int write_section(struct ccx_demuxer *ctx, struct ts_payload *payload, unsigned char*buf, int size, struct program_info *pinfo);
void ts_buffer_psi_packet(struct ccx_demuxer *ctx);
int parse_PMT (struct ccx_demuxer *ctx, unsigned char *buf, int len, struct program_info *pinfo);
int parse_PAT (struct ccx_demuxer *ctx);
void parse_EPG_packet (struct lib_ccx_ctx *ctx);
void EPG_free();
void EPG_free(struct lib_ccx_ctx *ctx);
char* EPG_DVB_decode_string(uint8_t *in, size_t size);
void parse_SDT(struct ccx_demuxer *ctx);
// myth.c
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
void myth_loop(struct lib_ccx_ctx *ctx);
// utility.c
void fatal(int exit_code, const char *fmt, ...);
void dvprint(const char *fmt, ...);
void mprint (const char *fmt, ...);
void sleep_secs (int secs);
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
@@ -379,98 +235,54 @@ bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
int hex2int (char high, char low);
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
void timestamp_to_smptetttime(uint64_t timestamp, char *buffer);
void millis_to_date (uint64_t timestamp, char *buffer) ;
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
void millis_to_date (uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator);
#ifndef _WIN32
void m_signal(int sig, void (*func)(int));
#endif
unsigned encode_line (unsigned char *buffer, unsigned char *text);
void buffered_seek (struct lib_ccx_ctx *ctx, int offset);
void buffered_seek (struct ccx_demuxer *ctx, int offset);
extern void build_parity_table(void);
void tlt_process_pes_packet(struct lib_ccx_ctx *ctx, uint8_t *buffer, uint16_t size);
void telxcc_init(struct lib_ccx_ctx *ctx);
void telxcc_close(struct lib_ccx_ctx *ctx);
void tlt_read_rcwt(struct lib_ccx_ctx *ctx);
int tlt_process_pes_packet(struct lib_cc_decode *dec_ctx, uint8_t *buffer, uint16_t size, struct cc_subtitle *sub);
void* telxcc_init(void);
void telxcc_close(void **ctx, struct cc_subtitle *sub);
void tlt_read_rcwt(void *codec, unsigned char *buf, struct cc_subtitle *sub);
void telxcc_configure (void *codec, struct ccx_s_teletext_config *cfg);
void telxcc_update_gt(void *codec, uint32_t global_timestamp);
extern unsigned rollover_bits;
extern int global_timestamp_inited;
extern int strangeheader;
extern unsigned char *filebuffer;
extern LLONG filebuffer_start; // Position of buffer start relative to file
extern int filebuffer_pos; // Position of pointer relative to buffer start
extern int bytesinbuffer; // Number of bytes we actually have on buffer
extern const char *desc[256];
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
extern unsigned long net_activity_gui;
/* General (ES stream) video information */
extern unsigned current_hor_size;
extern unsigned current_vert_size;
extern unsigned current_aspect_ratio;
extern unsigned current_frame_rate;
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
extern int firstcall;
#define MAXBFRAMES 50
#define SORTBUF (2*MAXBFRAMES+1)
extern int cc_data_count[SORTBUF];
extern unsigned char cc_data_pkts[SORTBUF][10*31*3+1];
extern int has_ccdata_buffered;
extern unsigned char *subline;
// From ts_functions
extern unsigned cap_stream_type;
extern struct ts_payload payload;
//extern struct ts_payload payload;
extern unsigned char tspacket[188];
extern struct PAT_entry pmt_array[TS_PMT_MAP_SIZE];
extern uint16_t pmt_array_length;
extern unsigned pmtpid;
extern unsigned TS_program_number;
extern unsigned char *last_pat_payload;
extern unsigned last_pat_length;
extern long capbuflen;
#define HAUPPAGE_CCPID 1003 // PID for CC's in some Hauppauge recordings
/* Exit codes. Take this seriously as the GUI depends on them.
0 means OK as usual,
<100 means display whatever was output to stderr as a warning
>=100 means display whatever was output to stdout as an error
*/
// Some moved to ccx_common_common.h
#define EXIT_OK 0
#define EXIT_NO_INPUT_FILES 2
#define EXIT_TOO_MANY_INPUT_FILES 3
#define EXIT_INCOMPATIBLE_PARAMETERS 4
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
#define EXIT_MALFORMED_PARAMETER 7
#define EXIT_READ_ERROR 8
#define EXIT_NOT_CLASSIFIED 300
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
#define EXIT_BUFFER_FULL 502
#define EXIT_MISSING_ASF_HEADER 1001
#define EXIT_MISSING_RCWT_HEADER 1002
extern unsigned teletext_mode;
#define MAX_TLT_PAGES 1000
extern short int seen_sub_page[MAX_TLT_PAGES];
extern struct ccx_s_teletext_config tlt_config;
extern uint32_t tlt_packet_counter;
extern uint32_t tlt_frames_produced;
int is_decoder_processed_enough(struct lib_ccx_ctx *ctx);
struct lib_cc_decode *update_decoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo);
struct lib_cc_decode *update_decoder_list(struct lib_ccx_ctx *ctx);
struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo);
struct encoder_ctx * update_encoder_list(struct lib_ccx_ctx *ctx);
struct encoder_ctx *get_encoder_by_pn(struct lib_ccx_ctx *ctx, int pn);
#endif

511
src/lib_ccx/list.h Normal file
View File

@@ -0,0 +1,511 @@
/**
*
* Grabed from linux kernel source code and fix it for user space
* program. Of course, this is a GPL licensed header file.
*
*
*/
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#include "ccx_common_platform.h"
/**
* @name from other kernel headers
*/
/*@{*/
/**
* Get offset of a member
*/
#ifndef ccx_offsetof
#define ccx_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
/**
* Casts a member of a structure out to the containing structure
* @param ptr the pointer to the member.
* @param type the type of the container struct this is embedded in.
* @param member the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ((type *)( (char *)ptr - ccx_offsetof(type,member) ))
/*@}*/
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/**
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
/**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
* simplest possible list iteration code, no prefetching is done.
* Use this for code that knows the list to be very short (empty
* or 1 entry) most of the time.
*/
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
* @type iterator type
*/
#define list_for_each_entry(pos, head, member, type) \
for (pos = list_entry((head)->next, type, member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, type, member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
* list_prepare_entry - prepare a pos entry for use as a start point in
* list_for_each_entry_continue
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
/**
* list_for_each_entry_continue - iterate over list of given type
* continuing after existing point
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member, type) \
for (pos = list_entry((head)->next, type, member), \
n = list_entry(pos->member.next, type, member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, type, member))
/**
* list_for_each_entry_safe_continue - iterate over list of given type
* continuing after existing point safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
* removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
if (n->pprev) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif

View File

@@ -14,10 +14,11 @@ For now, integration with ccextractor is a quick hack. It could get better with
#include <stdio.h>
#include <fcntl.h>
#include "ccx_encoders_common.h"
#include "activity.h"
#include "file_buffer.h"
static unsigned int header_state;
static unsigned char psm_es_type[256];
int cc608_parity_table[256];
// LLONG processed_ccblocks = 0;
@@ -288,61 +289,29 @@ typedef struct AVPacket
static AVPacket av;
int get_be16(struct lib_ccx_ctx *ctx)
{
unsigned char a,b;
unsigned char *a_p = &a; // Just to suppress warnings
unsigned char *b_p = &b;
buffered_read_byte (ctx, a_p);
ctx->past++;
buffered_read_byte (ctx, b_p);
ctx->past++;
return (a<<8) | b;
}
int get_byte (struct lib_ccx_ctx *ctx)
{
unsigned char b;
unsigned char *b_p = &b;
buffered_read_byte(ctx, b_p);
if (result==1)
{
ctx->past++;
return b;
}
else
return 0;
}
unsigned int get_be32(struct lib_ccx_ctx *ctx)
{
unsigned int val;
val = get_be16(ctx) << 16;
val |= get_be16(ctx);
return val;
}
static LLONG get_pts(struct lib_ccx_ctx *ctx, int c)
static LLONG get_pts(struct ccx_demuxer *ctx, int c)
{
LLONG pts;
int val;
if (c < 0)
c = get_byte(ctx);
c = buffered_get_byte(ctx);
pts = (LLONG) ((c >> 1) & 0x07) << 30;
val = get_be16(ctx);
val = buffered_get_be16(ctx);
pts |= (LLONG) (val >> 1) << 15;
val = get_be16(ctx);
val = buffered_get_be16(ctx);
pts |= (LLONG) (val >> 1);
return pts;
}
static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
static int find_next_start_code(struct ccx_demuxer *ctx, int *size_ptr,
unsigned int *header_state)
{
unsigned int state, v;
int val, n;
LLONG result;
state = *header_state;
n = *size_ptr;
@@ -350,8 +319,8 @@ static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
{
unsigned char cx;
unsigned char *cx_p = &cx;
buffered_read_byte (ctx, cx_p);
if (result!=1)
result = buffered_read_byte(ctx, cx_p);
if (result != 1)
break;
ctx->past++;
v = cx;
@@ -370,43 +339,43 @@ found:
return val;
}
void url_fskip (struct lib_ccx_ctx *ctx, int length)
void url_fskip (struct ccx_demuxer *ctx, int length)
{
buffered_seek (ctx, length);
ctx->past+=length;
ctx->past += length;
}
static long mpegps_psm_parse(struct lib_ccx_ctx *ctx)
static long mpegps_psm_parse(struct ccx_demuxer *ctx)
{
int psm_length, ps_info_length, es_map_length;
psm_length = get_be16(ctx);
get_byte(ctx);
get_byte(ctx);
ps_info_length = get_be16(ctx);
psm_length = buffered_get_be16(ctx);
buffered_get_byte(ctx);
buffered_get_byte(ctx);
ps_info_length = buffered_get_be16(ctx);
/* skip program_stream_info */
url_fskip(ctx, ps_info_length);
es_map_length = get_be16(ctx);
es_map_length = buffered_get_be16(ctx);
/* at least one es available? */
while (es_map_length >= 4)
{
unsigned char type = (unsigned char) get_byte(ctx);
unsigned char es_id =(unsigned char) get_byte(ctx);
unsigned int es_info_length = get_be16(ctx);
unsigned char type = (unsigned char) buffered_get_byte(ctx);
unsigned char es_id =(unsigned char) buffered_get_byte(ctx);
unsigned int es_info_length = buffered_get_be16(ctx);
/* remember mapping from stream id to stream type */
psm_es_type[es_id] = type;
/* skip program_stream_info */
url_fskip(ctx, es_info_length);
es_map_length -= 4 + es_info_length;
}
get_be32(ctx); /* crc32 */
buffered_get_be32(ctx); /* crc32 */
return 2 + psm_length;
}
static int mpegps_read_pes_header(struct lib_ccx_ctx *ctx, int *pstart_code,
static int mpegps_read_pes_header(struct ccx_demuxer *ctx, int *pstart_code,
LLONG *ppts, LLONG *pdts)
{
int len, size, startcode, c, flags, header_len;
@@ -428,11 +397,11 @@ redo:
startcode == PRIVATE_STREAM_2)
{
/* skip them */
len = get_be16(ctx);
len = buffered_get_be16(ctx);
// url_fskip(ctx, len);
goto redo;
}
position_sanity_check();
position_sanity_check(ctx->infd);
if (startcode == PROGRAM_STREAM_MAP)
{
mpegps_psm_parse(ctx);
@@ -445,30 +414,30 @@ redo:
(startcode == 0x1bd)))
goto redo;
len = get_be16(ctx);
len = buffered_get_be16(ctx);
pts = AV_NOPTS_VALUE;
dts = AV_NOPTS_VALUE;
position_sanity_check();
position_sanity_check(ctx->infd);
/* stuffing */
for(;;) {
if (len < 1)
goto redo;
c = get_byte(ctx);
c = buffered_get_byte(ctx);
len--;
/* XXX: for mpeg1, should test only bit 7 */
if (c != 0xff)
break;
}
position_sanity_check();
position_sanity_check(ctx->infd);
if ((c & 0xc0) == 0x40) {
/* buffer scale & size */
if (len < 2)
goto redo;
get_byte(ctx);
c = get_byte(ctx);
buffered_get_byte(ctx);
c = buffered_get_byte(ctx);
len -= 2;
}
position_sanity_check();
position_sanity_check(ctx->infd);
if ((c & 0xf0) == 0x20) {
if (len < 4)
goto redo;
@@ -488,8 +457,8 @@ redo:
goto redo;
}
#endif
flags = get_byte(ctx);
header_len = get_byte(ctx);
flags = buffered_get_byte(ctx);
header_len = buffered_get_byte(ctx);
len -= 2;
if (header_len > len)
goto redo;
@@ -509,26 +478,26 @@ redo:
}
len -= header_len;
while (header_len > 0) {
get_byte(ctx);
buffered_get_byte(ctx);
header_len--;
}
}
else if( c!= 0xf )
goto redo;
position_sanity_check();
position_sanity_check(ctx->infd);
if (startcode == PRIVATE_STREAM_1 /* && psm_es_type[startcode & 0xff] */)
{
if (len < 1)
goto redo;
startcode = get_byte(ctx);
startcode = buffered_get_byte(ctx);
len--;
if (startcode >= 0x80 && startcode <= 0xbf) {
/* audio: skip header */
if (len < 3)
goto redo;
get_byte(ctx);
get_byte(ctx);
get_byte(ctx);
buffered_get_byte(ctx);
buffered_get_byte(ctx);
buffered_get_byte(ctx);
len -= 3;
}
}
@@ -563,7 +532,7 @@ void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
}
LLONG linemask = 0;
dec_ctx = ctx->dec_ctx;
dec_ctx = update_decoder_list(ctx);
// unsigned long long utc = lastccptsu;
// [i]tv0 means there is a linemask
@@ -646,7 +615,7 @@ void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
// lastccptsu = utc;
}
static int mpegps_read_packet(struct lib_ccx_ctx *ctx)
static int mpegps_read_packet(struct ccx_demuxer *ctx)
{
LLONG pts, dts;
@@ -655,7 +624,7 @@ redo:
len = mpegps_read_pes_header(ctx, &startcode, &pts, &dts);
if (len < 0)
return len;
position_sanity_check();
position_sanity_check(ctx->infd);
/* now find stream */
/*
for(i=0;i<s->nb_streams;i++) {
@@ -697,7 +666,7 @@ redo:
{
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
unsigned char buf[8];
buffered_read (ctx, buf,8);
buffered_read(ctx, buf, 8);
ctx->past+=8;
// get_buffer(&s->pb, buf, 8);
buffered_seek(ctx, -8);
@@ -755,9 +724,9 @@ goto skip; */
// audio data
if (len <= 3)
goto skip;
get_byte(ctx); // emphasis (1), muse(1), reserved(1), frame number(5)
get_byte(ctx); // quant (2), freq(2), reserved(1), channels(3)
get_byte(ctx); // dynamic range control (0x80 = off)
buffered_get_byte(ctx); // emphasis (1), muse(1), reserved(1), frame number(5)
buffered_get_byte(ctx); // quant (2), freq(2), reserved(1), channels(3)
buffered_get_byte(ctx); // dynamic range control (0x80 = off)
len -= 3;
//freq = (b1 >> 4) & 3;
//st->codec->sample_rate = lpcm_freq_tab[freq];
@@ -779,9 +748,9 @@ goto skip; */
}
av.codec_id=codec_id;
av.type=type;
buffered_read (ctx, av.data,av.size);
ctx->past+=av.size;
position_sanity_check();
buffered_read(ctx, av.data, av.size);
ctx->past += av.size;
position_sanity_check(ctx->infd);
// LSEEK (fh,pkt->size,SEEK_CUR);
av.pts = pts;
av.dts = dts;
@@ -795,62 +764,30 @@ goto skip; */
return 0;
}
static int cc608_parity(unsigned int byte)
{
int ones = 0;
for (int i = 0; i < 7; i++)
{
if (byte & (1 << i))
ones++;
}
return ones & 1;
}
static void cc608_build_parity_table(int *parity_table)
{
unsigned int byte;
int parity_v;
for (byte = 0; byte <= 127; byte++)
{
parity_v = cc608_parity(byte);
/* CC uses odd parity (i.e., # of 1's in byte is odd.) */
parity_table[byte] = parity_v;
parity_table[byte | 0x80] = !parity_v;
}
}
void build_parity_table (void)
{
cc608_build_parity_table(cc608_parity_table);
}
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
void myth_loop(struct lib_ccx_ctx *ctx)
{
int rc;
int has_vbi=0;
LLONG saved = 0;
struct cc_subtitle dec_sub;
struct lib_cc_decode *dec_ctx = NULL;
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
unsigned long desp_length=65536;
unsigned char *desp=(unsigned char *) malloc (desp_length);
av.data=NULL;
ccx_options.buffer_input = 1;
dec_ctx = ctx->dec_ctx;
if (init_file_buffer())
{
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
}
unsigned long desp_length=65536;
unsigned char *desp=(unsigned char *) malloc (desp_length);
dec_ctx = update_decoder_list(ctx);
desp_length = 65536;
desp = (unsigned char *) malloc (desp_length);
if (!desp)
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
saved=0;
memset(&dec_sub, 0, sizeof(dec_sub));
while (!dec_ctx->processed_enough && (rc=mpegps_read_packet(ctx))==0)
while (is_decoder_processed_enough(ctx) == CCX_FALSE && (rc=mpegps_read_packet(ctx->demux_ctx))==0)
{
position_sanity_check();
position_sanity_check(ctx->demux_ctx->infd);
if (av.codec_id==CODEC_ID_MPEG2VBI && av.type==CODEC_TYPE_DATA)
{
if (!has_vbi)
@@ -874,19 +811,17 @@ void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
}
if (av.pts!=AV_NOPTS_VALUE)
{
current_pts=av.pts;
if (pts_set==0)
pts_set=1;
set_current_pts(dec_ctx->timing, av.pts);
}
memcpy (desp+saved,av.data,av.size);
LLONG used = process_m2v(ctx, desp, length, &dec_sub);
LLONG used = process_m2v(dec_ctx, desp, length, &dec_sub);
memmove (desp,desp+used,(unsigned int) (length-used));
saved=length-used;
}
if (ccx_options.live_stream)
{
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
int th=cur_sec/10;
if (ctx->last_reported_progress!=th)
{
@@ -898,10 +833,10 @@ void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
{
if (ctx->total_inputsize > 0 )
{
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
int progress = (int) ((((ctx->total_past+ctx->demux_ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
activity_progress (progress, cur_sec/60, cur_sec%60);
fflush (stdout);

View File

@@ -16,30 +16,39 @@
#define PASSWORD 2
#define BIN_MODE 3
#define CC_DESC 4
#define BIN_HEADER 5
#define BIN_DATA 6
#define EPG_DATA 7
#pragma warning( suppress : 4005)
#define ERROR 51
#define UNKNOWN_COMMAND 52
#define WRONG_PASSWORD 53
#define CONN_LIMIT 54
#define PING 55
/* #include <time.h> */
#define DFT_PORT "2048" /* Default port for server and client */
#define WRONG_PASSWORD_DELAY 2 /* Seconds */
#define BUFFER_SIZE 50
#define NO_RESPONCE_INTERVAL 20
#define PING_INTERVAL 3
int srv_sd = -1; /* Server socket descriptor */
const char *srv_addr;
const char *srv_port;
const char *srv_cc_desc;
const char *srv_pwd;
unsigned char *srv_header;
size_t srv_header_len;
/*
* 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);
@@ -68,7 +77,10 @@ void init_sockets (void);
void pr_command(char c);
#endif
void connect_to_srv(const char *addr, const char *port, const char *cc_desc)
void handle_write_error();
int set_nonblocking(int fd);
void connect_to_srv(const char *addr, const char *port, const char *cc_desc, const char *pwd)
{
if (NULL == addr)
{
@@ -85,14 +97,16 @@ void connect_to_srv(const char *addr, const char *port, const char *cc_desc)
if ((srv_sd = tcp_connect(addr, port)) < 0)
fatal(EXIT_FAILURE, "Unable to connect\n");
if (ask_passwd(srv_sd) < 0)
if (write_block(srv_sd, PASSWORD, pwd, pwd ? strlen(pwd) : 0) < 0)
fatal(EXIT_FAILURE, "Unable to connect\n");
if (cc_desc != NULL &&
write_block(srv_sd, CC_DESC, cc_desc, strlen(cc_desc)) < 0)
{
if (write_block(srv_sd, CC_DESC, cc_desc, cc_desc ? strlen(cc_desc) : 0) < 0)
fatal(EXIT_FAILURE, "Unable to connect\n");
}
srv_addr = addr;
srv_port = port;
srv_cc_desc = cc_desc;
srv_pwd = pwd;
mprint("Connected to %s:%s\n", addr, port);
}
@@ -106,38 +120,24 @@ void net_send_header(const unsigned char *data, size_t 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)
if (write_block(srv_sd, BIN_HEADER, data, len) <= 0)
{
printf("Can't send BIN header\n");
return;
}
char ok;
if (read_byte(srv_sd, &ok) != 1)
if (srv_header != NULL)
return;
#if DEBUG_OUT
fprintf(stderr, "[S] ");
pr_command(ok);
fprintf(stderr, "\n");
#endif
if ((srv_header = malloc(len)) == NULL)
fatal(EXIT_FAILURE, "Not enought memory");
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;
}
memcpy(srv_header, data, len);
srv_header_len = len;
}
void net_send_cc(const unsigned char *data, size_t len)
int net_send_cc(const unsigned char *data, int len, void *private_data, struct cc_subtitle *sub)
{
assert(srv_sd > 0);
@@ -145,19 +145,188 @@ void net_send_cc(const unsigned char *data, size_t len)
fprintf(stderr, "[C] Sending %u bytes\n", len);
#endif
ssize_t rc;
if ((rc = writen(srv_sd, data, len)) != (int) len)
if (write_block(srv_sd, BIN_DATA, data, len) <= 0)
{
if (rc < 0)
mprint("write() error: %s", strerror(errno));
return;
printf("Can't send BIN data\n");
return -1;
}
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
/* nanosleep((struct timespec[]){{0, 4000000}}, NULL); */
/* Sleep(100); */
return 1;
}
void net_check_conn()
{
time_t now;
static time_t last_ping = 0;
char c = 0;
int rc;
if (srv_sd <= 0)
return;
now = time(NULL);
if (last_ping == 0)
last_ping = now;
do {
c = 0;
rc = read_byte(srv_sd, &c);
if (c == PING) {
#if DEBUG_OUT
fprintf(stderr, "[S] Recieved PING\n");
#endif
last_ping = now;
}
} while (rc > 0 && c == PING);
if (now - last_ping > NO_RESPONCE_INTERVAL)
{
fprintf(stderr,
"[S] No PING recieved from the server in %u sec, reconnecting\n",
NO_RESPONCE_INTERVAL);
close(srv_sd);
srv_sd = -1;
connect_to_srv(srv_addr, srv_port, srv_cc_desc, srv_pwd);
net_send_header(srv_header, srv_header_len);
last_ping = now;
}
static time_t last_send_ping = 0;
if (now - last_send_ping >= PING_INTERVAL)
{
if (write_block(srv_sd, PING, NULL, 0) < 0)
{
printf("Unable to send data\n");
exit(EXIT_FAILURE);
}
last_send_ping = now;
}
}
void net_send_epg(
const char *start,
const char *stop,
const char *title,
const char *desc,
const char *lang,
const char *category
)
{
size_t st;
size_t sp;
size_t t;
size_t d;
size_t l;
size_t c;
size_t len;
char *epg;
char *end;
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
assert(srv_sd > 0);
if (NULL == start)
return;
if (NULL == stop)
return;
st = strlen(start) + 1;
sp = strlen(stop) + 1;
t = 1;
if (title != NULL)
t += strlen(title);
d = 1;
if (desc != NULL)
d += strlen(desc);
l = 1;
if (lang != NULL)
l += strlen(lang);
c = 1;
if (category != NULL)
c += strlen(category);
len = st + sp + t + d + l + c;
epg = (char *) calloc(len, sizeof(char));
if (NULL == epg)
return;
end = epg;
memcpy(end, start, st);
end += st;
memcpy(end, stop, sp);
end += sp;
if (title != NULL)
memcpy(end, title, t);
end += t;
if (desc != NULL)
memcpy(end, desc, d);
end += d;
if (lang != NULL)
memcpy(end, lang, l);
end += l;
if (category != NULL)
memcpy(end, category, c);
end += c;
#if DEBUG_OUT
fprintf(stderr, "[C] Sending EPG: %u bytes\n", len);
#endif
if (write_block(srv_sd, EPG_DATA, epg, len) <= 0)
fprintf(stderr, "Can't send EPG data\n");
return;
}
int net_tcp_read(int socket, void *buffer, size_t length)
{
assert(buffer != NULL);
assert(length > 0);
time_t now = time(NULL);
static time_t last_ping = 0;
if (last_ping == 0)
last_ping = now;
if (now - last_ping > PING_INTERVAL)
{
last_ping = now;
if (write_byte(socket, PING) <= 0)
fatal(EXIT_FAILURE, "Unable to send keep-alive packet to client\n");
}
int rc;
char c;
size_t l;
do
{
l = length;
if ((rc = read_block(socket, &c, buffer, &l)) <= 0)
return rc;
}
while (c != BIN_DATA && c != BIN_HEADER);
return l;
}
/*
* command | lenght | data | \r\n
* 1 byte | INT_LEN bytes | lenght bytes | 2 bytes
@@ -206,7 +375,7 @@ ssize_t write_block(int fd, char command, const char *buf, size_t buf_len)
}
#if DEBUG_OUT
if (buf != NULL)
if (buf != NULL && command != BIN_HEADER && command != BIN_DATA)
{
fwrite(buf, sizeof(char), buf_len, stderr);
fprintf(stderr, " ");
@@ -296,83 +465,12 @@ int tcp_connect(const char *host, const char *port)
if (NULL == p)
return -1;
if (set_nonblocking(sockfd) < 0)
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)
@@ -436,33 +534,9 @@ int start_tcp_srv(const char *port, const char *pwd)
free(cliaddr);
if (pwd != NULL && (rc = check_password(sockfd, pwd)) <= 0)
goto close_conn;
if (check_password(sockfd, pwd) > 0)
break;
#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);
@@ -482,43 +556,33 @@ close_conn:
int check_password(int fd, const char *pwd)
{
assert(pwd != NULL);
char c;
int rc;
size_t len;
char buf[BUFFER_SIZE];
size_t len = BUFFER_SIZE;
static char buf[BUFFER_SIZE + 1];
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 ((rc = read_block(fd, &c, buf, &len)) <= 0)
return rc;
buf[len] = '\0';
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;
}
if (pwd == NULL)
return 1;
if (c == PASSWORD && strcmp(pwd, buf) == 0) {
return 1;
}
#if DEBUG_OUT
fprintf(stderr, "[C] Wrong passsword\n");
#endif
#if DEBUG_OUT
fprintf(stderr, "[S] PASSWORD\n");
#endif
if (write_byte(fd, PASSWORD) < 0)
return -1;
return -1;
}
int tcp_bind(const char *port, int *family)
@@ -652,7 +716,7 @@ ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
fprintf(stderr, " ");
#endif
size_t len = atoi(len_str);
size_t len = atoi(len_str);
if (len > 0)
{
@@ -679,8 +743,11 @@ ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
nread += rc;
#if DEBUG_OUT
fwrite(buf, sizeof(char), len, stderr);
fprintf(stderr, " ");
if (*command != BIN_DATA && *command != BIN_HEADER)
{
fwrite(buf, sizeof(char), len, stderr);
fprintf(stderr, " ");
}
#endif
}
@@ -734,6 +801,18 @@ void pr_command(char c)
case PASSWORD:
fprintf(stderr, "PASSWORD");
break;
case BIN_HEADER:
fprintf(stderr, "BIN_HEADER");
break;
case BIN_DATA:
fprintf(stderr, "BIN_DATA");
break;
case EPG_DATA:
fprintf(stderr, "EPG_DATA");
break;
case PING:
fprintf(stderr, "PING");
break;
default:
fprintf(stderr, "UNKNOWN (%d)", (int) c);
break;
@@ -767,6 +846,10 @@ ssize_t readn(int fd, void *vptr, size_t n)
{
nread = 0;
}
else if (errno == EAGAIN || errno == EWOULDBLOCK)
{
break;
}
else
{
#if _WIN32
@@ -810,11 +893,7 @@ ssize_t writen(int fd, const void *vptr, size_t n)
}
else
{
#if _WIN32
wprintf(L"send() eror: %ld\n", WSAGetLastError());
#else
mprint("send() error: %s\n", strerror(errno));
#endif
handle_write_error();
return -1;
}
}
@@ -897,9 +976,11 @@ int start_upd_srv(const char *addr_str, unsigned port)
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
#ifndef _WIN32
if (IN_MULTICAST(addr))
servaddr.sin_addr.s_addr = htonl(addr);
else
#endif
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
@@ -961,3 +1042,71 @@ void init_sockets (void)
socket_inited = 1;
}
}
void handle_write_error()
{
#if _WIN32
long err = WSAGetLastError();
#else
char *err = strerror(errno);
#endif
if (srv_sd < 0)
return;
char c = 0;
int rc;
do {
c = 0;
rc = read_byte(srv_sd, &c);
if (rc < 0)
{
#if _WIN32
wprintf(L"send() eror: %ld\n", err);
#else
mprint("send() error: %s\n", err);
#endif
return;
}
} while (rc > 0 && c == PING);
switch (c)
{
case PASSWORD:
mprint("Wrong password (use -tcppassword)\n");
break;
case CONN_LIMIT:
mprint("Too many connections to the server, please wait\n");
break;
case ERROR:
mprint("Internal server error");
break;
default:
#if _WIN32
wprintf(L"send() eror: %ld\n", err);
#else
mprint("send() error: %s\n", err);
#endif
break;
}
return;
}
int set_nonblocking(int fd)
{
int f;
#ifdef O_NONBLOCK
if ((f = fcntl(fd, F_GETFL, 0)) < 0)
f = 0;
return fcntl(fd, F_SETFL, f | O_NONBLOCK);
#else
f = 1;
#if _WIN32
return ioctlsocket(fd, FIONBIO, &f);
#else
return ioctl(fd, FIONBIO, &f);
#endif
#endif
}

View File

@@ -3,10 +3,23 @@
#include <sys/types.h>
void connect_to_srv(const char *addr, const char *port, const char *cc_desc);
void connect_to_srv(const char *addr, const char *port, const char *cc_desc, const char *pwd);
void net_send_header(const unsigned char *data, size_t len);
void net_send_cc(const unsigned char *data, size_t len);
int net_send_cc(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
void net_check_conn();
void net_send_epg(
const char *start,
const char *stop,
const char *title,
const char *desc,
const char *lang,
const char *category
);
int net_tcp_read(int socket, void *buffer, size_t length);
int start_tcp_srv(const char *port, const char *pwd);

View File

@@ -1,13 +1,13 @@
#include "png.h"
#include "lib_ccx.h"
#ifdef ENABLE_OCR
#include "platform.h"
#include "capi.h"
#include "ccx_common_constants.h"
#include "allheaders.h"
#include <dirent.h>
#include "spupng_encoder.h"
#include "ccx_encoders_helpers.h"
#undef OCR_DEBUG
struct ocrCtx
{
TessBaseAPI* api;
@@ -63,11 +63,12 @@ static int search_language_pack(const char *dirname,const char *lang)
return -1;
}
static void delete_ocr (struct ocrCtx* ctx)
void delete_ocr (void** arg)
{
struct ocrCtx* ctx = *arg;
TessBaseAPIEnd(ctx->api);
TessBaseAPIDelete(ctx->api);
freep(&ctx);
freep(arg);
}
void* init_ocr(int lang_index)
{
@@ -93,24 +94,58 @@ void* init_ocr(int lang_index)
/* select english */
lang_index = 1;
}
ret = TessBaseAPIInit3(ctx->api,"", language[lang_index]);
ret = TessBaseAPIInit3(ctx->api, NULL, language[lang_index]);
if(ret < 0)
{
goto fail;
}
return ctx;
fail:
delete_ocr(ctx);
delete_ocr((void**)&ctx);
return NULL;
}
int ignore_alpha_at_edge(png_byte *alpha, unsigned char* indata, int w, int h, PIX *in, PIX **out)
{
int i, j, index, start_y, end_y;
int find_end_x = CCX_FALSE;
BOX* cropWindow;
for (j = 1; j < w-1; j++)
{
for (i = 0; i < h; i++)
{
index = indata[i * w + (j)];
if(alpha[index] != 0)
{
if(find_end_x == CCX_FALSE)
{
start_y = j;
find_end_x = CCX_TRUE;
}
else
{
end_y = j;
}
}
}
}
cropWindow = boxCreate(start_y, 0, (w - (start_y + ( w - end_y) )), h - 1);
*out = pixClipRectangle(in, cropWindow, NULL);
boxDestroy(&cropWindow);
return 0;
}
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h)
{
PIX *pix;
PIX *pix = NULL;
PIX *cpix = NULL;
char*text_out= NULL;
int i,j,index;
unsigned int wpl;
unsigned int *data,*ppixel;
BOOL tess_ret = FALSE;
struct ocrCtx* ctx = arg;
pix = pixCreate(w, h, 32);
if(pix == NULL)
@@ -133,13 +168,24 @@ char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* i
ppixel++;
}
}
text_out = TessBaseAPIProcessPage(ctx->api, pix, 0, NULL, NULL, 0);
if(!text_out)
ignore_alpha_at_edge(alpha, indata, w, h, pix, &cpix);
#ifdef OCR_DEBUG
{
char str[128] = "";
static int i = 0;
sprintf(str,"temp/file_c_%d.png",i);
pixWrite(str, cpix, IFF_PNG);
i++;
}
#endif
TessBaseAPISetImage2(ctx->api, cpix);
tess_ret = TessBaseAPIRecognize(ctx->api, NULL);
if( tess_ret != 0)
printf("\nsomething messy\n");
//TessDeleteText(text_out);
pixDestroy(&pix);
text_out = TessBaseAPIGetUTF8Text(ctx->api);
pixDestroy(&pix);
pixDestroy(&cpix);
return text_out;
}
@@ -207,7 +253,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
/* sorted in increasing order of intensity */
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
#if OCR_DEBUG
#ifdef OCR_DEBUG
ccx_common_logging.log_ftn("Intensity ordered table\n");
for (int i = 0; i < nb_color; i++)
{
@@ -240,7 +286,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
histogram[iot[max_ind]] = 0;
}
#if OCR_DEBUG
#ifdef OCR_DEBUG
ccx_common_logging.log_ftn("max redundant intensities table\n");
for (int i = 0; i < max_color; i++)
{
@@ -276,7 +322,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
}
}
#if OCR_DEBUG
#ifdef OCR_DEBUG
ccx_common_logging.log_ftn("Colors present in quantized Image\n");
for (int i = 0; i < nb_color; i++)
{
@@ -296,30 +342,88 @@ int ocr_rect(void* arg, struct cc_bitmap *rect, char **str)
png_color *palette = NULL;
png_byte *alpha = NULL;
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
palette = (png_color*) malloc(rect->nb_colors * sizeof(png_color));
if(!palette)
{
ret = -1;
goto end;
}
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
alpha = (png_byte*) malloc(rect->nb_colors * sizeof(png_byte));
if(!alpha)
{
ret = -1;
goto end;
}
/* TODO do rectangle wise, one color table should not be used for all rectangles */
mapclut_paletee(palette, alpha, (uint32_t *)rect->data[1],rect->nb_colors);
quantize_map(alpha, palette, rect->data[0], rect->w * rect->h, 3, rect->nb_colors);
*str = ocr_bitmap(arg, palette, alpha, rect->data[0], rect->w, rect->h);
end:
freep(&palette);
freep(&alpha);
return ret;
}
/**
* Call back function used while sorting rectangle by y position
* if both rectangle have same y position then x position is considered
*/
int compare_rect_by_ypos(const void*p1, const void *p2, void*arg)
{
const struct cc_bitmap* r1 = p1;
const struct cc_bitmap* r2 = p2;
if(r1->y > r2->y)
{
return 1;
}
else if (r1->y == r2->y)
{
if(r1->x > r2->x)
return 1;
}
else
{
return -1;
}
}
/**
* Check multiple rectangles and combine them to give one paragraph
* for all text detected from rectangles
*/
char *paraof_ocrtext(struct cc_subtitle *sub)
{
int i;
int len = 0;
char *str;
struct cc_bitmap* rect;
shell_sort(sub->data, sub->nb_data, sizeof(struct cc_bitmap), compare_rect_by_ypos, NULL);
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
{
if(rect->ocr_text)
len += strlen(rect->ocr_text);
}
if(len <= 0)
return NULL;
else
{
str = malloc(len+1);
if(!str)
return NULL;
*str = '\0';
}
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
{
strcat(str, rect->ocr_text);
freep(&rect->ocr_text);
}
return str;
}
#else
char* ocr_bitmap(png_color *palette,png_byte *alpha, unsigned char* indata,unsigned char d,int w, int h)
{

View File

@@ -2,8 +2,10 @@
#define OCR_H
#include <png.h>
void delete_ocr (void** arg);
void* init_ocr(int lang_index);
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h);
int ocr_rect(void* arg, struct cc_bitmap *rect, char **str);
char *paraof_ocrtext(struct cc_subtitle *sub);
#endif

View File

@@ -6,256 +6,235 @@
#include <unistd.h>
#endif
/* TODO remove dependency of encoder by removing writeDVDraw from this file */
#include "ccx_encoders_structs.h"
void init_write (struct ccx_s_write *wb,char *filename)
void dinit_write(struct ccx_s_write *wb)
{
if (wb->fh > 0)
close(wb->fh);
freep(&wb->filename);
}
int init_write (struct ccx_s_write *wb, char *filename)
{
memset(wb, 0, sizeof(struct ccx_s_write));
wb->fh=-1;
wb->filename=filename;
}
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, ccx_decoder_608_context *context, struct cc_subtitle *sub)
{
// Don't do anything for empty data
if (data==NULL)
return;
if (ccx_options.write_format==CCX_OF_RAW || ccx_options.write_format==CCX_OF_DVDRAW)
wb->fh=-1;
wb->filename = filename;
mprint ("Creating %s\n", filename);
wb->fh = open (filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (wb->fh == -1)
{
if (context && context->out)
writeraw (data,length,context->out);
return CCX_COMMON_EXIT_FILE_CREATION_FAILED;
}
else 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_SPUPNG ||
ccx_options.write_format==CCX_OF_NULL)
process608 (data,length,context, sub);
else
fatal(CCX_COMMON_EXIT_BUG_BUG, "Should not be reached!");
return EXIT_OK;
}
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile)
int writeraw (const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub)
{
if (closefile && wb!=NULL && wb->fh!=-1 && !ctx->cc_to_stdout)
close (wb->fh);
unsigned char* sub_data = NULL;
// Don't do anything for empty data
if (data==NULL)
return -1;
sub->data = realloc(sub->data, length + sub->nb_data);
if (!sub->data)
return EXIT_NOT_ENOUGH_MEMORY;
sub_data = sub->data;
memcpy(sub_data + sub->nb_data, data, length);
sub->got_output = 1;
sub->nb_data += length;
sub->type = CC_RAW;
return EXIT_SUCCESS;
}
void writeDVDraw (const unsigned char *data1, int length1,
const unsigned char *data2, int length2,
struct ccx_s_write *wb)
struct cc_subtitle *sub)
{
/* these are only used by DVD raw mode: */
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
loop 3: 11 elements, rest: 15 elements */
static int datacount = 0; /* counts within loop */
/* these are only used by DVD raw mode: */
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
loop 3: 11 elements, rest: 15 elements */
static int datacount = 0; /* counts within loop */
if (datacount==0)
{
write (wb->fh,DVD_HEADER,sizeof (DVD_HEADER));
if (loopcount==1)
write (wb->fh,lc1,sizeof (lc1));
if (loopcount==2)
write (wb->fh,lc2,sizeof (lc2));
if (loopcount==3)
{
write (wb->fh,lc3,sizeof (lc3));
if (data2 && length2)
write (wb->fh,data2,length2);
}
if (loopcount>3)
{
write (wb->fh,lc4,sizeof (lc4));
if (datacount==0)
{
writeraw (DVD_HEADER, sizeof (DVD_HEADER), NULL, sub);
if (loopcount==1)
writeraw (lc1, sizeof (lc1), NULL, sub);
if (loopcount==2)
writeraw (lc2, sizeof (lc2), NULL, sub);
if (loopcount==3)
{
writeraw (lc3, sizeof (lc3), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
}
}
datacount++;
write (wb->fh,lc5,sizeof (lc5));
writeraw (data2, length2, NULL, sub);
}
if (loopcount>3)
{
writeraw (lc4, sizeof (lc4), NULL, sub);
if (data2 && length2)
writeraw (data2, length2, NULL, sub);
}
}
datacount++;
writeraw (lc5, sizeof (lc5), NULL, sub);
if (data1 && length1)
write (wb->fh,data1,length1);
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
((loopcount > 3) && (datacount < 15)))
{
write (wb->fh,lc6,sizeof (lc6));
writeraw (data1, length1, NULL, sub);
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
((loopcount > 3) && (datacount < 15)))
{
writeraw (lc6, sizeof(lc6), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
}
else
{
if (loopcount==1)
{
write (wb->fh,lc6,sizeof (lc6));
writeraw (data2, length2, NULL, sub);
}
else
{
if (loopcount==1)
{
writeraw (lc6, sizeof(lc6), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
}
loopcount++;
datacount=0;
}
writeraw (data2, length2, NULL, sub);
}
loopcount++;
datacount=0;
}
}
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
const unsigned char *data2, int length2, struct cc_subtitle *sub)
{
struct ccx_decoder_608_context *field_1 = ctx->context_cc608_field_1;
struct ccx_decoder_608_context *field_2 = ctx->context_cc608_field_2;
struct ccx_s_write *wbout1 = ctx->wbout1;
field_1->out = ctx->wbout1 ;
field_2->out = ctx->wbout2 ;
if (ctx->write_format==CCX_OF_DVDRAW)
writeDVDraw (data1, length1, data2, length2, wbout1);
writeDVDraw (data1, length1, data2, length2, sub);
else /* Broadcast raw or any non-raw */
{
if (length1 && ccx_options.extract != 2)
if (length1 && ctx->extract != 2)
{
writedata(data1, length1, field_1, sub);
ctx->current_field = 1;
ctx->writedata(data1, length1, ctx, sub);
}
if (length2)
{
if (ccx_options.extract != 1)
writedata(data2, length2, field_2, sub);
ctx->current_field = 2;
if (ctx->extract != 1)
ctx->writedata(data2, length2, ctx, sub);
else // User doesn't want field 2 data, but we want XDS.
writedata (data2,length2,NULL, sub);
{
ctx->writedata (data2, length2, ctx, sub);
}
}
}
}
/* Buffer data with the same FTS and write when a new FTS or data==NULL
* is encountered */
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data)
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data, struct cc_subtitle *sub)
{
static LLONG prevfts = -1;
LLONG currfts = fts_now + fts_global;
LLONG currfts = ctx->timing->fts_now + ctx->timing->fts_global;
static uint16_t cbcount = 0;
static int cbempty=0;
static unsigned char cbbuffer[0xFFFF*3]; // TODO: use malloc
static unsigned char cbheader[8+2];
struct ccx_s_write *wbout1 = ctx->wbout1;
if ( (prevfts != currfts && prevfts != -1)
|| data == NULL
|| cbcount == 0xFFFF)
{
// Remove trailing empty or 608 padding caption blocks
if ( cbcount != 0xFFFF)
{
unsigned char cc_valid;
unsigned char cc_type;
int storecbcount=cbcount;
for( int cb = cbcount-1; cb >= 0 ; cb-- )
{
cc_valid = (*(cbbuffer+3*cb) & 4) >>2;
cc_type = *(cbbuffer+3*cb) & 3;
// The -fullbin option disables pruning of 608 padding blocks
if ( (cc_valid && cc_type <= 1 // Only skip NTSC padding packets
&& !ccx_options.fullbin // Unless we want to keep them
&& *(cbbuffer+3*cb+1)==0x80
&& *(cbbuffer+3*cb+2)==0x80)
|| !(cc_valid || cc_type==3) ) // or unused packets
{
cbcount--;
}
else
{
cb = -1;
}
}
dbg_print(CCX_DMT_CBRAW, "%s Write %d RCWT blocks - skipped %d padding / %d unused blocks.\n",
print_mstime(prevfts), cbcount, storecbcount - cbcount, cbempty);
}
// New FTS, write data header
// RCWT data header (10 bytes):
//byte(s) value description
//0-7 FTS int64_t number with current FTS
//8-9 blocks Number of 3 byte data blocks with the same FTS that are
// following this header
memcpy(cbheader,&prevfts,8);
memcpy(cbheader+8,&cbcount,2);
if (cbcount > 0)
{
if (ccx_options.send_to_srv)
{
net_send_cc(cbheader, 10);
net_send_cc(cbbuffer, 3*cbcount);
}
else
{
writeraw(cbheader,10,wbout1);
writeraw(cbbuffer,3*cbcount, wbout1);
}
}
cbcount = 0;
cbempty = 0;
}
if ( data )
{
// Store the data while the FTS is unchanged
unsigned char cc_valid = (*data & 4) >> 2;
unsigned char cc_type = *data & 3;
// Store only non-empty packets
if (cc_valid || cc_type==3)
{
// Store in buffer until we know how many blocks come with
// this FTS.
memcpy(cbbuffer+cbcount*3, data, 3);
cbcount++;
}
else
{
cbempty++;
}
}
else
{
// Write a padding block for field 1 and 2 data if this is the final
// call to this function. This forces the RCWT file to have the
// same length as the source video file.
// currfts currently holds the end time, subtract one block length
// so that the FTS corresponds to the time before the last block is
// written
currfts -= 1001/30;
memcpy(cbheader,&currfts,8);
cbcount = 2;
memcpy(cbheader+8,&cbcount,2);
memcpy(cbbuffer, "\x04\x80\x80", 3); // Field 1 padding
memcpy(cbbuffer+3, "\x05\x80\x80", 3); // Field 2 padding
if (ccx_options.send_to_srv)
if ( (prevfts != currfts && prevfts != -1)
|| data == NULL
|| cbcount == 0xFFFF)
{
// Remove trailing empty or 608 padding caption blocks
if ( cbcount != 0xFFFF)
{
net_send_cc(cbheader, 10);
net_send_cc(cbbuffer, 3*cbcount);
unsigned char cc_valid;
unsigned char cc_type;
int storecbcount=cbcount;
for( int cb = cbcount-1; cb >= 0 ; cb-- )
{
cc_valid = (*(cbbuffer+3*cb) & 4) >>2;
cc_type = *(cbbuffer+3*cb) & 3;
// The -fullbin option disables pruning of 608 padding blocks
if ( (cc_valid && cc_type <= 1 // Only skip NTSC padding packets
&& !ctx->fullbin // Unless we want to keep them
&& *(cbbuffer+3*cb+1)==0x80
&& *(cbbuffer+3*cb+2)==0x80)
|| !(cc_valid || cc_type==3) ) // or unused packets
{
cbcount--;
}
else
{
cb = -1;
}
}
dbg_print(CCX_DMT_CBRAW, "%s Write %d RCWT blocks - skipped %d padding / %d unused blocks.\n",
print_mstime(prevfts), cbcount, storecbcount - cbcount, cbempty);
}
// New FTS, write data header
// RCWT data header (10 bytes):
//byte(s) value description
//0-7 FTS int64_t number with current FTS
//8-9 blocks Number of 3 byte data blocks with the same FTS that are
// following this header
memcpy(cbheader,&prevfts,8);
memcpy(cbheader+8,&cbcount,2);
if (cbcount > 0)
{
ctx->writedata(cbheader, 10, ctx->context_cc608_field_1, sub);
ctx->writedata(cbbuffer, 3 * cbcount, ctx->context_cc608_field_1, sub);
}
cbcount = 0;
cbempty = 0;
}
if ( data )
{
// Store the data while the FTS is unchanged
unsigned char cc_valid = (*data & 4) >> 2;
unsigned char cc_type = *data & 3;
// Store only non-empty packets
if (cc_valid || cc_type==3)
{
// Store in buffer until we know how many blocks come with
// this FTS.
memcpy(cbbuffer+cbcount*3, data, 3);
cbcount++;
}
else
{
writeraw(cbheader,10, wbout1);
writeraw(cbbuffer,3*cbcount, wbout1);
cbempty++;
}
}
else
{
// Write a padding block for field 1 and 2 data if this is the final
// call to this function. This forces the RCWT file to have the
// same length as the source video file.
cbcount = 0;
cbempty = 0;
// currfts currently holds the end time, subtract one block length
// so that the FTS corresponds to the time before the last block is
// written
currfts -= 1001/30;
dbg_print(CCX_DMT_CBRAW, "%s Write final padding RCWT blocks.\n",
print_mstime(currfts));
}
memcpy(cbheader,&currfts,8);
cbcount = 2;
memcpy(cbheader+8,&cbcount,2);
prevfts = currfts;
memcpy(cbbuffer, "\x04\x80\x80", 3); // Field 1 padding
memcpy(cbbuffer+3, "\x05\x80\x80", 3); // Field 2 padding
ctx->writedata(cbheader, 10, ctx->context_cc608_field_1, sub);
ctx->writedata(cbbuffer, 3 * cbcount, ctx->context_cc608_field_1, sub);
cbcount = 0;
cbempty = 0;
dbg_print(CCX_DMT_CBRAW, "%s Write final padding RCWT blocks.\n",
print_mstime(currfts));
}
prevfts = currfts;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,24 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "teletext.h"
#include "ccx_decoders_708.h"
void params_dump(struct lib_ccx_ctx *ctx)
{
// Display parsed parameters
mprint ("Input: ");
// Display parsed parameters
mprint ("Input: ");
switch (ccx_options.input_source)
{
case CCX_DS_FILE:
for (int i=0;i<ctx->num_input_files;i++)
mprint ("%s%s",ctx->inputfile[i],i==(ctx->num_input_files-1)?"":",");
mprint ("%s%s",ctx->inputfile[i],i==(ctx->num_input_files-1)?"":",");
break;
case CCX_DS_STDIN:
mprint ("stdin");
break;
case CCX_DS_NETWORK:
if (ccx_options.udpaddr == NULL)
if (ccx_options.udpaddr == NULL)
mprint ("Network, UDP/%u",ccx_options.udpport);
else
{
@@ -26,82 +29,63 @@ void params_dump(struct lib_ccx_ctx *ctx)
mprint("Network, TCP/%s", ccx_options.tcpport);
break;
}
mprint ("\n");
mprint ("[Extract: %d] ", ccx_options.extract);
mprint ("[Stream mode: ");
switch (ctx->auto_stream)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
mprint ("Elementary");
break;
case CCX_SM_TRANSPORT:
mprint ("Transport");
break;
case CCX_SM_PROGRAM:
mprint ("Program");
break;
case CCX_SM_ASF:
mprint ("DVR-MS");
break;
case CCX_SM_WTV:
mprint ("Windows Television (WTV)");
break;
case CCX_SM_MCPOODLESRAW:
mprint ("McPoodle's raw");
break;
case CCX_SM_AUTODETECT:
mprint ("Autodetect");
break;
case CCX_SM_RCWT:
mprint ("BIN");
break;
case CCX_SM_MP4:
mprint ("MP4");
break;
#ifdef WTV_DEBUG
case CCX_SM_HEX_DUMP:
mprint ("Hex");
break;
#endif
default:
fatal(CCX_COMMON_EXIT_BUG_BUG, "BUG: Unknown stream mode.\n");
break;
}
mprint ("]\n");
mprint ("\n");
mprint ("[Extract: %d] ", ccx_options.extract);
mprint ("[Stream mode: ");
ctx->demux_ctx->print_cfg(ctx->demux_ctx);
mprint ("]\n");
mprint ("[Program : ");
if (ccx_options.ts_forced_program_selected != 0)
mprint ("%u ]",ccx_options.ts_forced_program);
if (ccx_options.demux_cfg.ts_forced_program_selected != 0)
mprint ("%u ]",ccx_options.demux_cfg.ts_forced_program);
else
mprint ("Auto ]");
mprint (" [Hauppage mode: %s]",ccx_options.hauppauge_mode?"Yes":"No");
mprint (" [Use MythTV code: ");
switch (ccx_options.auto_myth)
{
case 0:
mprint ("Disabled");
break;
case 1:
mprint ("Forced - Overrides stream mode setting");
break;
case 2:
mprint ("Auto");
break;
}
mprint ("]");
if (ccx_options.wtvconvertfix)
{
mprint (" [Windows 7 wtv to dvr-ms conversion fix: Enabled]");
}
mprint ("\n");
mprint (" [Use MythTV code: ");
switch (ccx_options.auto_myth)
{
case 0:
mprint ("Disabled");
break;
case 1:
mprint ("Forced - Overrides stream mode setting");
break;
case 2:
mprint ("Auto");
break;
}
mprint ("]");
mprint ("\n");
if (ccx_options.wtvmpeg2)
{
mprint (" [WTV use MPEG2 stream: Enabled]");
}
mprint ("\n");
if (ccx_options.settings_dtvcc.enabled)
{
mprint ("[CEA-708: %d decoders active]\n", ccx_options.settings_dtvcc.active_services_count);
if (ccx_options.settings_dtvcc.active_services_count == CCX_DTVCC_MAX_SERVICES)
{
char *charset = ccx_options.enc_cfg.all_services_charset;
mprint ("[CEA-708: using charset \"%s\" for all services]\n", charset ? charset : "none");
}
else
{
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
if (ccx_options.settings_dtvcc.services_enabled[i])
mprint("[CEA-708: using charset \"%s\" for service %d]\n",
ccx_options.enc_cfg.services_charsets[i] ?
ccx_options.enc_cfg.services_charsets[i] : "none",
i + 1);
}
}
}
mprint ("[Timing mode: ");
if (ccx_options.wtvconvertfix)
mprint (" [Windows 7 wtv to dvr-ms conversion fix: Enabled]\n");
if (ccx_options.wtvmpeg2)
mprint (" [WTV use MPEG2 stream: Enabled]\n");
mprint ("[Timing mode: ");
switch (ccx_options.use_gop_as_pts)
{
case 1:
@@ -115,101 +99,135 @@ void params_dump(struct lib_ccx_ctx *ctx)
break;
}
mprint ("] ");
mprint ("[Debug: %s] ", (ccx_options.debug_mask & CCX_DMT_VERBOSE) ? "Yes": "No");
mprint ("[Buffer input: %s]\n", ccx_options.buffer_input ? "Yes": "No");
mprint ("[Use pic_order_cnt_lsb for H.264: %s] ", ccx_options.usepicorder ? "Yes": "No");
mprint ("[Debug: %s] ", (ccx_options.debug_mask & CCX_DMT_VERBOSE) ? "Yes": "No");
mprint ("[Buffer input: %s]\n", ccx_options.buffer_input ? "Yes": "No");
mprint ("[Use pic_order_cnt_lsb for H.264: %s] ", ccx_options.usepicorder ? "Yes": "No");
mprint("[Print CC decoder traces: %s]\n", (ccx_options.debug_mask & CCX_DMT_DECODER_608) ? "Yes" : "No");
mprint ("[Target format: %s] ",ctx->extension);
mprint ("[Encoding: ");
switch (ccx_options.encoding)
{
case CCX_ENC_UNICODE:
mprint ("Unicode");
break;
case CCX_ENC_UTF_8:
mprint ("UTF-8");
break;
case CCX_ENC_LATIN_1:
mprint ("Latin-1");
break;
}
mprint ("] ");
mprint ("[Delay: %lld] ",ctx->subs_delay);
mprint ("[Target format: %s] ",ctx->extension);
mprint ("[Encoding: ");
switch (ccx_options.enc_cfg.encoding)
{
case CCX_ENC_UNICODE:
mprint ("Unicode");
break;
case CCX_ENC_UTF_8:
mprint ("UTF-8");
break;
case CCX_ENC_LATIN_1:
mprint ("Latin-1");
break;
}
mprint ("] ");
mprint ("[Delay: %lld] ",ctx->subs_delay);
mprint ("[Trim lines: %s]\n",ccx_options.trim_subs?"Yes":"No");
mprint ("[Add font color data: %s] ", ccx_options.nofontcolor? "No" : "Yes");
mprint ("[Trim lines: %s]\n",ccx_options.enc_cfg.trim_subs?"Yes":"No");
mprint ("[Add font color data: %s] ", ccx_options.nofontcolor? "No" : "Yes");
mprint ("[Add font typesetting: %s]\n", ccx_options.notypesetting? "No" : "Yes");
mprint ("[Convert case: ");
if (ccx_options.sentence_cap_file!=NULL)
mprint ("Yes, using %s", ccx_options.sentence_cap_file);
else
{
mprint ("%s",ccx_options.sentence_cap?"Yes, but only built-in words":"No");
}
mprint ("]");
mprint (" [Video-edit join: %s]", ccx_options.binary_concat?"No":"Yes");
mprint ("\n[Extraction start time: ");
if (ccx_options.extraction_start.set==0)
mprint ("not set (from start)");
else
mprint ("%02d:%02d:%02d", ccx_options.extraction_start.hh,
ccx_options.extraction_start.mm,
ccx_options.extraction_start.ss);
mprint ("]\n");
mprint ("[Extraction end time: ");
if (ccx_options.extraction_end.set==0)
mprint ("not set (to end)");
else
mprint ("%02d:%02d:%02d", ccx_options.extraction_end.hh,
ccx_options.extraction_end.mm,
ccx_options.extraction_end.ss);
mprint ("]\n");
mprint ("[Live stream: ");
if (ccx_options.live_stream==0)
mprint ("No");
else
{
if (ccx_options.live_stream<1)
mprint ("Yes, no timeout");
else
mprint ("Yes, timeout: %d seconds",ccx_options.live_stream);
}
mprint ("] [Clock frequency: %d]\n",MPEG_CLOCK_FREQ);
mprint ("Teletext page: [");
mprint ("[Convert case: ");
if (ccx_options.sentence_cap_file!=NULL)
mprint ("Yes, using %s", ccx_options.sentence_cap_file);
else
{
mprint ("%s",ccx_options.enc_cfg.sentence_cap?"Yes, but only built-in words":"No");
}
mprint ("]");
mprint (" [Video-edit join: %s]", ccx_options.binary_concat?"No":"Yes");
mprint ("\n[Extraction start time: ");
if (ccx_options.extraction_start.set==0)
mprint ("not set (from start)");
else
mprint ("%02d:%02d:%02d", ccx_options.extraction_start.hh,
ccx_options.extraction_start.mm,
ccx_options.extraction_start.ss);
mprint ("]\n");
mprint ("[Extraction end time: ");
if (ccx_options.extraction_end.set==0)
mprint ("not set (to end)");
else
mprint ("%02d:%02d:%02d", ccx_options.extraction_end.hh,
ccx_options.extraction_end.mm,
ccx_options.extraction_end.ss);
mprint ("]\n");
mprint ("[Live stream: ");
if (ccx_options.live_stream==0)
mprint ("No");
else
{
if (ccx_options.live_stream<1)
mprint ("Yes, no timeout");
else
mprint ("Yes, timeout: %d seconds",ccx_options.live_stream);
}
mprint ("] [Clock frequency: %d]\n",MPEG_CLOCK_FREQ);
mprint ("[Teletext page: ");
if (tlt_config.page)
mprint ("%d]\n",tlt_config.page);
else
mprint ("Autodetect]\n");
mprint ("Start credits text: [%s]\n",
ccx_options.start_credits_text?ccx_options.start_credits_text:"None");
if (ccx_options.start_credits_text)
{
mprint ("Start credits time: Insert between [%ld] and [%ld] seconds\n",
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
(long) (ccx_options.startcreditsnotafter.time_in_ms/1000)
);
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.startcreditsforatmost.time_in_ms/1000)
);
}
if (ccx_options.end_credits_text)
{
mprint ("End credits text: [%s]\n",
ccx_options.end_credits_text?ccx_options.end_credits_text:"None");
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.endcreditsforatmost.time_in_ms/1000)
);
}
mprint ("[Start credits text: %s]\n",
ccx_options.enc_cfg.start_credits_text?ccx_options.enc_cfg.start_credits_text:"None");
if (ccx_options.enc_cfg.start_credits_text)
{
mprint ("Start credits time: Insert between [%ld] and [%ld] seconds\n",
(long) (ccx_options.enc_cfg.startcreditsnotbefore.time_in_ms/1000),
(long) (ccx_options.enc_cfg.startcreditsnotafter.time_in_ms/1000)
);
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.enc_cfg.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.enc_cfg.startcreditsforatmost.time_in_ms/1000)
);
}
if (ccx_options.enc_cfg.end_credits_text)
{
mprint ("End credits text: [%s]\n",
ccx_options.enc_cfg.end_credits_text?ccx_options.enc_cfg.end_credits_text:"None");
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.enc_cfg.endcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.enc_cfg.endcreditsforatmost.time_in_ms/1000)
);
}
}
#define Y_N(cond) ((cond) ? "Yes" : "No")
void print_cc_report(struct lib_ccx_ctx *ctx, struct cap_info* info)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = update_decoder_list_cinfo(ctx, info);
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
{
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
}
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
{
printf("Services: ");
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
if (ctx->freport.data_from_708->services[i] == 0)
continue;
printf("%d ", i);
}
printf("\n");
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
}
}
void print_file_report(struct lib_ccx_ctx *ctx)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
#define Y_N(cond) ((cond) ? "Yes" : "No")
enum ccx_stream_mode_enum stream_mode;
struct ccx_demuxer *demux_ctx = ctx->demux_ctx;
printf("File: ");
switch (ccx_options.input_source)
@@ -232,46 +250,44 @@ void print_file_report(struct lib_ccx_ctx *ctx)
break;
}
struct cap_info* program;
printf("Stream Mode: ");
switch (ctx->stream_mode)
switch (demux_ctx->stream_mode)
{
case CCX_SM_TRANSPORT:
printf("Transport Stream\n");
printf("Program Count: %d\n", ctx->freport.program_cnt);
printf("Program Count: %d\n", demux_ctx->freport.program_cnt);
printf("Program Numbers: ");
for (int i = 0; i < pmt_array_length; i++)
{
if (pmt_array[i].program_number == 0)
continue;
printf("%u ", pmt_array[i].program_number);
}
for (int i = 0; i < demux_ctx->nb_program; i++)
printf("%u ", demux_ctx->pinfo[i].program_number);
printf("\n");
for (int i = 0; i < 65536; i++)
{
if (ctx->PIDs_programs[i] == 0)
if (demux_ctx->PIDs_programs[i] == 0)
continue;
printf("PID: %u, Program: %u, ", i, ctx->PIDs_programs[i]->program_number);
printf("PID: %u, Program: %u, ", i, demux_ctx->PIDs_programs[i]->program_number);
int j;
for (j = 0; j < SUB_STREAMS_CNT; j++)
{
if (ctx->freport.dvb_sub_pid[j] == i)
if (demux_ctx->freport.dvb_sub_pid[j] == i)
{
printf("DVB Subtitles\n");
break;
}
if (ctx->freport.tlt_sub_pid[j] == i)
if (demux_ctx->freport.tlt_sub_pid[j] == i)
{
printf("Teletext Subtitles\n");
break;
}
}
if (j == SUB_STREAMS_CNT)
printf("%s\n", desc[ctx->PIDs_programs[i]->printable_stream_type]);
printf("%s\n", desc[demux_ctx->PIDs_programs[i]->printable_stream_type]);
}
break;
@@ -304,91 +320,65 @@ void print_file_report(struct lib_ccx_ctx *ctx)
default:
break;
}
if (ccx_bufferdatatype == CCX_PES &&
(ctx->stream_mode == CCX_SM_TRANSPORT ||
ctx->stream_mode == CCX_SM_PROGRAM ||
ctx->stream_mode == CCX_SM_ASF ||
ctx->stream_mode == CCX_SM_WTV))
if(list_empty(&demux_ctx->cinfo_tree.all_stream))
{
printf("Width: %u\n", ctx->freport.width);
printf("Height: %u\n", ctx->freport.height);
printf("Aspect Ratio: %s\n", aspect_ratio_types[ctx->freport.aspect_ratio]);
printf("Frame Rate: %s\n", framerates_types[ctx->freport.frame_rate]);
print_cc_report(ctx, NULL);
}
if (ctx->freport.program_cnt > 1)
printf("//////// Program #%u: ////////\n", TS_program_number);
printf("DVB Subtitles: ");
int j;
for (j = 0; j < SUB_STREAMS_CNT; j++)
list_for_each_entry(program, &demux_ctx->cinfo_tree.pg_stream, pg_stream, struct cap_info)
{
unsigned pid = ctx->freport.dvb_sub_pid[j];
if (pid == 0)
continue;
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
struct cap_info* info = NULL;
printf("//////// Program #%u: ////////\n", program->program_number);
printf("DVB Subtitles: ");
info = get_sib_stream_by_type(program, CCX_CODEC_DVB);
if(info)
printf("Yes\n");
else
printf("No\n");
printf("Teletext: ");
info = get_sib_stream_by_type(program, CCX_CODEC_TELETEXT);
if(info)
{
printf("Yes\n");
break;
}
}
if (j == SUB_STREAMS_CNT)
printf("No\n");
printf("Teletext: ");
for (j = 0; j < SUB_STREAMS_CNT; j++)
{
unsigned pid = ctx->freport.tlt_sub_pid[j];
if (pid == 0)
continue;
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
{
printf("Yes\n");
dec_ctx = update_decoder_list_cinfo(ctx, info);
printf("Pages With Subtitles: ");
for (int i = 0; i < MAX_TLT_PAGES; i++)
{
if (seen_sub_page[i] == 0)
continue;
tlt_print_seen_pages(dec_ctx);
printf("%d ", i);
}
printf("\n");
break;
printf("\n");
}
}
if (j == SUB_STREAMS_CNT)
printf("No\n");
else
printf("No\n");
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
{
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
}
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
{
printf("Services: ");
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
printf("ATSC Closed Caption: ");
info = get_sib_stream_by_type(program, CCX_CODEC_ATSC_CC);
if(info)
{
if (ctx->freport.data_from_708->services[i] == 0)
continue;
printf("%d ", i);
printf("Yes\n");
print_cc_report(ctx, info);
}
else
printf("No\n");
info = get_best_sib_stream(program);
if(!info)
continue;
dec_ctx = update_decoder_list_cinfo(ctx, info);
if (dec_ctx->in_bufferdatatype == CCX_PES &&
(info->stream == CCX_SM_TRANSPORT ||
info->stream == CCX_SM_PROGRAM ||
info->stream == CCX_SM_ASF ||
info->stream == CCX_SM_WTV))
{
printf("Width: %u\n", dec_ctx->current_hor_size);
printf("Height: %u\n", dec_ctx->current_vert_size);
printf("Aspect Ratio: %s\n", aspect_ratio_types[dec_ctx->current_aspect_ratio]);
printf("Frame Rate: %s\n", framerates_types[dec_ctx->current_frame_rate]);
}
printf("\n");
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
}
printf("MPEG-4 Timed Text: %s\n", Y_N(ctx->freport.mp4_cc_track_cnt));
@@ -396,7 +386,7 @@ void print_file_report(struct lib_ccx_ctx *ctx)
printf("MPEG-4 Timed Text tracks count: %d\n", ctx->freport.mp4_cc_track_cnt);
}
freep(&ctx->freport.data_from_608);
memset(&ctx->freport, 0, sizeof (struct file_report));
#undef Y_N
#undef Y_N
}

View File

@@ -7,58 +7,50 @@
// enough space.
//#define SORTBUF (2*MAXBFRAMES+1) - from lib_ccx.h
// B-Frames can be (temporally) before or after the anchor
int cc_data_count[SORTBUF];
// Store fts;
static LLONG cc_fts[SORTBUF];
// Store HD CC packets
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
// Set to true if data is buffered
int has_ccdata_buffered = 0;
// The sequence number of the current anchor frame. All currently read
// B-Frames belong to this I- or P-frame.
static int anchor_seq_number = -1;
void init_hdcc (void)
void init_hdcc (struct lib_cc_decode *ctx)
{
for (int j=0; j<SORTBUF; j++)
{
cc_data_count[j] = 0;
cc_fts[j] = 0;
}
memset(cc_data_pkts, 0, SORTBUF*(31*3+1));
has_ccdata_buffered = 0;
for (int j=0; j<SORTBUF; j++)
{
ctx->cc_data_count[j] = 0;
ctx->cc_fts[j] = 0;
}
memset(ctx->cc_data_pkts, 0, SORTBUF*(31*3+1));
ctx->has_ccdata_buffered = 0;
}
// Buffer caption blocks for later sorting/flushing.
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now,struct cc_subtitle *sub)
void store_hdcc(struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now, struct cc_subtitle *sub)
{
// Uninitialized?
if (anchor_seq_number < 0)
{
anchor_hdcc( sequence_number);
}
enum ccx_stream_mode_enum stream_mode;
int seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
//stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx);
// Uninitialized?
if (ctx->anchor_seq_number < 0)
{
anchor_hdcc( ctx, sequence_number);
}
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
{
// 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");
int seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
process_hdcc(ctx, sub);
anchor_hdcc( sequence_number);
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
}
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
{
// 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");
has_ccdata_buffered = 1;
process_hdcc(ctx, sub);
anchor_hdcc( ctx, sequence_number);
seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
}
ctx->has_ccdata_buffered = 1;
// In GOP mode the fts is set only once for the whole GOP. Recreate
// the right time according to the sequence number.
if (ccx_options.use_gop_as_pts==1)
{
current_fts_now += (LLONG) (sequence_number*1000.0/current_fps);
}
// the right time according to the sequence number.
if (ccx_options.use_gop_as_pts==1)
{
current_fts_now += (LLONG) (sequence_number*1000.0/current_fps);
}
if (cc_count)
{
@@ -66,47 +58,46 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
{
// Changed by CFS to concat, i.e. don't assume there's no data already for this seq_index.
// Needed at least for MP4 samples. // TODO: make sure we don't overflow
cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
if (ctx->stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
cc_data_count[seq_index] = 0;
memcpy(cc_data_pkts[seq_index]+cc_data_count[seq_index]*3, cc_data, cc_count*3+1);
ctx->cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
//if (stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
ctx->cc_data_count[seq_index] = 0;
memcpy(ctx->cc_data_pkts[seq_index] + ctx->cc_data_count[seq_index] * 3, cc_data, cc_count * 3 + 1);
}
cc_data_count[seq_index] += cc_count;
ctx->cc_data_count[seq_index] += cc_count;
}
// DEBUG STUFF
/*
printf("\nCC blocks, channel 0:\n");
for ( int i=0; i < cc_count*3; i+=3)
{
printf("%s", debug_608toASC( cc_data+i, 0) );
}
printf("\n");
*/
// DEBUG STUFF
/*
printf("\nCC blocks, channel 0:\n");
for ( int i=0; i < cc_count*3; i+=3)
{
printf("%s", debug_608toASC( cc_data+i, 0) );
}
printf("\n");
*/
}
// Set a new anchor frame that new B-frames refer to.
void anchor_hdcc(int seq)
void anchor_hdcc(struct lib_cc_decode *ctx, int seq)
{
// Re-init the index
anchor_seq_number = seq;
// Re-init the index
ctx->anchor_seq_number = seq;
}
// Sort/flash caption block buffer
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
void process_hdcc (struct lib_cc_decode *ctx, struct cc_subtitle *sub)
{
// Remember the current value
LLONG store_fts_now = fts_now;
struct lib_cc_decode *dec_ctx;
LLONG store_fts_now = ctx->timing->fts_now;
int reset_cb = -1;
dbg_print(CCX_DMT_VERBOSE, "Flush HD caption blocks\n");
dec_ctx = ctx->dec_ctx;
for (int seq=0; seq<SORTBUF; seq++)
{
// We rely on this.
if (ccx_bufferdatatype == CCX_H264)
reset_cb = 1;
if (ctx->in_bufferdatatype == CCX_H264)
reset_cb = 1;
// If fts_now is unchanged we rely on cc block counting,
// otherwise reset counters as they get changed by do_cb()
@@ -114,9 +105,9 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
// updated, like it used do happen for elementary streams.
// Since use_gop_as_pts this is not needed anymore, but left
// here for posterity.
if (reset_cb < 0 && cc_fts[seq] && seq<SORTBUF-1 && cc_fts[seq+1])
if (reset_cb < 0 && ctx->cc_fts[seq] && seq<SORTBUF-1 && ctx->cc_fts[seq+1])
{
if (cc_fts[seq] != cc_fts[seq+1])
if (ctx->cc_fts[seq] != ctx->cc_fts[seq+1])
reset_cb = 1;
else
reset_cb = 0;
@@ -129,10 +120,10 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
}
// Skip sequence numbers without data
if (cc_data_count[seq] == 0)
if (ctx->cc_data_count[seq] == 0)
continue;
if (cc_data_pkts[seq][cc_data_count[seq]*3]!=0xFF)
if (ctx->cc_data_pkts[seq][ctx->cc_data_count[seq]*3]!=0xFF)
{
// This is not optional. Something is wrong.
dbg_print(CCX_DMT_VERBOSE, "Missing 0xFF marker at end\n");
@@ -141,14 +132,14 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
}
// Re-create original time
fts_now = cc_fts[seq];
process_cc_data( dec_ctx, cc_data_pkts[seq], cc_data_count[seq], sub);
ctx->timing->fts_now = ctx->cc_fts[seq];
process_cc_data( ctx, ctx->cc_data_pkts[seq], ctx->cc_data_count[seq], sub);
}
// Restore the value
fts_now = store_fts_now;
ctx->timing->fts_now = store_fts_now;
// Now that we are done, clean up.
init_hdcc();
init_hdcc(ctx);
}

View File

@@ -12,127 +12,123 @@
static int initialized = 0;
void
spupng_init_font()
void spupng_init_font()
{
uint8_t *t, *p;
int i, j;
uint8_t *t, *p;
int i, j;
/* de-interleave font image (puts all chars in row 0) */
if (!(t = (uint8_t*)malloc(ccfont2_width * ccfont2_height / 8)))
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
/* de-interleave font image (puts all chars in row 0) */
if (!(t = (uint8_t*)malloc(ccfont2_width * ccfont2_height / 8)))
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
for (p = t, i = 0; i < CCH; i++)
for (j = 0; j < ccfont2_height; p += ccfont2_width / 8, j += CCH)
memcpy(p, ccfont2_bits + (j + i) * ccfont2_width / 8,
ccfont2_width / 8);
for (p = t, i = 0; i < CCH; i++)
for (j = 0; j < ccfont2_height; p += ccfont2_width / 8, j += CCH)
memcpy(p, ccfont2_bits + (j + i) * ccfont2_width / 8,
ccfont2_width / 8);
memcpy(ccfont2_bits, t, ccfont2_width * ccfont2_height / 8);
free(t);
memcpy(ccfont2_bits, t, ccfont2_width * ccfont2_height / 8);
free(t);
}
struct spupng_t *spunpg_init(struct ccx_s_write *out)
{
struct spupng_t *sp = (struct spupng_t *) malloc(sizeof(struct spupng_t));
if (NULL == sp)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
struct spupng_t *sp = (struct spupng_t *) malloc(sizeof(struct spupng_t));
if (NULL == sp)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
if (!initialized)
{
initialized = 1;
spupng_init_font();
}
if (!initialized)
{
initialized = 1;
spupng_init_font();
}
if ((sp->fpxml = fdopen(out->fh, "w")) == NULL)
{
{
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
out->filename, strerror(errno));
}
sp->dirname = (char *) malloc(
sizeof(char) * (strlen(out->filename) + 3));
if (NULL == sp->dirname)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
out->filename, strerror(errno));
}
sp->dirname = (char *) malloc(
sizeof(char) * (strlen(out->filename) + 3));
if (NULL == sp->dirname)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
strcpy(sp->dirname, out->filename);
char* p = strrchr(sp->dirname, '.');
if (NULL == p)
p = sp->dirname + strlen(sp->dirname);
*p = '\0';
strcat(sp->dirname, ".d");
if (0 != mkdir(sp->dirname, 0777))
{
if (errno != EEXIST)
{
char* p = strrchr(sp->dirname, '.');
if (NULL == p)
p = sp->dirname + strlen(sp->dirname);
*p = '\0';
strcat(sp->dirname, ".d");
if (0 != mkdir(sp->dirname, 0777))
{
if (errno != EEXIST)
{
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot create %s: %s\n",
sp->dirname, strerror(errno));
}
// If dirname isn't a directory or if we don't have write permission,
// the first attempt to create a .png file will fail and we'll XXxit.
}
sp->dirname, strerror(errno));
}
// If dirname isn't a directory or if we don't have write permission,
// the first attempt to create a .png file will fail and we'll XXxit.
}
// enough to append /subNNNN.png
sp->pngfile = (char *) malloc(sizeof(char) * (strlen(sp->dirname) + 13));
if (NULL == sp->pngfile)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "Memory allocation failed");
sp->fileIndex = 0;
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex);
// enough to append /subNNNN.png
sp->pngfile = (char *) malloc(sizeof(char) * (strlen(sp->dirname) + 13));
if (NULL == sp->pngfile)
ccx_common_logging.fatal_ftn(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.
// 15 rows by 32 columns, plus 2 columns for left & right padding
// So each .png image will be 16*34 wide and 26*15 high, or 544x390
// To center image in 720x480 DVD screen, offset image by 88 and 45
// Need to keep yOffset even to prevent flicker on interlaced displays
// Would need to do something different for PAL format and teletext.
sp->xOffset = 88;
sp->yOffset = 46;
// For NTSC closed captions and 720x480 DVD subtitle resolution:
// Each character is 16x26.
// 15 rows by 32 columns, plus 2 columns for left & right padding
// So each .png image will be 16*34 wide and 26*15 high, or 544x390
// To center image in 720x480 DVD screen, offset image by 88 and 45
// Need to keep yOffset even to prevent flicker on interlaced displays
// Would need to do something different for PAL format and teletext.
sp->xOffset = 88;
sp->yOffset = 46;
return sp;
return sp;
}
void
spunpg_free(struct spupng_t *sp)
void spunpg_free(struct spupng_t *sp)
{
free(sp->dirname);
free(sp->pngfile);
free(sp);
free(sp->dirname);
free(sp->pngfile);
free(sp);
}
void
spupng_write_header(struct spupng_t *sp,int multiple_files,char *first_input_file)
void spupng_write_header(struct spupng_t *sp,int multiple_files,char *first_input_file)
{
fprintf(sp->fpxml, "<subpictures>\n<stream>\n");
if (multiple_files)
fprintf(sp->fpxml, "<!-- %s -->\n", first_input_file);
fprintf(sp->fpxml, "<subpictures>\n<stream>\n");
if (multiple_files)
fprintf(sp->fpxml, "<!-- %s -->\n", first_input_file);
}
void
spupng_write_footer(struct spupng_t *sp)
void spupng_write_footer(struct spupng_t *sp)
{
fprintf(sp->fpxml, "</stream>\n</subpictures>\n");
fflush(sp->fpxml);
fclose(sp->fpxml);
fprintf(sp->fpxml, "</stream>\n</subpictures>\n");
fflush(sp->fpxml);
fclose(sp->fpxml);
}
void write_spumux_header(struct ccx_s_write *out)
void write_spumux_header(struct encoder_ctx *ctx, struct ccx_s_write *out)
{
if (0 == out->spupng_data)
out->spupng_data = spunpg_init(out);
if (0 == out->spupng_data)
out->spupng_data = spunpg_init(out);
spupng_write_header((struct spupng_t*)out->spupng_data,out->multiple_files,out->first_input_file);
spupng_write_header((struct spupng_t*)out->spupng_data, ctx->multiple_files, ctx->first_input_file);
}
void write_spumux_footer(struct ccx_s_write *out)
{
if (0 != out->spupng_data)
{
struct spupng_t *sp = (struct spupng_t *) out->spupng_data;
if (0 != out->spupng_data)
{
struct spupng_t *sp = (struct spupng_t *) out->spupng_data;
spupng_write_footer(sp);
spunpg_free(sp);
spupng_write_footer(sp);
spunpg_free(sp);
out->spupng_data = 0;
out->fh = -1;
}
out->spupng_data = 0;
out->fh = -1;
}
}
/**
@@ -171,35 +167,37 @@ void write_spumux_footer(struct ccx_s_write *out)
* @return
* Glyph number.
*/
static unsigned int
unicode_ccfont2(unsigned int c, int italic)
static unsigned int unicode_ccfont2(unsigned int c, int italic)
{
static const unsigned short specials[] = {
0x00E1, 0x00E9,
0x00ED, 0x00F3, 0x00FA, 0x00E7, 0x00F7, 0x00D1, 0x00F1, 0x25A0,
0x00AE, 0x00B0, 0x00BD, 0x00BF, 0x2122, 0x00A2, 0x00A3, 0x266A,
0x00E0, 0x0020, 0x00E8, 0x00E2, 0x00EA, 0x00EE, 0x00F4, 0x00FB };
unsigned int i;
static const unsigned short specials[] = {
0x00E1, 0x00E9,
0x00ED, 0x00F3, 0x00FA, 0x00E7, 0x00F7, 0x00D1, 0x00F1, 0x25A0,
0x00AE, 0x00B0, 0x00BD, 0x00BF, 0x2122, 0x00A2, 0x00A3, 0x266A,
0x00E0, 0x0020, 0x00E8, 0x00E2, 0x00EA, 0x00EE, 0x00F4, 0x00FB };
unsigned int i;
if (c < 0x0020)
c = 15; /* invalid */
else if (c < 0x0080)
/*c = c */;
else {
for (i = 0; i < sizeof(specials) / sizeof(specials[0]); i++)
if (specials[i] == c) {
c = i + 6;
goto slant;
}
c = 15; /* invalid */
}
if (c < 0x0020)
c = 15; /* invalid */
else if (c < 0x0080)
/*c = c */;
else
{
for (i = 0; i < sizeof(specials) / sizeof(specials[0]); i++)
{
if (specials[i] == c)
{
c = i + 6;
goto slant;
}
}
c = 15; /* invalid */
}
slant:
if (italic)
c += 4 * 32;
if (italic)
c += 4 * 32;
return c;
return c;
}
/**
@@ -251,40 +249,41 @@ draw_blank(int canvas_type, uint8_t *canvas, unsigned int rowstride,
* Draw one character (function template - define a static version with
* constant @a canvas_type, @a font, @a cpl, @a cw, @a ch).
*/
static void
draw_char(int canvas_type, uint8_t *canvas, int rowstride,
static void draw_char(int canvas_type, uint8_t *canvas, int rowstride,
uint8_t *pen, uint8_t *font, int cpl, int cw, int ch,
int glyph, unsigned int underline)
{
uint8_t *src;
int shift, x, y;
uint8_t *src;
int shift, x, y;
assert(cw >= 8 && cw <= 16);
assert(ch >= 1 && ch <= 31);
assert(cw >= 8 && cw <= 16);
assert(ch >= 1 && ch <= 31);
x = glyph * cw;
shift = x & 7;
src = font + (x >> 3);
x = glyph * cw;
shift = x & 7;
src = font + (x >> 3);
for (y = 0; y < ch; underline >>= 1, y++) {
int bits = ~0;
for (y = 0; y < ch; underline >>= 1, y++)
{
int bits = ~0;
if (!(underline & 1)) {
if (!(underline & 1))
{
#ifdef __i386__
bits = (*((uint16_t *) src) >> shift);
bits = (*((uint16_t *) src) >> shift);
#else
/* unaligned/little endian */
bits = ((src[1] * 256 + src[0]) >> shift);
/* unaligned/little endian */
bits = ((src[1] * 256 + src[0]) >> shift);
#endif
}
}
for (x = 0; x < cw; bits >>= 1, x++)
poke(canvas, x, peek(pen, bits & 1));
for (x = 0; x < cw; bits >>= 1, x++)
poke(canvas, x, peek(pen, bits & 1));
canvas += rowstride;
canvas += rowstride;
src += cpl * cw / 8;
}
src += cpl * cw / 8;
}
}
/*
@@ -293,10 +292,10 @@ draw_char(int canvas_type, uint8_t *canvas, int rowstride,
void draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
int unicode, int italic, int underline)
{
draw_char(sizeof(*canvas), canvas, rowstride,
pen, (uint8_t *) ccfont2_bits, CCPL, CCW, CCH,
unicode_ccfont2(unicode, italic),
underline * (3 << 24) /* cell row 24, 25 */);
draw_char(sizeof(*canvas), canvas, rowstride,
pen, (uint8_t *) ccfont2_bits, CCPL, CCW, CCH,
unicode_ccfont2(unicode, italic),
underline * (3 << 24) /* cell row 24, 25 */);
}
void write_sputag(struct spupng_t *sp,LLONG ms_start,LLONG ms_end)
@@ -319,8 +318,8 @@ void write_spucomment(struct spupng_t *sp,const char *str)
char* get_spupng_filename(void *ctx)
{
struct spupng_t *sp = (struct spupng_t *)ctx;
return sp->pngfile;
struct spupng_t *sp = (struct spupng_t *)ctx;
return sp->pngfile;
}
void inc_spupng_fileindex(void *ctx)
{
@@ -330,9 +329,9 @@ void inc_spupng_fileindex(void *ctx)
}
void set_spupng_offset(void *ctx,int x,int y)
{
struct spupng_t *sp = (struct spupng_t *)ctx;
sp->xOffset = x;
sp->yOffset = y;
struct spupng_t *sp = (struct spupng_t *)ctx;
sp->xOffset = x;
sp->yOffset = y;
}
int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
png_color *palette, png_byte *alpha, int nb_color)
@@ -554,7 +553,7 @@ int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *conte
/* TODO do rectangle wise, one color table should not be used for all rectangles */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
#if ENABLE_OCR
#ifdef ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
write_spucomment(sp, rect[0].ocr_text);

View File

@@ -4,6 +4,7 @@
#include "ccx_common_platform.h"
#include "ccx_encoders_structs.h"
#include "png.h"
#include "ccx_encoders_common.h"
// CC page dimensions
#define ROWS 15
@@ -14,16 +15,16 @@
struct spupng_t
{
FILE* fpxml;
FILE* fppng;
char* dirname;
char* pngfile;
int fileIndex;
int xOffset;
int yOffset;
FILE* fpxml;
FILE* fppng;
char* dirname;
char* pngfile;
int fileIndex;
int xOffset;
int yOffset;
};
void write_spumux_header(struct ccx_s_write *out);
void write_spumux_header(struct encoder_ctx *ctx, struct ccx_s_write *out);
void write_spumux_footer(struct ccx_s_write *out);
void draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
int unicode, int italic, int underline);

View File

@@ -5,86 +5,128 @@
#else
#include <unistd.h>
#endif
#include "activity.h"
#include "utility.h"
#include "ccx_common_timing.h"
#include "file_buffer.h"
void detect_stream_type (struct lib_ccx_ctx *ctx)
void detect_stream_type (struct ccx_demuxer *ctx)
{
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
ctx->startbytes_avail = (int) buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
if( ctx->startbytes_avail == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
if( ctx->startbytes_avail == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
if (ctx->startbytes_avail>=4)
{
// Check for ASF magic bytes
if (ctx->startbytes[0]==0x30 &&
ctx->startbytes[1]==0x26 &&
ctx->startbytes[2]==0xb2 &&
ctx->startbytes[3]==0x75)
ctx->stream_mode=CCX_SM_ASF;
}
if (ctx->startbytes_avail>=4)
{
// Check for ASF magic bytes
if (ctx->startbytes[0]==0x30 &&
ctx->startbytes[1]==0x26 &&
ctx->startbytes[2]==0xb2 &&
ctx->startbytes[3]==0x75)
ctx->stream_mode=CCX_SM_ASF;
}
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 4)
{
if(ctx->startbytes[0]==0xb7 &&
ctx->startbytes[1]==0xd8 &&
ctx->startbytes[2]==0x00 &&
ctx->startbytes[3]==0x20)
ctx->stream_mode = CCX_SM_WTV;
}
{
if(ctx->startbytes[0]==0xb7 &&
ctx->startbytes[1]==0xd8 &&
ctx->startbytes[2]==0x00 &&
ctx->startbytes[3]==0x20)
ctx->stream_mode = CCX_SM_WTV;
}
#ifdef WTV_DEBUG
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=6)
{
// Check for hexadecimal dump generated by wtvccdump
// ; CCHD
if (ctx->startbytes[0]==';' &&
ctx->startbytes[1]==' ' &&
ctx->startbytes[2]=='C' &&
ctx->startbytes[3]=='C' &&
ctx->startbytes[4]=='H' &&
ctx->startbytes[5]=='D')
ctx->stream_mode= CCX_SM_HEX_DUMP;
if (ctx->startbytes[0]==';' &&
ctx->startbytes[1]==' ' &&
ctx->startbytes[2]=='C' &&
ctx->startbytes[3]=='C' &&
ctx->startbytes[4]=='H' &&
ctx->startbytes[5]=='D')
ctx->stream_mode= CCX_SM_HEX_DUMP;
}
#endif
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=11)
{
// Check for CCExtractor magic bytes
if (ctx->startbytes[0]==0xCC &&
ctx->startbytes[1]==0xCC &&
ctx->startbytes[2]==0xED &&
ctx->startbytes[8]==0 &&
ctx->startbytes[9]==0 &&
ctx->startbytes[10]==0)
ctx->stream_mode=CCX_SM_RCWT;
}
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
{
if (ctx->startbytes_avail > 188*8) // Otherwise, assume no TS
{
// First check for TS
for (unsigned i=0; i<188;i++)
{
if (ctx->startbytes[i]==0x47 && ctx->startbytes[i+188]==0x47 &&
ctx->startbytes[i+188*2]==0x47 && ctx->startbytes[i+188*3]==0x47 &&
ctx->startbytes[i+188*4]==0x47 && ctx->startbytes[i+188*5]==0x47 &&
ctx->startbytes[i+188*6]==0x47 && ctx->startbytes[i+188*7]==0x47
)
{
// Eight sync bytes, that's good enough
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_TRANSPORT;
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=11)
{
// Check for CCExtractor magic bytes
if (ctx->startbytes[0]==0xCC &&
ctx->startbytes[1]==0xCC &&
ctx->startbytes[2]==0xED &&
ctx->startbytes[8]==0 &&
ctx->startbytes[9]==0 &&
ctx->startbytes[10]==0)
ctx->stream_mode=CCX_SM_RCWT;
}
if ((ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
&& ctx->startbytes_avail >= 4) // Still not found
{
long idx = 0, nextBoxLocation = 0, lastBoxLocation = 0;
int boxScore = 0;
// Scan the buffer for valid succeeding MP4 boxes.
while (idx < ctx->startbytes_avail - 7){
lastBoxLocation = idx;
// Check if we have a valid box
if (isValidMP4Box(ctx->startbytes, idx, &nextBoxLocation, &boxScore))
{
idx = nextBoxLocation; // If the box is valid, a new box should be found on the next location... Not somewhere in between.
if (boxScore > 7)
{
break;
}
continue;
}
else
{
// Not a valid box, reset score. We need a couple of successive boxes to identify a MP4 file.
boxScore = 0;
idx++;
}
}
if (boxScore > 1)
{
// We had at least one box (or multiple) at the end to "claim" this is MP4. A single valid box at the end is doubtful...
ctx->stream_mode = CCX_SM_MP4;
}
}
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
{
if (ctx->startbytes_avail > 188*8) // Otherwise, assume no TS
{
// First check for TS
for (unsigned i=0; i<188;i++)
{
if (ctx->startbytes[i]==0x47 && ctx->startbytes[i+188]==0x47 &&
ctx->startbytes[i+188*2]==0x47 && ctx->startbytes[i+188*3]==0x47 &&
ctx->startbytes[i+188*4]==0x47 && ctx->startbytes[i+188*5]==0x47 &&
ctx->startbytes[i+188*6]==0x47 && ctx->startbytes[i+188*7]==0x47
)
{
// Eight sync bytes, that's good enough
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_TRANSPORT;
ctx->m2ts = 0;
break;
}
}
break;
}
}
if (ctx->stream_mode == CCX_SM_TRANSPORT)
{
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as TS\n");
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return;
}
// Check for M2TS
for (unsigned i = 0; i<192; i++)
{
if (ctx->startbytes[i+4] == 0x47 && ctx->startbytes[i + 4 + 192] == 0x47 &&
ctx->startbytes[i + 192 * 2+4] == 0x47 && ctx->startbytes[i + 192 * 3+4] == 0x47 &&
ctx->startbytes[i + 192 * 4+4] == 0x47 && ctx->startbytes[i + 192 * 5+4] == 0x47 &&
ctx->startbytes[i + 192 * 6+4] == 0x47 && ctx->startbytes[i + 192 * 7+4] == 0x47
)
ctx->startbytes[i + 192 * 2+4] == 0x47 && ctx->startbytes[i + 192 * 3+4] == 0x47 &&
ctx->startbytes[i + 192 * 4+4] == 0x47 && ctx->startbytes[i + 192 * 5+4] == 0x47 &&
ctx->startbytes[i + 192 * 6+4] == 0x47 && ctx->startbytes[i + 192 * 7+4] == 0x47
)
{
// Eight sync bytes, that's good enough
ctx->startbytes_pos = i;
@@ -93,138 +135,78 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
break;
}
}
// Now check for PS (Needs PACK header)
for (unsigned i=0;
i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
i++)
{
if (ctx->startbytes[i]==0x00 && ctx->startbytes[i+1]==0x00 &&
ctx->startbytes[i+2]==0x01 && ctx->startbytes[i+3]==0xBA)
{
// If we find a PACK header it is not an ES
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_PROGRAM;
break;
}
}
// TiVo is also a PS
if (ctx->startbytes[0]=='T' && ctx->startbytes[1]=='i' &&
ctx->startbytes[2]=='V' && ctx->startbytes[3]=='o')
{
// The TiVo header is longer, but the PS loop will find the beginning
ctx->startbytes_pos=187;
ctx->stream_mode=CCX_SM_PROGRAM;
strangeheader=1; // Avoid message about unrecognized header
}
}
else
{
ctx->startbytes_pos=0;
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
}
}
if ((ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
&& ctx->startbytes_avail>=4) // Still not found
{
// Try for MP4 by looking for box signatures - this should happen very
// early in the file according to specs
for (int i=0;i<ctx->startbytes_avail-3;i++)
{
// Look for the a box of type 'file'
if (
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='t' &&
ctx->startbytes[i+2]=='y' && ctx->startbytes[i+3]=='p')
||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='o' &&
ctx->startbytes[i+2]=='o' && ctx->startbytes[i+3]=='v')
||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='d' &&
ctx->startbytes[i+2]=='a' && ctx->startbytes[i+3]=='t')
||
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='e' &&
ctx->startbytes[i+2]=='e' && ctx->startbytes[i+3]=='e')
||
(ctx->startbytes[i]=='s' && ctx->startbytes[i+1]=='k' &&
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='p')
||
(ctx->startbytes[i]=='u' && ctx->startbytes[i+1]=='d' &&
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='e' &&
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
||
(ctx->startbytes[i]=='v' && ctx->startbytes[i+1]=='o' &&
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='d')
)
if (ctx->stream_mode == CCX_SM_TRANSPORT)
{
ctx->stream_mode=CCX_SM_MP4;
break;
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as M2TS\n");
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return;
}
// Now check for PS (Needs PACK header)
for (unsigned i=0;
i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
i++)
{
if (ctx->startbytes[i]==0x00 && ctx->startbytes[i+1]==0x00 &&
ctx->startbytes[i+2]==0x01 && ctx->startbytes[i+3]==0xBA)
{
// If we find a PACK header it is not an ES
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_PROGRAM;
break;
}
}
if (ctx->stream_mode == CCX_SM_PROGRAM)
{
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as PS\n");
}
// TiVo is also a PS
if (ctx->startbytes[0]=='T' && ctx->startbytes[1]=='i' &&
ctx->startbytes[2]=='V' && ctx->startbytes[3]=='o')
{
// The TiVo header is longer, but the PS loop will find the beginning
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as Tivo PS\n");
ctx->startbytes_pos = 187;
ctx->stream_mode = CCX_SM_PROGRAM;
ctx->strangeheader = 1; // Avoid message about unrecognized header
}
}
else
{
ctx->startbytes_pos=0;
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
}
}
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
return_to_buffer (ctx->startbytes, ctx->startbytes_avail);
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
return_to_buffer (ctx, ctx->startbytes, ctx->startbytes_avail);
}
int detect_myth( struct lib_ccx_ctx *ctx )
int detect_myth( struct ccx_demuxer *ctx )
{
int vbi_blocks=0;
// VBI data? if yes, use myth loop
// STARTBTYTESLENGTH is 1MB, if the file is shorter we will never detect
// it as a mythTV file
if (ctx->startbytes_avail==STARTBYTESLENGTH)
{
unsigned char uc[3];
memcpy (uc,ctx->startbytes,3);
for (int i=3;i<ctx->startbytes_avail;i++)
{
if (((uc[0]=='t') && (uc[1]=='v') && (uc[2] == '0')) ||
((uc[0]=='T') && (uc[1]=='V') && (uc[2] == '0')))
vbi_blocks++;
uc[0]=uc[1];
uc[1]=uc[2];
uc[2]=ctx->startbytes[i];
}
}
if (vbi_blocks>10) // Too much coincidence
return 1;
int vbi_blocks=0;
// VBI data? if yes, use myth loop
// STARTBTYTESLENGTH is 1MB, if the file is shorter we will never detect
// it as a mythTV file
if (ctx->startbytes_avail==STARTBYTESLENGTH)
{
unsigned char uc[3];
memcpy (uc,ctx->startbytes,3);
for (int i=3;i<ctx->startbytes_avail;i++)
{
if (((uc[0]=='t') && (uc[1]=='v') && (uc[2] == '0')) ||
((uc[0]=='T') && (uc[1]=='V') && (uc[2] == '0')))
vbi_blocks++;
uc[0]=uc[1];
uc[1]=uc[2];
uc[2]=ctx->startbytes[i];
}
}
if (vbi_blocks>10) // Too much coincidence
return 1;
return 0;
}
int read_pts_pes(unsigned char*header, int len)
{
/* unsigned int peslen = 0; */
LLONG bits_9;
unsigned int bits_10;
unsigned int bits_11;
unsigned int bits_12;
unsigned int bits_13;
//function used only to set start time
if(pts_set)
return -1;
//it might not be pes packet
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
return -1;
/* peslen = header[4] << 8 | header[5]; */
if (header[7] & 0x80)
{
bits_9 = ((LLONG) header[9] & 0x0E) << 29; // PTS 32..30 - Must be LLONG to prevent overflow
bits_10 = header[10] << 22; // PTS 29..22
bits_11 = (header[11] & 0xFE) << 14; // PTS 21..15
bits_12 = header[12] << 7; // PTS 14-7
bits_13 = header[13] >> 1; // PTS 6-0
}
else
return -1;
current_pts = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
pts_set = 1;
return 0;
return 0;
}
/* Read and evaluate the current video PES header. The function returns
@@ -234,119 +216,144 @@ int read_pts_pes(unsigned char*header, int len)
* 0 .. Read from file into nextheader
* >0 .. Use data in nextheader with the length of sbuflen
*/
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen)
int read_video_pes_header (struct ccx_demuxer *ctx, struct demuxer_data *data, unsigned char *nextheader, int *headerlength, int sbuflen)
{
// Read the next video PES
// ((nextheader[3]&0xf0)==0xe0)
unsigned peslen=nextheader[4]<<8 | nextheader[5];
unsigned payloadlength = 0; // Length of packet data bytes
// Read the next video PES
// ((nextheader[3]&0xf0)==0xe0)
long long result;
unsigned peslen=nextheader[4]<<8 | nextheader[5];
unsigned payloadlength = 0; // Length of packet data bytes
static LLONG current_pts_33=0; // Last PTS from the header, without rollover bits
if ( !sbuflen )
{
// Extension present, get it
buffered_read (ctx, nextheader+6,3);
ctx->past=ctx->past+result;
if (result!=3) {
// Consider this the end of the show.
return -1;
}
}
else
{
// We need at least 9 bytes to continue
if( sbuflen < 9 )
return -1;
}
*headerlength = 6+3;
if ( !sbuflen )
{
// Extension present, get it
result = buffered_read (ctx, nextheader+6,3);
ctx->past=ctx->past+result;
if (result!=3) {
// Consider this the end of the show.
return -1;
}
}
else
{
if (data->bufferdatatype == CCX_DVB_SUBTITLE
&& peslen == 1 && nextheader[6] == 0xFF)
{
*headerlength = sbuflen;
return 0;
}
if (sbuflen < 9) // We need at least 9 bytes to continue
{
return -1;
}
}
*headerlength = 6+3;
unsigned hskip=0;
unsigned hskip=0;
// Assume header[8] is right, but double check
if ( !sbuflen )
{
if (nextheader[8] > 0) {
buffered_read (ctx, nextheader+9,nextheader[8]);
ctx->past=ctx->past+result;
if (result!=nextheader[8]) {
return -1;
}
}
}
else
{
// See if the buffer is big enough
if( sbuflen < *headerlength + (int)nextheader[8] )
return -1;
}
*headerlength += (int) nextheader[8];
int falsepes = 0;
/* int pesext = 0; */
// Assume header[8] is right, but double check
if ( !sbuflen )
{
if (nextheader[8] > 0)
{
result = buffered_read (ctx, nextheader+9,nextheader[8]);
ctx->past = ctx->past+result;
if (result!=nextheader[8])
{
return -1;
}
}
}
else
{
// See if the buffer is big enough
if( sbuflen < *headerlength + (int)nextheader[8] )
return -1;
}
*headerlength += (int) nextheader[8];
int falsepes = 0;
/* int pesext = 0; */
// Avoid false positives, check --- not really needed
if ( (nextheader[7]&0xC0) == 0x80 ) {
// PTS only
hskip += 5;
if( (nextheader[9]&0xF1) != 0x21 || (nextheader[11]&0x01) != 0x01
|| (nextheader[13]&0x01) != 0x01 ) {
falsepes = 1;
mprint("False PTS\n");
}
} else if ( (nextheader[7]&0xC0) == 0xC0 ) {
// PTS and DTS
hskip += 10;
if( (nextheader[9]&0xF1) != 0x31 || (nextheader[11]&0x01) != 0x01
|| (nextheader[13]&0x01) != 0x01
|| (nextheader[14]&0xF1) != 0x11 || (nextheader[16]&0x01) != 0x01
|| (nextheader[18]&0x01) != 0x01 ) {
falsepes = 1;
mprint("False PTS/DTS\n");
}
} else if ( (nextheader[7]&0xC0) == 0x40 ) {
// Forbidden
falsepes = 1;
mprint("False PTS/DTS flag\n");
}
if ( !falsepes && nextheader[7]&0x20 ) { // ESCR
if ((nextheader[9+hskip]&0xC4) != 0x04 || !(nextheader[11+hskip]&0x04)
|| !(nextheader[13+hskip]&0x04) || !(nextheader[14+hskip]&0x01) ) {
falsepes = 1;
mprint("False ESCR\n");
}
hskip += 6;
}
if ( !falsepes && nextheader[7]&0x10 ) { // ES
if ( !(nextheader[9+hskip]&0x80) || !(nextheader[11+hskip]&0x01) ) {
mprint("False ES\n");
falsepes = 1;
}
hskip += 3;
}
if ( !falsepes && nextheader[7]&0x04) { // add copy info
if ( !(nextheader[9+hskip]&0x80) ) {
mprint("False add copy info\n");
falsepes = 1;
}
hskip += 1;
}
if ( !falsepes && nextheader[7]&0x02) { // PES CRC
hskip += 2;
}
if ( !falsepes && nextheader[7]&0x01) { // PES extension
if ( (nextheader[9+hskip]&0x0E)!=0x0E ) {
mprint("False PES ext\n");
falsepes = 1;
}
hskip += 1;
/* pesext = 1; */
}
// Avoid false positives, check --- not really needed
if ( (nextheader[7]&0xC0) == 0x80 )
{
// PTS only
hskip += 5;
if( (nextheader[9]&0xF1) != 0x21 || (nextheader[11]&0x01) != 0x01
|| (nextheader[13]&0x01) != 0x01 )
{
falsepes = 1;
mprint("False PTS\n");
}
}
else if ( (nextheader[7]&0xC0) == 0xC0 )
{
// PTS and DTS
hskip += 10;
if( (nextheader[9]&0xF1) != 0x31 || (nextheader[11]&0x01) != 0x01
|| (nextheader[13]&0x01) != 0x01
|| (nextheader[14]&0xF1) != 0x11 || (nextheader[16]&0x01) != 0x01
|| (nextheader[18]&0x01) != 0x01 ) {
falsepes = 1;
mprint("False PTS/DTS\n");
}
}
else if ( (nextheader[7]&0xC0) == 0x40 )
{
// Forbidden
falsepes = 1;
mprint("False PTS/DTS flag\n");
}
if ( !falsepes && nextheader[7]&0x20 )
{ // ESCR
if ((nextheader[9+hskip]&0xC4) != 0x04 || !(nextheader[11+hskip]&0x04)
|| !(nextheader[13+hskip]&0x04) || !(nextheader[14+hskip]&0x01) )
{
falsepes = 1;
mprint("False ESCR\n");
}
hskip += 6;
}
if ( !falsepes && nextheader[7]&0x10 )
{ // ES
if ( !(nextheader[9+hskip]&0x80) || !(nextheader[11+hskip]&0x01) ) {
mprint("False ES\n");
falsepes = 1;
}
hskip += 3;
}
if ( !falsepes && nextheader[7]&0x04)
{ // add copy info
if ( !(nextheader[9+hskip]&0x80) ) {
mprint("False add copy info\n");
falsepes = 1;
}
hskip += 1;
}
if ( !falsepes && nextheader[7]&0x02)
{ // PES CRC
hskip += 2;
}
if ( !falsepes && nextheader[7]&0x01)
{ // PES extension
if ( (nextheader[9+hskip]&0x0E)!=0x0E )
{
mprint("False PES ext\n");
falsepes = 1;
}
hskip += 1;
/* pesext = 1; */
}
if ( !falsepes ) {
hskip = nextheader[8];
}
if ( !falsepes )
{
hskip = nextheader[8];
}
if ( !falsepes && nextheader[7]&0x80 ) {
// Read PTS from byte 9,10,11,12,13
if ( !falsepes && nextheader[7]&0x80 )
{
// Read PTS from byte 9,10,11,12,13
LLONG bits_9 = ((LLONG) nextheader[9] & 0x0E)<<29; // PTS 32..30 - Must be LLONG to prevent overflow
unsigned bits_10 = nextheader[10] << 22; // PTS 29..22
@@ -354,7 +361,7 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
unsigned bits_12 = nextheader[12] << 7; // PTS 14-7
unsigned bits_13 = nextheader[13] >> 1; // PTS 6-0
if (pts_set) // Otherwise can't check for rollovers yet
if (data->pts != CCX_NOPTS) // Otherwise can't check for rollovers yet
{
if (!bits_9 && ((current_pts_33>>30)&7)==7) // PTS about to rollover
rollover_bits++;
@@ -364,33 +371,94 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
current_pts_33 = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
current_pts = (LLONG) rollover_bits<<33 | current_pts_33;
data->pts = (LLONG) rollover_bits<<33 | current_pts_33;
if (pts_set==0)
pts_set=1;
/* The user data holding the captions seems to come between GOP and
* the first frame. The sync PTS (sync_pts) (set at picture 0)
* corresponds to the first frame of the current GOP. */
}
dbg_print(CCX_DMT_VERBOSE, "Set PTS: %s (%u)\n",
print_mstime((current_pts)/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (current_pts) );
/* The user data holding the captions seems to come between GOP and
* the first frame. The sync PTS (sync_pts) (set at picture 0)
* corresponds to the first frame of the current GOP. */
}
// This might happen in PES packets in TS stream. It seems that when the
// packet length is unkown it is set to 0.
if (peslen+6 >= hskip+9)
{
payloadlength = peslen - (hskip + 3); // for [6], [7] and [8]
}
// This might happen in PES packets in TS stream. It seems that when the
// packet length is unkown it is set to 0.
if (peslen+6 >= hskip+9)
{
payloadlength = peslen - (hskip + 3); // for [6], [7] and [8]
}
// Use a save default if this is not a real PES header
if (falsepes)
{
mprint("False PES header\n");
}
// Use a save default if this is not a real PES header
if (falsepes) {
mprint("False PES header\n");
}
dbg_print(CCX_DMT_VERBOSE, "PES header length: %d (%d verified) Data length: %d\n",
*headerlength, hskip+9, payloadlength);
dbg_print(CCX_DMT_VERBOSE, "PES header length: %d (%d verified) Data length: %d\n",
*headerlength, hskip+9, payloadlength);
return payloadlength;
return payloadlength;
}
/*
* Structure for a MP4 box type. Contains the name of the box type and the score we want to assign when a given box type is found.
*/
typedef struct ccx_stream_mp4_box
{
char boxType[5]; // Name of the box structure
int score; // The weight of how heavy a box structure should be counted in order to "recognize" an MP4 file.
} ccx_stream_mp4_box;
/* The box types below are taken from table 1 from ISO/IEC 14496-12_2012 (page 12 and further).
* An asterisk (*) marks a mandatory box for a regular file.
* Box types that are on the second level or deeper are omitted.
*/
ccx_stream_mp4_box ccx_stream_mp4_boxes[11] = {
{ "ftyp", 6 }, // File type and compatibility*
{ "pdin", 1 }, // Progressive download information
{ "moov", 5 }, // Container for all metadata*
{ "moof", 4 }, // Movie fragment
{ "mfra", 3 }, // Movie fragment random access
{ "mdat", 2 }, // Media data container
{ "free", 1 }, // Free space
{ "skip", 1 }, // Free space
{ "meta", 1 }, // Metadata
{ "wide", 1 }, // For boxes that are > 2^32 bytes (https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html)
{ "void", 1 } // Unknown where this is from/for, assume free space.
};
/*
* Checks if the buffer, beginning at the given position, contains a valid MP4 box (defined in the ccx_stream_mp4_boxes array).
* If it does contain one, it will set the nextBoxLocation to position + current box size (this should be the place in the buffer
* where the next box should be in case of an mp4) and increment the box score with the defined score for the found box.
*
* Returns 1 when a box is found, 0 when none is found.
*/
int isValidMP4Box(unsigned char *buffer, long position, long *nextBoxLocation, int *boxScore)
{
for (int idx = 0; idx < 11; idx++)
{
if (buffer[position + 4] == ccx_stream_mp4_boxes[idx].boxType[0] && buffer[position + 5] == ccx_stream_mp4_boxes[idx].boxType[1] &&
buffer[position + 6] == ccx_stream_mp4_boxes[idx].boxType[2] && buffer[position + 7] == ccx_stream_mp4_boxes[idx].boxType[3]){
mprint("Detected MP4 box with name: %s\n", ccx_stream_mp4_boxes[idx].boxType);
// Box name matches. Do crude validation of possible box size, and if valid, add points for "valid" box
long boxSize = buffer[position] << 24;
boxSize |= buffer[position + 1] << 16;
boxSize |= buffer[position + 2] << 8;
boxSize |= buffer[position + 3];
*boxScore += ccx_stream_mp4_boxes[idx].score;
if (boxSize == 0 || boxSize == 1)
{
// If 0, runs to end of file. If 1, next field contains int_64 containing size, which is definitely bigger than the cache. Both times we can skip further checks by setting
// nextBoxLocation to the max possible.
*nextBoxLocation = UINT32_MAX;
}
else
{
// Set nextBoxLocation to current position + boxSize, as that will be the location of the next box.
*nextBoxLocation = position + boxSize;
}
return 1;
}
}
return 0;
}

View File

@@ -7,247 +7,6 @@
//#include <inttypes.h>
typedef enum {
LATIN = 0,
CYRILLIC1,
CYRILLIC2,
CYRILLIC3,
GREEK,
ARABIC,
HEBREW
} g0_charsets_t;
// Note: All characters are encoded in UCS-2
// --- G0 ----------------------------------------------------------------------
// G0 charsets
uint16_t G0[5][96] = {
{ // Latin G0 Primary Set
0x0020, 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00ab, 0x00bd, 0x00bb, 0x005e, 0x0023,
0x002d, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00bc, 0x00a6, 0x00be, 0x00f7, 0x007f
},
{ // Cyrillic G0 Primary Set - Option 1 - Serbian/Croatian
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x044b, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x3200, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
0x041f, 0x040c, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040a, 0x0417, 0x040b, 0x0416, 0x0402, 0x0428, 0x040f,
0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0428, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
0x043f, 0x042c, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0423, 0x0429, 0x042a, 0x0437, 0x042b, 0x0436, 0x0422, 0x0448, 0x042f
},
{ // Cyrillic G0 Primary Set - Option 2 - Russian/Bulgarian
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x044b, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x042a, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042b,
0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c, 0x044a, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044b
},
{ // Cyrillic G0 Primary Set - Option 3 - Ukrainian
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x00ef, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x0049, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x00cf,
0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c, 0x0069, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x00ff
},
{ // Greek G0 Primary Set
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf
}
//{ // Arabic G0 Primary Set
//},
//{ // Hebrew G0 Primary Set
//}
};
// array positions where chars from G0_LATIN_NATIONAL_SUBSETS are injected into G0[LATIN]
const uint8_t G0_LATIN_NATIONAL_SUBSETS_POSITIONS[13] = {
0x03, 0x04, 0x20, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x5b, 0x5c, 0x5d, 0x5e
};
// ETS 300 706, chapter 15.2, table 32: Function of Default G0 and G2 Character Set Designation
// and National Option Selection bits in packets X/28/0 Format 1, X/28/4, M/29/0 and M/29/4
// Latin National Option Sub-sets
struct {
const char *language;
uint16_t characters[13];
} const G0_LATIN_NATIONAL_SUBSETS[14] = {
{ // 0
"English",
{ 0x00a3, 0x0024, 0x0040, 0x00ab, 0x00bd, 0x00bb, 0x005e, 0x0023, 0x002d, 0x00bc, 0x00a6, 0x00be, 0x00f7 }
},
{ // 1
"French",
{ 0x00e9, 0x00ef, 0x00e0, 0x00eb, 0x00ea, 0x00f9, 0x00ee, 0x0023, 0x00e8, 0x00e2, 0x00f4, 0x00fb, 0x00e7 }
},
{ // 2
"Swedish, Finnish, Hungarian",
{ 0x0023, 0x00a4, 0x00c9, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f, 0x00e9, 0x00e4, 0x00f6, 0x00e5, 0x00fc }
},
{ // 3
"Czech, Slovak",
{ 0x0023, 0x016f, 0x010d, 0x0165, 0x017e, 0x00fd, 0x00ed, 0x0159, 0x00e9, 0x00e1, 0x011b, 0x00fa, 0x0161 }
},
{ // 4
"German",
{ 0x0023, 0x0024, 0x00a7, 0x00c4, 0x00d6, 0x00dc, 0x005e, 0x005f, 0x00b0, 0x00e4, 0x00f6, 0x00fc, 0x00df }
},
{ // 5
"Portuguese, Spanish",
{ 0x00e7, 0x0024, 0x00a1, 0x00e1, 0x00e9, 0x00ed, 0x00f3, 0x00fa, 0x00bf, 0x00fc, 0x00f1, 0x00e8, 0x00e0 }
},
{ // 6
"Italian",
{ 0x00a3, 0x0024, 0x00e9, 0x00b0, 0x00e7, 0x00bb, 0x005e, 0x0023, 0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec }
},
{ // 7
"Rumanian",
{ 0x0023, 0x00a4, 0x0162, 0x00c2, 0x015e, 0x0102, 0x00ce, 0x0131, 0x0163, 0x00e2, 0x015f, 0x0103, 0x00ee }
},
{ // 8
"Polish",
{ 0x0023, 0x0144, 0x0105, 0x017b, 0x015a, 0x0141, 0x0107, 0x00f3, 0x0119, 0x017c, 0x015b, 0x0142, 0x017a }
},
{ // 9
"Turkish",
{ 0x0054, 0x011f, 0x0130, 0x015e, 0x00d6, 0x00c7, 0x00dc, 0x011e, 0x0131, 0x015f, 0x00f6, 0x00e7, 0x00fc }
},
{ // a
"Serbian, Croatian, Slovenian",
{ 0x0023, 0x00cb, 0x010c, 0x0106, 0x017d, 0x0110, 0x0160, 0x00eb, 0x010d, 0x0107, 0x017e, 0x0111, 0x0161 }
},
{ // b
"Estonian",
{ 0x0023, 0x00f5, 0x0160, 0x00c4, 0x00d6, 0x017e, 0x00dc, 0x00d5, 0x0161, 0x00e4, 0x00f6, 0x017e, 0x00fc }
},
{ // c
"Lettish, Lithuanian",
{ 0x0023, 0x0024, 0x0160, 0x0117, 0x0119, 0x017d, 0x010d, 0x016b, 0x0161, 0x0105, 0x0173, 0x017e, 0x012f }
}
};
// References to the G0_LATIN_NATIONAL_SUBSETS array
const uint8_t G0_LATIN_NATIONAL_SUBSETS_MAP[56] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x01, 0x02, 0x03, 0x04, 0xff, 0x06, 0xff,
0x00, 0x01, 0x02, 0x09, 0x04, 0x05, 0x06, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0x07,
0xff, 0xff, 0x0b, 0x03, 0x04, 0xff, 0x0c, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x09, 0xff, 0xff, 0xff, 0xff
};
// --- G2 ----------------------------------------------------------------------
const uint16_t G2[1][96] = {
{ // Latin G2 Supplementary Set
0x0020, 0x00a1, 0x00a2, 0x00a3, 0x0024, 0x00a5, 0x0023, 0x00a7, 0x00a4, 0x2018, 0x201c, 0x00ab, 0x2190, 0x2191, 0x2192, 0x2193,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00d7, 0x00b5, 0x00b6, 0x00b7, 0x00f7, 0x2019, 0x201d, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x0020, 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, 0x0000, 0x030a, 0x0327, 0x005f, 0x030b, 0x0328, 0x030c,
0x2015, 0x00b9, 0x00ae, 0x00a9, 0x2122, 0x266a, 0x20ac, 0x2030, 0x03B1, 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e,
0x03a9, 0x00c6, 0x0110, 0x00aa, 0x0126, 0x0000, 0x0132, 0x013f, 0x0141, 0x00d8, 0x0152, 0x00ba, 0x00de, 0x0166, 0x014a, 0x0149,
0x0138, 0x00e6, 0x0111, 0x00f0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00f8, 0x0153, 0x00df, 0x00fe, 0x0167, 0x014b, 0x0020
}
// { // Cyrillic G2 Supplementary Set
// },
// { // Greek G2 Supplementary Set
// },
// { // Arabic G2 Supplementary Set
// }
};
const uint16_t G2_ACCENTS[15][52] = {
// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
{ // grave
0x00c0, 0x0000, 0x0000, 0x0000, 0x00c8, 0x0000, 0x0000, 0x0000, 0x00cc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d2, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x00d9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e0, 0x0000, 0x0000, 0x0000, 0x00e8, 0x0000,
0x0000, 0x0000, 0x00ec, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f9, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // acute
0x00c1, 0x0000, 0x0106, 0x0000, 0x00c9, 0x0000, 0x0000, 0x0000, 0x00cd, 0x0000, 0x0000, 0x0139, 0x0000, 0x0143, 0x00d3, 0x0000,
0x0000, 0x0154, 0x015a, 0x0000, 0x00da, 0x0000, 0x0000, 0x0000, 0x00dd, 0x0179, 0x00e1, 0x0000, 0x0107, 0x0000, 0x00e9, 0x0000,
0x0123, 0x0000, 0x00ed, 0x0000, 0x0000, 0x013a, 0x0000, 0x0144, 0x00f3, 0x0000, 0x0000, 0x0155, 0x015b, 0x0000, 0x00fa, 0x0000,
0x0000, 0x0000, 0x00fd, 0x017a
},
{ // circumflex
0x00c2, 0x0000, 0x0108, 0x0000, 0x00ca, 0x0000, 0x011c, 0x0124, 0x00ce, 0x0134, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d4, 0x0000,
0x0000, 0x0000, 0x015c, 0x0000, 0x00db, 0x0000, 0x0174, 0x0000, 0x0176, 0x0000, 0x00e2, 0x0000, 0x0109, 0x0000, 0x00ea, 0x0000,
0x011d, 0x0125, 0x00ee, 0x0135, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f4, 0x0000, 0x0000, 0x0000, 0x015d, 0x0000, 0x00fb, 0x0000,
0x0175, 0x0000, 0x0177, 0x0000
},
{ // tilde
0x00c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0128, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d1, 0x00d5, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0168, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0129, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f1, 0x00f5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0169, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // macron
0x0100, 0x0000, 0x0000, 0x0000, 0x0112, 0x0000, 0x0000, 0x0000, 0x012a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014c, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x016a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0101, 0x0000, 0x0000, 0x0000, 0x0113, 0x0000,
0x0000, 0x0000, 0x012b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016b, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // breve
0x0102, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x011e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0103, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x011f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // dot
0x0000, 0x0000, 0x010a, 0x0000, 0x0116, 0x0000, 0x0120, 0x0000, 0x0130, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017b, 0x0000, 0x0000, 0x010b, 0x0000, 0x0117, 0x0000,
0x0121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x017c
},
{ // umlaut
0x00c4, 0x0000, 0x0000, 0x0000, 0x00cb, 0x0000, 0x0000, 0x0000, 0x00cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d6, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x00dc, 0x0000, 0x0000, 0x0000, 0x0178, 0x0000, 0x00e4, 0x0000, 0x0000, 0x0000, 0x00eb, 0x0000,
0x0000, 0x0000, 0x00ef, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00fc, 0x0000,
0x0000, 0x0000, 0x00ff, 0x0000
},
{ 0 },
{ // ring
0x00c5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x016e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016f, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // cedilla
0x0000, 0x0000, 0x00c7, 0x0000, 0x0000, 0x0000, 0x0122, 0x0000, 0x0000, 0x0000, 0x0136, 0x013b, 0x0000, 0x0145, 0x0000, 0x0000,
0x0000, 0x0156, 0x015e, 0x0162, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e7, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0137, 0x013c, 0x0000, 0x0146, 0x0000, 0x0000, 0x0000, 0x0157, 0x015f, 0x0163, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ 0 },
{ // double acute
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0150, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0170, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0171, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // ogonek
0x0104, 0x0000, 0x0000, 0x0000, 0x0118, 0x0000, 0x0000, 0x0000, 0x012e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0105, 0x0000, 0x0000, 0x0000, 0x0119, 0x0000,
0x0000, 0x0000, 0x012f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0173, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
},
{ // caron
0x0000, 0x0000, 0x010c, 0x010e, 0x011a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x013d, 0x0000, 0x0147, 0x0000, 0x0000,
0x0000, 0x0158, 0x0160, 0x0164, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017d, 0x0000, 0x0000, 0x010d, 0x010f, 0x011b, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x013e, 0x0000, 0x0148, 0x0000, 0x0000, 0x0000, 0x0159, 0x0161, 0x0165, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x017e
}
};
int tlt_print_seen_pages(struct lib_cc_decode *dec_ctx);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More