Compare commits

..

364 Commits
v0.77 ... 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
94 changed files with 15206 additions and 8486 deletions

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

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.77
ccextractor, 0.78
-----------------
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
Maintainer: cfsmp3
@@ -20,7 +20,7 @@ Google Summer of Code 2014 students
Google Summer of Code 2015 students
- Willem van iseghem
- Ruslan KuchumoV
- Ruslan Kuchumov
- Anshul Maheshwari
- Nurendra Choudhary
- Oleg Kiselev

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)

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

@@ -24,15 +24,13 @@ void sigint_handler()
struct ccx_s_options ccx_options;
int main(int argc, char *argv[])
{
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);
@@ -53,39 +51,15 @@ int main(int argc, char *argv[])
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");
dec_ctx = ctx->dec_ctx;
// Prepare write structures
init_write(&ctx->wbout1,ccx_options.wbout1.filename);
init_write(&ctx->wbout2,ccx_options.wbout2.filename);
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);
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)
{
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];
}
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;
}
params_dump(ctx);
// default teletext page
@@ -94,161 +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);
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);
if (detect_input_file_overwrite(ctx, ctx->wbout1.filename)) {
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
"Output filename is same as one of input filenames. Check output parameters.\n");
}
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");
}
}
if (init_encoder(enc_ctx, &ctx->wbout1, &ccx_options))
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);
}
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);
if (detect_input_file_overwrite(ctx, ctx->wbout1.filename)) {
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
"Output filename is same as one of input filenames. Check output parameters.\n");
}
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);
}
}
if (init_encoder(enc_ctx, &ctx->wbout1, &ccx_options))
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);
if (detect_input_file_overwrite(ctx, ctx->wbout2.filename)) {
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
"Output filename is same as one of input filenames. Check output parameters.\n");
}
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)
dec_ctx->writedata (BROADCAST_HEADER,sizeof (BROADCAST_HEADER), dec_ctx->context_cc608_field_2, NULL);
}
if( init_encoder(enc_ctx+1, &ctx->wbout2, &ccx_options) )
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)
@@ -258,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);
@@ -298,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
@@ -328,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;
@@ -342,105 +137,30 @@ 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)
{
struct ccx_s_mp4Cfg mp4_cfg = {ccx_options.mp4vidtrack};
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something
ccx_options.use_gop_as_pts = 1; // Force GOP timing for ES
@@ -452,25 +172,25 @@ 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:
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, &mp4_cfg, ctx->inputfile[0],&enc_ctx);
processmp4 (ctx, &ctx->mp4_cfg, ctx->inputfile[0]);
if (ccx_options.print_file_reports)
print_file_report(ctx);
break;
@@ -485,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) ),
@@ -537,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));
@@ -577,81 +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, &dec_sub);
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
}
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;
@@ -660,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

@@ -8,9 +8,8 @@
#include "ccx_encoders_common.h"
#include "ccx_common_option.h"
#include "ccx_mp4.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 "activity.h"
#include "ccx_dtvcc.h"
static short bswap16(short v)
{
@@ -33,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; )
{
@@ -63,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);
@@ -73,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;
@@ -92,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;
@@ -120,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)
{
@@ -169,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)
@@ -280,11 +284,15 @@ unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int l
}
*/
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, 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);
@@ -344,7 +352,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
}
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
{
{
if (cc_track_count && !cfg->mp4vidtrack)
continue;
GF_AVCConfig *cnf = gf_isom_avc_config_get(f,i+1,1);
@@ -353,7 +361,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
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);
}
}
@@ -367,8 +375,6 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
}
}
if (type == GF_ISOM_MEDIA_CAPTIONS &&
(subtype == GF_ISOM_SUBTYPE_C608 || subtype == GF_ISOM_SUBTYPE_C708))
@@ -408,10 +414,8 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
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
@@ -452,7 +456,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
break;
}
do_cea708 = 1;
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)
{
@@ -483,7 +487,9 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n");
continue;
}
do_708(ctx->dec_ctx, (unsigned char *) temp, 4);
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;
@@ -503,7 +509,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
data += 4;
do {
ret = process608((unsigned char *) data, len, ctx->dec_ctx->context_cc608_field_1,
ret = process608((unsigned char *) data, len, dec_ctx,
&dec_sub);
len -= ret;
data += ret;
@@ -521,12 +527,12 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
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);
}
}

View File

@@ -20,7 +20,7 @@ endif (WITH_OCR)
aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
aux_source_directory ("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
add_library (ccx ${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")

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

@@ -1,6 +1,8 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "asf_constants.h"
#include "activity.h"
#include "file_buffer.h"
// Indicate first / subsequent calls to asf_getmoredata()
int firstcall;
@@ -61,7 +63,7 @@ char *guidstr(void *val)
* When the function is called the next time it continues to read
* where it stopped before, static variables make sure that parameters
* are remembered between calls. */
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
int asf_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata)
{
int enough = 0;
int payload_read = 0;
@@ -98,6 +100,15 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
unsigned char *curpos;
int64_t getbytes;
size_t result = 0;
struct demuxer_data *data;
if(!*ppdata)
*ppdata = alloc_demuxer_data();
if(!*ppdata)
return -1;
data = *ppdata;
// Read Header Object and the Top-level Data Object header only once
if(firstcall)
@@ -152,8 +163,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
asf_data_container.PayloadExtPTSEntry[stream] = -1;
}
buffered_read(ctx, asf_data_container.parsebuf,30);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 30);
ctx->demux_ctx->past += result;
if (result!=30)
{
mprint("Premature end of file!\n");
@@ -186,8 +197,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
curpos = asf_data_container.parsebuf + 30;
getbytes = asf_data_container.HeaderObjectSize - 30;
buffered_read(ctx, curpos, (int) getbytes);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, curpos, (int) getbytes);
ctx->demux_ctx->past += result;
if (result!=getbytes)
{
mprint("Premature end of file!\n");
@@ -497,7 +508,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
// it is not reliable.
// Now decide where we are going to expect the captions
ccx_bufferdatatype = CCX_PES; // Except for NTSC captions
data->bufferdatatype = CCX_PES; // Except for NTSC captions
if (asf_data_container.StreamProperties.CaptionStreamNumber > 0
&& (asf_data_container.StreamProperties.CaptionStreamStyle == 1 ||
(asf_data_container.StreamProperties.CaptionStreamStyle == 2 && !ccx_options.wtvconvertfix)))
@@ -510,7 +521,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
//if (debug_parse)
mprint("\nNTSC captions in stream #%d\n\n", asf_data_container.StreamProperties.CaptionStreamNumber);
ccx_bufferdatatype = CCX_RAW;
data->bufferdatatype = CCX_RAW;
asf_data_container.StreamProperties.DecodeStreamNumber = asf_data_container.StreamProperties.CaptionStreamNumber;
}
else if (asf_data_container.StreamProperties.CaptionStreamNumber > 0 && asf_data_container.StreamProperties.CaptionStreamStyle == 2)
@@ -535,8 +546,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
asf_data_container.PacketSize = MinPacketSize;
// Now the Data Object, except for the packages
buffered_read(ctx, asf_data_container.parsebuf, 50); // No realloc needed.
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 50); // No realloc needed.
ctx->demux_ctx->past += result;
if (result!=50)
{
mprint("Premature end of file!\n");
@@ -577,8 +588,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
dbg_print(CCX_DMT_PARSE, "\nReading packet %d/%d\n", asf_data_container.datapacketcur + 1, asf_data_container.TotalDataPackets);
// First packet
buffered_read(ctx, asf_data_container.parsebuf, 1); // No realloc needed.
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 1); // No realloc needed.
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=1)
{
@@ -594,8 +605,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
fatal(EXIT_NOT_CLASSIFIED, "Error Correction Length Type not 00 - reserved - aborting ...\n");
}
buffered_read(ctx, asf_data_container.parsebuf + 1, ecdatalength);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + 1, ecdatalength);
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=ecdatalength)
{
@@ -615,8 +626,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
}
// Now payload parsing information
buffered_read(ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=2)
{
@@ -651,8 +662,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
payloadparsersize = asf_data_container.PacketLType + SequenceType + PaddingLType + 6;
buffered_read(ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=payloadparsersize)
{
@@ -689,8 +700,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
unsigned char plheader[1];
buffered_read(ctx, plheader, 1);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, plheader, 1);
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=1)
{
@@ -728,8 +739,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
int payloadheadersize = 1 + asf_data_container.MediaNumberLType + asf_data_container.OffsetMediaLType + asf_data_container.ReplicatedLType;
buffered_read(ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=payloadheadersize)
{
@@ -756,8 +767,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
asf_data_container.parsebufsize = ReplicatedLength;
}
buffered_read(ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result!=ReplicatedLength)
{
@@ -832,8 +843,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
unsigned char plheader[4];
buffered_read(ctx, plheader, asf_data_container.PayloadLType);
ctx->past+=result;
result = buffered_read(ctx->demux_ctx, plheader, asf_data_container.PayloadLType);
ctx->demux_ctx->past += result;
asf_data_container.dobjectread += result;
if (result != asf_data_container.PayloadLType)
{
@@ -927,9 +938,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
}
// Remember, we are reading the previous package.
current_pts = asf_data_container.StreamProperties.currDecodeStreamPTS*(MPEG_CLOCK_FREQ / 1000);
if (pts_set==0)
pts_set=1;
data->pts = asf_data_container.StreamProperties.currDecodeStreamPTS*(MPEG_CLOCK_FREQ / 1000);
}
}
@@ -971,14 +980,18 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
// Read the data
dbg_print(CCX_DMT_PARSE, "Reading Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
int want = (long)((BUFSIZE - inbuf)>asf_data_container.PayloadLength ?
asf_data_container.PayloadLength : (BUFSIZE - inbuf));
data->stream_pid = asf_data_container.StreamProperties.DecodeStreamNumber;
data->program_number = 1;
data->codec = CCX_CODEC_ATSC_CC;
int want = (long)((BUFSIZE - data->len)>asf_data_container.PayloadLength ?
asf_data_container.PayloadLength : (BUFSIZE - data->len));
if (want < (long)asf_data_container.PayloadLength)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Buffer size to small for ASF payload!\nPlease file a bug report!\n");
buffered_read (ctx, ctx->buffer+inbuf,want);
payload_read+=(int) result;
inbuf+=result;
ctx->past+=result;
result = buffered_read (ctx->demux_ctx, data->buffer+data->len,want);
payload_read += (int) result;
data->len += result;
ctx->demux_ctx->past+=result;
if (result != asf_data_container.PayloadLength)
{
mprint("Premature end of file!\n");
@@ -991,8 +1004,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
// Skip non-cc data
dbg_print(CCX_DMT_PARSE, "Skipping Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
buffered_skip(ctx, (int)asf_data_container.PayloadLength);
ctx->past+=result;
result = buffered_skip(ctx->demux_ctx, (int)asf_data_container.PayloadLength);
ctx->demux_ctx->past += result;
if (result != asf_data_container.PayloadLength)
{
mprint("Premature end of file!\n");
@@ -1009,8 +1022,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
// Skip padding bytes
dbg_print(CCX_DMT_PARSE, "Skip %d padding\n", asf_data_container.PaddingLength);
buffered_skip(ctx, (long)asf_data_container.PaddingLength);
ctx->past+=result;
result = buffered_skip(ctx->demux_ctx, (long)asf_data_container.PaddingLength);
ctx->demux_ctx->past += result;
if (result != asf_data_container.PaddingLength)
{
mprint("Premature end of file!\n");
@@ -1029,8 +1042,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
// Skip the rest of the file
dbg_print(CCX_DMT_PARSE, "Skip the rest: %d\n", (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
buffered_skip(ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
ctx->past+=result;
result = buffered_skip(ctx->demux_ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
ctx->demux_ctx->past += result;
// Don not set end_of_file (although it is true) as this would
// produce an premature end error.
//end_of_file=1;
@@ -1038,5 +1051,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
// parsebuf is freed automatically when the program closes.
}
if(!payload_read)
return CCX_EOF;
return payload_read;
}

View File

@@ -2,59 +2,96 @@
#include "ccx_common_option.h"
#include "utility.h"
#include <math.h>
#include "avc_functions.h"
#define dvprint(...) dbg_print( CCX_DMT_VIDES, __VA_ARGS__)
// Functions to parse a AVC/H.264 data stream, see ISO/IEC 14496-10
int ccblocks_in_avc_total=0;
int ccblocks_in_avc_lost=0;
// local functions
static unsigned char *remove_03emu(unsigned char *from, unsigned char *to);
static void sei_rbsp (unsigned char *seibuf, unsigned char *seiend);
static unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend);
static void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend);
static void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend);
static void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
static unsigned char cc_count;
// buffer to hold cc data
static unsigned char *cc_data = NULL;
static long cc_databufsize = 1024;
int cc_buffer_saved=1; // Was the CC buffer saved after it was last updated?
static int got_seq_para=0;
static unsigned nal_ref_idc;
static LLONG seq_parameter_set_id;
static int log2_max_frame_num=0;
static int pic_order_cnt_type;
static int log2_max_pic_order_cnt_lsb=0;
static int frame_mbs_only_flag;
// Use and throw stats for debug, remove this uglyness soon
long num_nal_unit_type_7=0;
long num_vcl_hrd=0;
long num_nal_hrd=0;
long num_jump_in_frames=0;
long num_unexpected_sei_length=0;
static void sei_rbsp (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend);
static unsigned char *sei_message (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend);
static void user_data_registered_itu_t_t35 (struct avc_ctx *ctx, unsigned char *userbuf, unsigned char *userend);
static void seq_parameter_set_rbsp (struct avc_ctx *ctx, unsigned char *seqbuf, unsigned char *seqend);
static void slice_header (struct lib_cc_decode *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
double roundportable(double x) { return floor(x + 0.5); }
int ebsp_to_rbsp(char* rbsp, char* ebsp, int length);
void init_avc(void)
void dinit_avc(struct avc_ctx **ctx)
{
cc_data = (unsigned char*)malloc(1024);
struct avc_ctx *lctx = *ctx;
if (lctx->ccblocks_in_avc_lost>0)
{
mprint ("Total caption blocks received: %d\n", lctx->ccblocks_in_avc_total);
mprint ("Total caption blocks lost: %d\n", lctx->ccblocks_in_avc_lost);
}
freep(&lctx->cc_data);
freep(ctx);
}
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
struct avc_ctx *init_avc(void)
{
struct avc_ctx *ctx = malloc(sizeof(struct avc_ctx ));
if(!ctx)
return NULL;
ctx->cc_data = (unsigned char*)malloc(1024);
if(!ctx->cc_data)
{
free(ctx);
return NULL;
}
ctx->cc_count = 0;
// buffer to hold cc data
ctx->cc_databufsize = 1024;
ctx->cc_buffer_saved = CCX_TRUE; // Was the CC buffer saved after it was last updated?
ctx->got_seq_para = 0;
ctx->nal_ref_idc = 0;
ctx->seq_parameter_set_id = 0;
ctx->log2_max_frame_num = 0;
ctx->pic_order_cnt_type = 0;
ctx->log2_max_pic_order_cnt_lsb = 0;
ctx->frame_mbs_only_flag = 0;
ctx->ccblocks_in_avc_total = 0;
ctx->ccblocks_in_avc_lost = 0;
ctx->frame_num = -1;
ctx->lastframe_num = -1;
ctx->currref = 0;
ctx->maxidx = -1;
ctx->lastmaxidx=-1;
// Used to find tref zero in PTS mode
ctx->minidx=10000;
ctx->lastminidx=10000;
// Used to remember the max temporal reference number (poc mode)
ctx->maxtref = 0;
ctx->last_gop_maxtref = 0;
// Used for PTS ordering of CC blocks
ctx->currefpts = 0;
ctx->last_pic_order_cnt_lsb = -1;
ctx->last_slice_pts = -1;
return ctx;
}
void do_NAL (struct lib_cc_decode *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
{
unsigned char *NALstop;
unsigned nal_unit_type = *NALstart & 0x1F;
enum ccx_avc_nal_types nal_unit_type = *NALstart & 0x1F;
NALstop = NAL_length+NALstart;
NALstop = remove_03emu(NALstart+1, NALstop); // Add +1 to NALstop for TS, without it for MP4. Still don't know why
dvprint("BEGIN NAL unit type: %d length %d ref_idc: %d - Buffered captions before: %d\n",
nal_unit_type, NALstop-NALstart-1, ctx->avc_ctx->nal_ref_idc, !ctx->avc_ctx->cc_buffer_saved);
if (NALstop==NULL) // remove_03emu failed.
{
mprint ("\rNotice: NAL of type %u had to be skipped because remove_03emu failed.\n", nal_unit_type);
@@ -69,11 +106,11 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
{
// Found sequence parameter set
// We need this to parse NAL type 1 (CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1)
num_nal_unit_type_7++;
seq_parameter_set_rbsp(NALstart+1, NALstop);
got_seq_para = 1;
ctx->avc_ctx->num_nal_unit_type_7++;
seq_parameter_set_rbsp(ctx->avc_ctx, NALstart+1, NALstop);
ctx->avc_ctx->got_seq_para = 1;
}
else if ( got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
else if ( ctx->avc_ctx->got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_IDR_PICTURE)) // Only if nal_unit_type=1
{
// Found coded slice of a non-IDR picture
@@ -81,13 +118,13 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
// slice_layer_without_partitioning_rbsp( );
slice_header(ctx, NALstart+1, NALstop, nal_unit_type, sub);
}
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
else if ( ctx->avc_ctx->got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
{
// Found SEI (used for subtitles)
//set_fts(); // FIXME - check this!!!
sei_rbsp(NALstart+1, NALstop);
//set_fts(ctx->timing); // FIXME - check this!!!
sei_rbsp(ctx->avc_ctx, NALstart+1, NALstop);
}
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
else if ( ctx->avc_ctx->got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
{
// Found Picture parameter set
}
@@ -98,11 +135,14 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
dump (CCX_DMT_GENERIC_NOTICES,NALstart+1, NALstop-(NALstart+1),0, 0);
}
dvprint("END NAL unit type: %d length %d ref_idc: %d - Buffered captions after: %d\n",
nal_unit_type, NALstop-NALstart-1, ctx->avc_ctx->nal_ref_idc, !ctx->avc_ctx->cc_buffer_saved);
}
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
// The number of processed bytes is returned.
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
size_t process_avc ( struct lib_cc_decode *ctx, unsigned char *avcbuf, size_t avcbuflen ,struct cc_subtitle *sub)
{
unsigned char *bpos = avcbuf;
unsigned char *NALstart;
@@ -199,16 +239,9 @@ LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbufl
"Broken AVC stream - forbidden_zero_bit not zero ...");
}
nal_ref_idc = *NALstart >> 5;
unsigned nal_unit_type = *NALstart & 0x1F;
dvprint("BEGIN NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions before: %d\n",
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
ctx->avc_ctx->nal_ref_idc = *NALstart >> 5;
dvprint("process_avc: zeropad %d\n", zeropad);
do_NAL (ctx, NALstart, NALstop-NALstart, sub);
dvprint("END NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions after: %d\n",
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
}
return avcbuflen;
@@ -273,17 +306,19 @@ unsigned char *remove_03emu(unsigned char *from, unsigned char *to)
// Process SEI payload in AVC data. This function combines sei_rbsp()
// and rbsp_trailing_bits().
void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
void sei_rbsp (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend)
{
unsigned char *tbuf = seibuf;
while(tbuf < seiend - 1) // Use -1 because of trailing marker
{
tbuf = sei_message(tbuf, seiend - 1);
tbuf = sei_message(ctx, tbuf, seiend - 1);
}
if(tbuf == seiend - 1 )
{
if(*tbuf != 0x80)
mprint("Strange rbsp_trailing_bits value: %02X\n",*tbuf);
else
dvprint("\n");
}
else
{
@@ -293,13 +328,13 @@ void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
mprint ("\n Failed block (at sei_rbsp) was:\n");
dump (CCX_DMT_GENERIC_NOTICES,(unsigned char *) seibuf, seiend-seibuf,0,0);
num_unexpected_sei_length++;
ctx->num_unexpected_sei_length++;
}
}
// This combines sei_message() and sei_payload().
unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
unsigned char *sei_message (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend)
{
int payloadType = 0;
while (*seibuf==0xff)
@@ -341,26 +376,26 @@ unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
dbg_print(CCX_DMT_VERBOSE, "\n");
// Ignore all except user_data_registered_itu_t_t35() payload
if(!broken && payloadType == 4)
user_data_registered_itu_t_t35(paystart, paystart+payloadSize);
user_data_registered_itu_t_t35(ctx, paystart, paystart+payloadSize);
return seibuf;
}
void copy_ccdata_to_buffer (char *source, int new_cc_count)
void copy_ccdata_to_buffer (struct avc_ctx *ctx, char *source, int new_cc_count)
{
ccblocks_in_avc_total++;
if (cc_buffer_saved==0)
ctx->ccblocks_in_avc_total++;
if (ctx->cc_buffer_saved == CCX_FALSE)
{
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten\n");
ccblocks_in_avc_lost++;
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten, trailing end might get lost\n");
ctx->ccblocks_in_avc_lost++;
}
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
cc_count+=new_cc_count;
cc_buffer_saved=0;
memcpy(ctx->cc_data + ctx->cc_count*3, source, new_cc_count*3+1);
ctx->cc_count += new_cc_count;
ctx->cc_buffer_saved = CCX_FALSE;
}
void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend)
void user_data_registered_itu_t_t35 (struct avc_ctx *ctx, unsigned char *userbuf, unsigned char *userend)
{
unsigned char *tbuf = userbuf;
unsigned char *cc_tmpdata;
@@ -464,15 +499,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
"Syntax problem: Final 0xFF marker missing.");
// Save the data and process once we know the sequence number
if (local_cc_count*3+1 > cc_databufsize)
if ( ( (ctx->cc_count + local_cc_count) * 3) + 1 > ctx->cc_databufsize)
{
cc_data = (unsigned char*)realloc(cc_data, (size_t) cc_count*6+1);
if (!cc_data)
ctx->cc_data = (unsigned char*)realloc(ctx->cc_data, (size_t) ( (ctx->cc_count + local_cc_count) * 6) + 1);
if (!ctx->cc_data)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
cc_databufsize = (long) cc_count*6+1;
ctx->cc_databufsize = (long) ( (ctx->cc_count + local_cc_count) * 6) + 1;
}
// Copy new cc data into cc_data
copy_ccdata_to_buffer ((char *) cc_tmpdata, local_cc_count);
copy_ccdata_to_buffer (ctx, (char *) cc_tmpdata, local_cc_count);
break;
case 0x06:
dbg_print(CCX_DMT_VERBOSE, "bar_data (unsupported for now)\n");
@@ -536,15 +571,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
"Syntax problem: Final 0xFF marker missing.");
// Save the data and process once we know the sequence number
if (cc_count*3+1 > cc_databufsize)
if ( (((local_cc_count + ctx->cc_count) * 3) + 1) > ctx->cc_databufsize)
{
cc_data = (unsigned char*)realloc(cc_data, (size_t) cc_count*6+1);
if (!cc_data)
ctx->cc_data = (unsigned char*)realloc(ctx->cc_data, (size_t) (((local_cc_count + ctx->cc_count) * 6) + 1));
if (!ctx->cc_data)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
cc_databufsize = (long) cc_count*6+1;
ctx->cc_databufsize = (long) (((local_cc_count + ctx->cc_count) * 6) + 1);
}
// Copy new cc data into cc_data - replace command below.
copy_ccdata_to_buffer ((char *) cc_tmpdata, local_cc_count);
copy_ccdata_to_buffer (ctx, (char *) cc_tmpdata, local_cc_count);
//dump(tbuf,user_data_len-1,0);
break;
@@ -557,7 +592,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
// Process sequence parameters in AVC data.
void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
void seq_parameter_set_rbsp (struct avc_ctx *ctx, unsigned char *seqbuf, unsigned char *seqend)
{
LLONG tmp, tmp1;
struct bitstream q1;
@@ -583,8 +618,8 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
dvprint("reserved= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,8);
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
seq_parameter_set_id = ue(&q1);
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,seq_parameter_set_id);
ctx->seq_parameter_set_id = ue(&q1);
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", ctx->seq_parameter_set_id, ctx->seq_parameter_set_id);
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
|| profile_idc == 86 || profile_idc == 118 || profile_idc == 128){
@@ -650,18 +685,18 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
}
}
}
log2_max_frame_num = (int)ue(&q1);
dvprint("log2_max_frame_num4_minus4= % 4d (%#X)\n", log2_max_frame_num,log2_max_frame_num);
log2_max_frame_num += 4; // 4 is added due to the formula.
pic_order_cnt_type = (int)ue(&q1);
dvprint("pic_order_cnt_type= % 4d (%#X)\n", pic_order_cnt_type,pic_order_cnt_type);
if( pic_order_cnt_type == 0 )
ctx->log2_max_frame_num = (int)ue(&q1);
dvprint("log2_max_frame_num4_minus4= % 4d (%#X)\n", ctx->log2_max_frame_num, ctx->log2_max_frame_num);
ctx->log2_max_frame_num += 4; // 4 is added due to the formula.
ctx->pic_order_cnt_type = (int)ue(&q1);
dvprint("pic_order_cnt_type= % 4d (%#X)\n", ctx->pic_order_cnt_type, ctx->pic_order_cnt_type);
if( ctx->pic_order_cnt_type == 0 )
{
log2_max_pic_order_cnt_lsb = (int)ue(&q1);
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", log2_max_pic_order_cnt_lsb,log2_max_pic_order_cnt_lsb);
log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
ctx->log2_max_pic_order_cnt_lsb = (int)ue(&q1);
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", ctx->log2_max_pic_order_cnt_lsb,ctx->log2_max_pic_order_cnt_lsb);
ctx->log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
}
else if( pic_order_cnt_type == 1 )
else if( ctx->pic_order_cnt_type == 1 )
{
// CFS: Untested, just copied from specs.
tmp= u(&q1,1);
@@ -691,9 +726,9 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
dvprint("pic_width_in_mbs_minus1= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("pic_height_in_map_units_minus1= % 4lld (%#llX)\n",tmp,tmp);
frame_mbs_only_flag = (int)u(&q1,1);
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", frame_mbs_only_flag,frame_mbs_only_flag);
if ( !frame_mbs_only_flag )
ctx->frame_mbs_only_flag = (int)u(&q1,1);
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", ctx->frame_mbs_only_flag, ctx->frame_mbs_only_flag);
if ( !ctx->frame_mbs_only_flag )
{
tmp=u(&q1,1);
dvprint("mb_adaptive_fr_fi_flag= % 4lld (%#llX)\n",tmp,tmp);
@@ -785,8 +820,11 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
if (fixed_frame_rate_flag){
double clock_tick = (double) num_units_in_tick / time_scale;
dvprint("clock_tick= %f\n", clock_tick);
current_fps = (double)time_scale / (2 * num_units_in_tick); // Based on formula D-2, p. 359 of the ISO/IEC 14496-10:2012(E) spec.
mprint("Changed fps using NAL to: %f\n", current_fps);
if (current_fps != (double)time_scale / (2 * num_units_in_tick))
{
current_fps = (double)time_scale / (2 * num_units_in_tick); // Based on formula D-2, p. 359 of the ISO/IEC 14496-10:2012(E) spec.
mprint("Changed fps using NAL to: %f\n", current_fps);
}
}
}
tmp = u(&q1,1);
@@ -796,7 +834,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
//printf("Boom nal_hrd\n");
// exit(1);
num_nal_hrd++;
ctx->num_nal_hrd++;
return;
}
tmp1 = u(&q1,1);
@@ -805,7 +843,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
{
// TODO.
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
num_vcl_hrd++;
ctx->num_vcl_hrd++;
// exit(1);
}
if ( tmp || tmp1 )
@@ -827,57 +865,53 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
}
// Process slice header in AVC data.
void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
/**
Process slice header in AVC data.
Slice Header is parsed to get sequence of frames
*/
void slice_header (struct lib_cc_decode *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
{
LLONG tmp;
struct bitstream q1;
int maxframe_num;
LLONG slice_type, bottom_field_flag=0, pic_order_cnt_lsb=-1;
int curridx;
int IdrPicFlag;
LLONG field_pic_flag = 0; // Moved here because it's needed for ctx->avc_ctx->pic_order_cnt_type==2
if (init_bitstream(&q1, heabuf, heaend))
{
mprint ("Skipping slice header due to failure in init_bitstream.\n");
return;
}
LLONG slice_type, bottom_field_flag=0, pic_order_cnt_lsb=-1;
static LLONG frame_num=-1, lastframe_num = -1;
static int currref=0, maxidx=-1, lastmaxidx=-1;
// Used to find tref zero in PTS mode
static int minidx=10000, lastminidx=10000;
int curridx;
int IdrPicFlag = ((nal_unit_type == 5 )?1:0);
IdrPicFlag = ((nal_unit_type == 5 )?1:0);
// Used to remember the max temporal reference number (poc mode)
static int maxtref = 0;
static int last_gop_maxtref = 0;
// Used for PTS ordering of CC blocks
static LLONG currefpts = 0;
dvprint("\nSLICE HEADER\n");
tmp = ue(&q1);
dvprint("first_mb_in_slice= % 4lld (%#llX)\n",tmp,tmp);
slice_type = ue(&q1);
dvprint("slice_type= %llX\n", slice_type);
dvprint("slice_type= % 4llX\n", slice_type);
tmp = ue(&q1);
dvprint("pic_parameter_set_id= % 4lld (%#llX)\n",tmp,tmp);
lastframe_num = frame_num;
int maxframe_num = (int) ((1<<log2_max_frame_num) - 1);
ctx->avc_ctx->lastframe_num = ctx->avc_ctx->frame_num;
maxframe_num = (int) ((1<<ctx->avc_ctx->log2_max_frame_num) - 1);
// Needs log2_max_frame_num_minus4 + 4 bits
frame_num = u(&q1,log2_max_frame_num);
dvprint("frame_num= %llX\n", frame_num);
ctx->avc_ctx->frame_num = u(&q1,ctx->avc_ctx->log2_max_frame_num);
dvprint("frame_num= % 4llX\n", ctx->avc_ctx->frame_num);
LLONG field_pic_flag = 0; // Moved here because it's needed for pic_order_cnt_type==2
if( !frame_mbs_only_flag )
if( !ctx->avc_ctx->frame_mbs_only_flag )
{
field_pic_flag = u(&q1,1);
dvprint("field_pic_flag= %llX\n", field_pic_flag);
dvprint("field_pic_flag= % 4llX\n", field_pic_flag);
if( field_pic_flag )
{
// bottom_field_flag
bottom_field_flag = u(&q1,1);
dvprint("bottom_field_flag= %llX\n", bottom_field_flag);
dvprint("bottom_field_flag= % 4llX\n", bottom_field_flag);
// TODO - Do this right.
// When bottom_field_flag is set the video is interlaced,
@@ -886,22 +920,36 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
}
}
dvprint("IdrPicFlag= %d\n", IdrPicFlag );
dvprint("IdrPicFlag= % 4d\n", IdrPicFlag );
if( nal_unit_type == 5 )
{
tmp=ue(&q1);
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
//TODO
}
if( pic_order_cnt_type == 0 )
if( ctx->avc_ctx->pic_order_cnt_type == 0 )
{
pic_order_cnt_lsb=u(&q1,log2_max_pic_order_cnt_lsb);
dvprint("pic_order_cnt_lsb= %llX\n", pic_order_cnt_lsb);
pic_order_cnt_lsb=u(&q1,ctx->avc_ctx->log2_max_pic_order_cnt_lsb);
dvprint("pic_order_cnt_lsb= % 4llX\n", pic_order_cnt_lsb);
}
if( pic_order_cnt_type == 1 )
if( ctx->avc_ctx->pic_order_cnt_type == 1 )
{
fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type == 1 not yet supported.");
fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: ctx->avc_ctx->pic_order_cnt_type == 1 not yet supported.");
}
//Ignore slice with same pic order or pts
if ( ccx_options.usepicorder )
{
if ( ctx->avc_ctx->last_pic_order_cnt_lsb == pic_order_cnt_lsb)
return;
ctx->avc_ctx->last_pic_order_cnt_lsb = pic_order_cnt_lsb;
}
else
{
if (ctx->timing->current_pts == ctx->avc_ctx->last_slice_pts)
return;
ctx->avc_ctx->last_slice_pts = ctx->timing->current_pts;
}
#if 0
else
@@ -918,7 +966,7 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
LLONG tempPicOrderCnt=0;
if (IdrPicFlag == 1)
tempPicOrderCnt=0;
else if (nal_ref_idc == 0)
else if (ctx->avc_ctx->nal_ref_idc == 0)
tempPicOrderCnt = 2*(FrameNumOffset + frame_num) -1 ;
else
tempPicOrderCnt = 2*(FrameNumOffset + frame_num);
@@ -936,7 +984,7 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
//pic_order_cnt_lsb=tempPicOrderCnt;
//pic_order_cnt_lsb=u(&q1,tempPicOrderCnt);
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: ctx->avc_ctx->pic_order_cnt_type != 0 not yet supported.");
//TODO
// Calculate picture order count (POC) according to 8.2.1
}
@@ -944,44 +992,49 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
// The rest of the data in slice_header() is currently unused.
// A reference pic (I or P is always the last displayed picture of a POC
// sequence. B slices can be reference pics, so ignore nal_ref_idc.
// sequence. B slices can be reference pics, so ignore ctx->avc_ctx->nal_ref_idc.
int isref = 0;
switch (slice_type)
{
// P-SLICES
case 0:
case 5:
// I-SLICES
// I-SLICES
case 2:
case 7:
isref=1;
break;
}
int maxrefcnt = (int) ((1<<log2_max_pic_order_cnt_lsb) - 1);
int maxrefcnt = (int) ((1<<ctx->avc_ctx->log2_max_pic_order_cnt_lsb) - 1);
// If we saw a jump set maxidx, lastmaxidx to -1
LLONG dif = frame_num - lastframe_num;
LLONG dif = ctx->avc_ctx->frame_num - ctx->avc_ctx->lastframe_num;
if (dif == -maxframe_num)
dif = 0;
if ( lastframe_num > -1 && (dif < 0 || dif > 1) )
if ( ctx->avc_ctx->lastframe_num > -1 && (dif < 0 || dif > 1) )
{
num_jump_in_frames++;
dvprint("\nJump in frame numbers (%lld/%lld)\n", frame_num, lastframe_num);
ctx->avc_ctx->num_jump_in_frames++;
dvprint("\nJump in frame numbers (%lld/%lld)\n", ctx->avc_ctx->frame_num, ctx->avc_ctx->lastframe_num);
// This will prohibit setting current_tref on potential
// jumps.
maxidx = -1;
lastmaxidx = -1;
ctx->avc_ctx->maxidx = -1;
ctx->avc_ctx->lastmaxidx = -1;
}
#if 0
Leaving it for record, after testing garbled_dishHD.mpg, and
2014 SugarHouse Casino Mummers Parade Fancy Brigades_new.ts might need to come back
// Sometimes two P-slices follow each other, see garbled_dishHD.mpg,
// in this case we only treat the first as a reference pic
if (isref && ctx->frames_since_last_gop <= 3) // Used to be == 1, but the sample file
{ // 2014 SugarHouse Casino Mummers Parade Fancy Brigades_new.ts was garbled
// Probably doing a proper PTS sort would be a better solution.
isref = 0;
//isref = 0;
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
}
#endif
// if slices are buffered - flush
if (isref)
@@ -991,73 +1044,73 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
slice_types[slice_type], maxrefcnt);
// Flush buffered cc blocks before doing the housekeeping
if (has_ccdata_buffered)
if (ctx->has_ccdata_buffered)
{
process_hdcc(ctx, sub);
}
ctx->last_gop_length = ctx->frames_since_last_gop;
ctx->frames_since_last_gop = 0;
last_gop_maxtref = maxtref;
maxtref = 0;
lastmaxidx = maxidx;
maxidx = 0;
lastminidx = minidx;
minidx = 10000;
ctx->avc_ctx->last_gop_maxtref = ctx->avc_ctx->maxtref;
ctx->avc_ctx->maxtref = 0;
ctx->avc_ctx->lastmaxidx = ctx->avc_ctx->maxidx;
ctx->avc_ctx->maxidx = 0;
ctx->avc_ctx->lastminidx = ctx->avc_ctx->minidx;
ctx->avc_ctx->minidx = 10000;
if ( ccx_options.usepicorder ) {
// Use pic_order_cnt_lsb
// Make sure that curridx never wraps for curidx values that
// are smaller than currref
currref = (int)pic_order_cnt_lsb;
if (currref < maxrefcnt/3)
ctx->avc_ctx->currref = (int)pic_order_cnt_lsb;
if (ctx->avc_ctx->currref < maxrefcnt/3)
{
currref += maxrefcnt+1;
ctx->avc_ctx->currref += maxrefcnt+1;
}
// If we wrapped arround lastmaxidx might be larger than
// the current index - fix this.
if (lastmaxidx > currref + maxrefcnt/2) // implies lastmaxidx > 0
lastmaxidx -=maxrefcnt+1;
if (ctx->avc_ctx->lastmaxidx > ctx->avc_ctx->currref + maxrefcnt/2) // implies lastmaxidx > 0
ctx->avc_ctx->lastmaxidx -=maxrefcnt+1;
} else {
// Use PTS ordering
currefpts = current_pts;
currref = 0;
ctx->avc_ctx->currefpts = ctx->timing->current_pts;
ctx->avc_ctx->currref = 0;
}
anchor_hdcc( currref );
anchor_hdcc( ctx, ctx->avc_ctx->currref );
}
if ( ccx_options.usepicorder ) {
// Use pic_order_cnt_lsb
// Wrap (add max index value) curridx if needed.
if( currref - pic_order_cnt_lsb > maxrefcnt/2 )
if( ctx->avc_ctx->currref - pic_order_cnt_lsb > maxrefcnt/2 )
curridx = (int)pic_order_cnt_lsb + maxrefcnt+1;
else
curridx = (int)pic_order_cnt_lsb;
// Track maximum index for this GOP
if ( curridx > maxidx )
maxidx = curridx;
if ( curridx > ctx->avc_ctx->maxidx )
ctx->avc_ctx->maxidx = curridx;
// Calculate tref
if ( lastmaxidx > 0 ) {
current_tref = curridx - lastmaxidx -1;
if ( ctx->avc_ctx->lastmaxidx > 0 ) {
ctx->timing->current_tref = curridx - ctx->avc_ctx->lastmaxidx -1;
// Set maxtref
if( current_tref > maxtref ) {
maxtref = current_tref;
if( ctx->timing->current_tref > ctx->avc_ctx->maxtref ) {
ctx->avc_ctx->maxtref = ctx->timing->current_tref;
}
// Now an ugly workaround where pic_order_cnt_lsb increases in
// steps of two. The 1.5 is an approximation, it should be:
// last_gop_maxtref+1 == last_gop_length*2
if ( last_gop_maxtref > ctx->last_gop_length*1.5 ) {
current_tref = current_tref/2;
if ( ctx->avc_ctx->last_gop_maxtref > ctx->last_gop_length*1.5 ) {
ctx->timing->current_tref = ctx->timing->current_tref/2;
}
}
else
current_tref = 0;
ctx->timing->current_tref = 0;
if ( current_tref < 0 ) {
if ( ctx->timing->current_tref < 0 ) {
mprint("current_tref is negative!?\n");
}
} else {
@@ -1065,69 +1118,64 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
// frame rate
// The 2* accounts for a discrepancy between current and actual FPS
// seen in some files (CCSample2.mpg)
curridx = (int)roundportable(2*(current_pts - currefpts)/(MPEG_CLOCK_FREQ/current_fps));
curridx = (int)roundportable(2*(ctx->timing->current_pts - ctx->avc_ctx->currefpts)/(MPEG_CLOCK_FREQ/current_fps));
if (abs(curridx) >= MAXBFRAMES) {
// Probably a jump in the timeline. Warn and handle gracefully.
mprint("\nFound large gap in PTS! Trying to recover ...\n");
mprint("\nFound large gap(%d) in PTS! Trying to recover ...\n", curridx);
curridx = 0;
}
// Track maximum index for this GOP
if ( curridx > maxidx )
maxidx = curridx;
if ( curridx > ctx->avc_ctx->maxidx )
ctx->avc_ctx->maxidx = curridx;
// Track minimum index for this GOP
if ( curridx < minidx )
minidx = curridx;
if ( curridx < ctx->avc_ctx->minidx )
ctx->avc_ctx->minidx = curridx;
current_tref = 1;
if ( curridx == lastminidx ) {
ctx->timing->current_tref = 1;
if ( curridx == ctx->avc_ctx->lastminidx ) {
// This implies that the minimal index (assuming its number is
// fairly constant) sets the temporal reference to zero - needed to set sync_pts.
current_tref = 0;
ctx->timing->current_tref = 0;
}
if ( lastmaxidx == -1) {
if ( ctx->avc_ctx->lastmaxidx == -1) {
// Set temporal reference to zero on minimal index and in the first GOP
// to avoid setting a wrong fts_offset
current_tref = 0;
ctx->timing->current_tref = 0;
}
}
set_fts(); // Keep frames_since_ref_time==0, use current_tref
set_fts(ctx->timing); // Keep frames_since_ref_time==0, use current_tref
dbg_print(CCX_DMT_TIME, "PTS: %s (%8u)",
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (current_pts));
dbg_print(CCX_DMT_TIME, " picordercnt:%3lld tref:%3d idx:%3d refidx:%3d lmaxidx:%3d maxtref:%3d\n",
pic_order_cnt_lsb, current_tref,
curridx, currref, lastmaxidx, maxtref);
dbg_print(CCX_DMT_TIME, "FTS: %s",
print_mstime(get_fts()));
pic_order_cnt_lsb, ctx->timing->current_tref,
curridx, ctx->avc_ctx->currref, ctx->avc_ctx->lastmaxidx, ctx->avc_ctx->maxtref);
dbg_print(CCX_DMT_TIME, " sync_pts:%s (%8u)",
print_mstime(sync_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (sync_pts));
print_mstime(ctx->timing->sync_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (ctx->timing->sync_pts));
dbg_print(CCX_DMT_TIME, " - %s since GOP: %2u",
slice_types[slice_type],
(unsigned) (ctx->frames_since_last_gop));
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, frame_num);
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, ctx->avc_ctx->frame_num);
// sync_pts is (was) set when current_tref was zero
if ( lastmaxidx > -1 && current_tref == 0 )
if ( ctx->avc_ctx->lastmaxidx > -1 && ctx->timing->current_tref == 0 )
{
if (ccx_options.debug_mask & CCX_DMT_TIME )
{
dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
print_debug_timing();
print_debug_timing(ctx->timing);
}
}
total_frames_count++;
ctx->frames_since_last_gop++;
store_hdcc(ctx, cc_data, cc_count, curridx, fts_now, sub);
cc_buffer_saved=1; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
cc_count=0;
store_hdcc(ctx, ctx->avc_ctx->cc_data, ctx->avc_ctx->cc_count, curridx, ctx->timing->fts_now, sub);
ctx->avc_ctx->cc_buffer_saved = CCX_TRUE; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
ctx->avc_ctx->cc_count = 0;
}
// max_dec_frame_buffering .. Max frames in buffer

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

@@ -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, ...)
{
@@ -64,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,19 +2,49 @@
#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
/* 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, ...);
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms);
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

@@ -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
@@ -130,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,
};
@@ -160,6 +163,8 @@ enum ccx_output_format
CCX_OF_SMPTETT = 6,
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
@@ -192,7 +197,8 @@ enum ccx_encoding_type
{
CCX_ENC_UNICODE = 0,
CCX_ENC_LATIN_1 = 1,
CCX_ENC_UTF_8 = 2
CCX_ENC_UTF_8 = 2,
CCX_ENC_ASCII = 3
};
enum ccx_bufferdata_type
@@ -205,6 +211,7 @@ enum ccx_bufferdata_type
CCX_TELETEXT = 5,
CCX_PRIVATE_MPEG2_CC = 6,
CCX_DVB_SUBTITLE = 7,
CCX_ISDB_SUBTITLE = 8,
};
enum ccx_frame_type
@@ -228,6 +235,7 @@ enum ccx_code_type
CCX_CODEC_TELETEXT,
CCX_CODEC_DVB,
CCX_CODEC_ISDB_CC,
CCX_CODEC_ATSC_CC,
CCX_CODEC_NONE,
};
@@ -257,7 +265,7 @@ enum cdp_section_type
* 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.
@@ -276,4 +284,12 @@ enum cdp_section_type
#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,21 +1,20 @@
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_708.h"
#include "utility.h"
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;
@@ -23,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
@@ -57,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.
@@ -90,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>

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,6 +23,7 @@ enum subtype
{
CC_BITMAP,
CC_608,
CC_708,
CC_TEXT,
CC_RAW,
};
@@ -28,6 +31,9 @@ enum subtype
/**
* 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
{
@@ -36,18 +42,33 @@ struct cc_subtitle
* @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,19 +37,62 @@ 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)
{
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;
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;
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 (!pts_set && ccx_common_timing_settings.is_elementary_stream)
return;
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 (pts_set == 2)
if (ctx->pts_set == 2)
{
dif=(int) (current_pts-sync_pts)/MPEG_CLOCK_FREQ;
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.
@@ -74,61 +103,61 @@ void set_fts(void)
{
// 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);
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)
if(ctx->current_tref != 0 && ctx->current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
{
fts_now = fts_max;
ctx->fts_now = ctx->fts_max;
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
return;
return CCX_OK;
}
}
}
// Set min_pts, fts_offset
if (pts_set != 0)
if (ctx->pts_set != 0)
{
pts_set = 2;
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 (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
ctx->sync_pts = (LLONG)(ctx->current_pts
-ctx->current_tref*1000.0/current_fps
*(MPEG_CLOCK_FREQ/1000));
if(current_tref == 0)
if(ctx->current_tref == 0)
{ // Earliest time in GOP.
fts_offset = 0;
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.
fts_offset = 0;
ctx->fts_offset = 0;
}
else
{ // It needs to be "+1" because the current frame is
// not yet counted.
fts_offset = (LLONG)((total_frames_count
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 );
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);
}
@@ -139,31 +168,31 @@ void set_fts(void)
// 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)
ctx->fts_offset = ctx->fts_offset
+ (ctx->sync_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
+ (LLONG) (frames_since_ref_time*1000/current_fps);
fts_max = fts_offset;
ctx->fts_max = ctx->fts_offset;
// Start counting again from here
pts_set = 1; // Force min to be set again
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
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
min_pts = sync_pts;
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 );
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;
if(ctx->current_tref == 0)
ctx->sync_pts = ctx->current_pts;
// Reset counters
cb_field1 = 0;
@@ -174,53 +203,56 @@ void set_fts(void)
// 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 )
if ( ctx->fts_now > ctx->fts_max )
{
fts_max = fts_now;
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;
switch (current_field)
{
case 1:
fts = fts_now + fts_global + cb_field1*1001/30;
fts = ctx->fts_now + ctx->fts_global + cb_field1*1001/30;
break;
case 2:
fts = fts_now + fts_global + cb_field2*1001/30;
fts = ctx->fts_now + ctx->fts_global + cb_field2*1001/30;
break;
case 3:
fts = fts_now + fts_global + cb_708*1001/30;
fts = ctx->fts_now + ctx->fts_global + cb_708*1001/30;
break;
default:
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
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;
return ctx->fts_max + ctx->fts_global;
}
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
@@ -243,6 +275,28 @@ char *print_mstime2buf( LLONG mstime , char *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. */
char *print_mstime( LLONG mstime )
@@ -252,31 +306,31 @@ char *print_mstime( LLONG mstime )
}
/* 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);
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)) );
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);
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()));
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);
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)

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\">"},
@@ -121,10 +120,9 @@ void ccx_decoder_608_dinit_library(void **ctx)
freep(ctx);
}
ccx_decoder_608_context* ccx_decoder_608_init_library(struct 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)
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(struct ccx_decoder_608_set
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->report = settings->report;
data->timing = timing;
clear_eia608_cc_buffer(data, &data->buffer1);
clear_eia608_cc_buffer(data, &data->buffer2);
@@ -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);
}
}
@@ -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)
@@ -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;
@@ -763,7 +757,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
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,7 +793,7 @@ 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;
@@ -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.
@@ -977,7 +971,7 @@ 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;
@@ -1075,16 +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 */
/* 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;
ccx_decoder_608_context *context = private_data;
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)
@@ -1119,16 +1126,16 @@ int process608(const unsigned char *data, int length, void *private_data, struct
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;
@@ -1137,17 +1144,19 @@ int process608(const unsigned char *data, int length, void *private_data, struct
// 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
@@ -1168,7 +1177,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
{
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.
@@ -1183,10 +1192,10 @@ int process608(const unsigned char *data, int length, void *private_data, struct
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);
@@ -1196,9 +1205,9 @@ int process608(const unsigned char *data, int length, void *private_data, struct
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",
@@ -1213,7 +1222,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
{
// 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

@@ -13,8 +13,8 @@ extern LLONG ts_start_of_xds;
*/
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,6 +24,7 @@ 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
@@ -47,26 +48,21 @@ 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
{
@@ -122,10 +118,9 @@ void ccx_decoder_608_dinit_library(void **ctx);
*
*/
ccx_decoder_608_context* ccx_decoder_608_init_library(struct 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);
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
@@ -146,7 +141,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
* 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);

File diff suppressed because it is too large Load Diff

View File

@@ -2,79 +2,78 @@
#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;
@@ -82,143 +81,142 @@ struct S_COMMANDS_C1
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;
} ccx_dtvcc_pen_color;
typedef struct e708Pen_attribs
typedef struct ccx_dtvcc_pen_attribs
{
int pen_size;
int offset;
@@ -227,28 +225,47 @@ typedef struct e708Pen_attribs
int edge_type;
int underline;
int italic;
} e708Pen_attribs;
} ccx_dtvcc_pen_attribs;
typedef struct e708Window_attribs
typedef struct ccx_dtvcc_window_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_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 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
{
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; // Handy, in case we only have a pointer to the window
int number;
int priority;
int col_lock;
int row_lock;
@@ -262,52 +279,94 @@ typedef struct e708Window
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;
ccx_dtvcc_window_attribs attribs;
int pen_row;
int pen_column;
unsigned char *rows[I708_MAX_ROWS+1]; // Max is 15, but we define an extra one for convenience
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 reset_count;
unsigned services[CCX_DTVCC_MAX_SERVICES];
} ccx_decoder_dtvcc_report;
typedef struct ccx_dtvcc_service_decoder
{
ccx_dtvcc_window windows[CCX_DTVCC_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;
dtvcc_tv_screen *tv;
int cc_count;
} ccx_dtvcc_service_decoder;
extern int do_cea708; // Process 708 data?
extern int cea708services[]; // [] -> 1 for services to be processed
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;
extern int resets_708;
/**
* TODO
* solution requires "sink" or "writer" entity to write captions to output file
* decoders have to know nothing about output files
*/
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength);
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;
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);
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,33 +12,33 @@ 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;
}
unsigned char get_internal_from_G1 (unsigned char g1_char)
unsigned char dtvcc_get_internal_from_G1(unsigned char 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;
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
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;
@@ -161,13 +102,13 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
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,
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
* Note that printdata() and dtvcc_process_data() must not be called for
* the CCX_OF_RCWT case. */
if (cc_valid || cc_type==3)
@@ -179,14 +120,14 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
case 0:
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
current_field=1;
ctx->current_field = 1;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
@@ -203,14 +144,14 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
case 1:
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
current_field=2;
ctx->current_field = 2;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
@@ -231,13 +172,13 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
// DTVCC packet start
current_field=3;
ctx->current_field = 3;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
@@ -249,8 +190,8 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
temp[3]=cc_block[2];
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
do_708 (ctx,(const unsigned char *) temp, 4);
if (ctx->write_format != CCX_OF_RCWT)
ccx_dtvcc_process_data(ctx, (const unsigned char *) temp, 4);
else
writercwtdata(ctx, cc_block, sub);
}
@@ -270,6 +211,18 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
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,36 +231,60 @@ 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(
setting->settings_608,
setting->cc_channel,
1,
setting->trim_subs,
setting->encoding,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->subs_delay,
setting->output_format
);
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
setting->settings_608,
setting->cc_channel,
2,
setting->trim_subs,
setting->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));
@@ -320,19 +297,96 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
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

@@ -7,21 +7,13 @@
#include "ccx_decoders_structs.h"
#include "ccx_common_option.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
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);
@@ -32,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,16 +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
int trim_subs; // Remove spaces at sides?
enum ccx_encoding_type encoding;
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];
@@ -102,14 +112,73 @@ 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);
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +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,10 +1,15 @@
#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) \
@@ -12,7 +17,12 @@
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
@@ -26,32 +36,64 @@ struct encoder_ctx
unsigned int capacity;
/* keep count of srt subtitle*/
unsigned int srt_counter;
/* output context */
struct ccx_s_write *out;
/* start time of previous sub */
LLONG prev_start;
LLONG subs_delay;
LLONG last_displayed_subs_ms;
int startcredits_displayed;
/* 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_date_format date_format;
char millis_separator;
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?
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
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_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
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;
unsigned int teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
unsigned int send_to_srv;
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
int no_bom;
// 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
@@ -61,13 +103,11 @@ struct encoder_ctx
* write subtitle header to file refrenced by
* output context
*
* @param ctx preallocated encoder ctx
* @param out output context
* @param opt Option to initilaize encoder cfg params
* @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 ccx_s_options *opt);
struct encoder_ctx *init_encoder(struct encoder_cfg *opt);
/**
* try to add end credits in subtitle file and then write subtitle
@@ -76,9 +116,11 @@ int init_encoder(struct encoder_ctx *ctx, struct ccx_s_write *out, struct ccx_s_
* 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
@@ -87,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);
@@ -105,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;
@@ -361,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)
@@ -389,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

@@ -5,24 +5,47 @@
#include "spupng_encoder.h"
#include "ocr.h"
#include "utility.h"
#include "ccx_encoders_helpers.h"
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 used;
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
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->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");
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
@@ -45,16 +68,24 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
unsigned char *begin = unescaped;
while (begin < unescaped+len)
{
unsigned int u = encode_line (el, begin);
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_br, encoded_br_length);
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;
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin += strlen ((const char *) begin) + 1;
}
@@ -63,8 +94,10 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
{
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);
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);
@@ -72,15 +105,21 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
write(context->out->fh, context->buffer, used);
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;
@@ -107,7 +146,6 @@ int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context
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))
@@ -145,11 +183,40 @@ int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context
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;
@@ -158,30 +225,29 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
endms = data->end_time;
endms--; // To prevent overlapping with next line.
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
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->buffer,(unsigned char *) 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 (subline, i, data);
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, context->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);
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");
@@ -189,7 +255,7 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) 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",
@@ -198,7 +264,7 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
used = encode_line(context, context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
return wrote_something;
}

View File

@@ -28,6 +28,7 @@
#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)
@@ -40,6 +41,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
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");
@@ -52,7 +54,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer, (unsigned char *) 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)
@@ -74,16 +76,16 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
unsigned char *begin = unescaped;
while (begin < unescaped+len)
{
unsigned int u = encode_line (el, begin);
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 (wb->fh, encoded_br, encoded_br_length);
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;
}
@@ -92,14 +94,14 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer, (unsigned char *) 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->buffer, (unsigned char *) str);
used = encode_line(context, context->buffer, (unsigned char *) str);
write (context->out->fh, context->buffer, used);
sprintf ((char *) str, "</p>\n");
free(el);
@@ -110,6 +112,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
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];
@@ -139,7 +142,6 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
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))
@@ -153,7 +155,7 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
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);
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
sprintf ( buf,"</p>\n");
write (context->out->fh, buf,strlen(buf) );
@@ -167,6 +169,33 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
}
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;
@@ -175,6 +204,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
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
@@ -191,22 +221,22 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) 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 (subline, i, data);
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, context->subline, length);
wrote_something=1;
write(context->out->fh, encoded_crlf, encoded_crlf_length);
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
}
}
sprintf ((char *) str,"</p>\n");
@@ -214,14 +244,14 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) 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->buffer,(unsigned char *) str);
used = encode_line(context, context->buffer,(unsigned char *) str);
//write (wb->fh, enc_buffer,enc_buffer_used);
return wrote_something;

View File

@@ -1,7 +1,24 @@
#include <assert.h>
#include <sys/stat.h>
#include "608_spupng.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;
@@ -181,6 +198,76 @@ int spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
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);
@@ -196,6 +283,7 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
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)
{
@@ -235,11 +323,11 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
{
if (data->row_used[row])
{
int len = get_decoder_line_encoded(subline, row, data);
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 = subline; ptr < subline+len; ptr++)
for (unsigned char* ptr = context->subline; ptr < context->subline+len; ptr++)
{
switch (*ptr)
{
@@ -255,14 +343,66 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
break;
}
}
strncat(str,(const char*)subline,256);
strncat(str,"\n",256);
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;

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);
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);
@@ -182,7 +222,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
{
if (context->sentence_cap)
{
capitalize (i,data);
capitalize (context, i, data);
correct_case(i,data);
}
if (context->autodash && context->trim_subs)
@@ -190,7 +230,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
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);
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

View File

@@ -2,10 +2,6 @@
#define CXX_MP4_H
struct ccx_s_mp4Cfg
{
unsigned int mp4vidtrack :1;
};
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,void *enc_ctx);
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;
@@ -1558,7 +1575,9 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
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;
@@ -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

View File

@@ -1,43 +1,28 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "activity.h"
// Functions to parse a mpeg-2 data stream, see ISO/IEC 13818-2 6.2
static int no_bitstream_error = 0;
static int saw_seqgoppic = 0;
static int in_pic_data = 0;
static unsigned current_progressive_sequence = 2;
static unsigned current_pulldownfields = 32768;
static int temporal_reference = 0;
static enum ccx_frame_type picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
static unsigned picture_structure = 0;
unsigned top_field_first = 0; // Needs to be global
static unsigned repeat_first_field = 0;
static unsigned progressive_frame = 0;
static unsigned pulldownfields = 0;
static uint8_t search_start_code(struct bitstream *esstream);
static uint8_t next_start_code(struct bitstream *esstream);
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
static int sequence_ext(struct bitstream *esstream);
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int pic_header(struct bitstream *esstream);
static int pic_coding_ext(struct bitstream *esstream);
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
static int es_video_sequence(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream);
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
static int read_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int gop_header(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int read_pic_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
static int read_eau_info(struct lib_cc_decode* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
static int extension_and_user_data(struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
static int read_pic_data(struct bitstream *esstream);
#define debug( ... ) ccx_common_logging.debug_ftn( CCX_DMT_VERBOSE, __VA_ARGS__)
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data".
* The number of processed bytes is returned.
* Defined in ISO/IEC 13818-2 6.2 */
LLONG process_m2v (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)
{
if (length<8) // Need to look ahead 8 bytes
return length;
@@ -71,7 +56,7 @@ static uint8_t search_start_code(struct bitstream *esstream)
// Keep a negative esstream->bitsleft, but correct it.
if (esstream->bitsleft <= 0)
{
dbg_print(CCX_DMT_VERBOSE, "search_start_code: bitsleft <= 0\n");
debug("search_start_code: bitsleft <= 0\n");
esstream->bitsleft -= 8*4;
return 0xB4;
}
@@ -110,12 +95,12 @@ static uint8_t search_start_code(struct bitstream *esstream)
esstream->pos = tstr;
if (esstream->bitsleft < 0)
{
dbg_print(CCX_DMT_VERBOSE, "search_start_code: bitsleft <= 0\n");
debug("search_start_code: bitsleft <= 0\n");
return 0xB4;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "search_start_code: Found %02X\n", tstr[3]);
debug("search_start_code: Found %02X\n", tstr[3]);
return tstr[3];
}
}
@@ -142,7 +127,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
// Only start looking if there is enough data. Adjust bitsleft.
if (esstream->bitsleft < 4*8)
{
dbg_print(CCX_DMT_VERBOSE, "next_start_code: bitsleft %lld < 32\n", esstream->bitsleft);
debug("next_start_code: bitsleft %lld < 32\n", esstream->bitsleft);
esstream->bitsleft -= 8*4;
return 0xB4;
}
@@ -154,7 +139,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
tmp = read_u8(esstream);
if (tmp)
{
dbg_print(CCX_DMT_VERBOSE, "next_start_code: Non zero stuffing\n");
debug("next_start_code: Non zero stuffing\n");
esstream->error = 1;
return 0xB4;
}
@@ -163,16 +148,16 @@ static uint8_t next_start_code(struct bitstream *esstream)
if (esstream->bitsleft < 8)
{
esstream->bitsleft -= 8;
dbg_print(CCX_DMT_VERBOSE, "next_start_code: bitsleft <= 0\n");
debug("next_start_code: bitsleft <= 0\n");
return 0xB4;
}
else
{
dbg_print(CCX_DMT_VERBOSE, "next_start_code: Found %02X\n", *(esstream->pos+3));
debug("next_start_code: Found %02X\n", *(esstream->pos+3));
if ( *(esstream->pos+3) == 0xB4 )
{
dbg_print(CCX_DMT_VERBOSE, "B4: assume bitstream syntax error!\n");
debug("B4: assume bitstream syntax error!\n");
esstream->error = 1;
}
@@ -185,19 +170,19 @@ static uint8_t next_start_code(struct bitstream *esstream)
// Otherwise. estream->pos shall point to the position where
// the next call will continue, i.e. the possible begin of an
// unfinished video sequence or after the finished sequence.
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
static int es_video_sequence(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
// Avoid "Skip forward" message on first call and later only
// once per search.
static int noskipmessage = 1;
uint8_t startcode;
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence()\n");
debug("es_video_sequence()\n");
esstream->error = 0;
// Analyze sequence header ...
if (!no_bitstream_error)
if (!ctx->no_bitstream_error)
{
// We might start here because of a syntax error. Discard
// all data until a new sequence_header_code or group_start_code
@@ -225,27 +210,27 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
skip_bits(esstream, 4*8);
}
no_bitstream_error = 1;
saw_seqgoppic = 0;
in_pic_data = 0;
ctx->no_bitstream_error = 1;
ctx->saw_seqgoppic = 0;
ctx->in_pic_data = 0;
}
do
{
startcode = next_start_code(esstream);
dbg_print(CCX_DMT_VERBOSE, "\nM2V - next start code %02X %d\n", startcode, in_pic_data);
debug("\nM2V - next start code %02X %d\n", startcode, ctx->in_pic_data);
// Syntax check - also returns on bitsleft < 0
if (startcode == 0xB4)
{
if (esstream->error)
{
no_bitstream_error = 0;
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence: syntax problem.\n");
ctx->no_bitstream_error = 0;
debug("es_video_sequence: syntax problem.\n");
}
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence: return on B4 startcode.\n");
debug("es_video_sequence: return on B4 startcode.\n");
return 0;
}
@@ -254,72 +239,72 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
if (startcode == 0xB7)
{
skip_u32(esstream); // Advance bitstream
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
break;
}
if (!in_pic_data && startcode == 0xB3)
if (!ctx->in_pic_data && startcode == 0xB3)
{
if (!read_seq_info(ctx, esstream))
{
if (esstream->error)
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
}
saw_seqgoppic = 1;
ctx->saw_seqgoppic = 1;
continue;
}
if (!in_pic_data && startcode == 0xB8)
if (!ctx->in_pic_data && startcode == 0xB8)
{
if (!read_gop_info(ctx, esstream,sub))
{
if (esstream->error)
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
}
saw_seqgoppic = 2;
ctx->saw_seqgoppic = 2;
continue;
}
if (!in_pic_data && startcode == 0x00)
if (!ctx->in_pic_data && startcode == 0x00)
{
if (!read_pic_info(ctx, esstream, sub))
{
if (esstream->error)
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
}
saw_seqgoppic = 3;
in_pic_data = 1;
ctx->saw_seqgoppic = 3;
ctx->in_pic_data = 1;
continue;
}
// Only looks for extension and user data if we saw sequence, gop
// or picture info before.
// This check needs to be before the "in_pic_data" part.
if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
// This check needs to be before the "ctx->in_pic_data" part.
if ( ctx->saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
{
if (!read_eau_info(ctx, esstream, saw_seqgoppic-1, sub))
if (!read_eau_info(ctx, esstream, ctx->saw_seqgoppic-1, sub))
{
if (esstream->error)
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
}
saw_seqgoppic = 0;
ctx->saw_seqgoppic = 0;
continue;
}
if (in_pic_data) // See comment in read_pic_data()
if (ctx->in_pic_data) // See comment in read_pic_data()
{
if (!read_pic_data(esstream))
{
if (esstream->error)
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
}
saw_seqgoppic = 0;
in_pic_data = 0;
ctx->saw_seqgoppic = 0;
ctx->in_pic_data = 0;
continue;
}
@@ -332,7 +317,7 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
{
mprint("\nUnexpected startcode: %02X\n", startcode);
}
no_bitstream_error = 0;
ctx->no_bitstream_error = 0;
return 0;
} while(1);
@@ -344,9 +329,9 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
// If a bitstream syntax problem occured the bitstream will
// point to after the problem, in case we run out of data the bitstream
// will point to where we want to restart after getting more.
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info\n");
debug("Read Sequence Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
@@ -358,7 +343,7 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
unsigned char *video_seq_start = esstream->pos;
sequence_header(ctx, esstream);
sequence_ext(esstream);
sequence_ext(ctx, esstream);
// FIXME: if sequence extension is missing this is not MPEG-2,
// or broken. Set bitstream error.
//extension_and_user_data(esstream);
@@ -372,7 +357,7 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
return 0;
}
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info - processed\n\n");
debug("Read Sequence Info - processed\n\n");
return 1;
}
@@ -381,9 +366,9 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Sequence header\n");
debug("Sequence header\n");
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -397,10 +382,12 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
unsigned aspect_ratio = (unsigned) read_bits(esstream,4);
unsigned frame_rate = (unsigned) read_bits(esstream,4);
#if 0
ctx->freport.width = hor_size;
ctx->freport.height = vert_size;
ctx->freport.aspect_ratio = aspect_ratio;
ctx->freport.frame_rate = frame_rate;
#endif
// Discard some information
read_bits(esstream, 18+1+10+1);
@@ -416,10 +403,10 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
return 0;
// If we got the whole sequence, process
if (hor_size!=current_hor_size ||
vert_size!=current_vert_size ||
aspect_ratio!=current_aspect_ratio ||
frame_rate!=current_frame_rate)
if (hor_size!= ctx->current_hor_size ||
vert_size!= ctx->current_vert_size ||
aspect_ratio!=ctx->current_aspect_ratio ||
frame_rate!= ctx->current_frame_rate)
{
// If horizontal/vertical size, framerate and/or aspect
// ratio are ilegal, we discard the
@@ -432,12 +419,6 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
aspect_ratio>0 && aspect_ratio<5)
{
mprint ("\n\nNew video information found");
if (pts_set==2)
{
unsigned cur_sec = (unsigned) ((current_pts - min_pts)
/ MPEG_CLOCK_FREQ);
mprint (" at %02u:%02u",cur_sec/60, cur_sec % 60);
}
mprint ("\n");
mprint ("[%u * %u] [AR: %s] [FR: %s]",
hor_size,vert_size,
@@ -445,21 +426,21 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
framerates_types[frame_rate]);
// No newline, force the output of progressive info in picture
// info part.
current_progressive_sequence = 2;
ctx->current_progressive_sequence = 2;
current_hor_size=hor_size;
current_vert_size=vert_size;
current_aspect_ratio=aspect_ratio;
current_frame_rate=frame_rate;
current_fps = framerates_values[current_frame_rate];
ctx->current_hor_size = hor_size;
ctx->current_vert_size = vert_size;
ctx->current_aspect_ratio = aspect_ratio;
ctx->current_frame_rate=frame_rate;
current_fps = framerates_values[ctx->current_frame_rate];
activity_video_info (hor_size,vert_size,
aspect_ratio_types[aspect_ratio],
framerates_types[frame_rate]);
}
else
{
dbg_print(CCX_DMT_VERBOSE, "\nInvalid sequence header:\n");
dbg_print(CCX_DMT_VERBOSE, "V: %u H: %u FR: %u AS: %u\n",
debug("\nInvalid sequence header:\n");
debug("V: %u H: %u FR: %u AS: %u\n",
vert_size, hor_size, frame_rate, aspect_ratio);
esstream->error = 1;
return 0;
@@ -474,9 +455,9 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int sequence_ext(struct bitstream *esstream)
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Sequence extension\n");
debug("Sequence extension\n");
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -484,7 +465,7 @@ static int sequence_ext(struct bitstream *esstream)
// Syntax check
if (next_start_code(esstream) != 0xB5)
{
dbg_print(CCX_DMT_VERBOSE, "sequence_ext: syntax problem.\n");
debug("sequence_ext: syntax problem.\n");
return 0;
}
@@ -498,7 +479,7 @@ static int sequence_ext(struct bitstream *esstream)
esstream->error = 1;
if (esstream->error)
dbg_print(CCX_DMT_VERBOSE, "sequence_ext: syntax problem.\n");
debug("sequence_ext: syntax problem.\n");
return 0;
}
@@ -506,9 +487,9 @@ static int sequence_ext(struct bitstream *esstream)
skip_bits(esstream, 8);
unsigned progressive_sequence = (unsigned) read_bits(esstream,1);
if (progressive_sequence!=current_progressive_sequence)
if (progressive_sequence!=ctx->current_progressive_sequence)
{
current_progressive_sequence = progressive_sequence;
ctx->current_progressive_sequence = progressive_sequence;
mprint(" [progressive: %s]\n\n",
(progressive_sequence ? "yes" : "no"));
}
@@ -527,9 +508,9 @@ static int sequence_ext(struct bitstream *esstream)
// If a bitstream syntax problem occured the bitstream will
// point to after the problem, in case we run out of data the bitstream
// will point to where we want to restart after getting more.
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
static int read_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info\n");
debug("Read GOP Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
@@ -552,7 +533,7 @@ static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
return 0;
}
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info - processed\n\n");
debug("Read GOP Info - processed\n\n");
return 1;
}
@@ -561,9 +542,9 @@ static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
static int gop_header(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
debug("GOP header\n");
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -592,21 +573,21 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
// do the padding.
// Flush buffered cc blocks before doing the housekeeping
if (has_ccdata_buffered)
if (ctx->has_ccdata_buffered)
{
process_hdcc(ctx, sub);
}
// Last GOPs pulldown frames
if ((current_pulldownfields>0) != (pulldownfields>0))
if ((ctx->current_pulldownfields>0) != (ctx->pulldownfields>0))
{
current_pulldownfields = pulldownfields;
dbg_print(CCX_DMT_VERBOSE, "Pulldown: %s", (pulldownfields ? "on" : "off"));
if (pulldownfields)
dbg_print(CCX_DMT_VERBOSE, " - %u fields in last GOP", pulldownfields);
dbg_print(CCX_DMT_VERBOSE, "\n");
ctx->current_pulldownfields = ctx->pulldownfields;
debug("Pulldown: %s", (ctx->pulldownfields ? "on" : "off"));
if (ctx->pulldownfields)
debug(" - %u fields in last GOP", ctx->pulldownfields);
debug("\n");
}
pulldownfields = 0;
ctx->pulldownfields = 0;
// Report synchronization jumps between GOPs. Warn if there
// are 20% or more deviation.
@@ -637,22 +618,22 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
// need the length of all frames.
if ( total_frames_count == 0 )
{ // If this is the first frame there cannot be an offset
fts_fc_offset = 0;
ctx->timing->fts_fc_offset = 0;
// first_gop_time.ms stays unchanged
}
else
{
fts_fc_offset = (LLONG) ((total_frames_count+1)
ctx->timing->fts_fc_offset = (LLONG) ((total_frames_count+1)
*1000.0/current_fps);
// Compensate for those written before
first_gop_time.ms -= fts_fc_offset;
first_gop_time.ms -= ctx->timing->fts_fc_offset;
}
dbg_print(CCX_DMT_TIME, "\nFirst GOP time: %02u:%02u:%02u:%03u %+lldms\n",
gtc.time_code_hours,
gtc.time_code_minutes, gtc.time_code_seconds,
(unsigned) (1000.0*gtc.time_code_pictures/current_fps),
fts_fc_offset);
ctx->timing->fts_fc_offset);
}
gop_time = gtc;
@@ -664,13 +645,11 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
// If we use GOP timing, reconstruct the PTS from the GOP
if (ccx_options.use_gop_as_pts==1)
{
current_pts = gtc.ms*(MPEG_CLOCK_FREQ/1000);
if (pts_set==0)
pts_set=1;
current_tref = 0;
set_current_pts(ctx->timing, gtc.ms*(MPEG_CLOCK_FREQ/1000));
ctx->timing->current_tref = 0;
frames_since_ref_time = 0;
set_fts();
fts_at_gop_start = get_fts_max();
set_fts(ctx->timing);
fts_at_gop_start = get_fts_max(ctx->timing);
}
else
{
@@ -679,14 +658,14 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
// next GOP.
// This effect will also lead to captions being one GOP early
// for DVD captions.
fts_at_gop_start = get_fts_max() + (LLONG) (1000.0/current_fps);
fts_at_gop_start = get_fts_max(ctx->timing) + (LLONG) (1000.0/current_fps);
}
if (ccx_options.debug_mask & CCX_DMT_TIME)
{
dbg_print(CCX_DMT_TIME, "\nNew GOP:\n");
dbg_print(CCX_DMT_TIME, "\nDrop frame flag: %u:\n", drop_frame_flag);
print_debug_timing();
print_debug_timing(ctx->timing);
}
}
@@ -698,9 +677,9 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
// If a bitstream syntax problem occured the bitstream will
// point to after the problem, in case we run out of data the bitstream
// will point to where we want to restart after getting more.
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
static int read_pic_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info\n");
debug("Read PIC Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
@@ -711,8 +690,8 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
// after getting more.
unsigned char *pic_info_start = esstream->pos;
pic_header(esstream);
pic_coding_ext(esstream);
pic_header(ctx, esstream);
pic_coding_ext(ctx, esstream);
if (esstream->error)
return 0;
@@ -723,45 +702,36 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
return 0;
}
// Analyse/use the picture information
static int maxtref; // Use to remember the temporal reference number
// A new anchor frame - flush buffered caption data. Might be flushed
// in GOP header already.
if (picture_coding_type==CCX_FRAME_TYPE_I_FRAME || picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
if (ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME || ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
{
if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
(temporal_reference != current_tref))
if (((ctx->picture_structure != 0x1) && (ctx->picture_structure != 0x2)) ||
(ctx->temporal_reference != ctx->timing->current_tref))
{
// NOTE: process_hdcc() needs to be called before set_fts() as it
// uses fts_now to re-create the timeline !!!!!
if (has_ccdata_buffered)
if (ctx->has_ccdata_buffered)
{
process_hdcc(ctx, sub);
}
anchor_hdcc(temporal_reference);
anchor_hdcc(ctx, ctx->temporal_reference);
}
}
current_tref = temporal_reference;
current_picture_coding_type = picture_coding_type;
ctx->timing->current_tref = ctx->temporal_reference;
ctx->timing->current_picture_coding_type = ctx->picture_coding_type;
// We mostly use PTS, but when the GOP mode is enabled do not set
// the FTS time here.
if (ccx_options.use_gop_as_pts!=1)
{
set_fts(); // Initialize fts
set_fts(ctx->timing); // Initialize fts
}
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u) - tref: %2d - %s since tref0/GOP: %2u/%2u",
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (current_pts), temporal_reference,
pict_types[picture_coding_type],
(unsigned) (frames_since_ref_time),
(unsigned) (ctx->frames_since_last_gop));
dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", top_field_first,
repeat_first_field, progressive_frame);
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", ctx->top_field_first,
ctx->repeat_first_field, ctx->progressive_frame);
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts(ctx->timing, ctx->current_field)));
// Set min_pts/sync_pts according to the current time stamp.
// Use fts_at_gop_start as reference when a GOP header was seen
@@ -770,10 +740,10 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
// header. Use the current FTS values as reference.
// Note: If a GOP header was present the reference time is from
// the beginning of the GOP, otherwise it is now.
if(temporal_reference == 0)
if(ctx->temporal_reference == 0)
{
ctx->last_gop_length = maxtref + 1;
maxtref = temporal_reference;
ctx->last_gop_length = ctx->maxtref + 1;
ctx->maxtref = ctx->temporal_reference;
// frames_since_ref_time is used in set_fts()
@@ -786,20 +756,20 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
else
{
// No GOP header, use the current values
fts_at_gop_start=get_fts();
fts_at_gop_start = get_fts(ctx->timing, ctx->current_field);
frames_since_ref_time = 0;
}
if (ccx_options.debug_mask & CCX_DMT_TIME)
{
dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
print_debug_timing();
print_debug_timing(ctx->timing);
}
ctx->saw_gop_header = 0; // Reset the value
}
if ( !ctx->saw_gop_header && picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
if ( !ctx->saw_gop_header && ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
{
// A new GOP beginns with an I-frame. Lets hope there are
// never more than one per GOP
@@ -807,20 +777,20 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
}
// Set maxtref
if( temporal_reference > maxtref ) {
maxtref = temporal_reference;
if (maxtref+1 > ctx->max_gop_length)
ctx->max_gop_length = maxtref+1;
if( ctx->temporal_reference > ctx->maxtref ) {
ctx->maxtref = ctx->temporal_reference;
if (ctx->maxtref + 1 > ctx->max_gop_length)
ctx->max_gop_length = ctx->maxtref + 1;
}
unsigned extraframe = 0;
if (repeat_first_field)
if (ctx->repeat_first_field)
{
pulldownfields++;
ctx->pulldownfields++;
ctx->total_pulldownfields++;
if ( current_progressive_sequence || !(ctx->total_pulldownfields%2) )
if ( ctx->current_progressive_sequence || !(ctx->total_pulldownfields%2) )
extraframe = 1;
if ( current_progressive_sequence && top_field_first )
if ( ctx->current_progressive_sequence && ctx->top_field_first )
extraframe = 2;
dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
ctx->total_pulldownfields, extraframe);
@@ -831,7 +801,7 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
ctx->frames_since_last_gop += 1+extraframe;
frames_since_ref_time += 1+extraframe;
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info - processed\n\n");
debug("Read PIC Info - processed\n\n");
return 1;
}
@@ -840,9 +810,9 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int pic_header(struct bitstream *esstream)
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "PIC header\n");
debug("PIC header\n");
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -851,16 +821,16 @@ static int pic_header(struct bitstream *esstream)
if (read_u32(esstream) != 0x00010000) // LSB first (0x00000100)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
temporal_reference = (int) read_bits(esstream,10);
picture_coding_type = (enum ccx_frame_type) read_bits(esstream,3);
ctx->temporal_reference = (int) read_bits(esstream,10);
ctx->picture_coding_type = (enum ccx_frame_type) read_bits(esstream,3);
// Discard vbv_delay
skip_bits(esstream, 16);
// Discard some information
if (picture_coding_type == 2 || picture_coding_type == 3)
if (ctx->picture_coding_type == 2 || ctx->picture_coding_type == 3)
skip_bits(esstream, 4);
if (picture_coding_type == 3)
if (ctx->picture_coding_type == 3)
skip_bits(esstream, 4);
// extra_information
@@ -872,15 +842,15 @@ static int pic_header(struct bitstream *esstream)
if (esstream->bitsleft < 0)
return 0;
if ( !(picture_coding_type==CCX_FRAME_TYPE_I_FRAME
|| picture_coding_type==CCX_FRAME_TYPE_P_FRAME
|| picture_coding_type==CCX_FRAME_TYPE_B_FRAME))
if ( !(ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME
|| ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME
|| ctx->picture_coding_type==CCX_FRAME_TYPE_B_FRAME))
{
if (esstream->bitsleft >= 0) // When bits left, this is wrong
esstream->error = 1;
if (esstream->error)
dbg_print(CCX_DMT_VERBOSE, "pic_header: syntax problem.\n");
debug("pic_header: syntax problem.\n");
return 0;
}
@@ -891,9 +861,9 @@ static int pic_header(struct bitstream *esstream)
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int pic_coding_ext(struct bitstream *esstream)
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Picture coding extension %lld\n", esstream->bitsleft);
debug("Picture coding extension %lld\n", esstream->bitsleft);
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -901,7 +871,7 @@ static int pic_coding_ext(struct bitstream *esstream)
// Syntax check
if (next_start_code(esstream) != 0xB5)
{
dbg_print(CCX_DMT_VERBOSE, "pic_coding_ext: syntax problem.\n");
debug("pic_coding_ext: syntax problem.\n");
return 0;
}
@@ -915,18 +885,18 @@ static int pic_coding_ext(struct bitstream *esstream)
esstream->error = 1;
if (esstream->error)
dbg_print(CCX_DMT_VERBOSE, "pic_coding_ext: syntax problem.\n");
debug("pic_coding_ext: syntax problem.\n");
return 0;
}
// Discard some information
skip_bits(esstream, 4*4+2);
picture_structure = (unsigned int) read_bits(esstream, 2);
top_field_first = (unsigned int) read_bits(esstream, 1);
ctx->picture_structure = (unsigned int) read_bits(esstream, 2);
ctx->top_field_first = (unsigned int) read_bits(esstream, 1);
skip_bits(esstream, 5*1);
repeat_first_field = (unsigned int) read_bits(esstream, 1);
ctx->repeat_first_field = (unsigned int) read_bits(esstream, 1);
skip_bits(esstream, 1); // chroma
progressive_frame = (unsigned int) read_bits(esstream, 1);
ctx->progressive_frame = (unsigned int) read_bits(esstream, 1);
unsigned composite_display = (unsigned int) read_bits(esstream,1);
if (composite_display)
skip_bits(esstream, 1+3+1+7+8);
@@ -934,7 +904,7 @@ static int pic_coding_ext(struct bitstream *esstream)
if (esstream->bitsleft < 0)
return 0;
dbg_print(CCX_DMT_VERBOSE, "Picture coding extension - processed\n");
debug("Picture coding extension - processed\n");
// Read complete
return 1;
@@ -945,9 +915,9 @@ static int pic_coding_ext(struct bitstream *esstream)
// If a bitstream syntax problem occured the bitstream will
// point to after the problem, in case we run out of data the bitstream
// will point to where we want to restart after getting more.
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
static int read_eau_info(struct lib_cc_decode* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info\n");
debug("Read Extension and User Info\n");
// We only get here after seeing that start code
unsigned char *tst = next_bytes(esstream, 4);
@@ -962,14 +932,14 @@ static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, in
if( !extension_and_user_data(ctx, esstream, udtype, sub) )
{
if (esstream->error)
dbg_print(CCX_DMT_VERBOSE, "\nWarning: Retry while reading Extension and User Data!\n");
debug("\nWarning: Retry while reading Extension and User Data!\n");
else
dbg_print(CCX_DMT_VERBOSE, "\nBitstream problem while reading Extension and User Data!\n");
debug("\nBitstream problem while reading Extension and User Data!\n");
return 0;
}
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info - processed\n\n");
debug("Read Extension and User Info - processed\n\n");
return 1;
}
@@ -978,9 +948,9 @@ static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, in
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
static int extension_and_user_data(struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data(%d)\n", udtype);
debug("Extension and user data(%d)\n", udtype);
if (esstream->error || esstream->bitsleft <= 0)
return 0;
@@ -1013,13 +983,13 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
if (esstream->error)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - syntax problem\n");
debug("Extension and user data - syntax problem\n");
return 0;
}
if (esstream->bitsleft < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - inclomplete\n");
debug("Extension and user data - inclomplete\n");
// Restore to where we need to continue
init_bitstream(esstream, eau_start, esstream->end);
esstream->bitsleft = -1; // Redundant
@@ -1034,7 +1004,7 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
}
else
{
dbg_print(CCX_DMT_VERBOSE, "Skip %d bytes extension data.\n",
debug("Skip %d bytes extension data.\n",
esstream->pos - dstart);
}
// If we get here esstream points to the end of a block
@@ -1047,19 +1017,19 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
if (esstream->error)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - syntax problem\n");
debug("Extension and user data - syntax problem\n");
return 0;
}
if (esstream->bitsleft < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - inclomplete\n");
debug("Extension and user data - inclomplete\n");
// Restore to where we need to continue
init_bitstream(esstream, eau_start, esstream->end);
esstream->bitsleft = -1; // Redundant
return 0;
}
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - processed\n");
debug("Extension and user data - processed\n");
// Read complete
return 1;
@@ -1072,7 +1042,7 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
// will point to where we want to restart after getting more.
static int read_pic_data(struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Read PIC Data\n");
debug("Read PIC Data\n");
uint8_t startcode = next_start_code(esstream);
@@ -1083,7 +1053,7 @@ static int read_pic_data(struct bitstream *esstream)
// We only get here after seeing that start code
if (startcode < 0x01 || startcode > 0xAF)
{
dbg_print(CCX_DMT_VERBOSE, "Read Pic Data - processed0\n");
debug("Read Pic Data - processed0\n");
return 1;
}
@@ -1103,9 +1073,9 @@ static int read_pic_data(struct bitstream *esstream)
init_bitstream(esstream, slice_start, esstream->end);
if ( esstream->error )
dbg_print(CCX_DMT_VERBOSE, "read_pic_data: syntax problem.\n");
debug("read_pic_data: syntax problem.\n");
else
dbg_print(CCX_DMT_VERBOSE, "read_pic_data: reached end of bitstream.\n");
debug("read_pic_data: reached end of bitstream.\n");
return 0;
}
@@ -1125,7 +1095,7 @@ static int read_pic_data(struct bitstream *esstream)
return 0;
}
dbg_print(CCX_DMT_VERBOSE, "Read Pic Data - processed\n");
debug("Read Pic Data - processed\n");
return 1;
}

View File

@@ -9,10 +9,8 @@
// 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);
// Shall not happen
@@ -25,7 +23,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
}
// Do something
ctx->stat_numuserheaders++;
//ctx->stat_numuserheaders++;
//header+=4;
unsigned char *ud_header = next_bytes(ustream, 4);
@@ -40,7 +38,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
{
ctx->stat_dvdccheaders++;
// ctx->stat_dvdccheaders++;
// Probably unneeded, but keep looking for extra caption blocks
int maybeextracb = 1;
@@ -66,8 +64,8 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
// 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);
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++)
@@ -94,7 +92,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(dec_ctx, data, sub);
do_cb(ctx, data, sub);
rcbcount++;
}
else
@@ -125,7 +123,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(dec_ctx, data, sub);
do_cb(ctx, data, sub);
ecbcount++;
}
else
@@ -146,7 +144,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
{
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
ctx->stat_scte20ccheaders++;
// ctx->stat_scte20ccheaders++;
read_bytes(ustream, 2); // "03 01"
unsigned cc_count = (unsigned int) read_bits(ustream,5);
@@ -186,7 +184,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
field_number = (field_number - 1) & 0x01;
// top_field_first also affects to which field the caption
// belongs.
if(!top_field_first)
if(!ctx->top_field_first)
field_number ^= 0x01;
cc_data[j*3]=0x04|(field_number);
cc_data[j*3+1]=reverse8(cc_data1);
@@ -194,7 +192,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
}
}
cc_data[cc_count*3]=0xFF;
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
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");
}
@@ -207,26 +205,28 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
&& 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);
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(dec_ctx, data, sub);
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++;
// ctx->stat_hdtv++;
read_bytes(ustream, 4); // "47 41 39 34"
@@ -266,7 +266,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
// 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);
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");
}
@@ -287,7 +287,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
ctx->stat_dishheaders++;
// ctx->stat_dishheaders++;
read_bytes(ustream, 2); // "05 02"
@@ -346,7 +346,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
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;
@@ -371,7 +371,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
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;
@@ -436,7 +436,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
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;
@@ -452,7 +452,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
{
// Either a documentation or more examples are needed.
ctx->stat_divicom++;
// ctx->stat_divicom++;
unsigned char data[3];
@@ -462,7 +462,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(dec_ctx, data, sub);
do_cb(ctx, data, sub);
// This is probably incomplete!
}
else

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,7 +1,8 @@
#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};
@@ -11,12 +12,12 @@ int iResult = 0;
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;
@@ -27,22 +28,22 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files fai
{
LLONG ts=0;
int h;
for (int i=0;i<ctx->num_input_files;i++)
for (int i = 0; i < ctx->num_input_files; i++)
{
if (0 == strcmp(ctx->inputfile[i],"-")) // Skip stdin
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)
if (h == -1)
{
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
mprint ("\rUnable to open %s\r\n", ctx->inputfile[i]);
return -1;
}
if (!ccx_options.live_stream)
ts+=getfilesize (h);
ts += getfilesize (h);
close (h);
}
return ts;
@@ -50,64 +51,44 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files fai
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->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->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;
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;
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- */
@@ -117,223 +98,206 @@ 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);
if(ctx->infd < 0)
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
return 1;
}
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)
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->past, ctx->inputsize);
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->past=0; // Reset always or at the end we'll have double the size
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;
}
void position_sanity_check (void)
{
#ifdef SANITY_CHECK
if (in!=-1)
}
for (;;)
{
LLONG realpos=LSEEK (in,0,SEEK_CUR);
if (realpos!=ctx->past-filebuffer_pos+bytesinbuffer)
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]);
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
{
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,ctx->past);
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
}
}
#endif
}
int init_file_buffer(void)
{
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;
}
void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
void position_sanity_check (int in)
{
position_sanity_check();
if (offset<0)
#ifdef SANITY_CHECK
if (in!=-1)
{
filebuffer_pos+=offset;
if (filebuffer_pos<0)
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(struct ccx_demuxer *ctx)
{
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 ccx_demuxer *ctx, int offset)
{
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 ((filebuffer_pos+ctx->startbytes_pos) < 0)
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+=filebuffer_pos;
filebuffer_pos=0;
ctx->startbytes_pos += ctx->filebuffer_pos;
ctx->filebuffer_pos = 0;
}
}
else
{
buffered_read_opt (ctx, NULL, offset);
position_sanity_check();
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;
ccx_options.live_stream = 0;
return;
}
if (ccx_options.live_stream==-1) // Just sleep, no timeout to check
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;
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)
size_t copied = 0;
time_t seconds = 0;
position_sanity_check(ctx->infd);
if (ccx_options.live_stream > 0)
time (&seconds);
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
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);
int eof = (ctx->infd == -1);
while ((!eof || ccx_options.live_stream) && bytes)
{
@@ -343,8 +307,8 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
// for the data to come up
sleepandchecktimeout (seconds);
}
size_t ready = bytesinbuffer-filebuffer_pos;
if (ready==0) // We really need to read more
size_t ready = ctx->bytesinbuffer - ctx->filebuffer_pos;
if (ready == 0) // We really need to read more
{
if (!ccx_options.buffer_input)
{
@@ -356,25 +320,27 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
{
// No code for network support here, because network is always
// buffered - if here, then it must be files.
if (buffer!=NULL) // Read
if (buffer != NULL) // Read
{
i=read (ctx->infd,buffer,bytes);
i = read (ctx->infd, buffer, bytes);
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
buffer+=i;
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
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);
np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving
i = (int) (np - op);
}
if (i==0 && ccx_options.live_stream)
// 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)
if (ccx_options.input_source == CCX_DS_STDIN)
{
ccx_options.live_stream = 0;
break;
@@ -386,35 +352,37 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
}
else
{
copied+=i;
bytes-=i;
copied += i;
bytes -= i;
}
}
while ((i || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))) && bytes);
(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 = bytesinbuffer > 8 ? 8 : bytesinbuffer;
memmove (filebuffer,filebuffer+(FILEBUFFERSIZE-keep),keep);
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);
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, copied)))
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied)))
eof = 1;
}
filebuffer_pos = keep;
bytesinbuffer=(int) i + keep;
ctx->filebuffer_pos = keep;
ctx->bytesinbuffer = (int) i + keep;
ready = i;
}
int copy = (int) (ready>=bytes ? bytes:ready);
@@ -422,63 +390,97 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
{
if (buffer != NULL)
{
memcpy (buffer, filebuffer+filebuffer_pos, copy);
buffer+=copy;
memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, copy);
buffer += copy;
}
filebuffer_pos+=copy;
bytes-=copy;
copied+=copy;
ctx->filebuffer_pos += copy;
bytes -= copy;
copied += copy;
}
}
return copied;
}
else // Read without buffering
{
if (buffer!=NULL)
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))))
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)
else if (i == 0)
sleepandchecktimeout (seconds);
else
{
copied+=i;
bytes-=i;
buffer+=i;
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)
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
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)
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);
switch_to_next_file(ctx->parent, 0);
else
break;
}
}
}
return copied;
}
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(
@@ -16,13 +21,17 @@ static struct ccx_decoders_common_settings_t *init_decoder_setting(
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->trim_subs = opt->trim_subs;
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)
@@ -31,121 +40,77 @@ static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setti
}
static int init_ctx_input(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
static int init_ctx_outbase(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
{
int len;
char *file,*c;
char *file;
switch (opt->input_source)
if (opt->output_filename)
{
case CCX_DS_FILE:
if(!ctx->inputfile || !ctx->inputfile[0]) {
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;
}
len = strlen (ctx->inputfile[0]) + 1;
file = ctx->inputfile[0];
break;
case CCX_DS_STDIN:
len = strlen ("stdin") + 1;
file = "stdin";
break;
case CCX_DS_NETWORK:
case CCX_DS_TCP:
len = strlen ("network") + 1;
file = "network";
break;
default:
errno = EINVAL;
return -1;
}
ctx->basefilename = get_basename(file);
}
ctx->basefilename = (char *) malloc(len);
if (ctx->basefilename == NULL) {
return -1;
}
strcpy (ctx->basefilename, file);
for (c = ctx->basefilename + len - 1; c > ctx->basefilename && *c != '.'; c--)
{;} // Get last .
if (*c == '.')
*c = 0;
return 0;
}
static int init_ctx_extension(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
struct encoder_ctx *get_encoder_by_pn(struct lib_ccx_ctx *ctx, int pn)
{
switch (opt->write_format)
struct encoder_ctx *enc_ctx;
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
{
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:
mprint ("write_format doesn't have any legal value, this is a bug.\n");
errno = EINVAL;
return -1;
if (enc_ctx->program_number == pn)
return enc_ctx;
}
return 0;
return NULL;
}
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
{
int ret = 0;
struct lib_ccx_ctx *ctx;
struct ccx_decoder_608_report *report_608;
struct ccx_decoders_common_settings_t *dec_setting;
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.
// Set logging functions for libraries
ccx_common_logging.debug_ftn = &dbg_print;
@@ -154,51 +119,29 @@ 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);
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;
ret = init_ctx_input(opt, ctx);
ret = init_ctx_outbase(opt, ctx);
if (ret < 0) {
goto end;
}
ret = init_ctx_extension(opt, ctx);
if (ret < 0) {
goto end;
}
// 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->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);
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
ctx->cc_to_stdout = opt->cc_to_stdout;
@@ -207,8 +150,21 @@ struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
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 < 0) {
if (ret != EXIT_OK)
{
free(ctx);
return NULL;
}
@@ -218,18 +174,216 @@ end:
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.77"
#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,7 +48,6 @@ 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
ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
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
@@ -138,18 +59,16 @@ struct ccx_s_teletext_config {
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;
@@ -157,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;
@@ -171,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
@@ -212,22 +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.
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];
@@ -235,47 +122,22 @@ 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 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 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);
@@ -288,51 +150,31 @@ 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
@@ -342,46 +184,47 @@ 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);
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 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, struct cc_subtitle *sub);
// stream_functions.c
int isValidMP4Box(unsigned char *buffer, long position, long *nextBoxLocation, int *boxScore);
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);
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, ...);
@@ -399,91 +242,47 @@ 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, struct cc_subtitle *sub);
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, struct cc_subtitle *sub);
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,35 +120,21 @@ 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;
}
int net_send_cc(const unsigned char *data, int len, void *private_data, struct cc_subtitle *sub)
@@ -145,17 +145,186 @@ int net_send_cc(const unsigned char *data, int len, void *private_data, struct c
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 rc;
printf("Can't send BIN data\n");
return -1;
}
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
/* nanosleep((struct timespec[]){{0, 4000000}}, NULL); */
/* Sleep(100); */
return rc;
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;
}
/*
@@ -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,11 +3,24 @@
#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);
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);
int start_upd_srv(const char *addr, unsigned port);

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,19 +6,28 @@
#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;
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)
{
return CCX_COMMON_EXIT_FILE_CREATION_FAILED;
}
return EXIT_OK;
}
int writeraw (const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub)
{
ccx_decoder_608_context *context = private_data;
unsigned char* sub_data = NULL;
// Don't do anything for empty data
if (data==NULL)
@@ -38,15 +47,9 @@ int writeraw (const unsigned char *data, int length, void *private_data, struct
return EXIT_SUCCESS;
}
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile)
{
if (closefile && wb!=NULL && wb->fh!=-1 && !ctx->cc_to_stdout)
close (wb->fh);
}
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,
@@ -55,43 +58,43 @@ void writeDVDraw (const unsigned char *data1, int length1,
if (datacount==0)
{
write (wb->fh,DVD_HEADER,sizeof (DVD_HEADER));
writeraw (DVD_HEADER, sizeof (DVD_HEADER), NULL, sub);
if (loopcount==1)
write (wb->fh,lc1,sizeof (lc1));
writeraw (lc1, sizeof (lc1), NULL, sub);
if (loopcount==2)
write (wb->fh,lc2,sizeof (lc2));
writeraw (lc2, sizeof (lc2), NULL, sub);
if (loopcount==3)
{
write (wb->fh,lc3,sizeof (lc3));
writeraw (lc3, sizeof (lc3), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
writeraw (data2, length2, NULL, sub);
}
if (loopcount>3)
{
write (wb->fh,lc4,sizeof (lc4));
writeraw (lc4, sizeof (lc4), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
writeraw (data2, length2, NULL, sub);
}
}
datacount++;
write (wb->fh,lc5,sizeof (lc5));
writeraw (lc5, sizeof (lc5), NULL, sub);
if (data1 && length1)
write (wb->fh,data1,length1);
writeraw (data1, length1, NULL, sub);
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
((loopcount > 3) && (datacount < 15)))
{
write (wb->fh,lc6,sizeof (lc6));
writeraw (lc6, sizeof(lc6), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
writeraw (data2, length2, NULL, sub);
}
else
{
if (loopcount==1)
{
write (wb->fh,lc6,sizeof (lc6));
writeraw (lc6, sizeof(lc6), NULL, sub);
if (data2 && length2)
write (wb->fh,data2,length2);
writeraw (data2, length2, NULL, sub);
}
loopcount++;
datacount=0;
@@ -102,25 +105,24 @@ void writeDVDraw (const unsigned char *data1, int length1,
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 && ctx->extract != 2)
{
ctx->writedata(data1, length1, field_1, sub);
ctx->current_field = 1;
ctx->writedata(data1, length1, ctx, sub);
}
if (length2)
{
ctx->current_field = 2;
if (ctx->extract != 1)
ctx->writedata(data2, length2, field_2, sub);
ctx->writedata(data2, length2, ctx, sub);
else // User doesn't want field 2 data, but we want XDS.
ctx->writedata (data2,length2,NULL, sub);
{
ctx->writedata (data2, length2, ctx, sub);
}
}
}
}
@@ -130,12 +132,11 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt
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

View File

@@ -1,60 +1,13 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "utility.h"
#include "activity.h"
#include "ccx_encoders_helpers.h"
#include "ccx_common_common.h"
#include "ccx_decoders_708.h"
static int inputfile_capacity=0;
static const char *DEF_VAL_STARTCREDITSNOTBEFORE="0";
static const char *DEF_VAL_STARTCREDITSNOTAFTER="5:00"; // To catch the theme after the teaser in TV shows
static const char *DEF_VAL_STARTCREDITSFORATLEAST="2";
static const char *DEF_VAL_STARTCREDITSFORATMOST="5";
static const char *DEF_VAL_ENDCREDITSFORATLEAST="2";
static const char *DEF_VAL_ENDCREDITSFORATMOST="5";
int stringztoms (const char *s, struct ccx_boundary_time *bt)
{
unsigned ss=0, mm=0, hh=0;
int value=-1;
int colons=0;
const char *c=s;
while (*c)
{
if (*c==':')
{
if (value==-1) // : at the start, or ::, etc
return -1;
colons++;
if (colons>2) // Max 2, for HH:MM:SS
return -1;
hh=mm;
mm=ss;
ss=value;
value=-1;
}
else
{
if (!isdigit (*c)) // Only : or digits, so error
return -1;
if (value==-1)
value=*c-'0';
else
value=value*10+*c-'0';
}
c++;
}
hh = mm;
mm = ss;
ss = value;
if (mm > 59 || ss > 59)
return -1;
bt->set = 1;
bt->hh = hh;
bt->mm = mm;
bt->ss = ss;
LLONG secs = (hh * 3600 + mm * 60 + ss);
bt->time_in_ms = secs*1000;
return 0;
}
int process_cap_file (char *filename)
{
int ret = 0;
@@ -218,11 +171,14 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
if (strcmp (format,"srt")==0)
opt->write_format=CCX_OF_SRT;
else if (strcmp(format, "webvtt") == 0)
opt->write_format = CCX_OF_WEBVTT;
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
opt->write_format=CCX_OF_SAMI;
else if (strcmp (format,"transcript")==0 || strcmp (format,"txt")==0)
{
opt->write_format=CCX_OF_TRANSCRIPT;
opt->settings_dtvcc.no_rollup = 1;
}
else if (strcmp (format,"timedtranscript")==0 || strcmp (format,"ttxt")==0)
{
@@ -239,10 +195,10 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
}
else if (strcmp (format,"report")==0)
{
opt->write_format=CCX_OF_NULL;
opt->messages_target=0;
opt->print_file_reports=1;
opt->ts_autoprogram=1;
opt->write_format = CCX_OF_NULL;
opt->messages_target = 0;
opt->print_file_reports = 1;
opt->demux_cfg.ts_allprogram = CCX_TRUE;
}
else if (strcmp (format,"raw")==0)
opt->write_format=CCX_OF_RAW;
@@ -256,6 +212,8 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
opt->write_format=CCX_OF_DVDRAW;
else if (strcmp (format,"spupng")==0)
opt->write_format=CCX_OF_SPUPNG;
else if (strcmp (format,"simplexml")==0)
opt->write_format=CCX_OF_SIMPLE_XML;
else
fatal (EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format);
}
@@ -264,39 +222,39 @@ void set_input_format (struct ccx_s_options *opt, const char *format)
{
if (opt->input_source == CCX_DS_TCP && strcmp(format, "bin")!=0)
{
mprint("Intput format is changed to bin\n");
mprint("Input format is changed to bin\n");
format = "bin";
}
while (*format=='-')
format++;
if (strcmp (format,"es")==0) // Does this actually do anything?
opt->auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
opt->demux_cfg.auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
else if (strcmp(format, "ts") == 0)
{
opt->auto_stream = CCX_SM_TRANSPORT;
opt->m2ts = 0;
opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT;
opt->demux_cfg.m2ts = 0;
}
else if (strcmp(format, "m2ts") == 0)
{
opt->auto_stream = CCX_SM_TRANSPORT;
opt->m2ts = 1;
opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT;
opt->demux_cfg.m2ts = 1;
}
else if (strcmp (format,"ps")==0 || strcmp (format,"nots")==0)
opt->auto_stream = CCX_SM_PROGRAM;
opt->demux_cfg.auto_stream = CCX_SM_PROGRAM;
else if (strcmp (format,"asf")==0 || strcmp (format,"dvr-ms")==0)
opt->auto_stream = CCX_SM_ASF;
opt->demux_cfg.auto_stream = CCX_SM_ASF;
else if (strcmp (format,"wtv")==0)
opt->auto_stream = CCX_SM_WTV;
opt->demux_cfg.auto_stream = CCX_SM_WTV;
else if (strcmp (format,"raw")==0)
opt->auto_stream = CCX_SM_MCPOODLESRAW;
opt->demux_cfg.auto_stream = CCX_SM_MCPOODLESRAW;
else if (strcmp (format,"bin")==0)
opt->auto_stream = CCX_SM_RCWT;
opt->demux_cfg.auto_stream = CCX_SM_RCWT;
else if (strcmp (format,"mp4")==0)
opt->auto_stream = CCX_SM_MP4;
opt->demux_cfg.auto_stream = CCX_SM_MP4;
#ifdef WTV_DEBUG
else if (strcmp (format,"hex")==0)
opt->auto_stream = CCX_SM_HEX_DUMP;
opt->demux_cfg.auto_stream = CCX_SM_HEX_DUMP;
#endif
else
fatal (EXIT_MALFORMED_PARAMETER, "Unknown input file format: %s\n", format);
@@ -337,6 +295,8 @@ void usage (void)
mprint ("Output will be one single file (either raw or srt). Use this if you made your\n");
mprint ("recording in several cuts (to skip commercials for example) but you want one\n");
mprint ("subtitle file with contiguous timing.\n\n");
mprint ("Effect output files\n");
mprint (" -outinterval x output in interval of x seconds\n");
mprint ("Network support:\n");
mprint (" -udp port: Read the input via UDP (listening in the specified port)\n");
mprint (" instead of reading a file.\n\n");
@@ -357,10 +317,19 @@ void usage (void)
mprint (" (DEFAULT is -1)\n");
mprint (" -cc2: When in srt/sami mode, process captions in channel 2\n");
mprint (" instead of channel 1.\n");
mprint ("-svc --service N,N...: Enabled CEA-708 captions processing for the listed\n");
mprint (" services. The parameter is a command delimited list\n");
mprint ("-svc --service N1[cs1],N2[cs2]...:\n");
mprint (" Enable CEA-708 (DTVCC) captions processing for the listed\n");
mprint (" services. The parameter is a comma delimited list\n");
mprint (" of services numbers, such as \"1,2\" to process the\n");
mprint (" primary and secondary language services.\n");
mprint (" Pass \"all\" to process all services found.\n");
mprint ("\n");
mprint (" If captions in a service are stored in 16-bit encoding, you can\n");
mprint (" specify what charset or encoding was used. Pass its name after\n");
mprint (" service number (e.g. \"1[EUC-KR],3\" or \"all[EUC-KR]\") and it will\n");
mprint (" encode specified charset to UTF-8 using iconv. See iconv documentation\n");
mprint (" to check if required encoding/charset is supported.\n");
mprint ("\n");
mprint ("In general, if you want English subtitles you don't need to use these options\n");
mprint ("as they are broadcast in field 1, channel 1. If you want the second language\n");
mprint ("(usually Spanish) you may need to try -2, or -cc2, or both.\n\n");
@@ -386,6 +355,7 @@ void usage (void)
mprint (" -out=format\n\n");
mprint (" where format is one of these:\n");
mprint (" srt -> SubRip (default, so not actually needed).\n");
mprint (" webvtt -> WebVTT format\n");
mprint (" sami -> MS Synchronized Accesible Media Interface.\n");
mprint (" bin -> CC data in CCExtractor's own binary format.\n");
mprint (" raw -> CC data in McPoodle's Broadcast format.\n");
@@ -402,7 +372,7 @@ void usage (void)
mprint (" report -> Prints to stdout information about captions\n");
mprint (" in specified input. Don't produce any file\n");
mprint (" output\n\n");
mprint (" Note: Teletext output can only be srt, txt or ttxt for now.\n\n");
mprint (" Note: Teletext output can only be srt, webvtt, txt or ttxt for now.\n\n");
mprint ("Options that affect how input files will be processed.\n");
@@ -496,11 +466,11 @@ void usage (void)
mprint (" -utf8: Encode subtitles in UTF-8 (no longer needed.\n");
mprint (" because UTF-8 is now the default).\n");
mprint (" -latin1: Encode subtitles in Latin-1\n");
mprint (" -nofc --nofontcolor: For .srt/.sami, don't add font color tags.\n");
mprint ("-nots --notypesetting: For .srt/.sami, don't add typesetting tags.\n");
mprint (" -nofc --nofontcolor: For .srt/.sami/.vtt, don't add font color tags.\n");
mprint ("-nots --notypesetting: For .srt/.sami/.vtt, don't add typesetting tags.\n");
mprint (" -trim: Trim lines.\n");
mprint (" -dc --defaultcolor: Select a different default color (instead of\n");
mprint (" white). This causes all output in .srt/.smi\n");
mprint (" white). This causes all output in .srt/.smi/.vtt\n");
mprint (" files to have a font tag, which makes the files\n");
mprint (" larger. Add the color you want in RGB, such as\n");
mprint (" -dc #FF0000 for red.\n");
@@ -532,9 +502,10 @@ void usage (void)
mprint (" terminator.\n");
mprint (" -autodash: Based on position on screen, attempt to determine\n");
mprint (" the different speakers and a dash (-) when each\n");
mprint (" of them talks (.srt only, -trim required).\n");
mprint (" -xmltv: produce an XMLTV file containing the EPG data from\n");
mprint (" the source TS file.\n\n");
mprint (" of them talks (.srt/.vtt only, -trim required).\n");
mprint (" -xmltv mode: produce an XMLTV file containing the EPG data from\n");
mprint (" the source TS file. Mode: 1 = full output\n");
mprint (" 2 = live output. 3 = both\n\n");
mprint ("Options that affect how ccextractor reads and writes (buffering):\n");
@@ -566,7 +537,7 @@ void usage (void)
mprint ("Options that affect timing:\n");
mprint (" -delay ms: For srt/sami, add this number of milliseconds to\n");
mprint (" -delay ms: For srt/sami/webvtt, add this number of milliseconds to\n");
mprint (" all times. For example, -delay 400 makes subtitles\n");
mprint (" appear 400ms late. You can also use negative numbers\n");
mprint (" to make subs appear early.\n");
@@ -592,14 +563,14 @@ void usage (void)
mprint ("Options that affect which codec is to be used have to be searched in input\n");
mprint (" If codec type is not selected then first elementry stream suitable for \n"
mprint (" If codec type is not selected then first elementary stream suitable for \n"
" subtitle is selected, please consider -teletext -noteletext override this\n"
" option.\n"
" -codec dvbsub select the dvb subtitle from all elementry stream,\n"
" -codec dvbsub select the dvb subtitle from all elementary stream,\n"
" if stream of dvb subtitle type is not found then \n"
" nothing is selected and no subtitle is generated\n"
" -nocodec dvbsub ignore dvb subtitle and follow default behaviour\n"
" -codec teletext select the teletext subtitle from elementry stream\n"
" -codec teletext select the teletext subtitle from elementary stream\n"
" -nocodec teletext ignore teletext subtitle\n"
" NOTE: option given in form -foo=bar ,-foo = bar and --foo=bar are invalid\n"
" valid option are only in form -foo bar\n"
@@ -658,6 +629,7 @@ void usage (void)
mprint (" file. (Only for TS/ASF files at the moment.)\n");
mprint (" -parsePAT: Print Program Association Table dump.\n");
mprint (" -parsePMT: Print Program Map Table dump.\n");
mprint(" -dumpdef: Hex-dump defective TS packets.\n");
mprint (" -investigate_packets: If no CC packets are detected based on the PMT, try\n");
mprint (" to find data in all packets by scanning.\n\n");
@@ -738,30 +710,95 @@ void usage (void)
mprint(" ...\n");
}
void parse_708services (char *s)
void parse_708_services (struct ccx_s_options *opts, char *s)
{
char *c, *e, *l;
if (s==NULL)
const char *all = "all";
size_t all_len = strlen(all);
int diff = strncmp(s, all, all_len);
if (!diff) {
size_t s_len = strlen(s);
char *charset = NULL;
if (s_len > all_len + 2) // '[' and ']'
charset = strndup(s + all_len + 1, s_len - all_len - 2);
opts->settings_dtvcc.enabled = 1;
opts->enc_cfg.dtvcc_extract = 1;
opts->enc_cfg.all_services_charset = charset;
opts->enc_cfg.services_charsets = (char **) calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES);
if (!opts->enc_cfg.services_charsets)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services");
memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *));
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
{
opts->settings_dtvcc.services_enabled[i] = 1;
opts->enc_cfg.services_enabled[i] = 1;
}
opts->settings_dtvcc.active_services_count = CCX_DTVCC_MAX_SERVICES;
return;
l=s+strlen (s);
for (c=s; c<l && *c; )
}
char *c, *e, *l;
if (s == NULL)
return;
l = s + strlen(s);
for (c = s; c < l && *c; )
{
int svc=-1;
while (*c && !isdigit (*c))
int svc = -1;
while (*c && !isdigit(*c))
c++;
if (!*c) // We're done
break;
e=c;
e = c;
while (isdigit (*e))
e++;
*e=0;
svc=atoi (c);
if (svc<1 || svc>CCX_DECODERS_708_MAX_SERVICES)
fatal (EXIT_MALFORMED_PARAMETER, "Invalid service number (%d), valid range is 1-%d.",svc,CCX_DECODERS_708_MAX_SERVICES);
cea708services[svc-1]=1;
do_cea708=1;
c=e+1;
int charset_start_found = (*e == '[');
*e = 0;
svc = atoi(c);
if (svc < 1 || svc > CCX_DTVCC_MAX_SERVICES)
fatal(EXIT_MALFORMED_PARAMETER,
"[CEA-708] Malformed parameter: "
"Invalid service number (%d), valid range is 1-%d.", svc, CCX_DTVCC_MAX_SERVICES);
opts->settings_dtvcc.services_enabled[svc - 1] = 1;
opts->enc_cfg.services_enabled[svc - 1] = 1;
opts->settings_dtvcc.enabled = 1;
opts->enc_cfg.dtvcc_extract = 1;
opts->settings_dtvcc.active_services_count++;
if (!opts->enc_cfg.services_charsets)
{
opts->enc_cfg.services_charsets = (char **) calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES);
if (!opts->enc_cfg.services_charsets)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services");
memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *));
}
e = e + 1;
c = e;
if (!charset_start_found)
continue;
while (*e && *e != ']' && *e != ',')
e++;
if (*e == ']')
{
char *charset = strndup(c, e - c);
if (strlen(charset))
opts->enc_cfg.services_charsets[svc - 1] = charset;
c = e + 1;
}
else if (!*e)
{
fatal(EXIT_MALFORMED_PARAMETER,
"[CEA-708] Malformed parameter: missing closing ] in CEA-708 services list");
}
}
if (!opts->settings_dtvcc.active_services_count)
fatal(EXIT_MALFORMED_PARAMETER,
"[CEA-708] Malformed parameter: no services");
}
long atol_size (char *s)
@@ -789,16 +826,6 @@ int atoi_hex (char *s)
int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
{
char *cea708_service_list=NULL; // List CEA-708 services
// Sensible default values for credits
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &opt->startcreditsnotbefore);
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &opt->startcreditsnotafter);
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &opt->startcreditsforatleast);
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &opt->startcreditsforatmost);
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &opt->endcreditsforatleast);
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &opt->endcreditsforatmost);
// Parse parameters
for (int i=1; i<argc; i++)
{
@@ -859,11 +886,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
continue;
}
if (strcmp(argv[i], "-bom") == 0){
opt->no_bom = 0;
opt->enc_cfg.no_bom = 0;
continue;
}
if (strcmp(argv[i], "-nobom") == 0){
opt->no_bom = 1;
opt->enc_cfg.no_bom = 1;
continue;
}
if (strcmp (argv[i],"-nots")==0 ||
@@ -899,11 +926,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
i++;
if(!strcmp (argv[i],"teletext"))
{
opt->codec = CCX_CODEC_TELETEXT;
opt->demux_cfg.codec = CCX_CODEC_TELETEXT;
}
else if(!strcmp (argv[i],"dvbsub"))
{
opt->codec = CCX_CODEC_DVB;
opt->demux_cfg.codec = CCX_CODEC_DVB;
}
else
{
@@ -918,11 +945,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
i++;
if(!strcmp (argv[i],"teletext"))
{
opt->nocodec = CCX_CODEC_TELETEXT;
opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT;
}
else if(!strcmp (argv[i],"dvbsub"))
{
opt->nocodec = CCX_CODEC_DVB;
opt->demux_cfg.nocodec = CCX_CODEC_DVB;
}
else
{
@@ -933,7 +960,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
/* Output file formats */
if (strcmp (argv[i],"-srt")==0 ||
strcmp (argv[i],"-dvdraw")==0 ||
strcmp (argv[i],"-sami")==0 || strcmp (argv[i],"-smi")==0 ||
strcmp(argv[i], "-sami") == 0 || strcmp(argv[i], "-smi") == 0 || strcmp(argv[i], "-webvtt") == 0 ||
strcmp (argv[i],"--transcript")==0 || strcmp (argv[i],"-txt")==0 ||
strcmp (argv[i],"--timedtranscript")==0 || strcmp (argv[i],"-ttxt")==0 ||
strcmp (argv[i],"-null")==0)
@@ -951,14 +978,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--startcreditstext")==0)
&& i<argc-1)
{
opt->start_credits_text=argv[i+1];
opt->enc_cfg.start_credits_text=argv[i+1];
i++;
continue;
}
if ((strcmp (argv[i],"--startcreditsnotbefore")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->startcreditsnotbefore)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsnotbefore)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsnotbefore only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -968,7 +995,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--startcreditsnotafter")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->startcreditsnotafter)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsnotafter)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsnotafter only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -978,7 +1005,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--startcreditsforatleast")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->startcreditsforatleast)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsforatleast)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -988,7 +1015,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--startcreditsforatmost")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->startcreditsforatmost)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsforatmost)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -999,14 +1026,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--endcreditstext")==0 )
&& i<argc-1)
{
opt->end_credits_text=argv[i+1];
opt->enc_cfg.end_credits_text=argv[i+1];
i++;
continue;
}
if ((strcmp (argv[i],"--endcreditsforatleast")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->endcreditsforatleast)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.endcreditsforatleast)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--endcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -1016,7 +1043,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if ((strcmp (argv[i],"--endcreditsforatmost")==0)
&& i<argc-1)
{
if (stringztoms (argv[i+1],&opt->endcreditsforatmost)==-1)
if (stringztoms (argv[i+1],&opt->enc_cfg.endcreditsforatmost)==-1)
{
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n");
}
@@ -1062,7 +1089,9 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if (strcmp (argv[i],"-noru")==0 ||
strcmp (argv[i],"--norollup")==0)
{
opt->no_rollup = 1;
opt->settings_608.no_rollup = 1;
opt->settings_dtvcc.no_rollup = 1;
continue;
}
if (strcmp (argv[i],"-ru1")==0)
@@ -1077,12 +1106,18 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strcmp (argv[i],"-ru3")==0)
{
opt->settings_608 .force_rollup = 3;
opt->settings_608.force_rollup = 3;
continue;
}
if (strcmp (argv[i],"-trim")==0)
{
opt->trim_subs=1;
opt->enc_cfg.trim_subs=1;
continue;
}
if (strcmp (argv[i],"-outinterval")==0)
{
opt->out_interval = atoi(argv[i+1]);
i++;
continue;
}
if (strcmp (argv[i],"--gui_mode_reports")==0)
@@ -1098,14 +1133,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
if (strcmp (argv[i],"--sentencecap")==0 ||
strcmp (argv[i],"-sc")==0)
{
opt->sentence_cap=1;
opt->enc_cfg.sentence_cap=1;
continue;
}
if ((strcmp (argv[i],"--capfile")==0 ||
strcmp (argv[i],"-caf")==0)
&& i<argc-1)
{
opt->sentence_cap=1;
opt->enc_cfg.sentence_cap=1;
opt->sentence_cap_file=argv[i+1];
i++;
continue;
@@ -1115,18 +1150,24 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
{
if (i==argc-1 // Means no following argument
|| !isanumber (argv[i+1])) // Means is not a number
opt->ts_forced_program = (unsigned)-1; // Autodetect
opt->demux_cfg.ts_forced_program = -1; // Autodetect
else
{
opt->ts_forced_program=atoi_hex (argv[i+1]);
opt->ts_forced_program_selected=1;
opt->demux_cfg.ts_forced_program=atoi_hex (argv[i+1]);
opt->demux_cfg.ts_forced_program_selected=1;
i++;
}
continue;
}
if (strcmp (argv[i],"-autoprogram")==0)
{
opt->ts_autoprogram=1;
opt->demux_cfg.ts_autoprogram=1;
continue;
}
if (strcmp (argv[i],"-multiprogram")==0)
{
opt->multiprogram = 1;
opt->demux_cfg.ts_allprogram = CCX_TRUE;
continue;
}
if (strcmp (argv[i],"--stream")==0 ||
@@ -1288,6 +1329,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
opt->debug_mask |= CCX_DMT_PMT;
continue;
}
if (strcmp(argv[i], "-dumpdef") == 0)
{
opt->debug_mask |= CCX_DMT_DUMPDEF;
continue;
}
if (strcmp (argv[i],"-investigate_packets")==0)
{
opt->investigate_packets=1;
@@ -1326,17 +1372,17 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strstr (argv[i],"-unicode")!=NULL)
{
opt->encoding=CCX_ENC_UNICODE;
opt->enc_cfg.encoding=CCX_ENC_UNICODE;
continue;
}
if (strstr (argv[i],"-utf8")!=NULL)
{
opt->encoding=CCX_ENC_UTF_8;
opt->enc_cfg.encoding=CCX_ENC_UTF_8;
continue;
}
if (strstr (argv[i],"-latin1")!=NULL)
{
opt->encoding=CCX_ENC_LATIN_1;
opt->enc_cfg.encoding=CCX_ENC_LATIN_1;
continue;
}
if (strcmp (argv[i],"-poc")==0 || strcmp (argv[i],"--usepicorder")==0)
@@ -1366,52 +1412,39 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strcmp (argv[i],"-o")==0 && i<argc-1)
{
opt->output_filename=argv[i+1];
opt->output_filename = argv[i+1];
i++;
continue;
}
if (strcmp (argv[i],"-cf")==0 && i<argc-1)
{
opt->out_elementarystream_filename=argv[i+1];
i++;
continue;
}
if (strcmp (argv[i],"-o1")==0 && i<argc-1)
{
opt->wbout1.filename=argv[i+1];
i++;
continue;
}
if (strcmp (argv[i],"-o2")==0 && i<argc-1)
{
opt->wbout2.filename=argv[i+1];
opt->demux_cfg.out_elementarystream_filename = argv[i+1];
i++;
continue;
}
if ( (strcmp (argv[i],"-svc")==0 || strcmp (argv[i],"--service")==0) &&
i<argc-1)
{
cea708_service_list=argv[i+1];
parse_708services (cea708_service_list);
parse_708_services(opt, argv[i + 1]);
i++;
continue;
}
if (strcmp (argv[i],"-datapid")==0 && i<argc-1)
{
opt->ts_cappid = atoi_hex(argv[i+1]);
opt->ts_forced_cappid=1;
opt->demux_cfg.ts_cappids[opt->demux_cfg.nb_ts_cappid] = atoi_hex(argv[i+1]);
opt->demux_cfg.nb_ts_cappid++;
i++;
continue;
}
if (strcmp (argv[i],"-datastreamtype")==0 && i<argc-1)
{
opt->ts_datastreamtype = atoi_hex(argv[i+1]);
opt->demux_cfg.ts_datastreamtype = atoi_hex(argv[i+1]);
i++;
continue;
}
if (strcmp (argv[i],"-streamtype")==0 && i<argc-1)
{
opt->ts_forced_streamtype = atoi_hex(argv[i+1]);
opt->demux_cfg.ts_forced_streamtype = atoi_hex(argv[i+1]);
i++;
continue;
}
@@ -1420,14 +1453,13 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
{
tlt_config.page = atoi_hex(argv[i+1]);
tlt_config.user_page = tlt_config.page;
opt->teletext_mode=CCX_TXT_IN_USE;
i++;
continue;
}
if (strcmp (argv[i],"-UCLA")==0 || strcmp (argv[i],"-ucla")==0)
{
opt->millis_separator='.';
opt->no_bom = 1;
opt->enc_cfg.no_bom = 1;
if (!opt->transcript_settings.isFinal){
opt->transcript_settings.showStartTime = 1;
opt->transcript_settings.showEndTime = 1;
@@ -1440,7 +1472,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strcmp (argv[i],"-lf")==0 || strcmp (argv[i],"-LF")==0)
{
opt->line_terminator_lf = 1;
opt->enc_cfg.line_terminator_lf = 1;
continue;
}
if (strcmp (argv[i],"-noautotimeref")==0)
@@ -1450,7 +1482,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strcmp (argv[i],"-autodash")==0)
{
opt->autodash = 1;
opt->enc_cfg.autodash = 1;
continue;
}
if (strcmp (argv[i],"-xmltv")==0)
@@ -1524,14 +1556,12 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
}
if (strcmp (argv[i],"-teletext")==0)
{
opt->codec = CCX_CODEC_TELETEXT;
opt->teletext_mode=CCX_TXT_IN_USE;
opt->demux_cfg.codec = CCX_CODEC_TELETEXT;
continue;
}
if (strcmp (argv[i],"-noteletext")==0)
{
opt->nocodec = CCX_CODEC_TELETEXT;
opt->teletext_mode=CCX_TXT_FORBIDDEN;
opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT;
continue;
}
/* Custom transcript */
@@ -1587,6 +1617,9 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
set_output_format(opt, "bin");
opt->xmltv = 2;
opt->xmltvliveinterval = 2;
char *addr = argv[i + 1];
if (*addr == '[')
{
@@ -1657,7 +1690,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
activity_report_version();
}
if(opt->sentence_cap)
if(opt->enc_cfg.sentence_cap)
{
if(add_built_in_words())
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory for word list");
@@ -1666,14 +1699,10 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
ccx_encoders_helpers_perform_shellsort_words();
}
if(opt->ts_forced_program != -1)
opt->ts_forced_program_selected = 1;
if(opt->demux_cfg.ts_forced_program != -1)
opt->demux_cfg.ts_forced_program_selected = 1;
if(opt->wbout2.filename != NULL && (opt->extract != 2 || opt->extract != 12) )
mprint("WARN: -o2 ignored! you might want -2 or -12 with -o2\n");
// Init telexcc redundant options
tlt_config.transcript_settings = &opt->transcript_settings;
tlt_config.levdistmincnt = opt->levdistmincnt;
tlt_config.levdistmaxpct = opt->levdistmaxpct;
tlt_config.extraction_start = opt->extraction_start;
@@ -1683,7 +1712,6 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
tlt_config.date_format = opt->date_format;
tlt_config.noautotimeref = opt->noautotimeref;
tlt_config.send_to_srv = opt->send_to_srv;
tlt_config.encoding = opt->encoding;
tlt_config.nofontcolor = opt->nofontcolor;
tlt_config.millis_separator = opt->millis_separator;
@@ -1717,17 +1745,55 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
return EXIT_TOO_MANY_INPUT_FILES;
}
if (opt->demux_cfg.auto_stream == CCX_SM_MCPOODLESRAW && opt->write_format==CCX_OF_RAW)
{
print_error(opt->gui_mode_reports, "-in=raw can only be used if the output is a subtitle file.\n");
return EXIT_INCOMPATIBLE_PARAMETERS;
}
if (opt->demux_cfg.auto_stream == CCX_SM_RCWT && opt->write_format==CCX_OF_RCWT && opt->output_filename == NULL)
{
print_error(opt->gui_mode_reports,
"CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n");
return EXIT_INCOMPATIBLE_PARAMETERS;
}
if (opt->write_format != CCX_OF_DVDRAW && opt->cc_to_stdout && opt->extract==12)
{
print_error(opt->gui_mode_reports, "You can't extract both fields to stdout at the same time in broadcast mode.");
return EXIT_INCOMPATIBLE_PARAMETERS;
}
if (opt->write_format == CCX_OF_SPUPNG && opt->cc_to_stdout)
{
print_error(opt->gui_mode_reports, "You cannot use -out=spupng with -stdout.");
return EXIT_INCOMPATIBLE_PARAMETERS;
}
if (opt->write_format == CCX_OF_WEBVTT && opt->enc_cfg.encoding != CCX_ENC_UTF_8)
{
mprint("Note: Output format is WebVTT, forcing UTF-8");
opt->enc_cfg.encoding = CCX_ENC_UTF_8;
}
/* Initialize some Encoder Configuration */
opt->enc_cfg.extract = opt->extract;
if (opt->num_input_files > 0)
{
opt->enc_cfg.multiple_files = 1;
opt->enc_cfg.first_input_file = opt->inputfile[0];
}
opt->enc_cfg.cc_to_stdout = opt->cc_to_stdout;
opt->enc_cfg.write_format = opt->write_format;
opt->enc_cfg.send_to_srv = opt->send_to_srv;
opt->enc_cfg.date_format = opt->date_format;
opt->enc_cfg.transcript_settings = opt->transcript_settings;
opt->enc_cfg.millis_separator = opt->millis_separator;
opt->enc_cfg.no_font_color = opt->nofontcolor;
opt->enc_cfg.no_type_setting = opt->notypesetting;
opt->enc_cfg.subs_delay = opt->subs_delay;
if(opt->output_filename && opt->multiprogram == CCX_FALSE)
opt->enc_cfg.output_filename = strdup(opt->output_filename);
else
opt->enc_cfg.output_filename = NULL;
return EXIT_OK;
}
int detect_input_file_overwrite(struct lib_ccx_ctx *ctx, const char *output_filename)
{
for (int i = 0; i < ctx->num_input_files; i++)
{
if (!strcmp(ctx->inputfile[i], output_filename)) {
return 1;
}
}
return 0;
}

View File

@@ -1,5 +1,8 @@
#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)
{
@@ -29,48 +32,12 @@ void params_dump(struct lib_ccx_ctx *ctx)
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;
}
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");
@@ -89,17 +56,34 @@ void params_dump(struct lib_ccx_ctx *ctx)
break;
}
mprint ("]");
if (ccx_options.wtvconvertfix)
{
mprint (" [Windows 7 wtv to dvr-ms conversion fix: Enabled]");
}
mprint ("\n");
if (ccx_options.wtvmpeg2)
if (ccx_options.settings_dtvcc.enabled)
{
mprint (" [WTV use MPEG2 stream: 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 ("\n");
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)
@@ -121,7 +105,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
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)
switch (ccx_options.enc_cfg.encoding)
{
case CCX_ENC_UNICODE:
mprint ("Unicode");
@@ -136,7 +120,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
mprint ("] ");
mprint ("[Delay: %lld] ",ctx->subs_delay);
mprint ("[Trim lines: %s]\n",ccx_options.trim_subs?"Yes":"No");
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: ");
@@ -144,7 +128,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
mprint ("Yes, using %s", ccx_options.sentence_cap_file);
else
{
mprint ("%s",ccx_options.sentence_cap?"Yes, but only built-in words":"No");
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");
@@ -175,41 +159,75 @@ void params_dump(struct lib_ccx_ctx *ctx)
mprint ("Yes, timeout: %d seconds",ccx_options.live_stream);
}
mprint ("] [Clock frequency: %d]\n",MPEG_CLOCK_FREQ);
mprint ("Teletext page: [");
mprint ("[Teletext page: ");
if (tlt_config.page)
mprint ("%d]\n",tlt_config.page);
else
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 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.startcreditsnotbefore.time_in_ms/1000),
(long) (ccx_options.startcreditsnotafter.time_in_ms/1000)
(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.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.startcreditsforatmost.time_in_ms/1000)
(long) (ccx_options.enc_cfg.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.enc_cfg.startcreditsforatmost.time_in_ms/1000)
);
}
if (ccx_options.end_credits_text)
if (ccx_options.enc_cfg.end_credits_text)
{
mprint ("End credits text: [%s]\n",
ccx_options.end_credits_text?ccx_options.end_credits_text:"None");
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.endcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.endcreditsforatmost.time_in_ms/1000)
(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
}

View File

@@ -7,39 +7,31 @@
// 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;
ctx->cc_data_count[j] = 0;
ctx->cc_fts[j] = 0;
}
memset(cc_data_pkts, 0, SORTBUF*(31*3+1));
has_ccdata_buffered = 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)
{
enum ccx_stream_mode_enum stream_mode;
//stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx);
// Uninitialized?
if (anchor_seq_number < 0)
if (ctx->anchor_seq_number < 0)
{
anchor_hdcc( sequence_number);
anchor_hdcc( ctx, sequence_number);
}
int seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
int seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
{
@@ -47,11 +39,11 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
dbg_print(CCX_DMT_VERBOSE, "Too many B-frames, or missing anchor frame. Trying to recover ..\n");
process_hdcc(ctx, sub);
anchor_hdcc( sequence_number);
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
anchor_hdcc( ctx, sequence_number);
seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
}
has_ccdata_buffered = 1;
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.
@@ -66,12 +58,12 @@ 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
/*
@@ -85,28 +77,27 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
}
// 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;
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

@@ -109,12 +109,12 @@ void spupng_write_footer(struct spupng_t *sp)
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);
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)

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
@@ -23,7 +24,7 @@ struct spupng_t
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,8 +5,12 @@
#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);
@@ -66,7 +70,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
while (idx < ctx->startbytes_avail - 7){
lastBoxLocation = idx;
// Check if we have a valid box
if (isValidMP4Box(&ctx->startbytes, idx, &nextBoxLocation, &boxScore))
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)
@@ -111,7 +115,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
if (ctx->stream_mode == CCX_SM_TRANSPORT)
{
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as TS\n");
return_to_buffer (ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return;
}
@@ -134,7 +138,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
if (ctx->stream_mode == CCX_SM_TRANSPORT)
{
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as M2TS\n");
return_to_buffer (ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
return;
}
@@ -163,9 +167,9 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
{
// 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;
strangeheader=1; // Avoid message about unrecognized header
ctx->startbytes_pos = 187;
ctx->stream_mode = CCX_SM_PROGRAM;
ctx->strangeheader = 1; // Avoid message about unrecognized header
}
}
else
@@ -175,11 +179,11 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
}
}
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
return_to_buffer (ctx->startbytes, ctx->startbytes_avail);
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
@@ -204,40 +208,6 @@ int detect_myth( struct lib_ccx_ctx *ctx )
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;
}
/* Read and evaluate the current video PES header. The function returns
* the length of the payload if successful, otherwise -1 is returned
@@ -246,10 +216,11 @@ 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)
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
@@ -257,7 +228,7 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
if ( !sbuflen )
{
// Extension present, get it
buffered_read (ctx, nextheader+6,3);
result = buffered_read (ctx, nextheader+6,3);
ctx->past=ctx->past+result;
if (result!=3) {
// Consider this the end of the show.
@@ -266,13 +237,12 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
}
else
{
if (ccx_bufferdatatype == CCX_DVB_SUBTITLE
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;
@@ -287,8 +257,8 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
{
if (nextheader[8] > 0)
{
buffered_read (ctx, nextheader+9,nextheader[8]);
ctx->past=ctx->past+result;
result = buffered_read (ctx, nextheader+9,nextheader[8]);
ctx->past = ctx->past+result;
if (result!=nextheader[8])
{
return -1;
@@ -391,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++;
@@ -401,14 +371,8 @@ 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;
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. */

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

View File

@@ -0,0 +1,76 @@
#ifndef TS_FUNCTION_H
#define TS_FUNCTION_H
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
int64_t pcr;
unsigned char section_buf[4098];
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 elementary_PID;
enum ccx_stream_type stream_type;
unsigned printable_stream_type;
};
struct PSI_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];
};
#endif

278
src/lib_ccx/ts_info.c Normal file
View File

@@ -0,0 +1,278 @@
#include "ccx_demuxer.h"
#include "ccx_common_common.h"
#include "lib_ccx.h"
#include "dvb_subtitle_decoder.h"
/**
We need stream info from PMT table when any of the following Condition meets:
1) Dont have any caption stream registered to be extracted
2) Want a streams per program, and program_number has never been registered
3) We need single stream and its info about codec and buffertype is incomplete
*/
int need_capInfo(struct ccx_demuxer *ctx, int program_number)
{
struct cap_info* iter;
if(list_empty(&ctx->cinfo_tree.all_stream))
{
return CCX_TRUE;
}
if(ctx->ts_allprogram == CCX_TRUE)
{
list_for_each_entry(iter, &ctx->cinfo_tree.pg_stream, pg_stream, struct cap_info)
{
if (iter->program_number == program_number)
return CCX_FALSE;
}
return CCX_TRUE;
}
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->codec == CCX_CODEC_NONE)
return CCX_TRUE;
if (iter->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM)
return CCX_TRUE;
}
return CCX_FALSE;
}
void ignore_other_stream(struct ccx_demuxer *ctx, int pid)
{
struct cap_info* iter;
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->pid != pid)
iter->ignore = 1;
}
}
int get_programme_number(struct ccx_demuxer *ctx, int pid)
{
struct cap_info* iter;
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->pid == pid)
return iter->program_number;
}
return CCX_UNKNOWN;
}
struct cap_info *get_sib_stream_by_type(struct cap_info* program, enum ccx_code_type type)
{
struct cap_info* iter;
list_for_each_entry(iter, &program->sib_head, sib_stream, struct cap_info)
{
if(iter->codec == type)
return iter;
}
return NULL;
}
struct cap_info* get_best_sib_stream(struct cap_info* program)
{
struct cap_info* info;
info = get_sib_stream_by_type(program, CCX_CODEC_TELETEXT);
if(info)
return info;
info = get_sib_stream_by_type(program, CCX_CODEC_DVB);
if(info)
return info;
info = get_sib_stream_by_type(program, CCX_CODEC_ATSC_CC);
if(info)
return info;
return NULL;
}
void ignore_other_sib_stream(struct cap_info* head, int pid)
{
struct cap_info* iter;
list_for_each_entry(iter, &head->sib_head, sib_stream, struct cap_info)
{
if(iter->pid != pid)
iter->ignore = 1;
}
}
int get_best_stream(struct ccx_demuxer *ctx)
{
struct cap_info* iter;
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->codec == CCX_CODEC_TELETEXT)
return iter->pid;
}
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->codec == CCX_CODEC_DVB)
return iter->pid;
}
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->codec == CCX_CODEC_ISDB_CC)
return iter->pid;
}
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->codec == CCX_CODEC_ATSC_CC)
return iter->pid;
}
return -1;
}
struct demuxer_data *get_data_stream(struct demuxer_data *data, int pid)
{
struct demuxer_data *ptr = data;
for(ptr = data; ptr; ptr = ptr->next_stream)
if(ptr->stream_pid == pid && ptr->len > 0)
return ptr;
return NULL;
}
int need_capInfo_for_pid(struct ccx_demuxer *ctx, int pid)
{
struct cap_info* iter;
if(list_empty(&ctx->cinfo_tree.all_stream))
{
return CCX_FALSE;
}
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if (iter->pid == pid && iter->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM)
return CCX_TRUE;
}
return CCX_FALSE;
}
static void* init_private_data(enum ccx_code_type codec)
{
switch(codec)
{
case CCX_CODEC_TELETEXT:
return telxcc_init();
case CCX_CODEC_DVB:
return dvbsub_init_decoder(NULL);
default:
return NULL;
}
}
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* ptr;
struct cap_info* tmp;
struct cap_info* program_iter;
if(!ctx)
{
errno = EINVAL;
return -1;
}
if (ctx->ts_datastreamtype != CCX_STREAM_TYPE_UNKNOWNSTREAM && ctx->ts_datastreamtype != stream)
{
errno = EINVAL;
return -1;
}
ptr = &ctx->cinfo_tree;
list_for_each_entry(tmp, &ptr->all_stream, all_stream, struct cap_info)
{
if (tmp->pid == pid)
{
if(tmp->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM || tmp->codec == CCX_CODEC_NONE)
{
if(stream != CCX_STREAM_TYPE_UNKNOWNSTREAM)
tmp->stream = stream;
if(codec != CCX_CODEC_NONE)
{
tmp->codec = codec;
tmp->codec_private_data = init_private_data(codec);
}
tmp->saw_pesstart = 0;
tmp->capbuflen = 0;
tmp->capbufsize = 0;
tmp->ignore = 0;
if(private_data)
tmp->codec_private_data = private_data;
}
return CCX_OK;
}
}
if( ctx->flag_ts_forced_cappid == CCX_TRUE)
return CCX_EINVAL;
tmp = malloc(sizeof(struct cap_info));
if(!tmp)
{
return -1;
}
tmp->pid = pid;
tmp->stream = stream;
tmp->codec = codec;
tmp->program_number = pn;
tmp->saw_pesstart = 0;
tmp->capbuflen = 0;
tmp->capbufsize = 0;
tmp->capbuf = NULL;
tmp->ignore = CCX_FALSE;
if(!private_data && codec != CCX_CODEC_NONE)
tmp->codec_private_data = init_private_data(codec);
else
tmp->codec_private_data = private_data;
list_add_tail( &(tmp->all_stream), &(ptr->all_stream) );
list_for_each_entry(program_iter, &ptr->pg_stream, pg_stream, struct cap_info)
{
if (program_iter->program_number == pn)
{
list_add_tail( &(tmp->sib_stream), &(program_iter->sib_head) );
return CCX_OK;
}
}
INIT_LIST_HEAD(&(tmp->sib_head));
list_add_tail( &(tmp->sib_stream), &(tmp->sib_head) );
list_add_tail( &(tmp->pg_stream), &(ptr->pg_stream) );
return 0;
}
void dinit_cap (struct ccx_demuxer *ctx)
{
struct cap_info* iter;
while(!list_empty(&ctx->cinfo_tree.all_stream))
{
iter = list_entry(ctx->cinfo_tree.all_stream.next, struct cap_info, all_stream);
list_del(&iter->all_stream);
free(iter);
}
INIT_LIST_HEAD(&ctx->cinfo_tree.all_stream);
INIT_LIST_HEAD(&ctx->cinfo_tree.sib_stream);
INIT_LIST_HEAD(&ctx->cinfo_tree.pg_stream);
}
struct cap_info * get_cinfo(struct ccx_demuxer *ctx, int pid)
{
struct cap_info* iter;
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
{
if(iter->pid == pid && iter->codec != CCX_CODEC_NONE && iter->stream != CCX_STREAM_TYPE_UNKNOWNSTREAM)
return iter;
}
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
#include "utility.h"
#include <stdbool.h>
#ifdef WIN32
#include "..\\win_iconv\\win_iconv.h"
#include "..\\win_iconv\\iconv.h"
#else
#include "iconv.h"
#endif
@@ -81,7 +81,7 @@ void EPG_DVB_calc_start_time(struct EPG_event *event, uint64_t time)
y = y + k + 1900;
m = m - 1 - k*12;
sprintf(event->start_time_string, "%02d%02d%02d%06x +0000",y,m,d,time&0xffffff);
sprintf(event->start_time_string, "%02ld%02ld%02ld%06llx +0000",y,m,d,time&0xffffff);
}
}
@@ -193,6 +193,50 @@ void EPG_print_event(struct EPG_event *event, uint32_t channel, FILE *f)
fprintf(f, " </program>\n");
}
void EPG_output_net(struct lib_ccx_ctx *ctx)
{
int i;
unsigned j;
struct EPG_event *event;
/* TODO: don't remove untill someone fixes segfault with -xmltv 2 */
if (ctx->demux_ctx == NULL)
return;
if (ctx->demux_ctx->nb_program == 0)
return;
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
{
if (ctx->demux_ctx->pinfo[i].program_number == ccx_options.demux_cfg.ts_forced_program)
break;
}
if (i == ctx->demux_ctx->nb_program)
return;
for (j = 0; j < ctx->eit_programs[i].array_len; j++)
{
event = &(ctx->eit_programs[i].epg_events[j]);
if (event->live_output == true)
continue;
event->live_output = true;
char *category = NULL;
if (event->num_categories > 0)
category = EPG_DVB_content_type_to_string(event->categories[0]);
net_send_epg(
event->start_time_string, event->end_time_string,
event->event_name,
event->extended_text,
event->ISO_639_language_code,
category
);
}
}
// Creates fills and closes a new XMLTV file for live mode output.
// File should include only events not previously output.
void EPG_output_live(struct lib_ccx_ctx *ctx)
@@ -200,7 +244,7 @@ void EPG_output_live(struct lib_ccx_ctx *ctx)
int c=false, i, j;
FILE *f;
char *filename, *finalfilename;
for(i=0; i<pmt_array_length; i++)
for(i=0; i < ctx->demux_ctx->nb_program; i++)
{
for(j=0; j<ctx->eit_programs[i].array_len; j++)
if(ctx->eit_programs[i].epg_events[j].live_output==false)
@@ -216,24 +260,24 @@ void EPG_output_live(struct lib_ccx_ctx *ctx)
f = fopen(filename, "w");
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
for(i=0; i<pmt_array_length; i++)
for(i=0; i < ctx->demux_ctx->nb_program; i++)
{
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
fprintf(f, " <display-name>%i</display-name>\n", ctx->demux_ctx->pinfo[i].program_number);
fprintf(f, " </channel>\n");
}
for(i=0; i<pmt_array_length; i++)
for(i=0; i < ctx->demux_ctx->nb_program; i++)
{
for(j=0; j<ctx->eit_programs[i].array_len; j++)
if(ctx->eit_programs[i].epg_events[j].live_output==false)
{
ctx->eit_programs[i].epg_events[j].live_output=true;
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
}
}
fprintf(f, "</tv>");
fclose(f);
finalfilename = malloc(strlen(ctx->wbout1.filename)+30);
finalfilename = malloc(strlen(filename)+30);
memcpy(finalfilename, filename, strlen(filename)-5);
finalfilename[strlen(filename)-5]='\0';
rename(filename, finalfilename);
@@ -248,39 +292,49 @@ void EPG_output(struct lib_ccx_ctx *ctx)
FILE *f;
char *filename;
int i,j, ce;
filename = malloc(strlen(ctx->basefilename) + 9);
if(filename == NULL)
return;
memcpy(filename, ctx->basefilename, strlen(ctx->basefilename)+1);
strcat(filename, "_epg.xml");
f = fopen(filename, "w");
free(filename);
freep(&filename);
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
for(i=0; i<pmt_array_length; i++)
for(i=0; i<ctx->demux_ctx->nb_program; i++)
{
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
fprintf(f, " <display-name>");
if(ctx->demux_ctx->pinfo[i].name[0] != '\0')
EPG_fprintxml(f, ctx->demux_ctx->pinfo[i].name);
else
fprintf(f, "%i\n", ctx->demux_ctx->pinfo[i].program_number);
fprintf(f, "</display-name>\n");
fprintf(f, " </channel>\n");
}
if(ccx_options.xmltvonlycurrent==0)
{ // print all events
for(i=0; i<pmt_array_length; i++)
for(i=0; i<ctx->demux_ctx->nb_program; i++)
{
for(j=0; j<ctx->eit_programs[i].array_len; j++)
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
}
if(pmt_array_length==0) //Stream has no PMT, fall back to unordered events
if(ctx->demux_ctx->nb_program==0) //Stream has no PMT, fall back to unordered events
for(j=0; j<ctx->eit_programs[TS_PMT_MAP_SIZE].array_len; j++)
EPG_print_event(&ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j], ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j].service_id, f);
}
else
{ // print current events only
for(i=0; i<pmt_array_length; i++)
for(i=0; i<ctx->demux_ctx->nb_program; i++)
{
ce = ctx->eit_current_events[i];
for(j=0; j<ctx->eit_programs[i].array_len; j++)
{
if(ce==ctx->eit_programs[i].epg_events[j].id)
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
}
}
}
@@ -721,9 +775,9 @@ void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32
event.num_ratings=0;
event.num_categories=0;
event.live_output=false;
for (i = 0; i < pmt_array_length; i++)
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
{
if (pmt_array[i].program_number == ctx->ATSC_source_pg_map[source_id])
if (ctx->demux_ctx->pinfo[i].program_number == ctx->ATSC_source_pg_map[source_id])
pmt_map=i;
}
@@ -816,14 +870,14 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
uint16_t service_id;
int32_t pmt_map = -1;
int i;
int hasnew=false;
int hasnew = false;
struct EPG_event event;
uint8_t section_number;
uint8_t last_section_number;
uint8_t segment_last_section_number;
uint32_t events_length = section_length - 11;
uint8_t *offset=payload_start;
uint32_t remaining=events_length;
uint32_t events_length;
uint8_t *offset;
uint32_t remaining;
if(size < 13)
@@ -840,17 +894,17 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
offset = payload_start;
remaining = events_length;
for (i = 0; i < pmt_array_length; i++)
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
{
if (pmt_array[i].program_number == service_id)
pmt_map=i;
if (ctx->demux_ctx->pinfo[i].program_number == service_id)
pmt_map = i;
}
//For any service we don't have an PMT for (yet), store it in the special last array pos.
if(pmt_map==-1)
pmt_map=TS_PMT_MAP_SIZE;
if(pmt_map == -1)
pmt_map = TS_PMT_MAP_SIZE;
if(events_length>size-14)
if(events_length > size-14)
{
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n");
//XXX hack to override segfault, we should concat packets instead
@@ -923,7 +977,7 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
//handle outputing to xml files
void EPG_handle_output(struct lib_ccx_ctx *ctx)
{
int cur_sec = (int) ((ctx->global_timestamp-ctx->min_global_timestamp) / 1000);
int cur_sec = (int) ((ctx->demux_ctx->global_timestamp - ctx->demux_ctx->min_global_timestamp) / 1000);
if(ccx_options.xmltv==1 || ccx_options.xmltv==3)
{ //full outout
if(ccx_options.xmltvoutputinterval!=0 && cur_sec>ctx->epg_last_output+ccx_options.xmltvliveinterval)
@@ -932,12 +986,15 @@ void EPG_handle_output(struct lib_ccx_ctx *ctx)
EPG_output(ctx);
}
}
if(ccx_options.xmltv==2 || ccx_options.xmltv==3)
if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
{ //live output
if(cur_sec>ctx->epg_last_live_output+ccx_options.xmltvliveinterval)
{
ctx->epg_last_live_output=cur_sec;
EPG_output_live(ctx);
if (ccx_options.send_to_srv)
EPG_output_net(ctx);
else
EPG_output_live(ctx);
}
}
}
@@ -1036,9 +1093,12 @@ void parse_EPG_packet(struct lib_ccx_ctx *ctx)
void EPG_free(struct lib_ccx_ctx *ctx)
{
int i = 0, j;
if(ccx_options.xmltv==2 || ccx_options.xmltv==3)
if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
{
EPG_output_live(ctx);
if (ccx_options.send_to_srv)
EPG_output_net(ctx);
else
EPG_output_live(ctx);
}
for (i = 0; i < TS_PMT_MAP_SIZE; i++)
{

View File

@@ -1,9 +1,131 @@
#include <signal.h>
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "activity.h"
int temp_debug = 0; // This is a convenience variable used to enable/disable debug on variable conditions. Find references to understand.
static uint32_t crc32_table [] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
int verify_crc32(uint8_t *buf, int len)
{
int i = 0;
int32_t crc = -1;
for (i = 0; i < len; i++)
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (buf[i] & 0xff)) & 0xff];
return crc?CCX_FALSE:CCX_TRUE;
}
int stringztoms (const char *s, struct ccx_boundary_time *bt)
{
unsigned ss=0, mm=0, hh=0;
int value=-1;
int colons=0;
const char *c=s;
while (*c)
{
if (*c==':')
{
if (value==-1) // : at the start, or ::, etc
return -1;
colons++;
if (colons>2) // Max 2, for HH:MM:SS
return -1;
hh=mm;
mm=ss;
ss=value;
value=-1;
}
else
{
if (!isdigit (*c)) // Only : or digits, so error
return -1;
if (value==-1)
value=*c-'0';
else
value=value*10+*c-'0';
}
c++;
}
hh = mm;
mm = ss;
ss = value;
if (mm > 59 || ss > 59)
return -1;
bt->set = 1;
bt->hh = hh;
bt->mm = mm;
bt->ss = ss;
LLONG secs = (hh * 3600 + mm * 60 + ss);
bt->time_in_ms = secs*1000;
return 0;
}
void timestamp_to_srttime(uint64_t timestamp, char *buffer)
{
uint64_t p = timestamp;
@@ -250,3 +372,142 @@ void m_signal(int sig, void (*func)(int))
return;
}
#endif
char *get_basename(char *filename)
{
char *c;
int len;
char *basefilename;
if(!filename)
return NULL;
len = strlen(filename);
basefilename = (char *) malloc(len+1);
if (basefilename == NULL)
{
return NULL;
}
strcpy (basefilename, filename);
for (c = basefilename + len; c > basefilename && *c != '.'; c--)
{;} // Get last .
if (*c == '.')
*c = 0;
return basefilename;
}
char *get_file_extension(enum ccx_output_format write_format)
{
switch (write_format)
{
case CCX_OF_RAW:
return strdup(".raw");
case CCX_OF_SRT:
return strdup(".srt");
case CCX_OF_WEBVTT:
return strdup (".vtt");
case CCX_OF_SAMI:
return strdup(".smi");
case CCX_OF_SMPTETT:
return strdup(".ttml");
case CCX_OF_TRANSCRIPT:
return strdup(".txt");
case CCX_OF_RCWT:
return strdup(".bin");
case CCX_OF_SPUPNG:
return strdup(".xml");
case CCX_OF_DVDRAW:
return strdup(".dvdraw");
case CCX_OF_SIMPLE_XML:
return strdup(".xml");
case CCX_OF_NULL:
return NULL;
default:
mprint ("write_format doesn't have any legal value, this is a bug.\n");
errno = EINVAL;
return NULL;
}
return 0;
}
char *create_outfilename(const char *basename, const char *suffix, const char *extension)
{
char *ptr = NULL;
size_t blen, slen, elen;
if(basename)
blen = strlen(basename);
else
blen = 0;
if(suffix)
slen = strlen(suffix);
else
slen = 0;
if(extension)
elen = strlen(extension);
else
elen = 0;
if ( (elen + slen + blen) <= 0)
return NULL;
ptr = malloc(elen + slen + blen + 1);
if(!ptr)
return NULL;
ptr[0] = '\0';
if(basename)
strcat(ptr, basename);
if(suffix)
strcat(ptr, suffix);
if(extension)
strcat(ptr, extension);
return ptr;
}
size_t utf16_to_utf8(unsigned short utf16_char, unsigned char *out)
{
if (utf16_char < 0x80) {
out[0] = (unsigned char)((utf16_char >> 0 & 0x7F) | 0x00);
return 1;
} else if (utf16_char < 0x0800) {
out[0] = (unsigned char)((utf16_char >> 6 & 0x1F) | 0xC0);
out[1] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
return 2;
} else if (utf16_char < 0x010000) {
out[0] = (unsigned char)((utf16_char >> 12 & 0x0F) | 0xE0);
out[1] = (unsigned char)((utf16_char >> 6 & 0x3F) | 0x80);
out[2] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
return 3;
} else if (utf16_char < 0x110000) {
out[0] = (unsigned char)((utf16_char >> 18 & 0x07) | 0xF0);
out[1] = (unsigned char)((utf16_char >> 12 & 0x3F) | 0x80);
out[2] = (unsigned char)((utf16_char >> 6 & 0x3F) | 0x80);
out[3] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
return 4;
}
return 0;
}
#ifdef _WIN32
char *strndup(const char *s, size_t n)
{
char *p;
p = (char *)malloc(n + 1);
if (p == NULL)
return NULL;
memcpy(p, s, n);
p[n] = '\0';
return p;
}
char *strtok_r(char *str, const char *delim, char **saveptr)
{
strtok_s(str, delim, saveptr);
}
#endif //_WIN32

View File

@@ -10,7 +10,23 @@
#define RL16(x) (*(unsigned short int*)(x))
#define RB16(x) (ntohs(*(unsigned short int*)(x)))
#define RB24(x) ( ((unsigned char*)(x))[0] << 16 | ((unsigned char*)(x))[1] << 8 | ((unsigned char*)(x))[2] )
#define CCX_NOPTS ((int64_t)UINT64_C(0x8000000000000000))
extern int temp_debug;
void init_boundary_time (struct ccx_boundary_time *bt);
void print_error (int mode, const char *fmt, ...);
#endif
int stringztoms (const char *s, struct ccx_boundary_time *bt);
char *get_basename(char *filename);
char *get_file_extension(enum ccx_output_format write_format);
char *create_outfilename(const char *basename, const char *suffix, const char *extension);
int verify_crc32(uint8_t *buf, int len);
size_t utf16_to_utf8(unsigned short utf16_char, unsigned char *out);
#ifdef _WIN32
char *strndup(const char *s, size_t n);
char *strtok_r(char *str, const char *delim, char **saveptr);
#endif //_WIN32
#endif //CC_UTILITY_H

View File

@@ -1,18 +1,19 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "wtv_constants.h"
#include "activity.h"
#include "file_buffer.h"
int check_stream_id(int stream_id, int video_streams[], int num_streams);
int add_skip_chunks(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag);
int add_skip_chunks(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag);
void init_chunked_buffer(struct wtv_chunked_buffer *cb);
uint64_t get_meta_chunk_start(uint64_t offset);
uint64_t time_to_pes_time(uint64_t time);
void add_chunk(struct wtv_chunked_buffer *cb, uint64_t value);
int qsort_cmpint (const void * a, const void * b);
void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb);
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb);
void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb);
// Helper function for qsort (64bit int sort)
int qsort_cmpint (const void * a, const void * b)
@@ -58,29 +59,29 @@ uint64_t time_to_pes_time(uint64_t time)
// Read the actual values of the passed lookup offset and add them to
// the list of chunks to skip as nessasary. Returns false on error.
int add_skip_chunks(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag)
int add_skip_chunks(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag)
{
uint32_t value;
int64_t result;
uint64_t start = ctx->past;
buffered_seek(ctx, (int)((offset*WTV_CHUNK_SIZE) - start));
uint64_t seek_back=0-((offset*WTV_CHUNK_SIZE)-start);
uint32_t value;
buffered_read(ctx, (unsigned char*)&value, 4);
result = buffered_read(ctx, (unsigned char*)&value, 4);
if(result!=4)
return 0;
seek_back-=4;
while(value!=0)
{
dbg_print(CCX_DMT_PARSE, "value: %llx\n", get_meta_chunk_start(value));
buffered_read(ctx, (unsigned char*)&value, 4);
result = buffered_read(ctx, (unsigned char*)&value, 4);
if(result!=4)
return 0;
add_chunk(cb, get_meta_chunk_start(value));
seek_back-=4;
}
buffered_seek(ctx, (int)seek_back);
dbg_print(CCX_DMT_PARSE, "filebuffer_pos: %x\n", filebuffer_pos);
return 1;
}
@@ -96,7 +97,7 @@ void add_chunk(struct wtv_chunked_buffer *cb, uint64_t value)
// skip_sized_buffer. Same as get_sized_buffer, only without actually copying any data
// in to the buffer.
void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
{
if(cb->buffer!=NULL && cb->buffer_size>0) {
free(cb->buffer);
@@ -121,47 +122,50 @@ void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, u
// get_sized_buffer will alloc and set a buffer in the passed wtv_chunked_buffer struct
// it will handle any meta data chunks that need to be skipped in the file
// Will print error messages and return a null buffer on error.
void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
{
if(cb->buffer!=NULL && cb->buffer_size>0)
int64_t result;
if(cb->buffer != NULL && cb->buffer_size > 0)
{
free(cb->buffer);
}
if(size>WTV_MAX_ALLOC)
if(size > WTV_MAX_ALLOC)
{
mprint("\nRequested buffer of %i > %i bytes (WTV_MAX_ALLOC)!\n", size, WTV_MAX_ALLOC);
cb->buffer=NULL;
cb->buffer = NULL;
return;
}
cb->buffer = (uint8_t*)malloc(size);
cb->buffer_size=size;
cb->buffer_size = size;
uint64_t start = cb->filepos;
if(cb->skip_chunks[cb->chunk]!=-1 && start+size>cb->skip_chunks[cb->chunk])
if(cb->skip_chunks[cb->chunk] != -1 && (start + size) > cb->skip_chunks[cb->chunk])
{
buffered_read(ctx, cb->buffer, (int)(cb->skip_chunks[cb->chunk]-start));
cb->filepos+=cb->skip_chunks[cb->chunk]-start;
cb->filepos += cb->skip_chunks[cb->chunk]-start;
buffered_seek(ctx, WTV_META_CHUNK_SIZE);
cb->filepos+=WTV_META_CHUNK_SIZE;
buffered_read(ctx, cb->buffer+(cb->skip_chunks[cb->chunk]-start), (int)(size-(cb->skip_chunks[cb->chunk]-start)));
cb->filepos+=size-(cb->skip_chunks[cb->chunk]-start);
cb->filepos += WTV_META_CHUNK_SIZE;
result = buffered_read(ctx, cb->buffer+(cb->skip_chunks[cb->chunk]-start), (int)(size-(cb->skip_chunks[cb->chunk]-start)));
cb->filepos += size-(cb->skip_chunks[cb->chunk]-start);
cb->chunk++;
}
else
{
buffered_read(ctx, cb->buffer, size);
cb->filepos+=size;
if(result!=size)
result = buffered_read(ctx, cb->buffer, size);
cb->filepos += size;
if(result != size)
{
free(cb->buffer);
cb->buffer_size=0;
ctx->past=cb->filepos;
cb->buffer=NULL;
cb->buffer_size = 0;
ctx->past = cb->filepos;
cb->buffer = NULL;
mprint("\nPremature end of file!\n");
return;
}
}
ctx->past=cb->filepos;
ctx->past = cb->filepos;
return;
}
@@ -169,20 +173,20 @@ void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, ui
// the wtv header/root sections and calculate the skip_chunks.
// If successful, will return with the file positioned
// at the start of the data dir
int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb)
{
int64_t result;
ctx->startbytes_avail = (int)buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
return_to_buffer(ctx->startbytes, ctx->startbytes_avail);
return_to_buffer(ctx, ctx->startbytes, ctx->startbytes_avail);
uint8_t *parsebuf;
parsebuf = (uint8_t*)malloc(1024);
buffered_read(ctx, parsebuf,0x42);
result = buffered_read(ctx, parsebuf,0x42);
ctx->past+=result;
if (result!=0x42)
{
mprint("\nPremature end of file!\n");
end_of_file=1;
return 0;
return CCX_EOF;
}
// Expecting WTV header
if( !memcmp(parsebuf, WTV_HEADER, 16 ) )
@@ -192,8 +196,7 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
else
{
mprint("\nMissing WTV header. Abort.\n");
end_of_file=1;
return 0;
return CCX_EOF;
}
//Next read just enough to get the location of the root directory
@@ -205,21 +208,18 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
dbg_print(CCX_DMT_PARSE, "root_dir: %x\n", root_dir);
//Seek to start of the root dir. Typically 0x1100
buffered_skip(ctx, (root_dir*WTV_CHUNK_SIZE)-0x42);
ctx->past+=(root_dir*WTV_CHUNK_SIZE)-0x42;
result = buffered_skip(ctx,(root_dir*WTV_CHUNK_SIZE)-0x42);
ctx->past += (root_dir*WTV_CHUNK_SIZE)-0x42;
if (result!=(root_dir*WTV_CHUNK_SIZE)-0x42)
{
end_of_file=1;
return 0;
}
return CCX_EOF;
// Read and calculate the meta data chunks in the file we need to skip over
// while parsing the file.
int end=0;
while(!end)
{
buffered_read(ctx, parsebuf, 32);
result = buffered_read(ctx, parsebuf, 32);
int x;
for(x=0; x<16; x++)
dbg_print(CCX_DMT_PARSE, "%02X ", parsebuf[x]);
@@ -228,9 +228,8 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
if (result!=32)
{
mprint("\nPremature end of file!\n");
end_of_file=1;
free(parsebuf);
return 0;
return CCX_EOF;
}
ctx->past+=32;
if( !memcmp(parsebuf, WTV_EOF, 16 ))
@@ -250,17 +249,15 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
if(len>1024)
{
mprint("Too large for buffer!\n");
end_of_file=1;
free(parsebuf);
return 0;
return CCX_EOF;
}
buffered_read(ctx, parsebuf, len-32);
result = buffered_read(ctx, parsebuf, len-32);
if (result!=len-32)
{
mprint("Premature end of file!\n");
end_of_file=1;
free(parsebuf);
return 0;
return CCX_EOF;
}
ctx->past+=len-32;
// Read a unicode string
@@ -287,9 +284,8 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
if(!add_skip_chunks(ctx, cb, value, flag))
{
mprint("Premature end of file!\n");
end_of_file=1;
free(parsebuf);
return 0;
return CCX_EOF;
}
}
free(string);
@@ -306,46 +302,52 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
// Seek forward to the start of the data dir
// Typically 0x40000
buffered_skip(ctx, (int)((cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE)-ctx->past));
cb->filepos=(cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE);
result = buffered_skip(ctx,(int)((cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE)-ctx->past));
cb->filepos = (cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE);
cb->chunk++;
ctx->past=cb->filepos;
ctx->past = cb->filepos;
free(parsebuf);
return 1;
return CCX_OK;
}
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct demuxer_data *data)
{
static int video_streams[32];
static int alt_stream; //Stream to use for timestamps if the cc stream has broken timestamps
static int use_alt_stream = 0;
static int num_streams=0;
static int num_streams = 0;
int64_t result;
struct lib_cc_decode *dec_ctx = update_decoder_list(ctx);
while(1)
{
int bytesread = 0;
// Read the 32 bytes containing the GUID and length and stream_id info
get_sized_buffer(ctx, cb, 32);
if(cb->buffer==NULL) {end_of_file=1; return 0; } //Make this a macro?
uint8_t guid[16];
memcpy(&guid, cb->buffer, 16); // Read the GUID
int x;
uint32_t len;
uint32_t pad;
uint32_t stream_id;
// Read the 32 bytes containing the GUID and length and stream_id info
get_sized_buffer(ctx->demux_ctx, cb, 32);
if(cb->buffer == NULL)
return CCX_EOF;
memcpy(&guid, cb->buffer, 16); // Read the GUID
for(x=0; x<16; x++)
dbg_print(CCX_DMT_PARSE, "%02X ", guid[x]);
dbg_print(CCX_DMT_PARSE, "\n");
uint32_t len;
memcpy(&len, cb->buffer+16, 4); // Read the length
len-=32;
dbg_print(CCX_DMT_PARSE, "len %X\n", len);
uint32_t pad;
pad = len%8==0 ? 0 : 8- (len % 8); // Calculate the padding to add to the length
// to get to the next GUID
dbg_print(CCX_DMT_PARSE, "pad %X\n", pad);
uint32_t stream_id;
memcpy(&stream_id, cb->buffer+20, 4);
stream_id = stream_id & 0x7f; // Read and calculate the stream_id
dbg_print(CCX_DMT_PARSE, "stream_id: %X\n", stream_id);
dbg_print(CCX_DMT_PARSE, "stream_id: 0x%X\n", stream_id);
for(x=0; x<num_streams; x++)
dbg_print(CCX_DMT_PARSE, "video stream_id: %X\n", video_streams[x]);
@@ -354,30 +356,31 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
// This is the end of the data in this file
// read the padding at the end of the file
// and return one more byte
dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
uint8_t *parsebuf;
dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
parsebuf = (uint8_t*)malloc(1024);
do {
buffered_read(ctx, parsebuf, 1024);
ctx->past+=1024;
result = buffered_read(ctx->demux_ctx, parsebuf, 1024);
ctx->demux_ctx->past+=1024;
} while (result==1024);
ctx->past+=result;
ctx->demux_ctx->past+=result;
free(parsebuf);
free(cb->buffer);
cb->buffer=NULL;
//return one more byte so the final percentage is shown correctly
*(ctx->buffer+inbuf)=0x00;
end_of_file=1;
inbuf++;
return 1;
*(data->buffer+data->len)=0x00;
data->len++;
return CCX_EOF;
}
if( !memcmp(guid, WTV_STREAM2, 16 ) )
{
// The WTV_STREAM2 GUID appares near the start of the data dir
// It maps stream_ids to the type of stream
dbg_print(CCX_DMT_PARSE, "WTV STREAM2\n");
get_sized_buffer(ctx, cb, 0xc+16);
if(cb->buffer==NULL) {end_of_file=1; return 0; }
get_sized_buffer(ctx->demux_ctx, cb, 0xc+16);
if(cb->buffer==NULL)
return CCX_EOF;
static unsigned char stream_type[16];
memcpy(&stream_type, cb->buffer+0xc, 16); //Read the stream type GUID
const void *stream_guid;
@@ -397,18 +400,19 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
if (!memcmp(guid, WTV_TIMING, 16) && ((use_alt_stream < WTV_CC_TIMESTAMP_MAGIC_THRESH && check_stream_id(stream_id, video_streams, num_streams))
|| (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH && stream_id == alt_stream)))
{
int64_t time;
// The WTV_TIMING GUID contains a timestamp for the given stream_id
dbg_print(CCX_DMT_PARSE, "WTV TIMING\n");
get_sized_buffer(ctx, cb, 0x8+0x8);
if(cb->buffer==NULL) {end_of_file=1; return 0; }
int64_t time;
get_sized_buffer(ctx->demux_ctx, cb, 0x8+0x8);
if(cb->buffer==NULL)
return CCX_EOF;
memcpy(&time, cb->buffer+0x8, 8); // Read the timestamp
dbg_print(CCX_DMT_PARSE, "TIME: %ld\n", time);
if (time != -1 && time != WTV_CC_TIMESTAMP_MAGIC) { // Ignore -1 timestamps
current_pts = time_to_pes_time(time); // Convert from WTV to PES time
pts_set = 1;
set_current_pts(dec_ctx->timing, time_to_pes_time(time));
frames_since_ref_time = 0;
set_fts();
set_fts(dec_ctx->timing);
}
else if (time == WTV_CC_TIMESTAMP_MAGIC && stream_id != alt_stream) {
use_alt_stream++;
@@ -419,21 +423,22 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
len-=16;
}
if( !memcmp(guid, WTV_DATA, 16 )
&& check_stream_id(stream_id, video_streams, num_streams) && current_pts!=0
&& check_stream_id(stream_id, video_streams, num_streams) && dec_ctx->timing->current_pts != 0
&& (ccx_options.wtvmpeg2 || (!ccx_options.wtvmpeg2 && len==2)))
{
// This is the data for a stream we want to process
dbg_print(CCX_DMT_PARSE, "\nWTV DATA\n");
get_sized_buffer(ctx, cb, len);
if(cb->buffer==NULL) {end_of_file=1; return 0; }
memcpy(ctx->buffer+inbuf, cb->buffer, len);
inbuf+=result;
get_sized_buffer(ctx->demux_ctx, cb, len);
if(cb->buffer==NULL)
return CCX_EOF;
memcpy(data->buffer+data->len, cb->buffer, len);
data->len += len;
bytesread+=(int) len;
frames_since_ref_time++;
set_fts();
set_fts(dec_ctx->timing);
if(pad>0)
{ //Make sure we skip any padding too, since we are returning here
skip_sized_buffer(ctx, cb, pad);
skip_sized_buffer(ctx->demux_ctx, cb, pad);
}
return bytesread;
}
@@ -442,26 +447,52 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
// skip any remaining data
// For any unhandled GUIDs this will be len+pad
// For others it will just be pad
skip_sized_buffer(ctx, cb, len+pad);
skip_sized_buffer(ctx->demux_ctx, cb, len+pad);
}
}
}
LLONG wtv_getmoredata(struct lib_ccx_ctx *ctx)
int wtv_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data ** ppdata)
{
static struct wtv_chunked_buffer cb;
if(firstcall)
{
init_chunked_buffer(&cb);
if(ccx_options.wtvmpeg2)
ccx_bufferdatatype=CCX_PES;
else
ccx_bufferdatatype=CCX_RAW;
if(read_header(ctx, &cb)==0)
// read_header returned an error
// read_header will have printed the error message
return 0;
firstcall=0;
}
return get_data(ctx, &cb);
int ret = CCX_OK;
struct demuxer_data *data;
if(!*ppdata)
{
*ppdata = alloc_demuxer_data();
if(!*ppdata)
return -1;
data = *ppdata;
//TODO Set to dummy, find and set actual value
data->program_number = 1;
data->stream_pid = 1;
data->codec = CCX_CODEC_ATSC_CC;
}
else
{
data = *ppdata;
}
if(firstcall)
{
init_chunked_buffer(&cb);
if(ccx_options.wtvmpeg2)
data->bufferdatatype=CCX_PES;
else
data->bufferdatatype=CCX_RAW;
read_header(ctx->demux_ctx, &cb);
if(ret != CCX_OK)
{
// read_header returned an error
// read_header will have printed the error message
return ret;
}
firstcall=0;
}
ret = get_data(ctx, &cb, data);
return ret;
}

14
src/win_iconv/iconv.h Executable file
View File

@@ -0,0 +1,14 @@
#ifndef _LIBICONV_H
#define _LIBICONV_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* iconv_t;
iconv_t iconv_open(const char *tocode, const char *fromcode);
int iconv_close(iconv_t cd);
size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
#ifdef __cplusplus
}
#endif
#endif

4145
src/win_iconv/win_iconv.h → src/win_iconv/win_iconv.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -42,6 +42,7 @@
<ClInclude Include="..\src\libpng\pngpriv.h" />
<ClInclude Include="..\src\libpng\pngstruct.h" />
<ClInclude Include="..\src\lib_ccx\608_spupng.h" />
<ClInclude Include="..\src\lib_ccx\avc_functions.h" />
<ClInclude Include="..\src\lib_ccx\ccx_common_char_encoding.h" />
<ClInclude Include="..\src\lib_ccx\ccx_common_common.h" />
<ClInclude Include="..\src\lib_ccx\ccx_common_constants.h" />
@@ -50,7 +51,10 @@
<ClInclude Include="..\src\lib_ccx\ccx_common_timing.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_608.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_encoding.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_output.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_common.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_isdb.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_structs.h" />
<ClInclude Include="..\src\lib_ccx\ccx_decoders_xds.h" />
<ClInclude Include="..\src\lib_ccx\ccx_encoders_common.h" />
@@ -61,6 +65,7 @@
<ClInclude Include="..\src\lib_ccx\lib_ccx.h" />
<ClInclude Include="..\src\lib_ccx\spupng_encoder.h" />
<ClInclude Include="..\src\lib_ccx\teletext.h" />
<ClInclude Include="..\src\lib_ccx\utility.h" />
<ClInclude Include="..\src\zlib\crc32.h" />
<ClInclude Include="..\src\zlib\deflate.h" />
<ClInclude Include="..\src\zlib\gzguts.h" />
@@ -134,11 +139,6 @@
<ClCompile Include="..\src\libpng\pngwrite.c" />
<ClCompile Include="..\src\libpng\pngwtran.c" />
<ClCompile Include="..\src\libpng\pngwutil.c" />
<ClCompile Include="..\src\lib_ccx\608_sami.c" />
<ClCompile Include="..\src\lib_ccx\608_smptett.c" />
<ClCompile Include="..\src\lib_ccx\608_spupng.c" />
<ClCompile Include="..\src\lib_ccx\608_srt.c" />
<ClCompile Include="..\src\lib_ccx\708_encoding.c" />
<ClCompile Include="..\src\lib_ccx\activity.c" />
<ClCompile Include="..\src\lib_ccx\asf_functions.c" />
<ClCompile Include="..\src\lib_ccx\avc_functions.c" />
@@ -149,10 +149,21 @@
<ClCompile Include="..\src\lib_ccx\ccx_common_timing.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_608.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_common.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_isdb.c" />
<ClCompile Include="..\src\lib_ccx\ccx_decoders_xds.c" />
<ClCompile Include="..\src\lib_ccx\ccx_demuxer.c" />
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_common.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_helpers.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_spupng.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_srt.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_webvtt.c" />
<ClCompile Include="..\src\lib_ccx\ccx_encoders_xds.c" />
<ClCompile Include="..\src\lib_ccx\cc_bitstream.c" />
<ClCompile Include="..\src\lib_ccx\configuration.c" />
<ClCompile Include="..\src\lib_ccx\dvb_subtitle_decoder.c" />
@@ -172,10 +183,12 @@
<ClCompile Include="..\src\lib_ccx\stream_functions.c" />
<ClCompile Include="..\src\lib_ccx\telxcc.c" />
<ClCompile Include="..\src\lib_ccx\ts_functions.c" />
<ClCompile Include="..\src\lib_ccx\ts_info.c" />
<ClCompile Include="..\src\lib_ccx\ts_tables.c" />
<ClCompile Include="..\src\lib_ccx\ts_tables_epg.c" />
<ClCompile Include="..\src\lib_ccx\utility.c" />
<ClCompile Include="..\src\lib_ccx\wtv_functions.c" />
<ClCompile Include="..\src\win_iconv\win_iconv.c" />
<ClCompile Include="..\src\zlib\adler32.c" />
<ClCompile Include="..\src\zlib\crc32.c" />
<ClCompile Include="..\src\zlib\deflate.c" />
@@ -193,7 +206,7 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>

View File

@@ -240,6 +240,21 @@
<ClInclude Include="..\src\lib_ccx\lib_ccx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_encoding.h">
<Filter>Header Files\ccx_decoders</Filter>
</ClInclude>
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_output.h">
<Filter>Header Files\ccx_decoders</Filter>
</ClInclude>
<ClInclude Include="..\src\lib_ccx\ccx_decoders_isdb.h">
<Filter>Header Files\ccx_decoders</Filter>
</ClInclude>
<ClInclude Include="..\src\lib_ccx\avc_functions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\lib_ccx\utility.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\ccextractor.c">
@@ -533,21 +548,6 @@
<ClCompile Include="..\src\lib_ccx\ccx_common_timing.c">
<Filter>Source Files\ccx_common</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\608_sami.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\608_smptett.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\608_spupng.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\608_srt.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\708_encoding.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_common.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
@@ -566,5 +566,56 @@
<ClCompile Include="..\src\lib_ccx\ts_tables_epg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_demuxer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ts_info.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c">
<Filter>Source Files\ccx_decoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c">
<Filter>Source Files\ccx_decoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c">
<Filter>Source Files\ccx_decoders</Filter>
</ClCompile>
<ClCompile Include="..\src\win_iconv\win_iconv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c">
<Filter>Source Files\ccx_decoders</Filter>
</ClCompile>
<ClCompile Include="..\src\win_iconv\win_iconv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_spupng.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_srt.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_webvtt.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_encoders_xds.c">
<Filter>Source Files\ccx_encoders</Filter>
</ClCompile>
<ClCompile Include="..\src\lib_ccx\ccx_decoders_isdb.c">
<Filter>Source Files\ccx_decoders</Filter>
</ClCompile>
</ItemGroup>
</Project>