mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-08 13:34:59 +00:00
Compare commits
459 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0de521f22b | ||
|
|
c027b449cf | ||
|
|
0427878dbd | ||
|
|
93797023e3 | ||
|
|
02cd11ec7c | ||
|
|
edc3d85cd5 | ||
|
|
0e9d0e6e46 | ||
|
|
07e9d8a04e | ||
|
|
524ec68a63 | ||
|
|
046fd4c435 | ||
|
|
2fb03f3af3 | ||
|
|
cd4267bc2e | ||
|
|
48c4306cdc | ||
|
|
63fd4ad847 | ||
|
|
2cf86d46ff | ||
|
|
3c3f7afb32 | ||
|
|
a046be0ebb | ||
|
|
dc2af919eb | ||
|
|
23b7470daf | ||
|
|
78585c84b4 | ||
|
|
02b93fa73f | ||
|
|
3c6aff704c | ||
|
|
beeb797b6e | ||
|
|
d275463039 | ||
|
|
51dae0ba8d | ||
|
|
850f5f98b6 | ||
|
|
0424a474bc | ||
|
|
37496f8a1a | ||
|
|
02593c9867 | ||
|
|
79ab53876c | ||
|
|
a917695029 | ||
|
|
b2bfebce6f | ||
|
|
5b5f358919 | ||
|
|
92df11162c | ||
|
|
6feef59d75 | ||
|
|
944c6d25a2 | ||
|
|
9e94520a54 | ||
|
|
d249b1cf1b | ||
|
|
5661e4f37b | ||
|
|
e8ae2874d6 | ||
|
|
f3c386f729 | ||
|
|
03b8f93e04 | ||
|
|
2a583883dc | ||
|
|
1cee9200b2 | ||
|
|
c634cf5ada | ||
|
|
804c6414ee | ||
|
|
0cc9642851 | ||
|
|
286398c15d | ||
|
|
d0b57ecb1f | ||
|
|
5b11c6a5c6 | ||
|
|
90c8da76bd | ||
|
|
e87ed5ba1c | ||
|
|
1aa9a7c4d9 | ||
|
|
509cb9839d | ||
|
|
0089901b07 | ||
|
|
877ee7b2c7 | ||
|
|
d117dacf0f | ||
|
|
1ea58bd200 | ||
|
|
dcc8af915f | ||
|
|
4d4af9ff7f | ||
|
|
a9a861e8f2 | ||
|
|
ab70c8b382 | ||
|
|
d8e99ef810 | ||
|
|
c92e92f73d | ||
|
|
d3862ba88b | ||
|
|
0023c6545b | ||
|
|
2ca835ea1b | ||
|
|
20859d3ee7 | ||
|
|
e79700ea93 | ||
|
|
e02d9bd98b | ||
|
|
d7136a8390 | ||
|
|
e1d8da9d37 | ||
|
|
cfecd67500 | ||
|
|
26623b2428 | ||
|
|
44d9117d8d | ||
|
|
31de878ea7 | ||
|
|
9768555e7c | ||
|
|
72e422d76e | ||
|
|
8860be13e4 | ||
|
|
3b7ad97f0a | ||
|
|
5e305f2769 | ||
|
|
0a798606ee | ||
|
|
3775daf36c | ||
|
|
8c5de01034 | ||
|
|
1c352e67e4 | ||
|
|
79838077f2 | ||
|
|
058bb83a25 | ||
|
|
d2f840bb36 | ||
|
|
a576c90f4e | ||
|
|
a1bd01de5f | ||
|
|
9a5e817f36 | ||
|
|
bc20bc3f45 | ||
|
|
783a6e2aa0 | ||
|
|
992c56b262 | ||
|
|
c674cef79e | ||
|
|
509ed756fd | ||
|
|
152b69ddba | ||
|
|
c2eedab33d | ||
|
|
677fee4145 | ||
|
|
72dad743dc | ||
|
|
e262b0699a | ||
|
|
6942089a32 | ||
|
|
993adc3dec | ||
|
|
fe7a39c0cb | ||
|
|
3bd704e495 | ||
|
|
6992e54f8e | ||
|
|
4d5ab77fed | ||
|
|
1b2328d728 | ||
|
|
2944e12541 | ||
|
|
763972ca4b | ||
|
|
01fe0c1fc9 | ||
|
|
8d160a70ff | ||
|
|
fc90b9c9f5 | ||
|
|
0a803df23f | ||
|
|
d3a1ed4b06 | ||
|
|
ad89e0074b | ||
|
|
169a39eb3e | ||
|
|
a6145af7f3 | ||
|
|
03b60ef140 | ||
|
|
1b7ef1e198 | ||
|
|
72de68a575 | ||
|
|
24e7b94599 | ||
|
|
c5dc4531ae | ||
|
|
a3e07b4a63 | ||
|
|
d48555b849 | ||
|
|
a1f05caddf | ||
|
|
669eb36603 | ||
|
|
ce379bcfda | ||
|
|
00657ffdcd | ||
|
|
d9e0ba027f | ||
|
|
a7279e3d8a | ||
|
|
61ae7e9f10 | ||
|
|
548d323ca1 | ||
|
|
d2d7a17f3b | ||
|
|
65b0ed0038 | ||
|
|
2b0523d34c | ||
|
|
5bef6bd5a4 | ||
|
|
5ca3965c7b | ||
|
|
e855665c87 | ||
|
|
e9bf8dad9f | ||
|
|
54c2b21a4c | ||
|
|
afe5cba480 | ||
|
|
8c34f4cbb2 | ||
|
|
e422e7075a | ||
|
|
cc0ee507dd | ||
|
|
540850f0b9 | ||
|
|
a973c0a9c3 | ||
|
|
ae27b3411b | ||
|
|
89c4ac091a | ||
|
|
843ca9b60a | ||
|
|
d135362d40 | ||
|
|
2f1b9df6e9 | ||
|
|
5ef2519bf5 | ||
|
|
f258d317cc | ||
|
|
4d3fcd6779 | ||
|
|
f1b0aff789 | ||
|
|
6e9a30b354 | ||
|
|
37091708b7 | ||
|
|
0885aae79c | ||
|
|
5e5d30d154 | ||
|
|
a614db1e20 | ||
|
|
f7f29e558b | ||
|
|
ddc1bfe74f | ||
|
|
18b95d9564 | ||
|
|
b012f87d87 | ||
|
|
73f277fe95 | ||
|
|
bd3df850a5 | ||
|
|
73b52462c0 | ||
|
|
267d7b4a2e | ||
|
|
35cdeda56c | ||
|
|
0f90eebdf6 | ||
|
|
962357ed0f | ||
|
|
69d077df9e | ||
|
|
e2b0534374 | ||
|
|
4204b7878d | ||
|
|
1e2237f7ec | ||
|
|
6bfe3b3f86 | ||
|
|
940bee33a4 | ||
|
|
7c787157d8 | ||
|
|
7514886199 | ||
|
|
ad5b917f3b | ||
|
|
66408fc950 | ||
|
|
94ec02eea9 | ||
|
|
5e33e2e2ac | ||
|
|
34613037fc | ||
|
|
f2b24f13af | ||
|
|
c718d21d0f | ||
|
|
a2828f0060 | ||
|
|
4b3b846a2c | ||
|
|
b232945c71 | ||
|
|
f91d1cb9b7 | ||
|
|
fadd8aad8b | ||
|
|
b0479b247a | ||
|
|
a659544bd2 | ||
|
|
9ce4c99180 | ||
|
|
52f51147b8 | ||
|
|
34836b50a1 | ||
|
|
7179796365 | ||
|
|
966c90eece | ||
|
|
3281bf929a | ||
|
|
906a0704bc | ||
|
|
20785c095c | ||
|
|
dee2280d06 | ||
|
|
f6b69b64c3 | ||
|
|
2f09b37f7c | ||
|
|
20cf0f5151 | ||
|
|
860e926b5a | ||
|
|
9f81a4b5c1 | ||
|
|
5d85220121 | ||
|
|
6423efa2d7 | ||
|
|
932cb77265 | ||
|
|
691244a00e | ||
|
|
440c59a5fd | ||
|
|
8a3e2b5efc | ||
|
|
119a4361df | ||
|
|
6c93b6dcf4 | ||
|
|
4d76cd30c0 | ||
|
|
96fd051e01 | ||
|
|
2fe0da30be | ||
|
|
890e045a88 | ||
|
|
b333df4317 | ||
|
|
33d91a979c | ||
|
|
b3614f592f | ||
|
|
3bdb5f3863 | ||
|
|
ad6346f802 | ||
|
|
66f41438be | ||
|
|
647a91eafa | ||
|
|
ecf200e290 | ||
|
|
da576bff2b | ||
|
|
fcbf113526 | ||
|
|
b90d144ff6 | ||
|
|
2ac0ed2032 | ||
|
|
0afefc0392 | ||
|
|
9efe2b4b22 | ||
|
|
d54d881390 | ||
|
|
58b496a434 | ||
|
|
41a8803860 | ||
|
|
4146423878 | ||
|
|
1c35dcae03 | ||
|
|
3bcdbce709 | ||
|
|
250ee1f29b | ||
|
|
fd1a86b2f5 | ||
|
|
3433ed2e5c | ||
|
|
c7606beae1 | ||
|
|
d639323e4c | ||
|
|
72e780f175 | ||
|
|
651dc67a5d | ||
|
|
6cfd7710a7 | ||
|
|
adc1d4662d | ||
|
|
5c51b582bf | ||
|
|
16e794163c | ||
|
|
4e25d80b48 | ||
|
|
2949918ed1 | ||
|
|
46ea522ecb | ||
|
|
f571a04ffc | ||
|
|
610b811d53 | ||
|
|
e5c4053c05 | ||
|
|
0b9bf16850 | ||
|
|
8489edf966 | ||
|
|
22127cccb0 | ||
|
|
57eb42c7bb | ||
|
|
0a6630f7ab | ||
|
|
b89dd8d401 | ||
|
|
778e66f951 | ||
|
|
7a06d99443 | ||
|
|
3fff94a555 | ||
|
|
b65cc8ad8e | ||
|
|
28ddfef2b1 | ||
|
|
f23cc1f41e | ||
|
|
1ca63ba125 | ||
|
|
af66ace345 | ||
|
|
c0079aee6f | ||
|
|
21a88f9cc1 | ||
|
|
9923ef98ee | ||
|
|
abce1dd873 | ||
|
|
308d500308 | ||
|
|
ae6cf97bce | ||
|
|
53bedd30c1 | ||
|
|
764d251986 | ||
|
|
1bfb96151f | ||
|
|
741e87e00e | ||
|
|
098bff1230 | ||
|
|
0374c5ec78 | ||
|
|
e7bec67c93 | ||
|
|
b9e0f67dec | ||
|
|
acd96d44d2 | ||
|
|
4e4da44c39 | ||
|
|
bb0f836e84 | ||
|
|
5f6a8c7f54 | ||
|
|
0c6bf5d8b1 | ||
|
|
f8210f94f2 | ||
|
|
243674ed96 | ||
|
|
322d352ca0 | ||
|
|
c8c71085e1 | ||
|
|
4969e6a8fd | ||
|
|
ece4a5fa8a | ||
|
|
7d034f44e4 | ||
|
|
c12d3856f2 | ||
|
|
24f9106cde | ||
|
|
58503141c3 | ||
|
|
3b214f491b | ||
|
|
f83ca18c7d | ||
|
|
1261cee8dc | ||
|
|
92ecaa9434 | ||
|
|
fd66228b26 | ||
|
|
bfd7556b50 | ||
|
|
3174e3dc9e | ||
|
|
ec26080bd2 | ||
|
|
5ea83ccf9d | ||
|
|
5af65d941a | ||
|
|
0d79ad3cb6 | ||
|
|
8499a6b426 | ||
|
|
577a79de47 | ||
|
|
6133b9c26d | ||
|
|
c4e91f8ccc | ||
|
|
589fd91d8e | ||
|
|
03eba6114b | ||
|
|
56f0786cc3 | ||
|
|
aff591fd9b | ||
|
|
bdaa3a1352 | ||
|
|
f3b104584d | ||
|
|
e47315e423 | ||
|
|
43335e30a9 | ||
|
|
79c4a48d60 | ||
|
|
a5538902ec | ||
|
|
1b9d905b28 | ||
|
|
89c8b018c8 | ||
|
|
cde69fdd88 | ||
|
|
a798fdf57e | ||
|
|
8b89ad0c5a | ||
|
|
309f4130e0 | ||
|
|
0f2ccdbe4f | ||
|
|
eeb33de590 | ||
|
|
91a8997826 | ||
|
|
5fb7bc434c | ||
|
|
77540355ed | ||
|
|
c5362b682e | ||
|
|
e0f3751fe8 | ||
|
|
54583f95a3 | ||
|
|
990e653e91 | ||
|
|
9d2fb48d3d | ||
|
|
e5e51c4389 | ||
|
|
74dbd4d7e5 | ||
|
|
784a46d165 | ||
|
|
83e1959db8 | ||
|
|
e0bf79f28b | ||
|
|
5c1f4772c7 | ||
|
|
deca14c2c2 | ||
|
|
8023ebe8e2 | ||
|
|
0e98604267 | ||
|
|
7e68c8e823 | ||
|
|
601dbfd062 | ||
|
|
35983534f1 | ||
|
|
f88330c7c9 | ||
|
|
a0bf7dadf8 | ||
|
|
f2added8d1 | ||
|
|
9f78a843ee | ||
|
|
3e78fdd675 | ||
|
|
c5dfd52eb9 | ||
|
|
08df39c3d4 | ||
|
|
9fad88fee3 | ||
|
|
6ae94fdbab | ||
|
|
8d5f0e5505 | ||
|
|
11b614cedf | ||
|
|
fc79649c9c | ||
|
|
b85e93a2cb | ||
|
|
dd8923b2e4 | ||
|
|
1437aea328 | ||
|
|
1fdad2314f | ||
|
|
6aac9dad43 | ||
|
|
fc248dd41f | ||
|
|
a2394df838 | ||
|
|
306d60ccf9 | ||
|
|
d78a722260 | ||
|
|
4a34799e09 | ||
|
|
489622fb0b | ||
|
|
9689dd8c19 | ||
|
|
d29f6817c6 | ||
|
|
f9ea7009fe | ||
|
|
ddd8381440 | ||
|
|
964b8c1165 | ||
|
|
0541a2fb62 | ||
|
|
f3654174fc | ||
|
|
0fc1055da6 | ||
|
|
a654b133e5 | ||
|
|
3a886c6a5b | ||
|
|
4a8d51aed1 | ||
|
|
70f5723c89 | ||
|
|
b85702a706 | ||
|
|
0bf1e83fa1 | ||
|
|
67d62631aa | ||
|
|
43f276abca | ||
|
|
7cea808f46 | ||
|
|
adbe8ed934 | ||
|
|
a3eba7cf45 | ||
|
|
3f26290614 | ||
|
|
d63660468a | ||
|
|
3daecf66a3 | ||
|
|
16db90a630 | ||
|
|
c1d7f82819 | ||
|
|
f8ee9504a8 | ||
|
|
c75d056b76 | ||
|
|
6c38f1b73b | ||
|
|
00b61a291d | ||
|
|
fcdc5f852b | ||
|
|
0424b0f119 | ||
|
|
82559fd572 | ||
|
|
3837ffae59 | ||
|
|
2e4cda0383 | ||
|
|
dc6ef18c21 | ||
|
|
bf3790183a | ||
|
|
bfa8b593ab | ||
|
|
401d679f80 | ||
|
|
157faaf0b5 | ||
|
|
cb49812d17 | ||
|
|
d88fa2a3ce | ||
|
|
5716ab7cfc | ||
|
|
04b9e40cc5 | ||
|
|
2f92036557 | ||
|
|
6aaa4fe2d4 | ||
|
|
ab0f54bb57 | ||
|
|
6642084132 | ||
|
|
c5ca7c7e1a | ||
|
|
5b24334b43 | ||
|
|
df93801021 | ||
|
|
64285879db | ||
|
|
0523f0bcd5 | ||
|
|
c6721ebc3e | ||
|
|
9d22f9a466 | ||
|
|
d58fb00970 | ||
|
|
62e189a9cb | ||
|
|
dc17946a55 | ||
|
|
78d8d858d2 | ||
|
|
30e7f95f38 | ||
|
|
8026d2e671 | ||
|
|
c98e00201a | ||
|
|
9b0ba130f1 | ||
|
|
83aa9709f4 | ||
|
|
340549e916 | ||
|
|
6d41964bba | ||
|
|
71f030f4ee | ||
|
|
67653d06d3 | ||
|
|
ab9f3a4b4a | ||
|
|
d9e9305e2c | ||
|
|
2bcc0c5561 | ||
|
|
cd03d8a658 | ||
|
|
589074886b | ||
|
|
c6ca493752 | ||
|
|
aef649d23a | ||
|
|
610b7323f4 | ||
|
|
eb6f6a9000 | ||
|
|
f3fe829d48 | ||
|
|
cb39d12615 | ||
|
|
5d52026736 | ||
|
|
48dce9c7ce | ||
|
|
2032a754e6 | ||
|
|
aa353140ef | ||
|
|
ee47e8458f | ||
|
|
081f127c85 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ linux/ccextractor
|
||||
linux/depend
|
||||
windows/debug/**
|
||||
windows/release/**
|
||||
build/
|
||||
|
||||
####
|
||||
# Visual Studio project Ignored files
|
||||
|
||||
@@ -4,7 +4,7 @@ ccextractor
|
||||
Carlos' version (mainstream) is the most stable branch.
|
||||
|
||||
Extracting subtitles has never been so easy. Just type the following command:
|
||||
ccextrator "name of input"
|
||||
ccextractor "name of input"
|
||||
|
||||
Gui lovers should download the Sorceforge version of CCExtractor, the Git Version is not your cup of tea.
|
||||
http://ccextractor.sourceforge.net/download-ccextractor.html
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
0.79 (2016-01-09)
|
||||
-----------------
|
||||
- Support for Grid Format (g608)
|
||||
- Show Correct number of teletext packet processed
|
||||
- Removed Segfault on incorrect mp4 detection
|
||||
- Remove xml header from transcript format
|
||||
- Help message updated for Teletext
|
||||
- Added --help and -h for help message
|
||||
- Added --nohtmlescape option
|
||||
- Added --noscte20 option
|
||||
|
||||
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).
|
||||
|
||||
58
docs/G608.TXT
Normal file
58
docs/G608.TXT
Normal file
@@ -0,0 +1,58 @@
|
||||
G608
|
||||
====
|
||||
G608 (for grid 608) is generated by CCExtractor by using -out=g608.
|
||||
|
||||
This is a verbose format that exports the contents of the 608 grid verbatim
|
||||
so there's no loss of positioning or colors due the limitations or complexy
|
||||
or other output formats.
|
||||
|
||||
G608 is a text file with a structure based on .srt and looks like this:
|
||||
|
||||
1
|
||||
00:00:02,019 --> 00:00:03,585
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
99999999999999999999999999999999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
- Previously on The Tudors... 90000000000000000000000000000009RIIIIIIIIIIIIIIIIRRRRRRRRRRRRRRR
|
||||
- Your Holy Father offs you 99000000000000000000000000000999RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
|
||||
For each subtitle frame there's exactly 15 rows (which represent the 15 rows of the 608 screen)
|
||||
of 96 characters each.
|
||||
|
||||
Each row is divided in 3 blocks: 32 characters for the text, 32 characters for the color, and
|
||||
32 characters for the font.
|
||||
|
||||
The possible color values are:
|
||||
COL_WHITE = 0,
|
||||
COL_GREEN = 1,
|
||||
COL_BLUE = 2,
|
||||
COL_CYAN = 3,
|
||||
COL_RED = 4,
|
||||
COL_YELLOW = 5,
|
||||
COL_MAGENTA = 6,
|
||||
COL_USERDEFINED = 7,
|
||||
COL_BLACK = 8,
|
||||
COL_TRANSPARENT = 9
|
||||
|
||||
And the possible font values are:
|
||||
R => Regular
|
||||
I => Italic
|
||||
U => Underlined
|
||||
B => Underlined + italic
|
||||
|
||||
If a 'E' is found in ether color or font that means a bug in CCExtractor. Should you ever get
|
||||
an E please send us a .bin file that causes it.
|
||||
|
||||
This format is intended for post processing tools that need to represent the output of a 608
|
||||
decoder accurately but that don't want to deal with the madness of other more generic subtitle
|
||||
formats.
|
||||
18
docs/OCR.txt
18
docs/OCR.txt
@@ -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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ccextractor, 0.77
|
||||
ccextractor, 0.79
|
||||
-----------------
|
||||
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
|
||||
|
||||
339
docs/gpl-2.0.txt
Normal file
339
docs/gpl-2.0.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -4,6 +4,7 @@ CC = gcc
|
||||
SYS := $(shell gcc -dumpmachine)
|
||||
CFLAGS = -O3 -std=gnu99
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib -I../src/lib_ccx -I../src/.
|
||||
INCLUDE += -I../src/zvbi
|
||||
ALL_FLAGS = -Wno-write-strings -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm
|
||||
|
||||
@@ -13,7 +14,7 @@ endif
|
||||
TARGET = ccextractor
|
||||
|
||||
OBJS_DIR = objs
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib:../src/lib_ccx
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib:../src/lib_ccx:../src/zvbi
|
||||
|
||||
SRCS_DIR = ../src
|
||||
SRCS_C = $(wildcard $(SRCS_DIR)/*.c)
|
||||
@@ -27,6 +28,10 @@ SRCS_PNG_DIR = $(SRCS_DIR)/libpng
|
||||
SRCS_PNG = $(wildcard $(SRCS_PNG_DIR)/*.c)
|
||||
OBJS_PNG = $(SRCS_PNG:$(SRCS_PNG_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_ZVBI_DIR = $(SRCS_DIR)/zvbi
|
||||
SRCS_ZVBI = $(wildcard $(SRCS_ZVBI_DIR)/*.c)
|
||||
OBJS_ZVBI = $(SRCS_ZVBI:$(SRCS_ZVBI_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_GPACMP4_DIR = $(SRCS_DIR)/gpacmp4
|
||||
SRCS_GPACMP4_C = $(wildcard $(SRCS_GPACMP4_DIR)/*.c)
|
||||
SRCS_GPACMP4_CPP = $(wildcard $(SRCS_GPACMP4_DIR)/*.cpp)
|
||||
@@ -42,7 +47,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)
|
||||
|
||||
@@ -84,8 +89,8 @@ all: objs_dir $(TARGET)
|
||||
objs_dir:
|
||||
mkdir -p $(OBJS_DIR)
|
||||
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(OBJS_CCX)
|
||||
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_CCX) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZVBI) $(OBJS_ZLIB) $(OBJS_CCX)
|
||||
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZVBI) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJS_DIR)/%.o: %.c
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@
|
||||
@@ -113,7 +118,7 @@ uninstall:
|
||||
|
||||
.PHONY: depend dep
|
||||
depend dep:
|
||||
$(CC) $(CFLAGS) $(INCLUDE) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CCX) \
|
||||
$(CC) $(CFLAGS) $(INCLUDE) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZVBI) $(SRCS_ZLIB) $(SRCS_CCX) \
|
||||
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
|
||||
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend
|
||||
|
||||
|
||||
12
linux/build
12
linux/build
@@ -1,2 +1,12 @@
|
||||
#!/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/ -I../src/zvbi"
|
||||
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
|
||||
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
|
||||
SRC_ZVBI="$(find ../src/zvbi/ -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_ZVBI $SRC_LIBPNG"
|
||||
BLD_LINKER="-lm -zmuldefs"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
#!/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/ -I../src/zvbi"
|
||||
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
|
||||
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
|
||||
SRC_ZVBI="$(find ../src/zvbi/ -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_ZVBI $SRC_LIBPNG"
|
||||
BLD_LINKER="-lm -zmuldefs"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_DARWIN -D_FILE_OFFSET_BITS=64 -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I ../src/gpacmp4 -I ../src/lib_ccx -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp' \! -name 'win_*') $(find ../src/ -name '*.c' \! -name 'win_*') -liconv
|
||||
#!/bin/bash
|
||||
cd `dirname $0`
|
||||
BLD_FLAGS="-std=gnu99 -Wno-write-strings -DGPAC_CONFIG_DARWIN -D_FILE_OFFSET_BITS=64 -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek"
|
||||
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 -liconv"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
|
||||
@@ -20,6 +20,8 @@ configure_file (
|
||||
include_directories ("${PROJECT_SOURCE_DIR}")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/lib_ccx")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/gpacmp4/")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/zvbi")
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/zvbi" SOURCEFILE)
|
||||
|
||||
#Adding some platform specific library path
|
||||
link_directories (/opt/local/lib)
|
||||
@@ -44,9 +46,15 @@ if(PKG_CONFIG_FOUND)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} png)
|
||||
else (PNG_FOUND)
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/libpng/")
|
||||
include_directories ("${PROJEXT_SOURCE_DIR}/zlib/")
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/zlib/" SOURCEFILE)
|
||||
endif(PNG_FOUND)
|
||||
else(PKG_CONFIG_FOUND)
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/libpng/")
|
||||
include_directories ("${PROJEXT_SOURCE_DIR}/zlib/")
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/zlib/" SOURCEFILE)
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
|
||||
########################################################
|
||||
|
||||
@@ -8,7 +8,6 @@ License: GPL 2.0
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include "ffmpeg_intgr.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_mp4.h"
|
||||
|
||||
@@ -24,15 +23,10 @@ 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);
|
||||
|
||||
@@ -43,6 +37,10 @@ int main(int argc, char *argv[])
|
||||
usage ();
|
||||
fatal (EXIT_NO_INPUT_FILES, "(This help screen was shown because there were no input files)\n");
|
||||
}
|
||||
else if (ret == EXIT_WITH_HELP)
|
||||
{
|
||||
return EXIT_OK;
|
||||
}
|
||||
else if (ret != EXIT_OK)
|
||||
{
|
||||
exit(ret);
|
||||
@@ -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,39 +77,29 @@ 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);
|
||||
if (ctx->total_inputsize==-1)
|
||||
fatal (EXIT_UNABLE_TO_DETERMINE_FILE_SIZE, "Failed to determine total file size.\n");
|
||||
if (ctx->total_inputsize < 0)
|
||||
{
|
||||
switch (ctx->total_inputsize)
|
||||
{
|
||||
case -1*ENOENT:
|
||||
fatal(EXIT_NO_INPUT_FILES, "Failed to open file: File not Exist");
|
||||
case -1*EACCES:
|
||||
fatal(EXIT_READ_ERROR, "Failed to open file: Unable to access");
|
||||
case -1*EINVAL:
|
||||
fatal(EXIT_READ_ERROR, "Failed to open file: Invalid opening flag.");
|
||||
case -1*EMFILE:
|
||||
fatal(EXIT_TOO_MANY_INPUT_FILES, "Failed to open file: Too many files are open.");
|
||||
default:
|
||||
fatal(EXIT_READ_ERROR, "Failed to open file: Reason unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -298,149 +107,33 @@ 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
|
||||
close_input_file(ctx);
|
||||
ffmpeg_ctx = init_ffmpeg(ctx->inputfile[0]);
|
||||
if(ffmpeg_ctx)
|
||||
{
|
||||
do
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned char *bptr = ctx->buffer;
|
||||
int len = ff_get_ccframe(ffmpeg_ctx, bptr, 1024);
|
||||
int cc_count = 0;
|
||||
if(len == AVERROR(EAGAIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(len == AVERROR_EOF)
|
||||
break;
|
||||
else if(len == 0)
|
||||
continue;
|
||||
else if(len < 0 )
|
||||
{
|
||||
mprint("Error extracting Frame\n");
|
||||
break;
|
||||
|
||||
}
|
||||
else
|
||||
cc_count = len/3;
|
||||
ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_sub);
|
||||
if(ret >= 0 && dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}while(1);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
@@ -449,28 +142,32 @@ int main(int argc, char *argv[])
|
||||
case CCX_SM_PROGRAM:
|
||||
case CCX_SM_ASF:
|
||||
case CCX_SM_WTV:
|
||||
case CCX_SM_GXF:
|
||||
#ifdef ENABLE_FFMPEG
|
||||
case CCX_SM_FFMPEG:
|
||||
#endif
|
||||
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,173 +182,137 @@ 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)
|
||||
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
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 (ctx->total_pulldownframes)
|
||||
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)));
|
||||
|
||||
if (dec_ctx->codec == CCX_CODEC_ATSC_CC)
|
||||
{
|
||||
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 (dec_ctx->total_pulldownframes)
|
||||
mprint ("incl. pulldown frames: %s (%u frames at %.2ffps)\n",
|
||||
print_mstime( (LLONG)(ctx->total_pulldownframes*1000/current_fps) ),
|
||||
ctx->total_pulldownframes, current_fps);
|
||||
if (pts_set >= 1 && min_pts != 0x01FFFFFFFFLL)
|
||||
print_mstime( (LLONG)(dec_ctx->total_pulldownframes*1000/current_fps) ),
|
||||
dec_ctx->total_pulldownframes, current_fps);
|
||||
if (dec_ctx->timing->pts_set >= 1 && dec_ctx->timing->min_pts != 0x01FFFFFFFFLL)
|
||||
{
|
||||
LLONG postsyncms = (LLONG) (ctx->frames_since_last_gop*1000/current_fps);
|
||||
LLONG postsyncms = (LLONG) (dec_ctx->frames_since_last_gop*1000/current_fps);
|
||||
mprint ("\nMin PTS: %s\n",
|
||||
print_mstime( min_pts/(MPEG_CLOCK_FREQ/1000) - fts_offset));
|
||||
print_mstime( dec_ctx->timing->min_pts/(MPEG_CLOCK_FREQ/1000) - dec_ctx->timing->fts_offset));
|
||||
if (pts_big_change)
|
||||
mprint ("(Reference clock was reset at some point, Min PTS is approximated)\n");
|
||||
mprint ("Max PTS: %s\n",
|
||||
print_mstime( sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms));
|
||||
print_mstime( dec_ctx->timing->sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms));
|
||||
|
||||
mprint ("Length: %s\n",
|
||||
print_mstime( sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms
|
||||
- min_pts/(MPEG_CLOCK_FREQ/1000) + fts_offset ));
|
||||
print_mstime( dec_ctx->timing->sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms
|
||||
- dec_ctx->timing->min_pts/(MPEG_CLOCK_FREQ/1000) + dec_ctx->timing->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));
|
||||
mprint ("Final GOP time: %s%+3dF\n",
|
||||
print_mstime(gop_time.ms),
|
||||
ctx->frames_since_last_gop);
|
||||
dec_ctx->frames_since_last_gop);
|
||||
mprint ("Diff. GOP length: %s%+3dF",
|
||||
print_mstime(gop_time.ms - first_gop_time.ms),
|
||||
ctx->frames_since_last_gop);
|
||||
mprint (" (%s)\n",
|
||||
dec_ctx->frames_since_last_gop);
|
||||
mprint (" (%s)\n\n",
|
||||
print_mstime(gop_time.ms - first_gop_time.ms
|
||||
+(LLONG) ((ctx->frames_since_last_gop)*1000/29.97)) );
|
||||
+(LLONG) ((dec_ctx->frames_since_last_gop)*1000/29.97)) );
|
||||
}
|
||||
|
||||
if (ctx->false_pict_header)
|
||||
mprint ("\nNumber of likely false picture headers (discarded): %d\n",ctx->false_pict_header);
|
||||
/* if (dec_ctx->false_pict_header)
|
||||
mprint ("\nNumber of likely false picture headers (discarded): %d\n",dec_ctx->false_pict_header);
|
||||
|
||||
if (ctx->stat_numuserheaders)
|
||||
mprint("\nTotal user data fields: %d\n", ctx->stat_numuserheaders);
|
||||
if (ctx->stat_dvdccheaders)
|
||||
mprint("DVD-type user data fields: %d\n", ctx->stat_dvdccheaders);
|
||||
if (ctx->stat_scte20ccheaders)
|
||||
mprint("SCTE-20 type user data fields: %d\n", ctx->stat_scte20ccheaders);
|
||||
if (ctx->stat_replay4000headers)
|
||||
mprint("ReplayTV 4000 user data fields: %d\n", ctx->stat_replay4000headers);
|
||||
if (ctx->stat_replay5000headers)
|
||||
mprint("ReplayTV 5000 user data fields: %d\n", ctx->stat_replay5000headers);
|
||||
if (ctx->stat_hdtv)
|
||||
mprint("HDTV type user data fields: %d\n", ctx->stat_hdtv);
|
||||
if (ctx->stat_dishheaders)
|
||||
mprint("Dish Network user data fields: %d\n", ctx->stat_dishheaders);
|
||||
if (ctx->stat_divicom)
|
||||
if (dec_ctx->stat_numuserheaders)
|
||||
mprint("\nTotal user data fields: %d\n", dec_ctx->stat_numuserheaders);
|
||||
if (dec_ctx->stat_dvdccheaders)
|
||||
mprint("DVD-type user data fields: %d\n", dec_ctx->stat_dvdccheaders);
|
||||
if (dec_ctx->stat_scte20ccheaders)
|
||||
mprint("SCTE-20 type user data fields: %d\n", dec_ctx->stat_scte20ccheaders);
|
||||
if (dec_ctx->stat_replay4000headers)
|
||||
mprint("ReplayTV 4000 user data fields: %d\n", dec_ctx->stat_replay4000headers);
|
||||
if (dec_ctx->stat_replay5000headers)
|
||||
mprint("ReplayTV 5000 user data fields: %d\n", dec_ctx->stat_replay5000headers);
|
||||
if (dec_ctx->stat_hdtv)
|
||||
mprint("HDTV type user data fields: %d\n", dec_ctx->stat_hdtv);
|
||||
if (dec_ctx->stat_dishheaders)
|
||||
mprint("Dish Network user data fields: %d\n", dec_ctx->stat_dishheaders);
|
||||
if (dec_ctx->stat_divicom)
|
||||
{
|
||||
mprint("CEA608/Divicom user data fields: %d\n", ctx->stat_divicom);
|
||||
mprint("CEA608/Divicom user data fields: %d\n", dec_ctx->stat_divicom);
|
||||
|
||||
mprint("\n\nNOTE! The CEA 608 / Divicom standard encoding for closed\n");
|
||||
mprint("caption is not well understood!\n\n");
|
||||
mprint("Please submit samples to the developers.\n\n\n");
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
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 +321,14 @@ 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);
|
||||
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);
|
||||
#endif
|
||||
dbg_print(CCX_DMT_708, "[CEA-708] The 708 decoder was reset [%d] times.\n", ctx->freport.data_from_708->reset_count);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
17
src/lib_ccx/activity.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2,59 +2,102 @@
|
||||
#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;
|
||||
|
||||
ctx->num_nal_unit_type_7 = 0;
|
||||
ctx->num_vcl_hrd = 0;
|
||||
ctx->num_nal_hrd = 0;
|
||||
ctx->num_jump_in_frames = 0;
|
||||
ctx->num_unexpected_sei_length = 0;
|
||||
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 +112,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 +124,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 +141,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 +245,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 +312,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 +334,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 +382,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 +505,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 +577,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 +598,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 +624,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 +691,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 +732,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 +826,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 +840,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 +849,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 +871,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 +926,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 +972,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 +990,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,36 +998,37 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
@@ -991,73 +1046,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 +1120,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
|
||||
|
||||
55
src/lib_ccx/avc_functions.h
Normal file
55
src/lib_ccx/avc_functions.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2,19 +2,50 @@
|
||||
#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_WITH_HELP 9
|
||||
#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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -159,7 +162,10 @@ enum ccx_output_format
|
||||
CCX_OF_NULL = 5,
|
||||
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_DVDRAW = 8, // See -d at http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_TOOLS.HTML#CCExtract
|
||||
CCX_OF_WEBVTT = 9,
|
||||
CCX_OF_SIMPLE_XML = 10,
|
||||
CCX_OF_G608 = 11,
|
||||
};
|
||||
|
||||
enum ccx_output_date_format
|
||||
@@ -185,6 +191,10 @@ enum ccx_stream_mode_enum
|
||||
CCX_SM_HEX_DUMP = 8, // Hexadecimal dump generated by wtvccdump
|
||||
#endif
|
||||
CCX_SM_WTV = 9,
|
||||
#ifdef ENABLE_FFMPEG
|
||||
CCX_SM_FFMPEG = 10,
|
||||
#endif
|
||||
CCX_SM_GXF = 11,
|
||||
CCX_SM_AUTODETECT = 16
|
||||
};
|
||||
|
||||
@@ -192,7 +202,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 +216,9 @@ enum ccx_bufferdata_type
|
||||
CCX_TELETEXT = 5,
|
||||
CCX_PRIVATE_MPEG2_CC = 6,
|
||||
CCX_DVB_SUBTITLE = 7,
|
||||
CCX_ISDB_SUBTITLE = 8,
|
||||
/* BUffer where cc data contain 3 byte cc_valid ccdata 1 ccdata 2 */
|
||||
CCX_RAW_TYPE = 9,
|
||||
};
|
||||
|
||||
enum ccx_frame_type
|
||||
@@ -228,6 +242,7 @@ enum ccx_code_type
|
||||
CCX_CODEC_TELETEXT,
|
||||
CCX_CODEC_DVB,
|
||||
CCX_CODEC_ISDB_CC,
|
||||
CCX_CODEC_ATSC_CC,
|
||||
CCX_CODEC_NONE,
|
||||
};
|
||||
|
||||
@@ -257,7 +272,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 +291,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
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#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_rollup = 0;
|
||||
options->noscte20 = 0;
|
||||
|
||||
options->no_bom = 0; // Use BOM by default.
|
||||
|
||||
options->settings_608.direct_rollup = 0;
|
||||
options->settings_608.no_rollup = 0;
|
||||
@@ -23,22 +24,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 +51,22 @@ 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->keep_output_closed = 0; // By default just keep the file open.
|
||||
options->force_flush = 0; // Don't flush whenever content is writtern.
|
||||
options->ucla = 0; // By default, -UCLA not used
|
||||
|
||||
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 +76,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);
|
||||
}
|
||||
|
||||
@@ -4,36 +4,94 @@
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
struct ccx_s_options // Options from user parameters
|
||||
#include "list.h"
|
||||
|
||||
struct demuxer_cfg
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
int notypesetting;
|
||||
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.
|
||||
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
|
||||
int keep_output_closed;
|
||||
int force_flush; // Force flush on content write
|
||||
int ucla; // 1 if -UCLA used, 0 if not
|
||||
|
||||
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 noscte20;
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
int nohtmlescape;
|
||||
int notypesetting;
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
int print_file_reports;
|
||||
|
||||
|
||||
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
|
||||
ccx_decoder_dtvcc_settings settings_dtvcc; //Same for 708 decoder
|
||||
|
||||
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 +102,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 +110,41 @@ 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
|
||||
int keep_output_closed;
|
||||
int force_flush; // Force flush on content write
|
||||
int ucla; // 1 if UCLA used, 0 if not
|
||||
|
||||
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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,35 +1126,37 @@ 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;
|
||||
}
|
||||
if (hi>=0x10 && hi<=0x1F) // Non-character code or special/extended char
|
||||
// http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
|
||||
// http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
|
||||
// http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/CC_CODES.HTML
|
||||
// http://www.theneitherworld.com/mcpoodle/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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
9
src/lib_ccx/ccx_decoders_708_encoding.h
Normal file
9
src/lib_ccx/ccx_decoders_708_encoding.h
Normal 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_*/
|
||||
425
src/lib_ccx/ccx_decoders_708_output.c
Normal file
425
src/lib_ccx/ccx_decoders_708_output.c
Normal 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),"%s", (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\"> </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);
|
||||
}
|
||||
19
src/lib_ccx/ccx_decoders_708_output.h
Normal file
19
src/lib_ccx/ccx_decoders_708_output.h
Normal 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_*/
|
||||
@@ -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,72 @@ 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->noscte20 = setting->noscte20;
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
ctx->false_pict_header = 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 +309,98 @@ 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_G608 ||
|
||||
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->output_format!=CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
setting->xds_write_to_file = 0;
|
||||
}
|
||||
ctx->xds_ctx = ccx_decoders_xds_init_library(ctx->timing, setting->xds_write_to_file);
|
||||
|
||||
ctx->vbi_decoder = NULL;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
1419
src/lib_ccx/ccx_decoders_isdb.c
Normal file
1419
src/lib_ccx/ccx_decoders_isdb.c
Normal file
File diff suppressed because it is too large
Load Diff
13
src/lib_ccx/ccx_decoders_isdb.h
Normal file
13
src/lib_ccx/ccx_decoders_isdb.h
Normal 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
|
||||
@@ -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,22 @@ 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;
|
||||
int noscte20;
|
||||
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 xds_write_to_file;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct lib_cc_decode
|
||||
{
|
||||
int cc_stats[4];
|
||||
@@ -102,14 +113,86 @@ 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 noscte20;
|
||||
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
|
||||
|
||||
/* Stats. Modified in es_userdata.c*/
|
||||
/* int stat_numuserheaders;
|
||||
int stat_dvdccheaders;
|
||||
int stat_scte20ccheaders;
|
||||
int stat_replay5000headers;
|
||||
int stat_replay4000headers;
|
||||
int stat_dishheaders;
|
||||
int stat_hdtv;
|
||||
int stat_divicom;
|
||||
int false_pict_header;*/
|
||||
|
||||
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;
|
||||
struct ccx_decoder_vbi_ctx *vbi_decoder;
|
||||
|
||||
int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
};
|
||||
|
||||
100
src/lib_ccx/ccx_decoders_vbi.c
Normal file
100
src/lib_ccx/ccx_decoders_vbi.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "ccx_decoders_vbi.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "utility.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
void delete_decoder_vbi(struct ccx_decoder_vbi_ctx** arg)
|
||||
{
|
||||
struct ccx_decoder_vbi_ctx* ctx = *arg;
|
||||
vbi_raw_decoder_destroy (&ctx->zvbi_decoder);
|
||||
|
||||
freep(arg);
|
||||
}
|
||||
struct ccx_decoder_vbi_ctx* init_decoder_vbi(struct ccx_decoder_vbi_cfg *cfg)
|
||||
{
|
||||
struct ccx_decoder_vbi_ctx *vbi;
|
||||
|
||||
vbi = malloc(sizeof(*vbi));
|
||||
if(!vbi)
|
||||
return NULL;
|
||||
|
||||
#ifdef VBI_DEBUG
|
||||
vbi->vbi_debug_dump = fopen("dump_720.vbi","w");
|
||||
#endif
|
||||
vbi_raw_decoder_init (&vbi->zvbi_decoder);
|
||||
|
||||
if(cfg == NULL)
|
||||
{
|
||||
/* Specify the image format. */
|
||||
vbi->zvbi_decoder.scanning = 525;
|
||||
|
||||
/* The decoder ignores chroma data. */
|
||||
vbi->zvbi_decoder.sampling_format = VBI_PIXFMT_YUV420;
|
||||
|
||||
/* You may have to adjust this. */
|
||||
vbi->zvbi_decoder.sampling_rate = 13.5e6; /* Hz */
|
||||
vbi->zvbi_decoder.bytes_per_line = 720;
|
||||
|
||||
/* Sampling starts 9.7 µs from the front edge of the
|
||||
hor. sync pulse. You may have to adjust this. */
|
||||
vbi->zvbi_decoder.offset = 9.7e-6 * 13.5e6;
|
||||
|
||||
/* Which lines were captured from the first field.
|
||||
You may have to adjust this. */
|
||||
vbi->zvbi_decoder.start[0] = 21;
|
||||
vbi->zvbi_decoder.count[0] = 1;
|
||||
|
||||
/* Second field. */
|
||||
vbi->zvbi_decoder.start[1] = 284;
|
||||
vbi->zvbi_decoder.count[1] = 1;
|
||||
|
||||
/* The image contains all lines of the first field,
|
||||
followed by all lines of the second field. */
|
||||
vbi->zvbi_decoder.interlaced = CCX_TRUE;
|
||||
|
||||
/* The first field is always first in memory. */
|
||||
vbi->zvbi_decoder.synchronous = CCX_TRUE;
|
||||
|
||||
/* Specify the services you want. */
|
||||
vbi_raw_decoder_add_services (&vbi->zvbi_decoder, VBI_SLICED_CAPTION_525, /* strict */ 0);
|
||||
|
||||
}
|
||||
return vbi;
|
||||
}
|
||||
|
||||
int decode_vbi(struct lib_cc_decode *dec_ctx, uint8_t field, unsigned char *buffer, size_t len, struct cc_subtitle *sub)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int n_lines;
|
||||
vbi_sliced sliced[52];
|
||||
if(dec_ctx->vbi_decoder == NULL)
|
||||
{
|
||||
dec_ctx->vbi_decoder = init_decoder_vbi(NULL);
|
||||
}
|
||||
|
||||
len -= 720;
|
||||
|
||||
n_lines = vbi_raw_decode(&dec_ctx->vbi_decoder->zvbi_decoder, buffer, sliced);
|
||||
//n_lines = vbi3_raw_decoder_decode (&dec_ctx->vbi_decoder->zvbi_decoder, sliced, 2, buffer);
|
||||
if (n_lines > 0)
|
||||
{
|
||||
for (i = 0; i < n_lines; ++i)
|
||||
{
|
||||
int index = 0;
|
||||
//for(index = 0; index < 56; index += 2)
|
||||
{
|
||||
unsigned char data[3];
|
||||
if (field == 1)
|
||||
data[0] = 0x04;
|
||||
else
|
||||
data[0] = 0x05;
|
||||
data[1] = sliced[i].data[index];
|
||||
data[2] = sliced[i].data[index+1];
|
||||
do_cb(dec_ctx, data, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return CCX_OK;
|
||||
}
|
||||
28
src/lib_ccx/ccx_decoders_vbi.h
Normal file
28
src/lib_ccx/ccx_decoders_vbi.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef CCX_DECODER_VBI
|
||||
#define CCX_DECODER_VBI
|
||||
|
||||
#include <zvbi_decoder.h>
|
||||
#define VBI_DEBUG
|
||||
|
||||
#include "ccx_decoders_structs.h"
|
||||
|
||||
struct ccx_decoder_vbi_cfg
|
||||
{
|
||||
#ifdef VBI_DEBUG
|
||||
char *debug_file_name;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ccx_decoder_vbi_ctx
|
||||
{
|
||||
int vbi_decoder_inited;
|
||||
vbi_raw_decoder zvbi_decoder;
|
||||
//vbi3_raw_decoder zvbi_decoder;
|
||||
#ifdef VBI_DEBUG
|
||||
FILE *vbi_debug_dump;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
int decode_vbi(struct lib_cc_decode *dec_ctx, uint8_t field, unsigned char *buffer, size_t len, struct cc_subtitle *sub);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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, int xds_write_to_file);
|
||||
|
||||
void xds_cea608_test();
|
||||
#endif
|
||||
|
||||
400
src/lib_ccx/ccx_demuxer.c
Normal file
400
src/lib_ccx/ccx_demuxer.c
Normal file
@@ -0,0 +1,400 @@
|
||||
#include "ccx_demuxer.h"
|
||||
#include "activity.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "utility.h"
|
||||
#include "ffmpeg_intgr.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)
|
||||
{
|
||||
ctx->past = 0;
|
||||
ctx->min_global_timestamp = 0;
|
||||
ctx->global_timestamp_inited = 0;
|
||||
ctx->last_global_timestamp = 0;
|
||||
ctx->offset_global_timestamp = 0;
|
||||
|
||||
#ifdef ENABLE_FFMPEG
|
||||
ctx->ffmpeg_ctx = init_ffmpeg(file);
|
||||
if(ctx->ffmpeg_ctx)
|
||||
{
|
||||
ctx->stream_mode = CCX_SM_FFMPEG;
|
||||
ctx->auto_stream = CCX_SM_FFMPEG;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mprint ("\rFailed to initialized ffmpeg falling back to legacy\n");
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
case CCX_SM_GXF:
|
||||
mprint ("\rFile seems to be a GXF\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;
|
||||
}
|
||||
|
||||
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->tb.num = 1;
|
||||
data->tb.den = 90000;
|
||||
data->next_stream = 0;
|
||||
data->next_program = 0;
|
||||
return data;
|
||||
|
||||
}
|
||||
182
src/lib_ccx/ccx_demuxer.h
Normal file
182
src/lib_ccx/ccx_demuxer.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#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"
|
||||
#include "utility.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;
|
||||
#ifdef ENABLE_FFMPEG
|
||||
void *ffmpeg_ctx;
|
||||
#endif
|
||||
|
||||
void *parent;
|
||||
|
||||
//Will contain actual Demuxer Context
|
||||
void *private_data;
|
||||
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 ccx_rational tb;
|
||||
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
147
src/lib_ccx/ccx_dtvcc.c
Normal 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
14
src/lib_ccx/ccx_dtvcc.h
Normal 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
@@ -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,70 @@ 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
|
||||
/* Keep output file closed when not actually writing to it and start over each time (add headers, etc) */
|
||||
unsigned int keep_output_closed;
|
||||
/* Force a flush on the file buffer whenever content is written */
|
||||
int force_flush;
|
||||
/* Keep track of whether -UCLA used */
|
||||
int ucla;
|
||||
|
||||
/* 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 +109,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 +122,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
|
||||
@@ -86,18 +134,31 @@ void dinit_encoder(struct encoder_ctx *ctx);
|
||||
*/
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer_as_g608(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
|
||||
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 +166,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
|
||||
|
||||
109
src/lib_ccx/ccx_encoders_g608.c
Normal file
109
src/lib_ccx/ccx_encoders_g608.c
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
|
||||
static unsigned int get_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
unsigned char *line = data->characters[line_num];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int bytes = 0;
|
||||
switch (ctx->encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
bytes = get_char_in_utf_8(buffer, line[i]);
|
||||
break;
|
||||
case CCX_ENC_LATIN_1:
|
||||
get_char_in_latin_1(buffer, line[i]);
|
||||
bytes = 1;
|
||||
break;
|
||||
case CCX_ENC_UNICODE:
|
||||
get_char_in_unicode(buffer, line[i]);
|
||||
bytes = 2;
|
||||
case CCX_ENC_ASCII:
|
||||
*buffer = line[i];
|
||||
bytes = 1;
|
||||
break;
|
||||
}
|
||||
buffer += bytes;
|
||||
}
|
||||
return (unsigned int)(buffer - orig); // Return length
|
||||
}
|
||||
static unsigned int get_color_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (data->colors[line_num][i] < 10)
|
||||
*buffer++ = data->colors[line_num][i] + '0';
|
||||
else
|
||||
*buffer++ = 'E';
|
||||
}
|
||||
*buffer = 0;
|
||||
return (unsigned)(buffer - orig); // Return length
|
||||
}
|
||||
static unsigned int get_font_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if(data->fonts[line_num][i] == FONT_REGULAR)
|
||||
*buffer++ = 'R';
|
||||
else if(data->fonts[line_num][i] == FONT_UNDERLINED_ITALICS)
|
||||
*buffer++ = 'B';
|
||||
else if(data->fonts[line_num][i] == FONT_UNDERLINED)
|
||||
*buffer++ = 'U';
|
||||
else if(data->fonts[line_num][i] == FONT_ITALICS)
|
||||
*buffer++ = 'I';
|
||||
else
|
||||
*buffer++ = 'E';
|
||||
}
|
||||
return (unsigned)(buffer - orig); // Return length
|
||||
}
|
||||
int write_cc_buffer_as_g608(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
int wrote_something = 0;
|
||||
ms_start = data->start_time;
|
||||
|
||||
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.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
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, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
|
||||
|
||||
write (context->out->fh, context->buffer, used);
|
||||
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
int length = get_line_encoded (context, context->subline, i, data);
|
||||
write(context->out->fh, context->subline, length);
|
||||
|
||||
length = get_color_encoded (context, context->subline, i, data);
|
||||
write(context->out->fh, context->subline, length);
|
||||
|
||||
length = get_font_encoded (context, context->subline, i, data);
|
||||
write(context->out->fh, context->subline, length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
wrote_something=1;
|
||||
}
|
||||
|
||||
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -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[] =
|
||||
@@ -54,6 +54,11 @@ void correct_case(int line_num, struct eia608_screen *data)
|
||||
char *line = strdup(((char*)data->characters[line_num]));
|
||||
char *oline = (char*)data->characters[line_num];
|
||||
char *c = strtok(line, delim);
|
||||
if (c == NULL)
|
||||
{
|
||||
free(line);
|
||||
return;
|
||||
}
|
||||
do
|
||||
{
|
||||
char **index = bsearch(&c, spell_lower, spell_words, sizeof(*spell_lower), string_cmp);
|
||||
@@ -68,9 +73,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 +87,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 +103,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 +125,7 @@ unsigned encode_line(unsigned char *buffer, unsigned char *text)
|
||||
}
|
||||
text++;
|
||||
}
|
||||
*buffer = 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -128,7 +134,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 +145,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 +153,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 +174,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 +185,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 +222,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 +261,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 +375,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 +406,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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\"> </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\"> </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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,10 @@ typedef struct ccx_encoders_transcript_format {
|
||||
|
||||
struct ccx_s_write
|
||||
{
|
||||
int multiple_files;
|
||||
char *first_input_file;
|
||||
int fh;
|
||||
int temporarily_closed; // 1 means the file was created OK before but we released the handle
|
||||
char *filename;
|
||||
void* spupng_data;
|
||||
};
|
||||
|
||||
#define CCX_ENCODERS_STRUCTS_H
|
||||
#endif
|
||||
|
||||
272
src/lib_ccx/ccx_encoders_webvtt.c
Normal file
272
src/lib_ccx/ccx_encoders_webvtt.c
Normal 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;
|
||||
}
|
||||
95
src/lib_ccx/ccx_encoders_xds.c
Normal file
95
src/lib_ccx/ccx_encoders_xds.c
Normal 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]);
|
||||
}
|
||||
}
|
||||
|
||||
5
src/lib_ccx/ccx_encoders_xds.h
Normal file
5
src/lib_ccx/ccx_encoders_xds.h
Normal 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
|
||||
1734
src/lib_ccx/ccx_gxf.c
Normal file
1734
src/lib_ccx/ccx_gxf.c
Normal file
File diff suppressed because it is too large
Load Diff
9
src/lib_ccx/ccx_gxf.h
Normal file
9
src/lib_ccx/ccx_gxf.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef CCX_GXF
|
||||
#define CCX_GXF
|
||||
|
||||
#include "ccx_demuxer.h"
|
||||
|
||||
int ccx_gxf_probe(unsigned char *buf, int len);
|
||||
int ccx_gxf_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **data);
|
||||
struct ccx_gxf *ccx_gxf_init(struct ccx_demuxer *arg);
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_decoders_vbi.h"
|
||||
|
||||
|
||||
// Parse the user data for captions. The udtype variable denotes
|
||||
@@ -9,10 +10,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 +24,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);
|
||||
@@ -37,10 +36,10 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
}
|
||||
|
||||
// DVD CC header, see
|
||||
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
|
||||
// <http://www.theneitherworld.com/mcpoodle/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 +65,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 +93,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 +124,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
|
||||
@@ -140,13 +139,13 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read %d/%d DVD CC blocks\n", rcbcount, ecbcount);
|
||||
}
|
||||
// SCTE 20 user data
|
||||
else if (ud_header[0] == 0x03)
|
||||
else if (!ctx->noscte20 && ud_header[0] == 0x03)
|
||||
{
|
||||
if ((ud_header[1]&0x7F) == 0x01)
|
||||
{
|
||||
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
|
||||
|
||||
ctx->stat_scte20ccheaders++;
|
||||
// ctx->stat_scte20ccheaders++;
|
||||
read_bytes(ustream, 2); // "03 01"
|
||||
|
||||
unsigned cc_count = (unsigned int) read_bits(ustream,5);
|
||||
@@ -155,7 +154,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
unsigned field_number;
|
||||
unsigned cc_data1;
|
||||
unsigned cc_data2;
|
||||
/* unsigned marker; */
|
||||
|
||||
for (unsigned j=0;j<cc_count;j++)
|
||||
{
|
||||
skip_bits(ustream,2); // priority - unused
|
||||
@@ -163,7 +162,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
skip_bits(ustream,5); // line_offset - unused
|
||||
cc_data1 = (unsigned int) read_bits(ustream,8);
|
||||
cc_data2 = (unsigned int) read_bits(ustream,8);
|
||||
/* marker = (unsigned int)read_bits(ustream,1); // TODO: Add syntax check */
|
||||
read_bits(ustream,1); // TODO: Add syntax check */
|
||||
|
||||
if (ustream->bitsleft < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Oops!");
|
||||
@@ -186,7 +185,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 +193,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 +206,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 +267,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 +288,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 +347,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 +372,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 +437,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 +453,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,9 +463,34 @@ 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!
|
||||
}
|
||||
// GXF vbi OEM code
|
||||
else if ( !memcmp(ud_header,"\x73\x52\x21\x06", 4 ) )
|
||||
{
|
||||
int udatalen = ustream->end - ustream->pos;
|
||||
uint16_t line_nb;
|
||||
uint8_t line_type;
|
||||
uint8_t field = 1;
|
||||
read_bytes(ustream, 4); //skip header code
|
||||
read_bytes(ustream, 2); //skip data length
|
||||
line_nb = read_bits(ustream, 16);
|
||||
line_type = read_u8(ustream);
|
||||
field = (line_type & 0x03);
|
||||
if(field == 0)
|
||||
mprint("MPEG:VBI: Invalid field\n");
|
||||
|
||||
line_type = line_type >> 2;
|
||||
if(line_type != 1)
|
||||
mprint("MPEG:VBI: only support Luma line\n");
|
||||
|
||||
if (udatalen < 720)
|
||||
mprint("MPEG:VBI: Minimum 720 bytes in luma line required\n");
|
||||
|
||||
decode_vbi(ctx, field, ustream->pos, 720, sub);
|
||||
dbg_print(CCX_DMT_VERBOSE, "GXF (vbi line %d) user data:\n", line_nb);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some other user data
|
||||
|
||||
@@ -21,6 +21,7 @@ struct ffmpeg_ctx
|
||||
AVFrame *frame;
|
||||
int stream_index;
|
||||
};
|
||||
|
||||
/**
|
||||
* call back function to be registered for avlog
|
||||
*/
|
||||
@@ -52,13 +53,14 @@ static void log_cb(void* ptr, int level, const char* fmt, va_list vl)
|
||||
|
||||
vfprintf(flog, fmt, vl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @path this path could be relative or absolute path of static file
|
||||
* this path could be path of device
|
||||
*
|
||||
* @return ctx Context of ffmpeg
|
||||
*/
|
||||
void *init_ffmpeg(char *path)
|
||||
void *init_ffmpeg(const char *path)
|
||||
{
|
||||
int ret = 0;
|
||||
int stream_index = 0;
|
||||
@@ -120,6 +122,7 @@ void *init_ffmpeg(char *path)
|
||||
fail:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ctx context of ffmpeg
|
||||
* @param data preallocated buffer where data will be recieved
|
||||
@@ -158,10 +161,10 @@ int ff_get_ccframe(void *arg, unsigned char*data, int maxlen)
|
||||
{
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
current_pts = av_frame_get_best_effort_timestamp(ctx->frame);
|
||||
if(!pts_set)
|
||||
pts_set = 1;
|
||||
set_fts();
|
||||
// current_pts = av_frame_get_best_effort_timestamp(ctx->frame);
|
||||
// if(!pts_set)
|
||||
// pts_set = 1;
|
||||
// set_fts();
|
||||
for(int i = 0;i< ctx->frame->nb_side_data;i++)
|
||||
{
|
||||
if(ctx->frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
|
||||
@@ -184,4 +187,56 @@ int ff_get_ccframe(void *arg, unsigned char*data, int maxlen)
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int ffmpeg_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **ppdata)
|
||||
{
|
||||
struct demuxer_data *data;
|
||||
int ret = 0;
|
||||
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;
|
||||
data->bufferdatatype = CCX_RAW_TYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = *ppdata;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int len = ff_get_ccframe(ctx->ffmpeg_ctx, data->buffer, BUFSIZE);
|
||||
if(len == AVERROR(EAGAIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(len == AVERROR_EOF)
|
||||
{
|
||||
ret = CCX_EOF;
|
||||
break;
|
||||
}
|
||||
else if(len == 0)
|
||||
continue;
|
||||
else if(len < 0 )
|
||||
{
|
||||
mprint("Error extracting Frame\n");
|
||||
break;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
data->len = len;
|
||||
break;
|
||||
}
|
||||
|
||||
}while(1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,19 +5,14 @@
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/error.h"
|
||||
#endif
|
||||
#include "ccx_demuxer.h"
|
||||
/**
|
||||
* @path this path could be relative or absolute path of static file
|
||||
* this path could be path of device
|
||||
*
|
||||
* @return ctx Context of ffmpeg
|
||||
*/
|
||||
void *init_ffmpeg(char *path);
|
||||
void *init_ffmpeg(const char *path);
|
||||
|
||||
/**
|
||||
* @param ctx context of ffmpeg
|
||||
* @param data preallocated buffer where data will be recieved
|
||||
* @param maxlen length of buffer, where data will be copied
|
||||
* @return number of bytes recieved as data
|
||||
*/
|
||||
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen);
|
||||
int ffmpeg_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **ppdata);
|
||||
#endif
|
||||
|
||||
94
src/lib_ccx/file_buffer.h
Normal file
94
src/lib_ccx/file_buffer.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#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);
|
||||
unsigned short buffered_get_le16(struct ccx_demuxer *ctx);
|
||||
unsigned int buffered_get_le32(struct ccx_demuxer *ctx);
|
||||
#endif
|
||||
@@ -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,34 @@ 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)
|
||||
{
|
||||
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
|
||||
return -1;
|
||||
|
||||
if (h == -1) {
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
return -1 * ENOENT;
|
||||
case EACCES:
|
||||
return -1 * EACCES;
|
||||
case EINVAL:
|
||||
return -1 * EINVAL;
|
||||
case EMFILE:
|
||||
return -1 * EMFILE;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ccx_options.live_stream)
|
||||
ts+=getfilesize (h);
|
||||
ts += getfilesize (h);
|
||||
close (h);
|
||||
}
|
||||
return ts;
|
||||
@@ -50,64 +63,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 +110,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 +319,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 +332,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 +364,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 +402,117 @@ 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;
|
||||
}
|
||||
|
||||
unsigned short buffered_get_le16(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) (b<<8) )| ( (unsigned short) a);
|
||||
}
|
||||
|
||||
unsigned int buffered_get_le32(struct ccx_demuxer *ctx)
|
||||
{
|
||||
unsigned int val;
|
||||
val = buffered_get_le16(ctx);
|
||||
val |= buffered_get_le16(ctx) << 16;
|
||||
return val;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,18 @@ 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;
|
||||
setting->noscte20 = opt->noscte20;
|
||||
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;
|
||||
setting->xds_write_to_file = opt->transcript_settings.xds;
|
||||
|
||||
return setting;
|
||||
}
|
||||
static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setting)
|
||||
@@ -31,121 +41,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 +120,30 @@ 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->extension = get_file_extension(opt->write_format);
|
||||
|
||||
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 +152,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 +176,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);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#define VERSION "0.77"
|
||||
#define VERSION "0.79"
|
||||
|
||||
// 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
|
||||
@@ -136,20 +57,19 @@ struct ccx_s_teletext_config {
|
||||
unsigned send_to_srv;
|
||||
enum ccx_encoding_type encoding;
|
||||
int nofontcolor;
|
||||
int nohtmlescape;
|
||||
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 +77,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 +87,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 +113,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 +123,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 +151,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 +185,49 @@ 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 temporarily_open_output(struct ccx_s_write *wb);
|
||||
int temporarily_close_output(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);
|
||||
int isValidMP4Box(unsigned char *buffer, size_t position, size_t *nextBoxLocation, int *boxScore);
|
||||
void detect_stream_type (struct ccx_demuxer *ctx);
|
||||
int detect_myth( struct ccx_demuxer *ctx );
|
||||
int read_video_pes_header (struct ccx_demuxer *ctx, struct demuxer_data *data, unsigned char *nextheader, int *headerlength, int sbuflen);
|
||||
|
||||
// ts_functions.c
|
||||
void init_ts(struct lib_ccx_ctx *ctx);
|
||||
void dinit_ts (struct lib_ccx_ctx *ctx);
|
||||
int ts_readpacket(struct lib_ccx_ctx* ctx);
|
||||
long ts_readstream(struct lib_ccx_ctx *ctx);
|
||||
LLONG ts_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
int write_section(struct lib_ccx_ctx *ctx, struct ts_payload *payload, unsigned char*buf, int size, int pos);
|
||||
int parse_PMT (struct lib_ccx_ctx *ctx, unsigned char *buf, int len, int pos);
|
||||
int parse_PAT (struct lib_ccx_ctx *ctx);
|
||||
void init_ts(struct ccx_demuxer *ctx);
|
||||
int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload);
|
||||
long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data);
|
||||
int ts_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **data);
|
||||
int write_section(struct ccx_demuxer *ctx, struct ts_payload *payload, unsigned char*buf, int size, struct program_info *pinfo);
|
||||
void ts_buffer_psi_packet(struct ccx_demuxer *ctx);
|
||||
int parse_PMT (struct ccx_demuxer *ctx, unsigned char *buf, int len, struct program_info *pinfo);
|
||||
int parse_PAT (struct ccx_demuxer *ctx);
|
||||
void parse_EPG_packet (struct lib_ccx_ctx *ctx);
|
||||
void EPG_free();
|
||||
void EPG_free(struct lib_ccx_ctx *ctx);
|
||||
char* EPG_DVB_decode_string(uint8_t *in, size_t size);
|
||||
void parse_SDT(struct ccx_demuxer *ctx);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
void myth_loop(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
@@ -399,91 +245,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
511
src/lib_ccx/list.h
Normal 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,19 +6,58 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* TODO remove dependency of encoder by removing writeDVDraw from this file */
|
||||
#include "ccx_encoders_structs.h"
|
||||
void dinit_write(struct ccx_s_write *wb)
|
||||
{
|
||||
if (wb->fh > 0)
|
||||
close(wb->fh);
|
||||
freep(&wb->filename);
|
||||
}
|
||||
|
||||
void init_write (struct ccx_s_write *wb,char *filename)
|
||||
int temporarily_close_output(struct ccx_s_write *wb)
|
||||
{
|
||||
close(wb->fh);
|
||||
wb->fh = -1;
|
||||
wb->temporarily_closed = 1;
|
||||
}
|
||||
|
||||
int temporarily_open_output(struct ccx_s_write *wb)
|
||||
{
|
||||
int t = 0;
|
||||
// Try a few times before giving up. This is because this close/open stuff exists for processes
|
||||
// that demand exclusive access to the file, so often we'll find out that we cannot reopen the
|
||||
// file immediately.
|
||||
while (t < 5 && wb->fh == -1)
|
||||
{
|
||||
wb->fh = open(wb->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
sleep(1);
|
||||
}
|
||||
if (wb->fh == -1)
|
||||
{
|
||||
return CCX_COMMON_EXIT_FILE_CREATION_FAILED;
|
||||
}
|
||||
wb->temporarily_closed = 0;
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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->temporarily_closed = 0;
|
||||
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 +77,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 +88,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 +135,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 +162,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
|
||||
|
||||
@@ -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,10 @@ 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 if (strcmp (format,"g608")==0)
|
||||
opt->write_format=CCX_OF_G608;
|
||||
else
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format);
|
||||
}
|
||||
@@ -264,39 +224,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);
|
||||
@@ -315,6 +275,7 @@ void usage (void)
|
||||
mprint (" Syntax:\n");
|
||||
mprint (" ccextractor [options] inputfile1 [inputfile2...] [-o outputfilename]\n");
|
||||
mprint (" [-o1 outputfilename1] [-o2 outputfilename2]\n\n");
|
||||
mprint ("To see This Help Message: -h or --help\n\n");
|
||||
mprint ("File name related options:\n");
|
||||
mprint (" inputfile: file(s) to process\n");
|
||||
mprint (" -o outputfilename: Use -o parameters to define output filename if you don't\n");
|
||||
@@ -337,6 +298,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 +320,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 +358,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 +375,6 @@ 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 ("Options that affect how input files will be processed.\n");
|
||||
|
||||
@@ -483,6 +455,7 @@ void usage (void)
|
||||
mprint (" reference to the received data. Use this parameter if\n");
|
||||
mprint (" you prefer your own reference. Note: Current this only\n");
|
||||
mprint (" affects Teletext in timed transcript with -datets.\n");
|
||||
mprint (" --noscte20: Ignore SCTE-20 data if present.\n");
|
||||
mprint ("\n");
|
||||
mprint ("Options that affect what kind of output will be produced:\n");
|
||||
mprint(" -bom: Append a BOM (Byte Order Mark) to output files.\n");
|
||||
@@ -496,11 +469,12 @@ 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 (" --nohtmlescape: For .srt/.sami/.vtt, don't covert html unsafe character\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 +506,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");
|
||||
|
||||
@@ -542,6 +517,10 @@ void usage (void)
|
||||
mprint (" -nobi -nobufferinput: Disables input buffering.\n");
|
||||
mprint (" -bs --buffersize val: Specify a size for reading, in bytes (suffix with K or\n");
|
||||
mprint (" or M for kilobytes and megabytes). Default is 16M.\n");
|
||||
mprint (" -koc: keep-output-close. If used then CCExtractor will close\n");
|
||||
mprint (" the output file after writing each subtitle frame and\n");
|
||||
mprint (" attempt to create it again when needed.\n");
|
||||
mprint (" -ff --forceflush: Flush the file buffer whenever content is written.\n");
|
||||
mprint ("\n");
|
||||
|
||||
mprint ("Options that affect the built-in closed caption decoder:\n");
|
||||
@@ -566,7 +545,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 +571,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 +637,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 +718,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,19 +834,14 @@ 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++)
|
||||
{
|
||||
if (!strcmp (argv[i],"--help") || !strcmp(argv[i], "-h"))
|
||||
{
|
||||
usage();
|
||||
return EXIT_WITH_HELP;
|
||||
}
|
||||
if (strcmp (argv[i], "-")==0 || strcmp(argv[i], "-stdin") == 0)
|
||||
{
|
||||
|
||||
@@ -839,6 +879,17 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
opt->buffer_input = 0;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-koc") == 0)
|
||||
{
|
||||
opt->keep_output_closed = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-ff") == 0 || strcmp(argv[i], "--forceflush") == 0)
|
||||
{
|
||||
opt->force_flush = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((strcmp (argv[i],"-bs")==0 || strcmp (argv[i],"--buffersize")==0) && i<argc-1)
|
||||
{
|
||||
FILEBUFFERSIZE = atol_size(argv[i+1]);
|
||||
@@ -858,12 +909,17 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
opt->nofontcolor=1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"--nohtmlescape")==0)
|
||||
{
|
||||
opt->nohtmlescape=1;
|
||||
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 ||
|
||||
@@ -894,16 +950,16 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
|
||||
/*user specified subtitle to be selected */
|
||||
|
||||
if(!strcmp (argv[i],"-codec"))
|
||||
if(!strcmp (argv[i],"-codec") && i < argc - 1)
|
||||
{
|
||||
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
|
||||
{
|
||||
@@ -913,16 +969,16 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
/*user specified subtitle to be selected */
|
||||
|
||||
if(!strcmp (argv[i],"-nocodec"))
|
||||
if(!strcmp (argv[i],"-nocodec") && i < argc - 1)
|
||||
{
|
||||
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 +989,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 +1007,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 +1024,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 +1034,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 +1044,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 +1055,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 +1072,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");
|
||||
}
|
||||
@@ -1059,10 +1115,17 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
MPEG_CLOCK_FREQ=90090;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"--noscte20")==0)
|
||||
{
|
||||
opt->noscte20 = 1;
|
||||
continue;
|
||||
}
|
||||
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 +1140,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 && i<argc-1)
|
||||
{
|
||||
opt->out_interval = atoi(argv[i+1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"--gui_mode_reports")==0)
|
||||
@@ -1098,14 +1167,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 +1184,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 ||
|
||||
@@ -1270,6 +1345,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-xdsdebug")==0)
|
||||
{
|
||||
opt->transcript_settings.xds = 1;
|
||||
opt->debug_mask |= CCX_DMT_DECODER_XDS;
|
||||
continue;
|
||||
}
|
||||
@@ -1288,6 +1364,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 +1407,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 +1447,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 +1488,14 @@ 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->ucla = 1;
|
||||
opt->millis_separator = '.';
|
||||
opt->enc_cfg.no_bom = 1;
|
||||
if (!opt->transcript_settings.isFinal){
|
||||
opt->transcript_settings.showStartTime = 1;
|
||||
opt->transcript_settings.showEndTime = 1;
|
||||
@@ -1440,7 +1508,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 +1518,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 +1592,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 +1653,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 +1726,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 +1735,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,8 +1748,8 @@ 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.nohtmlescape = opt->nohtmlescape;
|
||||
tlt_config.millis_separator = opt->millis_separator;
|
||||
|
||||
// teletext page number out of range
|
||||
@@ -1717,17 +1782,56 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
return EXIT_TOO_MANY_INPUT_FILES;
|
||||
}
|
||||
|
||||
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 (opt->demux_cfg.auto_stream == CCX_SM_MCPOODLESRAW && opt->write_format==CCX_OF_RAW)
|
||||
{
|
||||
if (!strcmp(ctx->inputfile[i], output_filename)) {
|
||||
return 1;
|
||||
}
|
||||
print_error(opt->gui_mode_reports, "-in=raw can only be used if the output is a subtitle file.\n");
|
||||
return EXIT_INCOMPATIBLE_PARAMETERS;
|
||||
}
|
||||
return 0;
|
||||
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.force_flush = opt->force_flush;
|
||||
opt->enc_cfg.ucla = opt->ucla;
|
||||
opt->enc_cfg.no_type_setting = opt->notypesetting;
|
||||
opt->enc_cfg.subs_delay = opt->subs_delay;
|
||||
opt->enc_cfg.gui_mode_reports = opt->gui_mode_reports;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -5,8 +5,13 @@
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "activity.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_common_timing.h"
|
||||
#include "file_buffer.h"
|
||||
#include "ccx_gxf.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);
|
||||
@@ -23,6 +28,14 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
ctx->startbytes[3]==0x75)
|
||||
ctx->stream_mode=CCX_SM_ASF;
|
||||
}
|
||||
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND)
|
||||
{
|
||||
if (ccx_gxf_probe(ctx->startbytes, ctx->startbytes_avail) == CCX_TRUE)
|
||||
{
|
||||
ctx->stream_mode = CCX_SM_GXF;
|
||||
ctx->private_data = ccx_gxf_init(ctx);
|
||||
}
|
||||
}
|
||||
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 4)
|
||||
{
|
||||
if(ctx->startbytes[0]==0xb7 &&
|
||||
@@ -60,13 +73,12 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
if ((ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
|
||||
&& ctx->startbytes_avail >= 4) // Still not found
|
||||
{
|
||||
long idx = 0, nextBoxLocation = 0, lastBoxLocation = 0;
|
||||
size_t idx = 0, nextBoxLocation = 0;
|
||||
int boxScore = 0;
|
||||
// Scan the buffer for valid succeeding MP4 boxes.
|
||||
while (idx < ctx->startbytes_avail - 7){
|
||||
lastBoxLocation = idx;
|
||||
while (idx < ctx->startbytes_avail - 8){
|
||||
// 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 +123,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 +146,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 +175,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,15 +187,15 @@ 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
|
||||
// STARTBTYTESLENGTH is 1MB, if the file is shorter we will never detect
|
||||
// STARTBYTESLENGTH is 1MB, if the file is shorter we will never detect
|
||||
// it as a mythTV file
|
||||
if (ctx->startbytes_avail==STARTBYTESLENGTH)
|
||||
{
|
||||
@@ -204,40 +216,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 +224,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 +236,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 +245,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 +265,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 +369,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 +379,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. */
|
||||
@@ -446,18 +418,25 @@ typedef struct ccx_stream_mp4_box
|
||||
* An asterisk (*) marks a mandatory box for a regular file.
|
||||
* Box types that are on the second level or deeper are omitted.
|
||||
*/
|
||||
ccx_stream_mp4_box ccx_stream_mp4_boxes[11] = {
|
||||
ccx_stream_mp4_box ccx_stream_mp4_boxes[16] = {
|
||||
{ "ftyp", 6 }, // File type and compatibility*
|
||||
{ "pdin", 1 }, // Progressive download information
|
||||
{ "moov", 5 }, // Container for all metadata*
|
||||
{ "moof", 4 }, // Movie fragment
|
||||
{ "mfra", 3 }, // Movie fragment random access
|
||||
{ "mfra", 1 }, // Movie fragment random access
|
||||
{ "mdat", 2 }, // Media data container
|
||||
{ "free", 1 }, // Free space
|
||||
{ "skip", 1 }, // Free space
|
||||
{ "meta", 1 }, // Metadata
|
||||
{ "wide", 1 }, // For boxes that are > 2^32 bytes (https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html)
|
||||
{ "void", 1 } // Unknown where this is from/for, assume free space.
|
||||
{ "void", 1 }, // Unknown where this is from/for, assume free space.
|
||||
|
||||
// new ones in standard ISO/IEC 14496-12:2015
|
||||
{ "meco", 1 }, // additional metadata container
|
||||
{ "styp", 1 }, // segment type
|
||||
{ "sidx", 1 }, // segment index
|
||||
{ "ssix", 1 }, // subsegment index
|
||||
{ "prft", 1 } // producer reference time
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -467,15 +446,15 @@ ccx_stream_mp4_box ccx_stream_mp4_boxes[11] = {
|
||||
*
|
||||
* Returns 1 when a box is found, 0 when none is found.
|
||||
*/
|
||||
int isValidMP4Box(unsigned char *buffer, long position, long *nextBoxLocation, int *boxScore)
|
||||
int isValidMP4Box(unsigned char *buffer, size_t position, size_t *nextBoxLocation, int *boxScore)
|
||||
{
|
||||
for (int idx = 0; idx < 11; idx++)
|
||||
for (int idx = 0; idx < 16; idx++)
|
||||
{
|
||||
if (buffer[position + 4] == ccx_stream_mp4_boxes[idx].boxType[0] && buffer[position + 5] == ccx_stream_mp4_boxes[idx].boxType[1] &&
|
||||
buffer[position + 6] == ccx_stream_mp4_boxes[idx].boxType[2] && buffer[position + 7] == ccx_stream_mp4_boxes[idx].boxType[3]){
|
||||
mprint("Detected MP4 box with name: %s\n", ccx_stream_mp4_boxes[idx].boxType);
|
||||
// Box name matches. Do crude validation of possible box size, and if valid, add points for "valid" box
|
||||
long boxSize = buffer[position] << 24;
|
||||
size_t boxSize = buffer[position] << 24;
|
||||
boxSize |= buffer[position + 1] << 16;
|
||||
boxSize |= buffer[position + 2] << 8;
|
||||
boxSize |= buffer[position + 3];
|
||||
|
||||
@@ -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
|
||||
|
||||
1006
src/lib_ccx/telxcc.c
1006
src/lib_ccx/telxcc.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
76
src/lib_ccx/ts_functions.h
Normal file
76
src/lib_ccx/ts_functions.h
Normal 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
278
src/lib_ccx/ts_info.c
Normal 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
@@ -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%06"PRIu64 "+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,54 @@ 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);
|
||||
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++)
|
||||
if(!f)
|
||||
{
|
||||
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rUnable to open %s\n", filename);
|
||||
return;
|
||||
}
|
||||
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<ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
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 +780,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 +875,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 +899,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 +982,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 +991,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 +1098,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++)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user