mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-08 13:34:59 +00:00
Compare commits
803 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
7169c71360 | ||
|
|
5c3a757e5b | ||
|
|
673cadc6bf | ||
|
|
2318e714db | ||
|
|
a6d27a2de5 | ||
|
|
dc842b0312 | ||
|
|
3879f5c7ef | ||
|
|
e01d93afa8 | ||
|
|
6ec8086b0a | ||
|
|
b80572c3b6 | ||
|
|
3f6fd51f45 | ||
|
|
87af82f022 | ||
|
|
020ca9a1cf | ||
|
|
beccc3d5b7 | ||
|
|
1d03bd7d13 | ||
|
|
13290294a6 | ||
|
|
1eef500c73 | ||
|
|
ca5135c8aa | ||
|
|
740a1d798e | ||
|
|
b68a086698 | ||
|
|
0e60ceb4d0 | ||
|
|
2030c16b22 | ||
|
|
79b1bca8f7 | ||
|
|
76b3d3e4d1 | ||
|
|
90d8731a03 | ||
|
|
85270c7047 | ||
|
|
c9e596e60a | ||
|
|
24d83e130a | ||
|
|
4fc19d4289 | ||
|
|
74ad11b44f | ||
|
|
051a6f1f67 | ||
|
|
3f7eb981e6 | ||
|
|
8ca152262e | ||
|
|
f17501f0e5 | ||
|
|
6cc8d7de05 | ||
|
|
d4f6db8479 | ||
|
|
7b22a8d966 | ||
|
|
c5cebeaa4f | ||
|
|
f1cf6c7be8 | ||
|
|
80303ddde5 | ||
|
|
89ee62ea14 | ||
|
|
a1959d20f3 | ||
|
|
810cb73203 | ||
|
|
38b9ed7fcd | ||
|
|
35b8f2375f | ||
|
|
aa619b5f93 | ||
|
|
c03d3032aa | ||
|
|
191cdd2bdc | ||
|
|
9d5c8759e5 | ||
|
|
a4b5c6e028 | ||
|
|
113b606091 | ||
|
|
a69e031835 | ||
|
|
ba38055bed | ||
|
|
3c086e8ff0 | ||
|
|
f9c26d8684 | ||
|
|
2ed9789f9c | ||
|
|
282108942b | ||
|
|
6c107a0d4e | ||
|
|
6e4ab6faae | ||
|
|
e8016edfc1 | ||
|
|
30839f7c2c | ||
|
|
89459a6c2e | ||
|
|
c49db8c083 | ||
|
|
fa6588fa80 | ||
|
|
7d74256664 | ||
|
|
2210660ae4 | ||
|
|
f2fc93b7f8 | ||
|
|
d54a2d9486 | ||
|
|
88015d6d4b | ||
|
|
f1ff75b846 | ||
|
|
1123755dc7 | ||
|
|
6a4f379ab7 | ||
|
|
9369cde9a3 | ||
|
|
a1d985b4ca | ||
|
|
b26854d3d7 | ||
|
|
cbb4b4c7bb | ||
|
|
1a1aa746d5 | ||
|
|
b4f5b5b98e | ||
|
|
fa3b651ee1 | ||
|
|
91d079be1e | ||
|
|
d16ea0a7ea | ||
|
|
6133bf6297 | ||
|
|
14e1420b7e | ||
|
|
10568a0270 | ||
|
|
53da058fe1 | ||
|
|
4d199fb03b | ||
|
|
f04cbbd99c | ||
|
|
e572ba8b6e | ||
|
|
45974e88be | ||
|
|
8140bf3e52 | ||
|
|
4570965af2 | ||
|
|
fcd250a557 | ||
|
|
b92e42e685 | ||
|
|
5daccf4268 | ||
|
|
e0903a0789 | ||
|
|
bcf1546fc2 | ||
|
|
92f53be666 | ||
|
|
8ae0bd7f16 | ||
|
|
754159e2bc | ||
|
|
3f817d655c | ||
|
|
572837d7ba | ||
|
|
fb8dcf4025 | ||
|
|
c7b77b5555 | ||
|
|
fe1ac8564a | ||
|
|
9230390937 | ||
|
|
14f926124d | ||
|
|
76e8489304 | ||
|
|
0e0b1973f0 | ||
|
|
a6666a4fbd | ||
|
|
3a66db200d | ||
|
|
4f3e5fe677 | ||
|
|
ad99ccdfec | ||
|
|
1bc174efa2 | ||
|
|
983db8c92d | ||
|
|
b4ce115f7c | ||
|
|
cb7f31ef8c | ||
|
|
1a5d78b1b4 | ||
|
|
c873ff6a06 | ||
|
|
454024808d | ||
|
|
0a22e1e429 | ||
|
|
3fb288357d | ||
|
|
966d88fc10 | ||
|
|
c91aa79852 | ||
|
|
04ccb477f1 | ||
|
|
10ea570229 | ||
|
|
551c3d0e2f | ||
|
|
49530b079b | ||
|
|
02986fe7a8 | ||
|
|
a230ec5f6f | ||
|
|
7902b85d1b | ||
|
|
77d275d6a5 | ||
|
|
4c2a4a59a2 | ||
|
|
d80455a408 | ||
|
|
27e2bb9017 | ||
|
|
9358978a61 | ||
|
|
cffd02c106 | ||
|
|
b45370cbb4 | ||
|
|
56e15a3be0 | ||
|
|
7b4d93988f | ||
|
|
0e803eba95 | ||
|
|
8c9bfa17dd | ||
|
|
413173f5e5 | ||
|
|
1a050c76a5 | ||
|
|
c3d00d80f5 | ||
|
|
c989c941df | ||
|
|
dc9f6d250a | ||
|
|
9f00cec9c0 | ||
|
|
b7d2754518 | ||
|
|
94675b2dac | ||
|
|
2c9faa70ea | ||
|
|
b7616fcb17 | ||
|
|
eb93345544 | ||
|
|
e6024c1cb1 | ||
|
|
ecc4c2520e | ||
|
|
a83c686f6a | ||
|
|
c4a8135b4d | ||
|
|
004f9d512a | ||
|
|
53df68b4c3 | ||
|
|
74bb91aa5b | ||
|
|
453bb56520 | ||
|
|
db50730a00 | ||
|
|
36a266e43c | ||
|
|
354c52ec61 | ||
|
|
2b65419bfb | ||
|
|
740365db7e | ||
|
|
03dc0498ea | ||
|
|
e9a7474f3d | ||
|
|
1ecb2abd62 | ||
|
|
d3b4b8ff03 | ||
|
|
29aa63c23c | ||
|
|
7083a36ecb | ||
|
|
38421e886e | ||
|
|
b0de53c351 | ||
|
|
09dcb8b7c0 | ||
|
|
13ab9e6a4e | ||
|
|
08ae34bc24 | ||
|
|
f5f1a70eb8 | ||
|
|
471c130928 | ||
|
|
4db37e7ac3 | ||
|
|
3953f806b0 | ||
|
|
cf0ebd27f7 | ||
|
|
559d05c478 | ||
|
|
4d7e629ba5 | ||
|
|
866c4ea159 | ||
|
|
cf508653f2 | ||
|
|
b3b683aa83 | ||
|
|
9f6309ef14 | ||
|
|
b95e06c21c | ||
|
|
7ed99097ba | ||
|
|
3f4bbbde25 | ||
|
|
5828f50210 | ||
|
|
b5931e8749 | ||
|
|
c588b42e0a | ||
|
|
f9ee9570a4 | ||
|
|
55e408bbb7 | ||
|
|
93a5ae9728 | ||
|
|
5c7430cff5 | ||
|
|
fecf14bc15 | ||
|
|
a4275eba62 | ||
|
|
3873e8fd30 | ||
|
|
5e22be2576 | ||
|
|
0b568cb168 | ||
|
|
017d539710 | ||
|
|
06c8f69056 | ||
|
|
b06654b760 | ||
|
|
4ff49c2010 | ||
|
|
0c650711cf | ||
|
|
3128f10fb5 | ||
|
|
63b209929e | ||
|
|
5f68a9166f | ||
|
|
15616edea8 | ||
|
|
cce4ec5e1a | ||
|
|
72ecd279cf | ||
|
|
87f1a3845c | ||
|
|
4ae5f3483c | ||
|
|
38876690f8 | ||
|
|
7bb4e842dd | ||
|
|
26d9584a93 | ||
|
|
9d5ce9aaae | ||
|
|
47264425df | ||
|
|
e8f8d04369 | ||
|
|
78cb26c9cb | ||
|
|
2f5d45df01 | ||
|
|
53be44dfdb | ||
|
|
48b5a0b384 | ||
|
|
a08c7b1871 | ||
|
|
0a2a00f883 | ||
|
|
2125e58e1f | ||
|
|
5bdd6971f7 | ||
|
|
051bc7138d | ||
|
|
e6dca329ee | ||
|
|
6cfddb12a6 | ||
|
|
c9c063b8d8 | ||
|
|
e0cd8b2e56 | ||
|
|
38d2088db5 | ||
|
|
8e940b050a | ||
|
|
5733b40ca6 | ||
|
|
22c40675a6 | ||
|
|
a3ef46c21d | ||
|
|
93a546bab4 | ||
|
|
ec427fd82c | ||
|
|
70cc3c2046 | ||
|
|
5634960813 | ||
|
|
c7a49e80e3 | ||
|
|
617d2d30dc | ||
|
|
18f781d099 | ||
|
|
84db812769 | ||
|
|
7763f8aeab | ||
|
|
faa879801e | ||
|
|
4635329a5b | ||
|
|
b89cc3b6df | ||
|
|
e9f8313f7c | ||
|
|
324cd84ffe | ||
|
|
9d7518c9ec | ||
|
|
32e0d6023d | ||
|
|
c9465e476b | ||
|
|
45d237da40 | ||
|
|
631ae2e02f | ||
|
|
695aa14cd7 | ||
|
|
b638bb1d3a | ||
|
|
28950bf90e | ||
|
|
77f8289ca6 | ||
|
|
cece92a828 | ||
|
|
bd08454d66 | ||
|
|
c6e5dd5cf7 | ||
|
|
bd8e3ad137 | ||
|
|
8a2e71fcfb | ||
|
|
301c2a7138 | ||
|
|
5368d7292f | ||
|
|
29689b10aa | ||
|
|
4d8883d0f1 | ||
|
|
efe6fceb3a | ||
|
|
d9a998b95f | ||
|
|
bf94c2997d | ||
|
|
6405a3973d | ||
|
|
9270e22a65 | ||
|
|
02e19cf617 | ||
|
|
1493b6c4f5 | ||
|
|
74ab732999 | ||
|
|
5961d1b56e | ||
|
|
87d6a6bf91 | ||
|
|
456d23f547 | ||
|
|
02da93d0e4 | ||
|
|
597304e932 | ||
|
|
918889c890 | ||
|
|
47bfe6bffc | ||
|
|
5789a0a224 | ||
|
|
b15f54c7f9 | ||
|
|
bc3794eb14 | ||
|
|
4e66d290a6 | ||
|
|
7b48b01fd1 | ||
|
|
883dfaae4a | ||
|
|
884a25a7cd | ||
|
|
8cc8767634 | ||
|
|
90a6902ad4 | ||
|
|
b334acb426 | ||
|
|
9c847aa4f1 | ||
|
|
c3397d1949 | ||
|
|
41ad0b4006 | ||
|
|
7fa59a14f7 | ||
|
|
170a57b9c6 | ||
|
|
0a15c2d16e | ||
|
|
c52283676a | ||
|
|
ce3c2b5ae2 | ||
|
|
48e030d94c | ||
|
|
afaa7c8b76 | ||
|
|
4e6c0352b0 | ||
|
|
f84b69aca7 | ||
|
|
cc7ebbc4d7 | ||
|
|
7a74b815fa | ||
|
|
331038634d | ||
|
|
aa2c316093 | ||
|
|
3347f5d345 | ||
|
|
141792a299 | ||
|
|
183e613981 | ||
|
|
19e2912a71 | ||
|
|
dc82154a03 | ||
|
|
2029dab3bf | ||
|
|
405d808d0b | ||
|
|
783e889634 | ||
|
|
a32c8a3b7f | ||
|
|
5618df35c6 | ||
|
|
c054594383 | ||
|
|
c58f99378f | ||
|
|
45d1dfe425 | ||
|
|
a5dcf9242d | ||
|
|
ecc0714f48 | ||
|
|
26410b991d | ||
|
|
19b1bff7f4 | ||
|
|
bc1aff78d7 | ||
|
|
2df8931d00 | ||
|
|
b765198d53 | ||
|
|
22f620400a | ||
|
|
a68add78d0 | ||
|
|
14d866e8a2 | ||
|
|
335bca4507 | ||
|
|
f31425e9f0 | ||
|
|
3f54fab5f4 | ||
|
|
59c62d48b3 | ||
|
|
a926766478 | ||
|
|
cc233c61f2 | ||
|
|
e9fcdf392f | ||
|
|
c42f039297 | ||
|
|
8cbaf09b4f | ||
|
|
ee8d5dff66 | ||
|
|
ec0873f5a2 | ||
|
|
29515bfcd5 | ||
|
|
c85ebb0c1e | ||
|
|
d6e66d5c7f | ||
|
|
f65f2b229a | ||
|
|
5094351469 | ||
|
|
5d6a770ce8 | ||
|
|
010d7f9ce4 | ||
|
|
fb49e680a6 | ||
|
|
6b98856892 | ||
|
|
1a479a7199 | ||
|
|
2894bcd7ff | ||
|
|
1ae8040bd7 | ||
|
|
57a80084ce | ||
|
|
e35b4ea62c | ||
|
|
3546526177 | ||
|
|
12efb6166a | ||
|
|
9beee068ce | ||
|
|
9efcba5c02 | ||
|
|
947333ea64 | ||
|
|
7e527fc62a | ||
|
|
9f78c595b3 | ||
|
|
fa03442c85 | ||
|
|
e664c035a1 | ||
|
|
c522e3b054 | ||
|
|
b3c037ab21 | ||
|
|
097fdb643b | ||
|
|
43094a9897 | ||
|
|
aefa623cd4 | ||
|
|
1be11738eb | ||
|
|
5a09c116f6 | ||
|
|
bb700db08e | ||
|
|
2e8582b14c | ||
|
|
8d47dc2f82 | ||
|
|
6a3c736195 | ||
|
|
9463999325 | ||
|
|
e50c30eaaa | ||
|
|
45a3e21897 | ||
|
|
47dbcdff9c | ||
|
|
dc164f81e5 | ||
|
|
bab0ec8b60 | ||
|
|
f543e3f4e2 | ||
|
|
43d4b9abaa | ||
|
|
f5bbb6aef5 | ||
|
|
25b666c2ae | ||
|
|
78087073ac | ||
|
|
12c2ced497 | ||
|
|
87954419ba | ||
|
|
0add0bc2e9 | ||
|
|
7858afb837 | ||
|
|
69c0b2e223 | ||
|
|
855ca48220 | ||
|
|
02bee86397 | ||
|
|
315d466da8 | ||
|
|
d4597e0094 | ||
|
|
b8ff3414c0 | ||
|
|
2206cc1f78 | ||
|
|
00433467be | ||
|
|
1000e33e7f | ||
|
|
a64245fb5b | ||
|
|
2f784f00ff | ||
|
|
136012c558 | ||
|
|
874abf6442 | ||
|
|
20975957ee | ||
|
|
1fabae2870 | ||
|
|
abb3523ee3 | ||
|
|
ec63a06e25 | ||
|
|
8b4353f08c | ||
|
|
8bfb3b87c3 | ||
|
|
f1a493b999 | ||
|
|
3afcfa79e1 | ||
|
|
adaa436f6b | ||
|
|
37135762c5 | ||
|
|
e6aa7128df | ||
|
|
da8d4a290c | ||
|
|
4d11a727d9 | ||
|
|
3c232bfca0 | ||
|
|
b3fe96477a | ||
|
|
5f87544a0d | ||
|
|
f0c0ca4566 | ||
|
|
23719526cd | ||
|
|
67ffe22460 | ||
|
|
08996a3253 | ||
|
|
95e2f7665b | ||
|
|
a5ef2d1574 | ||
|
|
cc0a786004 | ||
|
|
4d6693d948 | ||
|
|
9c0792c5a0 | ||
|
|
0f06f47ab4 | ||
|
|
5371f854fc | ||
|
|
bd49f0f959 | ||
|
|
63d3071233 | ||
|
|
015a50bafd | ||
|
|
1ee4b9bd01 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,10 +9,13 @@ CVS
|
||||
*.o
|
||||
linux/ccextractor
|
||||
linux/depend
|
||||
windows/debug/*
|
||||
windows/debug/**
|
||||
windows/release/**
|
||||
|
||||
####
|
||||
# Visual Studio project Ignored files
|
||||
|
||||
*.suo
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.user
|
||||
|
||||
@@ -4,7 +4,7 @@ MAINTAINER = Marc Espie <espie@openbsd.org>
|
||||
CATEGORIES = multimedia
|
||||
COMMENT = closed caption subtitles extractor
|
||||
HOMEPAGE = http://ccextractor.sourceforge.net/
|
||||
V = 0.70
|
||||
V = 0.77
|
||||
DISTFILES = ccextractor.${V:S/.//}-src.zip
|
||||
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
|
||||
DISTNAME = ccextractor-$V
|
||||
|
||||
23
README.md
23
README.md
@@ -1,21 +1,12 @@
|
||||
ccextractor
|
||||
===========
|
||||
|
||||
CCExtractor - Carlos' version (mainstream).
|
||||
Carlos' version (mainstream) is the most stable branch.
|
||||
|
||||
0.70 - GSOC
|
||||
-----------
|
||||
This is the first release that is part of Google's Summer of Code.
|
||||
Anshul, Ruslan and Willem joined CCExtractor to work on a number of things
|
||||
over the summer, and their work is already reaching the mainstream
|
||||
version of CCExtractor.
|
||||
Extracting subtitles has never been so easy. Just type the following command:
|
||||
ccextrator "name of input"
|
||||
|
||||
- Added a huge dictionary submitted by Matt Stockard.
|
||||
- Added DVB subtitles decoder, spupng in output
|
||||
- Added support for cdt2 media atoms in QT video files. Now multiple atoms in
|
||||
a single sample sequence are supported.
|
||||
- Changed Makefile.
|
||||
- Fixed some bugs.
|
||||
- Added feature to print info about file's subtitles and streams.
|
||||
- Support Long PMT.
|
||||
- Support Configuration file.
|
||||
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
|
||||
|
||||
For News about release, please find CHANGES.TXT
|
||||
|
||||
@@ -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
|
||||
|
||||
263
docs/CHANGES.TXT
263
docs/CHANGES.TXT
@@ -1,5 +1,74 @@
|
||||
0.70 - GSOC
|
||||
-----------
|
||||
0.78 (2015-12-12)
|
||||
-----------------
|
||||
- Support to extract Closed Caption from MultiProgram at once.
|
||||
- CEA-708: exporting to SAMI (.smi), Transcript (.txt), Timed Transcript (ttxt) and SubRip (.srt).
|
||||
- CEA-708: 16 bit charset support (tested on Korean).
|
||||
- CEA-708: Roll Up captions handling.
|
||||
- Changed TCP connection protocol (BIN data is now wrapped in packets, added EPG support and keep-alive packets).
|
||||
- TCP connection password prompt is removed. To set connection password use -tcppassword argument instead.
|
||||
- Support ISDB Closed Caption.
|
||||
- Added a new output format, simplexml (used internally by a CCExtractor user, may or may not be useful for
|
||||
anyone else).
|
||||
|
||||
0.77 (2015-06-20)
|
||||
-----------------
|
||||
- Fixed bug in capitalization code ('I' was not being capitalized).
|
||||
- GUI should now run in Windows 8 (using the include .Net runtime, since
|
||||
3.5 cannot be installed in Windows 8 apparently).
|
||||
- Fixed Mac build script, binary is now compiled with support for
|
||||
files over 2 GB.
|
||||
- Fixed bug in PMT code, damaged PMT sections could make CCExtractor
|
||||
crash.
|
||||
|
||||
0.76 (2015-03-28)
|
||||
-----------------
|
||||
- Added basic M2TS support
|
||||
- Added EPG support - you can now export the Program Guide to XML
|
||||
- Some bugfixes
|
||||
|
||||
0.75 (2015-01-15)
|
||||
-----------------
|
||||
- Fixed issue with teletext to other then srt.
|
||||
- CCExtractor can be used as library if compiled using cmake
|
||||
- By default the Windows version adds BOM to generated UTF files (this is
|
||||
because it's needed to open the files correctly) while all other
|
||||
builds don't add it (because it messes with text processing tools).
|
||||
You can use -bom and -nobom to change the behaviour.
|
||||
|
||||
0.74 (2014-09-24)
|
||||
-----------------
|
||||
- Fixed issue with -o1 -o2 and -12 parameters (where it would write output only in the o2 file)
|
||||
- Fixed UCLA parameter issue. Now the UCLA parameter settings can't be overwritten anymore by later parameters that affect the custom transcript
|
||||
- Switched order around for TLT and TT page number in custom transcript to match UCLA settings
|
||||
- Added nobom parameter, for when files are processed by tools that can't handle the BOM. If using this, files might be not readable under windows.
|
||||
- Segfault fix when no input files were given
|
||||
- No more bin output when sending to server + possibility to send TT to server for processing
|
||||
- Windows: Added the Microsoft redistributable MSVCR120.DLL to both the installation package and the application zip.
|
||||
|
||||
0.73 - GSOC (2014-08-19)
|
||||
------------------------
|
||||
- Added support of BIN format for Teletext
|
||||
- Added start of librarisation. This will allow in the future for other programs to use encoder/decoder functions and more.
|
||||
|
||||
0.72 - GSOC (2014-08-12)
|
||||
------------------------
|
||||
- Fix for WTV files with incorrect timing
|
||||
- Added support for fps change using data from AVC video track in a H264 TS file.
|
||||
- Added FFMpeg Support to enable all encapsulator and decoder provided by ffmpeg
|
||||
|
||||
0.71 - GSOC (2014-07-31)
|
||||
------------------------
|
||||
- Added feature to receive captions in BIN format according to CCExtractor's own
|
||||
protocol over TCP (-tcp port [-tcppassword password])
|
||||
- Added ability to send captions to the server described above or to the
|
||||
online repository (-sendto host[:port])
|
||||
- Added -stdin parameter for reading input stream from standard input
|
||||
- Compilation in Cygwin using linux/Makefile
|
||||
- Fix for .bin files when not using latin1 charset
|
||||
- Correction of mp4 timing, when one timestamp points timing of two atom
|
||||
|
||||
0.70 - GSOC (2014-07-06)
|
||||
------------------------
|
||||
This is the first release that is part of Google's Summer of Code.
|
||||
Anshul, Ruslan and Willem joined CCExtractor to work on a number of things
|
||||
over the summer, and their work is already reaching the mainstream
|
||||
@@ -37,9 +106,10 @@ version of CCExtractor.
|
||||
1111001 is the default setting for -ucla
|
||||
Make sure you use this parameter after others that might affect these
|
||||
settings (-out, -ucla, -xds, -txt, -ttxt, ...)
|
||||
- Fixed Negative timing Bug
|
||||
|
||||
0.69
|
||||
----
|
||||
0.69 (2014-04-05)
|
||||
-----------------
|
||||
- A few patches from Christopher Small, including proper support
|
||||
for multiple multicast clients listening on the same port.
|
||||
- GUI: Fixed teletext preview.
|
||||
@@ -58,8 +128,8 @@ version of CCExtractor.
|
||||
- Windows GUI: Some code refactoring, since the HDHomeRun support makes
|
||||
the code larger enough to require more than one source file :-)
|
||||
|
||||
0.68
|
||||
----
|
||||
0.68 (2013-12-24)
|
||||
-----------------
|
||||
- A couple of shared variables between 608 decoders were causing
|
||||
problems when both fields were processed at the same time with
|
||||
-12, fixed.
|
||||
@@ -73,8 +143,8 @@ version of CCExtractor.
|
||||
(Heleen Buus).
|
||||
- Some fixes (Chris Small).
|
||||
|
||||
0.67
|
||||
----
|
||||
0.67 (2013-10-09)
|
||||
-----------------
|
||||
- Padding bytes were being discarded early in the process in 0.66,
|
||||
which is convenient for debugging, but it messes with timing in
|
||||
.raw, which depends on padding. Fixed.
|
||||
@@ -94,8 +164,8 @@ version of CCExtractor.
|
||||
roll-up mode.
|
||||
|
||||
|
||||
0.66
|
||||
----
|
||||
0.66 (2013-07-01)
|
||||
-----------------
|
||||
- Fixed bug in auto detection code that triggered a message
|
||||
about file being auto of sync.
|
||||
- Added -investigate_packets
|
||||
@@ -173,8 +243,8 @@ version of CCExtractor.
|
||||
- Added -noautotimeref: Prevent UTC reference from being auto set from
|
||||
the stream data.
|
||||
|
||||
0.65
|
||||
----
|
||||
0.65 (2013-03-14)
|
||||
-----------------
|
||||
- Minor GUI changes for teletext
|
||||
- Added end timestamps in timed transcripts
|
||||
- Added support for SMPTE (patch by John Kemp)
|
||||
@@ -192,8 +262,8 @@ version of CCExtractor.
|
||||
display their contents (-parsePAT and -parsePMT) which makes
|
||||
troubleshooting easier.
|
||||
|
||||
0.64
|
||||
----
|
||||
0.64 (2012-10-29)
|
||||
-----------------
|
||||
- Changed Window GUI size (larger).
|
||||
- Added Teletext options to GUI.
|
||||
- Added -teletext to force teletext mode even if not detected
|
||||
@@ -213,8 +283,8 @@ version of CCExtractor.
|
||||
- Added --nogoptime to force PTS timing even when CCExtractor would
|
||||
use GOP timing otherwise.
|
||||
|
||||
0.63
|
||||
----
|
||||
0.63 (2012-08-17)
|
||||
-----------------
|
||||
- Telext support added, by integrating Petr Kutalek's telxcc. Integration is
|
||||
still quite basic (there's equivalent code from both CCExtractor and
|
||||
telxcc) and some clean up is needed, but it works. Petr has announced that
|
||||
@@ -222,8 +292,8 @@ version of CCExtractor.
|
||||
CCExtractor.
|
||||
- Some bug fixes, as usual.
|
||||
|
||||
0.62
|
||||
----
|
||||
0.62 (2012-05-23)
|
||||
-----------------
|
||||
- Corrected Mac build "script" (needed to add GPAC includes). Thanks to the
|
||||
Mac users that sent this.
|
||||
- Hauppauge mode now uses PES timing, needed for files that don't have
|
||||
@@ -245,8 +315,8 @@ version of CCExtractor.
|
||||
or certain samples (we had none like this in our test collection). Thanks,
|
||||
Rajesh.
|
||||
|
||||
0.61
|
||||
----
|
||||
0.61 (2012-03-08)
|
||||
-----------------
|
||||
- Fix: GCC 3.4.4 can now build CCExtractor.
|
||||
- Fix: Damaged TS packets (those that come with 'error in transport' bit
|
||||
on) are now skipped.
|
||||
@@ -256,8 +326,8 @@ version of CCExtractor.
|
||||
anything but please report).
|
||||
- Some non-interesting cleanup.
|
||||
|
||||
0.60
|
||||
----
|
||||
0.60 (unreleased)
|
||||
-----------------
|
||||
- Add: MP4 support, using GPAC (a media library). Integration is currently
|
||||
"enough so it works", but needs some more work. There's some duplicate
|
||||
code, the stream must be a file (no streaming), etc.
|
||||
@@ -267,8 +337,8 @@ version of CCExtractor.
|
||||
roll-up) was broken, with complete lines being missing.
|
||||
- Fix: bin format not working as input.
|
||||
|
||||
0.59
|
||||
----
|
||||
0.59 (2011-10-07)
|
||||
-----------------
|
||||
- More AVC/H.264 work. pic_order_cnt_type != 0 will be processed now.
|
||||
- Fix: Roll-up captions with interruptions for Text (with ResumeTextDisplay
|
||||
in the middle of the caption data) were missing complete lines.
|
||||
@@ -296,8 +366,8 @@ version of CCExtractor.
|
||||
- Some code clean up, minor refactoring.
|
||||
- Teletext detection (not yet processing).
|
||||
|
||||
0.58
|
||||
----
|
||||
0.58 (2011-08-21)
|
||||
-----------------
|
||||
- Implemented new PTS based mode to order the caption information
|
||||
of AVC/H.264 data streams. The old pic_order_cnt_lsb based method
|
||||
is still available via the -poc or --usepicorder command switches.
|
||||
@@ -321,18 +391,18 @@ version of CCExtractor.
|
||||
output are processed OK.
|
||||
- Updated Windows GUI.
|
||||
|
||||
0.57
|
||||
----
|
||||
0.57 (2010-12-16)
|
||||
-----------------
|
||||
- Bugfixes in the Windows version. Some debug code was unintentionally
|
||||
left in the released version.
|
||||
|
||||
0.56
|
||||
----
|
||||
0.56 (2010-12-09)
|
||||
-----------------
|
||||
- H264 support
|
||||
- Other minor changes a lot less important
|
||||
|
||||
0.55
|
||||
----
|
||||
0.55 (2009-08-09)
|
||||
-----------------
|
||||
- Replace pattern matching code with improved parser for MPEG-2 elementary
|
||||
streams.
|
||||
- Fix parsing of ReplayTV 5000 captions.
|
||||
@@ -347,8 +417,8 @@ version of CCExtractor.
|
||||
because of the odd number of fields. I used top_field_first to tell when the channels
|
||||
are reversed. See Table 6-1 of the SCTE 20 [Paul Fernquist]
|
||||
|
||||
0.54
|
||||
----
|
||||
0.54 (2009-04-16)
|
||||
-----------------
|
||||
- Add -nosync and -fullbin switches for debugging purposes.
|
||||
- Remove -lg (--largegops) switch.
|
||||
- Improve syncronization of captions for source files with
|
||||
@@ -361,8 +431,8 @@ version of CCExtractor.
|
||||
- Added a feature to add start and end messages (for credits).
|
||||
See help screen for details.
|
||||
|
||||
0.53
|
||||
----
|
||||
0.53 (2009-02-24)
|
||||
-----------------
|
||||
- Force generated RCWT files to have the same length as source file.
|
||||
- Fix documentation for -startat / -endat switches.
|
||||
- Make -startat / -endat work with all output formats.
|
||||
@@ -388,8 +458,8 @@ version of CCExtractor.
|
||||
it (there's not .NET 3.5 for Windows 2000), as
|
||||
requested by a couple of key users.
|
||||
|
||||
0.51
|
||||
----
|
||||
0.51 (unreleased)
|
||||
-----------------
|
||||
- Removed -autopad and -goppad, no longer needed.
|
||||
- In preparation to a new binary format we have
|
||||
renamed the current .bin to .raw. Raw files
|
||||
@@ -414,14 +484,14 @@ version of CCExtractor.
|
||||
too.
|
||||
- [Volker] Dish Network clean-up
|
||||
|
||||
0.50
|
||||
----
|
||||
0.50 (2008-12-12)
|
||||
-----------------
|
||||
- [Volker] Fix in DVR-MS NTSC timing
|
||||
- [Volker] More clean-up
|
||||
- Minor fixes
|
||||
|
||||
0.49
|
||||
----
|
||||
0.49 (2008-12-10)
|
||||
-----------------
|
||||
- [Volker] Major MPEG parser rework. Code much
|
||||
cleaner now.
|
||||
- Some stations transmit broken roll-up captions,
|
||||
@@ -438,8 +508,8 @@ version of CCExtractor.
|
||||
- [Volker] Added support for DVR-MS NTSC files.
|
||||
- Other minor bugfixes and changes.
|
||||
|
||||
0.46
|
||||
----
|
||||
0.46 (2008-11-24)
|
||||
-----------------
|
||||
- Added support for live streaming, ccextractor
|
||||
can now process files that are being recorded
|
||||
at the same time.
|
||||
@@ -452,9 +522,8 @@ version of CCExtractor.
|
||||
Note: For now, it's only ATSC recordings, not
|
||||
NTSC (analog) recordings.
|
||||
|
||||
|
||||
0.45
|
||||
----
|
||||
0.45 (2008-11-14)
|
||||
-----------------
|
||||
- Added autodetection of DVR-MS files.
|
||||
- Added -asf to force DVR-MS mode.
|
||||
- Added some specific support for DVR-MS
|
||||
@@ -474,8 +543,8 @@ version of CCExtractor.
|
||||
need ccextractor to use GOP timing in large
|
||||
GOPs.
|
||||
|
||||
0.44
|
||||
----
|
||||
0.44 (2008-09-10)
|
||||
-----------------
|
||||
- Added an option to the GUI to process
|
||||
individual files in batch, i.e. call
|
||||
ccextractor once per file. Use it if you
|
||||
@@ -486,8 +555,8 @@ version of CCExtractor.
|
||||
- Several minor bugfixes.
|
||||
- Updated the GUI to add the new options.
|
||||
|
||||
0.43
|
||||
----
|
||||
0.43 (2008-06-20)
|
||||
-----------------
|
||||
- Fixed a bug in the read loop (no less)
|
||||
that caused some files to fail when
|
||||
reading without buffering (which is
|
||||
@@ -495,16 +564,16 @@ version of CCExtractor.
|
||||
- Several improvements in the GUI, such as
|
||||
saving current options as default.
|
||||
|
||||
0.42
|
||||
----
|
||||
0.42 (2008-06-17)
|
||||
-----------------
|
||||
- The option switch "-transcript" has been
|
||||
changed to "--transcript". Also, "-txt"
|
||||
has been added as the short alias.
|
||||
- Windows GUI
|
||||
- Updated help screen
|
||||
|
||||
0.41
|
||||
----
|
||||
0.41 (2008-06-15)
|
||||
-----------------
|
||||
- Default output is now .srt instead of .bin,
|
||||
use -raw if you need the data dump instead of
|
||||
.srt.
|
||||
@@ -516,15 +585,15 @@ version of CCExtractor.
|
||||
there aren't useless. But if they annoy
|
||||
you go ahead...
|
||||
|
||||
0.40
|
||||
----
|
||||
0.40 (2008-05-20)
|
||||
-----------------
|
||||
- Fixed a bug in the sanity check function
|
||||
that caused the Myth branch to abort.
|
||||
- Fixed the OSX build script, it needed a
|
||||
new #define to work.
|
||||
|
||||
0.39
|
||||
----
|
||||
0.39 (2008-05-11)
|
||||
-----------------
|
||||
- Added a -transcript. If used, the output will
|
||||
have no time information. Also, if in roll-up
|
||||
mode there will be no repeated lines.
|
||||
@@ -557,8 +626,8 @@ version of CCExtractor.
|
||||
join the subs), use -ve.
|
||||
|
||||
|
||||
0.36
|
||||
----
|
||||
0.36 (unreleased)
|
||||
-----------------
|
||||
- Fixed bug in SMI, nbsp was missing a ;.
|
||||
- Footer for SAMI files was incorrect (<body> and
|
||||
<sami> tags were being opened again instead of
|
||||
@@ -588,8 +657,8 @@ version of CCExtractor.
|
||||
as usual.
|
||||
|
||||
|
||||
0.35
|
||||
----
|
||||
0.35 (unreleased)
|
||||
-----------------
|
||||
- Added --defaultcolor to the help screen. Code
|
||||
was already in 0.34 but the documentation wasn't
|
||||
updated.
|
||||
@@ -598,8 +667,8 @@ version of CCExtractor.
|
||||
- At the end of the process, a ratio between
|
||||
video length and time to process is displayed.
|
||||
|
||||
0.34
|
||||
----
|
||||
0.34 (2007-06-03)
|
||||
-----------------
|
||||
- Added some basic letter case and capitalization
|
||||
support. For captions that broadcast in ALL
|
||||
UPPERCASE (most of them), ccextractor can now
|
||||
@@ -650,8 +719,8 @@ version of CCExtractor.
|
||||
Number (0.0.0.34 in this version) in case
|
||||
you want to check for version info.
|
||||
|
||||
0.33
|
||||
----
|
||||
0.33 (unreleased)
|
||||
-----------------
|
||||
- Added -scr or --screenfuls, to select the
|
||||
number of screenfuls ccextractor should
|
||||
write before exiting. A screenful is
|
||||
@@ -670,8 +739,8 @@ version of CCExtractor.
|
||||
Use -nofc or --nofontcolor if you don't
|
||||
want these tags.
|
||||
|
||||
0.32
|
||||
----
|
||||
0.32 (unreleased)
|
||||
-----------------
|
||||
- Added -delay ms, which adds (or substracts)
|
||||
a number of milliseconds to all times in
|
||||
.srt/.sami files. For example,
|
||||
@@ -690,8 +759,8 @@ version of CCExtractor.
|
||||
such as from minute 3 to minute 5. Check
|
||||
help screen for exact syntax.
|
||||
|
||||
0.31
|
||||
----
|
||||
0.31 (unreleased)
|
||||
-----------------
|
||||
- Added -dru (direct rollup), which causes
|
||||
roll-up captions to be written as
|
||||
they would on TV instead of line by line.
|
||||
@@ -699,20 +768,20 @@ version of CCExtractor.
|
||||
and ugly too (each line is written many
|
||||
times, two characters at time).
|
||||
|
||||
0.30
|
||||
----
|
||||
0.30 (2007-05-24)
|
||||
-----------------
|
||||
- Fix in extended char decoding, I wasn't
|
||||
replacing the previous char.
|
||||
- When a sequence code was found before
|
||||
having a PTS, reported time was
|
||||
undefined.
|
||||
|
||||
0.29
|
||||
----
|
||||
0.29 (unreleased)
|
||||
-----------------
|
||||
- Minor bugfix.
|
||||
|
||||
0.28
|
||||
----
|
||||
0.28 (unreleased)
|
||||
-----------------
|
||||
- Fixed a buffering related issue. Short version,
|
||||
the first 2 Mb in non-TS mode were being
|
||||
discarded.
|
||||
@@ -721,20 +790,20 @@ version of CCExtractor.
|
||||
they are not part of the .srt "standard"
|
||||
even if McPoodle add them.
|
||||
|
||||
0.27
|
||||
----
|
||||
0.27 (unreleased)
|
||||
-----------------
|
||||
- Modified sanitizing code, it's less aggresive
|
||||
now. Ideally it should mean that characters
|
||||
won't be missed anymore. We'll see.
|
||||
|
||||
0.26
|
||||
----
|
||||
0.26 (unreleased)
|
||||
-----------------
|
||||
- Added -gp (or -goppad) to make ccextractor use
|
||||
GOP timing. Try it for non TS files where
|
||||
subs start OK but desync as the video advances.
|
||||
|
||||
0.25
|
||||
----
|
||||
0.25 (unreleased)
|
||||
-----------------
|
||||
- Format detection is not perfect yet. I've added
|
||||
-nomyth to prevent the MytvTV code path to be
|
||||
called. I've seen apparently correct files that
|
||||
@@ -744,8 +813,8 @@ version of CCExtractor.
|
||||
options will work.
|
||||
|
||||
|
||||
0.24
|
||||
----
|
||||
0.24 (unreleased)
|
||||
-----------------
|
||||
- Fixed a bug that caused dvr-ms (Windows Media Center)
|
||||
files to be incorrectly processed (letters out of
|
||||
order all the time).
|
||||
@@ -759,8 +828,8 @@ version of CCExtractor.
|
||||
still can).
|
||||
|
||||
|
||||
0.22
|
||||
----
|
||||
0.22 (2007-05-15)
|
||||
-----------------
|
||||
- Added text mode handling into decoder, which gets rids
|
||||
of junk when text mode data is present.
|
||||
- Added support for certain (possibly non standard
|
||||
@@ -771,8 +840,8 @@ version of CCExtractor.
|
||||
- Other Minor bug fixes.
|
||||
|
||||
|
||||
0.20
|
||||
----
|
||||
0.20 (2007-05-07)
|
||||
-----------------
|
||||
- Unicode should be decent now.
|
||||
- Added support for Hauppauge PVR 250 cards, and (possibly)
|
||||
many others (bttv) with the same closed caption recording
|
||||
@@ -789,8 +858,8 @@ version of CCExtractor.
|
||||
though. If you have a good CSS for .SAMI files let me
|
||||
know.
|
||||
|
||||
0.19
|
||||
----
|
||||
0.19 (2007-05-03)
|
||||
-----------------
|
||||
- Work on Dish Network streams, timing was completely broken.
|
||||
It's fixed now at least for the samples I have, if it's not
|
||||
completely fixed let me know. Credit for this goes to
|
||||
@@ -801,8 +870,8 @@ version of CCExtractor.
|
||||
- Added Unicode and Latin-1 encoding.
|
||||
|
||||
|
||||
0.17
|
||||
----
|
||||
0.17 (2007-04-29)
|
||||
-----------------
|
||||
- Extraction to .srt is almost complete - works correctly for
|
||||
pop-up and roll-up captions, possibly not yet for paint-on
|
||||
(mostly because I don't have any sample with paint-on captions
|
||||
@@ -810,8 +879,8 @@ version of CCExtractor.
|
||||
- Minor bug fixes.
|
||||
- Automatic TS/non-TS mode detection.
|
||||
|
||||
0.14
|
||||
----
|
||||
0.14 (2007-04-25)
|
||||
-----------------
|
||||
- Work on handling special cases related to the MPEG reference
|
||||
clock: Roll over, jumps, etc.
|
||||
- Modified padding code a bit: In particular, padding occurs
|
||||
@@ -824,8 +893,8 @@ version of CCExtractor.
|
||||
needs to start with a TS header).
|
||||
- Minor bug fixes.
|
||||
|
||||
0.07
|
||||
----
|
||||
0.07 (2007-04-19)
|
||||
-----------------
|
||||
- Added MPEG reference clock parsing.
|
||||
- Added autopadding in TS. Does miracles with timing.
|
||||
- Added video information (as extracted from sequence header).
|
||||
|
||||
58
docs/FFMPEG.TXT
Normal file
58
docs/FFMPEG.TXT
Normal file
@@ -0,0 +1,58 @@
|
||||
Overview
|
||||
========
|
||||
FFmpeg Intigration was done to support multiple encapsulator.
|
||||
|
||||
Dependecy
|
||||
=========
|
||||
FFmpeg library's
|
||||
|
||||
Download and Install FFmpeg on your linux pc.
|
||||
---------------------------------------------
|
||||
|
||||
Download latest source code from following link
|
||||
https://ffmpeg.org/download.html
|
||||
|
||||
then following command to install ffmpeg
|
||||
./configure && make && make install
|
||||
|
||||
Note:If you installed ffmpeg on non standurd location, please change/update your
|
||||
enviorment variable $PATH and $LD_LIBRARY_PATH
|
||||
|
||||
Download and Install FFmpeg on your Windows pc.
|
||||
----------------------------------------------
|
||||
Download prebuild library from following link
|
||||
http://ffmpeg.zeranoe.com/builds/
|
||||
|
||||
You need to download Shared Versions to run the program and Dev Versions to compile.
|
||||
|
||||
How to compile ccextractor
|
||||
==========================
|
||||
|
||||
In Linux
|
||||
--------
|
||||
make ENABLE_FFMPEG=yes
|
||||
|
||||
On Windows
|
||||
----------
|
||||
put the path of libs/include of ffmpeg library in library paths.
|
||||
step 1) In visual studio 2013 right click <Project> and select property.
|
||||
step 2) Select Configuration properties in left panel(column) of property.
|
||||
step 3) Select VC++ Directory.
|
||||
step 4) In the right pane, in the right-hand column of the VC++ Directory property,
|
||||
open the drop-down menu and choose Edit.
|
||||
Step 5) Add path of Directory where you have kept uncompressed library of FFmpeg.
|
||||
|
||||
|
||||
Set preprocessor flag ENABLE_FFMPEG=1
|
||||
Step 1)In visual studio 2013 right click <Project> and select property.
|
||||
Step 2)In the left panel, select Configuration Properties, C/C++, Preprocessor.
|
||||
Step 3)In the right panel, in the right-hand column of the Preprocessor Definitions property, open the drop-down menu and choose Edit.
|
||||
Step 4)In the Preprocessor Definitions dialog box, add ENABLE_FFMPEG=1. Choose OK to save your changes.
|
||||
|
||||
Add library in linker
|
||||
step 1)Open property of project
|
||||
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 all FFmpeg's lib in new line
|
||||
26
docs/OCR.txt
26
docs/OCR.txt
@@ -6,8 +6,8 @@ extract text from images. In the World of Subtile, subtitle stored
|
||||
in bitmap format are common and even neccassary. for converting subtile
|
||||
in bitmap format to subtilte in text format ocr is used.
|
||||
|
||||
Dependecy
|
||||
=========
|
||||
Dependency
|
||||
==========
|
||||
Tesseract (OCR library by google)
|
||||
Leptonica (image processing library)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -55,13 +56,10 @@ 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 extract the tar file and put
|
||||
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.63
|
||||
ccextractor, 0.78
|
||||
-----------------
|
||||
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
|
||||
Maintainer: cfsmp3
|
||||
@@ -7,12 +7,26 @@ Lots of credit goes to other people, though:
|
||||
McPoodle (author of the original SCC_RIP), Neuron2, and others (see source
|
||||
code).
|
||||
|
||||
Home: http://ccextractor.sourceforge.net
|
||||
Home: http://www.ccextractor.org
|
||||
|
||||
You can subscribe to new releases notifications at freshmeat:
|
||||
|
||||
http://freshmeat.net/projects/ccextractor
|
||||
|
||||
Google Summer of Code 2014 students
|
||||
- Willem van iseghem
|
||||
- Ruslan KuchumoV
|
||||
- Anshul Maheshwari
|
||||
|
||||
Google Summer of Code 2015 students
|
||||
- Willem van iseghem
|
||||
- Ruslan Kuchumov
|
||||
- Anshul Maheshwari
|
||||
- Nurendra Choudhary
|
||||
- Oleg Kiselev
|
||||
- Vasanth Kalingeri
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
GPL 2.0.
|
||||
@@ -67,21 +81,18 @@ If there are Spanish subtitles, one of them should work.
|
||||
|
||||
McPoodle's page
|
||||
---------------
|
||||
http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
|
||||
http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
|
||||
|
||||
Essential CC related information and free (with source) tools.
|
||||
|
||||
Encoding
|
||||
--------
|
||||
This version, in both its Linux and Windows builds generates by
|
||||
default Latin-1 encoded files. You can use -unicode and -utf8
|
||||
if you prefer these encodings (usually it just depends on what
|
||||
your specific player likes).
|
||||
This has changed from the previous UTF-8 default which vobsub
|
||||
can't handle.
|
||||
default Unicode files. You can use -latin1 and -utf8 if you prefer
|
||||
these encodings (usually it just depends on what your specific
|
||||
player likes).
|
||||
|
||||
Future work
|
||||
-----------
|
||||
- Finish EIA-708 decoder
|
||||
- Network support
|
||||
- Please check www.ccextractor.org for news and future work.
|
||||
|
||||
|
||||
31
docs/using_cmake_build.txt
Normal file
31
docs/using_cmake_build.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
For building ccextractor using cmake folllow below steps..
|
||||
|
||||
Step 1) Check you have right version of cmake installed. ( version >= 3.0.2 )
|
||||
We are using CMP0037 policy of cmake which was introduced in 3.0.0
|
||||
since we have tested our system only with cmake version 3.0.2, I would
|
||||
suggest to use 3.0.2 or higher version.
|
||||
|
||||
|
||||
Step 2) create a seprate directory where you want to build the target.
|
||||
In Unix you can do it using follwing commands.
|
||||
~> cd ccextractor
|
||||
~> mkdir build
|
||||
|
||||
Step 3) make the build sytem using cmake
|
||||
~> cmake ../src/
|
||||
|
||||
Step 4) Compile the code.
|
||||
~> make
|
||||
~> make install
|
||||
|
||||
Step 5) Use CCextractor as you would like
|
||||
|
||||
|
||||
If you want to build CCExtractor with FFMpeg you need to pass
|
||||
cmake -DWITH_FFMPEG=ON ../src/
|
||||
|
||||
If you want to build CCExtractor with OCR you need to pass
|
||||
cmake -DWITH_OCR=ON ../src/
|
||||
|
||||
Hint for looking all the things you want to set from outside
|
||||
cmake -LAH ../src/
|
||||
@@ -1,22 +1,28 @@
|
||||
SHELL = /bin/sh
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
||||
SYS := $(shell gcc -dumpmachine)
|
||||
CFLAGS = -O3 -std=gnu99
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib
|
||||
ALL_FLAGS = -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm -zmuldefs
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib -I../src/lib_ccx -I../src/.
|
||||
ALL_FLAGS = -Wno-write-strings -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm
|
||||
|
||||
ifneq (, $(findstring linux, $(SYS)))
|
||||
CFLAGS +=-DGPAC_CONFIG_LINUX
|
||||
endif
|
||||
TARGET = ccextractor
|
||||
|
||||
OBJS_DIR = objs
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib:../src/lib_ccx
|
||||
|
||||
SRCS_DIR = ../src
|
||||
SRCS_C = $(wildcard $(SRCS_DIR)/*.c)
|
||||
OBJS = $(SRCS_C:$(SRCS_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_CCX_DIR = $(SRCS_DIR)/lib_ccx
|
||||
SRCS_CCX = $(wildcard $(SRCS_CCX_DIR)/*.c)
|
||||
OBJS_CCX = $(SRCS_CCX:$(SRCS_CCX_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_PNG_DIR = $(SRCS_DIR)/libpng
|
||||
SRCS_PNG = $(wildcard $(SRCS_PNG_DIR)/*.c)
|
||||
OBJS_PNG = $(SRCS_PNG:$(SRCS_PNG_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
@@ -36,9 +42,39 @@ INSTLALL_PROGRAM = $(INSTLALL)
|
||||
DESTDIR = /usr/bin
|
||||
|
||||
ifeq ($(ENABLE_OCR),yes)
|
||||
CFLAGS+=-I/usr/local/include/tesseract -I/usr/local/include/leptonica
|
||||
CFLAGS+=-DENABLE_OCR
|
||||
LDFLAGS+= $(shell pkg-config --libs tesseract)
|
||||
CFLAGS+=-DENABLE_OCR -DPNG_NO_CONFIG_H
|
||||
TESS_LDFLAGS+= $(shell pkg-config --libs tesseract)
|
||||
LEPT_LDFLAGS+= $(shell pkg-config --libs lept)
|
||||
|
||||
#error checking of library are there or not
|
||||
ifeq ($(TESS_LDFLAGS),$(EMPTY))
|
||||
$(error **ERROR** "tesseract not found")
|
||||
else
|
||||
#TODO print the version of library found
|
||||
$(info "tesseract found")
|
||||
endif
|
||||
ifeq ($(LEPT_LDFLAGS),$(EMPTY))
|
||||
$(error **ERROR** "leptonica not found")
|
||||
else
|
||||
#TODO print the version of library found
|
||||
$(info "Leptonica found")
|
||||
endif
|
||||
|
||||
CFLAGS += $(shell pkg-config --cflags tesseract)
|
||||
CFLAGS += $(shell pkg-config --cflags lept)
|
||||
LDFLAGS += $(TESS_LDFLAGS)
|
||||
LDFLAGS += $(LEPT_LDFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(ENABLE_FFMPEG),yes)
|
||||
CFLAGS+=-DENABLE_FFMPEG
|
||||
CFLAGS+= $(shell pkg-config --cflags libavcodec)
|
||||
CFLAGS+= $(shell pkg-config --cflags libavformat)
|
||||
CFLAGS+= $(shell pkg-config --cflags libavutil)
|
||||
LDFLAGS+= $(shell pkg-config --libs libavcodec )
|
||||
LDFLAGS+= $(shell pkg-config --libs libavformat )
|
||||
LDFLAGS+= $(shell pkg-config --libs libavutil )
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
@@ -48,8 +84,8 @@ all: objs_dir $(TARGET)
|
||||
objs_dir:
|
||||
mkdir -p $(OBJS_DIR)
|
||||
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB)
|
||||
$(CXX) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
$(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 $@
|
||||
|
||||
$(OBJS_DIR)/%.o: %.c
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@
|
||||
@@ -57,12 +93,15 @@ $(OBJS_DIR)/%.o: %.c
|
||||
$(OBJS_DIR)/%.o: %.cpp
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@ -I../src/gpacmp4
|
||||
|
||||
$(OBJS_DIR)/ccextractor.o: ccextractor.c
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) -O0 $< -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm $(TARGET) 2>/dev/null || true
|
||||
rm $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
|
||||
rm -rd $(OBJS_DIR) 2>/dev/null || true
|
||||
rm .depend 2>/dev/null || true
|
||||
rm -rf $(TARGET) 2>/dev/null || true
|
||||
rm -rf $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
|
||||
rm -rdf $(OBJS_DIR) 2>/dev/null || true
|
||||
rm -rf .depend 2>/dev/null || true
|
||||
|
||||
.PHONY: install
|
||||
install: $(TARGET)
|
||||
@@ -74,7 +113,7 @@ uninstall:
|
||||
|
||||
.PHONY: depend dep
|
||||
depend dep:
|
||||
$(CXX) $(CXXFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) \
|
||||
$(CC) $(CFLAGS) $(INCLUDE) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CCX) \
|
||||
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
|
||||
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend
|
||||
|
||||
|
||||
11
linux/build
11
linux/build
@@ -1,2 +1,11 @@
|
||||
#!/bin/bash
|
||||
gcc -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="-std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64"
|
||||
BLD_INCLUDE="-I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/"
|
||||
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
|
||||
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
|
||||
SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')"
|
||||
SRC_GPAC="$(find ../src/gpacmp4/ -name '*.c')"
|
||||
BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG"
|
||||
BLD_LINKER="-lm -zmuldefs"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
@@ -1,2 +1,11 @@
|
||||
#!/bin/bash
|
||||
gcc -g -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
|
||||
BLD_FLAGS="-g -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64"
|
||||
BLD_INCLUDE="-I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/"
|
||||
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
|
||||
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
|
||||
SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')"
|
||||
SRC_GPAC="$(find ../src/gpacmp4/ -name '*.c')"
|
||||
BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG"
|
||||
BLD_LINKER="-lm -zmuldefs"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
3
mac/build.command
Normal file → Executable file
3
mac/build.command
Normal file → Executable file
@@ -1 +1,2 @@
|
||||
g++ -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I../src/gpacmp4 -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c')
|
||||
gcc -std=gnu99 -Wno-write-strings -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
|
||||
|
||||
|
||||
151
src/608.h
151
src/608.h
@@ -1,151 +0,0 @@
|
||||
#ifndef __608_H__
|
||||
|
||||
enum cc_modes
|
||||
{
|
||||
MODE_POPON = 0,
|
||||
MODE_ROLLUP_2 = 1,
|
||||
MODE_ROLLUP_3 = 2,
|
||||
MODE_ROLLUP_4 = 3,
|
||||
MODE_TEXT = 4,
|
||||
MODE_PAINTON = 5,
|
||||
// Fake modes to emulate stuff
|
||||
MODE_FAKE_ROLLUP_1 = 100
|
||||
};
|
||||
|
||||
struct eia608_screen // A CC buffer
|
||||
{
|
||||
unsigned char characters[15][33];
|
||||
unsigned char colors[15][33];
|
||||
unsigned char fonts[15][33]; // Extra char at the end for a 0
|
||||
int row_used[15]; // Any data in row?
|
||||
int empty; // Buffer completely empty?
|
||||
};
|
||||
|
||||
struct s_context_cc608
|
||||
{
|
||||
struct eia608_screen buffer1;
|
||||
struct eia608_screen buffer2;
|
||||
int cursor_row, cursor_column;
|
||||
int visible_buffer;
|
||||
int srt_counter; // Number of subs currently written
|
||||
int screenfuls_counter; // Number of meaningful screenfuls written
|
||||
LLONG current_visible_start_ms; // At what time did the current visible buffer became so?
|
||||
// unsigned current_visible_start_cc; // At what time did the current visible buffer became so?
|
||||
enum cc_modes mode;
|
||||
unsigned char last_c1, last_c2;
|
||||
int channel; // Currently selected channel
|
||||
unsigned char color; // Color we are currently using to write
|
||||
unsigned char font; // Font we are currently using to write
|
||||
int rollup_base_row;
|
||||
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
|
||||
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
|
||||
int new_channel; // The new channel after a channel change
|
||||
int my_field; // Used for sanity checks
|
||||
long bytes_processed_608; // To be written ONLY by process_608
|
||||
struct ccx_s_write *out;
|
||||
int have_cursor_position;
|
||||
};
|
||||
|
||||
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];
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_srt(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
void capitalize (int line_num, struct eia608_screen *data);
|
||||
void correct_case (int line_num, struct eia608_screen *data);
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
|
||||
void correct_case (int line_num, struct eia608_screen *data);
|
||||
void capitalize (int line_num, struct eia608_screen *data);
|
||||
void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank);
|
||||
unsigned get_decoder_line_basic (unsigned char *buffer, 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);
|
||||
void delete_all_lines_but_current (struct eia608_screen *data, int row);
|
||||
void try_to_add_start_credits(struct s_context_cc608 *context);
|
||||
void try_to_add_end_credits(struct s_context_cc608 *context);
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context);
|
||||
|
||||
void handle_end_of_data(struct s_context_cc608 *context);
|
||||
void process608(const unsigned char *data, int length, struct s_context_cc608 *context);
|
||||
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c);
|
||||
void get_char_in_unicode (unsigned char *buffer, unsigned char c);
|
||||
int get_char_in_utf_8 (unsigned char *buffer, unsigned char c);
|
||||
unsigned char cctolower (unsigned char c);
|
||||
unsigned char cctoupper (unsigned char c);
|
||||
int general_608_init (void);
|
||||
LLONG get_visible_end (void);
|
||||
|
||||
#define CC608_SCREEN_WIDTH 32
|
||||
|
||||
#define REQUEST_BUFFER_CAPACITY(length) if (length>enc_buffer_capacity) \
|
||||
{enc_buffer_capacity=length*2; enc_buffer=(unsigned char*) realloc (enc_buffer, enc_buffer_capacity); \
|
||||
if (enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
|
||||
}
|
||||
|
||||
|
||||
enum color_code
|
||||
{
|
||||
COL_WHITE = 0,
|
||||
COL_GREEN = 1,
|
||||
COL_BLUE = 2,
|
||||
COL_CYAN = 3,
|
||||
COL_RED = 4,
|
||||
COL_YELLOW = 5,
|
||||
COL_MAGENTA = 6,
|
||||
COL_USERDEFINED = 7,
|
||||
COL_BLACK = 8,
|
||||
COL_TRANSPARENT = 9
|
||||
};
|
||||
|
||||
|
||||
enum font_bits
|
||||
{
|
||||
FONT_REGULAR = 0,
|
||||
FONT_ITALICS = 1,
|
||||
FONT_UNDERLINED = 2,
|
||||
FONT_UNDERLINED_ITALICS = 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum command_code
|
||||
{
|
||||
COM_UNKNOWN = 0,
|
||||
COM_ERASEDISPLAYEDMEMORY = 1,
|
||||
COM_RESUMECAPTIONLOADING = 2,
|
||||
COM_ENDOFCAPTION = 3,
|
||||
COM_TABOFFSET1 = 4,
|
||||
COM_TABOFFSET2 = 5,
|
||||
COM_TABOFFSET3 = 6,
|
||||
COM_ROLLUP2 = 7,
|
||||
COM_ROLLUP3 = 8,
|
||||
COM_ROLLUP4 = 9,
|
||||
COM_CARRIAGERETURN = 10,
|
||||
COM_ERASENONDISPLAYEDMEMORY = 11,
|
||||
COM_BACKSPACE = 12,
|
||||
COM_RESUMETEXTDISPLAY = 13,
|
||||
COM_ALARMOFF =14,
|
||||
COM_ALARMON = 15,
|
||||
COM_DELETETOENDOFROW = 16,
|
||||
COM_RESUMEDIRECTCAPTIONING = 17,
|
||||
// Non existing commands we insert to have the decoder
|
||||
// special stuff for us.
|
||||
COM_FAKE_RULLUP1 = 18
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define __608_H__
|
||||
#endif
|
||||
@@ -1,438 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
#include "utility.h"
|
||||
//extern unsigned char encoded_crlf[16];
|
||||
|
||||
// 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 bytes=0;
|
||||
while (*text)
|
||||
{
|
||||
switch (ccx_options.encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
case CCX_ENC_LATIN_1:
|
||||
*buffer=*text;
|
||||
bytes++;
|
||||
buffer++;
|
||||
break;
|
||||
case CCX_ENC_UNICODE:
|
||||
*buffer=*text;
|
||||
*(buffer+1)=0;
|
||||
bytes+=2;
|
||||
buffer+=2;
|
||||
break;
|
||||
}
|
||||
text++;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void correct_case(int line_num,struct eia608_screen *data)
|
||||
{
|
||||
char delim[64] = {
|
||||
' ' ,'\n','\r', 0x89,0x99,
|
||||
'!' , '"', '#', '%' , '&',
|
||||
'\'', '(', ')', ';' , '<',
|
||||
'=' , '>', '?', '[' ,'\\',
|
||||
']' , '*', '+', ',' , '-',
|
||||
'.' , '/', ':', '^' , '_',
|
||||
'{' , '|', '}', '~' ,'\0' };
|
||||
|
||||
char *line = strdup(((char*)data->characters[line_num]));
|
||||
char *oline = (char*)data->characters[line_num];
|
||||
char *c = strtok(line,delim);
|
||||
do
|
||||
{
|
||||
char **index = bsearch(&c,spell_lower,spell_words,sizeof(*spell_lower),string_cmp);
|
||||
|
||||
if(index)
|
||||
{
|
||||
char *correct_c = *(spell_correct + (index - spell_lower));
|
||||
size_t len=strlen (correct_c);
|
||||
memcpy(oline + (c - line),correct_c,len);
|
||||
}
|
||||
} while ( ( c = strtok(NULL,delim) ) != NULL );
|
||||
free(line);
|
||||
}
|
||||
|
||||
void capitalize (int line_num, struct eia608_screen *data)
|
||||
{
|
||||
for (int i=0;i<CC608_SCREEN_WIDTH;i++)
|
||||
{
|
||||
switch (data->characters[line_num][i])
|
||||
{
|
||||
case ' ':
|
||||
case 0x89: // This is a transparent space
|
||||
case '-':
|
||||
break;
|
||||
case '.': // Fallthrough
|
||||
case '?': // Fallthrough
|
||||
case '!':
|
||||
case ':':
|
||||
new_sentence=1;
|
||||
break;
|
||||
default:
|
||||
if (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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<CC608_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)
|
||||
{
|
||||
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 (!ccx_options.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 (ccx_options.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
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
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);
|
||||
for (int i=first;i<=last;i++)
|
||||
{
|
||||
get_char_in_latin_1 (buffer,line[i]);
|
||||
buffer++;
|
||||
}
|
||||
*buffer=0;
|
||||
return (unsigned) (buffer-orig); // Return length
|
||||
|
||||
}
|
||||
|
||||
unsigned char *close_tag (unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
|
||||
{
|
||||
for (int l=strlen (tagstack)-1; l>=0;l--)
|
||||
{
|
||||
char cur=tagstack[l];
|
||||
switch (cur)
|
||||
{
|
||||
case 'F':
|
||||
buffer+= encode_line (buffer,(unsigned char *) "</font>");
|
||||
(*pchanged_font)--;
|
||||
break;
|
||||
case 'U':
|
||||
buffer+=encode_line (buffer, (unsigned char *) "</u>");
|
||||
(*punderlined)--;
|
||||
break;
|
||||
case 'I':
|
||||
buffer+=encode_line (buffer, (unsigned char *) "</i>");
|
||||
(*pitalics)--;
|
||||
break;
|
||||
}
|
||||
tagstack[l]=0; // Remove from stack
|
||||
if (cur==tagtype) // We closed up to the required tag, done
|
||||
return buffer;
|
||||
}
|
||||
if (tagtype!='A') // All
|
||||
fatal (EXIT_BUG_BUG, "Mismatched tags in encoding, this is a bug, please report");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
int col = COL_WHITE;
|
||||
int underlined = 0;
|
||||
int italics = 0;
|
||||
int changed_font=0;
|
||||
char tagstack[128]=""; // Keep track of opening/closing tags
|
||||
|
||||
unsigned char *line = data->characters[line_num];
|
||||
unsigned char *orig=buffer; // Keep for debugging
|
||||
int first=0, last=31;
|
||||
if (ccx_options.trim_subs)
|
||||
find_limit_characters(line,&first,&last);
|
||||
for (int i=first;i<=last;i++)
|
||||
{
|
||||
// Handle color
|
||||
int its_col = data->colors[line_num][i];
|
||||
if (its_col != col && !ccx_options.nofontcolor &&
|
||||
!(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);
|
||||
// Add new font tag
|
||||
buffer+=encode_line (buffer, (unsigned char*) color_text[its_col][1]);
|
||||
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*) "\">");
|
||||
}
|
||||
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
|
||||
{
|
||||
strcat (tagstack,"F");
|
||||
changed_font++;
|
||||
}
|
||||
col = its_col;
|
||||
}
|
||||
// Handle underlined
|
||||
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
|
||||
if (is_underlined && underlined==0 && !ccx_options.notypesetting) // Open underline
|
||||
{
|
||||
buffer+=encode_line (buffer, (unsigned char *) "<u>");
|
||||
strcat (tagstack,"U");
|
||||
underlined++;
|
||||
}
|
||||
if (is_underlined==0 && underlined && !ccx_options.notypesetting) // Close underline
|
||||
{
|
||||
buffer = close_tag(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_options.notypesetting) // Open italics
|
||||
{
|
||||
buffer+=encode_line (buffer, (unsigned char *) "<i>");
|
||||
strcat (tagstack,"I");
|
||||
italics++;
|
||||
}
|
||||
if (has_ita==0 && italics && !ccx_options.notypesetting) // Close italics
|
||||
{
|
||||
buffer = close_tag(buffer,tagstack,'I',&underlined,&italics,&changed_font);
|
||||
}
|
||||
int bytes=0;
|
||||
switch (ccx_options.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;
|
||||
break;
|
||||
}
|
||||
buffer+=bytes;
|
||||
}
|
||||
buffer = close_tag(buffer,tagstack,'A',&underlined,&italics,&changed_font);
|
||||
if (underlined || italics || changed_font)
|
||||
fatal (EXIT_BUG_BUG, "Not all tags closed in encoding, this is a bug, please report.\n");
|
||||
*buffer=0;
|
||||
return (unsigned) (buffer-orig); // Return length
|
||||
}
|
||||
|
||||
|
||||
void delete_all_lines_but_current (struct eia608_screen *data, int row)
|
||||
{
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (i!=row)
|
||||
{
|
||||
memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
|
||||
data->characters[i][CC608_SCREEN_WIDTH]=0;
|
||||
memset (data->colors[i],ccx_options.cc608_default_color,CC608_SCREEN_WIDTH+1);
|
||||
memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1);
|
||||
data->row_used[i]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fprintf_encoded (FILE *fh, const char *string)
|
||||
{
|
||||
REQUEST_BUFFER_CAPACITY(strlen (string)*3);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) string);
|
||||
fwrite (enc_buffer,enc_buffer_used,1,fh);
|
||||
}
|
||||
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start;
|
||||
int with_data=0;
|
||||
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
with_data=1;
|
||||
}
|
||||
if (!with_data)
|
||||
return;
|
||||
|
||||
ms_start= context->current_visible_start_ms;
|
||||
|
||||
ms_start+=subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return;
|
||||
int time_reported=0;
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
fprintf (stderr, "###SUBTITLE#");
|
||||
if (!time_reported)
|
||||
{
|
||||
LLONG ms_end = get_fts()+subs_delay;
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
// Note, only MM:SS here as we need to save space in the preview window
|
||||
fprintf (stderr, "%02u:%02u#%02u:%02u#",
|
||||
h1*60+m1,s1, h2*60+m2,s2);
|
||||
time_reported=1;
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "##");
|
||||
|
||||
// We don't capitalize here because whatever function that was used
|
||||
// before to write to file already took care of it.
|
||||
int length = get_decoder_line_encoded_for_gui (subline, i, data);
|
||||
fwrite (subline, 1, length, stderr);
|
||||
fwrite ("\n",1,1,stderr);
|
||||
}
|
||||
}
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
void try_to_add_end_credits(struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG window, length, st, end;
|
||||
if (context->out->fh == -1)
|
||||
return;
|
||||
window=get_fts()-last_displayed_subs_ms-1;
|
||||
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
|
||||
return;
|
||||
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.endcreditsforatmost.time_in_ms;
|
||||
|
||||
st=get_fts()-length-1;
|
||||
end=get_fts();
|
||||
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.end_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.end_credits_text, context, st, end);
|
||||
break ;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void try_to_add_start_credits(struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG st, end, window, length;
|
||||
LLONG l = context->current_visible_start_ms + subs_delay;
|
||||
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
|
||||
|
||||
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
|
||||
return;
|
||||
|
||||
if (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
|
||||
return;
|
||||
|
||||
st = ccx_options.startcreditsnotbefore.time_in_ms>(last_displayed_subs_ms+1) ?
|
||||
ccx_options.startcreditsnotbefore.time_in_ms : (last_displayed_subs_ms+1); // When would credits actually start
|
||||
|
||||
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
|
||||
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
|
||||
|
||||
window = end-st; // Allowable time in MS
|
||||
|
||||
if (ccx_options.startcreditsforatleast.time_in_ms>window) // Window is too short
|
||||
return;
|
||||
|
||||
length=ccx_options.startcreditsforatmost.time_in_ms > window ?
|
||||
window : ccx_options.startcreditsforatmost.time_in_ms;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
|
||||
last_displayed_subs_ms, l);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
|
||||
ccx_options.startcreditsnotbefore.time_in_ms,
|
||||
ccx_options.startcreditsnotafter.time_in_ms);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Start of window: %lld End of window: %lld\n",st,end);
|
||||
|
||||
if (window>length+2)
|
||||
{
|
||||
// Center in time window
|
||||
LLONG pad=window-length;
|
||||
st+=(pad/2);
|
||||
}
|
||||
end=st+length;
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
write_stringz_as_srt(ccx_options.start_credits_text,context,st,end);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
write_stringz_as_sami(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
write_stringz_as_smptett(ccx_options.start_credits_text, context, st, end);
|
||||
break;
|
||||
default:
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
startcredits_displayed=1;
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
129
src/608_sami.c
129
src/608_sami.c
@@ -1,129 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)ms_start);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_br, encoded_br_length);
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)ms_end);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG startms, endms;
|
||||
int wrote_something=0;
|
||||
startms = context->current_visible_start_ms;
|
||||
|
||||
startms+=subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = get_visible_end()+subs_delay;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)startms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write (context->out->fh, subline, length);
|
||||
wrote_something=1;
|
||||
if (i!=14)
|
||||
write (context->out->fh, encoded_br, encoded_br_length);
|
||||
write (context->out->fh,encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)endms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
// Produces minimally-compliant SMPTE Timed Text (W3C TTML)
|
||||
// format-compatible output
|
||||
|
||||
// See http://www.w3.org/TR/ttaf1-dfxp/ and
|
||||
// https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
|
||||
|
||||
// Copyright (C) 2012 John Kemp
|
||||
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2);
|
||||
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
//write (wb->fh, encoded_br, encoded_br_length);
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\">\n\n",h2,m2,s2,ms2);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG endms;
|
||||
int wrote_something=0;
|
||||
LLONG startms = context->current_visible_start_ms;
|
||||
|
||||
startms+=subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = get_visible_end()+subs_delay;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
mstotime (startms,&h1,&m1,&s1,&ms1);
|
||||
mstotime (endms-1,&h2,&m2,&s2,&ms2);
|
||||
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
wrote_something=1;
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r%s\n", str);
|
||||
}
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
|
||||
//write (wb->fh, enc_buffer,enc_buffer_used);
|
||||
|
||||
return wrote_something;
|
||||
}
|
||||
279
src/608_spupng.c
279
src/608_spupng.c
@@ -1,279 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include "608_spupng.h"
|
||||
|
||||
void
|
||||
draw_row(struct eia608_screen* data, int row, uint8_t * canvas, int rowstride)
|
||||
{
|
||||
int column;
|
||||
int unicode = 0;
|
||||
uint8_t pen[2];
|
||||
uint8_t* cell;
|
||||
int first = -1;
|
||||
int last = 0;
|
||||
|
||||
pen[0] = COL_BLACK;
|
||||
|
||||
for (column = 0; column < COLUMNS ; column++) {
|
||||
|
||||
if (COL_TRANSPARENT != data->colors[row][column])
|
||||
{
|
||||
cell = canvas + ((column+1) * CCW);
|
||||
get_char_in_unicode((unsigned char*)&unicode, data->characters[row][column]);
|
||||
pen[1] = data->colors[row][column];
|
||||
|
||||
int attr = data->fonts[row][column];
|
||||
draw_char_indexed(cell, rowstride, pen, unicode, (attr & FONT_ITALICS) != 0, (attr & FONT_UNDERLINED) != 0);
|
||||
if (first < 0)
|
||||
{
|
||||
// draw a printable space before the first non-space char
|
||||
first = column;
|
||||
if (unicode != 0x20)
|
||||
{
|
||||
cell = canvas + ((first) * CCW);
|
||||
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
|
||||
}
|
||||
}
|
||||
last = column;
|
||||
}
|
||||
}
|
||||
// draw a printable space after the last non-space char
|
||||
// unicode should still contain the last character
|
||||
// check whether it is a space
|
||||
if (unicode != 0x20)
|
||||
{
|
||||
cell = canvas + ((last+2) * CCW);
|
||||
draw_char_indexed(cell, rowstride, pen, 0x20, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static png_color palette[10] =
|
||||
{
|
||||
{ 0xff, 0xff, 0xff }, // COL_WHITE = 0,
|
||||
{ 0x00, 0xff, 0x00 }, // COL_GREEN = 1,
|
||||
{ 0x00, 0x00, 0xff }, // COL_BLUE = 2,
|
||||
{ 0x00, 0xff, 0xff }, // COL_CYAN = 3,
|
||||
{ 0xff, 0x00, 0x00 }, // COL_RED = 4,
|
||||
{ 0xff, 0xff, 0x00 }, // COL_YELLOW = 5,
|
||||
{ 0xff, 0x00, 0xff }, // COL_MAGENTA = 6,
|
||||
{ 0xff, 0xff, 0xff }, // COL_USERDEFINED = 7,
|
||||
{ 0x00, 0x00, 0x00 }, // COL_BLACK = 8
|
||||
{ 0x00, 0x00, 0x00 } // COL_TRANSPARENT = 9
|
||||
};
|
||||
|
||||
static png_byte alpha[10] =
|
||||
{
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
0
|
||||
};
|
||||
|
||||
int
|
||||
spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
|
||||
png_structp png_ptr, png_infop info_ptr,
|
||||
png_bytep image,
|
||||
png_bytep* row_pointer,
|
||||
unsigned int ww, unsigned int wh)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
return 0;
|
||||
|
||||
png_init_io (png_ptr, sp->fppng);
|
||||
|
||||
png_set_IHDR (png_ptr,
|
||||
info_ptr,
|
||||
ww,
|
||||
wh,
|
||||
/* bit_depth */ 8,
|
||||
PNG_COLOR_TYPE_PALETTE,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_set_PLTE (png_ptr, info_ptr, palette, sizeof(palette) / sizeof(palette[0]));
|
||||
png_set_tRNS (png_ptr, info_ptr, alpha, sizeof(alpha) / sizeof(alpha[0]), NULL);
|
||||
|
||||
png_set_gAMA (png_ptr, info_ptr, 1.0 / 2.2);
|
||||
|
||||
png_write_info (png_ptr, info_ptr);
|
||||
|
||||
for (i = 0; i < wh; i++)
|
||||
row_pointer[i] = image + i * ww;
|
||||
|
||||
png_write_image (png_ptr, row_pointer);
|
||||
|
||||
png_write_end (png_ptr, info_ptr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytep *row_pointer;
|
||||
png_bytep image;
|
||||
int ww, wh, rowstride, row_adv;
|
||||
int row;
|
||||
|
||||
assert ((sizeof(png_byte) == sizeof(uint8_t))
|
||||
&& (sizeof(*image) == sizeof(uint8_t)));
|
||||
|
||||
// Allow space at beginning and end of each row for a padding space
|
||||
ww = CCW * (COLUMNS+2);
|
||||
wh = CCH * ROWS;
|
||||
row_adv = (COLUMNS+2) * CCW * CCH;
|
||||
|
||||
rowstride = ww * sizeof(*image);
|
||||
|
||||
if (!(row_pointer = (png_bytep*)malloc(sizeof(*row_pointer) * wh))) {
|
||||
mprint("Unable to allocate %d byte buffer.\n",
|
||||
sizeof(*row_pointer) * wh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(image = (png_bytep)malloc(wh * ww * sizeof(*image)))) {
|
||||
mprint("Unable to allocate %d KB image buffer.",
|
||||
wh * ww * sizeof(*image) / 1024);
|
||||
free(row_pointer);
|
||||
return 0;
|
||||
}
|
||||
// Initialize image to transparent
|
||||
memset(image, COL_TRANSPARENT, wh * ww * sizeof(*image));
|
||||
|
||||
/* draw the image */
|
||||
|
||||
for (row = 0; row < ROWS; row++) {
|
||||
if (data->row_used[row])
|
||||
draw_row(data, row, image + row * row_adv, rowstride);
|
||||
}
|
||||
|
||||
/* Now save the image */
|
||||
|
||||
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, NULL, NULL)))
|
||||
goto unknown_error;
|
||||
|
||||
if (!(info_ptr = png_create_info_struct(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
||||
goto unknown_error;
|
||||
}
|
||||
|
||||
if (!spupng_write_png (sp, data, png_ptr, info_ptr, image, row_pointer, ww, wh)) {
|
||||
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||
|
||||
free (row_pointer);
|
||||
|
||||
free (image);
|
||||
|
||||
return 1;
|
||||
|
||||
write_error:
|
||||
|
||||
unknown_error:
|
||||
free (row_pointer);
|
||||
|
||||
free (image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
struct s_context_cc608 *context)
|
||||
{
|
||||
LLONG ms_start = context->current_visible_start_ms + subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int row;
|
||||
int empty_buf = 1;
|
||||
char str[256] = "";
|
||||
for (row = 0; row < 15; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
empty_buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Blank page\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLONG ms_end = get_visible_end() + subs_delay;
|
||||
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
|
||||
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
if (!spupng_export_png(sp, data))
|
||||
{
|
||||
fatal(EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
fclose(sp->fppng);
|
||||
write_sputag(sp,ms_start,ms_end);
|
||||
for (row = 0; row < ROWS; row++)
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
int len = get_decoder_line_encoded(subline, row, data);
|
||||
// Check for characters that spumux won't parse
|
||||
// null chars will be changed to space
|
||||
// pairs of dashes will be changed to underscores
|
||||
for (unsigned char* ptr = subline; ptr < subline+len; ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case 0:
|
||||
*ptr = ' ';
|
||||
break;
|
||||
case '-':
|
||||
if (*(ptr+1) == '-')
|
||||
{
|
||||
*ptr++ = '_';
|
||||
*ptr = '_';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
strncat(str,(const char*)subline,256);
|
||||
strncat(str,"\n",256);
|
||||
}
|
||||
}
|
||||
|
||||
write_spucomment(sp,str);
|
||||
return 1;
|
||||
}
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context)
|
||||
{
|
||||
if (0 != context->out->spupng_data)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
|
||||
return spupng_write_ccbuffer(sp, data, context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
195
src/608_srt.c
195
src/608_srt.c
@@ -1,195 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
|
||||
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
|
||||
if there is any */
|
||||
void write_stringz_as_srt (char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
dbg_print(CCX_DMT_608, "\n- - - SRT caption - - -\n");
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_srt() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
free(el);
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
int wrote_something = 0;
|
||||
ms_start = context->current_visible_start_ms;
|
||||
|
||||
int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
|
||||
int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
|
||||
int empty_buf=1;
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
empty_buf=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
|
||||
return 0;
|
||||
|
||||
ms_start+=subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
ms_end=get_visible_end()+subs_delay;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, enc_buffer, enc_buffer_used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
|
||||
|
||||
dbg_print(CCX_DMT_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
|
||||
dbg_print(CCX_DMT_608, "%s",timeline);
|
||||
|
||||
write (context->out->fh, enc_buffer,enc_buffer_used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
if (ccx_options.sentence_cap)
|
||||
{
|
||||
capitalize (i,data);
|
||||
correct_case(i,data);
|
||||
}
|
||||
if (ccx_options.autodash && ccx_options.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);
|
||||
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<CC608_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)
|
||||
write(context->out->fh, "- ", 2);
|
||||
prev_line_start=first;
|
||||
prev_line_end=last;
|
||||
prev_line_center1=center1;
|
||||
prev_line_center2=center2;
|
||||
|
||||
}
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_608, "\r");
|
||||
dbg_print(CCX_DMT_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
wrote_something=1;
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
}
|
||||
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
return wrote_something;
|
||||
}
|
||||
292
src/708.h
292
src/708.h
@@ -1,292 +0,0 @@
|
||||
#ifndef _INCLUDE_708_
|
||||
#define _INCLUDE_708_
|
||||
#define MAX_708_PACKET_LENGTH 128
|
||||
|
||||
#define I708_MAX_ROWS 15
|
||||
#define I708_MAX_COLUMNS 42
|
||||
|
||||
#define I708_SCREENGRID_ROWS 75
|
||||
#define I708_SCREENGRID_COLUMNS 210
|
||||
|
||||
#define I708_MAX_WINDOWS 8
|
||||
|
||||
enum COMMANDS_C0_CODES
|
||||
{
|
||||
NUL=0,
|
||||
ETX=3,
|
||||
BS=8,
|
||||
FF=0xC,
|
||||
CR=0xD,
|
||||
HCR=0xE,
|
||||
EXT1=0x10,
|
||||
P16=0x18
|
||||
};
|
||||
|
||||
enum 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
|
||||
};
|
||||
|
||||
struct S_COMMANDS_C1
|
||||
{
|
||||
int code;
|
||||
const char *name;
|
||||
const char *description;
|
||||
int length;
|
||||
};
|
||||
|
||||
|
||||
enum eWindowsAttribJustify
|
||||
{
|
||||
left=0,
|
||||
right=1,
|
||||
center=2,
|
||||
full=3
|
||||
};
|
||||
|
||||
enum eWindowsAttribPrintDirection
|
||||
{
|
||||
pd_left_to_right=0,
|
||||
pd_right_to_left=1,
|
||||
pd_top_to_bottom=2,
|
||||
pd_bottom_to_top=3
|
||||
};
|
||||
|
||||
enum eWindowsAttribScrollDirection
|
||||
{
|
||||
sd_left_to_right=0,
|
||||
sd_right_to_left=1,
|
||||
sd_top_to_bottom=2,
|
||||
sd_bottom_to_top=3
|
||||
};
|
||||
|
||||
enum eWindowsAttribScrollDisplayEffect
|
||||
{
|
||||
snap=0,
|
||||
fade=1,
|
||||
wipe=2
|
||||
};
|
||||
|
||||
enum eWindowsAttribEffectDirection
|
||||
{
|
||||
left_to_right=0,
|
||||
right_to_left=1,
|
||||
top_to_bottom=2,
|
||||
bottom_to_top=3
|
||||
};
|
||||
|
||||
enum eWindowsAttribFillOpacity
|
||||
{
|
||||
solid=0,
|
||||
flash=1,
|
||||
traslucent=2,
|
||||
transparent=3
|
||||
};
|
||||
|
||||
enum eWindowsAttribBorderType
|
||||
{
|
||||
none=0,
|
||||
raised=1,
|
||||
depressed=2,
|
||||
uniform=3,
|
||||
shadow_left=4,
|
||||
shadow_right=5
|
||||
};
|
||||
|
||||
enum ePenAttribSize
|
||||
{
|
||||
pensize_small=0,
|
||||
pensize_standard=1,
|
||||
pensize_large=2
|
||||
};
|
||||
|
||||
enum ePenAttribFontStyle
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
enum ePanAttribTextTag
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
enum ePanAttribOffset
|
||||
{
|
||||
offset_subscript=0,
|
||||
offset_normal=1,
|
||||
offset_superscript=2
|
||||
};
|
||||
|
||||
enum ePanAttribEdgeType
|
||||
{
|
||||
edgetype_none=0,
|
||||
edgetype_raised=1,
|
||||
edgetype_depressed=2,
|
||||
edgetype_uniform=3,
|
||||
edgetype_left_drop_shadow=4,
|
||||
edgetype_right_drop_shadow=5
|
||||
};
|
||||
|
||||
enum eAnchorPoints
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
typedef struct e708Pen_color
|
||||
{
|
||||
int fg_color;
|
||||
int fg_opacity;
|
||||
int bg_color;
|
||||
int bg_opacity;
|
||||
int edge_color;
|
||||
} e708Pen_color;
|
||||
|
||||
typedef struct e708Pen_attribs
|
||||
{
|
||||
int pen_size;
|
||||
int offset;
|
||||
int text_tag;
|
||||
int font_tag;
|
||||
int edge_type;
|
||||
int underline;
|
||||
int italic;
|
||||
} e708Pen_attribs;
|
||||
|
||||
typedef struct e708Window_attribs
|
||||
{
|
||||
int fill_color;
|
||||
int fill_opacity;
|
||||
int border_color;
|
||||
int border_type01;
|
||||
int justify;
|
||||
int scroll_dir;
|
||||
int print_dir;
|
||||
int word_wrap;
|
||||
int border_type;
|
||||
int display_eff;
|
||||
int effect_dir;
|
||||
int effect_speed;
|
||||
} e708Window_attribs;
|
||||
|
||||
typedef struct e708Window
|
||||
{
|
||||
int is_defined;
|
||||
int number; // Handy, in case we only have a pointer to the window
|
||||
int priority;
|
||||
int col_lock;
|
||||
int row_lock;
|
||||
int visible;
|
||||
int anchor_vertical;
|
||||
int relative_pos;
|
||||
int anchor_horizontal;
|
||||
int row_count;
|
||||
int anchor_point;
|
||||
int col_count;
|
||||
int pen_style;
|
||||
int win_style;
|
||||
unsigned char commands[6]; // Commands used to create this window
|
||||
e708Window_attribs attribs;
|
||||
e708Pen_attribs pen;
|
||||
e708Pen_color pen_color;
|
||||
int pen_row;
|
||||
int pen_column;
|
||||
unsigned char *rows[I708_MAX_ROWS+1]; // Max is 15, but we define an extra one for convenience
|
||||
int memory_reserved;
|
||||
int is_empty;
|
||||
} e708Window;
|
||||
|
||||
typedef struct tvscreen
|
||||
{
|
||||
unsigned char chars[I708_SCREENGRID_ROWS][I708_SCREENGRID_COLUMNS+1];
|
||||
}
|
||||
tvscreen;
|
||||
|
||||
typedef struct cc708_service_decoder
|
||||
{
|
||||
e708Window windows[I708_MAX_WINDOWS];
|
||||
int current_window;
|
||||
int inited;
|
||||
LLONG current_visible_start_ms;
|
||||
tvscreen tv1, tv2; // Current and previous "screenfuls", note that we switch between them
|
||||
int is_empty_tv1, is_empty_tv2;
|
||||
int cur_tv; // 1 or 2 rather than 0 or 1, to at least be consistent with the decoder
|
||||
tvscreen *tv; // Pointer to the current TV buffer
|
||||
char *filename; // Where we are going to write our output
|
||||
int fh; // Handle to output file. -1 if not yet open
|
||||
int srt_counter;
|
||||
}
|
||||
cc708_service_decoder;
|
||||
|
||||
extern int resets_708;
|
||||
|
||||
void do_708 (const unsigned char *data, int datalength);
|
||||
void init_708(void);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
/********************************************************
|
||||
256 BYTES IS ENOUGH FOR ALL THE SUPPORTED CHARACTERS IN
|
||||
EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
|
||||
|
||||
00-1F -> Characters that are in the G2 group in 20-3F,
|
||||
except for 06, which is used for the closed captions
|
||||
sign "CC" which is defined in group G3 as 00. (this
|
||||
is by the article 33).
|
||||
20-7F -> Group G0 as is - corresponds to the ASCII code
|
||||
80-9F -> Characters that are in the G2 group in 60-7F
|
||||
(there are several blank characters here, that's OK)
|
||||
A0-FF -> Group G1 as is - non-English characters and symbols
|
||||
*/
|
||||
|
||||
unsigned char get_internal_from_G0 (unsigned char g0_char)
|
||||
{
|
||||
return g0_char;
|
||||
}
|
||||
|
||||
unsigned char 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)
|
||||
{
|
||||
if (g2_char>=0x20 && g2_char<=0x3F)
|
||||
return g2_char-0x20;
|
||||
if (g2_char>=0x60 && g2_char<=0x7F)
|
||||
return g2_char+0x20;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
// TODO: Probably not right
|
||||
// G3: Future Characters and Icon Expansion
|
||||
unsigned char get_internal_from_G3 (unsigned char g3_char)
|
||||
{
|
||||
if (g3_char==0xa0) // The "CC" (closed captions) sign
|
||||
return 0x06;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
}
|
||||
6
src/CCExtractorConfig.h.in
Normal file
6
src/CCExtractorConfig.h.in
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* the configured options and settings for CCExtractor
|
||||
*/
|
||||
|
||||
#define CCExtractor_VERSION_MAJOR @CCEXTRACTOR_VERSION_MAJOR@
|
||||
#define CCExtractor_VERSION_MINOR @CCEXTRACTOR_VERSION_MINOR@
|
||||
88
src/CMakeLists.txt
Normal file
88
src/CMakeLists.txt
Normal file
@@ -0,0 +1,88 @@
|
||||
cmake_minimum_required (VERSION 3.0.2)
|
||||
|
||||
project (CCExtractor)
|
||||
|
||||
option (WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF)
|
||||
option (WITH_OCR "Build with OCR (Optical Character Recognition) feature" OFF)
|
||||
|
||||
#Version number
|
||||
set (CCEXTRACTOR_VERSION_MAJOR 0)
|
||||
set (CCEXTRACTOR_VERSION_MINOR 77)
|
||||
|
||||
# configure a header file to pass some of the CMake settings
|
||||
# to the source code
|
||||
configure_file (
|
||||
"${PROJECT_SOURCE_DIR}/CCExtractorConfig.h.in"
|
||||
"${PROJECT_BINARY_DIR}/CCExtractorConfig.h"
|
||||
)
|
||||
|
||||
|
||||
include_directories ("${PROJECT_SOURCE_DIR}")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/lib_ccx")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/gpacmp4/")
|
||||
|
||||
#Adding some platform specific library path
|
||||
link_directories (/opt/local/lib)
|
||||
link_directories (/usr/local/lib)
|
||||
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g -std=gnu99 -Wno-write-strings -D_FILE_OFFSET_BITS=64")
|
||||
add_subdirectory (lib_ccx)
|
||||
|
||||
aux_source_directory (${PROJECT_SOURCE_DIR} SOURCEFILE)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ccx)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} m)
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} iconv)
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
find_package (PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PNG libpng )
|
||||
if(PNG_FOUND)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} png)
|
||||
else (PNG_FOUND)
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/libpng/")
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/zlib/" SOURCEFILE)
|
||||
endif(PNG_FOUND)
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
|
||||
########################################################
|
||||
# Build using FFmpeg libraries
|
||||
########################################################
|
||||
|
||||
if (PKG_CONFIG_FOUND AND WITH_FFMPEG)
|
||||
|
||||
pkg_check_modules (AVFORMAT REQUIRED libavformat)
|
||||
pkg_check_modules (AVUTIL REQUIRED libavutil)
|
||||
pkg_check_modules (AVCODEC REQUIRED libavcodec)
|
||||
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVFORMAT_STATIC_LIBRARIES})
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVUTIL_STATIC_LIBRARIES})
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVCODEC_STATIC_LIBRARIES})
|
||||
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
|
||||
endif (PKG_CONFIG_FOUND AND WITH_FFMPEG)
|
||||
|
||||
########################################################
|
||||
# Build with OCR using leptonica and tesseract libraries
|
||||
########################################################
|
||||
|
||||
if (WITH_OCR)
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules (TESSERACT REQUIRED tesseract)
|
||||
pkg_check_modules (LEPTONICA REQUIRED lept)
|
||||
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${TESSERACT_STATIC_LIBRARIES})
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${LEPTONICA_STATIC_LIBRARIES})
|
||||
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR ${TESSERACT_CFLAGS} ${LEPTONICA_CFLAGS}")
|
||||
endif (WITH_OCR)
|
||||
|
||||
add_executable (ccextractor ${SOURCEFILE})
|
||||
target_link_libraries (ccextractor ${EXTRA_LIBS})
|
||||
|
||||
install (TARGETS ccextractor DESTINATION bin)
|
||||
147
src/activity.c
147
src/activity.c
@@ -1,147 +0,0 @@
|
||||
/* This file contains functions that report the user of the GUI of
|
||||
relevant events. */
|
||||
|
||||
#include "ccextractor.h"
|
||||
|
||||
static int credits_shown=0;
|
||||
unsigned long net_activity_gui=0;
|
||||
|
||||
/* Print current progress. For percentaje, -1 -> streaming mode */
|
||||
void activity_progress (int percentaje, int cur_min, int cur_sec)
|
||||
{
|
||||
if (!ccx_options.no_progress_bar)
|
||||
{
|
||||
if (percentaje==-1)
|
||||
mprint ("\rStreaming | %02d:%02d", cur_min, cur_sec);
|
||||
else
|
||||
mprint ("\r%3d%% | %02d:%02d",percentaje, cur_min, cur_sec);
|
||||
}
|
||||
fflush (stdout);
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###PROGRESS#%d#%d#%d\n", percentaje, cur_min, cur_sec);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_input_file_open (const char *filename)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_xds_program_identification_number (unsigned minutes, unsigned hours, unsigned date, unsigned month)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", minutes,hours,date,month);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_xds_network_call_letters (const char *program_name)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###XDSNETWORKCALLLETTERS#%s\n", program_name);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_xds_program_name (const char *program_name)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###XDSPROGRAMNAME#%s\n", program_name);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_xds_program_description (int line_num, const char *program_desc)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###XDSPROGRAMDESC#%d#%s\n", line_num, program_desc);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
|
||||
hor_size,vert_size, aspect_ratio, framerate);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void activity_message (const char *fmt, ...)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
va_list args;
|
||||
fprintf (stderr, "###MESSAGE#");
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_input_file_closed (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILECLOSED\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_program_number (unsigned program_number)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n",program_number);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_report_version (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###VERSION#CCExtractor#%s\n",VERSION);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_report_data_read (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###DATAREAD#%lu\n",net_activity_gui/1000);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void activity_header (void)
|
||||
{
|
||||
if (!credits_shown)
|
||||
{
|
||||
credits_shown=1;
|
||||
mprint ("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION);
|
||||
mprint ("Teletext portions taken from Petr Kutalek's telxcc\n");
|
||||
mprint ("--------------------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
1041
src/asf_functions.c
1041
src/asf_functions.c
File diff suppressed because it is too large
Load Diff
1052
src/avc_functions.c
1052
src/avc_functions.c
File diff suppressed because it is too large
Load Diff
@@ -1,375 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
// Hold functions to read streams on a bit or byte oriented basis
|
||||
// plus some data related helper functions.
|
||||
|
||||
|
||||
// Guidelines for all bitsream functions:
|
||||
// * No function shall advance the pointer past the end marker
|
||||
// * If bitstream.bitsleft < 0 do not attempt any read access,
|
||||
// but decrease bitsleft by the number of bits that were
|
||||
// attempted to read.
|
||||
|
||||
// Initialize bitstream
|
||||
int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *end)
|
||||
{
|
||||
bstr->pos = start;
|
||||
bstr->bpos = 8;
|
||||
bstr->end = end;
|
||||
bstr->bitsleft = (bstr->end - bstr->pos)*8;
|
||||
bstr->error = 0;
|
||||
bstr->_i_pos = NULL;
|
||||
bstr->_i_bpos = 0;
|
||||
|
||||
if(bstr->bitsleft < 0)
|
||||
{
|
||||
// See if we can somehow recover of this disaster by reporting the problem instead of terminating.
|
||||
mprint ( "init_bitstream: bitstream has negative length!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Read bnum bits from bitstream bstr with the most significant
|
||||
// bit read first without advancing the bitstream pointer.
|
||||
// A 64 bit unsigned integer is returned. 0 is returned when
|
||||
// there are not enough bits left in the bitstream.
|
||||
uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
|
||||
if(bnum > 64)
|
||||
fatal(EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
|
||||
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bitstream.bitsleft, but correct it.
|
||||
if (bstr->bitsleft <= 0)
|
||||
{
|
||||
bstr->bitsleft -= bnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the remaining number of bits in bitstream after reading.
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
|
||||
if (bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 0;
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
unsigned char *vpos = bstr->pos;
|
||||
|
||||
if(vbit < 1 || vbit > 8)
|
||||
{
|
||||
fatal(EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if(vpos >= bstr->end)
|
||||
{
|
||||
// We should not get here ...
|
||||
fatal(EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
|
||||
}
|
||||
|
||||
res |= (*vpos & (0x01 << (vbit-1)) ? 1 : 0);
|
||||
vbit--;
|
||||
bnum--;
|
||||
|
||||
if(vbit == 0)
|
||||
{
|
||||
vpos++;
|
||||
vbit = 8;
|
||||
}
|
||||
|
||||
if(bnum)
|
||||
{
|
||||
res <<= 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember the bitstream position
|
||||
bstr->_i_bpos = vbit;
|
||||
bstr->_i_pos = vpos;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read bnum bits from bitstream bstr with the most significant
|
||||
// bit read first. A 64 bit unsigned integer is returned.
|
||||
uint64_t read_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = next_bits(bstr, bnum);
|
||||
|
||||
// Special case for reading zero bits. Also abort when not enough
|
||||
// bits are left. Return zero
|
||||
if(bnum == 0 || bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Advance the bitstream
|
||||
bstr->bpos = bstr->_i_bpos;
|
||||
bstr->pos = bstr->_i_pos;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// This function will advance the bitstream by bnum bits, if possible.
|
||||
// Advancing of more than 64 bits is possible.
|
||||
// Return TRUE when successfull, otherwise FALSE
|
||||
int skip_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
bstr->bitsleft -= bnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the remaining number of bits in bitstream after reading.
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
|
||||
if (bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 1;
|
||||
|
||||
bstr->bpos -= bnum%8;
|
||||
bstr->pos += bnum/8;
|
||||
|
||||
if (bstr->bpos < 1)
|
||||
{
|
||||
bstr->bpos += 8;
|
||||
bstr->pos += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Return TRUE if the current position in the bitstream is on a byte
|
||||
// boundary, i.e., the next bit in the bitstream is the first bit in
|
||||
// a byte, otherwise return FALSE
|
||||
int is_byte_aligned(struct bitstream *bstr)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
|
||||
if(vbit == 0 || vbit > 8)
|
||||
{
|
||||
fatal(EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
|
||||
}
|
||||
|
||||
if (vbit == 8)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Move bitstream to next byte border. Adjust bitsleft.
|
||||
void make_byte_aligned(struct bitstream *bstr)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
|
||||
if(vbit == 0 || vbit > 8)
|
||||
{
|
||||
fatal(EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
|
||||
}
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
// Pay attention to the bit alignment
|
||||
bstr->bitsleft = (bstr->bitsleft-7)/8 *8;
|
||||
return;
|
||||
}
|
||||
|
||||
if(bstr->bpos != 8)
|
||||
{
|
||||
bstr->bpos = 8;
|
||||
bstr->pos += 1;
|
||||
}
|
||||
// Reset, in case a next_???() function was used before
|
||||
bstr->bitsleft = 0LL + 8*(bstr->end-bstr->pos-1)+bstr->bpos;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Return pointer to first of bynum bytes from the bitstream if the
|
||||
// following conditions are TRUE:
|
||||
// The bitstream is byte aligned and there are enough bytes left in
|
||||
// it to read bynum bytes. Otherwise return NULL.
|
||||
// This function does not advance the bitstream pointer.
|
||||
unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
bstr->bitsleft -= bynum*8;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bynum*8;
|
||||
|
||||
if (!is_byte_aligned(bstr) || bstr->bitsleft < 0 || bynum < 1)
|
||||
return NULL;
|
||||
|
||||
// Remember the bitstream position
|
||||
bstr->_i_bpos = 8;
|
||||
bstr->_i_pos = bstr->pos + bynum;
|
||||
|
||||
return bstr->pos;
|
||||
}
|
||||
|
||||
|
||||
// Return pointer to first of bynum bytes from the bitstream if the
|
||||
// following conditions are TRUE:
|
||||
// The bitstream is byte aligned and there are enough bytes left in
|
||||
// it to read bynum bytes. Otherwise return NULL.
|
||||
// This function does advance the bitstream pointer.
|
||||
unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum)
|
||||
{
|
||||
unsigned char *res = next_bytes(bstr, bynum);
|
||||
|
||||
// Advance the bitstream when a read was possible
|
||||
if(res)
|
||||
{
|
||||
bstr->bpos = bstr->_i_bpos;
|
||||
bstr->pos = bstr->_i_pos;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Return an integer number with "bytes" precision from the current
|
||||
// bitstream position. Allowed "bytes" values are 1,2,4,8.
|
||||
// This function does advance the bitstream pointer when "advance" is
|
||||
// set to TRUE.
|
||||
// Numbers come MSB (most significant first), and we need to account for
|
||||
// little-endian and big-endian CPUs.
|
||||
uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
|
||||
{
|
||||
void *bpos;
|
||||
uint64_t rval=0;
|
||||
|
||||
if (advance)
|
||||
bpos = read_bytes(bstr, bytes);
|
||||
else
|
||||
bpos = next_bytes(bstr, bytes);
|
||||
|
||||
if (!bpos)
|
||||
return 0;
|
||||
|
||||
switch (bytes)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
fatal (EXIT_BUG_BUG, "bitstream_get_num: Illegal precision value [%u]!",
|
||||
bytes);
|
||||
break;
|
||||
}
|
||||
for (unsigned i=0;i<bytes;i++)
|
||||
{
|
||||
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
|
||||
unsigned char uc=*ucpos;
|
||||
rval=(rval<<8) + uc;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
// Read unsigned Exp-Golomb code from bitstream
|
||||
uint64_t ue(struct bitstream *bstr)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
int zeros=0;
|
||||
|
||||
while(!read_bits(bstr,1))
|
||||
zeros++;
|
||||
|
||||
res = (0x01 << zeros) - 1 + read_bits(bstr,zeros);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read signed Exp-Golomb code from bitstream
|
||||
int64_t se(struct bitstream *bstr)
|
||||
{
|
||||
int64_t res = 0;
|
||||
|
||||
res = ue(bstr);
|
||||
|
||||
// The following function might truncate when res+1 overflows
|
||||
//res = (res+1)/2 * (res % 2 ? 1 : -1);
|
||||
// Use this:
|
||||
res = (res/2+(res%2 ? 1 : 0)) * (res % 2 ? 1 : -1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read unsigned integer with bnum bits length. Basically an
|
||||
// alias for read_bits().
|
||||
uint64_t u(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
return read_bits(bstr, bnum);
|
||||
}
|
||||
|
||||
|
||||
// Read signed integer with bnum bits length.
|
||||
int64_t i(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = read_bits(bstr, bnum);
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 0;
|
||||
|
||||
return (0xFFFFFFFFFFFFFFFFULL << bnum) | res;
|
||||
}
|
||||
|
||||
|
||||
// Return the value with the bit order reversed.
|
||||
uint8_t reverse8(uint8_t data)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
|
||||
for (int k=0;k<8;k++)
|
||||
{
|
||||
res <<= 1;
|
||||
res |= (data & (0x01 << k) ? 1 : 0);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Functions used by both the 608 and 708 decoders. An effort should be
|
||||
made to reuse, not duplicate, as many functions as possible */
|
||||
|
||||
#include "ccextractor.h"
|
||||
|
||||
/* 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 fts = get_fts();
|
||||
if (fts <= minimum_fts)
|
||||
fts = minimum_fts+1;
|
||||
dbg_print(CCX_DMT_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)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts>minimum_fts)
|
||||
minimum_fts=fts;
|
||||
dbg_print(CCX_DMT_608, "Visible End time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,605 +0,0 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
// compatibility across platforms
|
||||
#include "platform.h"
|
||||
|
||||
#define VERSION "0.70"
|
||||
|
||||
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)
|
||||
|
||||
#include "608.h"
|
||||
#include "708.h"
|
||||
#include "bitstream.h"
|
||||
#include "constants.h"
|
||||
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
|
||||
struct ccx_boundary_time
|
||||
{
|
||||
int hh,mm,ss;
|
||||
LLONG time_in_ms;
|
||||
int set;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// TODO: add more options, and (perhaps) reduce other ccextractor options?
|
||||
int showStartTime, showEndTime; // Show start and/or end time.
|
||||
int showMode; // Show which mode if available (E.G.: POP, RU1, ...)
|
||||
int showCC; // Show which CC channel has been captured.
|
||||
int relativeTimestamp; // Timestamps relative to start of sample or in UTC?
|
||||
int xds; // Show XDS or not
|
||||
int useColors; // Add colors or no colors
|
||||
|
||||
} ccx_transcript_format;
|
||||
|
||||
extern ccx_transcript_format ccx_default_transcript_settings;
|
||||
|
||||
struct ccx_s_options // Options from user parameters
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int direct_rollup;
|
||||
int nofontcolor;
|
||||
int notypesetting;
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
int print_file_reports;
|
||||
|
||||
/* subtitle codec type */
|
||||
enum cxx_code_type codec;
|
||||
enum cxx_code_type nocodec;
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
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 norollup; // If 1, write one line at a time
|
||||
int forced_ru; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
|
||||
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
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
|
||||
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
|
||||
int wtvconvertfix; // Fix broken Windows 7 conversion
|
||||
int wtvmpeg2;
|
||||
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
|
||||
/* MP4 related stuff */
|
||||
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?
|
||||
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
|
||||
ccx_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
char millis_separator;
|
||||
LLONG screens_to_process; // How many screenfuls we want?
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
enum ccx_output_date_format date_format;
|
||||
enum color_code cc608_default_color;
|
||||
char *output_filename;
|
||||
char *out_elementarystream_filename;
|
||||
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 */
|
||||
in_addr_t udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
int noautotimeref; // Do NOT set time automatically?
|
||||
enum ccx_datasource input_source; // Files, stdin or network
|
||||
|
||||
};
|
||||
|
||||
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 ccx_s_write
|
||||
{
|
||||
int fh;
|
||||
char *filename;
|
||||
void* spupng_data;
|
||||
};
|
||||
|
||||
|
||||
struct gop_time_code
|
||||
{
|
||||
int drop_frame_flag;
|
||||
int time_code_hours;
|
||||
int time_code_minutes;
|
||||
int marker_bit;
|
||||
int time_code_seconds;
|
||||
int time_code_pictures;
|
||||
int inited;
|
||||
LLONG ms;
|
||||
};
|
||||
|
||||
|
||||
/* Report information */
|
||||
#define SUB_STREAMS_CNT 10
|
||||
struct file_report_t
|
||||
{
|
||||
unsigned program_cnt;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned aspect_ratio;
|
||||
unsigned frame_rate;
|
||||
unsigned xds : 1;
|
||||
unsigned cc_channels_608[4];
|
||||
unsigned services708[63];
|
||||
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned mp4_cc_track_cnt;
|
||||
} file_report;
|
||||
|
||||
|
||||
// Stuff for telcc.c
|
||||
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
|
||||
double offset; // time offset in seconds
|
||||
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
|
||||
uint8_t nonempty : 1; // produce at least one (dummy) frame
|
||||
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
|
||||
// uint64_t utc_refvalue; // UTC referential value => Moved to CCExtractor global, so can be used for 608 too
|
||||
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
|
||||
};
|
||||
|
||||
#define buffered_skip(bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else result=buffered_read_opt (NULL,bytes);
|
||||
|
||||
#define buffered_read(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 (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(buffer) if (bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
|
||||
filebuffer_pos++; \
|
||||
result=1; } \
|
||||
} else result=buffered_read_opt (buffer,1);
|
||||
|
||||
extern LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
//params.c
|
||||
void parse_parameters (int argc, char *argv[]);
|
||||
void usage (void);
|
||||
int atoi_hex (char *s);
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
|
||||
// general_loop.c
|
||||
void position_sanity_check ();
|
||||
int init_file_buffer( void );
|
||||
LLONG ps_getmoredata( void );
|
||||
LLONG general_getmoredata( void );
|
||||
void raw_loop (void);
|
||||
LLONG process_raw (void);
|
||||
void general_loop(void);
|
||||
void processhex (char *filename);
|
||||
void rcwt_loop( void );
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
// 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_xds_program_name (const char *program_name);
|
||||
void activity_xds_network_call_letters (const char *program_name);
|
||||
void activity_xds_program_identification_number (unsigned minutes, unsigned hours, unsigned date, unsigned month);
|
||||
void activity_xds_program_description (int line_num, const char *program_desc);
|
||||
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( void );
|
||||
|
||||
// wtv_functions.c
|
||||
LLONG wtv_getmoredata( void );
|
||||
|
||||
// avc_functions.c
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen);
|
||||
void init_avc(void);
|
||||
|
||||
// es_functions.c
|
||||
LLONG process_m2v (unsigned char *data, LLONG length);
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
// es_userdata.c
|
||||
int user_data(struct bitstream *ustream, int udtype);
|
||||
|
||||
// bitstream.c - see bitstream.h
|
||||
|
||||
// 608.c
|
||||
int write_cc_buffer(struct s_context_cc608 *context);
|
||||
unsigned char *debug_608toASC (unsigned char *ccdata, int channel);
|
||||
|
||||
|
||||
// cc_decoders_common.c
|
||||
LLONG get_visible_start (void);
|
||||
LLONG get_visible_end (void);
|
||||
|
||||
// file_functions.c
|
||||
LLONG getfilesize (int in);
|
||||
LLONG gettotalfilessize (void);
|
||||
void prepare_for_new_file (void);
|
||||
void close_input_file (void);
|
||||
int switch_to_next_file (LLONG bytesinbuffer);
|
||||
int init_sockets (void);
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// timing.c
|
||||
void set_fts(void);
|
||||
LLONG get_fts(void);
|
||||
LLONG get_fts_max(void);
|
||||
char *print_mstime( LLONG mstime );
|
||||
char *print_mstime2buf( LLONG mstime , char *buf );
|
||||
void print_debug_timing( void );
|
||||
int gop_accepted(struct gop_time_code* g );
|
||||
void calculate_ms_gop_time (struct gop_time_code *g);
|
||||
|
||||
// sequencing.c
|
||||
void init_hdcc (void);
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts);
|
||||
void anchor_hdcc(int seq);
|
||||
void process_hdcc (void);
|
||||
int do_cb (unsigned char *cc_block);
|
||||
|
||||
// mp4.c
|
||||
int processmp4 (char *file);
|
||||
|
||||
// params_dump.c
|
||||
void params_dump(void);
|
||||
void print_file_report(void);
|
||||
|
||||
// output.c
|
||||
void init_write (struct ccx_s_write *wb);
|
||||
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
|
||||
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context);
|
||||
void flushbuffer (struct ccx_s_write *wb, int closefile);
|
||||
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2);
|
||||
void writercwtdata (const unsigned char *data);
|
||||
|
||||
// stream_functions.c
|
||||
void detect_stream_type (void);
|
||||
int detect_myth( void );
|
||||
int read_video_pes_header (unsigned char *header, int *headerlength, int sbuflen);
|
||||
int read_pts_pes(unsigned char*header, int len);
|
||||
|
||||
// ts_functions.c
|
||||
void init_ts( void );
|
||||
int ts_readpacket(void);
|
||||
long ts_readstream(void);
|
||||
LLONG ts_getmoredata( void );
|
||||
int write_section(struct ts_payload *payload, unsigned char*buf, int size, int pos);
|
||||
int parse_PMT (unsigned char *buf,int len, int pos);
|
||||
int parse_PAT (void);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(void);
|
||||
|
||||
// mp4_bridge2bento4.c
|
||||
void mp4_loop (char *filename);
|
||||
|
||||
// xds.c
|
||||
void process_xds_bytes (const unsigned char hi, int lo);
|
||||
void do_end_of_xds (unsigned char expected_checksum);
|
||||
void xds_init();
|
||||
|
||||
// ccextractor.c
|
||||
LLONG calculate_gop_mstime (struct gop_time_code *g);
|
||||
void set_fts(void);
|
||||
char *print_mstime( LLONG mstime );
|
||||
void print_debug_timing( void );
|
||||
int switch_to_next_file (LLONG bytesinbuffer);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
void dvprint(const char *fmt, ...);
|
||||
void mprint (const char *fmt, ...);
|
||||
void subsprintf (const char *fmt, ...);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
void fdprintf (int fd, const char *fmt, ...);
|
||||
void init_boundary_time (struct ccx_boundary_time *bt);
|
||||
void sleep_secs (int secs);
|
||||
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
|
||||
bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
|
||||
int hex2int (char high, char low);
|
||||
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
|
||||
void millis_to_date (uint64_t timestamp, char *buffer) ;
|
||||
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
|
||||
|
||||
void init_context_cc608(struct s_context_cc608 *data, int field);
|
||||
unsigned encode_line (unsigned char *buffer, unsigned char *text);
|
||||
void buffered_seek (int offset);
|
||||
void write_subtitle_file_header(struct ccx_s_write *out);
|
||||
void write_subtitle_file_footer(struct ccx_s_write *out);
|
||||
extern void build_parity_table(void);
|
||||
|
||||
void tlt_process_pes_packet(uint8_t *buffer, uint16_t size) ;
|
||||
void telxcc_init(void);
|
||||
void telxcc_close(void);
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
|
||||
unsigned *seconds, unsigned *ms);
|
||||
|
||||
extern struct gop_time_code gop_time, first_gop_time, printed_gop;
|
||||
extern int gop_rollover;
|
||||
extern LLONG min_pts, sync_pts, current_pts;
|
||||
extern unsigned rollover_bits;
|
||||
extern uint32_t global_timestamp, min_global_timestamp;
|
||||
extern int global_timestamp_inited;
|
||||
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)
|
||||
// Count 608 (per field) and 708 blocks since last set_fts() call
|
||||
extern int cb_field1, cb_field2, cb_708;
|
||||
extern int saw_caption_block;
|
||||
|
||||
|
||||
extern unsigned char *buffer;
|
||||
extern LLONG past;
|
||||
extern LLONG total_inputsize, total_past; // Only in binary concat mode
|
||||
|
||||
extern char **inputfile;
|
||||
extern int current_file;
|
||||
extern LLONG result; // Number of bytes read/skipped in last read operation
|
||||
|
||||
|
||||
extern struct sockaddr_in servaddr, cliaddr;
|
||||
|
||||
extern int strangeheader;
|
||||
|
||||
extern unsigned char startbytes[STARTBYTESLENGTH];
|
||||
extern unsigned int startbytes_pos;
|
||||
extern int startbytes_avail; // Needs to be able to hold -1 result.
|
||||
|
||||
extern unsigned char *pesheaderbuf;
|
||||
extern int pts_set; //0 = No, 1 = received, 2 = min_pts set
|
||||
extern unsigned long long max_dif;
|
||||
|
||||
extern int MPEG_CLOCK_FREQ; // This is part of the standard
|
||||
|
||||
extern unsigned pts_big_change;
|
||||
extern unsigned total_frames_count;
|
||||
extern unsigned total_pulldownfields;
|
||||
extern unsigned total_pulldownframes;
|
||||
|
||||
extern int CaptionGap;
|
||||
|
||||
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 struct s_context_cc608 context_cc608_field_1, context_cc608_field_2;
|
||||
|
||||
extern const char *desc[256];
|
||||
|
||||
extern FILE *fh_out_elementarystream;
|
||||
extern int infd;
|
||||
extern int false_pict_header;
|
||||
|
||||
extern int stat_numuserheaders;
|
||||
extern int stat_dvdccheaders;
|
||||
extern int stat_scte20ccheaders;
|
||||
extern int stat_replay5000headers;
|
||||
extern int stat_replay4000headers;
|
||||
extern int stat_dishheaders;
|
||||
extern int stat_hdtv;
|
||||
extern int stat_divicom;
|
||||
extern enum ccx_stream_mode_enum stream_mode;
|
||||
extern int cc_stats[4];
|
||||
extern LLONG inputsize;
|
||||
|
||||
extern LLONG subs_delay;
|
||||
extern int startcredits_displayed, end_credits_displayed;
|
||||
extern LLONG last_displayed_subs_ms;
|
||||
extern int processed_enough;
|
||||
extern unsigned char usercolor_rgb[8];
|
||||
|
||||
extern const char *extension;
|
||||
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
|
||||
extern struct ccx_s_options ccx_options;
|
||||
extern int temp_debug;
|
||||
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 double current_fps;
|
||||
|
||||
extern int end_of_file;
|
||||
extern LLONG inbuf;
|
||||
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
extern int firstcall;
|
||||
extern LLONG minimum_fts; // No screen should start before this FTS
|
||||
|
||||
#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 int current_field;
|
||||
|
||||
extern int last_reported_progress;
|
||||
extern int cc_to_stdout;
|
||||
|
||||
extern unsigned hauppauge_warning_shown;
|
||||
extern unsigned char *subline;
|
||||
extern int saw_gop_header;
|
||||
extern int max_gop_length;
|
||||
extern int last_gop_length;
|
||||
extern int frames_since_last_gop;
|
||||
extern LLONG fts_at_gop_start;
|
||||
extern int frames_since_ref_time;
|
||||
extern enum ccx_stream_mode_enum auto_stream;
|
||||
extern int num_input_files;
|
||||
extern char *basefilename;
|
||||
extern int do_cea708; // Process 708 data?
|
||||
extern int cea708services[63]; // [] -> 1 for services to be processed
|
||||
extern struct ccx_s_write wbout1, wbout2, *wbxdsout;
|
||||
|
||||
extern char **spell_lower;
|
||||
extern char **spell_correct;
|
||||
extern int spell_words;
|
||||
extern int spell_capacity;
|
||||
|
||||
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 enum ccx_frame_type current_picture_coding_type;
|
||||
extern int current_tref; // Store temporal reference of current frame
|
||||
|
||||
extern int cc608_parity_table[256]; // From myth
|
||||
|
||||
// From ts_functions
|
||||
extern unsigned cap_stream_type;
|
||||
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
|
||||
*/
|
||||
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_FILE_CREATION_FAILED 5
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_UNSUPPORTED 9
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_NOT_ENOUGH_MEMORY 500
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_BUG_BUG 1000
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
extern int PIDs_seen[65536];
|
||||
extern struct PMT_entry *PIDs_programs[65536];
|
||||
|
||||
extern LLONG ts_start_of_xds;
|
||||
//extern int timestamps_on_transcript;
|
||||
|
||||
extern unsigned teletext_mode;
|
||||
|
||||
#define MAX_TLT_PAGES 1000
|
||||
extern short int seen_sub_page[MAX_TLT_PAGES];
|
||||
|
||||
extern uint64_t utc_refvalue; // UTC referential value
|
||||
extern struct ccx_s_teletext_config tlt_config;
|
||||
extern uint32_t tlt_packet_counter;
|
||||
extern uint32_t tlt_frames_produced;
|
||||
|
||||
#endif
|
||||
125
src/constants.c
125
src/constants.c
@@ -1,125 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
// RCWT header (11 bytes):
|
||||
//byte(s) value description (All values below are hex numbers, not
|
||||
// actual numbers or values
|
||||
//0-2 CCCCED magic number, for Closed Caption CC Extractor Data
|
||||
//3 CC Creating program. Legal values: CC = CC Extractor
|
||||
//4-5 0050 Program version number
|
||||
//6-7 0001 File format version
|
||||
//8-10 000000 Padding, required :-)
|
||||
const unsigned char rcwt_header[11]={0xCC, 0xCC, 0xED, 0xCC, 0x00, 0x50, 0, 1, 0, 0, 0};
|
||||
|
||||
const unsigned char BROADCAST_HEADER[]={0xff, 0xff, 0xff, 0xff};
|
||||
const unsigned char LITTLE_ENDIAN_BOM[]={0xff, 0xfe};
|
||||
const unsigned char UTF8_BOM[]={0xef, 0xbb,0xbf};
|
||||
|
||||
const unsigned char DVD_HEADER[8]={0x00,0x00,0x01,0xb2,0x43,0x43,0x01,0xf8};
|
||||
const unsigned char lc1[1]={0x8a};
|
||||
const unsigned char lc2[1]={0x8f};
|
||||
const unsigned char lc3[2]={0x16,0xfe};
|
||||
const unsigned char lc4[2]={0x1e,0xfe};
|
||||
const unsigned char lc5[1]={0xff};
|
||||
const unsigned char lc6[1]={0xfe};
|
||||
|
||||
const double framerates_values[16]=
|
||||
{
|
||||
0,
|
||||
24000.0/1001, /* 23.976 */
|
||||
24.0,
|
||||
25.0,
|
||||
30000.0/1001, /* 29.97 */
|
||||
30.0,
|
||||
50.0,
|
||||
60000.0/1001, /* 59.94 */
|
||||
60.0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
const char *framerates_types[16]=
|
||||
{
|
||||
"00 - forbidden",
|
||||
"01 - 23.976",
|
||||
"02 - 24",
|
||||
"03 - 25",
|
||||
"04 - 29.97",
|
||||
"05 - 30",
|
||||
"06 - 50",
|
||||
"07 - 59.94",
|
||||
"08 - 60",
|
||||
"09 - reserved",
|
||||
"10 - reserved",
|
||||
"11 - reserved",
|
||||
"12 - reserved",
|
||||
"13 - reserved",
|
||||
"14 - reserved",
|
||||
"15 - reserved"
|
||||
};
|
||||
|
||||
const char *aspect_ratio_types[16]=
|
||||
{
|
||||
"00 - forbidden",
|
||||
"01 - 1:1",
|
||||
"02 - 4:3",
|
||||
"03 - 16:9",
|
||||
"04 - 2.21:1",
|
||||
"05 - reserved",
|
||||
"06 - reserved",
|
||||
"07 - reserved",
|
||||
"08 - reserved",
|
||||
"09 - reserved",
|
||||
"10 - reserved",
|
||||
"11 - reserved",
|
||||
"12 - reserved",
|
||||
"13 - reserved",
|
||||
"14 - reserved",
|
||||
"15 - reserved"
|
||||
};
|
||||
|
||||
|
||||
const char *pict_types[8]=
|
||||
{
|
||||
"00 - ilegal (0)",
|
||||
"01 - I",
|
||||
"02 - P",
|
||||
"03 - B",
|
||||
"04 - ilegal (D)",
|
||||
"05 - ilegal (5)",
|
||||
"06 - ilegal (6)",
|
||||
"07 - ilegal (7)"
|
||||
};
|
||||
|
||||
|
||||
const char *slice_types[10]=
|
||||
{
|
||||
"0 - P",
|
||||
"1 - B",
|
||||
"2 - I",
|
||||
"3 - SP",
|
||||
"4 - SI",
|
||||
"5 - P",
|
||||
"6 - B",
|
||||
"7 - I",
|
||||
"8 - SP",
|
||||
"9 - SI"
|
||||
};
|
||||
|
||||
const char *cc_types[4] =
|
||||
{
|
||||
"NTSC line 21 field 1 closed captions",
|
||||
"NTSC line 21 field 2 closed captions",
|
||||
"DTVCC Channel Packet Data",
|
||||
"DTVCC Channel Packet Start"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NTSC_CC_f1 = 0,
|
||||
NTSC_CC_f2 = 1,
|
||||
DTVCC_PACKET_DATA = 2,
|
||||
DTVCC_PACKET_START = 3,
|
||||
};
|
||||
840
src/encoding.c
840
src/encoding.c
@@ -1,840 +0,0 @@
|
||||
#include <ctype.h>
|
||||
|
||||
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
{
|
||||
unsigned char c1='?';
|
||||
if (c<0x80)
|
||||
{
|
||||
// Regular line-21 character set, mostly ASCII except these exceptions
|
||||
switch (c)
|
||||
{
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
c1=0xe1;
|
||||
break;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
c1=0xe9;
|
||||
break;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
c1=0xed;
|
||||
break;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
c1=0xf3;
|
||||
break;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
c1=0xfa;
|
||||
break;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
c1=0xe7;
|
||||
break;
|
||||
case 0x7c: // division symbol
|
||||
c1=0xf7;
|
||||
break;
|
||||
case 0x7d: // uppercase N tilde
|
||||
c1=0xd1;
|
||||
break;
|
||||
case 0x7e: // lowercase n tilde
|
||||
c1=0xf1;
|
||||
break;
|
||||
default:
|
||||
c1=c;
|
||||
break;
|
||||
}
|
||||
*buffer=c1;
|
||||
return;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
c1=0xae;
|
||||
break;
|
||||
case 0x81: // degree sign
|
||||
c1=0xb0;
|
||||
break;
|
||||
case 0x82: // 1/2 symbol
|
||||
c1=0xbd;
|
||||
break;
|
||||
case 0x83: // Inverted (open) question mark
|
||||
c1=0xbf;
|
||||
break;
|
||||
case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
|
||||
break;
|
||||
case 0x85: // Cents symbol
|
||||
c1=0xa2;
|
||||
break;
|
||||
case 0x86: // Pounds sterling
|
||||
c1=0xa3;
|
||||
break;
|
||||
case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
|
||||
c1=0xb6;
|
||||
break;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
c1=0xe0;
|
||||
break;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
c1=0x20;
|
||||
break;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
c1=0xe8;
|
||||
break;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
c1=0xe2;
|
||||
break;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
c1=0xea;
|
||||
break;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
c1=0xee;
|
||||
break;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
c1=0xf4;
|
||||
break;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
c1=0xfb;
|
||||
break;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0x90: // capital letter A with acute
|
||||
c1=0xc1;
|
||||
break;
|
||||
case 0x91: // capital letter E with acute
|
||||
c1=0xc9;
|
||||
break;
|
||||
case 0x92: // capital letter O with acute
|
||||
c1=0xd3;
|
||||
break;
|
||||
case 0x93: // capital letter U with acute
|
||||
c1=0xda;
|
||||
break;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
c1=0xdc;
|
||||
break;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
c1=0xfc;
|
||||
break;
|
||||
case 0x96: // apostrophe
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x97: // inverted exclamation mark
|
||||
c1=0xa1;
|
||||
break;
|
||||
case 0x98: // asterisk
|
||||
c1=0x2a;
|
||||
break;
|
||||
case 0x99: // apostrophe (yes, duped). See CCADI source code.
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x9a: // em dash
|
||||
c1=0x2d;
|
||||
break;
|
||||
case 0x9b: // copyright sign
|
||||
c1=0xa9;
|
||||
break;
|
||||
case 0x9c: // Service Mark - not available in latin 1
|
||||
break;
|
||||
case 0x9d: // Full stop (.)
|
||||
c1=0x2e;
|
||||
break;
|
||||
case 0x9e: // Quoatation mark
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0x9f: // Quoatation mark
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
c1=0xc0;
|
||||
break;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
c1=0xc2;
|
||||
break;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
c1=0xc7;
|
||||
break;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
c1=0xc8;
|
||||
break;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
c1=0xca;
|
||||
break;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
c1=0xcb;
|
||||
break;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
c1=0xeb;
|
||||
break;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
c1=0xce;
|
||||
break;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
c1=0xcf;
|
||||
break;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
c1=0xef;
|
||||
break;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
c1=0xd4;
|
||||
break;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
c1=0xd9;
|
||||
break;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
c1=0xf9;
|
||||
break;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
c1=0xdb;
|
||||
break;
|
||||
case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
c1=0xab;
|
||||
break;
|
||||
case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
c1=0xbb;
|
||||
break;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
c1=0xc3;
|
||||
break;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
c1=0xe3;
|
||||
break;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
c1=0xcd;
|
||||
break;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
c1=0xcc;
|
||||
break;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
c1=0xec;
|
||||
break;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
c1=0xd2;
|
||||
break;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
c1=0xf2;
|
||||
break;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
c1=0xd5;
|
||||
break;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
c1=0xf5;
|
||||
break;
|
||||
case 0xb9: // Open curly brace
|
||||
c1=0x7b;
|
||||
break;
|
||||
case 0xba: // Closing curly brace
|
||||
c1=0x7d;
|
||||
break;
|
||||
case 0xbb: // Backslash
|
||||
c1=0x5c;
|
||||
break;
|
||||
case 0xbc: // Caret
|
||||
c1=0x5e;
|
||||
break;
|
||||
case 0xbd: // Underscore
|
||||
c1=0x5f;
|
||||
break;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
c1=0xa6;
|
||||
break;
|
||||
case 0xbf: // Tilde
|
||||
c1=0x7e;
|
||||
break;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
c1=0xc4;
|
||||
break;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
c1=0xe3;
|
||||
break;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
c1=0xd6;
|
||||
break;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
c1=0xf6;
|
||||
break;
|
||||
case 0xc4: // Esszett (sharp S)
|
||||
c1=0xdf;
|
||||
break;
|
||||
case 0xc5: // Yen symbol
|
||||
c1=0xa5;
|
||||
break;
|
||||
case 0xc6: // Currency symbol
|
||||
c1=0xa4;
|
||||
break;
|
||||
case 0xc7: // Vertical bar
|
||||
c1=0x7c;
|
||||
break;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
c1=0xc5;
|
||||
break;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
c1=0xe5;
|
||||
break;
|
||||
case 0xca: // Uppercase O, slash
|
||||
c1=0xd8;
|
||||
break;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
c1=0xf8;
|
||||
break;
|
||||
case 0xcc: // Upper left corner
|
||||
case 0xcd: // Upper right corner
|
||||
case 0xce: // Lower left corner
|
||||
case 0xcf: // Lower right corner
|
||||
default: // For those that don't have representation
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
break; // This are weird chars anyway
|
||||
}
|
||||
*buffer=c1;
|
||||
}
|
||||
|
||||
void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
{
|
||||
unsigned char c1,c2;
|
||||
switch (c)
|
||||
{
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
c2=0x21;
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0x87: // Music note
|
||||
c2=0x26;
|
||||
c1=0x6a;
|
||||
break;
|
||||
case 0x9c: // Service Mark
|
||||
c2=0x21;
|
||||
c1=0x20;
|
||||
break;
|
||||
case 0xcc: // Upper left corner
|
||||
c2=0x23;
|
||||
c1=0x1c;
|
||||
break;
|
||||
case 0xcd: // Upper right corner
|
||||
c2=0x23;
|
||||
c1=0x1d;
|
||||
break;
|
||||
case 0xce: // Lower left corner
|
||||
c2=0x23;
|
||||
c1=0x1e;
|
||||
break;
|
||||
case 0xcf: // Lower right corner
|
||||
c2=0x23;
|
||||
c1=0x1f;
|
||||
break;
|
||||
default: // Everything else, same as latin-1 followed by 00
|
||||
get_char_in_latin_1 (&c1,c);
|
||||
c2=0;
|
||||
break;
|
||||
}
|
||||
*buffer=c1;
|
||||
*(buffer+1)=c2;
|
||||
}
|
||||
|
||||
int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used
|
||||
{
|
||||
if (c<0x80) // Regular line-21 character set, mostly ASCII except these exceptions
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa1;
|
||||
return 2;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa9;
|
||||
return 2;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xad;
|
||||
return 2;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb3;
|
||||
return 2;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xba;
|
||||
return 2;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa7;
|
||||
return 2;
|
||||
case 0x7c: // division symbol
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb7;
|
||||
return 2;
|
||||
case 0x7d: // uppercase N tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x91;
|
||||
return 2;
|
||||
case 0x7e: // lowercase n tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb1;
|
||||
return 2;
|
||||
case 0x7f: // Solid block
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x96;
|
||||
*(buffer+2)=0xa0;
|
||||
return 3;
|
||||
default:
|
||||
*buffer=c;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xae;
|
||||
return 2;
|
||||
case 0x81: // degree sign
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xb0;
|
||||
return 2;
|
||||
case 0x82: // 1/2 symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbd;
|
||||
return 2;
|
||||
case 0x83: // Inverted (open) question mark
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbf;
|
||||
return 2;
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x84;
|
||||
*(buffer+2)=0xa2;
|
||||
return 3;
|
||||
case 0x85: // Cents symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa2;
|
||||
return 2;
|
||||
case 0x86: // Pounds sterling
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa3;
|
||||
return 2;
|
||||
case 0x87: // Music note
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x99;
|
||||
*(buffer+2)=0xaa;
|
||||
return 3;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa0;
|
||||
return 2;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
*buffer=0x20;
|
||||
return 1;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa8;
|
||||
return 2;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa2;
|
||||
return 2;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xaa;
|
||||
return 2;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xae;
|
||||
return 2;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb4;
|
||||
return 2;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xbb;
|
||||
return 2;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0x90: // capital letter A with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x81;
|
||||
return 2;
|
||||
case 0x91: // capital letter E with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x89;
|
||||
return 2;
|
||||
case 0x92: // capital letter O with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x93;
|
||||
return 2;
|
||||
case 0x93: // capital letter U with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9a;
|
||||
return 2;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9c;
|
||||
return 2;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xbc;
|
||||
return 2;
|
||||
case 0x96: // apostrophe
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x97: // inverted exclamation mark
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa1;
|
||||
return 2;
|
||||
case 0x98: // asterisk
|
||||
*buffer=0x2a;
|
||||
return 1;
|
||||
case 0x99: // Plain single quote
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x9a: // em dash
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x94;
|
||||
return 3;
|
||||
case 0x9b: // copyright sign
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa9;
|
||||
return 2;
|
||||
case 0x9c: // Service mark
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x84;
|
||||
*(buffer+2)=0xa0;
|
||||
return 3;
|
||||
case 0x9d: // Round bullet
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0xa2;
|
||||
return 3;
|
||||
case 0x9e: // Opening double quotes
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9c;
|
||||
return 3;
|
||||
case 0x9f: // Closing double quotes
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9d;
|
||||
return 3;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x80;
|
||||
return 2;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x82;
|
||||
return 2;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x87;
|
||||
return 2;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x88;
|
||||
return 2;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8a;
|
||||
return 2;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8b;
|
||||
return 2;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xab;
|
||||
return 2;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8e;
|
||||
return 2;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8f;
|
||||
return 2;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xaf;
|
||||
return 2;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x94;
|
||||
return 2;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x99;
|
||||
return 2;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb9;
|
||||
return 2;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9b;
|
||||
return 2;
|
||||
case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xab;
|
||||
return 2;
|
||||
case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbb;
|
||||
return 2;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x83;
|
||||
return 2;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa3;
|
||||
return 2;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8d;
|
||||
return 2;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8c;
|
||||
return 2;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xac;
|
||||
return 2;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x92;
|
||||
return 2;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb2;
|
||||
return 2;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x95;
|
||||
return 2;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb5;
|
||||
return 2;
|
||||
case 0xb9: // Open curly brace
|
||||
*buffer=0x7b;
|
||||
return 1;
|
||||
case 0xba: // Closing curly brace
|
||||
*buffer=0x7d;
|
||||
return 1;
|
||||
case 0xbb: // Backslash
|
||||
*buffer=0x5c;
|
||||
return 1;
|
||||
case 0xbc: // Caret
|
||||
*buffer=0x5e;
|
||||
return 1;
|
||||
case 0xbd: // Underscore
|
||||
*buffer=0x5f;
|
||||
return 1;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa6;
|
||||
return 2;
|
||||
case 0xbf: // Tilde
|
||||
*buffer=0x7e; // Not sure
|
||||
return 1;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x84;
|
||||
return 2;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x96;
|
||||
return 2;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb6;
|
||||
return 2;
|
||||
case 0xc4: // Esszett (sharp S)
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9f;
|
||||
return 2;
|
||||
case 0xc5: // Yen symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa5;
|
||||
return 2;
|
||||
case 0xc6: // Currency symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc7: // Vertical bar
|
||||
*buffer=0x7c;
|
||||
return 1;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x85;
|
||||
return 2;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa5;
|
||||
return 2;
|
||||
case 0xca: // Uppercase O, slash
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x98;
|
||||
return 2;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb8;
|
||||
return 2;
|
||||
case 0xcc: // Top left corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9c;
|
||||
return 3;
|
||||
case 0xcd: // Top right corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9d;
|
||||
return 3;
|
||||
case 0xce: // Bottom left corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9e;
|
||||
return 3;
|
||||
case 0xcf: // Bottom right corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9f;
|
||||
return 3;
|
||||
default: //
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
return 1; // This are weird chars anyway
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char cctolower (unsigned char c)
|
||||
{
|
||||
if (c>='A' && c<='Z')
|
||||
return tolower(c);
|
||||
switch (c)
|
||||
{
|
||||
case 0x7d: // uppercase N tilde
|
||||
return 0x7e;
|
||||
case 0x90: // capital letter A with acute
|
||||
return 0x2a;
|
||||
case 0x91: // capital letter E with acute
|
||||
return 0x5c;
|
||||
case 0x92: // capital letter O with acute
|
||||
return 0x5f;
|
||||
case 0x93: // capital letter U with acute
|
||||
return 0x60;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
return 0x7b;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
return 0x88;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
return 0x8a;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
return 0x8b;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
return 0x8c;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
return 0x8d;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
return 0x8e;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
return 0x8f;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
return 0x95;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
return 0xa6;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
return 0xa9;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
return 0xac;
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
return 0xb1;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
return 0x5e;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
return 0xb4;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
return 0xb6;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
return 0xb8;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
return 0xc1;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
return 0xc3;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
return 0xc9;
|
||||
case 0xca: // Uppercase O, slash
|
||||
return 0xcb;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned char cctoupper (unsigned char c)
|
||||
{
|
||||
if (c>='a' && c<='z')
|
||||
return toupper(c);
|
||||
switch (c)
|
||||
{
|
||||
case 0x7e: // lowercase n tilde
|
||||
return 0x7d;
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
return 0x90;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
return 0x91;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
return 0xb2;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
return 0x92;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
return 0x93;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
return 0xa2;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
return 0xa0;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
return 0xa3;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
return 0xa1;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
return 0xa4;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
return 0xa7;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
return 0xaa;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
return 0xad;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
return 0x94;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
return 0xa5;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
return 0xa8;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
return 0xab;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
return 0xb0;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
return 0xb3;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
return 0xb5;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
return 0xb7;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
return 0xc0;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
return 0xc2;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
return 0xc8;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
return 0xca;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
1132
src/es_functions.c
1132
src/es_functions.c
File diff suppressed because it is too large
Load Diff
@@ -1,479 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
|
||||
// Parse the user data for captions. The udtype variable denotes
|
||||
// to which type of data it belongs:
|
||||
// 0 .. sequence header
|
||||
// 1 .. GOP header
|
||||
// 2 .. picture header
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if ustream->error
|
||||
// is FALSE, parsing can set ustream->error to TRUE.
|
||||
int user_data(struct bitstream *ustream, int udtype)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
|
||||
|
||||
// Shall not happen
|
||||
if (ustream->error || ustream->bitsleft <= 0)
|
||||
{
|
||||
// ustream->error=1;
|
||||
return 0; // Actually discarded on call.
|
||||
// CFS: Seen in a Wobble edited file.
|
||||
// fatal(EXIT_BUG_BUG, "user_data: Impossible!");
|
||||
}
|
||||
|
||||
// Do something
|
||||
stat_numuserheaders++;
|
||||
//header+=4;
|
||||
|
||||
unsigned char *ud_header = next_bytes(ustream, 4);
|
||||
if (ustream->error || ustream->bitsleft <= 0)
|
||||
{
|
||||
return 0; // Actually discarded on call.
|
||||
// CFS: Seen in Stick_VHS.mpg.
|
||||
// fatal(EXIT_BUG_BUG, "user_data: Impossible!");
|
||||
}
|
||||
|
||||
// DVD CC header, see
|
||||
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
|
||||
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
|
||||
{
|
||||
stat_dvdccheaders++;
|
||||
|
||||
// Probably unneeded, but keep looking for extra caption blocks
|
||||
int maybeextracb = 1;
|
||||
|
||||
read_bytes(ustream, 4); // "43 43 01 F8"
|
||||
|
||||
unsigned char pattern_flag = (unsigned char) read_bits(ustream,1);
|
||||
read_bits(ustream,1);
|
||||
int capcount=(int) read_bits(ustream,5);
|
||||
int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra
|
||||
|
||||
int field1packet = 0; // expect Field 1 first
|
||||
if (pattern_flag == 0x00)
|
||||
field1packet=1; // expect Field 1 second
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n",
|
||||
capcount, (truncate_flag?"+1":""));
|
||||
|
||||
capcount += truncate_flag;
|
||||
|
||||
// This data comes before the first frame header, so
|
||||
// in order to get the correct timing we need to set the
|
||||
// current time to one frame after the maximum time of the
|
||||
// last GOP. Only usefull when there are frames before
|
||||
// the GOP.
|
||||
if (fts_max > 0)
|
||||
fts_now = fts_max + (LLONG) (1000.0/current_fps);
|
||||
|
||||
int rcbcount = 0;
|
||||
for (int i=0; i<capcount; i++)
|
||||
{
|
||||
for (int j=0;j<2;j++)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=read_u8(ustream);
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
|
||||
// Obey the truncate flag.
|
||||
if ( truncate_flag && i == capcount-1 && j == 1 )
|
||||
{
|
||||
maybeextracb = 0;
|
||||
break;
|
||||
}
|
||||
/* Field 1 and 2 data can be in either order,
|
||||
with marker bytes of \xff and \xfe
|
||||
Since markers can be repeated, use pattern as well */
|
||||
if ((data[0]&0xFE) == 0xFE) // Check if valid
|
||||
{
|
||||
if (data[0]==0xff && j==field1packet)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data);
|
||||
rcbcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Illegal caption segment - stop here.\n");
|
||||
maybeextracb = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Theoretically this should not happen, oh well ...
|
||||
// Deal with extra closed captions some DVD have.
|
||||
int ecbcount = 0;
|
||||
while ( maybeextracb && (next_u8(ustream)&0xFE) == 0xFE )
|
||||
{
|
||||
for (int j=0;j<2;j++)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=read_u8(ustream);
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
/* Field 1 and 2 data can be in either order,
|
||||
with marker bytes of \xff and \xfe
|
||||
Since markers can be repeated, use pattern as well */
|
||||
if ((data[0]&0xFE) == 0xFE) // Check if valid
|
||||
{
|
||||
if (data[0]==0xff && j==field1packet)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data);
|
||||
ecbcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Illegal (extra) caption segment - stop here.\n");
|
||||
maybeextracb = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read %d/%d DVD CC blocks\n", rcbcount, ecbcount);
|
||||
}
|
||||
// SCTE 20 user data
|
||||
else if (ud_header[0] == 0x03)
|
||||
{
|
||||
if ((ud_header[1]&0x7F) == 0x01)
|
||||
{
|
||||
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
|
||||
|
||||
stat_scte20ccheaders++;
|
||||
read_bytes(ustream, 2); // "03 01"
|
||||
|
||||
unsigned cc_count = (unsigned int) read_bits(ustream,5);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading %d SCTE 20 CC blocks\n", cc_count);
|
||||
|
||||
unsigned field_number;
|
||||
unsigned cc_data1;
|
||||
unsigned cc_data2;
|
||||
/* unsigned marker; */
|
||||
for (unsigned j=0;j<cc_count;j++)
|
||||
{
|
||||
skip_bits(ustream,2); // priority - unused
|
||||
field_number = (unsigned int) read_bits(ustream,2);
|
||||
skip_bits(ustream,5); // line_offset - unused
|
||||
cc_data1 = (unsigned int) read_bits(ustream,8);
|
||||
cc_data2 = (unsigned int) read_bits(ustream,8);
|
||||
/* marker = (unsigned int)read_bits(ustream,1); // TODO: Add syntax check */
|
||||
|
||||
if (ustream->bitsleft < 0)
|
||||
fatal(EXIT_BUG_BUG, "Oops!");
|
||||
|
||||
// Field_number is either
|
||||
// 0 .. forbiden
|
||||
// 1 .. field 1 (odd)
|
||||
// 2 .. field 2 (even)
|
||||
// 3 .. repeated, from repeat_first_field, effectively field 1
|
||||
if (field_number < 1)
|
||||
{
|
||||
// 0 is invalid
|
||||
cc_data[j*3]=0x00; // Set to invalid
|
||||
cc_data[j*3+1]=0x00;
|
||||
cc_data[j*3+2]=0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Treat field_number 3 as 1
|
||||
field_number = (field_number - 1) & 0x01;
|
||||
// top_field_first also affects to which field the caption
|
||||
// belongs.
|
||||
if(!top_field_first)
|
||||
field_number ^= 0x01;
|
||||
cc_data[j*3]=0x04|(field_number);
|
||||
cc_data[j*3+1]=reverse8(cc_data1);
|
||||
cc_data[j*3+2]=reverse8(cc_data2);
|
||||
}
|
||||
}
|
||||
cc_data[cc_count*3]=0xFF;
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
|
||||
}
|
||||
// reserved - unspecified
|
||||
}
|
||||
// ReplayTV 4000/5000 caption header - parsing information
|
||||
// derived from CCExtract.bdl
|
||||
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|
||||
|| ud_header[0] == 0x99) //ReplayTV 5000
|
||||
&& ud_header[1] == 0x02 )
|
||||
{
|
||||
unsigned char data[3];
|
||||
if (ud_header[0]==0xbb)
|
||||
stat_replay4000headers++;
|
||||
else
|
||||
stat_replay5000headers++;
|
||||
|
||||
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(data);
|
||||
read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data);
|
||||
}
|
||||
// HDTV - see A/53 Part 4 (Video)
|
||||
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
|
||||
{
|
||||
stat_hdtv++;
|
||||
|
||||
read_bytes(ustream, 4); // "47 41 39 34"
|
||||
|
||||
unsigned char type_code = read_u8(ustream);
|
||||
if (type_code==0x03) // CC data.
|
||||
{
|
||||
skip_bits(ustream,1); // reserved
|
||||
unsigned char process_cc_data = (unsigned char) read_bits(ustream,1);
|
||||
skip_bits(ustream,1); // additional_data - unused
|
||||
unsigned char cc_count = (unsigned char) read_bits(ustream,5);
|
||||
read_bytes(ustream, 1); // "FF"
|
||||
if (process_cc_data)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading %d HDTV CC blocks\n", cc_count);
|
||||
|
||||
int proceed = 1;
|
||||
unsigned char *cc_data = read_bytes(ustream, cc_count*3);
|
||||
if (ustream->bitsleft < 0)
|
||||
fatal(EXIT_BUG_BUG, "Not enough for CC captions!");
|
||||
|
||||
// Check for proper marker - This read makes sure that
|
||||
// cc_count*3+1 bytes are read and available in cc_data.
|
||||
if (read_u8(ustream)!=0xFF)
|
||||
proceed=0;
|
||||
|
||||
if (!proceed)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "\rThe following payload is not properly terminated.\n");
|
||||
dump (CCX_DMT_VERBOSE, cc_data, cc_count*3+1, 0, 0);
|
||||
}
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading %d HD CC blocks\n", cc_count);
|
||||
|
||||
// B-frames might be (temporal) before or after the anchor
|
||||
// frame they belong to. Store the buffer until the next anchor
|
||||
// frame occurs. The buffer will be flushed (sorted) in the
|
||||
// picture header (or GOP) section when the next anchor occurs.
|
||||
// Please note we store the current value of the global
|
||||
// fts_now variable (and not get_fts()) as we are going to
|
||||
// re-create the timeline in process_hdcc() (Slightly ugly).
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
|
||||
}
|
||||
}
|
||||
// reserved - additional_cc_data
|
||||
}
|
||||
// DVB closed caption header for Dish Network (Field 1 only) */
|
||||
else if ( !memcmp(ud_header,"\x05\x02", 2 ) )
|
||||
{
|
||||
// Like HDTV (above) Dish Network captions can be stored at each
|
||||
// frame, but maximal two caption blocks per frame and only one
|
||||
// field is stored.
|
||||
// To process this with the HDTV framework we create a "HDTV" caption
|
||||
// format compatible array. Two times 3 bytes plus one for the 0xFF
|
||||
// marker at the end. Pre-init to field 1 and set the 0xFF marker.
|
||||
static unsigned char dishdata[7] = {0x04, 0, 0, 0x04, 0, 0, 0xFF};
|
||||
int cc_count;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
|
||||
|
||||
stat_dishheaders++;
|
||||
|
||||
read_bytes(ustream, 2); // "05 02"
|
||||
|
||||
// The next bytes are like this:
|
||||
// header[2] : ID: 0x04 (MPEG?), 0x03 (H264?)
|
||||
// header[3-4]: Two byte counter (counting (sub-)GOPs?)
|
||||
// header[5-6]: Two bytes, maybe checksum?
|
||||
// header[7]: Pattern type
|
||||
// on B-frame: 0x02, 0x04
|
||||
// on I-/P-frame: 0x05
|
||||
unsigned char id = read_u8(ustream);
|
||||
unsigned dishcount = read_u16(ustream);
|
||||
unsigned something = read_u16(ustream);
|
||||
unsigned char type = read_u8(ustream);
|
||||
dbg_print(CCX_DMT_PARSE, "DN ID: %02X Count: %5u Unknown: %04X Pattern: %X",
|
||||
id, dishcount, something, type);
|
||||
|
||||
unsigned char hi;
|
||||
|
||||
// The following block needs 4 to 6 bytes starting from the
|
||||
// current position
|
||||
unsigned char *dcd = ustream->pos; // dish caption data
|
||||
switch (type)
|
||||
{
|
||||
case 0x02:
|
||||
// Two byte caption - always on B-frame
|
||||
// The following 4 bytes are:
|
||||
// 0 : 0x09
|
||||
// 1-2: caption block
|
||||
// 3 : REPEAT - 02: two bytes
|
||||
// - 04: four bytes (repeat first two)
|
||||
dbg_print(CCX_DMT_PARSE, "\n02 %02X %02X:%02X - R:%02X :",
|
||||
dcd[0], dcd[1], dcd[2], dcd[3]);
|
||||
|
||||
cc_count = 1;
|
||||
dishdata[1]=dcd[1];
|
||||
dishdata[2]=dcd[2];
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
|
||||
|
||||
type=dcd[3]; // repeater (0x02 or 0x04)
|
||||
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
|
||||
if (type==0x04 && hi<32) // repeat (only for non-character pairs)
|
||||
{
|
||||
cc_count = 2;
|
||||
dishdata[3]=0x04; // Field 1
|
||||
dishdata[4]=dishdata[1];
|
||||
dishdata[5]=dishdata[2];
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, ":\n");
|
||||
}
|
||||
|
||||
dishdata[cc_count*3] = 0xFF; // Set end marker
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
|
||||
// Ignore 3 (0x0A, followed by two unknown) bytes.
|
||||
break;
|
||||
case 0x04:
|
||||
// Four byte caption - always on B-frame
|
||||
// The following 5 bytes are:
|
||||
// 0 : 0x09
|
||||
// 1-2: caption block
|
||||
// 3-4: caption block
|
||||
dbg_print(CCX_DMT_PARSE, "\n04 %02X %02X:%02X:%02X:%02X :",
|
||||
dcd[0], dcd[1], dcd[2], dcd[3], dcd[4]);
|
||||
|
||||
cc_count = 2;
|
||||
dishdata[1]=dcd[1];
|
||||
dishdata[2]=dcd[2];
|
||||
|
||||
dishdata[3]=0x04; // Field 1
|
||||
dishdata[4]=dcd[3];
|
||||
dishdata[5]=dcd[4];
|
||||
dishdata[6] = 0xFF; // Set end marker
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
|
||||
// Ignore 4 (0x020A, followed by two unknown) bytes.
|
||||
break;
|
||||
case 0x05:
|
||||
// Buffered caption - always on I-/P-frame
|
||||
// The following six bytes are:
|
||||
// 0 : 0x04
|
||||
// - the following are from previous 0x05 caption header -
|
||||
// 1 : prev dcd[2]
|
||||
// 2-3: prev dcd[3-4]
|
||||
// 4-5: prev dcd[5-6]
|
||||
dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n",
|
||||
dcd[0], dcd[1],
|
||||
(unsigned)dcd[2]*256+dcd[3],
|
||||
dcd[4], dcd[5]);
|
||||
dcd+=6; // Skip these 6 bytes
|
||||
|
||||
// Now one of the "regular" 0x02 or 0x04 captions follows
|
||||
dbg_print(CCX_DMT_PARSE, "%02X %02X %02X:%02X",
|
||||
dcd[0], dcd[1], dcd[2], dcd[3]);
|
||||
|
||||
type=dcd[0]; // Number of caption bytes (0x02 or 0x04)
|
||||
|
||||
cc_count = 1;
|
||||
dishdata[1]=dcd[2];
|
||||
dishdata[2]=dcd[3];
|
||||
|
||||
dcd+=4; // Skip the first 4 bytes.
|
||||
if (type==0x02)
|
||||
{
|
||||
type=dcd[0]; // repeater (0x02 or 0x04)
|
||||
dcd++; // Skip the repeater byte.
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, " - R:%02X :%s", type, debug_608toASC( dishdata, 0) );
|
||||
|
||||
hi = dishdata[1] & 0x7f; // Get only the 7 low bits
|
||||
if (type==0x04 && hi<32)
|
||||
{
|
||||
cc_count = 2;
|
||||
dishdata[3]=0x04; // Field 1
|
||||
dishdata[4]=dishdata[1];
|
||||
dishdata[5]=dishdata[2];
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, ":\n");
|
||||
}
|
||||
dishdata[cc_count*3] = 0xFF; // Set end marker
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, ":%02X:%02X ",
|
||||
dcd[0], dcd[1]);
|
||||
cc_count = 2;
|
||||
dishdata[3]=0x04; // Field 1
|
||||
dishdata[4]=dcd[0];
|
||||
dishdata[5]=dcd[1];
|
||||
dishdata[6] = 0xFF; // Set end marker
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, ":%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now);
|
||||
|
||||
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
|
||||
break;
|
||||
default:
|
||||
// printf ("Unknown?\n");
|
||||
break;
|
||||
} // switch
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data - done\n");
|
||||
}
|
||||
// CEA 608 / aka "Divicom standard", see:
|
||||
// http://www.pixeltools.com/tech_tip_closed_captioning.html
|
||||
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
|
||||
{
|
||||
// Either a documentation or more examples are needed.
|
||||
stat_divicom++;
|
||||
|
||||
unsigned char data[3];
|
||||
|
||||
read_bytes(ustream, 2); // "02 09"
|
||||
read_bytes(ustream, 2); // "80 80" ???
|
||||
read_bytes(ustream, 2); // "02 0A" ???
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data);
|
||||
// This is probably incomplete!
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some other user data
|
||||
// 06 02 ... Seems to be DirectTV
|
||||
dbg_print(CCX_DMT_VERBOSE, "Unrecognized user data:\n");
|
||||
int udatalen = ustream->end - ustream->pos;
|
||||
dump (CCX_DMT_VERBOSE, ustream->pos, (udatalen > 128 ? 128 : udatalen),0 ,0);
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "User data - processed\n");
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
}
|
||||
@@ -1,501 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
|
||||
long FILEBUFFERSIZE = 1024*1024*16; // 16 Mbytes no less. Minimize number of real read calls()
|
||||
LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData = {0};
|
||||
int iResult = 0;
|
||||
#endif
|
||||
|
||||
LLONG getfilesize (int in)
|
||||
{
|
||||
LLONG current=LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in,0,SEEK_END);
|
||||
LSEEK (in,current,SEEK_SET);
|
||||
return length;
|
||||
}
|
||||
|
||||
LLONG gettotalfilessize (void) // -1 if one or more files failed to open
|
||||
{
|
||||
LLONG ts=0;
|
||||
int h;
|
||||
for (int i=0;i<num_input_files;i++)
|
||||
{
|
||||
if (0 == strcmp(inputfile[i],"-")) // Skip stdin
|
||||
continue;
|
||||
#ifdef _WIN32
|
||||
h=OPEN (inputfile[i],O_RDONLY | O_BINARY);
|
||||
#else
|
||||
h=OPEN (inputfile[i],O_RDONLY);
|
||||
#endif
|
||||
if (h==-1)
|
||||
{
|
||||
mprint ("\rUnable to open %s\r\n",inputfile[i]);
|
||||
return -1;
|
||||
}
|
||||
if (!ccx_options.live_stream)
|
||||
ts+=getfilesize (h);
|
||||
close (h);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
void prepare_for_new_file (void)
|
||||
{
|
||||
// Init per file variables
|
||||
min_pts=0x01FFFFFFFFLL; // 33 bit
|
||||
sync_pts=0;
|
||||
pts_set = 0;
|
||||
// inputsize=0; Now responsibility of switch_to_next_file()
|
||||
last_reported_progress=-1;
|
||||
stat_numuserheaders = 0;
|
||||
stat_dvdccheaders = 0;
|
||||
stat_scte20ccheaders = 0;
|
||||
stat_replay5000headers = 0;
|
||||
stat_replay4000headers = 0;
|
||||
stat_dishheaders = 0;
|
||||
stat_hdtv = 0;
|
||||
stat_divicom = 0;
|
||||
total_frames_count = 0;
|
||||
total_pulldownfields = 0;
|
||||
total_pulldownframes = 0;
|
||||
cc_stats[0]=0; cc_stats[1]=0; cc_stats[2]=0; cc_stats[3]=0;
|
||||
false_pict_header=0;
|
||||
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;
|
||||
saw_caption_block=0;
|
||||
past=0;
|
||||
pts_big_change=0;
|
||||
startbytes_pos=0;
|
||||
startbytes_avail=0;
|
||||
init_file_buffer();
|
||||
anchor_hdcc(-1);
|
||||
firstcall = 1;
|
||||
}
|
||||
|
||||
/* Close input file if there is one and let the GUI know */
|
||||
void close_input_file (void)
|
||||
{
|
||||
if (infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
|
||||
{
|
||||
close (infd);
|
||||
infd=-1;
|
||||
activity_input_file_closed();
|
||||
}
|
||||
}
|
||||
|
||||
int init_sockets (void)
|
||||
{
|
||||
static int socket_inited=0;
|
||||
if (!socket_inited)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData = {0};
|
||||
// Initialize Winsock
|
||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
wprintf(L"WSAStartup failed: %d\n", iResult);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
socket_inited=1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close current file and open next one in list -if any- */
|
||||
/* bytesinbuffer is the number of bytes read (in some buffer) that haven't been added
|
||||
to 'past' yet. We provide this number to switch_to_next_file() so a final sanity check
|
||||
can be done */
|
||||
|
||||
int switch_to_next_file (LLONG bytesinbuffer)
|
||||
{
|
||||
if (current_file==-1 || !ccx_options.binary_concat)
|
||||
{
|
||||
memset (PIDs_seen,0,65536*sizeof (int));
|
||||
memset (PIDs_programs,0,65536*sizeof (struct PMT_entry *));
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
if (infd!=-1) // Means we had already processed stdin. So we're done.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
return 0;
|
||||
}
|
||||
infd=0;
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rReading from standard input\n");
|
||||
return 1;
|
||||
}
|
||||
if (ccx_options.input_source==CCX_DS_NETWORK)
|
||||
{
|
||||
if (infd!=-1) // Means we have already bound a socket.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (init_sockets())
|
||||
return 1;
|
||||
infd=socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (IN_MULTICAST(ccx_options.udpaddr))
|
||||
{
|
||||
int on = 1;
|
||||
(void)setsockopt(infd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
|
||||
}
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr=htonl(IN_MULTICAST(ccx_options.udpaddr) ? ccx_options.udpaddr : INADDR_ANY);
|
||||
servaddr.sin_port=htons(ccx_options.udpport);
|
||||
if (bind(infd,(struct sockaddr *)&servaddr,sizeof(servaddr)))
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "bind() failed.");
|
||||
}
|
||||
if (IN_MULTICAST(ccx_options.udpaddr)) {
|
||||
struct ip_mreq group;
|
||||
group.imr_multiaddr.s_addr = htonl(ccx_options.udpaddr);
|
||||
group.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (setsockopt(infd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "cannot join multicast group.");
|
||||
}
|
||||
}
|
||||
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
if (ccx_options.udpaddr == INADDR_ANY)
|
||||
{
|
||||
mprint ("\rReading from UDP socket %u\n",ccx_options.udpport);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl(ccx_options.udpaddr);
|
||||
mprint ("\rReading from UDP socket %s:%u\n", inet_ntoa(in), ccx_options.udpport);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Close current and make sure things are still sane */
|
||||
if (infd!=-1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
close_input_file ();
|
||||
if (inputsize>0 && ((past+bytesinbuffer) < inputsize) && !processed_enough)
|
||||
{
|
||||
mprint("\n\n\n\nATTENTION!!!!!!\n");
|
||||
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
|
||||
inputfile[current_file], current_file, past, inputsize);
|
||||
}
|
||||
if (ccx_options.binary_concat)
|
||||
{
|
||||
total_past+=inputsize;
|
||||
past=0; // Reset always or at the end we'll have double the size
|
||||
}
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
current_file++;
|
||||
if (current_file>=num_input_files)
|
||||
break;
|
||||
|
||||
// The following \n keeps the progress percentage from being overwritten.
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rOpening file: %s\n", inputfile[current_file]);
|
||||
#ifdef _WIN32
|
||||
infd=OPEN (inputfile[current_file],O_RDONLY | O_BINARY);
|
||||
#else
|
||||
infd=OPEN (inputfile[current_file],O_RDONLY);
|
||||
#endif
|
||||
if (infd == -1)
|
||||
mprint ("\rWarning: Unable to open input file [%s]\n", inputfile[current_file]);
|
||||
else
|
||||
{
|
||||
activity_input_file_open (inputfile[current_file]);
|
||||
if (!ccx_options.live_stream)
|
||||
{
|
||||
inputsize = getfilesize (infd);
|
||||
if (!ccx_options.binary_concat)
|
||||
total_inputsize=inputsize;
|
||||
}
|
||||
return 1; // Succeeded
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void position_sanity_check ()
|
||||
{
|
||||
#ifdef SANITY_CHECK
|
||||
if (in!=-1)
|
||||
{
|
||||
LLONG realpos=LSEEK (in,0,SEEK_CUR);
|
||||
if (realpos!=past-filebuffer_pos+bytesinbuffer)
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,past);
|
||||
}
|
||||
}
|
||||
#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 (int offset)
|
||||
{
|
||||
position_sanity_check();
|
||||
if (offset<0)
|
||||
{
|
||||
filebuffer_pos+=offset;
|
||||
if (filebuffer_pos<0)
|
||||
{
|
||||
// We got into the start buffer (hopefully)
|
||||
if (startbytes_pos+filebuffer_pos < 0)
|
||||
{
|
||||
fatal (EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
|
||||
}
|
||||
startbytes_pos+=filebuffer_pos;
|
||||
filebuffer_pos=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read_opt (NULL, offset);
|
||||
position_sanity_check();
|
||||
}
|
||||
}
|
||||
|
||||
void sleepandchecktimeout (time_t start)
|
||||
{
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
|
||||
// real time input from hardware.
|
||||
sleep_secs (1);
|
||||
ccx_options.live_stream=0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ccx_options.live_stream==-1) // Just sleep, no timeout to check
|
||||
{
|
||||
sleep_secs (1);
|
||||
return;
|
||||
}
|
||||
if (time(NULL)>start+ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
|
||||
ccx_options.live_stream=0;
|
||||
else
|
||||
sleep_secs(1);
|
||||
}
|
||||
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes == 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;
|
||||
return;
|
||||
}
|
||||
if (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;
|
||||
}
|
||||
|
||||
if (bytesinbuffer + bytes > FILEBUFFERSIZE)
|
||||
fatal (EXIT_BUG_BUG, "Invalid return_to_buffer() - please submit a bug report.");
|
||||
memmove (filebuffer+bytes,filebuffer,bytesinbuffer);
|
||||
memcpy (filebuffer,buffer,bytes);
|
||||
bytesinbuffer+=bytes;
|
||||
}
|
||||
|
||||
LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
{
|
||||
LLONG copied=0;
|
||||
position_sanity_check();
|
||||
time_t seconds=0;
|
||||
if (ccx_options.live_stream>0)
|
||||
time (&seconds);
|
||||
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
|
||||
{
|
||||
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
|
||||
int eof = (infd==-1);
|
||||
|
||||
while ((!eof || ccx_options.live_stream) && bytes)
|
||||
{
|
||||
if (eof)
|
||||
{
|
||||
// No more data available inmediately, we sleep a while to give time
|
||||
// for the data to come up
|
||||
sleepandchecktimeout (seconds);
|
||||
}
|
||||
size_t ready = bytesinbuffer-filebuffer_pos;
|
||||
if (ready==0) // We really need to read more
|
||||
{
|
||||
if (!ccx_options.buffer_input)
|
||||
{
|
||||
// We got in the buffering code because of the initial buffer for
|
||||
// detection stuff. However we don't want more buffering so
|
||||
// we do the rest directly on the final buffer.
|
||||
int i;
|
||||
do
|
||||
{
|
||||
// No code for network support here, because network is always
|
||||
// buffered - if here, then it must be files.
|
||||
if (buffer!=NULL) // Read
|
||||
{
|
||||
i=read (infd,buffer,bytes);
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
buffer+=i;
|
||||
}
|
||||
else // Seek
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (infd,bytes,SEEK_CUR); // Pos after moving
|
||||
i=(int) (np-op);
|
||||
}
|
||||
if (i==0 && ccx_options.live_stream)
|
||||
{
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
ccx_options.live_stream = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sleepandchecktimeout (seconds);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
copied+=i;
|
||||
bytes-=i;
|
||||
}
|
||||
|
||||
}
|
||||
while ((i || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(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 i;
|
||||
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
|
||||
i=read (infd, filebuffer+keep,FILEBUFFERSIZE-keep);
|
||||
else
|
||||
{
|
||||
socklen_t len = sizeof(cliaddr);
|
||||
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,(struct sockaddr *)&cliaddr,&len);
|
||||
}
|
||||
if( i == -1)
|
||||
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(copied)))
|
||||
eof=1;
|
||||
}
|
||||
filebuffer_pos=keep;
|
||||
bytesinbuffer=(int) i+keep;
|
||||
ready=i;
|
||||
}
|
||||
int copy = (int) (ready>=bytes ? bytes:ready);
|
||||
if (copy)
|
||||
{
|
||||
if (buffer!=NULL)
|
||||
{
|
||||
memcpy (buffer, filebuffer+filebuffer_pos, copy);
|
||||
buffer+=copy;
|
||||
}
|
||||
filebuffer_pos+=copy;
|
||||
bytes-=copy;
|
||||
copied+=copy;
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
else // Read without buffering
|
||||
{
|
||||
|
||||
if (buffer!=NULL)
|
||||
{
|
||||
int i;
|
||||
while (bytes>0 && infd!=-1 &&
|
||||
((i=read(infd,buffer,bytes))!=0 || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(copied))))
|
||||
{
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
else if (i==0)
|
||||
sleepandchecktimeout (seconds);
|
||||
else
|
||||
{
|
||||
copied+=i;
|
||||
bytes-=i;
|
||||
buffer+=i;
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
// return fread(buffer,1,bytes,in);
|
||||
//return FSEEK (in,bytes,SEEK_CUR);
|
||||
while (bytes!=0 && infd!=-1)
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (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(0);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
}
|
||||
@@ -1,826 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "708.h"
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
|
||||
// IMPORTED TRASH INFO, REMOVE
|
||||
extern long num_nal_unit_type_7;
|
||||
extern long num_vcl_hrd;
|
||||
extern long num_nal_hrd;
|
||||
extern long num_jump_in_frames;
|
||||
extern long num_unexpected_sei_length;
|
||||
|
||||
/* General video information */
|
||||
unsigned current_hor_size = 0;
|
||||
unsigned current_vert_size = 0;
|
||||
unsigned current_aspect_ratio = 0;
|
||||
unsigned current_frame_rate = 4; // Assume standard fps, 29.97
|
||||
double current_fps = (double) 30000.0 / 1001; /* 29.97 */ // TODO: Get from framerates_values[] instead
|
||||
LLONG current_pts = 0;
|
||||
unsigned rollover_bits = 0; // The PTS rolls over every 26 hours and that can happen in the middle of a stream.
|
||||
LLONG result; // Number of bytes read/skipped in last read operation
|
||||
int end_of_file=0; // End of file?
|
||||
|
||||
|
||||
const static unsigned char DO_NOTHING[] = {0x80, 0x80};
|
||||
LLONG inbuf = 0; // Number of bytes loaded in buffer
|
||||
int ccx_bufferdatatype = CCX_PES; // Can be RAW, PES, H264 or Hauppage
|
||||
|
||||
int current_tref = 0; // Store temporal reference of current frame
|
||||
enum ccx_frame_type current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
|
||||
// Remember if the last header was valid. Used to suppress too much output
|
||||
// and the expected unrecognized first header for TiVo files.
|
||||
int strangeheader=0;
|
||||
|
||||
unsigned char *filebuffer;
|
||||
LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
extern void *cxx_dvb_context;
|
||||
|
||||
LLONG process_raw_with_field (void);
|
||||
|
||||
// Program stream specific data grabber
|
||||
LLONG ps_getmoredata(void)
|
||||
{
|
||||
int enough = 0;
|
||||
int payload_read = 0;
|
||||
|
||||
static unsigned vpesnum=0;
|
||||
|
||||
unsigned char nextheader[512]; // Next header in PS
|
||||
int falsepack=0;
|
||||
|
||||
// Read and return the next video PES payload
|
||||
do
|
||||
{
|
||||
if (BUFSIZE-inbuf<500)
|
||||
{
|
||||
mprint("Less than 500 left\n");
|
||||
enough=1; // Stop when less than 500 bytes are left in buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read(nextheader,6);
|
||||
past+=result;
|
||||
if (result!=6)
|
||||
{
|
||||
// Consider this the end of the show.
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Search for a header that is not a picture header (nextheader[3]!=0x00)
|
||||
while ( !(nextheader[0]==0x00 && nextheader[1]==0x00
|
||||
&& nextheader[2]==0x01 && nextheader[3]!=0x00) )
|
||||
{
|
||||
if( !strangeheader )
|
||||
{
|
||||
mprint ("\nNot a recognized header. Searching for next header.\n");
|
||||
dump (CCX_DMT_GENERIC_NOTICES, nextheader,6,0,0);
|
||||
// Only print the message once per loop / unrecognized header
|
||||
strangeheader = 1;
|
||||
}
|
||||
|
||||
unsigned char *newheader;
|
||||
// The amount of bytes read into nextheader by the buffered_read above
|
||||
int hlen = 6;
|
||||
// Find first 0x00
|
||||
// If there is a 00 in the first element we need to advance
|
||||
// one step as clearly bytes 1,2,3 are wrong
|
||||
newheader = (unsigned char *) memchr (nextheader+1, 0, hlen-1);
|
||||
if (newheader != NULL )
|
||||
{
|
||||
int atpos = newheader-nextheader;
|
||||
|
||||
memmove (nextheader,newheader,(size_t)(hlen-atpos));
|
||||
buffered_read(nextheader+(hlen-atpos),atpos);
|
||||
past+=result;
|
||||
if (result!=atpos)
|
||||
{
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read(nextheader,hlen);
|
||||
past+=result;
|
||||
if (result!=hlen)
|
||||
{
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (end_of_file)
|
||||
{
|
||||
// No more headers
|
||||
break;
|
||||
}
|
||||
// Found 00-00-01 in nextheader, assume a regular header
|
||||
strangeheader=0;
|
||||
|
||||
// PACK header
|
||||
if ( nextheader[3]==0xBA)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "PACK header\n");
|
||||
buffered_read(nextheader+6,8);
|
||||
past+=result;
|
||||
if (result!=8)
|
||||
{
|
||||
// Consider this the end of the show.
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (nextheader[4]&0xC4)!=0x44 || !(nextheader[6]&0x04)
|
||||
|| !(nextheader[8]&0x04) || !(nextheader[9]&0x01)
|
||||
|| (nextheader[12]&0x03)!=0x03 )
|
||||
{
|
||||
// broken pack header
|
||||
falsepack=1;
|
||||
}
|
||||
// We don't need SCR/SCR_ext
|
||||
int stufflen=nextheader[13]&0x07;
|
||||
|
||||
if (falsepack)
|
||||
{
|
||||
mprint ("Warning: Defective Pack header\n");
|
||||
}
|
||||
|
||||
// If not defect, load stuffing
|
||||
buffered_skip ((int) stufflen);
|
||||
past+=stufflen;
|
||||
// fake a result value as something was skipped
|
||||
result=1;
|
||||
continue;
|
||||
}
|
||||
// Some PES stream
|
||||
else if (nextheader[3]>=0xBB && nextheader[3]<=0xDF)
|
||||
{
|
||||
// System header
|
||||
// nextheader[3]==0xBB
|
||||
// 0xBD Private 1
|
||||
// 0xBE PAdding
|
||||
// 0xBF Private 2
|
||||
// 0xC0-0DF audio
|
||||
|
||||
unsigned headerlen=nextheader[4]<<8 | nextheader[5];
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "non Video PES (type 0x%2X) - len %u\n",
|
||||
nextheader[3], headerlen);
|
||||
|
||||
// The 15000 here is quite arbitrary, the longest packages I
|
||||
// know of are 12302 bytes (Private 1 data in RTL recording).
|
||||
if ( headerlen > 15000 )
|
||||
{
|
||||
mprint("Suspicious non Video PES (type 0x%2X) - len %u\n",
|
||||
nextheader[3], headerlen);
|
||||
mprint("Do not skip over, search for next.\n");
|
||||
headerlen = 2;
|
||||
}
|
||||
|
||||
// Skip over it
|
||||
buffered_skip ((int) headerlen);
|
||||
past+=headerlen;
|
||||
// fake a result value as something was skipped
|
||||
result=1;
|
||||
|
||||
continue;
|
||||
}
|
||||
// Read the next video PES
|
||||
else if ((nextheader[3]&0xf0)==0xe0)
|
||||
{
|
||||
int hlen; // Dummy variable, unused
|
||||
int peslen = read_video_pes_header(nextheader, &hlen, 0);
|
||||
if (peslen < 0)
|
||||
{
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
|
||||
vpesnum++;
|
||||
dbg_print(CCX_DMT_VERBOSE, "PES video packet #%u\n", vpesnum);
|
||||
|
||||
|
||||
int want = (int) ((BUFSIZE-inbuf)>peslen ? peslen : (BUFSIZE-inbuf));
|
||||
|
||||
if (want != peslen) {
|
||||
fatal(EXIT_BUFFER_FULL, "Oh Oh, PES longer than remaining buffer space\n");
|
||||
}
|
||||
if (want == 0) // Found package with header but without payload
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
buffered_read (buffer+inbuf,want);
|
||||
past=past+result;
|
||||
if (result>0) {
|
||||
payload_read+=(int) result;
|
||||
}
|
||||
inbuf+=result;
|
||||
|
||||
if (result!=want) { // Not complete - EOF
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
enough = 1; // We got one PES
|
||||
|
||||
} else {
|
||||
// If we are here this is an unknown header type
|
||||
mprint("Unknown header %02X\n", nextheader[3]);
|
||||
strangeheader=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (result!=0 && !enough && BUFSIZE!=inbuf);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "PES data read: %d\n", payload_read);
|
||||
|
||||
return payload_read;
|
||||
}
|
||||
|
||||
|
||||
// Returns number of bytes read, or zero for EOF
|
||||
LLONG general_getmoredata(void)
|
||||
{
|
||||
int bytesread = 0;
|
||||
int want;
|
||||
|
||||
do
|
||||
{
|
||||
want = (int) (BUFSIZE-inbuf);
|
||||
buffered_read (buffer+inbuf,want); // This is a macro.
|
||||
// 'result' HAS the number of bytes read
|
||||
past=past+result;
|
||||
inbuf+=result;
|
||||
bytesread+=(int) result;
|
||||
} while (result!=0 && result!=want);
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
// Hexadecimal dump process
|
||||
void processhex (char *filename)
|
||||
{
|
||||
size_t max=(size_t) inputsize+1; // Enough for the whole thing. Hex dumps are small so we can be lazy here
|
||||
char *line=(char *) malloc (max);
|
||||
/* const char *mpeg_header="00 00 01 b2 43 43 01 f8 "; // Always present */
|
||||
FILE *fr = fopen (filename, "rt");
|
||||
unsigned char *bytes=NULL;
|
||||
unsigned byte_count=0;
|
||||
int warning_shown=0;
|
||||
while(fgets(line, max-1, fr) != NULL)
|
||||
{
|
||||
char *c1, *c2=NULL; // Positions for first and second colons
|
||||
/* int len; */
|
||||
long timing;
|
||||
if (line[0]==';') // Skip comments
|
||||
continue;
|
||||
c1=strchr (line,':');
|
||||
if (c1) c2=strchr (c1+1,':');
|
||||
if (!c2) // Line doesn't contain what we want
|
||||
continue;
|
||||
*c1=0;
|
||||
*c2=0;
|
||||
/* len=atoi (line); */
|
||||
timing=atol (c1+2)*(MPEG_CLOCK_FREQ/1000);
|
||||
current_pts=timing;
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
c2++;
|
||||
/*
|
||||
if (strlen (c2)==8)
|
||||
{
|
||||
unsigned char high1=c2[1];
|
||||
unsigned char low1=c2[2];
|
||||
int value1=hex2int (high1,low1);
|
||||
unsigned char high2=c2[4];
|
||||
unsigned char low2=c2[5];
|
||||
int value2=hex2int (high2,low2);
|
||||
buffer[0]=value1;
|
||||
buffer[1]=value2;
|
||||
inbuf=2;
|
||||
process_raw();
|
||||
continue;
|
||||
}
|
||||
if (strlen (c2)<=(strlen (mpeg_header)+1))
|
||||
continue; */
|
||||
c2++; // Skip blank
|
||||
/*
|
||||
if (strncmp (c2,mpeg_header,strlen (mpeg_header))) // No idea how to deal with this.
|
||||
{
|
||||
if (!warning_shown)
|
||||
{
|
||||
warning_shown=1;
|
||||
mprint ("\nWarning: This file contains data I can't process: Please submit .hex for analysis!\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// OK, seems like a decent chunk of CCdata.
|
||||
c2+=strlen (mpeg_header);
|
||||
*/
|
||||
byte_count=strlen (c2)/3;
|
||||
/*
|
||||
if (atoi (line)!=byte_count+strlen (mpeg_header)/3) // Number of bytes reported don't match actual contents
|
||||
continue;
|
||||
*/
|
||||
if (atoi (line)!=byte_count) // Number of bytes reported don't match actual contents
|
||||
continue;
|
||||
if (!byte_count) // Nothing to get from this line except timing info, already done.
|
||||
continue;
|
||||
bytes=(unsigned char *) malloc (byte_count);
|
||||
if (!bytes)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Out of memory.\n");
|
||||
unsigned char *bytes=(unsigned char *) malloc (byte_count);
|
||||
for (unsigned i=0;i<byte_count;i++)
|
||||
{
|
||||
unsigned char high=c2[0];
|
||||
unsigned char low=c2[1];
|
||||
int value=hex2int (high,low);
|
||||
if (value==-1)
|
||||
fatal (EXIT_FAILURE, "Incorrect format, unexpected non-hex string.");
|
||||
bytes[i]=value;
|
||||
c2+=3;
|
||||
}
|
||||
memcpy (buffer, bytes, byte_count);
|
||||
inbuf=byte_count;
|
||||
process_raw();
|
||||
continue;
|
||||
// New wtv format, everything else hopefully obsolete
|
||||
|
||||
int ok=0; // Were we able to process the line?
|
||||
// Attempt to detect how the data is encoded.
|
||||
// Case 1 (seen in all elderman's samples):
|
||||
// 18 : 467 : 00 00 01 b2 43 43 01 f8 03 42 ff fd 54 80 fc 94 2c ff
|
||||
// Always 03 after header, then something unknown (seen 42, 43, c2, c3...),
|
||||
// then ff, then data with field info, and terminated with ff.
|
||||
if (byte_count>3 && bytes[0]==0x03 &&
|
||||
bytes[2]==0xff && bytes[byte_count-1]==0xff)
|
||||
{
|
||||
ok=1;
|
||||
for (unsigned i=3; i<byte_count-2; i+=3)
|
||||
{
|
||||
inbuf=3;
|
||||
buffer[0]=bytes[i];
|
||||
buffer[1]=bytes[i+1];
|
||||
buffer[2]=bytes[i+2];
|
||||
process_raw_with_field();
|
||||
}
|
||||
}
|
||||
// Case 2 (seen in P2Pfiend samples):
|
||||
// Seems to match McPoodle's descriptions on DVD encoding
|
||||
else
|
||||
{
|
||||
unsigned char magic=bytes[0];
|
||||
/* unsigned extra_field_flag=magic&1; */
|
||||
unsigned caption_count=((magic>>1)&0x1F);
|
||||
unsigned filler=((magic>>6)&1);
|
||||
/* unsigned pattern=((magic>>7)&1); */
|
||||
int always_ff=1;
|
||||
int current_field=0;
|
||||
if (filler==0 && caption_count*6==byte_count-1) // Note that we are ignoring the extra field for now...
|
||||
{
|
||||
ok=1;
|
||||
for (unsigned i=1; i<byte_count-2; i+=3)
|
||||
if (bytes[i]!=0xff)
|
||||
{
|
||||
// If we only find FF in the first byte then either there's only field 1 data, OR
|
||||
// there's alternating field 1 and field 2 data. Don't know how to tell apart. For now
|
||||
// let's assume that always FF means alternating.
|
||||
always_ff=0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i=1; i<byte_count-2; i+=3)
|
||||
{
|
||||
inbuf=3;
|
||||
if (always_ff) // Try to tell apart the fields based on the pattern field.
|
||||
{
|
||||
buffer[0]=current_field | 4; // | 4 to enable the 'valid' bit
|
||||
current_field = !current_field;
|
||||
}
|
||||
else
|
||||
buffer[0]=bytes[i];
|
||||
|
||||
buffer[1]=bytes[i+1];
|
||||
buffer[2]=bytes[i+2];
|
||||
process_raw_with_field();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok && !warning_shown)
|
||||
{
|
||||
warning_shown=1;
|
||||
mprint ("\nWarning: This file contains data I can't process: Please submit .hex for analysis!\n");
|
||||
}
|
||||
free (bytes);
|
||||
}
|
||||
fclose(fr);
|
||||
}
|
||||
|
||||
// Raw file process
|
||||
void raw_loop ()
|
||||
{
|
||||
LLONG got;
|
||||
LLONG processed;
|
||||
|
||||
current_pts = 90; // Pick a valid PTS time
|
||||
pts_set = 1;
|
||||
set_fts(); // Now set the FTS related variables
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
|
||||
do
|
||||
{
|
||||
inbuf=0;
|
||||
|
||||
got=general_getmoredata();
|
||||
|
||||
if (got == 0) // Shortcircuit if we got nothing to process
|
||||
break;
|
||||
|
||||
processed=process_raw();
|
||||
|
||||
int ccblocks = cb_field1;
|
||||
current_pts += cb_field1*1001/30*(MPEG_CLOCK_FREQ/1000);
|
||||
set_fts(); // Now set the FTS related variables including fts_max
|
||||
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s incl. %d CB\n",
|
||||
print_mstime(get_fts()), ccblocks);
|
||||
|
||||
if (processed<got)
|
||||
{
|
||||
mprint ("BUG BUG\n");
|
||||
}
|
||||
}
|
||||
while (inbuf);
|
||||
}
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (three byte packets, the first being the field).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw_with_field (void)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=0x04; // Field 1
|
||||
current_field=1;
|
||||
|
||||
for (unsigned long i=0; i<inbuf; i=i+3)
|
||||
{
|
||||
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
|
||||
{
|
||||
// Skip broadcast header
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0]=buffer[i];
|
||||
data[1]=buffer[i+1];
|
||||
data[2]=buffer[i+2];
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (two byte packets).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw (void)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=0x04; // Field 1
|
||||
current_field=1;
|
||||
|
||||
for (unsigned long i=0; i<inbuf; i=i+2)
|
||||
{
|
||||
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
|
||||
{
|
||||
// Skip broadcast header
|
||||
}
|
||||
else
|
||||
{
|
||||
data[1]=buffer[i];
|
||||
data[2]=buffer[i+1];
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
|
||||
void general_loop(void)
|
||||
{
|
||||
LLONG overlap=0;
|
||||
LLONG pos = 0; /* Current position in buffer */
|
||||
inbuf = 0; // No data yet
|
||||
|
||||
end_of_file = 0;
|
||||
current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
|
||||
while (!end_of_file && !processed_enough)
|
||||
{
|
||||
/* Get rid of the bytes we already processed */
|
||||
overlap=inbuf-pos;
|
||||
if ( pos != 0 ) {
|
||||
// Only when needed as memmove has been seen crashing
|
||||
// for dest==source and n >0
|
||||
memmove (buffer,buffer+pos,(size_t) (inbuf-pos));
|
||||
inbuf-=pos;
|
||||
}
|
||||
pos = 0;
|
||||
|
||||
// GET MORE DATA IN BUFFER
|
||||
LLONG i;
|
||||
position_sanity_check();
|
||||
switch (stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
i = general_getmoredata();
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
i = ts_getmoredata();
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
i = ps_getmoredata();
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
i = asf_getmoredata();
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
i = wtv_getmoredata();
|
||||
break;
|
||||
default:
|
||||
fatal(EXIT_BUG_BUG, "Impossible stream_mode");
|
||||
}
|
||||
|
||||
position_sanity_check();
|
||||
if (fh_out_elementarystream!=NULL)
|
||||
fwrite (buffer+overlap,1,(size_t) (inbuf-overlap),fh_out_elementarystream);
|
||||
|
||||
if (i==0)
|
||||
{
|
||||
end_of_file = 1;
|
||||
memset (buffer+inbuf, 0, (size_t) (BUFSIZE-inbuf)); /* Clear buffer at the end */
|
||||
}
|
||||
|
||||
if (inbuf == 0)
|
||||
{
|
||||
/* Done: Get outta here */
|
||||
break;
|
||||
}
|
||||
|
||||
LLONG got; // Means 'consumed' from buffer actually
|
||||
|
||||
static LLONG last_pts = 0x01FFFFFFFFLL;
|
||||
|
||||
if (ccx_options.hauppauge_mode)
|
||||
{
|
||||
got = process_raw_with_field();
|
||||
if (pts_set)
|
||||
set_fts(); // Try to fix timing from TS data
|
||||
}
|
||||
else if(ccx_bufferdatatype == CCX_DVB_SUBTITLE)
|
||||
{
|
||||
int out_size = 0;
|
||||
dvbsub_decode(cxx_dvb_context,NULL,&out_size,buffer + 2,inbuf);
|
||||
set_fts();
|
||||
got = inbuf;
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PES)
|
||||
{
|
||||
got = process_m2v (buffer, inbuf);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_TELETEXT)
|
||||
{
|
||||
// Dispatch to Petr Kutalek 's telxcc.
|
||||
tlt_process_pes_packet (buffer, (uint16_t) inbuf);
|
||||
got = inbuf;
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PRIVATE_MPEG2_CC)
|
||||
{
|
||||
got = inbuf; // Do nothing. Still don't know how to process it
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_RAW) // Raw two byte 608 data from DVR-MS/ASF
|
||||
{
|
||||
// The asf_getmoredata() loop sets current_pts when possible
|
||||
if (pts_set == 0)
|
||||
{
|
||||
mprint("DVR-MS/ASF file without useful time stamps - count blocks.\n");
|
||||
// Otherwise rely on counting blocks
|
||||
current_pts = 12345; // Pick a valid PTS time
|
||||
pts_set = 1;
|
||||
}
|
||||
|
||||
if (current_pts != last_pts)
|
||||
{
|
||||
// Only initialize the FTS values and reset the cb
|
||||
// counters when the PTS is different. This happens frequently
|
||||
// with ASF files.
|
||||
|
||||
if (min_pts==0x01FFFFFFFFLL)
|
||||
{
|
||||
// First call
|
||||
fts_at_gop_start = 0;
|
||||
}
|
||||
else
|
||||
fts_at_gop_start = get_fts();
|
||||
|
||||
frames_since_ref_time = 0;
|
||||
set_fts();
|
||||
|
||||
last_pts = current_pts;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
|
||||
got = process_raw();
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_H264) // H.264 data from TS file
|
||||
{
|
||||
got = process_avc(buffer, inbuf);
|
||||
}
|
||||
else
|
||||
fatal(EXIT_BUG_BUG, "Unknown data type!");
|
||||
|
||||
if (got>inbuf)
|
||||
{
|
||||
mprint ("BUG BUG\n");
|
||||
}
|
||||
pos+=got;
|
||||
|
||||
if (ccx_options.live_stream)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int th=cur_sec/10;
|
||||
if (last_reported_progress!=th)
|
||||
{
|
||||
activity_progress (-1,cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = th;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (total_inputsize>255) // Less than 255 leads to division by zero below.
|
||||
{
|
||||
int progress = (int) ((((total_past+past)>>8)*100)/(total_inputsize>>8));
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
LLONG t=get_fts();
|
||||
if (!t && global_timestamp_inited)
|
||||
t=global_timestamp-min_global_timestamp;
|
||||
int cur_sec = (int) (t / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
position_sanity_check();
|
||||
}
|
||||
// Flush remaining HD captions
|
||||
if (has_ccdata_buffered)
|
||||
process_hdcc();
|
||||
|
||||
if (total_past!=total_inputsize && ccx_options.binary_concat && !processed_enough)
|
||||
{
|
||||
mprint("\n\n\n\nATTENTION!!!!!!\n");
|
||||
mprint("Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
|
||||
inputfile[current_file], current_file, past, inputsize);
|
||||
}
|
||||
mprint ("\nNumber of NAL_type_7: %ld\n",num_nal_unit_type_7);
|
||||
mprint ("Number of VCL_HRD: %ld\n",num_vcl_hrd);
|
||||
mprint ("Number of NAL HRD: %ld\n",num_nal_hrd);
|
||||
mprint ("Number of jump-in-frames: %ld\n",num_jump_in_frames);
|
||||
mprint ("Number of num_unexpected_sei_length: %ld", num_unexpected_sei_length);
|
||||
}
|
||||
|
||||
// Raw caption with FTS file process
|
||||
void rcwt_loop( void )
|
||||
{
|
||||
static unsigned char *parsebuf;
|
||||
static long parsebufsize = 1024;
|
||||
|
||||
// As BUFSIZE is a macro this is just a reminder
|
||||
if (BUFSIZE < (3*0xFFFF + 10))
|
||||
fatal (EXIT_BUG_BUG, "BUFSIZE too small for RCWT caption block.\n");
|
||||
|
||||
// Generic buffer to hold some data
|
||||
parsebuf = (unsigned char*)malloc(1024);
|
||||
|
||||
|
||||
LLONG currfts;
|
||||
uint16_t cbcount = 0;
|
||||
|
||||
int bread = 0; // Bytes read
|
||||
|
||||
buffered_read(parsebuf,11);
|
||||
past+=result;
|
||||
bread+=(int) result;
|
||||
if (result!=11)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
end_of_file=1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Expecting RCWT header
|
||||
if( !memcmp(parsebuf, "\xCC\xCC\xED", 3 ) )
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "\nRCWT header\n");
|
||||
dbg_print(CCX_DMT_PARSE, "File created by %02X version %02X%02X\nFile format revision: %02X%02X\n",
|
||||
parsebuf[3], parsebuf[4], parsebuf[5],
|
||||
parsebuf[6], parsebuf[7]);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal(EXIT_MISSING_RCWT_HEADER, "Missing RCWT header. Abort.\n");
|
||||
}
|
||||
|
||||
// Initialize first time. As RCWT files come with the correct FTS the
|
||||
// initial (minimal) time needs to be set to 0.
|
||||
current_pts = 0;
|
||||
pts_set=1;
|
||||
set_fts(); // Now set the FTS related variables
|
||||
|
||||
// Loop until no more data is found
|
||||
while(1)
|
||||
{
|
||||
// Read the data header
|
||||
buffered_read(parsebuf,10);
|
||||
past+=result;
|
||||
bread+=(int) result;
|
||||
|
||||
if (result!=10)
|
||||
{
|
||||
if (result!=0)
|
||||
mprint("Premature end of file!\n");
|
||||
|
||||
// We are done
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
currfts = *((LLONG*)(parsebuf));
|
||||
cbcount = *((uint16_t*)(parsebuf+8));
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "RCWT data header FTS: %s blocks: %u\n",
|
||||
print_mstime(currfts), cbcount);
|
||||
|
||||
if ( cbcount > 0 )
|
||||
{
|
||||
if ( cbcount*3 > parsebufsize) {
|
||||
parsebuf = (unsigned char*)realloc(parsebuf, cbcount*3);
|
||||
if (!parsebuf)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
parsebufsize = cbcount*3;
|
||||
}
|
||||
buffered_read(parsebuf,cbcount*3);
|
||||
past+=result;
|
||||
bread+=(int) result;
|
||||
if (result!=cbcount*3)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
end_of_file=1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Process the data
|
||||
current_pts = currfts*(MPEG_CLOCK_FREQ/1000);
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts(); // Now set the FTS related variables
|
||||
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
|
||||
for (int j=0; j<cbcount*3; j=j+3)
|
||||
{
|
||||
do_cb(parsebuf+j);
|
||||
}
|
||||
}
|
||||
} // end while(1)
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "Processed %d bytes\n", bread);
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/setup.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_AVILIB
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
@@ -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:
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/network.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/odf_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/tools.h>
|
||||
|
||||
|
||||
|
||||
@@ -227,7 +227,8 @@ enum
|
||||
GF_ISOM_SUBTYPE_LSR1 = GF_4CC( 'l', 's', 'r', '1' ),
|
||||
|
||||
/* CAPTIONS */
|
||||
GF_ISOM_SUBTYPE_C608 = GF_4CC ('c', '6', '0', '8' )
|
||||
GF_ISOM_SUBTYPE_C608 = GF_4CC( 'c', '6', '0', '8' ),
|
||||
GF_ISOM_SUBTYPE_C708 = GF_4CC( 'c', '7', '0', '8' )
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/odf_dev.h>
|
||||
|
||||
#ifndef GPAC_MINIMAL_ODF
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/network.h>
|
||||
#ifndef _WIN32
|
||||
@@ -398,23 +398,6 @@ GF_ISOFile *gf_isom_open_file(const char *fileName, u32 OpenMode, const char *tm
|
||||
return mov;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
void gf_utc_time_since_1970(u32 *sec, u32 *msec)
|
||||
{
|
||||
#if defined (WIN32) && !defined(_WIN32_WCE)
|
||||
struct _timeb tb;
|
||||
_ftime( &tb );
|
||||
*sec = (u32) tb.time;
|
||||
*msec = tb.millitm;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
*sec = tv.tv_sec;
|
||||
*msec = tv.tv_usec/1000;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
u64 gf_isom_get_mp4time()
|
||||
{
|
||||
u32 calctime, msec;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
@@ -1736,15 +1736,15 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min
|
||||
chunk_dur += dur;
|
||||
stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size);
|
||||
chunk_size += size;
|
||||
|
||||
|
||||
}
|
||||
if (dmin>chunk_dur) dmin = chunk_dur;
|
||||
if (dmax<chunk_dur) dmax = chunk_dur;
|
||||
davg += chunk_dur;
|
||||
if (smin>chunk_size) smin = chunk_size;
|
||||
if (smax<chunk_size) smax = chunk_size;
|
||||
savg += chunk_dur;
|
||||
|
||||
savg += chunk_size;
|
||||
|
||||
tot_chunks ++;
|
||||
sample_idx += stsc->entries[i].samplesPerChunk;
|
||||
if (i+1==stsc->nb_entries) break;
|
||||
@@ -1752,8 +1752,10 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min
|
||||
if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break;
|
||||
}
|
||||
}
|
||||
if (tot_chunks) davg /= tot_chunks;
|
||||
|
||||
if (tot_chunks) {
|
||||
davg /= tot_chunks;
|
||||
savg /= tot_chunks;
|
||||
}
|
||||
if (dur_min) *dur_min = dmin;
|
||||
if (dur_avg) *dur_avg = (u32) davg;
|
||||
if (dur_max) *dur_max = dmax;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
@@ -333,10 +333,12 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp,
|
||||
//divided into the original and the edition files
|
||||
if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) {
|
||||
//same as last call in read mode
|
||||
if (!mdia->information->dataHandler || (mdia->information->dataEntryIndex != dataRefIndex)) {
|
||||
if (!mdia->information->dataHandler) {
|
||||
e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
|
||||
if (e) return e;
|
||||
}
|
||||
if (mdia->information->dataEntryIndex != dataRefIndex)
|
||||
mdia->information->dataEntryIndex = dataRefIndex;
|
||||
} else {
|
||||
e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
|
||||
if (e) return e;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gpac/isomedia.h>
|
||||
#include "../ccextractor.h"
|
||||
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length); // From avc_functions.c
|
||||
void set_fts(void); // From timing.c
|
||||
#include "lib_ccx.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_mp4.h"
|
||||
#include "activity.h"
|
||||
#include "ccx_dtvcc.h"
|
||||
|
||||
static short bswap16(short v)
|
||||
{
|
||||
@@ -24,16 +27,17 @@ static struct {
|
||||
unsigned type[32];
|
||||
}s_nalu_stats;
|
||||
|
||||
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
|
||||
static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
|
||||
{
|
||||
int status = 0;
|
||||
u32 i;
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
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; )
|
||||
{
|
||||
@@ -59,19 +63,23 @@ static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
|
||||
temp_debug=0;
|
||||
|
||||
if (nal_length>0)
|
||||
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length);
|
||||
do_NAL (dec_ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
i += nal_length;
|
||||
} // outer for
|
||||
assert(i == s->dataLength);
|
||||
|
||||
return status;
|
||||
}
|
||||
static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count;
|
||||
|
||||
int status;
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -79,43 +87,46 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
|
||||
status = 0;
|
||||
|
||||
for(i = 0; i < sample_count; i++){
|
||||
for(i = 0; i < sample_count; i++)
|
||||
{
|
||||
u32 sdi;
|
||||
|
||||
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
|
||||
if (s!=NULL) {
|
||||
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
if (s!=NULL)
|
||||
{
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
process_m2v ((unsigned char *) s->data,s->dataLength);
|
||||
process_m2v (dec_ctx, (unsigned char *) s->data,s->dataLength, sub);
|
||||
gf_isom_sample_del(&s);
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count, last_sdi = 0;
|
||||
int status;
|
||||
GF_AVCConfig* c = NULL;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -123,19 +134,24 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
|
||||
status = 0;
|
||||
|
||||
for(i = 0; i < sample_count; i++){
|
||||
for(i = 0; i < sample_count; i++)
|
||||
{
|
||||
u32 sdi;
|
||||
|
||||
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
|
||||
|
||||
if(s != NULL){
|
||||
if(sdi != last_sdi){
|
||||
if(c != NULL){
|
||||
if(s != NULL)
|
||||
{
|
||||
if(sdi != last_sdi)
|
||||
{
|
||||
if(c != NULL)
|
||||
{
|
||||
gf_odf_avc_cfg_del(c);
|
||||
c = NULL;
|
||||
}
|
||||
|
||||
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL){
|
||||
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL)
|
||||
{
|
||||
gf_isom_sample_del(&s);
|
||||
status = -1;
|
||||
break;
|
||||
@@ -144,27 +160,29 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
last_sdi = sdi;
|
||||
}
|
||||
|
||||
status = process_avc_sample(timescale, c, s);
|
||||
status = process_avc_sample(ctx, timescale, c, s, sub);
|
||||
|
||||
gf_isom_sample_del(&s);
|
||||
|
||||
if(status != 0){
|
||||
if(status != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
}
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
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){
|
||||
if(c != NULL)
|
||||
{
|
||||
gf_odf_avc_cfg_del(c);
|
||||
c = NULL;
|
||||
}
|
||||
@@ -172,6 +190,87 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count)
|
||||
{
|
||||
unsigned char *data = ccdp_atom_content;
|
||||
|
||||
if (len < 4)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected size of cdp\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int cdp_id = (data[0] << 8) | data[1];
|
||||
if (cdp_id != 0x9669)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected header %hhX %hhX\n", data[0], data[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
unsigned int cdp_data_count = data[0];
|
||||
unsigned int cdp_frame_rate = data[1] >> 4; //frequency could be calculated
|
||||
if (cdp_data_count != len + 2)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected data length %u %u\n", cdp_data_count, len + 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
unsigned int cdp_flags = data[0];
|
||||
unsigned int cdp_counter = (data[1] << 8) | data[2];
|
||||
|
||||
data += 3;
|
||||
len -= 3;
|
||||
|
||||
unsigned int cdp_timecode_added = (cdp_flags & 0x80) >> 7;
|
||||
unsigned int cdp_data_added = (cdp_flags & 0x40) >> 6;
|
||||
|
||||
if (!cdp_data_added)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: packet without data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cdp_timecode_added)
|
||||
{
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (data[0] != CDP_SECTION_DATA)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: cdp_data_section byte not found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*cc_count = (unsigned int) (data[1] & 0x1F);
|
||||
|
||||
if (*cc_count != 10 && *cc_count != 20 && *cc_count != 25 && *cc_count != 30)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", *cc_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
if ((*cc_count) * 3 > len)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, *cc_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)(cdp_counter);
|
||||
(void)(cdp_frame_rate);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Here is application algorithm described in some C-like pseudo code:
|
||||
main(){
|
||||
@@ -180,19 +279,29 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
|
||||
if track is AVC track
|
||||
for each sample in track
|
||||
for each NALU in sample
|
||||
send to avc.cpp for processing
|
||||
send to avc.c for processing
|
||||
close(media)
|
||||
}
|
||||
|
||||
*/
|
||||
int processmp4 (char *file)
|
||||
int processmp4 (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;
|
||||
|
||||
mprint("opening \'%s\': ", file);
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
|
||||
|
||||
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL){
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
memset(&dec_sub,0,sizeof(dec_sub));
|
||||
mprint("opening \'%s\': ", file);
|
||||
#ifdef MP4_DEBUG
|
||||
gf_log_set_tool_level(GF_LOG_CONTAINER,GF_LOG_DEBUG);
|
||||
#endif
|
||||
|
||||
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL)
|
||||
{
|
||||
mprint("failed to open\n");
|
||||
return -2;
|
||||
}
|
||||
@@ -212,64 +321,84 @@ int processmp4 (char *file)
|
||||
(unsigned char) ((type>>16)%0x100),(unsigned char) ((type>>8)%0x100),(unsigned char) (type%0x100),
|
||||
(unsigned char) (subtype>>24%0x100),
|
||||
(unsigned char) ((subtype>>16)%0x100),(unsigned char) ((subtype>>8)%0x100),(unsigned char) (subtype%0x100));
|
||||
if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608)
|
||||
cc_track_count++;
|
||||
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
|
||||
if ((type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) ||
|
||||
(type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C708))
|
||||
cc_track_count++;
|
||||
if (type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
|
||||
avc_track_count++;
|
||||
}
|
||||
|
||||
for(i = 0; i < track_count; i++){
|
||||
mprint("mp4: found %u tracks: %u avc and %u cc\n", track_count, avc_track_count, cc_track_count);
|
||||
|
||||
for(i = 0; i < track_count; i++)
|
||||
{
|
||||
const u32 type = gf_isom_get_media_type(f, i + 1);
|
||||
const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1);
|
||||
|
||||
|
||||
if ( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_XDVB)
|
||||
{
|
||||
if (cc_track_count && !ccx_options.mp4vidtrack)
|
||||
if (cc_track_count && !cfg->mp4vidtrack)
|
||||
continue;
|
||||
if(process_xdvb_track(file, f, i + 1) != 0){
|
||||
if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
} }
|
||||
}
|
||||
if(dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
|
||||
{
|
||||
if (cc_track_count && !ccx_options.mp4vidtrack)
|
||||
{
|
||||
if (cc_track_count && !cfg->mp4vidtrack)
|
||||
continue;
|
||||
GF_AVCConfig *cnf = gf_isom_avc_config_get(f,i+1,1);
|
||||
if (cnf!=NULL)
|
||||
{
|
||||
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
|
||||
{
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL ((unsigned char *) seqcnf->data,seqcnf->size);
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL (dec_ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
}
|
||||
}
|
||||
|
||||
if(process_avc_track(file, f, i + 1) != 0){
|
||||
if(process_avc_track(ctx, file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
if(dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608)
|
||||
{
|
||||
if (avc_track_count && ccx_options.mp4vidtrack)
|
||||
if (type == GF_ISOM_MEDIA_CAPTIONS &&
|
||||
(subtype == GF_ISOM_SUBTYPE_C608 || subtype == GF_ISOM_SUBTYPE_C708))
|
||||
{
|
||||
if (avc_track_count && cfg->mp4vidtrack)
|
||||
continue;
|
||||
|
||||
/* unsigned num_streams = gf_isom_get_sample_description_count (f,i+1); */
|
||||
#ifdef MP4_DEBUG
|
||||
unsigned num_streams = gf_isom_get_sample_description_count (f,i+1);
|
||||
#endif
|
||||
unsigned num_samples = gf_isom_get_sample_count (f,i+1);
|
||||
|
||||
|
||||
u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet
|
||||
u32 timescale = gf_isom_get_media_timescale(f,i+1);
|
||||
// u64 duration = gf_isom_get_media_duration(f,i+1);
|
||||
/* mprint ("%u streams\n",num_streams);
|
||||
#ifdef MP4_DEBUG
|
||||
u64 duration = gf_isom_get_media_duration(f,i+1);
|
||||
mprint ("%u streams\n",num_streams);
|
||||
mprint ("%u sample counts\n",num_samples);
|
||||
mprint ("%u timescale\n",(unsigned) timescale);
|
||||
mprint ("%u duration\n",(unsigned) duration); */
|
||||
mprint ("%u duration\n",(unsigned) duration);
|
||||
#endif
|
||||
for (unsigned k = 0; k <num_samples; k++)
|
||||
{
|
||||
u32 StreamDescriptionIndex;
|
||||
u32 StreamDescriptionIndex;
|
||||
GF_ISOSample *sample= gf_isom_get_sample(f, i+1, k+1, &StreamDescriptionIndex);
|
||||
if (ProcessingStreamDescriptionIndex && ProcessingStreamDescriptionIndex!=StreamDescriptionIndex)
|
||||
{
|
||||
@@ -281,51 +410,129 @@ int processmp4 (char *file)
|
||||
ProcessingStreamDescriptionIndex=StreamDescriptionIndex;
|
||||
if (sample==NULL)
|
||||
continue;
|
||||
// mprint ("Data length: %lu\n",sample->dataLength);
|
||||
/* const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale; */
|
||||
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();
|
||||
#ifdef DEBUG
|
||||
mprint ("Data length: %lu\n",sample->dataLength);
|
||||
const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale;
|
||||
#endif
|
||||
set_current_pts(dec_ctx->timing, (sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale);
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
// Change by Willem
|
||||
|
||||
// Apparently the first 4 bytes are the sample length, and then comes 'cdat', and then the data itself
|
||||
/*if (sample->dataLength>8 && strncmp (sample->data+4, "cdat", 4)==0)
|
||||
int atomStart = 0;
|
||||
// process Atom by Atom
|
||||
while (atomStart < sample->dataLength)
|
||||
{
|
||||
//dump (256,( unsigned char *) sample->data+8,sample->dataLength-8,0, 1);
|
||||
process608((const unsigned char *)sample->data + 8, sample->dataLength - 8, &context_cc608_field_1);
|
||||
}*/
|
||||
|
||||
// Based on https://developer.apple.com/library/prerelease/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW87
|
||||
// An atom consists of the Atom size, Atom Type and the data.
|
||||
// First 4 bytes are length in bytes of this atom
|
||||
// byte 5-8 are the atom type. Should be either cdat or cdt2
|
||||
// byte 9-x are actual data.
|
||||
// This means a sample can contain multiple atoms!
|
||||
if (sample->dataLength > 8 && strncmp(sample->data + 4, "cdat", 4) == 0){ // The format of the closed captioning sample data is a sequence of one or more atoms, one of which must be a 'cdat' atom.
|
||||
int atomStart = 0;
|
||||
// process Atom by Atom
|
||||
while (atomStart < sample->dataLength){
|
||||
unsigned int atomLength = (unsigned char)sample->data[atomStart] << 24 | (unsigned char)sample->data[atomStart + 1] << 16 | (unsigned char)sample->data[atomStart + 2] << 8 | (unsigned char)sample->data[atomStart + 3];
|
||||
if (atomLength > 8 && (strncmp(sample->data + atomStart + 4, "cdat", 4) == 0 || strncmp(sample->data + atomStart + 4, "cdt2", 4) == 0)){
|
||||
dump(256, (unsigned char *)sample->data +atomStart+ 8, atomLength - 8, 0, 1);
|
||||
process608((const unsigned char *)sample->data + atomStart + 8, atomLength - 8, &context_cc608_field_1);
|
||||
}
|
||||
atomStart += atomLength;
|
||||
char *data = sample->data + atomStart;
|
||||
unsigned int atomLength = RB32(data);
|
||||
if (atomLength < 8 || atomLength > sample->dataLength)
|
||||
{
|
||||
mprint ("Invalid atom length. Atom length: %u, should be: %u\n", atomLength, sample->dataLength);
|
||||
break;
|
||||
}
|
||||
#ifdef MP4_DEBUG
|
||||
dump(256, (unsigned char *)data, atomLength - 8, 0, 1);
|
||||
#endif
|
||||
data += 4;
|
||||
int is_ccdp = !strncmp(data, "ccdp", 4);
|
||||
|
||||
if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4) || is_ccdp)
|
||||
{
|
||||
if (subtype == GF_ISOM_SUBTYPE_C708)
|
||||
{
|
||||
if (!is_ccdp)
|
||||
{
|
||||
mprint("Your video file seems to be an interesting sample for us\n");
|
||||
mprint("We haven't met c708 subtitle not in a \'ccdp\' atom before\n");
|
||||
mprint("Please, report\n");
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int cc_count;
|
||||
data += 4;
|
||||
unsigned char *cc_data = ccdp_find_data((unsigned char *) data, sample->dataLength - 8, &cc_count);
|
||||
|
||||
if (!cc_data)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: no cc data found in ccdp\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->dec_global_setting->settings_dtvcc->enabled = 1;
|
||||
unsigned char temp[4];
|
||||
for (int cc_i = 0; cc_i < cc_count; cc_i++, cc_data += 3)
|
||||
{
|
||||
unsigned char cc_info = cc_data[0];
|
||||
unsigned char cc_valid = (unsigned char) ((cc_info & 4) >> 2);
|
||||
unsigned char cc_type = (unsigned char) (cc_info & 3);
|
||||
|
||||
if (cc_info == CDP_SECTION_SVC_INFO || cc_info == CDP_SECTION_FOOTER)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: premature end of sample (0x73 or 0x74)\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((cc_info == 0xFA || cc_info == 0xFC || cc_info == 0xFD)
|
||||
&& (cc_data[1] & 0x7F) == 0 && (cc_data[2] & 0x7F) == 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: skipped (zero cc data)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
temp[0] = cc_valid;
|
||||
temp[1] = cc_type;
|
||||
temp[2] = cc_data[1];
|
||||
temp[3] = cc_data[2];
|
||||
|
||||
if (cc_type < 2)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n");
|
||||
continue;
|
||||
}
|
||||
dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work
|
||||
//TODO is it really always 4-bytes long?
|
||||
ccx_dtvcc_process_data(dec_ctx, (unsigned char *) temp, 4);
|
||||
cb_708++;
|
||||
}
|
||||
atomStart = sample->dataLength;
|
||||
}
|
||||
else //subtype == GF_ISOM_SUBTYPE_C608
|
||||
{
|
||||
if (is_ccdp)
|
||||
{
|
||||
mprint("Your video file seems to be an interesting sample for us\n");
|
||||
mprint("We haven't met c608 subtitle in a \'ccdp\' atom before\n");
|
||||
mprint("Please, report\n");
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int len = atomLength - 8;
|
||||
data += 4;
|
||||
|
||||
do {
|
||||
ret = process608((unsigned char *) data, len, dec_ctx,
|
||||
&dec_sub);
|
||||
len -= ret;
|
||||
data += ret;
|
||||
if (dec_sub.got_output) {
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
} while (len > 0);
|
||||
}
|
||||
}
|
||||
atomStart += atomLength;
|
||||
}
|
||||
|
||||
// End of change
|
||||
int progress = (int) ((k*100) / num_samples);
|
||||
if (last_reported_progress != progress)
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
int cur_sec = (int) (get_fts(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);
|
||||
}
|
||||
}
|
||||
@@ -336,9 +543,12 @@ int processmp4 (char *file)
|
||||
f = NULL;
|
||||
mprint ("ok\n");
|
||||
|
||||
if(avc_track_count == 0){
|
||||
if(avc_track_count == 0)
|
||||
{
|
||||
mprint("Found no AVC track(s). ", file);
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
mprint("Found %d AVC track(s). ", avc_track_count);
|
||||
}
|
||||
if (cc_track_count)
|
||||
@@ -346,9 +556,7 @@ int processmp4 (char *file)
|
||||
else
|
||||
mprint ("found no dedicated CC track(s).\n");
|
||||
|
||||
file_report.mp4_cc_track_cnt = cc_track_count;
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
ctx->freport.mp4_cc_track_cnt = cc_track_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/tools.h>
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/network.h>
|
||||
|
||||
/* the length of the URL separator ("://" || "|//") */
|
||||
|
||||
52
src/lib_ccx/CMakeLists.txt
Normal file
52
src/lib_ccx/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
cmake_policy (SET CMP0037 NEW)
|
||||
|
||||
set (CMAKE_C_FLAGS "-O0 -Wall -g -std=gnu99")
|
||||
|
||||
if (WITH_FFMPEG)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
|
||||
endif (WITH_FFMPEG)
|
||||
|
||||
if (WITH_OCR)
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules(TESSERACT REQUIRED tesseract)
|
||||
pkg_check_modules(LEPTONICA REQUIRED lept)
|
||||
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${TESSERACT_STATIC_LIBRARIES})
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${LEPTONICA_STATIC_LIBRARIES})
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR ${TESSERACT_CFLAGS} ${LEPTONICA_CFLAGS}")
|
||||
endif (WITH_OCR)
|
||||
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
|
||||
|
||||
add_library (ccx ${SOURCEFILE} ccx_dtvcc.h ccx_dtvcc.c)
|
||||
|
||||
if (MINGW OR CYGWIN)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_WIN32")
|
||||
endif (MINGW OR CYGWIN)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_LINUX")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_DARWIN")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
file (GLOB HeaderFiles *.h)
|
||||
file (WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
|
||||
"includedir=\${prefix}/include\n"
|
||||
"libdir=\${prefix}/lib\n\n"
|
||||
"Name: ccx\n"
|
||||
"Description: Closed Caption Extraction library\n"
|
||||
"Version: 0.75\n"
|
||||
"Cflags: -I\${includedir}/\n"
|
||||
"Libs: -L\${libdir} -lccx -lpng\n"
|
||||
"Libs.private: -lpng\n"
|
||||
)
|
||||
|
||||
install (TARGETS ccx DESTINATION lib)
|
||||
install (FILES ${HeaderFiles} DESTINATION include)
|
||||
install (FILES ccx.pc DESTINATION lib/pkgconfig)
|
||||
136
src/lib_ccx/activity.c
Normal file
136
src/lib_ccx/activity.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/* This file contains functions that report the user of the GUI of
|
||||
relevant events. */
|
||||
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
static int credits_shown=0;
|
||||
unsigned long net_activity_gui=0;
|
||||
|
||||
/* Print current progress. For percentage, -1 -> streaming mode */
|
||||
void activity_progress (int percentage, int cur_min, int cur_sec)
|
||||
{
|
||||
if (!ccx_options.no_progress_bar)
|
||||
{
|
||||
if (percentage==-1)
|
||||
mprint ("\rStreaming | %02d:%02d", cur_min, cur_sec);
|
||||
else
|
||||
mprint ("\r%3d%% | %02d:%02d",percentage, cur_min, cur_sec);
|
||||
}
|
||||
fflush (stdout);
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###PROGRESS#%d#%d#%d\n", percentage, cur_min, cur_sec);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_input_file_open (const char *filename)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_library_process(enum ccx_common_logging_gui message_type, ...)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports){
|
||||
va_list args;
|
||||
va_start(args, message_type);
|
||||
switch (message_type)
|
||||
{
|
||||
case CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS:
|
||||
vfprintf(stderr, "###XDSNETWORKCALLLETTERS#%s\n",args);
|
||||
break;
|
||||
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION:
|
||||
vfprintf(stderr, "###XDSPROGRAMDESC#%d#%s\n", args);
|
||||
break;
|
||||
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR:
|
||||
vfprintf(stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", args);
|
||||
break;
|
||||
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME:
|
||||
vfprintf(stderr, "###XDSPROGRAMNAME#%s\n", args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fflush(stderr);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
|
||||
hor_size,vert_size, aspect_ratio, framerate);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void activity_message (const char *fmt, ...)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
va_list args;
|
||||
fprintf (stderr, "###MESSAGE#");
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_input_file_closed (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILECLOSED\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_program_number (unsigned program_number)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n", program_number);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_report_version (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###VERSION#CCExtractor#%s\n", VERSION);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void activity_report_data_read (void)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###DATAREAD#%lu\n", net_activity_gui/1000);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void activity_header (void)
|
||||
{
|
||||
if (!credits_shown)
|
||||
{
|
||||
credits_shown = 1;
|
||||
mprint ("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION);
|
||||
mprint ("Teletext portions taken from Petr Kutalek's telxcc\n");
|
||||
mprint ("--------------------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
17
src/lib_ccx/activity.h
Normal file
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
|
||||
@@ -85,10 +85,10 @@ typedef struct {
|
||||
// Payload parsing information
|
||||
int MultiplePayloads; // ASF
|
||||
int PacketLType; // ASF
|
||||
int ReplicatedLType; // ASF
|
||||
int OffsetMediaLType; // ASF
|
||||
int MediaNumberLType; // ASF
|
||||
int StreamNumberLType; // ASF
|
||||
int ReplicatedLType; // ASF
|
||||
int OffsetMediaLType; // ASF
|
||||
int MediaNumberLType; // ASF
|
||||
int StreamNumberLType; // ASF
|
||||
uint32_t PacketLength;
|
||||
uint32_t PaddingLength;
|
||||
} asf_data;
|
||||
} asf_data;
|
||||
1057
src/lib_ccx/asf_functions.c
Normal file
1057
src/lib_ccx/asf_functions.c
Normal file
File diff suppressed because it is too large
Load Diff
1181
src/lib_ccx/avc_functions.c
Normal file
1181
src/lib_ccx/avc_functions.c
Normal file
File diff suppressed because it is too large
Load Diff
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
|
||||
@@ -9,22 +9,22 @@
|
||||
// end is used to check that nothing is read at "end" or after it.
|
||||
struct bitstream
|
||||
{
|
||||
unsigned char *pos;
|
||||
int bpos;
|
||||
unsigned char *end;
|
||||
// Indicate how many bits are left in the stream after the previous
|
||||
// read call. A negative number indicates that a read after the
|
||||
// end of the stream was attempted.
|
||||
int64_t bitsleft;
|
||||
// Indicate an error occured while parsing the bitstream.
|
||||
// This is meant to store high level syntax errors, i.e a function
|
||||
// using the bitstream functions found a syntax error.
|
||||
int error;
|
||||
// Internal (private) variable - used to store the the bitstream
|
||||
// position until it is decided if the bitstream pointer will be
|
||||
// increased by the calling function, or not.
|
||||
unsigned char *_i_pos;
|
||||
int _i_bpos;
|
||||
unsigned char *pos;
|
||||
int bpos;
|
||||
unsigned char *end;
|
||||
// Indicate how many bits are left in the stream after the previous
|
||||
// read call. A negative number indicates that a read after the
|
||||
// end of the stream was attempted.
|
||||
int64_t bitsleft;
|
||||
// Indicate an error occured while parsing the bitstream.
|
||||
// This is meant to store high level syntax errors, i.e a function
|
||||
// using the bitstream functions found a syntax error.
|
||||
int error;
|
||||
// Internal (private) variable - used to store the the bitstream
|
||||
// position until it is decided if the bitstream pointer will be
|
||||
// increased by the calling function, or not.
|
||||
unsigned char *_i_pos;
|
||||
int _i_bpos;
|
||||
};
|
||||
|
||||
#define read_u8(bstream) (uint8_t)bitstream_get_num(bstream,1,1)
|
||||
375
src/lib_ccx/cc_bitstream.c
Normal file
375
src/lib_ccx/cc_bitstream.c
Normal file
@@ -0,0 +1,375 @@
|
||||
#include "lib_ccx.h"
|
||||
|
||||
// Hold functions to read streams on a bit or byte oriented basis
|
||||
// plus some data related helper functions.
|
||||
|
||||
|
||||
// Guidelines for all bitsream functions:
|
||||
// * No function shall advance the pointer past the end marker
|
||||
// * If bitstream.bitsleft < 0 do not attempt any read access,
|
||||
// but decrease bitsleft by the number of bits that were
|
||||
// attempted to read.
|
||||
|
||||
// Initialize bitstream
|
||||
int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *end)
|
||||
{
|
||||
bstr->pos = start;
|
||||
bstr->bpos = 8;
|
||||
bstr->end = end;
|
||||
bstr->bitsleft = (bstr->end - bstr->pos)*8;
|
||||
bstr->error = 0;
|
||||
bstr->_i_pos = NULL;
|
||||
bstr->_i_bpos = 0;
|
||||
|
||||
if(bstr->bitsleft < 0)
|
||||
{
|
||||
// See if we can somehow recover of this disaster by reporting the problem instead of terminating.
|
||||
mprint ( "init_bitstream: bitstream has negative length!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Read bnum bits from bitstream bstr with the most significant
|
||||
// bit read first without advancing the bitstream pointer.
|
||||
// A 64 bit unsigned integer is returned. 0 is returned when
|
||||
// there are not enough bits left in the bitstream.
|
||||
uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
|
||||
if(bnum > 64)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
|
||||
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bitstream.bitsleft, but correct it.
|
||||
if (bstr->bitsleft <= 0)
|
||||
{
|
||||
bstr->bitsleft -= bnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the remaining number of bits in bitstream after reading.
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
|
||||
if (bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 0;
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
unsigned char *vpos = bstr->pos;
|
||||
|
||||
if(vbit < 1 || vbit > 8)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if(vpos >= bstr->end)
|
||||
{
|
||||
// We should not get here ...
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
|
||||
}
|
||||
|
||||
res |= (*vpos & (0x01 << (vbit-1)) ? 1 : 0);
|
||||
vbit--;
|
||||
bnum--;
|
||||
|
||||
if(vbit == 0)
|
||||
{
|
||||
vpos++;
|
||||
vbit = 8;
|
||||
}
|
||||
|
||||
if(bnum)
|
||||
{
|
||||
res <<= 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember the bitstream position
|
||||
bstr->_i_bpos = vbit;
|
||||
bstr->_i_pos = vpos;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read bnum bits from bitstream bstr with the most significant
|
||||
// bit read first. A 64 bit unsigned integer is returned.
|
||||
uint64_t read_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = next_bits(bstr, bnum);
|
||||
|
||||
// Special case for reading zero bits. Also abort when not enough
|
||||
// bits are left. Return zero
|
||||
if(bnum == 0 || bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Advance the bitstream
|
||||
bstr->bpos = bstr->_i_bpos;
|
||||
bstr->pos = bstr->_i_pos;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// This function will advance the bitstream by bnum bits, if possible.
|
||||
// Advancing of more than 64 bits is possible.
|
||||
// Return TRUE when successfull, otherwise FALSE
|
||||
int skip_bits(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
bstr->bitsleft -= bnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the remaining number of bits in bitstream after reading.
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bnum;
|
||||
if (bstr->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 1;
|
||||
|
||||
bstr->bpos -= bnum%8;
|
||||
bstr->pos += bnum/8;
|
||||
|
||||
if (bstr->bpos < 1)
|
||||
{
|
||||
bstr->bpos += 8;
|
||||
bstr->pos += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Return TRUE if the current position in the bitstream is on a byte
|
||||
// boundary, i.e., the next bit in the bitstream is the first bit in
|
||||
// a byte, otherwise return FALSE
|
||||
int is_byte_aligned(struct bitstream *bstr)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
|
||||
if(vbit == 0 || vbit > 8)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
|
||||
}
|
||||
|
||||
if (vbit == 8)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Move bitstream to next byte border. Adjust bitsleft.
|
||||
void make_byte_aligned(struct bitstream *bstr)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
|
||||
|
||||
int vbit = bstr->bpos;
|
||||
|
||||
if(vbit == 0 || vbit > 8)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
|
||||
}
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
// Pay attention to the bit alignment
|
||||
bstr->bitsleft = (bstr->bitsleft-7)/8 *8;
|
||||
return;
|
||||
}
|
||||
|
||||
if(bstr->bpos != 8)
|
||||
{
|
||||
bstr->bpos = 8;
|
||||
bstr->pos += 1;
|
||||
}
|
||||
// Reset, in case a next_???() function was used before
|
||||
bstr->bitsleft = 0LL + 8*(bstr->end-bstr->pos-1)+bstr->bpos;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Return pointer to first of bynum bytes from the bitstream if the
|
||||
// following conditions are TRUE:
|
||||
// The bitstream is byte aligned and there are enough bytes left in
|
||||
// it to read bynum bytes. Otherwise return NULL.
|
||||
// This function does not advance the bitstream pointer.
|
||||
unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum)
|
||||
{
|
||||
// Sanity check
|
||||
if(bstr->end - bstr->pos < 0)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
|
||||
|
||||
// Keep a negative bstr->bitsleft, but correct it.
|
||||
if (bstr->bitsleft < 0)
|
||||
{
|
||||
bstr->bitsleft -= bynum*8;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1)*8 + bstr->bpos - bynum*8;
|
||||
|
||||
if (!is_byte_aligned(bstr) || bstr->bitsleft < 0 || bynum < 1)
|
||||
return NULL;
|
||||
|
||||
// Remember the bitstream position
|
||||
bstr->_i_bpos = 8;
|
||||
bstr->_i_pos = bstr->pos + bynum;
|
||||
|
||||
return bstr->pos;
|
||||
}
|
||||
|
||||
|
||||
// Return pointer to first of bynum bytes from the bitstream if the
|
||||
// following conditions are TRUE:
|
||||
// The bitstream is byte aligned and there are enough bytes left in
|
||||
// it to read bynum bytes. Otherwise return NULL.
|
||||
// This function does advance the bitstream pointer.
|
||||
unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum)
|
||||
{
|
||||
unsigned char *res = next_bytes(bstr, bynum);
|
||||
|
||||
// Advance the bitstream when a read was possible
|
||||
if(res)
|
||||
{
|
||||
bstr->bpos = bstr->_i_bpos;
|
||||
bstr->pos = bstr->_i_pos;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Return an integer number with "bytes" precision from the current
|
||||
// bitstream position. Allowed "bytes" values are 1,2,4,8.
|
||||
// This function does advance the bitstream pointer when "advance" is
|
||||
// set to TRUE.
|
||||
// Numbers come MSB (most significant first), and we need to account for
|
||||
// little-endian and big-endian CPUs.
|
||||
uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
|
||||
{
|
||||
void *bpos;
|
||||
uint64_t rval=0;
|
||||
|
||||
if (advance)
|
||||
bpos = read_bytes(bstr, bytes);
|
||||
else
|
||||
bpos = next_bytes(bstr, bytes);
|
||||
|
||||
if (!bpos)
|
||||
return 0;
|
||||
|
||||
switch (bytes)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "bitstream_get_num: Illegal precision value [%u]!",
|
||||
bytes);
|
||||
break;
|
||||
}
|
||||
for (unsigned i=0;i<bytes;i++)
|
||||
{
|
||||
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
|
||||
unsigned char uc=*ucpos;
|
||||
rval=(rval<<8) + uc;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
// Read unsigned Exp-Golomb code from bitstream
|
||||
uint64_t ue(struct bitstream *bstr)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
int zeros=0;
|
||||
|
||||
while(!read_bits(bstr,1))
|
||||
zeros++;
|
||||
|
||||
res = (0x01 << zeros) - 1 + read_bits(bstr,zeros);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read signed Exp-Golomb code from bitstream
|
||||
int64_t se(struct bitstream *bstr)
|
||||
{
|
||||
int64_t res = 0;
|
||||
|
||||
res = ue(bstr);
|
||||
|
||||
// The following function might truncate when res+1 overflows
|
||||
//res = (res+1)/2 * (res % 2 ? 1 : -1);
|
||||
// Use this:
|
||||
res = (res/2+(res%2 ? 1 : 0)) * (res % 2 ? 1 : -1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Read unsigned integer with bnum bits length. Basically an
|
||||
// alias for read_bits().
|
||||
uint64_t u(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
return read_bits(bstr, bnum);
|
||||
}
|
||||
|
||||
|
||||
// Read signed integer with bnum bits length.
|
||||
int64_t i(struct bitstream *bstr, unsigned bnum)
|
||||
{
|
||||
uint64_t res = read_bits(bstr, bnum);
|
||||
|
||||
// Special case for reading zero bits. Return zero
|
||||
if(bnum == 0)
|
||||
return 0;
|
||||
|
||||
return (0xFFFFFFFFFFFFFFFFULL << bnum) | res;
|
||||
}
|
||||
|
||||
|
||||
// Return the value with the bit order reversed.
|
||||
uint8_t reverse8(uint8_t data)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
|
||||
for (int k=0;k<8;k++)
|
||||
{
|
||||
res <<= 1;
|
||||
res |= (data & (0x01 << k) ? 1 : 0);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
840
src/lib_ccx/ccx_common_char_encoding.c
Normal file
840
src/lib_ccx/ccx_common_char_encoding.c
Normal file
@@ -0,0 +1,840 @@
|
||||
#include <ctype.h>
|
||||
|
||||
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
{
|
||||
unsigned char c1='?';
|
||||
if (c<0x80)
|
||||
{
|
||||
// Regular line-21 character set, mostly ASCII except these exceptions
|
||||
switch (c)
|
||||
{
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
c1=0xe1;
|
||||
break;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
c1=0xe9;
|
||||
break;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
c1=0xed;
|
||||
break;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
c1=0xf3;
|
||||
break;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
c1=0xfa;
|
||||
break;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
c1=0xe7;
|
||||
break;
|
||||
case 0x7c: // division symbol
|
||||
c1=0xf7;
|
||||
break;
|
||||
case 0x7d: // uppercase N tilde
|
||||
c1=0xd1;
|
||||
break;
|
||||
case 0x7e: // lowercase n tilde
|
||||
c1=0xf1;
|
||||
break;
|
||||
default:
|
||||
c1=c;
|
||||
break;
|
||||
}
|
||||
*buffer=c1;
|
||||
return;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
c1=0xae;
|
||||
break;
|
||||
case 0x81: // degree sign
|
||||
c1=0xb0;
|
||||
break;
|
||||
case 0x82: // 1/2 symbol
|
||||
c1=0xbd;
|
||||
break;
|
||||
case 0x83: // Inverted (open) question mark
|
||||
c1=0xbf;
|
||||
break;
|
||||
case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
|
||||
break;
|
||||
case 0x85: // Cents symbol
|
||||
c1=0xa2;
|
||||
break;
|
||||
case 0x86: // Pounds sterling
|
||||
c1=0xa3;
|
||||
break;
|
||||
case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
|
||||
c1=0xb6;
|
||||
break;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
c1=0xe0;
|
||||
break;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
c1=0x20;
|
||||
break;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
c1=0xe8;
|
||||
break;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
c1=0xe2;
|
||||
break;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
c1=0xea;
|
||||
break;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
c1=0xee;
|
||||
break;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
c1=0xf4;
|
||||
break;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
c1=0xfb;
|
||||
break;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0x90: // capital letter A with acute
|
||||
c1=0xc1;
|
||||
break;
|
||||
case 0x91: // capital letter E with acute
|
||||
c1=0xc9;
|
||||
break;
|
||||
case 0x92: // capital letter O with acute
|
||||
c1=0xd3;
|
||||
break;
|
||||
case 0x93: // capital letter U with acute
|
||||
c1=0xda;
|
||||
break;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
c1=0xdc;
|
||||
break;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
c1=0xfc;
|
||||
break;
|
||||
case 0x96: // apostrophe
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x97: // inverted exclamation mark
|
||||
c1=0xa1;
|
||||
break;
|
||||
case 0x98: // asterisk
|
||||
c1=0x2a;
|
||||
break;
|
||||
case 0x99: // apostrophe (yes, duped). See CCADI source code.
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x9a: // em dash
|
||||
c1=0x2d;
|
||||
break;
|
||||
case 0x9b: // copyright sign
|
||||
c1=0xa9;
|
||||
break;
|
||||
case 0x9c: // Service Mark - not available in latin 1
|
||||
break;
|
||||
case 0x9d: // Full stop (.)
|
||||
c1=0x2e;
|
||||
break;
|
||||
case 0x9e: // Quoatation mark
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0x9f: // Quoatation mark
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
c1=0xc0;
|
||||
break;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
c1=0xc2;
|
||||
break;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
c1=0xc7;
|
||||
break;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
c1=0xc8;
|
||||
break;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
c1=0xca;
|
||||
break;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
c1=0xcb;
|
||||
break;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
c1=0xeb;
|
||||
break;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
c1=0xce;
|
||||
break;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
c1=0xcf;
|
||||
break;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
c1=0xef;
|
||||
break;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
c1=0xd4;
|
||||
break;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
c1=0xd9;
|
||||
break;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
c1=0xf9;
|
||||
break;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
c1=0xdb;
|
||||
break;
|
||||
case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
c1=0xab;
|
||||
break;
|
||||
case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
c1=0xbb;
|
||||
break;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
c1=0xc3;
|
||||
break;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
c1=0xe3;
|
||||
break;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
c1=0xcd;
|
||||
break;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
c1=0xcc;
|
||||
break;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
c1=0xec;
|
||||
break;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
c1=0xd2;
|
||||
break;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
c1=0xf2;
|
||||
break;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
c1=0xd5;
|
||||
break;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
c1=0xf5;
|
||||
break;
|
||||
case 0xb9: // Open curly brace
|
||||
c1=0x7b;
|
||||
break;
|
||||
case 0xba: // Closing curly brace
|
||||
c1=0x7d;
|
||||
break;
|
||||
case 0xbb: // Backslash
|
||||
c1=0x5c;
|
||||
break;
|
||||
case 0xbc: // Caret
|
||||
c1=0x5e;
|
||||
break;
|
||||
case 0xbd: // Underscore
|
||||
c1=0x5f;
|
||||
break;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
c1=0xa6;
|
||||
break;
|
||||
case 0xbf: // Tilde
|
||||
c1=0x7e;
|
||||
break;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
c1=0xc4;
|
||||
break;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
c1=0xe3;
|
||||
break;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
c1=0xd6;
|
||||
break;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
c1=0xf6;
|
||||
break;
|
||||
case 0xc4: // Esszett (sharp S)
|
||||
c1=0xdf;
|
||||
break;
|
||||
case 0xc5: // Yen symbol
|
||||
c1=0xa5;
|
||||
break;
|
||||
case 0xc6: // Currency symbol
|
||||
c1=0xa4;
|
||||
break;
|
||||
case 0xc7: // Vertical bar
|
||||
c1=0x7c;
|
||||
break;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
c1=0xc5;
|
||||
break;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
c1=0xe5;
|
||||
break;
|
||||
case 0xca: // Uppercase O, slash
|
||||
c1=0xd8;
|
||||
break;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
c1=0xf8;
|
||||
break;
|
||||
case 0xcc: // Upper left corner
|
||||
case 0xcd: // Upper right corner
|
||||
case 0xce: // Lower left corner
|
||||
case 0xcf: // Lower right corner
|
||||
default: // For those that don't have representation
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
break; // This are weird chars anyway
|
||||
}
|
||||
*buffer=c1;
|
||||
}
|
||||
|
||||
void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
{
|
||||
unsigned char c1,c2;
|
||||
switch (c)
|
||||
{
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
c2=0x21;
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0x87: // Music note
|
||||
c2=0x26;
|
||||
c1=0x6a;
|
||||
break;
|
||||
case 0x9c: // Service Mark
|
||||
c2=0x21;
|
||||
c1=0x20;
|
||||
break;
|
||||
case 0xcc: // Upper left corner
|
||||
c2=0x23;
|
||||
c1=0x1c;
|
||||
break;
|
||||
case 0xcd: // Upper right corner
|
||||
c2=0x23;
|
||||
c1=0x1d;
|
||||
break;
|
||||
case 0xce: // Lower left corner
|
||||
c2=0x23;
|
||||
c1=0x1e;
|
||||
break;
|
||||
case 0xcf: // Lower right corner
|
||||
c2=0x23;
|
||||
c1=0x1f;
|
||||
break;
|
||||
default: // Everything else, same as latin-1 followed by 00
|
||||
get_char_in_latin_1 (&c1,c);
|
||||
c2=0;
|
||||
break;
|
||||
}
|
||||
*buffer=c1;
|
||||
*(buffer+1)=c2;
|
||||
}
|
||||
|
||||
int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used
|
||||
{
|
||||
if (c<0x80) // Regular line-21 character set, mostly ASCII except these exceptions
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa1;
|
||||
return 2;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa9;
|
||||
return 2;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xad;
|
||||
return 2;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb3;
|
||||
return 2;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xba;
|
||||
return 2;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa7;
|
||||
return 2;
|
||||
case 0x7c: // division symbol
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb7;
|
||||
return 2;
|
||||
case 0x7d: // uppercase N tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x91;
|
||||
return 2;
|
||||
case 0x7e: // lowercase n tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb1;
|
||||
return 2;
|
||||
case 0x7f: // Solid block
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x96;
|
||||
*(buffer+2)=0xa0;
|
||||
return 3;
|
||||
default:
|
||||
*buffer=c;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xae;
|
||||
return 2;
|
||||
case 0x81: // degree sign
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xb0;
|
||||
return 2;
|
||||
case 0x82: // 1/2 symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbd;
|
||||
return 2;
|
||||
case 0x83: // Inverted (open) question mark
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbf;
|
||||
return 2;
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x84;
|
||||
*(buffer+2)=0xa2;
|
||||
return 3;
|
||||
case 0x85: // Cents symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa2;
|
||||
return 2;
|
||||
case 0x86: // Pounds sterling
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa3;
|
||||
return 2;
|
||||
case 0x87: // Music note
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x99;
|
||||
*(buffer+2)=0xaa;
|
||||
return 3;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa0;
|
||||
return 2;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
*buffer=0x20;
|
||||
return 1;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa8;
|
||||
return 2;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa2;
|
||||
return 2;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xaa;
|
||||
return 2;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xae;
|
||||
return 2;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb4;
|
||||
return 2;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xbb;
|
||||
return 2;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0x90: // capital letter A with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x81;
|
||||
return 2;
|
||||
case 0x91: // capital letter E with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x89;
|
||||
return 2;
|
||||
case 0x92: // capital letter O with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x93;
|
||||
return 2;
|
||||
case 0x93: // capital letter U with acute
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9a;
|
||||
return 2;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9c;
|
||||
return 2;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xbc;
|
||||
return 2;
|
||||
case 0x96: // apostrophe
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x97: // inverted exclamation mark
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa1;
|
||||
return 2;
|
||||
case 0x98: // asterisk
|
||||
*buffer=0x2a;
|
||||
return 1;
|
||||
case 0x99: // Plain single quote
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x9a: // em dash
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x94;
|
||||
return 3;
|
||||
case 0x9b: // copyright sign
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa9;
|
||||
return 2;
|
||||
case 0x9c: // Service mark
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x84;
|
||||
*(buffer+2)=0xa0;
|
||||
return 3;
|
||||
case 0x9d: // Round bullet
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0xa2;
|
||||
return 3;
|
||||
case 0x9e: // Opening double quotes
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9c;
|
||||
return 3;
|
||||
case 0x9f: // Closing double quotes
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9d;
|
||||
return 3;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x80;
|
||||
return 2;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x82;
|
||||
return 2;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x87;
|
||||
return 2;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x88;
|
||||
return 2;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8a;
|
||||
return 2;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8b;
|
||||
return 2;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xab;
|
||||
return 2;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8e;
|
||||
return 2;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8f;
|
||||
return 2;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xaf;
|
||||
return 2;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x94;
|
||||
return 2;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x99;
|
||||
return 2;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb9;
|
||||
return 2;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9b;
|
||||
return 2;
|
||||
case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xab;
|
||||
return 2;
|
||||
case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xbb;
|
||||
return 2;
|
||||
// THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x83;
|
||||
return 2;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa3;
|
||||
return 2;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8d;
|
||||
return 2;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x8c;
|
||||
return 2;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xac;
|
||||
return 2;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x92;
|
||||
return 2;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb2;
|
||||
return 2;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x95;
|
||||
return 2;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb5;
|
||||
return 2;
|
||||
case 0xb9: // Open curly brace
|
||||
*buffer=0x7b;
|
||||
return 1;
|
||||
case 0xba: // Closing curly brace
|
||||
*buffer=0x7d;
|
||||
return 1;
|
||||
case 0xbb: // Backslash
|
||||
*buffer=0x5c;
|
||||
return 1;
|
||||
case 0xbc: // Caret
|
||||
*buffer=0x5e;
|
||||
return 1;
|
||||
case 0xbd: // Underscore
|
||||
*buffer=0x5f;
|
||||
return 1;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa6;
|
||||
return 2;
|
||||
case 0xbf: // Tilde
|
||||
*buffer=0x7e; // Not sure
|
||||
return 1;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x84;
|
||||
return 2;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x96;
|
||||
return 2;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb6;
|
||||
return 2;
|
||||
case 0xc4: // Esszett (sharp S)
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x9f;
|
||||
return 2;
|
||||
case 0xc5: // Yen symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa5;
|
||||
return 2;
|
||||
case 0xc6: // Currency symbol
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc7: // Vertical bar
|
||||
*buffer=0x7c;
|
||||
return 1;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x85;
|
||||
return 2;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa5;
|
||||
return 2;
|
||||
case 0xca: // Uppercase O, slash
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x98;
|
||||
return 2;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb8;
|
||||
return 2;
|
||||
case 0xcc: // Top left corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9c;
|
||||
return 3;
|
||||
case 0xcd: // Top right corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9d;
|
||||
return 3;
|
||||
case 0xce: // Bottom left corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9e;
|
||||
return 3;
|
||||
case 0xcf: // Bottom right corner
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9f;
|
||||
return 3;
|
||||
default: //
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
return 1; // This are weird chars anyway
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char cctolower (unsigned char c)
|
||||
{
|
||||
if (c>='A' && c<='Z')
|
||||
return tolower(c);
|
||||
switch (c)
|
||||
{
|
||||
case 0x7d: // uppercase N tilde
|
||||
return 0x7e;
|
||||
case 0x90: // capital letter A with acute
|
||||
return 0x2a;
|
||||
case 0x91: // capital letter E with acute
|
||||
return 0x5c;
|
||||
case 0x92: // capital letter O with acute
|
||||
return 0x5f;
|
||||
case 0x93: // capital letter U with acute
|
||||
return 0x60;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
return 0x7b;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
return 0x88;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
return 0x8a;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
return 0x8b;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
return 0x8c;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
return 0x8d;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
return 0x8e;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
return 0x8f;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
return 0x95;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
return 0xa6;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
return 0xa9;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
return 0xac;
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
return 0xb1;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
return 0x5e;
|
||||
case 0xb3: // Uppercase I, grave accent
|
||||
return 0xb4;
|
||||
case 0xb5: // Uppercase O, grave accent
|
||||
return 0xb6;
|
||||
case 0xb7: // Uppercase O, tilde
|
||||
return 0xb8;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
return 0xc1;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
return 0xc3;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
return 0xc9;
|
||||
case 0xca: // Uppercase O, slash
|
||||
return 0xcb;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned char cctoupper (unsigned char c)
|
||||
{
|
||||
if (c>='a' && c<='z')
|
||||
return toupper(c);
|
||||
switch (c)
|
||||
{
|
||||
case 0x7e: // lowercase n tilde
|
||||
return 0x7d;
|
||||
case 0x2a: // lowercase a, acute accent
|
||||
return 0x90;
|
||||
case 0x5c: // lowercase e, acute accent
|
||||
return 0x91;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
return 0xb2;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
return 0x92;
|
||||
case 0x60: // lowercase u, acute accent
|
||||
return 0x93;
|
||||
case 0x7b: // lowercase c with cedilla
|
||||
return 0xa2;
|
||||
case 0x88: // lowercase a, grave accent
|
||||
return 0xa0;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
return 0xa3;
|
||||
case 0x8b: // lowercase a, circumflex accent
|
||||
return 0xa1;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
return 0xa4;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
return 0xa7;
|
||||
case 0x8e: // lowercase o, circumflex accent
|
||||
return 0xaa;
|
||||
case 0x8f: // lowercase u, circumflex accent
|
||||
return 0xad;
|
||||
case 0x95: // lowercase letter U with diaeresis
|
||||
return 0x94;
|
||||
case 0xa6: // lowercase letter e with diaresis
|
||||
return 0xa5;
|
||||
case 0xa9: // lowercase i, with diaresis
|
||||
return 0xa8;
|
||||
case 0xac: // lowercase u, grave accent
|
||||
return 0xab;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
return 0xb0;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
return 0xb3;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
return 0xb5;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
return 0xb7;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
return 0xc0;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
return 0xc2;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
return 0xc8;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
return 0xca;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
10
src/lib_ccx/ccx_common_char_encoding.h
Normal file
10
src/lib_ccx/ccx_common_char_encoding.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __CCX_COMMON_CHAR_ENCODING__
|
||||
#define __CCX_COMMON_CHAR_ENCODING__
|
||||
|
||||
void get_char_in_latin_1(unsigned char *buffer, unsigned char c);
|
||||
void get_char_in_unicode(unsigned char *buffer, unsigned char c);
|
||||
int get_char_in_utf_8(unsigned char *buffer, unsigned char c);
|
||||
unsigned char cctolower(unsigned char c);
|
||||
unsigned char cctoupper(unsigned char c);
|
||||
|
||||
#endif
|
||||
128
src/lib_ccx/ccx_common_common.c
Normal file
128
src/lib_ccx/ccx_common_common.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#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, ...)
|
||||
{
|
||||
/* Guess we need no more than 100 bytes. */
|
||||
int n, size = 100;
|
||||
char *p, *np;
|
||||
va_list ap;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
if ((p = (char *)malloc(size)) == NULL)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Try to print in the allocated space. */
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(p, size, fmt, ap);
|
||||
va_end(ap);
|
||||
/* If that worked, return the string. */
|
||||
if (n > -1 && n < size)
|
||||
{
|
||||
write(fd, p, n);
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) /* glibc 2.1 */
|
||||
size = n + 1; /* precisely what is needed */
|
||||
else /* glibc 2.0 */
|
||||
size *= 2; /* twice the old size */
|
||||
if ((np = (char *)realloc(p, size)) == NULL)
|
||||
{
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Converts the given milli to separate hours,minutes,seconds and ms variables */
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
|
||||
unsigned *seconds, unsigned *ms)
|
||||
{
|
||||
// LLONG milli = (LLONG) ((ccblock*1000)/29.97);
|
||||
*ms = (unsigned)(milli % 1000); // milliseconds
|
||||
milli = (milli - *ms) / 1000; // Remainder, in seconds
|
||||
*seconds = (int)(milli % 60);
|
||||
milli = (milli - *seconds) / 60; // Remainder, in minutes
|
||||
*minutes = (int)(milli % 60);
|
||||
milli = (milli - *minutes) / 60; // Remainder, in hours
|
||||
*hours = (int)milli;
|
||||
}
|
||||
/* Frees the given pointer */
|
||||
void freep(void *arg)
|
||||
{
|
||||
void **ptr = (void **)arg;
|
||||
if (*ptr)
|
||||
free(*ptr);
|
||||
*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);
|
||||
}
|
||||
50
src/lib_ccx/ccx_common_common.h
Normal file
50
src/lib_ccx/ccx_common_common.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef _CC_COMMON_COMMON
|
||||
#define _CC_COMMON_COMMON
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_structs.h"
|
||||
|
||||
// Define possible exit codes that will be passed on to the fatal function
|
||||
/* Exit codes. Take this seriously as the GUI depends on them.
|
||||
0 means OK as usual,
|
||||
<100 means display whatever was output to stderr as a warning
|
||||
>=100 means display whatever was output to stdout as an error
|
||||
*/
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
#define CCX_COMMON_EXIT_FILE_CREATION_FAILED 5
|
||||
#define CCX_COMMON_EXIT_UNSUPPORTED 9
|
||||
#define EXIT_NOT_ENOUGH_MEMORY 500
|
||||
#define CCX_COMMON_EXIT_BUG_BUG 1000
|
||||
|
||||
#define CCX_OK 0
|
||||
#define CCX_FALSE 0
|
||||
#define CCX_TRUE 1
|
||||
#define CCX_EAGAIN -100
|
||||
#define CCX_EOF -101
|
||||
#define CCX_EINVAL -102
|
||||
#define CCX_ENOSUPP -103
|
||||
#define CCX_ENOMEM -104
|
||||
|
||||
// Declarations
|
||||
void fdprintf(int fd, const char *fmt, ...);
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms);
|
||||
void freep(void *arg);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
|
||||
int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
|
||||
LLONG end_time, char *info, char *mode, enum ccx_encoding_type);
|
||||
|
||||
extern int cc608_parity_table[256]; // From myth
|
||||
#endif
|
||||
138
src/lib_ccx/ccx_common_constants.c
Normal file
138
src/lib_ccx/ccx_common_constants.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "ccx_common_constants.h"
|
||||
|
||||
// RCWT header (11 bytes):
|
||||
//byte(s) value description (All values below are hex numbers, not
|
||||
// actual numbers or values
|
||||
//0-2 CCCCED magic number, for Closed Caption CC Extractor Data
|
||||
//3 CC Creating program. Legal values: CC = CC Extractor
|
||||
//4-5 0050 Program version number
|
||||
//6-7 0001 File format version
|
||||
//8-10 000000 Padding, required :-)
|
||||
unsigned char rcwt_header[11]={0xCC, 0xCC, 0xED, 0xCC, 0x00, 0x50, 0, 1, 0, 0, 0};
|
||||
|
||||
const unsigned char BROADCAST_HEADER[]={0xff, 0xff, 0xff, 0xff};
|
||||
const unsigned char LITTLE_ENDIAN_BOM[]={0xff, 0xfe};
|
||||
const unsigned char UTF8_BOM[]={0xef, 0xbb,0xbf};
|
||||
|
||||
const unsigned char DVD_HEADER[8]={0x00,0x00,0x01,0xb2,0x43,0x43,0x01,0xf8};
|
||||
const unsigned char lc1[1]={0x8a};
|
||||
const unsigned char lc2[1]={0x8f};
|
||||
const unsigned char lc3[2]={0x16,0xfe};
|
||||
const unsigned char lc4[2]={0x1e,0xfe};
|
||||
const unsigned char lc5[1]={0xff};
|
||||
const unsigned char lc6[1]={0xfe};
|
||||
|
||||
const double framerates_values[16]=
|
||||
{
|
||||
0,
|
||||
24000.0/1001, /* 23.976 */
|
||||
24.0,
|
||||
25.0,
|
||||
30000.0/1001, /* 29.97 */
|
||||
30.0,
|
||||
50.0,
|
||||
60000.0/1001, /* 59.94 */
|
||||
60.0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
const char *framerates_types[16]=
|
||||
{
|
||||
"00 - forbidden",
|
||||
"01 - 23.976",
|
||||
"02 - 24",
|
||||
"03 - 25",
|
||||
"04 - 29.97",
|
||||
"05 - 30",
|
||||
"06 - 50",
|
||||
"07 - 59.94",
|
||||
"08 - 60",
|
||||
"09 - reserved",
|
||||
"10 - reserved",
|
||||
"11 - reserved",
|
||||
"12 - reserved",
|
||||
"13 - reserved",
|
||||
"14 - reserved",
|
||||
"15 - reserved"
|
||||
};
|
||||
|
||||
const char *aspect_ratio_types[16]=
|
||||
{
|
||||
"00 - forbidden",
|
||||
"01 - 1:1",
|
||||
"02 - 4:3",
|
||||
"03 - 16:9",
|
||||
"04 - 2.21:1",
|
||||
"05 - reserved",
|
||||
"06 - reserved",
|
||||
"07 - reserved",
|
||||
"08 - reserved",
|
||||
"09 - reserved",
|
||||
"10 - reserved",
|
||||
"11 - reserved",
|
||||
"12 - reserved",
|
||||
"13 - reserved",
|
||||
"14 - reserved",
|
||||
"15 - reserved"
|
||||
};
|
||||
|
||||
|
||||
const char *pict_types[8]=
|
||||
{
|
||||
"00 - ilegal (0)",
|
||||
"01 - I",
|
||||
"02 - P",
|
||||
"03 - B",
|
||||
"04 - ilegal (D)",
|
||||
"05 - ilegal (5)",
|
||||
"06 - ilegal (6)",
|
||||
"07 - ilegal (7)"
|
||||
};
|
||||
|
||||
|
||||
const char *slice_types[10]=
|
||||
{
|
||||
"0 - P",
|
||||
"1 - B",
|
||||
"2 - I",
|
||||
"3 - SP",
|
||||
"4 - SI",
|
||||
"5 - P",
|
||||
"6 - B",
|
||||
"7 - I",
|
||||
"8 - SP",
|
||||
"9 - SI"
|
||||
};
|
||||
|
||||
const char *cc_types[4] =
|
||||
{
|
||||
"NTSC line 21 field 1 closed captions",
|
||||
"NTSC line 21 field 2 closed captions",
|
||||
"DTVCC Channel Packet Data",
|
||||
"DTVCC Channel Packet Start"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NTSC_CC_f1 = 0,
|
||||
NTSC_CC_f2 = 1,
|
||||
DTVCC_PACKET_DATA = 2,
|
||||
DTVCC_PACKET_START = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* After Adding a new language here, dont forget
|
||||
* to increase NB_LANGUAGE define ccx_common_constants.h
|
||||
*/
|
||||
const char *language[NB_LANGUAGE] =
|
||||
{
|
||||
"und",
|
||||
"eng",
|
||||
"fin",
|
||||
"spa",
|
||||
NULL
|
||||
};
|
||||
@@ -1,6 +1,13 @@
|
||||
#ifndef CCX_CONSTANTS_H
|
||||
#define CCX_CONSTANTS_H
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
extern const char *framerates_types[16];
|
||||
extern const double framerates_values[16];
|
||||
|
||||
@@ -20,7 +27,7 @@ extern const unsigned char lc4[2];
|
||||
extern const unsigned char lc5[1];
|
||||
extern const unsigned char lc6[1];
|
||||
|
||||
extern const unsigned char rcwt_header[11];
|
||||
extern unsigned char rcwt_header[11];
|
||||
|
||||
#define ONEPASS 120 /* Bytes we can always look ahead without going out of limits */
|
||||
#define BUFSIZE (2048*1024+ONEPASS) /* 2 Mb plus the safety pass */
|
||||
@@ -29,26 +36,28 @@ extern const 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()
|
||||
|
||||
enum ccx_debug_message_types
|
||||
enum ccx_debug_message_types
|
||||
{
|
||||
/* Each debug message now belongs to one of these types. Use bitmaps in case
|
||||
we want one message to belong to more than one type. */
|
||||
/* Each debug message now belongs to one of these types. Use bitmaps in case
|
||||
we want one message to belong to more than one type. */
|
||||
CCX_DMT_PARSE=1, // Show information related to parsing the container
|
||||
CCX_DMT_VIDES=2,// Show video stream related information
|
||||
CCX_DMT_TIME=4, // Show GOP and PTS timing information
|
||||
CCX_DMT_VERBOSE=8, // Show lots of debugging output
|
||||
CCX_DMT_608=0x10, // Show CC-608 decoder debug?
|
||||
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
|
||||
CCX_DMT_XDS=0x40, // Show XDS decoder debug?
|
||||
CCX_DMT_DECODER_608=0x10, // Show CC-608 decoder debug?
|
||||
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
|
||||
CCX_DMT_DECODER_XDS=0x40, // Show XDS decoder debug?
|
||||
CCX_DMT_CBRAW=0x80, // Caption blocks with FTS timing
|
||||
CCX_DMT_GENERIC_NOTICES=0x100, // Generic, always displayed even if no debug is selected
|
||||
CCX_DMT_TELETEXT=0x200, // Show teletext debug?
|
||||
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
|
||||
@@ -74,7 +83,7 @@ enum ccx_avc_nal_types
|
||||
CCX_NAL_TYPE_RESERVED_17 = 18,
|
||||
CCX_NAL_TYPE_RESERVED_18 = 18,
|
||||
CCX_NAL_TYPE_CODED_SLICE_AUXILIARY_PICTURE = 19,
|
||||
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
|
||||
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
|
||||
CCX_NAL_TYPE_RESERVED_21 = 21,
|
||||
CCX_NAL_TYPE_RESERVED_22 = 22,
|
||||
CCX_NAL_TYPE_RESERVED_23 = 23,
|
||||
@@ -91,39 +100,40 @@ enum ccx_avc_nal_types
|
||||
// MPEG-2 TS stream types
|
||||
enum ccx_stream_type
|
||||
{
|
||||
CCX_STREAM_TYPE_UNKNOWNSTREAM = 0,
|
||||
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
|
||||
CCX_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
|
||||
CCX_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
|
||||
CCX_STREAM_TYPE_UNKNOWNSTREAM = 0,
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
|
||||
CCX_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
|
||||
CCX_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
|
||||
CCX_STREAM_TYPE_PRIVATE_TABLE_MPEG2 = 0x05,
|
||||
CCX_STREAM_TYPE_PRIVATE_MPEG2 = 0x06,
|
||||
CCX_STREAM_TYPE_MHEG_PACKETS = 0x07,
|
||||
CCX_STREAM_TYPE_MPEG2_ANNEX_A_DSM_CC = 0x08,
|
||||
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
|
||||
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_A = 0x0A,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_B = 0x0B,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_C = 0x0C,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_D = 0x0D,
|
||||
CCX_STREAM_TYPE_AUDIO_AAC = 0x0f,
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG4 = 0x10,
|
||||
CCX_STREAM_TYPE_VIDEO_H264 = 0x1b,
|
||||
CCX_STREAM_TYPE_AUDIO_AAC = 0x0f,
|
||||
CCX_STREAM_TYPE_VIDEO_MPEG4 = 0x10,
|
||||
CCX_STREAM_TYPE_VIDEO_H264 = 0x1b,
|
||||
CCX_STREAM_TYPE_PRIVATE_USER_MPEG2=0x80,
|
||||
CCX_STREAM_TYPE_AUDIO_AC3 = 0x81,
|
||||
CCX_STREAM_TYPE_AUDIO_HDMV_DTS = 0x82,
|
||||
CCX_STREAM_TYPE_AUDIO_DTS = 0x8a,
|
||||
CCX_STREAM_TYPE_AUDIO_AC3 = 0x81,
|
||||
CCX_STREAM_TYPE_AUDIO_HDMV_DTS = 0x82,
|
||||
CCX_STREAM_TYPE_AUDIO_DTS = 0x8a,
|
||||
};
|
||||
|
||||
enum ccx_mpeg_descriptor
|
||||
{
|
||||
CCX_MPEG_DSC_REGISTRATION = 0x05,
|
||||
CCX_MPEG_DSC_REGISTRATION = 0x05,
|
||||
CCX_MPEG_DSC_DATA_STREAM_ALIGNMENT = 0x06,
|
||||
CCX_MPEG_DSC_ISO639_LANGUAGE = 0x0A,
|
||||
CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR = 0x45,
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
@@ -138,20 +148,23 @@ enum ccx_datasource
|
||||
{
|
||||
CCX_DS_FILE=0,
|
||||
CCX_DS_STDIN=1,
|
||||
CCX_DS_NETWORK=2
|
||||
CCX_DS_NETWORK=2,
|
||||
CCX_DS_TCP=3
|
||||
};
|
||||
|
||||
enum ccx_output_format
|
||||
{
|
||||
CCX_OF_RAW = 0,
|
||||
CCX_OF_SRT = 1,
|
||||
CCX_OF_SAMI = 2,
|
||||
CCX_OF_TRANSCRIPT = 3,
|
||||
CCX_OF_RCWT = 4,
|
||||
CCX_OF_RAW = 0,
|
||||
CCX_OF_SRT = 1,
|
||||
CCX_OF_SAMI = 2,
|
||||
CCX_OF_TRANSCRIPT = 3,
|
||||
CCX_OF_RCWT = 4,
|
||||
CCX_OF_NULL = 5,
|
||||
CCX_OF_SMPTETT = 6,
|
||||
CCX_OF_SPUPNG = 7,
|
||||
CCX_OF_SPUPNG = 7,
|
||||
CCX_OF_DVDRAW = 8, // See -d at http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML#CCExtract
|
||||
CCX_OF_WEBVTT = 9,
|
||||
CCX_OF_SIMPLE_XML = 10,
|
||||
};
|
||||
|
||||
enum ccx_output_date_format
|
||||
@@ -165,45 +178,49 @@ enum ccx_output_date_format
|
||||
|
||||
enum ccx_stream_mode_enum
|
||||
{
|
||||
CCX_SM_ELEMENTARY_OR_NOT_FOUND=0,
|
||||
CCX_SM_TRANSPORT=1,
|
||||
CCX_SM_PROGRAM=2,
|
||||
CCX_SM_ASF=3,
|
||||
CCX_SM_MCPOODLESRAW = 4,
|
||||
CCX_SM_RCWT = 5, // Raw Captions With Time, not used yet.
|
||||
CCX_SM_MYTH = 6, // Use the myth loop
|
||||
CCX_SM_ELEMENTARY_OR_NOT_FOUND=0,
|
||||
CCX_SM_TRANSPORT=1,
|
||||
CCX_SM_PROGRAM=2,
|
||||
CCX_SM_ASF=3,
|
||||
CCX_SM_MCPOODLESRAW = 4,
|
||||
CCX_SM_RCWT = 5, // Raw Captions With Time, not used yet.
|
||||
CCX_SM_MYTH = 6, // Use the myth loop
|
||||
CCX_SM_MP4 = 7, // MP4, ISO-
|
||||
#ifdef WTV_DEBUG
|
||||
CCX_SM_HEX_DUMP = 8, // Hexadecimal dump generated by wtvccdump
|
||||
CCX_SM_WTV = 9,
|
||||
CCX_SM_AUTODETECT = 16
|
||||
#endif
|
||||
CCX_SM_WTV = 9,
|
||||
CCX_SM_AUTODETECT = 16
|
||||
};
|
||||
|
||||
enum ccx_encoding_type
|
||||
{
|
||||
CCX_ENC_UNICODE = 0,
|
||||
CCX_ENC_LATIN_1 = 1,
|
||||
CCX_ENC_UTF_8 = 2
|
||||
CCX_ENC_UNICODE = 0,
|
||||
CCX_ENC_LATIN_1 = 1,
|
||||
CCX_ENC_UTF_8 = 2,
|
||||
CCX_ENC_ASCII = 3
|
||||
};
|
||||
|
||||
enum ccx_bufferdata_type
|
||||
{
|
||||
CCX_UNKNOWN = 0,
|
||||
CCX_PES = 1,
|
||||
CCX_RAW = 2,
|
||||
CCX_H264 = 3,
|
||||
CCX_UNKNOWN = 0,
|
||||
CCX_PES = 1,
|
||||
CCX_RAW = 2,
|
||||
CCX_H264 = 3,
|
||||
CCX_HAUPPAGE = 4,
|
||||
CCX_TELETEXT = 5,
|
||||
CCX_PRIVATE_MPEG2_CC = 6,
|
||||
CCX_DVB_SUBTITLE = 7,
|
||||
CCX_ISDB_SUBTITLE = 8,
|
||||
};
|
||||
|
||||
enum ccx_frame_type
|
||||
{
|
||||
CCX_FRAME_TYPE_RESET_OR_UNKNOWN = 0,
|
||||
CCX_FRAME_TYPE_I_FRAME = 1,
|
||||
CCX_FRAME_TYPE_P_FRAME = 2,
|
||||
CCX_FRAME_TYPE_B_FRAME = 3,
|
||||
CCX_FRAME_TYPE_D_FRAME = 4
|
||||
CCX_FRAME_TYPE_RESET_OR_UNKNOWN = 0,
|
||||
CCX_FRAME_TYPE_I_FRAME = 1,
|
||||
CCX_FRAME_TYPE_P_FRAME = 2,
|
||||
CCX_FRAME_TYPE_B_FRAME = 3,
|
||||
CCX_FRAME_TYPE_D_FRAME = 4
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -212,13 +229,23 @@ typedef enum {
|
||||
UNDEF = 0xff
|
||||
} bool_t;
|
||||
|
||||
enum cxx_code_type
|
||||
enum ccx_code_type
|
||||
{
|
||||
CCX_CODEC_ANY,
|
||||
CCX_CODEC_TELETEXT,
|
||||
CCX_CODEC_DVB,
|
||||
CCX_CODEC_ISDB_CC,
|
||||
CCX_CODEC_ATSC_CC,
|
||||
CCX_CODEC_NONE,
|
||||
};
|
||||
|
||||
enum cdp_section_type
|
||||
{
|
||||
CDP_SECTION_DATA = 0x72,
|
||||
CDP_SECTION_SVC_INFO = 0x73,
|
||||
CDP_SECTION_FOOTER = 0x74
|
||||
};
|
||||
|
||||
/*
|
||||
* This Macro check whether descriptor tag is valid for teletext
|
||||
* codec or not.
|
||||
@@ -226,19 +253,19 @@ enum cxx_code_type
|
||||
* @param desc descriptor tag given for each stream
|
||||
*
|
||||
* @return if descriptor tag is valid then it return 1 otherwise 0
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define IS_VALID_TELETEXT_DESC(desc) ( ((desc) == CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR )|| \
|
||||
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
|
||||
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
|
||||
|
||||
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
|
||||
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
|
||||
|
||||
/*
|
||||
* This macro to be used when you want to find out whether you
|
||||
* should parse f_sel subtitle codec type or not
|
||||
*
|
||||
* @param u_sel pass the codec selected by user to be searched in
|
||||
* all elementry stream, we ignore the not to be selected stream
|
||||
* all elementary stream, we ignore the not to be selected stream
|
||||
* if we find stream this is selected stream. since setting
|
||||
* selected stream and not selected to same codec does not
|
||||
* make ay sense.
|
||||
@@ -251,12 +278,18 @@ enum cxx_code_type
|
||||
* to parse.
|
||||
*/
|
||||
#define IS_FEASIBLE(u_sel,u_nsel,f_sel) ( ( (u_sel) == CCX_CODEC_ANY && (u_nsel) != (f_sel) ) || (u_sel) == (f_sel) )
|
||||
#define CCX_TXT_FORBIDDEN 0 // Ignore teletext packets
|
||||
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
|
||||
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
|
||||
#define CCX_TXT_FORBIDDEN 0 // Ignore teletext packets
|
||||
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
|
||||
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
|
||||
|
||||
#define NB_LANGUAGE 5
|
||||
extern const char *language[NB_LANGUAGE];
|
||||
|
||||
#define CCX_OF_TYPE_TEXT 1
|
||||
#define CCX_OF_TYPE_IMAGE 2
|
||||
|
||||
#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
|
||||
132
src/lib_ccx/ccx_common_option.c
Normal file
132
src/lib_ccx/ccx_common_option.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#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
|
||||
#else
|
||||
options->buffer_input = 0; // In linux, not so much.
|
||||
#endif
|
||||
options->nofontcolor=0; // 1 = don't put <font color> tags
|
||||
options->notypesetting=0; // 1 = Don't put <i>, <u>, etc typesetting tags
|
||||
|
||||
|
||||
options->settings_608.direct_rollup = 0;
|
||||
options->settings_608.no_rollup = 0;
|
||||
options->settings_608.force_rollup = 0;
|
||||
options->settings_608.screens_to_process = -1;
|
||||
options->settings_608.default_color = COL_TRANSPARENT; // Defaults to transparant/no-color.
|
||||
|
||||
/* Credit stuff */
|
||||
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->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->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
|
||||
options->print_file_reports=0;
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
options->levdistmincnt=2; // Means 2 fails or less is "the same"...
|
||||
options->levdistmaxpct=10; // ...10% or less is also "the same"
|
||||
options->investigate_packets = 0; // Look for captions in all packets when everything else fails
|
||||
options->fullbin=0; // Disable pruning of padding cc blocks
|
||||
options->nosync=0; // Disable syncing
|
||||
options->hauppauge_mode=0; // If 1, use PID=1003, process specially and so on
|
||||
options->wtvconvertfix = 0; // Fix broken Windows 7 conversion
|
||||
options->wtvmpeg2 = 0;
|
||||
options->auto_myth = 2; // 2=auto
|
||||
/* MP4 related stuff */
|
||||
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->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->transcript_settings = ccx_encoders_default_transcript_settings;
|
||||
options->millis_separator=',';
|
||||
|
||||
options->write_format=CCX_OF_SRT; // 0=Raw, 1=srt, 2=SMI
|
||||
options->date_format=ODF_NONE;
|
||||
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
|
||||
/* Networking */
|
||||
options->udpaddr = NULL;
|
||||
options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
options->send_to_srv = 0;
|
||||
options->tcpport = NULL;
|
||||
options->tcp_password = NULL;
|
||||
options->tcp_desc = NULL;
|
||||
options->srv_addr = NULL;
|
||||
options->srv_port = NULL;
|
||||
options->noautotimeref=0; // Do NOT set time automatically?
|
||||
options->input_source=CCX_DS_FILE; // Files, stdin or network
|
||||
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->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);
|
||||
}
|
||||
144
src/lib_ccx/ccx_common_option.h
Normal file
144
src/lib_ccx/ccx_common_option.h
Normal file
@@ -0,0 +1,144 @@
|
||||
#ifndef CCX_COMMON_OPTION_H
|
||||
#define CCX_COMMON_OPTION_H
|
||||
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
#include "list.h"
|
||||
|
||||
struct demuxer_cfg
|
||||
{
|
||||
int m2ts; // Regular TS or M2TS
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
char *out_elementarystream_filename;
|
||||
|
||||
/* subtitle codec type */
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_code_type nocodec;
|
||||
|
||||
unsigned ts_autoprogram; // Try to find a stream with captions automatically (no -pn needed)
|
||||
unsigned ts_allprogram;
|
||||
unsigned ts_cappids[128]; // PID for stream that holds caption information
|
||||
int nb_ts_cappid;
|
||||
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
|
||||
int ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
unsigned ts_forced_program_selected;
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
};
|
||||
|
||||
struct encoder_cfg
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int dtvcc_extract; // 1 or 0
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
char *output_filename;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_date_format date_format;
|
||||
char millis_separator;
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
unsigned int send_to_srv;
|
||||
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
|
||||
char *first_input_file;
|
||||
int multiple_files;
|
||||
int no_font_color;
|
||||
int no_type_setting;
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int program_number;
|
||||
unsigned char in_format;
|
||||
|
||||
//CEA-708
|
||||
int services_enabled[CCX_DTVCC_MAX_SERVICES];
|
||||
char** services_charsets;
|
||||
char* all_services_charset;
|
||||
};
|
||||
struct ccx_s_options // Options from user parameters
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int no_rollup;
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
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 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
|
||||
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
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
|
||||
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 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
|
||||
/* MP4 related stuff */
|
||||
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 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
|
||||
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
enum ccx_output_date_format date_format;
|
||||
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
|
||||
/* Networking */
|
||||
char *udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
char *tcpport;
|
||||
char *tcp_password;
|
||||
char *tcp_desc;
|
||||
char *srv_addr;
|
||||
char *srv_port;
|
||||
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?
|
||||
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.
|
||||
int multiprogram;
|
||||
int out_interval;
|
||||
};
|
||||
|
||||
extern struct ccx_s_options ccx_options;
|
||||
void init_options (struct ccx_s_options *options);
|
||||
#endif
|
||||
115
src/lib_ccx/ccx_common_platform.h
Normal file
115
src/lib_ccx/ccx_common_platform.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#ifndef CCX_PLATFORM_H
|
||||
#define CCX_PLATFORM_H
|
||||
|
||||
// Default includes (cross-platform)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#ifdef _WIN32
|
||||
#define inline _inline
|
||||
#define typeof decltype
|
||||
#include <io.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
#include "inttypes.h"
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
typedef int socklen_t;
|
||||
typedef int ssize_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
#ifndef IN_CLASSD
|
||||
#define IN_CLASSD(i) (((INT32)(i) & 0xf0000000) == 0xe0000000)
|
||||
#define IN_MULTICAST(i) IN_CLASSD(i)
|
||||
#endif
|
||||
#include <direct.h>
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
#ifndef snprintf
|
||||
// Added ifndef because VS2013 warns for macro redefinition.
|
||||
#define snprintf(buf, len, fmt, ...) _snprintf(buf, len, fmt, __VA_ARGS__)
|
||||
#endif
|
||||
#define sleep(sec) Sleep((sec) * 1000)
|
||||
|
||||
#include <fcntl.h>
|
||||
#else // _WIN32
|
||||
#include <unistd.h>
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include "disable_warnings.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "stdintmsc.h"
|
||||
// Don't bug me with strcpy() deprecation warnings
|
||||
#pragma warning(disable : 4996)
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#define FOPEN64 fopen
|
||||
#define OPEN open
|
||||
#define FSEEK fseek
|
||||
#define FTELL ftell
|
||||
#define LSEEK lseek
|
||||
#define FSTAT fstat
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#define OPEN _open
|
||||
// 64 bit file functions
|
||||
#if defined(MSC_VER)
|
||||
extern "C" int __cdecl _fseeki64(FILE *, __int64, int);
|
||||
extern "C" __int64 __cdecl _ftelli64(FILE *);
|
||||
#define FSEEK _fseeki64
|
||||
#define FTELL _ftelli64
|
||||
#else
|
||||
// For MinGW
|
||||
#define FSEEK fseeko64
|
||||
#define FTELL ftello64
|
||||
#endif
|
||||
#define TELL _telli64
|
||||
#define LSEEK _lseeki64
|
||||
typedef struct _stati64 FSTATSTRUCT;
|
||||
#else
|
||||
// Linux internally maps these functions to 64bit usage,
|
||||
// if _FILE_OFFSET_BITS macro is set to 64
|
||||
#define FOPEN64 fopen
|
||||
#define OPEN open
|
||||
#define LSEEK lseek
|
||||
#define FSEEK fseek
|
||||
#define FTELL ftell
|
||||
#define FSTAT fstat
|
||||
#define TELL tell
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef int64_t_C
|
||||
#define int64_t_C(c) (c ## LL)
|
||||
#define uint64_t_C(c) (c ## ULL)
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0 // Not present in Linux because it's always binary
|
||||
#endif
|
||||
|
||||
typedef int64_t LLONG;
|
||||
|
||||
#endif // CCX_PLATFORM_H
|
||||
74
src/lib_ccx/ccx_common_structs.h
Normal file
74
src/lib_ccx/ccx_common_structs.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#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
|
||||
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION, // Called with line_num, xds_desc
|
||||
CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS // Called with current_xds_call_letters
|
||||
};
|
||||
|
||||
struct ccx_common_logging_t {
|
||||
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.
|
||||
void(*gui_ftn)(enum ccx_common_logging_gui message_type, ...); // Used to display things in a gui (if appropriate). Is called with the message_type and appropriate variables (described in enum)
|
||||
};
|
||||
extern struct ccx_common_logging_t ccx_common_logging;
|
||||
|
||||
enum subtype
|
||||
{
|
||||
CC_BITMAP,
|
||||
CC_608,
|
||||
CC_708,
|
||||
CC_TEXT,
|
||||
CC_RAW,
|
||||
};
|
||||
|
||||
/**
|
||||
* Raw Subtitle struct used as output of decoder (cc608)
|
||||
* and input for encoder (sami, srt, transcript or smptett etc)
|
||||
*
|
||||
* if subtype CC_BITMAP then data contain nb_data numbers of rectangle
|
||||
* which have to be displayed at same time.
|
||||
*/
|
||||
struct cc_subtitle
|
||||
{
|
||||
/**
|
||||
* A generic data which contain data according to decoder
|
||||
* @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
|
||||
367
src/lib_ccx/ccx_common_timing.c
Normal file
367
src/lib_ccx/ccx_common_timing.c
Normal file
@@ -0,0 +1,367 @@
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_common.h"
|
||||
|
||||
/* Provide the current time since the file (or the first file) started
|
||||
* in ms using PTS time information.
|
||||
* Requires: frames_since_ref_time, current_tref
|
||||
*/
|
||||
|
||||
// Count 608 (per field) and 708 blocks since last set_fts() call
|
||||
int cb_field1, cb_field2, cb_708;
|
||||
|
||||
int MPEG_CLOCK_FREQ = 90000; // This "constant" is part of the standard
|
||||
|
||||
int max_dif = 5;
|
||||
unsigned pts_big_change;
|
||||
|
||||
// PTS timing related stuff
|
||||
|
||||
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;
|
||||
|
||||
struct gop_time_code gop_time, first_gop_time, printed_gop;
|
||||
LLONG fts_at_gop_start = 0;
|
||||
int gop_rollover = 0;
|
||||
|
||||
struct ccx_common_timing_settings_t ccx_common_timing_settings;
|
||||
|
||||
void ccx_common_timing_init(LLONG *file_position,int no_sync)
|
||||
{
|
||||
ccx_common_timing_settings.disable_sync_check = 0;
|
||||
ccx_common_timing_settings.is_elementary_stream = 0;
|
||||
ccx_common_timing_settings.file_position = file_position;
|
||||
ccx_common_timing_settings.no_sync = no_sync;
|
||||
}
|
||||
|
||||
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 (!ctx->pts_set && ccx_common_timing_settings.is_elementary_stream)
|
||||
return CCX_OK;
|
||||
|
||||
// First check for timeline jump (only when min_pts was set (implies sync_pts)).
|
||||
int dif = 0;
|
||||
if (ctx->pts_set == 2)
|
||||
{
|
||||
dif=(int) (ctx->current_pts - ctx->sync_pts)/MPEG_CLOCK_FREQ;
|
||||
|
||||
if (ccx_common_timing_settings.disable_sync_check){
|
||||
// Disables sync check. Used for several input formats.
|
||||
dif = 0;
|
||||
}
|
||||
|
||||
if (dif < -0.2 || dif >= max_dif )
|
||||
{
|
||||
// ATSC specs: More than 3501 ms means missing component
|
||||
ccx_common_logging.log_ftn ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, *ccx_common_timing_settings.file_position);
|
||||
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",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(ctx->current_tref != 0 && ctx->current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
|
||||
{
|
||||
ctx->fts_now = ctx->fts_max;
|
||||
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
|
||||
return CCX_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set min_pts, fts_offset
|
||||
if (ctx->pts_set != 0)
|
||||
{
|
||||
ctx->pts_set = 2;
|
||||
|
||||
// Use this part only the first time min_pts is set. Later treat
|
||||
// it as a reference clock change
|
||||
if (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
|
||||
|
||||
ctx->min_pts = ctx->current_pts;
|
||||
|
||||
// Avoid next async test
|
||||
ctx->sync_pts = (LLONG)(ctx->current_pts
|
||||
-ctx->current_tref*1000.0/current_fps
|
||||
*(MPEG_CLOCK_FREQ/1000));
|
||||
|
||||
if(ctx->current_tref == 0)
|
||||
{ // Earliest time in GOP.
|
||||
ctx->fts_offset = 0;
|
||||
}
|
||||
else if ( total_frames_count-frames_since_ref_time == 0 )
|
||||
{ // If this is the first frame (PES) there cannot be an offset.
|
||||
// This part is also reached for dvr-ms/NTSC (RAW) as
|
||||
// total_frames_count = frames_since_ref_time = 0 when
|
||||
// this is called for the first time.
|
||||
ctx->fts_offset = 0;
|
||||
}
|
||||
else
|
||||
{ // It needs to be "+1" because the current frame is
|
||||
// not yet counted.
|
||||
ctx->fts_offset = (LLONG)((total_frames_count
|
||||
-frames_since_ref_time+1)
|
||||
*1000.0/current_fps);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nFirst sync time PTS: %s %+lldms (time before this PTS)\n",
|
||||
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
ctx->fts_offset );
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
|
||||
total_frames_count, frames_since_ref_time);
|
||||
}
|
||||
|
||||
// -nosync disables syncing
|
||||
if (pts_jump && !ccx_common_timing_settings.no_sync)
|
||||
{
|
||||
// The current time in the old time base is calculated using
|
||||
// sync_pts (set at the beginning of the last GOP) plus the
|
||||
// time of the frames since then.
|
||||
ctx->fts_offset = ctx->fts_offset
|
||||
+ (ctx->sync_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ (LLONG) (frames_since_ref_time*1000/current_fps);
|
||||
ctx->fts_max = ctx->fts_offset;
|
||||
|
||||
// Start counting again from here
|
||||
ctx->pts_set = 1; // Force min to be set again
|
||||
|
||||
// Avoid next async test - the gap might have occured on
|
||||
// current_tref != 0.
|
||||
ctx->sync_pts = (LLONG) (ctx->current_pts
|
||||
-ctx->current_tref*1000.0/current_fps
|
||||
*(MPEG_CLOCK_FREQ/1000));
|
||||
// Set min_pts = sync_pts as this is used for fts_now
|
||||
ctx->min_pts = ctx->sync_pts;
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n",
|
||||
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
ctx->fts_offset );
|
||||
}
|
||||
}
|
||||
|
||||
// Set sync_pts, fts_offset
|
||||
if(ctx->current_tref == 0)
|
||||
ctx->sync_pts = ctx->current_pts;
|
||||
|
||||
// Reset counters
|
||||
cb_field1 = 0;
|
||||
cb_field2 = 0;
|
||||
cb_708 = 0;
|
||||
|
||||
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
|
||||
// for uninitialized min_pts
|
||||
if (1) // CFS: Remove or think decent condition
|
||||
{
|
||||
if ( ctx->pts_set )
|
||||
{
|
||||
// If pts_set is TRUE we have min_pts
|
||||
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.log_ftn("Set PTS called without any global timestamp set\n");
|
||||
return CCX_EINVAL;
|
||||
}
|
||||
}
|
||||
if ( ctx->fts_now > ctx->fts_max )
|
||||
{
|
||||
ctx->fts_max = ctx->fts_now;
|
||||
}
|
||||
return CCX_OK;
|
||||
}
|
||||
|
||||
|
||||
LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
LLONG fts;
|
||||
|
||||
switch (current_field)
|
||||
{
|
||||
case 1:
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_field1*1001/30;
|
||||
break;
|
||||
case 2:
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_field2*1001/30;
|
||||
break;
|
||||
case 3:
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_708*1001/30;
|
||||
break;
|
||||
default:
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "get_fts: unhandled branch");
|
||||
}
|
||||
// ccx_common_logging.debug_ftn(CCX_DMT_TIME, "[FTS] "
|
||||
// "fts: %llu, fts_now: %llu, fts_global: %llu, current_field: %llu, cb_708: %llu\n",
|
||||
// fts, fts_now, fts_global, current_field, cb_708);
|
||||
return fts;
|
||||
}
|
||||
|
||||
LLONG get_fts_max(struct ccx_common_timing_ctx *ctx)
|
||||
{
|
||||
// This returns the maximum FTS that belonged to a frame. Caption block
|
||||
// counters are not applicable.
|
||||
return ctx->fts_max + ctx->fts_global;
|
||||
}
|
||||
|
||||
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
|
||||
to the microsecond value in mstime. */
|
||||
char *print_mstime2buf( LLONG mstime , 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 = (int) (mstime - 1000*(ss + 60*(mm + 60*hh)));
|
||||
|
||||
buf[0]='-';
|
||||
sprintf (buf+signoffset, "%02u:%02u:%02u:%03u",hh,mm,ss,ms);
|
||||
|
||||
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 )
|
||||
{
|
||||
static char buf[15]; // 14 should be long enough
|
||||
return print_mstime2buf (mstime, buf);
|
||||
}
|
||||
|
||||
/* Helper function for to display debug timing info. */
|
||||
void print_debug_timing(struct ccx_common_timing_ctx *ctx)
|
||||
{
|
||||
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
|
||||
// for uninitialized min_pts
|
||||
LLONG tempmin_pts = (ctx->min_pts==0x01FFFFFFFFLL ? ctx->sync_pts : ctx->min_pts);
|
||||
|
||||
ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ",
|
||||
print_mstime((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)((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(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(ctx)+(LLONG)(1000.0/current_fps)-ptslenms,
|
||||
get_fts_max(ctx)+(LLONG)(1000.0/current_fps)-goplenms);
|
||||
}
|
||||
|
||||
void calculate_ms_gop_time (struct gop_time_code *g)
|
||||
{
|
||||
int seconds=(g->time_code_hours*3600)+(g->time_code_minutes*60)+g->time_code_seconds;
|
||||
g->ms = (LLONG)( 1000*(seconds + g->time_code_pictures/current_fps) );
|
||||
if (gop_rollover)
|
||||
g->ms += 24*60*60*1000;
|
||||
}
|
||||
|
||||
int gop_accepted(struct gop_time_code* g )
|
||||
{
|
||||
if (! ((g->time_code_hours <= 23)
|
||||
&& (g->time_code_minutes <= 59)
|
||||
&& (g->time_code_seconds <= 59)
|
||||
&& (g->time_code_pictures <= 59)))
|
||||
return 0;
|
||||
|
||||
if (gop_time.time_code_hours==23 && gop_time.time_code_minutes==59 &&
|
||||
g->time_code_hours==0 && g->time_code_minutes==0)
|
||||
{
|
||||
gop_rollover = 1;
|
||||
return 1;
|
||||
}
|
||||
if (gop_time.inited)
|
||||
{
|
||||
if (gop_time.ms > g->ms)
|
||||
{
|
||||
// We are going back in time but it's not a complete day rollover
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
85
src/lib_ccx/ccx_common_timing.h
Normal file
85
src/lib_ccx/ccx_common_timing.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef __Timing_H__
|
||||
#define __Timing_H__
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
struct gop_time_code
|
||||
{
|
||||
int drop_frame_flag;
|
||||
int time_code_hours;
|
||||
int time_code_minutes;
|
||||
int marker_bit;
|
||||
int time_code_seconds;
|
||||
int time_code_pictures;
|
||||
int inited;
|
||||
LLONG ms;
|
||||
};
|
||||
|
||||
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.
|
||||
LLONG *file_position; // The position of the file
|
||||
};
|
||||
extern struct ccx_common_timing_settings_t ccx_common_timing_settings;
|
||||
|
||||
struct ccx_boundary_time
|
||||
{
|
||||
int hh,mm,ss;
|
||||
LLONG time_in_ms;
|
||||
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 MPEG_CLOCK_FREQ; // This is part of the standard
|
||||
|
||||
extern int max_dif;
|
||||
extern unsigned pts_big_change;
|
||||
|
||||
|
||||
extern enum ccx_frame_type current_picture_coding_type;
|
||||
extern double current_fps;
|
||||
extern int frames_since_ref_time;
|
||||
extern unsigned total_frames_count;
|
||||
|
||||
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 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);
|
||||
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);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
148
src/lib_ccx/ccx_decoders_608.h
Normal file
148
src/lib_ccx/ccx_decoders_608.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#ifndef CCX_DECODER_608_H
|
||||
#define CCX_DECODER_608_H
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
|
||||
extern LLONG ts_start_of_xds;
|
||||
|
||||
/*
|
||||
This variable (ccx_decoder_608_report) holds data on the cc channels & xds packets that are encountered during file parse.
|
||||
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
|
||||
for the report functionality.
|
||||
*/
|
||||
struct ccx_decoder_608_report
|
||||
{
|
||||
uint8_t xds : 1;
|
||||
uint8_t cc_channels[4];
|
||||
};
|
||||
|
||||
typedef struct ccx_decoder_608_settings
|
||||
{
|
||||
int direct_rollup; // Write roll-up captions directly instead of line by line?
|
||||
int force_rollup; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
unsigned char default_color; // Default color to use.
|
||||
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
|
||||
struct ccx_decoder_608_report *report;
|
||||
} ccx_decoder_608_settings;
|
||||
|
||||
typedef struct ccx_decoder_608_context
|
||||
{
|
||||
ccx_decoder_608_settings *settings;
|
||||
eia608_screen buffer1;
|
||||
eia608_screen buffer2;
|
||||
int cursor_row, cursor_column;
|
||||
int visible_buffer;
|
||||
int screenfuls_counter; // Number of meaningful screenfuls written
|
||||
LLONG current_visible_start_ms; // At what time did the current visible buffer became so?
|
||||
enum cc_modes mode;
|
||||
unsigned char last_c1, last_c2;
|
||||
int channel; // Currently selected channel
|
||||
unsigned char current_color; // Color we are currently using to write
|
||||
unsigned char font; // Font we are currently using to write
|
||||
int rollup_base_row;
|
||||
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
|
||||
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
|
||||
int new_channel; // The new channel after a channel change
|
||||
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
|
||||
int have_cursor_position;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
#define MAX_COLOR 10
|
||||
extern const char *color_text[MAX_COLOR][2];
|
||||
|
||||
typedef enum ccx_decoder_608_color_code
|
||||
{
|
||||
COL_WHITE = 0,
|
||||
COL_GREEN = 1,
|
||||
COL_BLUE = 2,
|
||||
COL_CYAN = 3,
|
||||
COL_RED = 4,
|
||||
COL_YELLOW = 5,
|
||||
COL_MAGENTA = 6,
|
||||
COL_USERDEFINED = 7,
|
||||
COL_BLACK = 8,
|
||||
COL_TRANSPARENT = 9
|
||||
} ccx_decoder_608_color_code;
|
||||
|
||||
|
||||
enum font_bits
|
||||
{
|
||||
FONT_REGULAR = 0,
|
||||
FONT_ITALICS = 1,
|
||||
FONT_UNDERLINED = 2,
|
||||
FONT_UNDERLINED_ITALICS = 3
|
||||
};
|
||||
|
||||
enum command_code
|
||||
{
|
||||
COM_UNKNOWN = 0,
|
||||
COM_ERASEDISPLAYEDMEMORY = 1,
|
||||
COM_RESUMECAPTIONLOADING = 2,
|
||||
COM_ENDOFCAPTION = 3,
|
||||
COM_TABOFFSET1 = 4,
|
||||
COM_TABOFFSET2 = 5,
|
||||
COM_TABOFFSET3 = 6,
|
||||
COM_ROLLUP2 = 7,
|
||||
COM_ROLLUP3 = 8,
|
||||
COM_ROLLUP4 = 9,
|
||||
COM_CARRIAGERETURN = 10,
|
||||
COM_ERASENONDISPLAYEDMEMORY = 11,
|
||||
COM_BACKSPACE = 12,
|
||||
COM_RESUMETEXTDISPLAY = 13,
|
||||
COM_ALARMOFF =14,
|
||||
COM_ALARMON = 15,
|
||||
COM_DELETETOENDOFROW = 16,
|
||||
COM_RESUMEDIRECTCAPTIONING = 17,
|
||||
// Non existing commands we insert to have the decoder
|
||||
// special stuff for us.
|
||||
COM_FAKE_RULLUP1 = 18
|
||||
};
|
||||
|
||||
|
||||
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 *halt,
|
||||
int cc_to_stdout,
|
||||
enum ccx_output_format output_format, struct ccx_common_timing_ctx *timing);
|
||||
|
||||
/**
|
||||
* @param data raw cc608 data to be processed
|
||||
*
|
||||
* @param length length of data passed
|
||||
*
|
||||
* @param private_data context of cc608 where important information related to 608
|
||||
* are stored.
|
||||
*
|
||||
* @param sub pointer to subtitle should be memset to 0 when passed first time
|
||||
* subtitle are stored when structure return
|
||||
*
|
||||
* @return number of bytes used from data, -1 when any error is encountered
|
||||
*/
|
||||
int process608(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
|
||||
/**
|
||||
* Issue a EraseDisplayedMemory here so if there's any captions pending
|
||||
* they get written to cc_subtitle
|
||||
*/
|
||||
void 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);
|
||||
|
||||
#endif
|
||||
1591
src/lib_ccx/ccx_decoders_708.c
Normal file
1591
src/lib_ccx/ccx_decoders_708.c
Normal file
File diff suppressed because it is too large
Load Diff
372
src/lib_ccx/ccx_decoders_708.h
Normal file
372
src/lib_ccx/ccx_decoders_708.h
Normal file
@@ -0,0 +1,372 @@
|
||||
#ifndef _INCLUDE_708_
|
||||
#define _INCLUDE_708_
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
|
||||
#define CCX_DTVCC_MAX_PACKET_LENGTH 128 //According to EIA-708B, part 5
|
||||
#define CCX_DTVCC_MAX_SERVICES 63
|
||||
|
||||
#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 CCX_DTVCC_SCREENGRID_ROWS 75
|
||||
#define CCX_DTVCC_SCREENGRID_COLUMNS 210
|
||||
|
||||
#define CCX_DTVCC_MAX_WINDOWS 8
|
||||
|
||||
#define CCX_DTVCC_FILENAME_TEMPLATE ".p%u.svc%02u"
|
||||
|
||||
#define CCX_DTVCC_NO_LAST_SEQUENCE -1
|
||||
|
||||
enum CCX_DTVCC_COMMANDS_C0_CODES
|
||||
{
|
||||
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 CCX_DTVCC_COMMANDS_C1_CODES
|
||||
{
|
||||
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 CCX_DTVCC_S_COMMANDS_C1
|
||||
{
|
||||
int code;
|
||||
const char *name;
|
||||
const char *description;
|
||||
int length;
|
||||
};
|
||||
|
||||
enum ccx_dtvcc_window_justify
|
||||
{
|
||||
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 ccx_dtvcc_window_pd //Print Direction
|
||||
{
|
||||
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 ccx_dtvcc_window_sd //Scroll Direction
|
||||
{
|
||||
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 ccx_dtvcc_window_sde //Scroll Display Effect
|
||||
{
|
||||
CCX_DTVCC_WINDOW_SDE_SNAP = 0,
|
||||
CCX_DTVCC_WINDOW_SDE_FADE = 1,
|
||||
CCX_DTVCC_WINDOW_SDE_WIPE = 2
|
||||
};
|
||||
|
||||
enum ccx_dtvcc_window_ed //Effect Direction
|
||||
{
|
||||
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 ccx_dtvcc_window_fo //Fill Opacity
|
||||
{
|
||||
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 ccx_dtvcc_window_border
|
||||
{
|
||||
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 ccx_dtvcc_pen_size
|
||||
{
|
||||
CCX_DTVCC_PEN_SIZE_SMALL = 0,
|
||||
CCX_DTVCC_PEN_SIZE_STANDART = 1,
|
||||
CCX_DTVCC_PEN_SIZE_LARGE = 2
|
||||
};
|
||||
|
||||
enum ccx_dtvcc_pen_font_style
|
||||
{
|
||||
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 ccx_dtvcc_pen_text_tag
|
||||
{
|
||||
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 ccx_dtvcc_pen_offset
|
||||
{
|
||||
CCX_DTVCC_PEN_OFFSET_SUBSCRIPT = 0,
|
||||
CCX_DTVCC_PEN_OFFSET_NORMAL = 1,
|
||||
CCX_DTVCC_PEN_OFFSET_SUPERSCRIPT = 2
|
||||
};
|
||||
|
||||
enum ccx_dtvcc_pen_edge
|
||||
{
|
||||
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 ccx_dtvcc_pen_anchor_point
|
||||
{
|
||||
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 ccx_dtvcc_pen_color
|
||||
{
|
||||
int fg_color;
|
||||
int fg_opacity;
|
||||
int bg_color;
|
||||
int bg_opacity;
|
||||
int edge_color;
|
||||
} ccx_dtvcc_pen_color;
|
||||
|
||||
typedef struct ccx_dtvcc_pen_attribs
|
||||
{
|
||||
int pen_size;
|
||||
int offset;
|
||||
int text_tag;
|
||||
int font_tag;
|
||||
int edge_type;
|
||||
int underline;
|
||||
int italic;
|
||||
} ccx_dtvcc_pen_attribs;
|
||||
|
||||
typedef struct 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_type;
|
||||
int border_color;
|
||||
} ccx_dtvcc_window_attribs;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
int priority;
|
||||
int col_lock;
|
||||
int row_lock;
|
||||
int visible;
|
||||
int anchor_vertical;
|
||||
int relative_pos;
|
||||
int anchor_horizontal;
|
||||
int row_count;
|
||||
int anchor_point;
|
||||
int col_count;
|
||||
int pen_style;
|
||||
int win_style;
|
||||
unsigned char commands[6]; // Commands used to create this window
|
||||
ccx_dtvcc_window_attribs attribs;
|
||||
int pen_row;
|
||||
int pen_column;
|
||||
ccx_dtvcc_symbol *rows[CCX_DTVCC_MAX_ROWS];
|
||||
ccx_dtvcc_pen_color pen_colors[CCX_DTVCC_MAX_ROWS];
|
||||
ccx_dtvcc_pen_attribs pen_attribs[CCX_DTVCC_MAX_ROWS];
|
||||
int memory_reserved;
|
||||
int is_empty;
|
||||
LLONG time_ms_show;
|
||||
LLONG time_ms_hide;
|
||||
} ccx_dtvcc_window;
|
||||
|
||||
typedef struct dtvcc_tv_screen
|
||||
{
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
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;
|
||||
dtvcc_tv_screen *tv;
|
||||
int cc_count;
|
||||
} ccx_dtvcc_service_decoder;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* solution requires "sink" or "writer" entity to write captions to output file
|
||||
* decoders have to know nothing about output files
|
||||
*/
|
||||
|
||||
typedef struct ccx_dtvcc_ctx
|
||||
{
|
||||
int is_active;
|
||||
int active_services_count;
|
||||
int services_active[CCX_DTVCC_MAX_SERVICES]; //0 - inactive, 1 - active
|
||||
int report_enabled;
|
||||
|
||||
ccx_decoder_dtvcc_report *report;
|
||||
|
||||
ccx_dtvcc_service_decoder decoders[CCX_DTVCC_MAX_SERVICES];
|
||||
|
||||
unsigned char current_packet[CCX_DTVCC_MAX_PACKET_LENGTH];
|
||||
int current_packet_length;
|
||||
|
||||
int last_sequence;
|
||||
|
||||
void *encoder; //we can't include header, so keeping it this way
|
||||
int no_rollup;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
} ccx_dtvcc_ctx;
|
||||
|
||||
|
||||
void ccx_dtvcc_clear_packet(ccx_dtvcc_ctx *ctx);
|
||||
void ccx_dtvcc_windows_reset(ccx_dtvcc_service_decoder *decoder);
|
||||
void ccx_dtvcc_decoder_flush(ccx_dtvcc_ctx *dtvcc, ccx_dtvcc_service_decoder *decoder);
|
||||
|
||||
void ccx_dtvcc_process_current_packet(ccx_dtvcc_ctx *dtvcc);
|
||||
void ccx_dtvcc_process_service_block(ccx_dtvcc_ctx *dtvcc,
|
||||
ccx_dtvcc_service_decoder *decoder,
|
||||
unsigned char *data,
|
||||
int data_length);
|
||||
|
||||
#endif
|
||||
45
src/lib_ccx/ccx_decoders_708_encoding.c
Normal file
45
src/lib_ccx/ccx_decoders_708_encoding.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/********************************************************
|
||||
256 BYTES IS ENOUGH FOR ALL THE SUPPORTED CHARACTERS IN
|
||||
EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
|
||||
|
||||
00-1F -> Characters that are in the G2 group in 20-3F,
|
||||
except for 06, which is used for the closed captions
|
||||
sign "CC" which is defined in group G3 as 00. (this
|
||||
is by the article 33).
|
||||
20-7F -> Group G0 as is - corresponds to the ASCII code
|
||||
80-9F -> Characters that are in the G2 group in 60-7F
|
||||
(there are several blank characters here, that's OK)
|
||||
A0-FF -> Group G1 as is - non-English characters and symbols
|
||||
*/
|
||||
|
||||
unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char)
|
||||
{
|
||||
return g0_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 dtvcc_get_internal_from_G2(unsigned char g2_char)
|
||||
{
|
||||
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 dtvcc_get_internal_from_G3(unsigned char g3_char)
|
||||
{
|
||||
if (g3_char == 0xa0) // The "CC" (closed captions) sign
|
||||
return 0x06;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
}
|
||||
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), (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_*/
|
||||
392
src/lib_ccx/ccx_decoders_common.c
Normal file
392
src/lib_ccx/ccx_decoders_common.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/* Functions used by both the 608 and 708 decoders. An effort should be
|
||||
made to reuse, not duplicate, as many functions as possible */
|
||||
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_char_encoding.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#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;
|
||||
|
||||
|
||||
/* 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 (struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
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 ctxget_visible_start */
|
||||
LLONG get_visible_end (struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int j = 0; j < cc_count * 3; j = j + 3)
|
||||
{
|
||||
if (validate_cc_data_pair( cc_data + j ) )
|
||||
continue;
|
||||
ret = do_cb(ctx, cc_data + j, sub);
|
||||
if (ret == 1) //1 means success here
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int validate_cc_data_pair (unsigned char *cc_data_pair)
|
||||
{
|
||||
unsigned char cc_valid = (*cc_data_pair & 4) >>2;
|
||||
unsigned char cc_type = *cc_data_pair & 3;
|
||||
|
||||
if (!cc_valid)
|
||||
return -1;
|
||||
|
||||
if (cc_type==0 || cc_type==1)
|
||||
{
|
||||
// For EIA-608 data we verify parity.
|
||||
if (!cc608_parity_table[cc_data_pair[2]])
|
||||
{
|
||||
// If the second byte doesn't pass parity, ignore pair
|
||||
return -1;
|
||||
}
|
||||
if (!cc608_parity_table[cc_data_pair[1]])
|
||||
{
|
||||
// The first byte doesn't pass parity, we replace it with a solid blank
|
||||
// and process the pair.
|
||||
cc_data_pair[1]=0x7F;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char cc_valid = (*cc_block & 4) >>2;
|
||||
unsigned char cc_type = *cc_block & 3;
|
||||
|
||||
int timeok = 1;
|
||||
|
||||
if ( ctx->fix_padding
|
||||
&& cc_valid==0 && cc_type <= 1 // Only fix NTSC packets
|
||||
&& cc_block[1]==0 && cc_block[2]==0 )
|
||||
{
|
||||
/* Padding */
|
||||
cc_valid=1;
|
||||
cc_block[1]=0x80;
|
||||
cc_block[2]=0x80;
|
||||
}
|
||||
|
||||
if ( ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
|
||||
ctx->write_format!=CCX_OF_DVDRAW &&
|
||||
(cc_block[0]==0xFA || cc_block[0]==0xFC || cc_block[0]==0xFD )
|
||||
&& (cc_block[1]&0x7F)==0 && (cc_block[2]&0x7F)==0) // CFS: Skip non-data, makes debugging harder.
|
||||
return 1;
|
||||
|
||||
// Print raw data with FTS.
|
||||
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(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 dtvcc_process_data() must not be called for
|
||||
* the CCX_OF_RCWT case. */
|
||||
|
||||
if (cc_valid || cc_type==3)
|
||||
{
|
||||
ctx->cc_stats[cc_type]++;
|
||||
|
||||
switch (cc_type)
|
||||
{
|
||||
case 0:
|
||||
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
|
||||
|
||||
ctx->current_field = 1;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
printdata (ctx, cc_block+1,2,0,0, sub);
|
||||
else
|
||||
writercwtdata(ctx, cc_block, sub);
|
||||
}
|
||||
cb_field1++;
|
||||
break;
|
||||
case 1:
|
||||
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
|
||||
|
||||
ctx->current_field = 2;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
printdata (ctx, 0,0,cc_block+1,2, sub);
|
||||
else
|
||||
writercwtdata(ctx, cc_block, sub);
|
||||
}
|
||||
cb_field2++;
|
||||
break;
|
||||
case 2: //EIA-708
|
||||
// DTVCC packet data
|
||||
// Fall through
|
||||
case 3: //EIA-708
|
||||
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
|
||||
|
||||
// DTVCC packet start
|
||||
ctx->current_field = 3;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
char temp[4];
|
||||
temp[0]=cc_valid;
|
||||
temp[1]=cc_type;
|
||||
temp[2]=cc_block[1];
|
||||
temp[3]=cc_block[2];
|
||||
if (timeok)
|
||||
{
|
||||
if (ctx->write_format != CCX_OF_RCWT)
|
||||
ccx_dtvcc_process_data(ctx, (const unsigned char *) temp, 4);
|
||||
else
|
||||
writercwtdata(ctx, cc_block, sub);
|
||||
}
|
||||
cb_708++;
|
||||
// Check for bytes read
|
||||
// printf ("Warning: Losing EIA-708 data!\n");
|
||||
break;
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
|
||||
} // switch (cc_type)
|
||||
} // cc_valid
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_CBRAW, " .. .. ..\n");
|
||||
dbg_print(CCX_DMT_VERBOSE, "Found !(cc_valid || cc_type==3) - ignore this block\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ctx = malloc(sizeof(struct lib_cc_decode));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->avc_ctx = init_avc();
|
||||
ctx->codec = setting->codec;
|
||||
ctx->timing = init_timing_ctx(&ccx_common_timing_settings);
|
||||
|
||||
setting->settings_dtvcc->timing = ctx->timing;
|
||||
|
||||
setting->settings_608->no_rollup = setting->no_rollup;
|
||||
setting->settings_dtvcc->no_rollup = setting->no_rollup;
|
||||
ctx->no_rollup = setting->no_rollup;
|
||||
|
||||
ctx->dtvcc = ccx_dtvcc_init(setting->settings_dtvcc);
|
||||
ctx->dtvcc->is_active = setting->settings_dtvcc->enabled;
|
||||
|
||||
if(setting->codec == CCX_CODEC_ATSC_CC)
|
||||
{
|
||||
// Prepare 608 context
|
||||
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
1,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->output_format,
|
||||
ctx->timing
|
||||
);
|
||||
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
2,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->output_format,
|
||||
ctx->timing
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->context_cc608_field_1 = NULL;
|
||||
ctx->context_cc608_field_2 = NULL;
|
||||
}
|
||||
ctx->current_field = 1;
|
||||
ctx->private_data = setting->private_data;
|
||||
ctx->fix_padding = setting->fix_padding;
|
||||
ctx->write_format = setting->output_format;
|
||||
ctx->subs_delay = setting->subs_delay;
|
||||
ctx->extract = setting->extract;
|
||||
ctx->fullbin = setting->fullbin;
|
||||
ctx->hauppauge_mode = setting->hauppauge_mode;
|
||||
ctx->program_number = setting->program_number;
|
||||
ctx->processed_enough = 0;
|
||||
ctx->max_gop_length = 0;
|
||||
ctx->has_ccdata_buffered = 0;
|
||||
ctx->in_bufferdatatype = CCX_UNKNOWN;
|
||||
ctx->frames_since_last_gop = 0;
|
||||
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
|
||||
if (setting->send_to_srv)
|
||||
ctx->writedata = net_send_cc;
|
||||
else if (setting->output_format==CCX_OF_RAW ||
|
||||
setting->output_format==CCX_OF_DVDRAW ||
|
||||
setting->output_format==CCX_OF_RCWT )
|
||||
ctx->writedata = writeraw;
|
||||
else if (setting->output_format==CCX_OF_SMPTETT ||
|
||||
setting->output_format==CCX_OF_SAMI ||
|
||||
setting->output_format==CCX_OF_SRT ||
|
||||
setting->output_format == CCX_OF_WEBVTT ||
|
||||
setting->output_format==CCX_OF_TRANSCRIPT ||
|
||||
setting->output_format==CCX_OF_SPUPNG ||
|
||||
setting->output_format==CCX_OF_SIMPLE_XML ||
|
||||
setting->output_format==CCX_OF_NULL)
|
||||
ctx->writedata = process608;
|
||||
else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid Write Format Selected");
|
||||
|
||||
memset (&ctx->dec_sub, 0,sizeof(ctx->dec_sub));
|
||||
|
||||
// Initialize HDTV caption buffer
|
||||
init_hdcc(ctx);
|
||||
|
||||
ctx->current_hor_size = 0;
|
||||
ctx->current_vert_size = 0;
|
||||
ctx->current_aspect_ratio = 0;
|
||||
ctx->current_frame_rate = 4; // Assume standard fps, 29.97
|
||||
|
||||
//Variables used while parsing elementry stream
|
||||
ctx->no_bitstream_error = 0;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
ctx->in_pic_data = 0;
|
||||
|
||||
ctx->current_progressive_sequence = 2;
|
||||
ctx->current_pulldownfields = 32768;
|
||||
|
||||
ctx->temporal_reference = 0;
|
||||
ctx->maxtref = 0;
|
||||
ctx->picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
ctx->picture_structure = 0;
|
||||
ctx->top_field_first = 0;
|
||||
ctx->repeat_first_field = 0;
|
||||
ctx->progressive_frame = 0;
|
||||
ctx->pulldownfields = 0;
|
||||
//es parser related variable ends here
|
||||
|
||||
memset(ctx->cc_stats, 0, 4 * sizeof(int));
|
||||
|
||||
ctx->anchor_seq_number = -1;
|
||||
// Init XDS buffers
|
||||
if(setting->ignore_xds == CCX_TRUE)
|
||||
ctx->xds_ctx = NULL;
|
||||
else
|
||||
ctx->xds_ctx = ccx_decoders_xds_init_library(ctx->timing);
|
||||
//xds_cea608_test(ctx->xds_ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/lib_ccx/ccx_decoders_common.h
Normal file
28
src/lib_ccx/ccx_decoders_common.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _CC_DECODER_COMMON
|
||||
#define _CC_DECODER_COMMON
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
extern uint64_t utc_refvalue; // UTC referential value
|
||||
|
||||
// Declarations
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
int validate_cc_data_pair (unsigned char *cc_data_pair);
|
||||
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub);
|
||||
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub);
|
||||
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
|
||||
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
|
||||
186
src/lib_ccx/ccx_decoders_structs.h
Normal file
186
src/lib_ccx/ccx_decoders_structs.h
Normal file
@@ -0,0 +1,186 @@
|
||||
#ifndef CCX_DECODERS_STRUCTS_H
|
||||
#define CCX_DECODERS_STRUCTS_H
|
||||
|
||||
#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 )
|
||||
struct cc_bitmap
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int nb_colors;
|
||||
unsigned char *data[2];
|
||||
int linesize[2];
|
||||
#ifdef ENABLE_OCR
|
||||
char *ocr_text;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum ccx_eia608_format
|
||||
{
|
||||
SFORMAT_CC_SCREEN,
|
||||
SFORMAT_CC_LINE,
|
||||
SFORMAT_XDS
|
||||
};
|
||||
|
||||
enum cc_modes
|
||||
{
|
||||
MODE_POPON = 0,
|
||||
MODE_ROLLUP_2 = 1,
|
||||
MODE_ROLLUP_3 = 2,
|
||||
MODE_ROLLUP_4 = 3,
|
||||
MODE_TEXT = 4,
|
||||
MODE_PAINTON = 5,
|
||||
// Fake modes to emulate stuff
|
||||
MODE_FAKE_ROLLUP_1 = 100
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure have fields which need to be ignored according to format,
|
||||
* for example if format is SFORMAT_XDS then all fields other then
|
||||
* xds related (xds_str, xds_len and cur_xds_packet_class) should be
|
||||
* ignored and not to be derefrenced.
|
||||
*
|
||||
* TODO use union inside struct for each kind of fields
|
||||
*/
|
||||
typedef struct eia608_screen // A CC buffer
|
||||
{
|
||||
/** format of data inside this structure */
|
||||
enum ccx_eia608_format format;
|
||||
unsigned char characters[15][33];
|
||||
unsigned char colors[15][33];
|
||||
unsigned char fonts[15][33]; // Extra char at the end for a 0
|
||||
int row_used[15]; // Any data in row?
|
||||
int empty; // Buffer completely empty?
|
||||
/** start time of this CC buffer */
|
||||
LLONG start_time;
|
||||
/** end time of this CC buffer */
|
||||
LLONG end_time;
|
||||
enum cc_modes mode;
|
||||
int channel; // Currently selected channel
|
||||
int my_field; // Used for sanity checks
|
||||
/** XDS string */
|
||||
char *xds_str;
|
||||
/** length of XDS string */
|
||||
size_t xds_len;
|
||||
/** Class of XDS string */
|
||||
int cur_xds_packet_class;
|
||||
} eia608_screen;
|
||||
|
||||
struct ccx_decoders_common_settings_t
|
||||
{
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
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
|
||||
int cc_to_stdout;
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
int no_rollup;
|
||||
struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder.
|
||||
ccx_decoder_dtvcc_settings *settings_dtvcc; //Same for cea 708 captions decoder (dtvcc)
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
unsigned send_to_srv;
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int program_number;
|
||||
enum ccx_code_type codec;
|
||||
int ignore_xds;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct lib_cc_decode
|
||||
{
|
||||
int cc_stats[4];
|
||||
int saw_caption_block;
|
||||
int processed_enough; // If 1, we have enough lines, time, etc.
|
||||
|
||||
/* 608 contexts - note that this shouldn't be global, they should be
|
||||
per program */
|
||||
void *context_cc608_field_1;
|
||||
void *context_cc608_field_2;
|
||||
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
struct cc_subtitle dec_sub;
|
||||
enum ccx_bufferdata_type in_bufferdatatype;
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
|
||||
int frames_since_last_gop;
|
||||
/* GOP-based timing */
|
||||
int saw_gop_header;
|
||||
/* Time info for timed-transcript */
|
||||
int max_gop_length; // (Maximum) length of a group of pictures
|
||||
int last_gop_length; // Length of the previous group of pictures
|
||||
unsigned total_pulldownfields;
|
||||
unsigned total_pulldownframes;
|
||||
int program_number;
|
||||
struct list_head list;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
enum ccx_code_type codec;
|
||||
// Set to true if data is buffered
|
||||
int has_ccdata_buffered;
|
||||
|
||||
struct avc_ctx *avc_ctx;
|
||||
void *private_data;
|
||||
|
||||
/* General video information */
|
||||
unsigned int current_hor_size;
|
||||
unsigned int current_vert_size;
|
||||
unsigned int current_aspect_ratio;
|
||||
unsigned int current_frame_rate; // Assume standard fps, 29.97
|
||||
|
||||
/* Reguired in es_function.c */
|
||||
int no_bitstream_error;
|
||||
int saw_seqgoppic;
|
||||
int in_pic_data;
|
||||
|
||||
unsigned int current_progressive_sequence;
|
||||
unsigned int current_pulldownfields ;
|
||||
|
||||
int temporal_reference;
|
||||
enum ccx_frame_type picture_coding_type;
|
||||
unsigned picture_structure;
|
||||
unsigned repeat_first_field;
|
||||
unsigned progressive_frame;
|
||||
unsigned pulldownfields;
|
||||
/* Reguired in es_function.c and es_userdata.c */
|
||||
unsigned top_field_first; // Needs to be global
|
||||
|
||||
ccx_dtvcc_ctx *dtvcc;
|
||||
int current_field;
|
||||
// Analyse/use the picture information
|
||||
int maxtref; // Use to remember the temporal reference number
|
||||
|
||||
int cc_data_count[SORTBUF];
|
||||
// Store fts;
|
||||
LLONG cc_fts[SORTBUF];
|
||||
// Store HD CC packets
|
||||
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
|
||||
|
||||
// The sequence number of the current anchor frame. All currently read
|
||||
// B-Frames belong to this I- or P-frame.
|
||||
int anchor_seq_number;
|
||||
struct ccx_decoders_xds_context *xds_ctx;
|
||||
|
||||
int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
};
|
||||
|
||||
#endif
|
||||
966
src/lib_ccx/ccx_decoders_xds.c
Normal file
966
src/lib_ccx/ccx_decoders_xds.c
Normal file
@@ -0,0 +1,966 @@
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_common.h"
|
||||
|
||||
LLONG ts_start_of_xds = -1; // Time at which we switched to XDS mode, =-1 hasn't happened yet
|
||||
|
||||
static const char *XDSclasses[]=
|
||||
{
|
||||
"Current",
|
||||
"Future",
|
||||
"Channel",
|
||||
"Miscellaneous",
|
||||
"Public service",
|
||||
"Reserved",
|
||||
"Private data",
|
||||
"End"
|
||||
};
|
||||
|
||||
static const char *XDSProgramTypes[]=
|
||||
{
|
||||
"Education","Entertainment", "Movie", "News", "Religious",
|
||||
"Sports", "Other", "Action","Advertisement", "Animated",
|
||||
"Anthology","Automobile","Awards","Baseball","Basketball",
|
||||
"Bulletin","Business","Classical","College","Combat",
|
||||
"Comedy","Commentary","Concert","Consumer","Contemporary",
|
||||
"Crime","Dance","Documentary","Drama","Elementary",
|
||||
"Erotica","Exercise","Fantasy","Farm","Fashion",
|
||||
"Fiction","Food","Football","Foreign","Fund-Raiser",
|
||||
"Game/Quiz","Garden","Golf","Government","Health",
|
||||
"High_School","History","Hobby","Hockey","Home",
|
||||
"Horror","Information","Instruction","International","Interview",
|
||||
"Language","Legal","Live","Local","Math",
|
||||
"Medical","Meeting","Military","Mini-Series","Music",
|
||||
"Mystery","National","Nature","Police","Politics",
|
||||
"Premiere","Pre-Recorded","Product","Professional","Public",
|
||||
"Racing","Reading","Repair","Repeat","Review",
|
||||
"Romance","Science","Series","Service","Shopping",
|
||||
"Soap_Opera","Special","Suspense","Talk","Technical",
|
||||
"Tennis","Travel","Variety","Video","Weather",
|
||||
"Western"
|
||||
};
|
||||
|
||||
#define XDS_CLASS_CURRENT 0
|
||||
#define XDS_CLASS_FUTURE 1
|
||||
#define XDS_CLASS_CHANNEL 2
|
||||
#define XDS_CLASS_MISC 3
|
||||
#define XDS_CLASS_PUBLIC 4
|
||||
#define XDS_CLASS_RESERVED 5
|
||||
#define XDS_CLASS_PRIVATE 6
|
||||
#define XDS_CLASS_END 7
|
||||
#define XDS_CLASS_OUT_OF_BAND 0x40 // Not a real class, a marker for packets for out-of-band data.
|
||||
|
||||
// Types for the classes current and future
|
||||
#define XDS_TYPE_PIN_START_TIME 1
|
||||
#define XDS_TYPE_LENGH_AND_CURRENT_TIME 2
|
||||
#define XDS_TYPE_PROGRAM_NAME 3
|
||||
#define XDS_TYPE_PROGRAM_TYPE 4
|
||||
#define XDS_TYPE_CONTENT_ADVISORY 5
|
||||
#define XDS_TYPE_AUDIO_SERVICES 6
|
||||
#define XDS_TYPE_CGMS 8 // Copy Generation Management System
|
||||
#define XDS_TYPE_ASPECT_RATIO_INFO 9 // Appears in CEA-608-B but in E it's been removed as is "reserved"
|
||||
#define XDS_TYPE_PROGRAM_DESC_1 0x10
|
||||
#define XDS_TYPE_PROGRAM_DESC_2 0x11
|
||||
#define XDS_TYPE_PROGRAM_DESC_3 0x12
|
||||
#define XDS_TYPE_PROGRAM_DESC_4 0x13
|
||||
#define XDS_TYPE_PROGRAM_DESC_5 0x14
|
||||
#define XDS_TYPE_PROGRAM_DESC_6 0x15
|
||||
#define XDS_TYPE_PROGRAM_DESC_7 0x16
|
||||
#define XDS_TYPE_PROGRAM_DESC_8 0x17
|
||||
|
||||
// Types for the class channel
|
||||
#define XDS_TYPE_NETWORK_NAME 1
|
||||
#define XDS_TYPE_CALL_LETTERS_AND_CHANNEL 2
|
||||
#define XDS_TYPE_TSID 4 // Transmission Signal Identifier
|
||||
|
||||
// Types for miscellaneous packets
|
||||
#define XDS_TYPE_TIME_OF_DAY 1
|
||||
#define XDS_TYPE_LOCAL_TIME_ZONE 4
|
||||
#define XDS_TYPE_OUT_OF_BAND_CHANNEL_NUMBER 0x40
|
||||
#define NUM_XDS_BUFFERS 9 // CEA recommends no more than one level of interleaving. Play it safe
|
||||
#define NUM_BYTES_PER_PACKET 35 // Class + type (repeated for convenience) + data + zero
|
||||
|
||||
struct xds_buffer
|
||||
{
|
||||
unsigned in_use;
|
||||
int xds_class;
|
||||
int xds_type;
|
||||
unsigned char bytes[NUM_BYTES_PER_PACKET]; // Class + type (repeated for convenience) + data + zero
|
||||
unsigned char used_bytes;
|
||||
} ;
|
||||
|
||||
typedef struct ccx_decoders_xds_context
|
||||
{
|
||||
// Program Identification Number (Start Time) for current program
|
||||
int current_xds_min;
|
||||
int current_xds_hour;
|
||||
int current_xds_date;
|
||||
int current_xds_month;
|
||||
int current_program_type_reported; // No.
|
||||
int xds_start_time_shown;
|
||||
int xds_program_length_shown;
|
||||
char xds_program_description[8][33];
|
||||
|
||||
char current_xds_network_name[33];
|
||||
char current_xds_program_name[33];
|
||||
char current_xds_call_letters[7];
|
||||
char current_xds_program_type[33];
|
||||
|
||||
struct xds_buffer xds_buffers[NUM_XDS_BUFFERS];
|
||||
int cur_xds_buffer_idx;
|
||||
int cur_xds_packet_class;
|
||||
unsigned char *cur_xds_payload;
|
||||
int cur_xds_payload_length;
|
||||
int cur_xds_packet_type;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
|
||||
} ccx_decoders_xds_context_t;
|
||||
|
||||
struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing)
|
||||
{
|
||||
int i;
|
||||
struct ccx_decoders_xds_context *ctx = NULL;
|
||||
|
||||
ctx = malloc(sizeof(struct ccx_decoders_xds_context));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->current_xds_min = -1;
|
||||
ctx->current_xds_hour = -1;
|
||||
ctx->current_xds_date = -1;
|
||||
ctx->current_xds_month = -1;
|
||||
ctx->current_program_type_reported = 0; // No.
|
||||
ctx->xds_start_time_shown = 0;
|
||||
ctx->xds_program_length_shown = 0;
|
||||
|
||||
for (i = 0; i < NUM_XDS_BUFFERS; i++)
|
||||
{
|
||||
ctx->xds_buffers[i].in_use = 0;
|
||||
ctx->xds_buffers[i].xds_class = -1;
|
||||
ctx->xds_buffers[i].xds_type = -1;
|
||||
ctx->xds_buffers[i].used_bytes = 0;
|
||||
memset(ctx->xds_buffers[i].bytes, 0, NUM_BYTES_PER_PACKET);
|
||||
}
|
||||
for (i = 0; i < 9; i++)
|
||||
memset(ctx->xds_program_description, 0, 32);
|
||||
|
||||
memset(ctx->current_xds_network_name, 0, 33);
|
||||
memset(ctx->current_xds_program_name, 0, 33);
|
||||
memset(ctx->current_xds_call_letters, 0, 7);
|
||||
memset(ctx->current_xds_program_type, 0, 33);
|
||||
|
||||
ctx->cur_xds_buffer_idx = -1;
|
||||
ctx->cur_xds_packet_class = -1;
|
||||
ctx->cur_xds_payload = NULL;
|
||||
ctx->cur_xds_payload_length = 0;
|
||||
ctx->cur_xds_packet_type = 0;
|
||||
ctx->timing = timing;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int write_xds_string(struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, char *p, size_t len)
|
||||
{
|
||||
struct eia608_screen *data = NULL;
|
||||
data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
|
||||
if (!data)
|
||||
{
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
ccx_common_logging.log_ftn("No Memory left");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sub->data = data;
|
||||
data = (struct eia608_screen *)sub->data + sub->nb_data;
|
||||
data->format = SFORMAT_XDS;
|
||||
data->start_time = ts_start_of_xds;
|
||||
data->end_time = get_fts(ctx->timing, 2);
|
||||
data->xds_str = p;
|
||||
data->xds_len = len;
|
||||
data->cur_xds_packet_class = ctx->cur_xds_packet_class;
|
||||
sub->nb_data++;
|
||||
sub->type = CC_608;
|
||||
sub->got_output = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void xdsprint (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, const char *fmt,...)
|
||||
{
|
||||
/* Guess we need no more than 100 bytes. */
|
||||
int n, size = 100;
|
||||
char *p, *np;
|
||||
va_list ap;
|
||||
|
||||
if ((p = (char *) malloc (size)) == NULL)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Try to print in the allocated space. */
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf (p, size, fmt, ap);
|
||||
va_end(ap);
|
||||
/* If that worked, return the string. */
|
||||
if (n > -1 && n < size)
|
||||
{
|
||||
write_xds_string(sub, ctx, p, n);
|
||||
return;
|
||||
}
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) /* glibc 2.1 */
|
||||
size = n+1; /* precisely what is needed */
|
||||
else /* glibc 2.0 */
|
||||
size *= 2; /* twice the old size */
|
||||
if ((np = (char *) realloc (p, size)) == NULL)
|
||||
{
|
||||
free(p);
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xds_debug_test(struct ccx_decoders_xds_context *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
process_xds_bytes (ctx, 0x05, 0x02);
|
||||
process_xds_bytes (ctx, 0x20, 0x20);
|
||||
do_end_of_xds (sub, ctx, 0x2a);
|
||||
|
||||
}
|
||||
|
||||
void xds_cea608_test(struct ccx_decoders_xds_context *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
/* This test is the sample data that comes in CEA-608. It sets the program name
|
||||
to be "Star Trek". The checksum is 0x1d and the validation must succeed. */
|
||||
process_xds_bytes (ctx, 0x01,0x03);
|
||||
process_xds_bytes (ctx, 0x53,0x74);
|
||||
process_xds_bytes (ctx, 0x61,0x72);
|
||||
process_xds_bytes (ctx, 0x20,0x54);
|
||||
process_xds_bytes (ctx, 0x72,0x65);
|
||||
process_xds_bytes (ctx, 0x02,0x03);
|
||||
process_xds_bytes (ctx, 0x02,0x03);
|
||||
process_xds_bytes (ctx, 0x6b,0x00);
|
||||
do_end_of_xds (sub, ctx, 0x1d);
|
||||
}
|
||||
|
||||
int how_many_used(struct ccx_decoders_xds_context *ctx)
|
||||
{
|
||||
int c=0;
|
||||
for (int i=0;i<NUM_XDS_BUFFERS;i++)
|
||||
if (ctx->xds_buffers[i].in_use)
|
||||
c++;
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
void clear_xds_buffer (struct ccx_decoders_xds_context *ctx, int num)
|
||||
{
|
||||
ctx->xds_buffers[num].in_use=0;
|
||||
ctx->xds_buffers[num].xds_class=-1;
|
||||
ctx->xds_buffers[num].xds_type=-1;
|
||||
ctx->xds_buffers[num].used_bytes=0;
|
||||
memset (ctx->xds_buffers[num].bytes , 0, NUM_BYTES_PER_PACKET);
|
||||
}
|
||||
|
||||
void process_xds_bytes (struct ccx_decoders_xds_context *ctx, const unsigned char hi, int lo)
|
||||
{
|
||||
int is_new;
|
||||
if(!ctx)
|
||||
return;
|
||||
|
||||
if (hi>=0x01 && hi<=0x0f)
|
||||
{
|
||||
int xds_class=(hi-1)/2; // Start codes 1 and 2 are "class type" 0, 3-4 are 2, and so on.
|
||||
is_new=hi%2; // Start codes are even
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Start: %u.%u Is new: %d | Class: %d (%s), Used buffers: %d\n",
|
||||
hi, lo, is_new, xds_class, XDSclasses[xds_class], how_many_used(ctx));
|
||||
int first_free_buf=-1;
|
||||
int matching_buf=-1;
|
||||
for (int i=0;i<NUM_XDS_BUFFERS;i++)
|
||||
{
|
||||
if (ctx->xds_buffers[i].in_use &&
|
||||
ctx->xds_buffers[i].xds_class==xds_class &&
|
||||
ctx->xds_buffers[i].xds_type==lo)
|
||||
{
|
||||
matching_buf=i;
|
||||
break;
|
||||
}
|
||||
if (first_free_buf==-1 && !ctx->xds_buffers[i].in_use)
|
||||
first_free_buf=i;
|
||||
}
|
||||
/* Here, 3 possibilities:
|
||||
1) We already had a buffer for this class/type and matching_buf points to it
|
||||
2) We didn't have a buffer for this class/type and first_free_buf points to an unused one
|
||||
3) All buffers are full and we will have to skip this packet.
|
||||
*/
|
||||
if (matching_buf==-1 && first_free_buf==-1)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("Note: All XDS buffers full (bug or suicidal stream). Ignoring this one (%d,%d).\n",xds_class,lo);
|
||||
ctx->cur_xds_buffer_idx=-1;
|
||||
return;
|
||||
|
||||
}
|
||||
ctx->cur_xds_buffer_idx=(matching_buf!=-1)? matching_buf:first_free_buf;
|
||||
|
||||
if (is_new || !ctx->xds_buffers[ctx->cur_xds_buffer_idx].in_use)
|
||||
{
|
||||
// Whatever we had before we discard; must belong to an interrupted packet
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].xds_class=xds_class;
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].xds_type=lo;
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes=0;
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].in_use=1;
|
||||
memset (ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET);
|
||||
}
|
||||
if (!is_new)
|
||||
{
|
||||
// Continue codes aren't added to packet.
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Informational: 00, or 0x20-0x7F, so 01-0x1f forbidden
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS: %02X.%02X (%c, %c)\n",hi,lo,hi,lo);
|
||||
if ((hi>0 && hi<=0x1f) || (lo>0 && lo<=0x1f))
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rNote: Illegal XDS data");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes<=32)
|
||||
{
|
||||
// Should always happen
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes[ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes++]=hi;
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes[ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes++]=lo;
|
||||
ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes[ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes]=0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ctx XDS context can be NULL, if user dont want to write xds in transcript
|
||||
*/
|
||||
void xds_do_copy_generation_management_system (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned c1, unsigned c2)
|
||||
{
|
||||
static unsigned last_c1=-1, last_c2=-1;
|
||||
static char copy_permited[256];
|
||||
static char aps[256];
|
||||
static char rcd[256];
|
||||
int changed=0;
|
||||
unsigned c1_6=(c1&0x40)>>6;
|
||||
/* unsigned unused1=(c1&0x20)>>5; */
|
||||
unsigned cgms_a_b4=(c1&0x10)>>4;
|
||||
unsigned cgms_a_b3=(c1&0x8)>>3;
|
||||
unsigned aps_b2=(c1&0x4)>>2;
|
||||
unsigned aps_b1=(c1&0x2)>>1;
|
||||
/* unsigned asb_0=(c1&0x1); */
|
||||
unsigned c2_6=(c2&0x40)>>6;
|
||||
/* unsigned c2_5=(c2&0x20)>>5; */
|
||||
/* unsigned c2_4=(c2&0x10)>>4; */
|
||||
/* unsigned c2_3=(c2&0x8)>>3; */
|
||||
/* unsigned c2_2=(c2&0x4)>>2; */
|
||||
/* unsigned c2_1=(c2&0x2)>>1; */
|
||||
unsigned rcd0=(c2&0x1);
|
||||
|
||||
/* User dont need xds */
|
||||
if(!ctx)
|
||||
return;
|
||||
|
||||
if (!c1_6 || !c2_6) // These must be high. If not, not following specs
|
||||
return;
|
||||
if (last_c1!=c1 || last_c2!=c2)
|
||||
{
|
||||
changed=1;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
// Changed since last time, decode
|
||||
|
||||
const char *copytext[4]={"Copy permited (no restrictions)", "No more copies (one generation copy has been made)",
|
||||
"One generation of copies can be made", "No copying is permited"};
|
||||
const char *apstext[4]={"No APS", "PSP On; Split Burst Off", "PSP On; 2 line Split Burst On", "PSP On; 4 line Split Burst On"};
|
||||
sprintf (copy_permited,"CGMS: %s", copytext[cgms_a_b4*2+cgms_a_b3]);
|
||||
sprintf (aps,"APS: %s", apstext[aps_b2*2+aps_b1]);
|
||||
sprintf (rcd,"Redistribution Control Descriptor: %d", rcd0);
|
||||
|
||||
}
|
||||
|
||||
xdsprint(sub, ctx, copy_permited);
|
||||
xdsprint(sub, ctx, aps);
|
||||
xdsprint(sub, ctx, rcd);
|
||||
if (changed)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n",copy_permited);
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n",aps);
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n",rcd);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",copy_permited);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",aps);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",rcd);
|
||||
}
|
||||
|
||||
void xds_do_content_advisory (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned c1, unsigned c2)
|
||||
{
|
||||
static unsigned last_c1=-1, last_c2=-1;
|
||||
static char age[256];
|
||||
static char content[256];
|
||||
static char rating[256];
|
||||
int changed=0;
|
||||
// Insane encoding
|
||||
unsigned c1_6=(c1&0x40)>>6;
|
||||
unsigned Da2=(c1&0x20)>>5;
|
||||
unsigned a1=(c1&0x10)>>4;
|
||||
unsigned a0=(c1&0x8)>>3;
|
||||
unsigned r2=(c1&0x4)>>2;
|
||||
unsigned r1=(c1&0x2)>>1;
|
||||
unsigned r0=(c1&0x1);
|
||||
unsigned c2_6=(c2&0x40)>>6;
|
||||
unsigned FV=(c2&0x20)>>5;
|
||||
unsigned S=(c2&0x10)>>4;
|
||||
unsigned La3=(c2&0x8)>>3;
|
||||
unsigned g2=(c2&0x4)>>2;
|
||||
unsigned g1=(c2&0x2)>>1;
|
||||
unsigned g0=(c2&0x1);
|
||||
unsigned supported=0;
|
||||
|
||||
if(!ctx)
|
||||
return;
|
||||
|
||||
if (!c1_6 || !c2_6) // These must be high. If not, not following specs
|
||||
return;
|
||||
if (last_c1!=c1 || last_c2!=c2)
|
||||
{
|
||||
changed=1;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
// Changed since last time, decode
|
||||
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
|
||||
if (!a1 && a0) // US TV parental guidelines
|
||||
{
|
||||
const char *agetext[8]={"None", "TV-Y (All Children)", "TV-Y7 (Older Children)",
|
||||
"TV-G (General Audience)", "TV-PG (Parental Guidance Suggested)",
|
||||
"TV-14 (Parents Strongly Cautioned)", "TV-MA (Mature Audience Only)", "None"};
|
||||
sprintf (age,"ContentAdvisory: US TV Parental Guidelines. Age Rating: %s", agetext[g2*4+g1*2+g0]);
|
||||
content[0]=0;
|
||||
if (!g2 && g1 && !g0) // For TV-Y7 (Older chidren), the Violence bit is "fantasy violence"
|
||||
{
|
||||
if (FV)
|
||||
strcpy (content, "[Fantasy Violence] ");
|
||||
}
|
||||
else // For all others, is real
|
||||
{
|
||||
if (FV)
|
||||
strcpy (content, "[Violence] ");
|
||||
}
|
||||
if (S)
|
||||
strcat (content, "[Sexual Situations] ");
|
||||
if (La3)
|
||||
strcat (content, "[Adult Language] ");
|
||||
if (Da2)
|
||||
strcat (content, "[Sexually Suggestive Dialog] ");
|
||||
supported=1;
|
||||
}
|
||||
if (!a0) // MPA
|
||||
{
|
||||
const char *ratingtext[8]={"N/A", "G", "PG", "PG-13", "R", "NC-17", "X", "Not Rated"};
|
||||
sprintf (rating,"ContentAdvisory: MPA Rating: %s", ratingtext[r2*4+r1*2+r0]);
|
||||
supported=1;
|
||||
}
|
||||
if (a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
|
||||
{
|
||||
const char *ratingtext[8]={"Exempt", "Children", "Children eight years and older",
|
||||
"General programming suitable for all audiences", "Parental Guidance",
|
||||
"Viewers 14 years and older", "Adult Programming", "[undefined]"};
|
||||
sprintf (rating,"ContentAdvisory: Canadian English Rating: %s", ratingtext[g2*4+g1*2+g0]);
|
||||
supported=1;
|
||||
}
|
||||
if (a0 && a1 && Da2 && !La3) // Canadian French Language Rating
|
||||
{
|
||||
const char *ratingtext[8] = { "Exempt?es", "G?n?ral", "G?n?ral - D?conseill? aux jeunes enfants",
|
||||
"Cette ?mission peut ne pas convenir aux enfants de moins de 13 ans",
|
||||
"Cette ?mission ne convient pas aux moins de 16 ans",
|
||||
"Cette ?mission est r?serv?e aux adultes", "[invalid]", "[invalid]" };
|
||||
sprintf(rating, "ContentAdvisory: Canadian French Rating: %s", ratingtext[g2 * 4 + g1 * 2 + g0]);
|
||||
supported = 1;
|
||||
}
|
||||
|
||||
}
|
||||
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
|
||||
if (!a1 && a0) // US TV parental guidelines
|
||||
{
|
||||
xdsprint(sub, ctx, age);
|
||||
xdsprint(sub, ctx, content);
|
||||
if (changed)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",age);
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",content);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",age);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",content);
|
||||
}
|
||||
if (!a0 || // MPA
|
||||
(a0 && a1 && !Da2 && !La3) || // Canadian English Language Rating
|
||||
(a0 && a1 && Da2 && !La3) // Canadian French Language Rating
|
||||
)
|
||||
{
|
||||
xdsprint(sub, ctx, rating);
|
||||
if (changed)
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",rating);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",rating);
|
||||
}
|
||||
|
||||
if (changed && !supported)
|
||||
ccx_common_logging.log_ftn ("XDS: Unsupported ContentAdvisory encoding, please submit sample.\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
int xds_do_current_and_future (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx)
|
||||
{
|
||||
int was_proc=0;
|
||||
|
||||
char *str = malloc(1024);
|
||||
char *tstr = NULL;
|
||||
int str_len = 1024;
|
||||
|
||||
if(!ctx)
|
||||
return CCX_EINVAL;
|
||||
|
||||
switch (ctx->cur_xds_packet_type)
|
||||
{
|
||||
case XDS_TYPE_PIN_START_TIME:
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<7) // We need 4 data bytes
|
||||
break;
|
||||
int min=ctx->cur_xds_payload[2] & 0x3f; // 6 bits
|
||||
int hour = ctx->cur_xds_payload[3] & 0x1f; // 5 bits
|
||||
int date = ctx->cur_xds_payload[4] & 0x1f; // 5 bits
|
||||
int month = ctx->cur_xds_payload[5] & 0xf; // 4 bits
|
||||
/* int changed=0; */
|
||||
if (ctx->current_xds_min!=min ||
|
||||
ctx->current_xds_hour!=hour ||
|
||||
ctx->current_xds_date!=date ||
|
||||
ctx->current_xds_month!=month)
|
||||
{
|
||||
/* changed=1; */
|
||||
ctx->xds_start_time_shown=0;
|
||||
ctx->current_xds_min=min;
|
||||
ctx->current_xds_hour=hour;
|
||||
ctx->current_xds_date=date;
|
||||
ctx->current_xds_month=month;
|
||||
}
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
|
||||
(ctx->cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
|
||||
date,month,hour,min);
|
||||
xdsprint (sub, ctx, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
|
||||
(ctx->cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
|
||||
date,month,hour,min);
|
||||
|
||||
if (!ctx->xds_start_time_shown && ctx->cur_xds_packet_class==XDS_CLASS_CURRENT)
|
||||
{
|
||||
ccx_common_logging.log_ftn("\rXDS: Program changed.\n");
|
||||
ccx_common_logging.log_ftn ("XDS program start time (DD/MM HH:MM) %02d-%02d %02d:%02d\n",date,month,hour,min);
|
||||
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR,
|
||||
ctx->current_xds_min, ctx->current_xds_hour, ctx->current_xds_date, ctx->current_xds_month);
|
||||
ctx->xds_start_time_shown=1;
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_LENGH_AND_CURRENT_TIME:
|
||||
{
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
int min=ctx->cur_xds_payload[2] & 0x3f; // 6 bits
|
||||
int hour = ctx->cur_xds_payload[3] & 0x1f; // 5 bits
|
||||
if (!ctx->xds_program_length_shown)
|
||||
ccx_common_logging.log_ftn ("\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
else
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
|
||||
xdsprint(sub, ctx, "Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
|
||||
if (ctx->cur_xds_payload_length>6) // Next two bytes (optional) available
|
||||
{
|
||||
int el_min=ctx->cur_xds_payload[4] & 0x3f; // 6 bits
|
||||
int el_hour = ctx->cur_xds_payload[5] & 0x1f; // 5 bits
|
||||
if (!ctx->xds_program_length_shown)
|
||||
ccx_common_logging.log_ftn ("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
else
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
xdsprint(sub, ctx, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
|
||||
|
||||
}
|
||||
if (ctx->cur_xds_payload_length>8) // Next two bytes (optional) available
|
||||
{
|
||||
int el_sec=ctx->cur_xds_payload[6] & 0x3f; // 6 bits
|
||||
if (!ctx->xds_program_length_shown)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, ":%02d",el_sec);
|
||||
xdsprint(sub, ctx, "Elapsed (SS) :%02d",el_sec);
|
||||
}
|
||||
if (!ctx->xds_program_length_shown)
|
||||
ccx_common_logging.log_ftn("\n");
|
||||
else
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\n");
|
||||
ctx->xds_program_length_shown=1;
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_PROGRAM_NAME:
|
||||
{
|
||||
was_proc=1;
|
||||
char xds_program_name[33];
|
||||
int i;
|
||||
for (i=2;i<ctx->cur_xds_payload_length-1;i++)
|
||||
xds_program_name[i-2]=ctx->cur_xds_payload[i];
|
||||
xds_program_name[i-2]=0;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS Program name: %s\n",xds_program_name);
|
||||
xdsprint(sub, ctx, "Program name: %s",xds_program_name);
|
||||
if (ctx->cur_xds_packet_class==XDS_CLASS_CURRENT &&
|
||||
strcmp (xds_program_name, ctx->current_xds_program_name)) // Change of program
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS Notice: Program is now %s\n", xds_program_name);
|
||||
strncpy (ctx->current_xds_program_name,xds_program_name, 33);
|
||||
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME, xds_program_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_PROGRAM_TYPE:
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
if (ctx->current_program_type_reported)
|
||||
{
|
||||
// Check if we should do it again
|
||||
for (int i=0;i<ctx->cur_xds_payload_length ; i++)
|
||||
{
|
||||
if (ctx->cur_xds_payload[i]!=ctx->current_xds_program_type[i])
|
||||
{
|
||||
ctx->current_program_type_reported=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS) && ctx->current_program_type_reported)
|
||||
// break;
|
||||
memcpy (ctx->current_xds_program_type,ctx->cur_xds_payload,ctx->cur_xds_payload_length);
|
||||
ctx->current_xds_program_type[ctx->cur_xds_payload_length]=0;
|
||||
if (!ctx->current_program_type_reported)
|
||||
ccx_common_logging.log_ftn ("\rXDS Program Type: ");
|
||||
|
||||
*str = '\0';
|
||||
tstr = str;
|
||||
for (int i=2;i<ctx->cur_xds_payload_length - 1; i++)
|
||||
{
|
||||
if (ctx->cur_xds_payload[i]==0) // Padding
|
||||
continue;
|
||||
if (!ctx->current_program_type_reported)
|
||||
ccx_common_logging.log_ftn ("[%02X-", ctx->cur_xds_payload[i]);
|
||||
if (ctx->cur_xds_payload[i]>=0x20 && ctx->cur_xds_payload[i]<0x7F)
|
||||
{
|
||||
snprintf(tstr,str_len - (tstr - str),"[%s] ",XDSProgramTypes[ctx->cur_xds_payload[i]-0x20]);
|
||||
tstr += strlen(tstr);
|
||||
}
|
||||
if (!ctx->current_program_type_reported)
|
||||
{
|
||||
if (ctx->cur_xds_payload[i]>=0x20 && ctx->cur_xds_payload[i]<0x7F)
|
||||
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[ctx->cur_xds_payload[i]-0x20]);
|
||||
else
|
||||
ccx_common_logging.log_ftn ("ILLEGAL VALUE");
|
||||
ccx_common_logging.log_ftn ("] ");
|
||||
}
|
||||
}
|
||||
xdsprint(sub, ctx, "Program type %s",str);
|
||||
if (!ctx->current_program_type_reported)
|
||||
ccx_common_logging.log_ftn ("\n");
|
||||
ctx->current_program_type_reported=1;
|
||||
break;
|
||||
case XDS_TYPE_CONTENT_ADVISORY:
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
xds_do_content_advisory (sub, ctx, ctx->cur_xds_payload[2],ctx->cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_AUDIO_SERVICES:
|
||||
was_proc=1; // I don't have any sample with this.
|
||||
break;
|
||||
case XDS_TYPE_CGMS:
|
||||
was_proc=1;
|
||||
xds_do_copy_generation_management_system (sub, ctx, ctx->cur_xds_payload[2],ctx->cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_ASPECT_RATIO_INFO:
|
||||
{
|
||||
unsigned ar_start, ar_end;
|
||||
was_proc = 1;
|
||||
if (ctx->cur_xds_payload_length < 5) // We need 2 data bytes
|
||||
break;
|
||||
if (!ctx->cur_xds_payload[2] & 20 || !ctx->cur_xds_payload[3] & 20) // Bit 6 must be 1
|
||||
break;
|
||||
/* CEA-608-B: The starting line is computed by adding 22 to the decimal number
|
||||
represented by bits S0 to S5. The ending line is computing by substracting
|
||||
the decimal number represented by bits E0 to E5 from 262 */
|
||||
ar_start = (ctx->cur_xds_payload[2] & 0x1F) + 22;
|
||||
ar_end = 262 - (ctx->cur_xds_payload[3] & 0x1F);
|
||||
unsigned active_picture_height = ar_end - ar_start;
|
||||
float aspect_ratio = (float) 320 / active_picture_height;
|
||||
ccx_common_logging.log_ftn("\rXDS Notice: Aspect ratio info, start line=%u, end line=%u\n", ar_start,ar_end);
|
||||
ccx_common_logging.log_ftn("\rXDS Notice: Aspect ratio info, active picture height=%u, ratio=%f\n", active_picture_height, aspect_ratio);
|
||||
|
||||
}
|
||||
case XDS_TYPE_PROGRAM_DESC_1:
|
||||
case XDS_TYPE_PROGRAM_DESC_2:
|
||||
case XDS_TYPE_PROGRAM_DESC_3:
|
||||
case XDS_TYPE_PROGRAM_DESC_4:
|
||||
case XDS_TYPE_PROGRAM_DESC_5:
|
||||
case XDS_TYPE_PROGRAM_DESC_6:
|
||||
case XDS_TYPE_PROGRAM_DESC_7:
|
||||
case XDS_TYPE_PROGRAM_DESC_8:
|
||||
{
|
||||
was_proc=1;
|
||||
int changed=0;
|
||||
char xds_desc[33];
|
||||
int i;
|
||||
for (i=2;i<ctx->cur_xds_payload_length-1;i++)
|
||||
xds_desc[i-2]=ctx->cur_xds_payload[i];
|
||||
xds_desc[i-2]=0;
|
||||
|
||||
if (xds_desc[0])
|
||||
{
|
||||
int line_num=ctx->cur_xds_packet_type-XDS_TYPE_PROGRAM_DESC_1;
|
||||
if (strcmp (xds_desc, ctx->xds_program_description[line_num]))
|
||||
changed=1;
|
||||
if (changed)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS description line %d: %s\n",line_num,xds_desc);
|
||||
strcpy (ctx->xds_program_description[line_num], xds_desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
|
||||
}
|
||||
xdsprint(sub, ctx, "XDS description line %d: %s",line_num,xds_desc);
|
||||
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION, line_num, xds_desc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
int xds_do_channel (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx)
|
||||
{
|
||||
int was_proc=0;
|
||||
if(!ctx)
|
||||
return CCX_EINVAL;
|
||||
|
||||
switch (ctx->cur_xds_packet_type)
|
||||
{
|
||||
case XDS_TYPE_NETWORK_NAME:
|
||||
was_proc=1;
|
||||
char xds_network_name[33];
|
||||
int i;
|
||||
for (i=2;i<ctx->cur_xds_payload_length-1;i++)
|
||||
xds_network_name[i-2]=ctx->cur_xds_payload[i];
|
||||
xds_network_name[i-2]=0;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Network name: %s\n",xds_network_name);
|
||||
xdsprint (sub, ctx, "Network: %s",xds_network_name);
|
||||
if (strcmp (xds_network_name, ctx->current_xds_network_name)) // Change of station
|
||||
{
|
||||
ccx_common_logging.log_ftn ("XDS Notice: Network is now %s\n", xds_network_name);
|
||||
strcpy (ctx->current_xds_network_name,xds_network_name);
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_CALL_LETTERS_AND_CHANNEL:
|
||||
{
|
||||
was_proc=1;
|
||||
char xds_call_letters[7];
|
||||
if (ctx->cur_xds_payload_length != 7 && ctx->cur_xds_payload_length != 9) // We need 4-6 data bytes
|
||||
break;
|
||||
for (i=2;i<ctx->cur_xds_payload_length-1;i++)
|
||||
{
|
||||
if (ctx->cur_xds_payload)
|
||||
xds_call_letters[i-2]=ctx->cur_xds_payload[i];
|
||||
}
|
||||
xds_call_letters[i-2]=0;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Network call letters: %s\n",xds_call_letters);
|
||||
xdsprint (sub, ctx, "Call Letters: %s",xds_call_letters);
|
||||
if (strncmp (xds_call_letters, ctx->current_xds_call_letters, 7)) // Change of station
|
||||
{
|
||||
ccx_common_logging.log_ftn ("XDS Notice: Network call letters now %s\n", xds_call_letters);
|
||||
strncpy (ctx->current_xds_call_letters, xds_call_letters, 7);
|
||||
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS, ctx->current_xds_call_letters);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_TSID:
|
||||
// According to CEA-608, data here (4 bytes) are used to identify the
|
||||
// "originating analog licensee". No interesting data for us.
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<7) // We need 4 data bytes
|
||||
break;
|
||||
unsigned b1=(ctx->cur_xds_payload[2])&0x10; // Only low 4 bits from each byte
|
||||
unsigned b2=(ctx->cur_xds_payload[3])&0x10;
|
||||
unsigned b3=(ctx->cur_xds_payload[4])&0x10;
|
||||
unsigned b4=(ctx->cur_xds_payload[5])&0x10;
|
||||
unsigned tsid=(b4<<12) | (b3<<8) | (b2<<4) | b1;
|
||||
if (tsid)
|
||||
xdsprint (sub, ctx, "TSID: %u",tsid);
|
||||
break;
|
||||
}
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int xds_do_private_data (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx)
|
||||
{
|
||||
char *str;
|
||||
int i;
|
||||
|
||||
if(!ctx)
|
||||
return CCX_EINVAL;
|
||||
|
||||
str = malloc((ctx->cur_xds_payload_length *3) + 1);
|
||||
if (str==NULL) // Only thing we can do with private data is dump it.
|
||||
return 1;
|
||||
|
||||
for (i = 2; i < ctx->cur_xds_payload_length - 1; i++)
|
||||
sprintf(str, "%02X ",ctx->cur_xds_payload[i]);
|
||||
|
||||
xdsprint(sub, ctx, str);
|
||||
free(str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xds_do_misc (struct ccx_decoders_xds_context *ctx)
|
||||
{
|
||||
int was_proc=0;
|
||||
if(!ctx)
|
||||
return CCX_EINVAL;
|
||||
|
||||
switch (ctx->cur_xds_packet_type)
|
||||
{
|
||||
case XDS_TYPE_TIME_OF_DAY:
|
||||
{
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<9) // We need 6 data bytes
|
||||
break;
|
||||
int min=ctx->cur_xds_payload[2] & 0x3f; // 6 bits
|
||||
int hour = ctx->cur_xds_payload[3] & 0x1f; // 5 bits
|
||||
int date = ctx->cur_xds_payload[4] & 0x1f; // 5 bits
|
||||
int month = ctx->cur_xds_payload[5] & 0xf; // 4 bits
|
||||
int reset_seconds = (ctx->cur_xds_payload[5] & 0x20);
|
||||
int day_of_week = ctx->cur_xds_payload[6] & 0x7;
|
||||
int year = (ctx->cur_xds_payload[7] & 0x3f) + 1990;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Time of day: (YYYY/MM/DD) %04d/%02d/%02d (HH:SS) %02d:%02d DoW: %d Reset seconds: %d\n",
|
||||
year,month,date,hour,min, day_of_week, reset_seconds);
|
||||
break;
|
||||
}
|
||||
case XDS_TYPE_LOCAL_TIME_ZONE:
|
||||
{
|
||||
was_proc=1;
|
||||
if (ctx->cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
// int b6 = (ctx->cur_xds_payload[2] & 0x40) >>6; // Bit 6 should always be 1
|
||||
int dst = (ctx->cur_xds_payload[2] & 0x20) >>5; // Daylight Saving Time
|
||||
int hour = ctx->cur_xds_payload[2] & 0x1f; // 5 bits
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Local Time Zone: %02d DST: %d\n",
|
||||
hour, dst);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
was_proc=0;
|
||||
break;
|
||||
}
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned char expected_checksum)
|
||||
{
|
||||
int cs = 0;
|
||||
int i;
|
||||
|
||||
if(!ctx)
|
||||
return;
|
||||
|
||||
if (ctx->cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */
|
||||
!ctx->xds_buffers[ctx->cur_xds_buffer_idx].in_use)
|
||||
return;
|
||||
ctx->cur_xds_packet_class = ctx->xds_buffers[ctx->cur_xds_buffer_idx].xds_class;
|
||||
ctx->cur_xds_payload = ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes;
|
||||
ctx->cur_xds_payload_length=ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes;
|
||||
ctx->cur_xds_packet_type=ctx->cur_xds_payload[1];
|
||||
ctx->cur_xds_payload[ctx->cur_xds_payload_length++]=0x0F; // The end byte itself, added to the packet
|
||||
|
||||
for (i = 0; i < ctx->cur_xds_payload_length; i++)
|
||||
{
|
||||
cs=cs+ctx->cur_xds_payload[i];
|
||||
cs=cs & 0x7f; // Keep 7 bits only
|
||||
int c=ctx->cur_xds_payload[i]&0x7F;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "%02X - %c cs: %02X\n",
|
||||
c,(c>=0x20)?c:'?', cs);
|
||||
}
|
||||
cs=(128-cs) & 0x7F; // Convert to 2's complement & discard high-order bit
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n",
|
||||
ctx->cur_xds_packet_class,XDSclasses[ctx->cur_xds_packet_class],
|
||||
ctx->cur_xds_payload_length,
|
||||
cs==expected_checksum, how_many_used(ctx));
|
||||
|
||||
if (cs!=expected_checksum || ctx->cur_xds_payload_length<3)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs);
|
||||
clear_xds_buffer (ctx, ctx->cur_xds_buffer_idx);
|
||||
return; // Bad packets ignored as per specs
|
||||
}
|
||||
|
||||
int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */
|
||||
if (ctx->cur_xds_packet_type & 0x40) // Bit 6 set
|
||||
{
|
||||
ctx->cur_xds_packet_class = XDS_CLASS_OUT_OF_BAND;
|
||||
}
|
||||
|
||||
switch (ctx->cur_xds_packet_class)
|
||||
{
|
||||
case XDS_CLASS_FUTURE: // Info on future program
|
||||
if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS)) // Don't bother processing something we don't need
|
||||
{
|
||||
was_proc=1;
|
||||
break;
|
||||
}
|
||||
case XDS_CLASS_CURRENT: // Info on current program
|
||||
was_proc = xds_do_current_and_future(sub, ctx);
|
||||
break;
|
||||
case XDS_CLASS_CHANNEL:
|
||||
was_proc = xds_do_channel(sub, ctx);
|
||||
break;
|
||||
|
||||
case XDS_CLASS_MISC:
|
||||
was_proc = xds_do_misc(ctx);
|
||||
break;
|
||||
case XDS_CLASS_PRIVATE: // CEA-608:
|
||||
// The Private Data Class is for use in any closed system for whatever that
|
||||
// system wishes. It shall not be defined by this standard now or in the future.
|
||||
was_proc = xds_do_private_data(sub, ctx);
|
||||
break;
|
||||
case XDS_CLASS_OUT_OF_BAND:
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Out-of-band data, ignored.");
|
||||
was_proc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_proc)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("Note: We found an currently unsupported XDS packet.\n");
|
||||
}
|
||||
clear_xds_buffer (ctx, ctx->cur_xds_buffer_idx);
|
||||
|
||||
}
|
||||
13
src/lib_ccx/ccx_decoders_xds.h
Normal file
13
src/lib_ccx/ccx_decoders_xds.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef CCX_DECODER_XDS_H
|
||||
#define CCX_DECODER_XDS_H
|
||||
|
||||
#include "ccx_decoders_common.h"
|
||||
|
||||
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);
|
||||
|
||||
struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing);
|
||||
|
||||
void xds_cea608_test();
|
||||
#endif
|
||||
381
src/lib_ccx/ccx_demuxer.c
Normal file
381
src/lib_ccx/ccx_demuxer.c
Normal file
@@ -0,0 +1,381 @@
|
||||
#include "ccx_demuxer.h"
|
||||
#include "activity.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "utility.h"
|
||||
|
||||
static void ccx_demuxer_reset(struct ccx_demuxer *ctx)
|
||||
{
|
||||
ctx->startbytes_pos=0;
|
||||
ctx->startbytes_avail=0;
|
||||
memset (ctx->PIDs_seen, 0, 65536*sizeof (int));
|
||||
memset (ctx->PIDs_programs, 0, 65536*sizeof (struct PMT_entry *));
|
||||
}
|
||||
|
||||
static void ccx_demuxer_close(struct ccx_demuxer *ctx)
|
||||
{
|
||||
ctx->past = 0;
|
||||
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
|
||||
{
|
||||
close (ctx->infd);
|
||||
ctx->infd=-1;
|
||||
activity_input_file_closed();
|
||||
}
|
||||
}
|
||||
|
||||
static int ccx_demuxer_isopen(struct ccx_demuxer *ctx)
|
||||
{
|
||||
return ctx->infd != -1;
|
||||
}
|
||||
static int ccx_demuxer_open(struct ccx_demuxer *ctx, const char *file)
|
||||
{
|
||||
init_file_buffer(ctx);
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
if (ctx->infd != -1) // Means we had already processed stdin. So we're done.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx->parent);
|
||||
return -1;
|
||||
}
|
||||
ctx->infd = 0;
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rReading from standard input\n");
|
||||
}
|
||||
else if (ccx_options.input_source == CCX_DS_NETWORK)
|
||||
{
|
||||
if (ctx->infd != -1) // Means we have already bound a socket.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx->parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
|
||||
if(ctx->infd < 0)
|
||||
{
|
||||
print_error(ccx_options.gui_mode_reports,"socket() failed.");
|
||||
return CCX_COMMON_EXIT_BUG_BUG;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if (ccx_options.input_source == CCX_DS_TCP)
|
||||
{
|
||||
if (ctx->infd != -1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx->parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ctx->infd = OPEN (file, O_RDONLY | O_BINARY);
|
||||
#else
|
||||
ctx->infd = OPEN (file, O_RDONLY);
|
||||
#endif
|
||||
if (ctx->infd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->auto_stream == CCX_SM_AUTODETECT)
|
||||
{
|
||||
detect_stream_type(ctx);
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
mprint ("\rFile seems to be an elementary stream, enabling ES mode\n");
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
mprint ("\rFile seems to be a transport stream, enabling TS mode\n");
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
mprint ("\rFile seems to be a program stream, enabling PS mode\n");
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
mprint ("\rFile seems to be an ASF, enabling DVR-MS mode\n");
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
mprint ("\rFile seems to be a WTV, enabling WTV mode\n");
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("\rFile seems to be McPoodle raw data\n");
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("\rFile seems to be a raw caption with time data\n");
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("\rFile seems to be a MP4\n");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("\rFile seems to be an hexadecimal dump\n");
|
||||
break;
|
||||
#endif
|
||||
case CCX_SM_MYTH:
|
||||
case CCX_SM_AUTODETECT:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->stream_mode = ctx->auto_stream;
|
||||
}
|
||||
|
||||
// The myth loop autodetect will only be used with ES or PS streams
|
||||
switch (ccx_options.auto_myth)
|
||||
{
|
||||
case 0:
|
||||
// Use whatever stream mode says
|
||||
break;
|
||||
case 1:
|
||||
// Force stream mode to myth
|
||||
ctx->stream_mode=CCX_SM_MYTH;
|
||||
break;
|
||||
case 2:
|
||||
// autodetect myth files, but only if it does not conflict with
|
||||
// the current stream mode
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
case CCX_SM_PROGRAM:
|
||||
if ( detect_myth(ctx->parent) )
|
||||
{
|
||||
ctx->stream_mode=CCX_SM_MYTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Keep stream_mode
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ctx->past = 0;
|
||||
ctx->min_global_timestamp = 0;
|
||||
ctx->global_timestamp_inited = 0;
|
||||
ctx->last_global_timestamp = 0;
|
||||
ctx->offset_global_timestamp = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
LLONG ccx_demuxer_getfilesize (struct ccx_demuxer *ctx)
|
||||
{
|
||||
LLONG ret = 0;
|
||||
int in = ctx->infd;
|
||||
LLONG current=LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in,0,SEEK_END);
|
||||
if(current < 0 ||length < 0)
|
||||
return -1;
|
||||
|
||||
ret = LSEEK (in, current, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int ccx_demuxer_get_stream_mode(struct ccx_demuxer *ctx)
|
||||
{
|
||||
return ctx->stream_mode;
|
||||
}
|
||||
|
||||
|
||||
static void ccx_demuxer_print_cfg(struct ccx_demuxer *ctx)
|
||||
{
|
||||
switch (ctx->auto_stream)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
mprint ("Elementary");
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
mprint ("Transport");
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
mprint ("Program");
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
mprint ("DVR-MS");
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
mprint ("Windows Television (WTV)");
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("McPoodle's raw");
|
||||
break;
|
||||
case CCX_SM_AUTODETECT:
|
||||
mprint ("Autodetect");
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("BIN");
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("MP4");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("Hex");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "BUG: Unknown stream mode.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
int ccx_demuxer_write_es(struct ccx_demuxer *ctx, unsigned char* buf, size_t len)
|
||||
{
|
||||
if (ctx->fh_out_elementarystream!=NULL)
|
||||
fwrite (buf, 1, len,ctx->fh_out_elementarystream);
|
||||
return CCX_OK;
|
||||
}
|
||||
|
||||
void ccx_demuxer_delete(struct ccx_demuxer **ctx)
|
||||
{
|
||||
struct ccx_demuxer *lctx = *ctx;
|
||||
int i;
|
||||
dinit_cap(lctx);
|
||||
freep(&lctx->last_pat_payload);
|
||||
for (i = 0; i < MAX_PSI_PID; i++)
|
||||
{
|
||||
if(lctx->PID_buffers[i]!=NULL && lctx->PID_buffers[i]->buffer!=NULL)
|
||||
{
|
||||
free(lctx->PID_buffers[i]->buffer);
|
||||
lctx->PID_buffers[i]->buffer=NULL;
|
||||
lctx->PID_buffers[i]->buffer_length=0;
|
||||
}
|
||||
freep(&lctx->PID_buffers[i]);
|
||||
}
|
||||
for (i = 0; i < MAX_PID; i++)
|
||||
{
|
||||
if( lctx->PIDs_programs[i])
|
||||
freep(lctx->PIDs_programs + i);
|
||||
}
|
||||
if (lctx->fh_out_elementarystream != NULL)
|
||||
fclose (lctx->fh_out_elementarystream);
|
||||
|
||||
freep(&lctx->filebuffer);
|
||||
freep(ctx);
|
||||
}
|
||||
|
||||
struct ccx_demuxer *init_demuxer(void *parent, struct demuxer_cfg *cfg)
|
||||
{
|
||||
int i;
|
||||
struct ccx_demuxer *ctx = malloc(sizeof(struct ccx_demuxer));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->infd = -1;//Set to -1 to indicate no file is open.
|
||||
ctx->m2ts = cfg->m2ts;
|
||||
ctx->auto_stream = cfg->auto_stream;
|
||||
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
|
||||
ctx->ts_autoprogram = cfg->ts_autoprogram;
|
||||
ctx->ts_allprogram = cfg->ts_allprogram;
|
||||
ctx->ts_datastreamtype = cfg->ts_datastreamtype;
|
||||
ctx->nb_program = 0;
|
||||
ctx->multi_stream_per_prog = 0;
|
||||
|
||||
if(cfg->ts_forced_program != -1)
|
||||
{
|
||||
ctx->pinfo[ctx->nb_program].pid = CCX_UNKNOWN;
|
||||
ctx->pinfo[ctx->nb_program].program_number = cfg->ts_forced_program;
|
||||
ctx->flag_ts_forced_pn = CCX_TRUE;
|
||||
ctx->nb_program++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->flag_ts_forced_pn = CCX_FALSE;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.all_stream);
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.sib_stream);
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.pg_stream);
|
||||
|
||||
ctx->codec = cfg->codec;
|
||||
|
||||
ctx->flag_ts_forced_cappid = CCX_FALSE;
|
||||
for(i = 0; i < cfg->nb_ts_cappid; i++)
|
||||
{
|
||||
if(ctx->codec == CCX_CODEC_ANY)
|
||||
update_capinfo(ctx, cfg->ts_cappids[i], cfg->ts_datastreamtype, CCX_CODEC_NONE, 0, NULL);
|
||||
else
|
||||
update_capinfo(ctx, cfg->ts_cappids[i], cfg->ts_datastreamtype, ctx->codec, 0, NULL);
|
||||
}
|
||||
|
||||
ctx->flag_ts_forced_cappid = cfg->nb_ts_cappid ? CCX_TRUE : CCX_FALSE;
|
||||
ctx->nocodec = cfg->nocodec;
|
||||
|
||||
ctx->reset = ccx_demuxer_reset;
|
||||
ctx->close = ccx_demuxer_close;
|
||||
ctx->open = ccx_demuxer_open;
|
||||
ctx->is_open = ccx_demuxer_isopen;
|
||||
ctx->get_filesize = ccx_demuxer_getfilesize;
|
||||
ctx->get_stream_mode = ccx_demuxer_get_stream_mode;
|
||||
ctx->print_cfg = ccx_demuxer_print_cfg;
|
||||
ctx->write_es = ccx_demuxer_write_es;
|
||||
ctx->hauppauge_warning_shown = 0;
|
||||
ctx->parent = parent;
|
||||
ctx->last_pat_payload = NULL;
|
||||
ctx->last_pat_length = 0;
|
||||
|
||||
ctx->fh_out_elementarystream = NULL;
|
||||
ctx->warning_program_not_found_shown = CCX_FALSE;
|
||||
ctx->strangeheader = 0;
|
||||
memset(&ctx->freport, 0, sizeof(ctx->freport));
|
||||
if (cfg->out_elementarystream_filename != NULL)
|
||||
{
|
||||
if ((ctx->fh_out_elementarystream = fopen (cfg->out_elementarystream_filename,"wb"))==NULL)
|
||||
{
|
||||
print_error(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to open clean file: %s\n", cfg->out_elementarystream_filename);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < MAX_PSI_PID; i++)
|
||||
ctx->PID_buffers[i]=NULL;
|
||||
|
||||
init_ts(ctx);
|
||||
ctx->filebuffer = NULL;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void delete_demuxer_data(struct demuxer_data *data)
|
||||
{
|
||||
free(data->buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
struct demuxer_data* alloc_demuxer_data(void)
|
||||
{
|
||||
struct demuxer_data* data = malloc(sizeof(struct demuxer_data));
|
||||
|
||||
if(!data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
data->buffer = (unsigned char *) malloc (BUFSIZE);
|
||||
if(!data->buffer)
|
||||
{
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
data->len = 0;
|
||||
data->bufferdatatype = CCX_PES;
|
||||
|
||||
data->program_number = -1;
|
||||
data->stream_pid = -1;
|
||||
data->codec = CCX_CODEC_NONE;
|
||||
data->len = 0;
|
||||
data->pts = CCX_NOPTS;
|
||||
data->next_stream = 0;
|
||||
data->next_program = 0;
|
||||
return data;
|
||||
|
||||
}
|
||||
174
src/lib_ccx/ccx_demuxer.h
Normal file
174
src/lib_ccx/ccx_demuxer.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef CCX_DEMUXER_H
|
||||
#define CCX_DEMUXER_H
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ts_functions.h"
|
||||
#include "list.h"
|
||||
#include "activity.h"
|
||||
|
||||
/* Report information */
|
||||
#define SUB_STREAMS_CNT 10
|
||||
#define MAX_PID 65536
|
||||
#define MAX_PSI_PID 8191
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
#define MAX_PROGRAM 128
|
||||
#define MAX_PROGRAM_NAME_LEN 128
|
||||
struct ccx_demux_report
|
||||
{
|
||||
unsigned program_cnt;
|
||||
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned mp4_cc_track_cnt;
|
||||
};
|
||||
|
||||
struct program_info
|
||||
{
|
||||
int pid;
|
||||
int program_number;
|
||||
uint8_t analysed_PMT_once:1;
|
||||
uint8_t version;
|
||||
uint8_t saved_section[1021];
|
||||
int32_t crc;
|
||||
uint8_t valid_crc:1;
|
||||
char name[MAX_PROGRAM_NAME_LEN];
|
||||
/**
|
||||
* -1 pid represent that pcr_pid is not available
|
||||
*/
|
||||
int16_t pcr_pid;
|
||||
};
|
||||
|
||||
struct cap_info
|
||||
{
|
||||
int pid;
|
||||
int program_number;
|
||||
enum ccx_stream_type stream;
|
||||
enum ccx_code_type codec;
|
||||
long capbufsize;
|
||||
unsigned char *capbuf;
|
||||
long capbuflen; // Bytes read in capbuf
|
||||
int saw_pesstart;
|
||||
int prev_counter;
|
||||
void *codec_private_data;
|
||||
int ignore;
|
||||
|
||||
/**
|
||||
List joining all stream in TS
|
||||
*/
|
||||
struct list_head all_stream;
|
||||
/**
|
||||
List joining all sibling Stream in Program
|
||||
*/
|
||||
struct list_head sib_head;
|
||||
struct list_head sib_stream;
|
||||
/**
|
||||
List joining all sibling Stream in Program
|
||||
*/
|
||||
struct list_head pg_stream;
|
||||
|
||||
};
|
||||
|
||||
struct ccx_demuxer
|
||||
{
|
||||
int m2ts;
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
|
||||
// Small buffer to help us with the initial sync
|
||||
unsigned char startbytes[STARTBYTESLENGTH];
|
||||
unsigned int startbytes_pos;
|
||||
int startbytes_avail;
|
||||
|
||||
// User Specified Param
|
||||
int ts_autoprogram;
|
||||
int ts_allprogram;
|
||||
int flag_ts_forced_pn;
|
||||
int flag_ts_forced_cappid;
|
||||
int ts_datastreamtype;
|
||||
|
||||
|
||||
struct program_info pinfo[MAX_PROGRAM];
|
||||
int nb_program;
|
||||
/* subtitle codec type */
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_code_type nocodec;
|
||||
struct cap_info cinfo_tree;
|
||||
|
||||
/* File handles */
|
||||
FILE *fh_out_elementarystream;
|
||||
int infd; // descriptor number to input.
|
||||
LLONG past; /* Position in file, if in sync same as ftell() */
|
||||
|
||||
// TODO relates to fts_global
|
||||
int64_t global_timestamp;
|
||||
int64_t min_global_timestamp;
|
||||
int64_t offset_global_timestamp;
|
||||
int64_t last_global_timestamp;
|
||||
int global_timestamp_inited;
|
||||
|
||||
struct PSI_buffer *PID_buffers[MAX_PSI_PID];
|
||||
int PIDs_seen[MAX_PID];
|
||||
|
||||
struct PMT_entry *PIDs_programs[MAX_PID];
|
||||
struct ccx_demux_report freport;
|
||||
|
||||
/* Hauppauge support */
|
||||
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
|
||||
|
||||
int multi_stream_per_prog;
|
||||
|
||||
unsigned char *last_pat_payload;
|
||||
unsigned last_pat_length;
|
||||
|
||||
unsigned char *filebuffer;
|
||||
LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
unsigned int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
unsigned int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
|
||||
int warning_program_not_found_shown;
|
||||
|
||||
// Remember if the last header was valid. Used to suppress too much output
|
||||
// and the expected unrecognized first header for TiVo files.
|
||||
int strangeheader;
|
||||
|
||||
void *parent;
|
||||
void (*print_cfg)(struct ccx_demuxer *ctx);
|
||||
void (*reset)(struct ccx_demuxer *ctx);
|
||||
void (*close)(struct ccx_demuxer *ctx);
|
||||
int (*open)(struct ccx_demuxer *ctx, const char *file_name);
|
||||
int (*is_open)(struct ccx_demuxer *ctx);
|
||||
int (*get_stream_mode)(struct ccx_demuxer *ctx);
|
||||
LLONG (*get_filesize) (struct ccx_demuxer *ctx);
|
||||
int (*write_es)(struct ccx_demuxer *ctx, unsigned char* buf, size_t len);
|
||||
};
|
||||
|
||||
struct demuxer_data
|
||||
{
|
||||
int program_number;
|
||||
int stream_pid;
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_bufferdata_type bufferdatatype;
|
||||
unsigned char *buffer;
|
||||
size_t len;
|
||||
LLONG pts;
|
||||
struct demuxer_data *next_stream;
|
||||
struct demuxer_data *next_program;
|
||||
};
|
||||
|
||||
struct cap_info *get_sib_stream_by_type(struct cap_info* program, enum ccx_code_type type);
|
||||
struct ccx_demuxer *init_demuxer(void *parent, struct demuxer_cfg *cfg);
|
||||
void ccx_demuxer_delete(struct ccx_demuxer **ctx);
|
||||
struct demuxer_data* alloc_demuxer_data(void);
|
||||
void delete_demuxer_data(struct demuxer_data *data);
|
||||
int update_capinfo(struct ccx_demuxer *ctx, int pid, enum ccx_stream_type stream, enum ccx_code_type codec, int pn, void *private_data);
|
||||
struct cap_info * get_cinfo(struct ccx_demuxer *ctx, int pid);
|
||||
int need_capInfo(struct ccx_demuxer *ctx, int program_number);
|
||||
int need_capInfo_for_pid(struct ccx_demuxer *ctx, int pid);
|
||||
struct demuxer_data *get_best_data(struct demuxer_data *data);
|
||||
struct demuxer_data *get_data_stream(struct demuxer_data *data, int pid);
|
||||
int get_best_stream(struct ccx_demuxer *ctx);
|
||||
void ignore_other_stream(struct ccx_demuxer *ctx, int pid);
|
||||
void dinit_cap (struct ccx_demuxer *ctx);
|
||||
int get_programme_number(struct ccx_demuxer *ctx, int pid);
|
||||
struct cap_info* get_best_sib_stream(struct cap_info* program);
|
||||
void ignore_other_sib_stream(struct cap_info* head, int pid);
|
||||
#endif
|
||||
147
src/lib_ccx/ccx_dtvcc.c
Normal file
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
|
||||
1526
src/lib_ccx/ccx_encoders_common.c
Normal file
1526
src/lib_ccx/ccx_encoders_common.c
Normal file
File diff suppressed because it is too large
Load Diff
166
src/lib_ccx/ccx_encoders_common.h
Normal file
166
src/lib_ccx/ccx_encoders_common.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#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_common_option.h"
|
||||
|
||||
#define REQUEST_BUFFER_CAPACITY(ctx,length) if (length>ctx->capacity) \
|
||||
{ctx->capacity = length * 2; ctx->buffer = (unsigned char*)realloc(ctx->buffer, ctx->capacity); \
|
||||
if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
|
||||
}
|
||||
|
||||
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
|
||||
* to all encoder
|
||||
*/
|
||||
struct encoder_ctx
|
||||
{
|
||||
/* common buffer used by all encoder */
|
||||
unsigned char *buffer;
|
||||
/* capacity of buffer */
|
||||
unsigned int capacity;
|
||||
/* keep count of srt subtitle*/
|
||||
unsigned int srt_counter;
|
||||
|
||||
/* Input outputs */
|
||||
/* Flag giving hint that output is send to server through network */
|
||||
unsigned int send_to_srv;
|
||||
/* Used only in Spupng output */
|
||||
int multiple_files;
|
||||
/* Used only in Spupng output and creating name of output file*/
|
||||
char *first_input_file;
|
||||
/* Its array with length of number of languages */
|
||||
struct ccx_s_write *out;
|
||||
/* number of member in array of write out array */
|
||||
int nb_out;
|
||||
/* Input file format used in Teletext for exceptional output */
|
||||
unsigned int in_fileformat; //1 =Normal, 2=Teletext
|
||||
|
||||
/* Flag saying BOM to be written in each output file */
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
struct ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
int no_bom;
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
int no_font_color;
|
||||
int no_type_setting;
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
unsigned char *subline; // Temp storage for storing each line
|
||||
int extract;
|
||||
|
||||
int dtvcc_extract; //1 or 0 depending if we have to handle dtvcc
|
||||
ccx_dtvcc_writer_ctx dtvcc_writers[CCX_DTVCC_MAX_SERVICES];
|
||||
|
||||
/* Timing related variables*/
|
||||
/* start time of previous sub */
|
||||
LLONG prev_start;
|
||||
LLONG subs_delay;
|
||||
LLONG last_displayed_subs_ms;
|
||||
enum ccx_output_date_format date_format;
|
||||
char millis_separator;
|
||||
|
||||
/* Credit stuff */
|
||||
int startcredits_displayed;
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
unsigned char encoded_br[16];
|
||||
unsigned int encoded_br_length;
|
||||
|
||||
int new_sentence; // Capitalize next letter?
|
||||
|
||||
int program_number;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define INITIAL_ENC_BUFFER_CAPACITY 2048
|
||||
/**
|
||||
* Inialize encoder context with output context
|
||||
* allocate initial memory to buffer of context
|
||||
* write subtitle header to file refrenced by
|
||||
* output context
|
||||
*
|
||||
* @param cfg Option to initilaize encoder cfg params
|
||||
*
|
||||
* @return Allocated and properly initilaized Encoder Context, NULL on failure
|
||||
*/
|
||||
struct encoder_ctx *init_encoder(struct encoder_cfg *opt);
|
||||
|
||||
/**
|
||||
* try to add end credits in subtitle file and then write subtitle
|
||||
* footer
|
||||
*
|
||||
* deallocate encoder ctx, so before using encoder_ctx again
|
||||
* after deallocating user need to allocate encoder ctx again
|
||||
*
|
||||
* @oaram arg pointer to initialized encoder ctx using init_encoder
|
||||
*
|
||||
* @param current_fts to calculate window for end credits
|
||||
*/
|
||||
void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts);
|
||||
|
||||
/**
|
||||
* @param ctx encoder context
|
||||
* @param sub subtitle context returned by decoder
|
||||
*/
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user